Imported Upstream version 0.3.5
[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 methods 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-2014 Markus Grüneis, 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  *  In addition, as a special exception, the copyright holders give
33  *  permission to link the code of portions of this program with the
34  *  OpenSSL library under certain conditions as described in each
35  *  individual source file, and distribute linked combinations
36  *  including the two.
37  *  You must obey the GNU General Public License in all respects
38  *  for all of the code used other than OpenSSL.  If you modify
39  *  file(s) with this exception, you may extend this exception to your
40  *  version of the file(s), but you are not obligated to do so.  If you
41  *  do not wish to do so, delete this exception statement from your
42  *  version.  If you delete this exception statement from all source
43  *  files in the program, then also delete it here.
44  */
45
46 #include <sstream>
47
48 #include "datatypes.h"
49
50 #include "logTargets.h"
51 #include "log.h"
52 #include "anytunError.h"
53
54 #include "options.h"
55
56 #ifdef LOG_WINEVENTLOG
57 #include <windows.h>
58 #include <strsafe.h>
59 #endif
60
61 #include <boost/date_time/posix_time/posix_time.hpp>
62
63 LogTarget::LogTarget() : opened(false), enabled(false), max_prio(Log::PRIO_NOTICE)
64 {
65 }
66
67 LogTarget::LogTarget(int prio) : opened(false), enabled(false), max_prio(prio)
68 {
69 }
70
71 LogTargetList::~LogTargetList()
72 {
73   clear();
74 }
75
76 LogTargetList::target_type_t LogTargetList::targetTypeFromString(std::string type)
77 {
78   if(type == "syslog") { return TARGET_SYSLOG; }
79   if(type == "file") { return TARGET_FILE; }
80   if(type == "stdout") { return TARGET_STDOUT; }
81   if(type == "stderr") { return TARGET_STDERR; }
82   if(type == "eventlog") { return TARGET_WINEVENTLOG; }
83   return TARGET_UNKNOWN;
84 }
85
86 std::string LogTargetList::targetTypeToString(target_type_t type)
87 {
88   switch(type) {
89   case TARGET_SYSLOG:
90     return "syslog";
91   case TARGET_FILE:
92     return "file";
93   case TARGET_STDOUT:
94     return "stdout";
95   case TARGET_STDERR:
96     return "stderr";
97   case TARGET_WINEVENTLOG:
98     return "eventlog";
99   default:
100     return "unknown";
101   }
102 }
103
104 LogTarget* LogTargetList::add(std::string conf)
105 {
106   std::stringstream s(conf);
107   std::string type;
108   getline(s, type, ':');
109   if(!s.good()) {
110     throw syntax_error(conf, 0);
111   }
112
113   int prio = Log::PRIO_NOTICE;
114   s >> prio;
115   if(s.fail()) {
116     throw syntax_error(conf, conf.find_first_of(':')+1);
117   }
118
119   char buff[100];
120   if(s.good()) {
121     s.get(buff[0]);
122     if(buff[0] != ',') {
123       throw syntax_error(conf, (s.tellg() > 0) ? static_cast<size_t>(s.tellg()) - 1 : 0);
124     }
125     s.get(buff, 100);
126   } else {
127     buff[0] = 0;
128   }
129
130   return add(targetTypeFromString(type), prio, buff);
131 }
132
133 LogTarget* LogTargetList::add(target_type_t type, int prio, std::string conf)
134 {
135   switch(type) {
136   case TARGET_SYSLOG: {
137 #ifdef LOG_SYSLOG
138     if(!LogTargetSyslog::duplicateAllowed() && targets.count(TARGET_SYSLOG)) {
139       AnytunError::throwErr() << targetTypeToString(TARGET_SYSLOG) << " logtarget is supported only once";
140     }
141
142     return targets.insert(TargetsMap::value_type(TARGET_SYSLOG, new LogTargetSyslog(prio, conf)))->second;
143 #else
144     AnytunError::throwErr() << targetTypeToString(TARGET_SYSLOG) << " logtarget is not supported";
145 #endif
146   }
147   case TARGET_FILE: {
148 #ifdef LOG_FILE
149     if(!LogTargetFile::duplicateAllowed() && targets.count(TARGET_FILE)) {
150       AnytunError::throwErr() << targetTypeToString(TARGET_FILE) << " logtarget is supported only once";
151     }
152
153     return targets.insert(TargetsMap::value_type(TARGET_FILE, new LogTargetFile(prio, conf)))->second;
154 #else
155     AnytunError::throwErr() << targetTypeToString(TARGET_FILE) << " logtarget is not supported";
156 #endif
157   }
158   case TARGET_STDOUT:
159   case TARGET_STDERR: {
160 #ifdef LOG_STDOUT
161     if(!LogTargetStdout::duplicateAllowed() && targets.count(type)) {
162       AnytunError::throwErr() << targetTypeToString(type) << " logtarget is supported only once";
163     }
164
165     if(type == TARGET_STDERR) {
166       return targets.insert(TargetsMap::value_type(type, new LogTargetStdout(prio, std::cerr)))->second;
167     } else {
168       return targets.insert(TargetsMap::value_type(type, new LogTargetStdout(prio, std::cout)))->second;
169     }
170 #else
171     AnytunError::throwErr() << targetTypeToString(type) + " logtarget is not supported";
172 #endif
173   }
174   case TARGET_WINEVENTLOG: {
175 #ifdef LOG_WINEVENTLOG
176     if(!LogTargetWinEventlog::duplicateAllowed() && targets.count(TARGET_WINEVENTLOG)) {
177       AnytunError::throwErr() << targetTypeToString(TARGET_WINEVENTLOG) << " logtarget is supported only once";
178     }
179
180     return targets.insert(TargetsMap::value_type(TARGET_WINEVENTLOG, new LogTargetWinEventlog(prio, conf)))->second;
181 #else
182     AnytunError::throwErr() << targetTypeToString(TARGET_WINEVENTLOG) << " logtarget is not supported";
183 #endif
184   }
185   default:
186     AnytunError::throwErr() << "unknown log target";
187   }
188   return NULL;
189 }
190
191 void LogTargetList::clear()
192 {
193   TargetsMap::iterator it;
194   for(it = targets.begin(); it != targets.end(); ++it) {
195     delete it->second;
196   }
197   targets.clear();
198 }
199
200 void LogTargetList::log(std::string msg, int prio)
201 {
202   TargetsMap::const_iterator it;
203   for(it = targets.begin(); it != targets.end(); ++it) {
204     if(it->second->isEnabled() && it->second->getMaxPrio() >= prio) {
205       it->second->log(msg, prio);
206     }
207   }
208 }
209
210
211 #ifdef LOG_SYSLOG
212 int LogTargetSyslog::facilityFromString(std::string fac)
213 {
214   if(fac == "user") { return FAC_USER; }
215   if(fac == "mail") { return FAC_MAIL; }
216   if(fac == "daemon") { return FAC_DAEMON; }
217   if(fac == "auth") { return FAC_AUTH; }
218   if(fac == "syslog") { return FAC_SYSLOG; }
219   if(fac == "lpr") { return FAC_LPR; }
220   if(fac == "news") { return FAC_NEWS; }
221   if(fac == "uucp") { return FAC_UUCP; }
222   if(fac == "cron") { return FAC_CRON; }
223   if(fac == "authpriv") { return FAC_AUTHPRIV; }
224   if(fac == "ftp") { return FAC_FTP; }
225   if(fac == "local0") { return FAC_LOCAL0; }
226   if(fac == "local1") { return FAC_LOCAL1; }
227   if(fac == "local2") { return FAC_LOCAL2; }
228   if(fac == "local3") { return FAC_LOCAL3; }
229   if(fac == "local4") { return FAC_LOCAL4; }
230   if(fac == "local5") { return FAC_LOCAL5; }
231   if(fac == "local6") { return FAC_LOCAL6; }
232   if(fac == "local7") { return FAC_LOCAL7; }
233
234   AnytunError::throwErr() << "unknown syslog facility";
235   return 0;
236 }
237
238 std::string LogTargetSyslog::facilityToString(int fac)
239 {
240   switch(fac) {
241   case FAC_USER:
242     return "user";
243   case FAC_MAIL:
244     return "mail";
245   case FAC_DAEMON:
246     return "daemon";
247   case FAC_AUTH:
248     return "auth";
249   case FAC_SYSLOG:
250     return "syslog";
251   case FAC_LPR:
252     return "lpr";
253   case FAC_NEWS:
254     return "news";
255   case FAC_UUCP:
256     return "uucp";
257   case FAC_CRON:
258     return "cron";
259   case FAC_AUTHPRIV:
260     return "authpriv";
261   case FAC_FTP:
262     return "ftp";
263   case FAC_LOCAL0:
264     return "local0";
265   case FAC_LOCAL1:
266     return "local1";
267   case FAC_LOCAL2:
268     return "local2";
269   case FAC_LOCAL3:
270     return "local3";
271   case FAC_LOCAL4:
272     return "local4";
273   case FAC_LOCAL5:
274     return "local5";
275   case FAC_LOCAL6:
276     return "local6";
277   case FAC_LOCAL7:
278     return "local7";
279   default:
280     AnytunError::throwErr() << "unknown syslog facility";
281   }
282   return "";
283 }
284
285 LogTargetSyslog::LogTargetSyslog(int prio, std::string conf) : LogTarget(prio)
286 {
287   std::stringstream s(conf);
288   facility = FAC_DAEMON;
289   getline(s, logname, ',');
290   if(s.fail()) {
291     logname = "anytun";
292     return;
293   }
294   std::string fac;
295   getline(s, fac, ',');
296   if(s.fail()) {
297     return;
298   }
299
300   facility = LogTargetSyslog::facilityFromString(fac);
301 }
302
303 LogTargetSyslog::~LogTargetSyslog()
304 {
305   if(opened) {
306     close();
307   }
308 }
309
310 void LogTargetSyslog::open()
311 {
312   openlog(logname.c_str(), LOG_PID, facility);
313   opened = true;
314 }
315
316 void LogTargetSyslog::close()
317 {
318   closelog();
319   opened = false;
320 }
321
322 void LogTargetSyslog::log(std::string msg, int prio)
323 {
324   if(!opened) {
325     return;
326   }
327
328   syslog((prio + 2) | facility, "%s", msg.c_str());
329 }
330
331 LogTargetSyslog& LogTargetSyslog::setLogName(std::string l)
332 {
333   logname = l;
334   if(opened) {
335     close();
336   }
337   open();
338   return *this;
339 }
340
341 LogTargetSyslog& LogTargetSyslog::setFacility(int f)
342 {
343   facility = f;
344   if(opened) {
345     close();
346   }
347   open();
348   return *this;
349 }
350 #endif
351
352
353 #ifdef LOG_FILE
354 LogTargetFile::LogTargetFile(int prio, std::string conf) : LogTarget(prio)
355 {
356   std::stringstream s(conf);
357   getline(s, logfilename, ',');
358   if(s.fail()) {
359     logfilename = "anytun.log";
360   }
361 }
362
363 LogTargetFile::~LogTargetFile()
364 {
365   if(opened) {
366     close();
367   }
368 }
369
370 void LogTargetFile::open()
371 {
372   logfile.open(logfilename.c_str(), std::fstream::out | std::fstream::app);
373   opened = logfile.is_open();
374 }
375
376 void LogTargetFile::close()
377 {
378   if(logfile.is_open()) {
379     logfile.close();
380   }
381   opened = false;
382 }
383
384 void LogTargetFile::log(std::string msg, int prio)
385 {
386   if(!opened) {
387     return;
388   }
389
390   std::string timestamp = boost::posix_time::to_simple_string(boost::posix_time::second_clock::local_time());
391   logfile << timestamp << " " << Log::prioToString(prio) << ": " << msg << std::endl;
392 }
393
394 LogTargetFile& LogTargetFile::setLogFilename(std::string l)
395 {
396   logfilename = l;
397   if(opened) {
398     close();
399   }
400   open();
401   return *this;
402 }
403 #endif
404
405
406 #ifdef LOG_STDOUT
407 LogTargetStdout::LogTargetStdout(int prio, std::ostream& s) : LogTarget(prio), stream(s)
408 {
409 }
410
411 LogTargetStdout::~LogTargetStdout()
412 {
413   if(opened) {
414     close();
415   }
416 }
417
418 void LogTargetStdout::open()
419 {
420   opened = true;
421 }
422
423 void LogTargetStdout::close()
424 {
425   opened = false;
426 }
427
428 void LogTargetStdout::log(std::string msg, int prio)
429 {
430   if(!opened) {
431     return;
432   }
433
434   std::string timestamp = boost::posix_time::to_simple_string(boost::posix_time::second_clock::local_time());
435   stream << timestamp << " " << Log::prioToString(prio) << ": " << msg << std::endl;
436 }
437 #endif
438
439
440 #ifdef LOG_WINEVENTLOG
441 LogTargetWinEventlog::LogTargetWinEventlog(int prio, std::string conf) : LogTarget(prio)
442 {
443   std::stringstream s(conf);
444   getline(s, logname, ',');
445   if(s.fail()) {
446     logname = "anytun";
447   }
448 }
449
450 LogTargetWinEventlog::~LogTargetWinEventlog()
451 {
452   if(opened) {
453     close();
454   }
455 }
456
457 void LogTargetWinEventlog::open()
458 {
459   h_event_source = RegisterEventSourceA(NULL, logname.c_str());
460   if(h_event_source) {
461     opened = true;
462   }
463 }
464
465 void LogTargetWinEventlog::close()
466 {
467   if(h_event_source) {
468     DeregisterEventSource(h_event_source);
469   }
470   opened = false;
471 }
472
473 void LogTargetWinEventlog::log(std::string msg, int prio)
474 {
475   if(!opened) {
476     return;
477   }
478
479   LPCTSTR lpszStrings[1];
480   CHAR buffer[STERROR_TEXT_MAX];
481   StringCchPrintfA(buffer, STERROR_TEXT_MAX, "%s", msg.c_str());
482   lpszStrings[0] = buffer;
483   if(h_event_source) {
484     ReportEventA(h_event_source, prioToEventLogType(prio), 0, prio, NULL, 1, 0, lpszStrings, NULL);
485   }
486 }
487
488 LogTargetWinEventlog& LogTargetWinEventlog::setLogName(std::string l)
489 {
490   logname = l;
491   if(opened) {
492     close();
493   }
494   open();
495   return *this;
496 }
497
498 WORD LogTargetWinEventlog::prioToEventLogType(int prio)
499 {
500   switch(prio) {
501   case Log::PRIO_ERROR:
502     return EVENTLOG_ERROR_TYPE;
503   case Log::PRIO_WARNING:
504     return EVENTLOG_WARNING_TYPE;
505   case Log::PRIO_NOTICE:
506     return EVENTLOG_INFORMATION_TYPE;
507   case Log::PRIO_INFO:
508     return EVENTLOG_SUCCESS;
509   case Log::PRIO_DEBUG:
510     return EVENTLOG_INFORMATION_TYPE;
511   default:
512     return EVENTLOG_ERROR_TYPE;
513   }
514 }
515 #endif