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 #ifndef TCPPROXY_log_targets_h_INCLUDED
29 #define TCPPROXY_log_targets_h_INCLUDED
30 
31 #include <time.h>
32 
get_time_formatted()33 static char* get_time_formatted()
34 {
35   char* time_string;
36   time_t t = time(NULL);
37   if(t < 0)
38     time_string = "<time read error>";
39   else {
40     time_string = ctime(&t);
41     if(!time_string)
42       time_string = "<time format error>";
43     else {
44       char* newline = strchr(time_string, '\n');
45       if(newline)
46         newline[0] = 0;
47     }
48   }
49   return time_string;
50 }
51 
52 #ifndef WINVER
53 enum syslog_facility_enum { USER = LOG_USER, MAIL = LOG_MAIL,
54                             DAEMON = LOG_DAEMON, AUTH = LOG_AUTH,
55                             SYSLOG = LOG_SYSLOG, LPR = LOG_LPR,
56                             NEWS = LOG_NEWS, UUCP = LOG_UUCP,
57                             CRON = LOG_CRON, AUTHPRIV = LOG_AUTHPRIV,
58                             FTP = LOG_FTP, LOCAL0 = LOG_LOCAL0,
59                             LOCAL1 = LOG_LOCAL1, LOCAL2 = LOG_LOCAL2,
60                             LOCAL3 = LOG_LOCAL3, LOCAL4 = LOG_LOCAL4,
61                             LOCAL5 = LOG_LOCAL5, LOCAL6 = LOG_LOCAL6,
62                             LOCAL7 = LOG_LOCAL7 };
63 typedef enum syslog_facility_enum syslog_facility_t;
64 
65 struct log_target_syslog_param_struct {
66   char* logname_;
67   syslog_facility_t facility_;
68 };
69 typedef struct log_target_syslog_param_struct log_target_syslog_param_t;
70 
log_target_syslog_init(log_target_t * self,const char * conf)71 int log_target_syslog_init(log_target_t* self, const char* conf)
72 {
73   if(!self || (conf && conf[0] == 0))
74     return -1;
75 
76   self->param_ = malloc(sizeof(log_target_syslog_param_t));
77   if(!self->param_)
78     return -2;
79 
80   char* logname;
81   const char* end = NULL;
82   if(!conf)
83     logname = strdup("tcpproxy");
84   else {
85     end = strchr(conf, ',');
86     if(end) {
87       size_t len = (size_t)(end - conf);
88       if(!len) {
89         free(self->param_);
90         return -1;
91       }
92       logname = malloc(len+1);
93       if(logname) {
94         strncpy(logname, conf, len);
95         logname[len] = 0;
96       }
97     }
98     else
99       logname = strdup(conf);
100   }
101 
102   if(!logname) {
103     free(self->param_);
104     return -2;
105   }
106   ((log_target_syslog_param_t*)(self->param_))->logname_ = logname;
107 
108   if(!end) {
109     ((log_target_syslog_param_t*)(self->param_))->facility_ = DAEMON;
110     return 0;
111   }
112 
113   if(end[1] == 0 || end[1] == ',') {
114     free(logname);
115     free(self->param_);
116     return -1;
117   }
118 
119   const char* start = end + 1;
120   end = strchr(start, ',');
121   int i;
122   for(i=0;;++i) {
123     if(facilitynames[i].c_name == NULL) {
124       free(logname);
125       free(self->param_);
126       return -1;
127     }
128 
129     if(( end && !strncmp(start, facilitynames[i].c_name, (size_t)(end - start)) && facilitynames[i].c_name[(size_t)(end-start)] == 0) ||
130        (!end && !strcmp(start, facilitynames[i].c_name))) {
131         ((log_target_syslog_param_t*)(self->param_))->facility_ = facilitynames[i].c_val;
132         break;
133     }
134   }
135 
136   return 0;
137 }
138 
log_target_syslog_open(log_target_t * self)139 void log_target_syslog_open(log_target_t* self)
140 {
141   if(!self || !self->param_)
142     return;
143 
144   openlog(((log_target_syslog_param_t*)(self->param_))->logname_, LOG_PID, ((log_target_syslog_param_t*)(self->param_))->facility_);
145   self->opened_ = 1;
146 }
147 
log_target_syslog_log(log_target_t * self,log_prio_t prio,const char * msg)148 void log_target_syslog_log(log_target_t* self, log_prio_t prio, const char* msg)
149 {
150   if(!self || !self->param_ || !self->opened_)
151     return;
152 
153   syslog((prio + 2) | ((log_target_syslog_param_t*)(self->param_))->facility_, "%s", msg);
154 }
155 
log_target_syslog_close(log_target_t * self)156 void log_target_syslog_close(log_target_t* self)
157 {
158   closelog();
159   self->opened_ = 0;
160 }
161 
log_target_syslog_clear(log_target_t * self)162 void log_target_syslog_clear(log_target_t* self)
163 {
164   if(!self || !self->param_)
165     return;
166 
167   if(((log_target_syslog_param_t*)(self->param_))->logname_)
168     free(((log_target_syslog_param_t*)(self->param_))->logname_);
169 
170   free(self->param_);
171 }
172 
log_target_syslog_new()173 log_target_t* log_target_syslog_new()
174 {
175   log_target_t* tmp = malloc(sizeof(log_target_t));
176   if(!tmp)
177     return NULL;
178 
179   tmp->type_ = TARGET_SYSLOG;
180   tmp->init = &log_target_syslog_init;
181   tmp->open = &log_target_syslog_open;
182   tmp->log = &log_target_syslog_log;
183   tmp->close = &log_target_syslog_close;
184   tmp->clear = &log_target_syslog_clear;
185   tmp->opened_ = 0;
186   tmp->enabled_ = 0;
187   tmp->max_prio_ = NOTICE;
188   tmp->param_ = NULL;
189   tmp->next_ = NULL;
190 
191   return tmp;
192 }
193 #endif
194 
195 struct log_target_file_param_struct {
196   char* logfilename_;
197   FILE* file_;
198 };
199 typedef struct log_target_file_param_struct log_target_file_param_t;
200 
log_target_file_init(log_target_t * self,const char * conf)201 int log_target_file_init(log_target_t* self, const char* conf)
202 {
203   if(!self || (conf && conf[0] == 0))
204     return -1;
205 
206   self->param_ = malloc(sizeof(log_target_file_param_t));
207   if(!self->param_)
208     return -2;
209 
210   char* logfilename;
211   if(!conf)
212     logfilename = strdup("tcpproxy.log");
213   else {
214     const char* end = strchr(conf, ',');
215     if(end) {
216       size_t len = (size_t)(end - conf);
217       if(!len) {
218         free(self->param_);
219         return -1;
220       }
221       logfilename = malloc(len+1);
222       if(logfilename) {
223         strncpy(logfilename, conf, len);
224         logfilename[len] = 0;
225       }
226     }
227     else
228       logfilename = strdup(conf);
229   }
230 
231   if(!logfilename) {
232     free(self->param_);
233     return -2;
234   }
235   ((log_target_file_param_t*)(self->param_))->logfilename_ = logfilename;
236   ((log_target_file_param_t*)(self->param_))->file_ = NULL;
237 
238   return 0;
239 }
240 
log_target_file_open(log_target_t * self)241 void log_target_file_open(log_target_t* self)
242 {
243   if(!self || !self->param_)
244     return;
245 
246   ((log_target_file_param_t*)(self->param_))->file_ = fopen(((log_target_file_param_t*)(self->param_))->logfilename_, "w");
247   if(((log_target_file_param_t*)(self->param_))->file_)
248     self->opened_ = 1;
249 }
250 
log_target_file_log(log_target_t * self,log_prio_t prio,const char * msg)251 void log_target_file_log(log_target_t* self, log_prio_t prio, const char* msg)
252 {
253   if(!self || !self->param_ || !self->opened_)
254     return;
255 
256   fprintf(((log_target_file_param_t*)(self->param_))->file_, "%s %s: %s\n", get_time_formatted(), log_prio_to_string(prio), msg);
257   fflush(((log_target_file_param_t*)(self->param_))->file_);
258 }
259 
log_target_file_close(log_target_t * self)260 void log_target_file_close(log_target_t* self)
261 {
262   if(!self || !self->param_)
263     return;
264 
265   fclose(((log_target_file_param_t*)(self->param_))->file_);
266   self->opened_ = 0;
267 }
268 
log_target_file_clear(log_target_t * self)269 void log_target_file_clear(log_target_t* self)
270 {
271   if(!self || !self->param_)
272     return;
273 
274   if(((log_target_file_param_t*)(self->param_))->logfilename_)
275     free(((log_target_file_param_t*)(self->param_))->logfilename_);
276 
277   free(self->param_);
278 }
279 
280 
log_target_file_new()281 log_target_t* log_target_file_new()
282 {
283   log_target_t* tmp = malloc(sizeof(log_target_t));
284   if(!tmp)
285     return NULL;
286 
287   tmp->type_ = TARGET_FILE;
288   tmp->init = &log_target_file_init;
289   tmp->open = &log_target_file_open;
290   tmp->log = &log_target_file_log;
291   tmp->close = &log_target_file_close;
292   tmp->clear = &log_target_file_clear;
293   tmp->opened_ = 0;
294   tmp->enabled_ = 0;
295   tmp->max_prio_ = NOTICE;
296   tmp->param_ = NULL;
297   tmp->next_ = NULL;
298 
299   return tmp;
300 }
301 
302 
log_target_stdout_log(log_target_t * self,log_prio_t prio,const char * msg)303 void log_target_stdout_log(log_target_t* self, log_prio_t prio, const char* msg)
304 {
305   printf("%s %s: %s\n", get_time_formatted(), log_prio_to_string(prio), msg);
306 }
307 
log_target_stdout_new()308 log_target_t* log_target_stdout_new()
309 {
310   log_target_t* tmp = malloc(sizeof(log_target_t));
311   if(!tmp)
312     return NULL;
313 
314   tmp->type_ = TARGET_STDOUT;
315   tmp->init = NULL;
316   tmp->open = NULL;
317   tmp->log = &log_target_stdout_log;
318   tmp->close = NULL;
319   tmp->clear = NULL;
320   tmp->opened_ = 0;
321   tmp->enabled_ = 0;
322   tmp->max_prio_ = NOTICE;
323   tmp->param_ = NULL;
324   tmp->next_ = NULL;
325 
326   return tmp;
327 }
328 
329 
log_target_stderr_log(log_target_t * self,log_prio_t prio,const char * msg)330 void log_target_stderr_log(log_target_t* self, log_prio_t prio, const char* msg)
331 {
332   fprintf(stderr, "%s %s: %s\n", get_time_formatted(), log_prio_to_string(prio), msg);
333 }
334 
log_target_stderr_new()335 log_target_t* log_target_stderr_new()
336 {
337   log_target_t* tmp = malloc(sizeof(log_target_t));
338   if(!tmp)
339     return NULL;
340 
341   tmp->type_ = TARGET_STDERR;
342   tmp->init = NULL;
343   tmp->open = NULL;
344   tmp->log = &log_target_stderr_log;
345   tmp->close = NULL;
346   tmp->clear = NULL;
347   tmp->opened_ = 0;
348   tmp->enabled_ = 0;
349   tmp->max_prio_ = NOTICE;
350   tmp->param_ = NULL;
351   tmp->next_ = NULL;
352 
353   return tmp;
354 }
355 
356 #endif
357