Merge commit 'upstream/0.3.2'
[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 methodes 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-2008 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
36 #include "datatypes.h"
37
38 #include <string.h>
39 #include <stdarg.h>
40 #include <stdlib.h>
41 #include <stdio.h>
42
43 #define SYSLOG_NAMES
44 #include <syslog.h>
45
46 #include "log.h"
47
48 log_t stdlog;
49
50 #include "log_targets.h"
51
52 const char* log_prio_to_string(log_prio_t prio)
53 {
54   switch(prio) {
55   case ERROR: return "ERROR";
56   case WARNING: return "WARNING";
57   case NOTICE: return "NOTICE";
58   case INFO: return "INFO";
59   case DEBUG: return "DEBUG";
60   }
61   return "UNKNOWN";
62 }
63
64 log_target_type_t log_target_parse_type(const char* conf)
65 {
66   if(!conf)
67     return TARGET_UNKNOWN;
68
69   if(!strncmp(conf, "syslog", 6)) return TARGET_SYSLOG;
70   if(!strncmp(conf, "file", 4)) return TARGET_FILE;
71   if(!strncmp(conf, "stdout", 6)) return TARGET_STDOUT;
72   if(!strncmp(conf, "stderr", 6)) return TARGET_STDERR;
73
74   return TARGET_UNKNOWN;
75 }
76
77 int log_targets_target_exists(log_targets_t* targets, log_target_type_t type)
78 {
79   if(!targets && !targets->first_)
80     return 0;
81
82   log_target_t* tmp = targets->first_;
83   while(tmp) {
84     if(tmp->type_ == type)
85       return 1;
86     tmp = tmp->next_;
87   }  
88   return 0;
89 }
90
91 int log_targets_add(log_targets_t* targets, const char* conf)
92 {
93   if(!targets)
94     return -1;
95
96   log_target_t* new_target = NULL;
97   int duplicates_allowed = 0;
98   switch(log_target_parse_type(conf)) {
99   case TARGET_SYSLOG: new_target = log_target_syslog_new(); break;
100   case TARGET_FILE: new_target = log_target_file_new(); duplicates_allowed = 1; break;
101   case TARGET_STDOUT: new_target = log_target_stdout_new(); break;
102   case TARGET_STDERR: new_target = log_target_stderr_new(); break;
103   default: return -3;
104   }
105   if(!new_target)
106     return -2;
107
108   if(!duplicates_allowed && log_targets_target_exists(targets, new_target->type_)) {
109     free(new_target);
110     return -4;
111   }
112
113   const char* prioptr = strchr(conf, ':');
114   if(!prioptr || prioptr[1] == 0) {
115     free(new_target);
116     return -1;
117   }
118   prioptr++;
119   if(!isdigit(prioptr[0]) || (prioptr[1] != 0 && prioptr[1] != ',')) {
120     free(new_target);
121     return -1;
122   }
123   new_target->max_prio_ = prioptr[0] - '0';
124   if(new_target->max_prio_ > 0)
125     new_target->enabled_ = 1;
126
127   if(new_target->init != NULL) {
128     const char* confptr = NULL;
129     if(prioptr[1] != 0)
130       confptr = prioptr+2;
131
132     int ret = (*new_target->init)(new_target, confptr);
133     if(ret) {
134       free(new_target);
135       return ret;
136     }
137   }
138
139   if(new_target->open != NULL)
140     (*new_target->open)(new_target);
141
142
143   if(!targets->first_) {
144     targets->first_ = new_target;
145   }
146   else {
147     log_target_t* tmp = targets->first_;
148     while(tmp->next_)
149       tmp = tmp->next_;
150     
151     tmp->next_ = new_target;
152   }
153   return 0;
154 }
155
156 void log_targets_log(log_targets_t* targets, log_prio_t prio, const char* msg)
157 {
158   if(!targets)
159     return;
160
161   log_target_t* tmp = targets->first_;
162   while(tmp) {
163     if(tmp->log != NULL && tmp->enabled_ && tmp->max_prio_ >= prio)
164       (*tmp->log)(tmp, prio, msg);
165
166     tmp = tmp->next_;
167   }
168 }
169
170 void log_targets_clear(log_targets_t* targets)
171 {
172   if(!targets)
173     return;
174
175   while(targets->first_) {
176     log_target_t* tmp = targets->first_;
177     targets->first_ = tmp->next_;
178     if(tmp->close != NULL)
179       (*tmp->close)(tmp);
180     if(tmp->clear != NULL)
181       (*tmp->clear)(tmp);
182     free(tmp);
183   }
184 }
185
186
187 void log_init()
188 {
189   stdlog.max_prio_ = 0;
190   stdlog.targets_.first_ = NULL;
191 }
192
193 void log_close()
194 {
195   log_targets_clear(&stdlog.targets_);
196 }
197
198 void update_max_prio()
199 {
200   log_target_t* tmp = stdlog.targets_.first_;
201   while(tmp) {
202     if(tmp->enabled_ && tmp->max_prio_ > stdlog.max_prio_)
203       stdlog.max_prio_ = tmp->max_prio_;
204
205     tmp = tmp->next_;
206   }
207 }
208
209 int log_add_target(const char* conf)
210 {
211   if(!conf)
212     return -1;
213
214   int ret = log_targets_add(&stdlog.targets_, conf);
215   if(!ret) update_max_prio();
216   return ret;
217 }
218
219 void log_printf(log_prio_t prio, const char* fmt, ...)
220 {
221   if(stdlog.max_prio_ < prio)
222     return;
223
224   static char msg[MSG_LENGTH_MAX];
225   va_list args;
226
227   va_start(args, fmt);
228   vsnprintf(msg, MSG_LENGTH_MAX, fmt, args);
229   va_end(args);
230
231   log_targets_log(&stdlog.targets_, prio, msg);
232 }
233
234 void log_print_hex_dump(log_prio_t prio, const u_int8_t* buf, u_int32_t len)
235 {
236   if(stdlog.max_prio_ < prio)
237     return;
238
239   static char msg[MSG_LENGTH_MAX];
240
241   if(!buf) {
242     snprintf(msg, MSG_LENGTH_MAX, "(NULL)");
243   }
244   else {
245     u_int32_t i;
246     int offset = snprintf(msg, MSG_LENGTH_MAX, "dump(%d): ", len);
247     if(offset < 0)
248       return;
249     u_int8_t* ptr = &msg[offset];
250     
251     for(i=0; i < len; i++) {
252       if(((i+1)*3) >= (MSG_LENGTH_MAX - offset))
253         break;
254       snprintf(ptr, 3, "%02X ", buf[i]);
255       ptr+=3;
256     }
257   }
258   log_targets_log(&stdlog.targets_, prio, msg);
259 }