02208c65d518f574bd2987ec504af70909a1b077
[debian/uanytun.git] / src / log.c
1 /*
2  *  uAnytun
3  *
4  *  uAnytun is a tiny implementation of SATP. Unlike Anytun which is a full
5  *  featured implementation uAnytun has no support for multiple connections
6  *  or synchronisation. It is a small single threaded implementation intended
7  *  to act as a client on small platforms.
8  *  The secure anycast tunneling protocol (satp) defines a protocol used
9  *  for communication between any combination of unicast and anycast
10  *  tunnel endpoints.  It has less protocol overhead than IPSec in Tunnel
11  *  mode and allows tunneling of every ETHER TYPE protocol (e.g.
12  *  ethernet, ip, arp ...). satp directly includes cryptography and
13  *  message authentication based on the methods used by SRTP.  It is
14  *  intended to deliver a generic, scaleable and secure solution for
15  *  tunneling and relaying of packets of any protocol.
16  *
17  *
18  *  Copyright (C) 2007-2014 Christian Pointner <equinox@anytun.org>
19  *
20  *  This file is part of uAnytun.
21  *
22  *  uAnytun is free software: you can redistribute it and/or modify
23  *  it under the terms of the GNU General Public License as published by
24  *  the Free Software Foundation, either version 3 of the License, or
25  *  any later version.
26  *
27  *  uAnytun is distributed in the hope that it will be useful,
28  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
29  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
30  *  GNU General Public License for more details.
31  *
32  *  You should have received a copy of the GNU General Public License
33  *  along with uAnytun. If not, see <http://www.gnu.org/licenses/>.
34  *
35  *  In addition, as a special exception, the copyright holders give
36  *  permission to link the code of portions of this program with the
37  *  OpenSSL library under certain conditions as described in each
38  *  individual source file, and distribute linked combinations
39  *  including the two.
40  *  You must obey the GNU General Public License in all respects
41  *  for all of the code used other than OpenSSL.  If you modify
42  *  file(s) with this exception, you may extend this exception to your
43  *  version of the file(s), but you are not obligated to do so.  If you
44  *  do not wish to do so, delete this exception statement from your
45  *  version.  If you delete this exception statement from all source
46  *  files in the program, then also delete it here.
47  */
48
49 #include "datatypes.h"
50
51 #include <ctype.h>
52 #include <string.h>
53 #include <stdarg.h>
54 #include <stdlib.h>
55 #include <stdio.h>
56
57 #define SYSLOG_NAMES
58 #include <syslog.h>
59
60 #include "log.h"
61
62 log_t stdlog;
63
64 #include "log_targets.h"
65
66 const char* log_prio_to_string(log_prio_t prio)
67 {
68   switch(prio) {
69   case ERROR: return "ERROR";
70   case WARNING: return "WARNING";
71   case NOTICE: return "NOTICE";
72   case INFO: return "INFO";
73   case DEBUG: return "DEBUG";
74   }
75   return "UNKNOWN";
76 }
77
78 log_target_type_t log_target_parse_type(const char* conf)
79 {
80   if(!conf)
81     return TARGET_UNKNOWN;
82
83   if(!strncmp(conf, "syslog", 6)) return TARGET_SYSLOG;
84   if(!strncmp(conf, "file", 4)) return TARGET_FILE;
85   if(!strncmp(conf, "stdout", 6)) return TARGET_STDOUT;
86   if(!strncmp(conf, "stderr", 6)) return TARGET_STDERR;
87
88   return TARGET_UNKNOWN;
89 }
90
91 int log_targets_target_exists(log_targets_t* targets, log_target_type_t type)
92 {
93   if(!targets && !targets->first_)
94     return 0;
95
96   log_target_t* tmp = targets->first_;
97   while(tmp) {
98     if(tmp->type_ == type)
99       return 1;
100     tmp = tmp->next_;
101   }
102   return 0;
103 }
104
105 int log_targets_add(log_targets_t* targets, const char* conf)
106 {
107   if(!targets)
108     return -1;
109
110   log_target_t* new_target = NULL;
111   int duplicates_allowed = 0;
112   switch(log_target_parse_type(conf)) {
113   case TARGET_SYSLOG: new_target = log_target_syslog_new(); break;
114   case TARGET_FILE: new_target = log_target_file_new(); duplicates_allowed = 1; break;
115   case TARGET_STDOUT: new_target = log_target_stdout_new(); break;
116   case TARGET_STDERR: new_target = log_target_stderr_new(); break;
117   default: return -3;
118   }
119   if(!new_target)
120     return -2;
121
122   if(!duplicates_allowed && log_targets_target_exists(targets, new_target->type_)) {
123     free(new_target);
124     return -4;
125   }
126
127   const char* prioptr = strchr(conf, ':');
128   if(!prioptr || prioptr[1] == 0) {
129     free(new_target);
130     return -1;
131   }
132   prioptr++;
133   if(!isdigit(prioptr[0]) || (prioptr[1] != 0 && prioptr[1] != ',')) {
134     free(new_target);
135     return -1;
136   }
137   new_target->max_prio_ = prioptr[0] - '0';
138   if(new_target->max_prio_ > 0)
139     new_target->enabled_ = 1;
140
141   if(new_target->init != NULL) {
142     const char* confptr = NULL;
143     if(prioptr[1] != 0)
144       confptr = prioptr+2;
145
146     int ret = (*new_target->init)(new_target, confptr);
147     if(ret) {
148       free(new_target);
149       return ret;
150     }
151   }
152
153   if(new_target->open != NULL)
154     (*new_target->open)(new_target);
155
156
157   if(!targets->first_) {
158     targets->first_ = new_target;
159   }
160   else {
161     log_target_t* tmp = targets->first_;
162     while(tmp->next_)
163       tmp = tmp->next_;
164
165     tmp->next_ = new_target;
166   }
167   return 0;
168 }
169
170 void log_targets_log(log_targets_t* targets, log_prio_t prio, const char* msg)
171 {
172   if(!targets)
173     return;
174
175   log_target_t* tmp = targets->first_;
176   while(tmp) {
177     if(tmp->log != NULL && tmp->enabled_ && tmp->max_prio_ >= prio)
178       (*tmp->log)(tmp, prio, msg);
179
180     tmp = tmp->next_;
181   }
182 }
183
184 void log_targets_clear(log_targets_t* targets)
185 {
186   if(!targets)
187     return;
188
189   while(targets->first_) {
190     log_target_t* tmp = targets->first_;
191     targets->first_ = tmp->next_;
192     if(tmp->close != NULL)
193       (*tmp->close)(tmp);
194     if(tmp->clear != NULL)
195       (*tmp->clear)(tmp);
196     free(tmp);
197   }
198 }
199
200
201 void log_init()
202 {
203   stdlog.max_prio_ = 0;
204   stdlog.targets_.first_ = NULL;
205 }
206
207 void log_close()
208 {
209   log_targets_clear(&stdlog.targets_);
210 }
211
212 void update_max_prio()
213 {
214   log_target_t* tmp = stdlog.targets_.first_;
215   while(tmp) {
216     if(tmp->enabled_ && tmp->max_prio_ > stdlog.max_prio_)
217       stdlog.max_prio_ = tmp->max_prio_;
218
219     tmp = tmp->next_;
220   }
221 }
222
223 int log_add_target(const char* conf)
224 {
225   if(!conf)
226     return -1;
227
228   int ret = log_targets_add(&stdlog.targets_, conf);
229   if(!ret) update_max_prio();
230   return ret;
231 }
232
233 void log_printf(log_prio_t prio, const char* fmt, ...)
234 {
235   if(stdlog.max_prio_ < prio)
236     return;
237
238   static char msg[MSG_LENGTH_MAX];
239   va_list args;
240
241   va_start(args, fmt);
242   vsnprintf(msg, MSG_LENGTH_MAX, fmt, args);
243   va_end(args);
244
245   log_targets_log(&stdlog.targets_, prio, msg);
246 }
247
248 void log_print_hex_dump(log_prio_t prio, const u_int8_t* buf, u_int32_t len)
249 {
250   if(stdlog.max_prio_ < prio)
251     return;
252
253   static char msg[MSG_LENGTH_MAX];
254
255   if(!buf) {
256     snprintf(msg, MSG_LENGTH_MAX, "(NULL)");
257   }
258   else {
259     u_int32_t i;
260     int offset = snprintf(msg, MSG_LENGTH_MAX, "dump(%d): ", len);
261     if(offset < 0)
262       return;
263     char* ptr = &msg[offset];
264
265     for(i=0; i < len; i++) {
266       if(((i+1)*3) >= (MSG_LENGTH_MAX - offset))
267         break;
268       snprintf(ptr, 4, "%02X ", buf[i]);
269       ptr+=3;
270     }
271   }
272   log_targets_log(&stdlog.targets_, prio, msg);
273 }