miniupnpd 1.9 (20160113)
[tomato.git] / release / src / router / miniupnpd / upnppinhole.c
blob932bc11ecaa4c2db04fc72d0509bff6bfe94eefa
1 /* $Id: upnppinhole.c,v 1.7 2014/12/09 09:13:53 nanard Exp $ */
2 /* MiniUPnP project
3 * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
4 * (c) 2006-2012 Thomas Bernard
5 * This software is subject to the conditions detailed
6 * in the LICENCE file provided within the distribution */
8 #include <stdlib.h>
9 #include <string.h>
10 #include <syslog.h>
11 #include <sys/types.h>
12 #include <sys/socket.h>
13 #include <netinet/in.h>
14 #include <net/if.h>
15 #include <arpa/inet.h>
17 #include <stdio.h>
18 #include <ctype.h>
19 #include <unistd.h>
21 #include "macros.h"
22 #include "config.h"
23 #include "upnpredirect.h"
24 #include "upnpglobalvars.h"
25 #include "upnpevents.h"
26 #include "upnppinhole.h"
27 #ifdef __APPLE__
28 /* XXX - Apple version of PF API seems to differ from what
29 * pf/pfpinhole.c expects so don't use that at least.. */
30 #ifdef USE_PF
31 #undef USE_PF
32 #endif /* USE_PF */
33 #endif /* __APPLE__ */
34 #if defined(USE_NETFILTER)
35 #include "netfilter/iptpinhole.h"
36 #endif
37 #if defined(USE_PF)
38 #include "pf/pfpinhole.h"
39 #endif
40 #if defined(USE_IPF)
41 #endif
42 #if defined(USE_IPFW)
43 #endif
45 #ifdef ENABLE_UPNPPINHOLE
47 #if 0
48 int
49 upnp_check_outbound_pinhole(int proto, int * timeout)
51 int s, tmptimeout, tmptime_out;
52 switch(proto)
54 case IPPROTO_UDP:
55 s = retrieve_timeout("udp_timeout", timeout);
56 return s;
57 break;
58 case IPPROTO_UDPLITE:
59 s = retrieve_timeout("udp_timeout_stream", timeout);
60 return s;
61 break;
62 case IPPROTO_TCP:
63 s = retrieve_timeout("tcp_timeout_established", timeout);
64 return s;
65 break;
66 case 65535:
67 s = retrieve_timeout("udp_timeout", timeout);
68 s = retrieve_timeout("udp_timeout_stream", &tmptimeout);
69 s = retrieve_timeout("tcp_timeout_established", &tmptime_out);
70 if(tmptimeout<tmptime_out)
72 if(tmptimeout<*timeout)
73 *timeout = tmptimeout;
75 else
77 if(tmptime_out<*timeout)
78 *timeout = tmptimeout;
80 return s;
81 break;
82 default:
83 return -5;
84 break;
86 return 0;
88 #endif
90 /* upnp_add_inboundpinhole()
91 * returns: 1 on success
92 * -1 Pinhole space exhausted
93 * -4 invalid arguments
94 * -42 not implemented
95 * TODO : return uid on success (positive) or error value (negative)
97 int
98 upnp_add_inboundpinhole(const char * raddr,
99 unsigned short rport,
100 const char * iaddr,
101 unsigned short iport,
102 int proto,
103 char * desc,
104 unsigned int leasetime,
105 int * uid)
107 int r;
108 time_t current;
109 unsigned int timestamp;
110 struct in6_addr address;
112 r = inet_pton(AF_INET6, iaddr, &address);
113 if(r <= 0) {
114 syslog(LOG_ERR, "inet_pton(%d, %s, %p) FAILED",
115 AF_INET6, iaddr, &address);
116 return -4;
118 current = time(NULL);
119 timestamp = current + leasetime;
120 r = 0;
122 #if 0
123 if(r == 1 && strcmp(iaddr, iaddr_old)==0 && iport==iport_old)
125 syslog(LOG_INFO, "Pinhole for inbound traffic from [%s]:%hu to [%s]:%hu with protocol %s already done. Updating it.", raddr, rport, iaddr_old, iport_old, protocol);
126 t = upnp_update_inboundpinhole(idfound, leaseTime);
127 *uid = atoi(idfound);
128 return t;
130 else
131 #endif
132 #if defined(USE_PF) || defined(USE_NETFILTER)
133 *uid = add_pinhole (0/*ext_if_name*/, raddr, rport,
134 iaddr, iport, proto, desc, timestamp);
135 return *uid >= 0 ? 1 : -1;
136 #else
137 return -42; /* not implemented */
138 #endif
141 #if 0
143 upnp_add_inboundpinhole_internal(const char * raddr, unsigned short rport,
144 const char * iaddr, unsigned short iport,
145 const char * proto, int * uid)
147 int c = 9999;
148 char cmd[256], cmd_raw[256], cuid[42];
149 #if 0
150 static const char cmdval_full_udptcp[] = "ip6tables -I %s %d -p %s -i %s -s %s --sport %hu -d %s --dport %hu -j ACCEPT";
151 static const char cmdval_udptcp[] = "ip6tables -I %s %d -p %s -i %s --sport %hu -d %s --dport %hu -j ACCEPT";
152 static const char cmdval_full_udplite[] = "ip6tables -I %s %d -p %s -i %s -s %s -d %s -j ACCEPT";
153 static const char cmdval_udplite[] = "ip6tables -I %s %d -p %s -i %s -d %s -j ACCEPT";
154 // raw table command
155 static const char cmdval_full_udptcp_raw[] = "ip6tables -t raw -I PREROUTING %d -p %s -i %s -s %s --sport %hu -d %s --dport %hu -j TRACE";
156 static const char cmdval_udptcp_raw[] = "ip6tables -t raw -I PREROUTING %d -p %s -i %s --sport %hu -d %s --dport %hu -j TRACE";
157 static const char cmdval_full_udplite_raw[] = "ip6tables -t raw -I PREROUTING %d -p %s -i %s -s %s -d %s -j TRACE";
158 static const char cmdval_udplite_raw[] = "ip6tables -t raw -I PREROUTING %d -p %s -i %s -d %s -j TRACE";
159 #endif
160 /*printf("%s\n", raddr);*/
161 if(raddr!=NULL)
163 #ifdef IPPROTO_UDPLITE
164 if(atoi(proto) == IPPROTO_UDPLITE)
166 /* snprintf(cmd, sizeof(cmd), cmdval_full_udplite, miniupnpd_forward_chain, line_number, proto, ext_if_name, raddr, iaddr);
167 snprintf(cmd_raw, sizeof(cmd_raw), cmdval_full_udplite_raw, line_number, proto, ext_if_name, raddr, iaddr);*/
169 else
170 #endif
172 /* snprintf(cmd, sizeof(cmd), cmdval_full_udptcp, miniupnpd_forward_chain, line_number, proto, ext_if_name, raddr, rport, iaddr, iport);
173 snprintf(cmd_raw, sizeof(cmd_raw), cmdval_full_udptcp_raw, line_number, proto, ext_if_name, raddr, rport, iaddr, iport);*/
176 else
178 #ifdef IPPROTO_UDPLITE
179 if(atoi(proto) == IPPROTO_UDPLITE)
181 /*snprintf(cmd, sizeof(cmd), cmdval_udplite, miniupnpd_forward_chain, line_number, proto, ext_if_name, iaddr);
182 snprintf(cmd_raw, sizeof(cmd_raw), cmdval_udplite_raw, line_number, proto, ext_if_name, iaddr);*/
184 else
185 #endif
187 /*snprintf(cmd, sizeof(cmd), cmdval_udptcp, miniupnpd_forward_chain, line_number, proto, ext_if_name, rport, iaddr, iport);
188 snprintf(cmd_raw, sizeof(cmd_raw), cmdval_udptcp_raw, line_number, proto, ext_if_name, rport, iaddr, iport);
192 #ifdef DEBUG
193 syslog(LOG_INFO, "Adding following ip6tables rule:");
194 syslog(LOG_INFO, " -> %s", cmd);
195 syslog(LOG_INFO, " -> %s", cmd_raw);
196 #endif
197 /* TODO Add a better checking error.*/
198 if(system(cmd) < 0 || system(cmd_raw) < 0)
200 return 0;
202 srand(time(NULL));
203 snprintf(cuid, sizeof(cuid), "%.4d", rand()%c);
204 *uid = atoi(cuid);
205 printf("\t_add_ uid: %s\n", cuid);
206 return 1;
208 #endif
210 /* upnp_get_pinhole_info()
211 * return values :
212 * 0 OK
213 * -1 Internal error
214 * -2 NOT FOUND (no such entry)
215 * ..
216 * -42 Not implemented
219 upnp_get_pinhole_info(unsigned short uid,
220 char * raddr, int raddrlen,
221 unsigned short * rport,
222 char * iaddr, int iaddrlen,
223 unsigned short * iport,
224 int * proto, char * desc, int desclen,
225 unsigned int * leasetime,
226 unsigned int * packets)
228 /* Call Firewall specific code to get IPv6 pinhole infos */
229 #if defined(USE_PF) || defined(USE_NETFILTER)
230 int r;
231 unsigned int timestamp;
232 u_int64_t packets_tmp;
233 /*u_int64_t bytes_tmp;*/
235 r = get_pinhole_info(uid, raddr, raddrlen, rport,
236 iaddr, iaddrlen, iport,
237 proto, desc, desclen,
238 leasetime ? &timestamp : NULL,
239 packets ? &packets_tmp : NULL,
240 NULL/*&bytes_tmp*/);
241 if(r >= 0) {
242 if(leasetime) {
243 time_t current_time;
244 current_time = time(NULL);
245 if(timestamp > (unsigned int)current_time)
246 *leasetime = timestamp - current_time;
247 else
248 *leasetime = 0;
250 if(packets)
251 *packets = (unsigned int)packets_tmp;
253 return r;
254 #else
255 UNUSED(uid);
256 UNUSED(raddr); UNUSED(raddrlen); UNUSED(rport);
257 UNUSED(iaddr); UNUSED(iaddrlen); UNUSED(iport);
258 UNUSED(proto); UNUSED(desc); UNUSED(desclen);
259 UNUSED(leasetime); UNUSED(packets);
260 return -42; /* not implemented */
261 #endif
265 upnp_get_pinhole_uid_by_index(int index)
267 #if defined (USE_NETFILTER)
268 return get_pinhole_uid_by_index(index);
269 #else
270 UNUSED(index);
271 return -42;
272 #endif /* defined (USE_NETFILTER) */
276 upnp_update_inboundpinhole(unsigned short uid, unsigned int leasetime)
278 #if defined(USE_PF) || defined(USE_NETFILTER)
279 unsigned int timestamp;
281 timestamp = time(NULL) + leasetime;
282 return update_pinhole(uid, timestamp);
283 #else
284 UNUSED(uid); UNUSED(leasetime);
286 return -42; /* not implemented */
287 #endif
291 upnp_delete_inboundpinhole(unsigned short uid)
293 #if defined(USE_PF) || defined(USE_NETFILTER)
294 return delete_pinhole(uid);
295 #else
296 UNUSED(uid);
298 return -1;
299 #endif
302 #if 0
304 * Result:
305 * 1: Found Result
306 * -4: No result
307 * -5: Result in another table
308 * -6: Result in another chain
309 * -7: Result in a chain not a rule
312 upnp_check_pinhole_working(const char * uid,
313 char * eaddr,
314 char * iaddr,
315 unsigned short * eport,
316 unsigned short * iport,
317 char * protocol,
318 int * rulenum_used)
320 /* TODO : to be implemented */
321 #if 0
322 FILE * fd;
323 time_t expire = time(NULL);
324 char buf[1024], filename[] = "/var/log/kern.log", expire_time[32]="";
325 int res = -4, str_len;
327 str_len = strftime(expire_time, sizeof(expire_time), "%b %d %H:%M:%S", localtime(&expire));
329 fd = fopen(filename, "r");
330 if (fd==NULL)
332 syslog(LOG_ERR, "Get_rule: could not open file: %s", filename);
333 return -1;
336 syslog(LOG_INFO, "Get_rule: Starting getting info in file %s for %s\n", filename, uid);
337 buf[sizeof(buf)-1] = 0;
338 while(fgets(buf, sizeof(buf)-1, fd) != NULL && res != 1)
340 //printf("line: %s\n", buf);
341 char * r, * t, * c, * p;
342 // looking for something like filter:FORWARD:rule: or filter:MINIUPNPD:rule:
343 r = strstr(buf, ":rule:");
344 p = strstr(buf, ":policy:");
345 t = strstr(buf, "TRACE:"); // table pointeur
346 t += 7;
347 c = t + 7; // chain pointeur
348 if(r)
350 printf("\t** Found %.*s\n", 24 ,t);
351 char * src, * dst, * sport, * dport, * proto, * line;
352 char time[15]="", src_addr[40], dst_addr[40], proto_tmp[8];
353 int proto_int;
354 strncpy(time, buf, sizeof(time));
355 /*if(compare_time(time, expire_time)<0)
357 printf("\t\tNot corresponding time\n");
358 continue;
361 line = r + 6;
362 printf("\trule line = %d\n", atoi(line));
364 src = strstr(buf, "SRC=");
365 src += 4;
366 snprintf(src_addr, sizeof(src_addr), "%.*s", 39, src);
367 #if 0
368 del_char(src_addr);
369 add_char(src_addr);
370 #endif
372 dst = strstr(buf, "DST=");
373 dst += 4;
374 snprintf(dst_addr, sizeof(dst_addr), "%.*s", 39, dst);
375 #if 0
376 del_char(dst_addr);
377 add_char(dst_addr);
378 #endif
380 proto = strstr(buf, "PROTO=");
381 proto += 6;
382 proto_int = atoi(protocol);
383 if(proto_int == IPPROTO_UDP)
384 strcpy(proto_tmp, "UDP");
385 else if(proto_int == IPPROTO_TCP)
386 strcpy(proto_tmp, "TCP");
387 #ifdef IPPROTO_UDPLITE
388 else if(proto_int == IPPROTO_UDPLITE)
389 strcpy(proto_tmp, "UDPLITE");
390 #endif
391 else
392 strcpy(proto_tmp, "UnsupportedProto");
394 // printf("\tCompare eaddr: %s // protocol: %s\n\t to addr: %s // protocol: %.*s\n", eaddr, proto_tmp, src_addr, strlen(proto_tmp), proto);
395 // printf("\tCompare iaddr: %s // protocol: %s\n\t to addr: %s // protocol: %.*s\n", iaddr, proto_tmp, dst_addr, strlen(proto_tmp), proto);
396 // TODO Check time
397 // Check that the paquet found in trace correspond to the one we are looking for
398 if( /*(strcmp(eaddr, src_addr) == 0) &&*/ (strcmp(iaddr, dst_addr) == 0) && (strncmp(proto_tmp, proto, strlen(proto_tmp))==0))
400 sport = strstr(buf, "SPT=");
401 sport += 4;
402 dport = strstr(buf, "DPT=");
403 dport += 4;
404 printf("\tCompare eport: %hu\n\t to port: %d\n", *eport, atoi(sport));
405 printf("\tCompare iport: %hu\n\t to port: %d\n", *iport, atoi(dport));
406 if(/*eport != atoi(sport) &&*/ *iport != atoi(dport))
408 printf("\t\tPort not corresponding\n");
409 continue;
411 printf("\ttable found: %.*s\n", 6, t);
412 printf("\tchain found: %.*s\n", 9, c);
413 // Check that the table correspond to the filter table
414 if(strncmp(t, "filter", 6)==0)
416 // Check that the table correspond to the MINIUPNP table
417 if(strncmp(c, "MINIUPNPD", 9)==0)
419 *rulenum_used = atoi(line);
420 res = 1;
422 else
424 res = -6;
425 continue;
428 else
430 res = -5;
431 continue;
434 else
436 printf("Packet information not corresponding\n");
437 continue;
440 if(!r && p)
442 printf("\t** Policy case\n");
443 char * src, * dst, * sport, * dport, * proto, * line;
444 char time[15], src_addr[40], dst_addr[40], proto_tmp[8];
445 int proto_int;
446 strncpy(time, buf, sizeof(time));
447 /*if(compare_time(time, expire_time)<0)
449 printf("\t\tNot corresponding time\n");
450 continue;
453 line = p + 8;
454 printf("\trule line = %d\n", atoi(line));
456 src = strstr(buf, "SRC=");
457 src += 4;
458 snprintf(src_addr, sizeof(src_addr), "%.*s", 39, src);
459 #if 0
460 del_char(src_addr);
461 add_char(src_addr);
462 #endif
464 dst = strstr(buf, "DST=");
465 dst += 4;
466 snprintf(dst_addr, sizeof(dst_addr), "%.*s", 39, dst);
467 #if 0
468 del_char(dst_addr);
469 add_char(dst_addr);
470 #endif
472 proto = strstr(buf, "PROTO=");
473 proto += 6;
474 proto_int = atoi(protocol);
475 if(proto_int == IPPROTO_UDP)
476 strcpy(proto_tmp, "UDP");
477 else if(proto_int == IPPROTO_TCP)
478 strcpy(proto_tmp, "TCP");
479 #ifdef IPPROTO_UDPLITE
480 else if(proto_int == IPPROTO_UDPLITE)
481 strcpy(proto_tmp, "UDPLITE");
482 #endif
483 else
484 strcpy(proto_tmp, "UnsupportedProto");
486 // printf("\tCompare eaddr: %s // protocol: %s\n\t to addr: %s // protocol: %.*s\n", eaddr, proto_tmp, src_addr, strlen(proto_tmp), proto);
487 // printf("\tCompare iaddr: %s // protocol: %s\n\t to addr: %s // protocol: %.*s\n", iaddr, proto_tmp, dst_addr, strlen(proto_tmp), proto);
488 // Check that the paquet found in trace correspond to the one we are looking for
489 if( (strcmp(eaddr, src_addr) == 0) && (strcmp(iaddr, dst_addr) == 0) && (strncmp(proto_tmp, proto, 5)==0))
491 sport = strstr(buf, "SPT=");
492 sport += 4;
493 dport = strstr(buf, "DPT=");
494 dport += 4;
495 printf("\tCompare eport: %hu\n\t to port: %d\n", *eport, atoi(sport));
496 printf("\tCompare iport: %hu\n\t to port: %d\n", *iport, atoi(dport));
497 if(*eport != atoi(sport) && *iport != atoi(dport))
499 printf("\t\tPort not corresponding\n");
500 continue;
502 else
504 printf("Find a corresponding policy trace in the chain: %.*s\n", 10, c);
505 res = -7;
506 continue;
509 else
510 continue;
513 fclose(fd);
514 return res;
515 #else
516 return -42; /* to be implemented */
517 #endif
519 #endif
522 upnp_clean_expired_pinholes(unsigned int * next_timestamp)
524 #if defined(USE_PF) || defined(USE_NETFILTER)
525 return clean_pinhole_list(next_timestamp);
526 #else
527 UNUSED(next_timestamp);
529 return 0; /* nothing to do */
530 #endif
533 #endif /* ENABLE_UPNPPINHOLE */