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