Imported Upstream version 0.3.4
[anytun.git] / src / logTargets.cpp
1 /*
2  *  anytun
3  *
4  *  The secure anycast tunneling protocol (satp) defines a protocol used
5  *  for communication between any combination of unicast and anycast
6  *  tunnel endpoints.  It has less protocol overhead than IPSec in Tunnel
7  *  mode and allows tunneling of every ETHER TYPE protocol (e.g.
8  *  ethernet, ip, arp ...). satp directly includes cryptography and
9  *  message authentication based on the methodes used by SRTP.  It is
10  *  intended to deliver a generic, scaleable and secure solution for
11  *  tunneling and relaying of packets of any protocol.
12  *
13  *
14  *  Copyright (C) 2007-2009 Othmar Gsenger, Erwin Nindl,
15  *                          Christian Pointner <satp@wirdorange.org>
16  *
17  *  This file is part of Anytun.
18  *
19  *  Anytun is free software: you can redistribute it and/or modify
20  *  it under the terms of the GNU General Public License as published by
21  *  the Free Software Foundation, either version 3 of the License, or
22  *  any later version.
23  *
24  *  Anytun is distributed in the hope that it will be useful,
25  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
26  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
27  *  GNU General Public License for more details.
28  *
29  *  You should have received a copy of the GNU General Public License
30  *  along with anytun.  If not, see <http://www.gnu.org/licenses/>.
31  */
32
33 #include <sstream>
34
35 #include "datatypes.h"
36
37 #include "logTargets.h"
38 #include "log.h"
39 #include "anytunError.h"
40
41 #include "options.h"
42
43 #ifdef LOG_WINEVENTLOG
44 #include <windows.h>
45 #include <strsafe.h>
46 #endif
47
48 #include <boost/date_time/posix_time/posix_time.hpp>
49
50 LogTarget::LogTarget() : opened(false), enabled(false), max_prio(Log::PRIO_NOTICE)
51 {
52 }
53
54 LogTarget::LogTarget(int prio) : opened(false), enabled(false), max_prio(prio)
55 {
56 }
57
58 LogTargetList::~LogTargetList()
59 {
60   clear();
61 }
62
63 LogTargetList::target_type_t LogTargetList::targetTypeFromString(std::string type)
64 {
65   if(type == "syslog") { return TARGET_SYSLOG; }
66   if(type == "file") { return TARGET_FILE; }
67   if(type == "stdout") { return TARGET_STDOUT; }
68   if(type == "stderr") { return TARGET_STDERR; }
69   if(type == "eventlog") { return TARGET_WINEVENTLOG; }
70   return TARGET_UNKNOWN;
71 }
72
73 std::string LogTargetList::targetTypeToString(target_type_t type)
74 {
75   switch(type) {
76   case TARGET_SYSLOG:
77     return "syslog";
78   case TARGET_FILE:
79     return "file";
80   case TARGET_STDOUT:
81     return "stdout";
82   case TARGET_STDERR:
83     return "stderr";
84   case TARGET_WINEVENTLOG:
85     return "eventlog";
86   default:
87     return "unknown";
88   }
89 }
90
91 LogTarget* LogTargetList::add(std::string conf)
92 {
93   std::stringstream s(conf);
94   std::string type;
95   getline(s, type, ':');
96   if(!s.good()) {
97     throw syntax_error(conf, 0);
98   }
99
100   int prio = Log::PRIO_NOTICE;
101   s >> prio;
102   if(s.fail()) {
103     throw syntax_error(conf, conf.find_first_of(':')+1);
104   }
105
106   char buff[100];
107   if(s.good()) {
108     s.get(buff[0]);
109     if(buff[0] != ',') {
110       throw syntax_error(conf, (s.tellg() > 0) ? static_cast<size_t>(s.tellg()) - 1 : 0);
111     }
112     s.get(buff, 100);
113   } else {
114     buff[0] = 0;
115   }
116
117   return add(targetTypeFromString(type), prio, buff);
118 }
119
120 LogTarget* LogTargetList::add(target_type_t type, int prio, std::string conf)
121 {
122   switch(type) {
123   case TARGET_SYSLOG: {
124 #ifdef LOG_SYSLOG
125     if(!LogTargetSyslog::duplicateAllowed() && targets.count(TARGET_SYSLOG)) {
126       AnytunError::throwErr() << targetTypeToString(TARGET_SYSLOG) << " logtarget is supported only once";
127     }
128
129     return targets.insert(TargetsMap::value_type(TARGET_SYSLOG, new LogTargetSyslog(prio, conf)))->second;
130 #else
131     AnytunError::throwErr() << targetTypeToString(TARGET_SYSLOG) << " logtarget is not supported";
132 #endif
133   }
134   case TARGET_FILE: {
135 #ifdef LOG_FILE
136     if(!LogTargetFile::duplicateAllowed() && targets.count(TARGET_FILE)) {
137       AnytunError::throwErr() << targetTypeToString(TARGET_FILE) << " logtarget is supported only once";
138     }
139
140     return targets.insert(TargetsMap::value_type(TARGET_FILE, new LogTargetFile(prio, conf)))->second;
141 #else
142     AnytunError::throwErr() << targetTypeToString(TARGET_FILE) << " logtarget is not supported";
143 #endif
144   }
145   case TARGET_STDOUT:
146   case TARGET_STDERR: {
147 #ifdef LOG_STDOUT
148     if(!LogTargetStdout::duplicateAllowed() && targets.count(type)) {
149       AnytunError::throwErr() << targetTypeToString(type) << " logtarget is supported only once";
150     }
151
152     if(type == TARGET_STDERR) {
153       return targets.insert(TargetsMap::value_type(type, new LogTargetStdout(prio, std::cerr)))->second;
154     } else {
155       return targets.insert(TargetsMap::value_type(type, new LogTargetStdout(prio, std::cout)))->second;
156     }
157 #else
158     AnytunError::throwErr() << targetTypeToString(type) + " logtarget is not supported";
159 #endif
160   }
161   case TARGET_WINEVENTLOG: {
162 #ifdef LOG_WINEVENTLOG
163     if(!LogTargetWinEventlog::duplicateAllowed() && targets.count(TARGET_WINEVENTLOG)) {
164       AnytunError::throwErr() << targetTypeToString(TARGET_WINEVENTLOG) << " logtarget is supported only once";
165     }
166
167     return targets.insert(TargetsMap::value_type(TARGET_WINEVENTLOG, new LogTargetWinEventlog(prio, conf)))->second;
168 #else
169     AnytunError::throwErr() << targetTypeToString(TARGET_WINEVENTLOG) << " logtarget is not supported";
170 #endif
171   }
172   default:
173     AnytunError::throwErr() << "unknown log target";
174   }
175   return NULL;
176 }
177
178 void LogTargetList::clear()
179 {
180   TargetsMap::iterator it;
181   for(it = targets.begin(); it != targets.end(); ++it) {
182     delete it->second;
183   }
184   targets.clear();
185 }
186
187 void LogTargetList::log(std::string msg, int prio)
188 {
189   TargetsMap::const_iterator it;
190   for(it = targets.begin(); it != targets.end(); ++it) {
191     if(it->second->isEnabled() && it->second->getMaxPrio() >= prio) {
192       it->second->log(msg, prio);
193     }
194   }
195 }
196
197
198 #ifdef LOG_SYSLOG
199 int LogTargetSyslog::facilityFromString(std::string fac)
200 {
201   if(fac == "user") { return FAC_USER; }
202   if(fac == "mail") { return FAC_MAIL; }
203   if(fac == "daemon") { return FAC_DAEMON; }
204   if(fac == "auth") { return FAC_AUTH; }
205   if(fac == "syslog") { return FAC_SYSLOG; }
206   if(fac == "lpr") { return FAC_LPR; }
207   if(fac == "news") { return FAC_NEWS; }
208   if(fac == "uucp") { return FAC_UUCP; }
209   if(fac == "cron") { return FAC_CRON; }
210   if(fac == "authpriv") { return FAC_AUTHPRIV; }
211   if(fac == "ftp") { return FAC_FTP; }
212   if(fac == "local0") { return FAC_LOCAL0; }
213   if(fac == "local1") { return FAC_LOCAL1; }
214   if(fac == "local2") { return FAC_LOCAL2; }
215   if(fac == "local3") { return FAC_LOCAL3; }
216   if(fac == "local4") { return FAC_LOCAL4; }
217   if(fac == "local5") { return FAC_LOCAL5; }
218   if(fac == "local6") { return FAC_LOCAL6; }
219   if(fac == "local7") { return FAC_LOCAL7; }
220
221   AnytunError::throwErr() << "unknown syslog facility";
222   return 0;
223 }
224
225 std::string LogTargetSyslog::facilityToString(int fac)
226 {
227   switch(fac) {
228   case FAC_USER:
229     return "user";
230   case FAC_MAIL:
231     return "mail";
232   case FAC_DAEMON:
233     return "daemon";
234   case FAC_AUTH:
235     return "auth";
236   case FAC_SYSLOG:
237     return "syslog";
238   case FAC_LPR:
239     return "lpr";
240   case FAC_NEWS:
241     return "news";
242   case FAC_UUCP:
243     return "uucp";
244   case FAC_CRON:
245     return "cron";
246   case FAC_AUTHPRIV:
247     return "authpriv";
248   case FAC_FTP:
249     return "ftp";
250   case FAC_LOCAL0:
251     return "local0";
252   case FAC_LOCAL1:
253     return "local1";
254   case FAC_LOCAL2:
255     return "local2";
256   case FAC_LOCAL3:
257     return "local3";
258   case FAC_LOCAL4:
259     return "local4";
260   case FAC_LOCAL5:
261     return "local5";
262   case FAC_LOCAL6:
263     return "local6";
264   case FAC_LOCAL7:
265     return "local7";
266   default:
267     AnytunError::throwErr() << "unknown syslog facility";
268   }
269   return "";
270 }
271
272 LogTargetSyslog::LogTargetSyslog(int prio, std::string conf) : LogTarget(prio)
273 {
274   std::stringstream s(conf);
275   facility = FAC_DAEMON;
276   getline(s, logname, ',');
277   if(s.fail()) {
278     logname = "anytun";
279     return;
280   }
281   std::string fac;
282   getline(s, fac, ',');
283   if(s.fail()) {
284     return;
285   }
286
287   facility = LogTargetSyslog::facilityFromString(fac);
288 }
289
290 LogTargetSyslog::~LogTargetSyslog()
291 {
292   if(opened) {
293     close();
294   }
295 }
296
297 void LogTargetSyslog::open()
298 {
299   openlog(logname.c_str(), LOG_PID, facility);
300   opened = true;
301 }
302
303 void LogTargetSyslog::close()
304 {
305   closelog();
306   opened = false;
307 }
308
309 void LogTargetSyslog::log(std::string msg, int prio)
310 {
311   if(!opened) {
312     return;
313   }
314
315   syslog((prio + 2) | facility, "%s", msg.c_str());
316 }
317
318 LogTargetSyslog& LogTargetSyslog::setLogName(std::string l)
319 {
320   logname = l;
321   if(opened) {
322     close();
323   }
324   open();
325   return *this;
326 }
327
328 LogTargetSyslog& LogTargetSyslog::setFacility(int f)
329 {
330   facility = f;
331   if(opened) {
332     close();
333   }
334   open();
335   return *this;
336 }
337 #endif
338
339
340 #ifdef LOG_FILE
341 LogTargetFile::LogTargetFile(int prio, std::string conf) : LogTarget(prio)
342 {
343   std::stringstream s(conf);
344   getline(s, logfilename, ',');
345   if(s.fail()) {
346     logfilename = "anytun.log";
347   }
348 }
349
350 LogTargetFile::~LogTargetFile()
351 {
352   if(opened) {
353     close();
354   }
355 }
356
357 void LogTargetFile::open()
358 {
359   logfile.open(logfilename.c_str(), std::fstream::out | std::fstream::app);
360   opened = logfile.is_open();
361 }
362
363 void LogTargetFile::close()
364 {
365   if(logfile.is_open()) {
366     logfile.close();
367   }
368   opened = false;
369 }
370
371 void LogTargetFile::log(std::string msg, int prio)
372 {
373   if(!opened) {
374     return;
375   }
376
377   std::string timestamp = boost::posix_time::to_simple_string(boost::posix_time::second_clock::local_time());
378   logfile << timestamp << " " << Log::prioToString(prio) << ": " << msg << std::endl;
379 }
380
381 LogTargetFile& LogTargetFile::setLogFilename(std::string l)
382 {
383   logfilename = l;
384   if(opened) {
385     close();
386   }
387   open();
388   return *this;
389 }
390 #endif
391
392
393 #ifdef LOG_STDOUT
394 LogTargetStdout::LogTargetStdout(int prio, std::ostream& s) : LogTarget(prio), stream(s)
395 {
396 }
397
398 LogTargetStdout::~LogTargetStdout()
399 {
400   if(opened) {
401     close();
402   }
403 }
404
405 void LogTargetStdout::open()
406 {
407   opened = true;
408 }
409
410 void LogTargetStdout::close()
411 {
412   opened = false;
413 }
414
415 void LogTargetStdout::log(std::string msg, int prio)
416 {
417   if(!opened) {
418     return;
419   }
420
421   std::string timestamp = boost::posix_time::to_simple_string(boost::posix_time::second_clock::local_time());
422   stream << timestamp << " " << Log::prioToString(prio) << ": " << msg << std::endl;
423 }
424 #endif
425
426
427 #ifdef LOG_WINEVENTLOG
428 LogTargetWinEventlog::LogTargetWinEventlog(int prio, std::string conf) : LogTarget(prio)
429 {
430   std::stringstream s(conf);
431   getline(s, logname, ',');
432   if(s.fail()) {
433     logname = "anytun";
434   }
435 }
436
437 LogTargetWinEventlog::~LogTargetWinEventlog()
438 {
439   if(opened) {
440     close();
441   }
442 }
443
444 void LogTargetWinEventlog::open()
445 {
446   h_event_source = RegisterEventSourceA(NULL, logname.c_str());
447   if(h_event_source) {
448     opened = true;
449   }
450 }
451
452 void LogTargetWinEventlog::close()
453 {
454   if(h_event_source) {
455     DeregisterEventSource(h_event_source);
456   }
457   opened = false;
458 }
459
460 void LogTargetWinEventlog::log(std::string msg, int prio)
461 {
462   if(!opened) {
463     return;
464   }
465
466   LPCTSTR lpszStrings[1];
467   CHAR buffer[STERROR_TEXT_MAX];
468   StringCchPrintfA(buffer, STERROR_TEXT_MAX, "%s", msg.c_str());
469   lpszStrings[0] = buffer;
470   if(h_event_source) {
471     ReportEventA(h_event_source, prioToEventLogType(prio), 0, prio, NULL, 1, 0, lpszStrings, NULL);
472   }
473 }
474
475 LogTargetWinEventlog& LogTargetWinEventlog::setLogName(std::string l)
476 {
477   logname = l;
478   if(opened) {
479     close();
480   }
481   open();
482   return *this;
483 }
484
485 WORD LogTargetWinEventlog::prioToEventLogType(int prio)
486 {
487   switch(prio) {
488   case Log::PRIO_ERROR:
489     return EVENTLOG_ERROR_TYPE;
490   case Log::PRIO_WARNING:
491     return EVENTLOG_WARNING_TYPE;
492   case Log::PRIO_NOTICE:
493     return EVENTLOG_INFORMATION_TYPE;
494   case Log::PRIO_INFO:
495     return EVENTLOG_SUCCESS;
496   case Log::PRIO_DEBUG:
497     return EVENTLOG_INFORMATION_TYPE;
498   default:
499     return EVENTLOG_ERROR_TYPE;
500   }
501 }
502 #endif