Imported Upstream version 0.3.2
[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: return "syslog";
77   case TARGET_FILE: return "file";
78   case TARGET_STDOUT: return "stdout";
79   case TARGET_STDERR: return "stderr";
80   case TARGET_WINEVENTLOG: return "eventlog";
81   default: return "unknown";
82   }
83 }
84
85 LogTarget* LogTargetList::add(std::string conf)
86 {
87   std::stringstream s(conf);
88   std::string type;
89   getline(s, type, ':');
90   if(!s.good())
91     throw syntax_error(conf, 0);
92
93   int prio = Log::PRIO_NOTICE;
94   s >> prio;
95   if(s.fail())
96     throw syntax_error(conf, conf.find_first_of(':')+1);
97
98   char buff[100];
99   if(s.good()) {
100     s.get(buff[0]);
101     if(buff[0] != ',')
102       throw syntax_error(conf, (s.tellg() > 0) ? static_cast<size_t>(s.tellg()) - 1 : 0);
103     s.get(buff, 100);
104   }
105   else
106     buff[0] = 0;
107
108   return add(targetTypeFromString(type), prio, buff);
109 }
110
111 LogTarget* LogTargetList::add(target_type_t type, int prio, std::string conf)
112 {
113   switch(type) {
114   case TARGET_SYSLOG: {
115     #ifdef LOG_SYSLOG
116     if(!LogTargetSyslog::duplicateAllowed() && targets.count(TARGET_SYSLOG))
117       AnytunError::throwErr() << targetTypeToString(TARGET_SYSLOG) << " logtarget is supported only once";
118
119     return targets.insert(TargetsMap::value_type(TARGET_SYSLOG, new LogTargetSyslog(prio, conf)))->second;
120     #else
121     AnytunError::throwErr() << targetTypeToString(TARGET_SYSLOG) << " logtarget is not supported";
122     #endif
123   }
124   case TARGET_FILE: {
125     #ifdef LOG_FILE
126     if(!LogTargetFile::duplicateAllowed() && targets.count(TARGET_FILE))
127       AnytunError::throwErr() << targetTypeToString(TARGET_FILE) << " logtarget is supported only once";
128
129     return targets.insert(TargetsMap::value_type(TARGET_FILE, new LogTargetFile(prio, conf)))->second;
130     #else
131     AnytunError::throwErr() << targetTypeToString(TARGET_FILE) << " logtarget is not supported";
132     #endif
133   }
134   case TARGET_STDOUT: 
135   case TARGET_STDERR: {
136     #ifdef LOG_STDOUT
137     if(!LogTargetStdout::duplicateAllowed() && targets.count(type))
138       AnytunError::throwErr() << targetTypeToString(type) << " logtarget is supported only once";
139     
140     if(type == TARGET_STDERR)
141       return targets.insert(TargetsMap::value_type(type, new LogTargetStdout(prio, std::cerr)))->second;
142     else
143       return targets.insert(TargetsMap::value_type(type, new LogTargetStdout(prio, std::cout)))->second;
144     #else
145     AnytunError::throwErr() << targetTypeToString(type) + " logtarget is not supported";
146     #endif
147   }
148   case TARGET_WINEVENTLOG: {
149     #ifdef LOG_WINEVENTLOG
150     if(!LogTargetWinEventlog::duplicateAllowed() && targets.count(TARGET_WINEVENTLOG))
151       AnytunError::throwErr() << targetTypeToString(TARGET_WINEVENTLOG) << " logtarget is supported only once";
152
153     return targets.insert(TargetsMap::value_type(TARGET_WINEVENTLOG, new LogTargetWinEventlog(prio, conf)))->second;
154     #else
155     AnytunError::throwErr() << targetTypeToString(TARGET_WINEVENTLOG) << " logtarget is not supported";
156     #endif
157   }
158   default: 
159     AnytunError::throwErr() << "unknown log target";
160   }
161   return NULL;
162 }
163
164 void LogTargetList::clear()
165 {
166   TargetsMap::iterator it;
167   for(it = targets.begin(); it != targets.end(); ++it)
168     delete it->second;
169   targets.clear();
170 }
171   
172 void LogTargetList::log(std::string msg, int prio)
173 {
174   TargetsMap::const_iterator it;
175   for(it = targets.begin(); it != targets.end(); ++it) {
176     if(it->second->isEnabled() && it->second->getMaxPrio() >= prio)
177       it->second->log(msg, prio);
178   }
179 }
180
181
182 #ifdef LOG_SYSLOG
183 int LogTargetSyslog::facilityFromString(std::string fac)
184 {
185   if(fac == "user") return FAC_USER;
186   if(fac == "mail") return FAC_MAIL;
187   if(fac == "daemon") return FAC_DAEMON;
188   if(fac == "auth") return FAC_AUTH;
189   if(fac == "syslog") return FAC_SYSLOG;
190   if(fac == "lpr") return FAC_LPR;
191   if(fac == "news") return FAC_NEWS;
192   if(fac == "uucp") return FAC_UUCP;
193   if(fac == "cron") return FAC_CRON;
194   if(fac == "authpriv") return FAC_AUTHPRIV;
195   if(fac == "ftp") return FAC_FTP;
196   if(fac == "local0") return FAC_LOCAL0;
197   if(fac == "local1") return FAC_LOCAL1;
198   if(fac == "local2") return FAC_LOCAL2;
199   if(fac == "local3") return FAC_LOCAL3;
200   if(fac == "local4") return FAC_LOCAL4;
201   if(fac == "local5") return FAC_LOCAL5;
202   if(fac == "local6") return FAC_LOCAL6;
203   if(fac == "local7") return FAC_LOCAL7;
204   
205   AnytunError::throwErr() << "unknown syslog facility";
206   return 0;
207 }
208
209 std::string LogTargetSyslog::facilityToString(int fac)
210 {
211   switch(fac) {
212   case FAC_USER: return "user";
213   case FAC_MAIL: return "mail";
214   case FAC_DAEMON: return "daemon";
215   case FAC_AUTH: return "auth";
216   case FAC_SYSLOG: return "syslog";
217   case FAC_LPR: return "lpr";
218   case FAC_NEWS: return "news";
219   case FAC_UUCP: return "uucp";
220   case FAC_CRON: return "cron";
221   case FAC_AUTHPRIV: return "authpriv";
222   case FAC_FTP: return "ftp";
223   case FAC_LOCAL0: return "local0";
224   case FAC_LOCAL1: return "local1";
225   case FAC_LOCAL2: return "local2";
226   case FAC_LOCAL3: return "local3";
227   case FAC_LOCAL4: return "local4";
228   case FAC_LOCAL5: return "local5";
229   case FAC_LOCAL6: return "local6";
230   case FAC_LOCAL7: return "local7";
231   default: AnytunError::throwErr() << "unknown syslog facility";
232   }
233   return "";
234 }
235
236 LogTargetSyslog::LogTargetSyslog(int prio, std::string conf) : LogTarget(prio)
237 {
238   std::stringstream s(conf);
239   facility = FAC_DAEMON;
240   getline(s, logname, ',');
241   if(s.fail()) {
242     logname = "anytun";
243     return;
244   }
245   std::string fac;
246   getline(s, fac, ',');
247   if(s.fail())
248     return;
249
250   facility = LogTargetSyslog::facilityFromString(fac);
251 }
252
253 LogTargetSyslog::~LogTargetSyslog()
254 {
255   if(opened)
256     close();
257 }
258
259 void LogTargetSyslog::open()
260 {
261   openlog(logname.c_str(), LOG_PID, facility);
262   opened = true;
263 }
264
265 void LogTargetSyslog::close()
266 {
267   closelog();
268   opened = false;
269 }
270
271 void LogTargetSyslog::log(std::string msg, int prio)
272 {
273   if(!opened)
274     return;
275
276   syslog((prio + 2) | facility, "%s", msg.c_str());  
277 }
278
279 LogTargetSyslog& LogTargetSyslog::setLogName(std::string l)
280 {
281   logname = l;
282   if(opened)
283     close();
284   open();
285   return *this;
286 }
287
288 LogTargetSyslog& LogTargetSyslog::setFacility(int f)
289 {
290   facility = f;
291   if(opened)
292     close();
293   open();
294   return *this;
295 }
296 #endif
297
298
299 #ifdef LOG_FILE
300 LogTargetFile::LogTargetFile(int prio, std::string conf) : LogTarget(prio)
301 {
302   std::stringstream s(conf);
303   getline(s, logfilename, ',');
304   if(s.fail())
305     logfilename = "anytun.log";
306 }
307
308 LogTargetFile::~LogTargetFile()
309 {
310   if(opened)
311     close();
312 }
313
314 void LogTargetFile::open()
315 {
316   logfile.open(logfilename.c_str(), std::fstream::out | std::fstream::app);
317   opened = logfile.is_open();
318 }
319
320 void LogTargetFile::close()
321 {
322   if(logfile.is_open())
323     logfile.close();
324   opened = false;
325 }
326
327 void LogTargetFile::log(std::string msg, int prio)
328 {
329   if(!opened)
330     return;
331
332   std::string timestamp = boost::posix_time::to_simple_string(boost::posix_time::second_clock::local_time());
333   logfile << timestamp << " " << Log::prioToString(prio) << ": " << msg << std::endl;
334 }
335
336 LogTargetFile& LogTargetFile::setLogFilename(std::string l)
337 {
338   logfilename = l;
339   if(opened)
340     close();
341   open();
342   return *this;
343 }
344 #endif
345
346
347 #ifdef LOG_STDOUT
348 LogTargetStdout::LogTargetStdout(int prio, std::ostream& s) : LogTarget(prio), stream(s)
349 {
350 }
351
352 LogTargetStdout::~LogTargetStdout()
353 {
354   if(opened)
355     close();
356 }
357
358 void LogTargetStdout::open()
359 {
360   opened = true;
361 }
362
363 void LogTargetStdout::close()
364 {
365   opened = false;
366 }
367
368 void LogTargetStdout::log(std::string msg, int prio)
369 {
370   if(!opened)
371     return;
372
373   std::string timestamp = boost::posix_time::to_simple_string(boost::posix_time::second_clock::local_time());
374   stream << timestamp << " " << Log::prioToString(prio) << ": " << msg << std::endl;
375 }
376 #endif
377
378
379 #ifdef LOG_WINEVENTLOG
380 LogTargetWinEventlog::LogTargetWinEventlog(int prio, std::string conf) : LogTarget(prio)
381 {
382   std::stringstream s(conf);
383   getline(s, logname, ',');
384   if(s.fail())
385     logname = "anytun";
386 }
387
388 LogTargetWinEventlog::~LogTargetWinEventlog()
389 {
390   if(opened)
391     close();
392 }
393
394 void LogTargetWinEventlog::open()
395 {
396   h_event_source = RegisterEventSourceA(NULL, logname.c_str());
397   if(h_event_source)
398     opened = true;
399 }
400
401 void LogTargetWinEventlog::close()
402 {
403   if(h_event_source)
404     DeregisterEventSource(h_event_source);
405   opened = false;
406 }
407
408 void LogTargetWinEventlog::log(std::string msg, int prio)
409 {
410   if(!opened)
411     return;
412
413   LPCTSTR lpszStrings[1];  
414   CHAR buffer[STERROR_TEXT_MAX];
415   StringCchPrintfA(buffer, STERROR_TEXT_MAX, "%s", msg.c_str());
416   lpszStrings[0] = buffer;
417   if(h_event_source)
418     ReportEventA(h_event_source, prioToEventLogType(prio), 0, prio, NULL, 1, 0, lpszStrings, NULL);
419 }
420
421 LogTargetWinEventlog& LogTargetWinEventlog::setLogName(std::string l)
422 {
423   logname = l;
424   if(opened)
425     close();
426   open();
427   return *this;
428 }
429
430 WORD LogTargetWinEventlog::prioToEventLogType(int prio)
431 {
432   switch(prio) {
433   case Log::PRIO_ERROR: return EVENTLOG_ERROR_TYPE;
434   case Log::PRIO_WARNING: return EVENTLOG_WARNING_TYPE;
435   case Log::PRIO_NOTICE: return EVENTLOG_INFORMATION_TYPE;
436   case Log::PRIO_INFO: return EVENTLOG_SUCCESS;
437   case Log::PRIO_DEBUG: return EVENTLOG_INFORMATION_TYPE;
438   default: return EVENTLOG_ERROR_TYPE;
439   }
440 }
441 #endif