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