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