Add PPTP runtime and GUI
[tomato.git] / release / src / router / miniupnpd / upnpredirect.c
blob9b21c400bc54bc1932982fa839f81ca09d805f9e
1 /* $Id: upnpredirect.c,v 1.60 2011/06/22 20:34:39 nanard Exp $ */
2 /* MiniUPnP project
3 * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
4 * (c) 2006-2011 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 "config.h"
22 #include "upnpredirect.h"
23 #include "upnpglobalvars.h"
24 #include "upnpevents.h"
25 #if defined(USE_NETFILTER)
26 #include "netfilter/iptcrdr.h"
27 #endif
28 #if defined(USE_PF)
29 #include "pf/obsdrdr.h"
30 #endif
31 #if defined(USE_IPF)
32 #include "ipf/ipfrdr.h"
33 #endif
34 #if defined(USE_IPFW)
35 #include "ipfw/ipfwrdr.h"
36 #endif
37 #ifdef USE_MINIUPNPDCTL
38 #include <stdio.h>
39 #include <unistd.h>
40 #endif
41 #ifdef ENABLE_LEASEFILE
42 #include <sys/stat.h>
43 #endif
45 /* from <inttypes.h> */
46 #ifndef PRIu64
47 #define PRIu64 "llu"
48 #endif
50 /* proto_atoi()
51 * convert the string "UDP" or "TCP" to IPPROTO_UDP and IPPROTO_UDP */
52 static int
53 proto_atoi(const char * protocol)
55 int proto = IPPROTO_TCP;
56 if(strcmp(protocol, "UDP") == 0)
57 proto = IPPROTO_UDP;
58 return proto;
61 #ifdef ENABLE_LEASEFILE
62 static int
63 lease_file_add(unsigned short eport,
64 const char * iaddr,
65 unsigned short iport,
66 int proto,
67 const char * desc,
68 unsigned int timestamp)
70 FILE * fd;
72 if (lease_file == NULL) return 0;
74 fd = fopen( lease_file, "a");
75 if (fd==NULL) {
76 syslog(LOG_ERR, "could not open lease file: %s", lease_file);
77 return -1;
80 fprintf(fd, "%s:%hu:%s:%hu:%u:%s\n",
81 ((proto==IPPROTO_TCP)?"TCP":"UDP"), eport, iaddr, iport,
82 timestamp, desc);
83 fclose(fd);
85 return 0;
88 static int
89 lease_file_remove(unsigned short eport, int proto)
91 FILE* fd, *fdt;
92 int tmp;
93 char buf[512];
94 char str[32];
95 char tmpfilename[128];
96 int str_size, buf_size;
99 if (lease_file == NULL) return 0;
101 if (strlen( lease_file) + 7 > sizeof(tmpfilename)) {
102 syslog(LOG_ERR, "Lease filename is too long");
103 return -1;
106 strncpy( tmpfilename, lease_file, sizeof(tmpfilename) );
107 strncat( tmpfilename, "XXXXXX", sizeof(tmpfilename) - strlen(tmpfilename));
109 fd = fopen( lease_file, "r");
110 if (fd==NULL) {
111 return 0;
114 snprintf( str, sizeof(str), "%s:%u", ((proto==IPPROTO_TCP)?"TCP":"UDP"), eport);
115 str_size = strlen(str);
117 tmp = mkstemp(tmpfilename);
118 if (tmp==-1) {
119 fclose(fd);
120 syslog(LOG_ERR, "could not open temporary lease file");
121 return -1;
123 fchmod(tmp, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
124 fdt = fdopen(tmp, "a");
126 buf[sizeof(buf)-1] = 0;
127 while( fgets(buf, sizeof(buf)-1, fd) != NULL) {
128 buf_size = strlen(buf);
130 if (buf_size < str_size || strncmp(str, buf, str_size)!=0) {
131 fwrite(buf, buf_size, 1, fdt);
134 fclose(fdt);
135 fclose(fd);
137 if (rename(tmpfilename, lease_file) < 0) {
138 syslog(LOG_ERR, "could not rename temporary lease file to %s", lease_file);
139 remove(tmpfilename);
142 return 0;
146 /* reload_from_lease_file()
147 * read lease_file and add the rules contained
149 int reload_from_lease_file()
151 FILE * fd;
152 char * p;
153 unsigned short eport, iport;
154 char * proto;
155 char * iaddr;
156 char * desc;
157 char * rhost;
158 unsigned int leaseduration;
159 unsigned int timestamp;
160 time_t current_time;
161 char line[128];
162 int r;
164 if(!lease_file) return -1;
165 fd = fopen( lease_file, "r");
166 if (fd==NULL) {
167 syslog(LOG_ERR, "could not open lease file: %s", lease_file);
168 return -1;
170 if(unlink(lease_file) < 0) {
171 syslog(LOG_WARNING, "could not unlink file %s : %m", lease_file);
174 current_time = time(NULL);
175 while(fgets(line, sizeof(line), fd)) {
176 syslog(LOG_DEBUG, "parsing lease file line '%s'", line);
177 proto = line;
178 p = strchr(line, ':');
179 if(!p) {
180 syslog(LOG_ERR, "unrecognized data in lease file");
181 continue;
183 *(p++) = '\0';
184 iaddr = strchr(p, ':');
185 if(!iaddr) {
186 syslog(LOG_ERR, "unrecognized data in lease file");
187 continue;
189 *(iaddr++) = '\0';
190 eport = (unsigned short)atoi(p);
191 p = strchr(iaddr, ':');
192 if(!p) {
193 syslog(LOG_ERR, "unrecognized data in lease file");
194 continue;
196 *(p++) = '\0';
197 timestamp = (unsigned int)atoi(p);
198 p = strchr(p, ':');
199 if(!p) {
200 syslog(LOG_ERR, "unrecognized data in lease file");
201 continue;
203 *(p++) = '\0';
204 desc = strchr(p, ':');
205 if(!desc) {
206 syslog(LOG_ERR, "unrecognized data in lease file");
207 continue;
209 *(desc++) = '\0';
210 iport = (unsigned short)atoi(p);
211 /* trim description */
212 while(isspace(*desc))
213 desc++;
214 p = desc;
215 while(*(p+1))
216 p++;
217 while(isspace(*p) && (p > desc))
218 *(p--) = '\0';
220 if(timestamp > 0) {
221 if(timestamp <= current_time) {
222 syslog(LOG_NOTICE, "already expired lease in lease file");
223 continue;
224 } else {
225 leaseduration = current_time - timestamp;
227 } else {
228 leaseduration = 0; /* default value */
230 rhost = NULL;
231 r = upnp_redirect(rhost, eport, iaddr, iport, proto, desc, leaseduration);
232 if(r == -1) {
233 syslog(LOG_ERR, "Failed to redirect %hu -> %s:%hu protocol %s",
234 eport, iaddr, iport, proto);
235 } else if(r == -2) {
236 /* Add the redirection again to the lease file */
237 lease_file_add(eport, iaddr, iport, proto_atoi(proto),
238 desc, timestamp);
241 fclose(fd);
243 return 0;
245 #endif
247 /* upnp_redirect()
248 * calls OS/fw dependant implementation of the redirection.
249 * protocol should be the string "TCP" or "UDP"
250 * returns: 0 on success
251 * -1 failed to redirect
252 * -2 already redirected
253 * -3 permission check failed
256 upnp_redirect(const char * rhost, unsigned short eport,
257 const char * iaddr, unsigned short iport,
258 const char * protocol, const char * desc,
259 unsigned int leaseduration)
261 int proto, r;
262 char iaddr_old[32];
263 unsigned short iport_old;
264 struct in_addr address;
265 unsigned int timestamp;
267 proto = proto_atoi(protocol);
268 if(inet_aton(iaddr, &address) < 0) {
269 syslog(LOG_ERR, "inet_aton(%s) : %m", iaddr);
270 return -1;
273 if(!check_upnp_rule_against_permissions(upnppermlist, num_upnpperm,
274 eport, address, iport)) {
275 syslog(LOG_INFO, "redirection permission check failed for "
276 "%hu->%s:%hu %s", eport, iaddr, iport, protocol);
277 return -3;
279 r = get_redirect_rule(ext_if_name, eport, proto,
280 iaddr_old, sizeof(iaddr_old), &iport_old, 0, 0,
281 0, 0,
282 &timestamp, 0, 0);
283 if(r == 0) {
284 /* if existing redirect rule matches redirect request return success
285 * xbox 360 does not keep track of the port it redirects and will
286 * redirect another port when receiving ConflictInMappingEntry */
287 if(strcmp(iaddr, iaddr_old)==0 && iport==iport_old) {
288 /* redirection allready exists */
289 syslog(LOG_INFO, "port %hu %s already redirected to %s:%hu, replacing", eport, (proto==IPPROTO_TCP)?"tcp":"udp", iaddr_old, iport_old);
290 /* remove and then add again */
291 if(_upnp_delete_redir(eport, proto) < 0) {
292 syslog(LOG_ERR, "failed to remove port mapping");
293 return 0;
295 } else {
296 syslog(LOG_INFO, "port %hu protocol %s already redirected to %s:%hu",
297 eport, protocol, iaddr_old, iport_old);
298 return -2;
301 timestamp = (leaseduration > 0) ? time(NULL) + leaseduration : 0;
302 syslog(LOG_INFO, "redirecting port %hu to %s:%hu protocol %s for: %s",
303 eport, iaddr, iport, protocol, desc);
304 return upnp_redirect_internal(rhost, eport, iaddr, iport, proto,
305 desc, timestamp);
309 upnp_redirect_internal(const char * rhost, unsigned short eport,
310 const char * iaddr, unsigned short iport,
311 int proto, const char * desc,
312 unsigned int timestamp)
314 /*syslog(LOG_INFO, "redirecting port %hu to %s:%hu protocol %s for: %s",
315 eport, iaddr, iport, protocol, desc); */
316 if(add_redirect_rule2(ext_if_name, rhost, eport, iaddr, iport, proto,
317 desc, timestamp) < 0) {
318 return -1;
321 #ifdef ENABLE_LEASEFILE
322 lease_file_add( eport, iaddr, iport, proto, desc, timestamp);
323 #endif
324 /* syslog(LOG_INFO, "creating pass rule to %s:%hu protocol %s for: %s",
325 iaddr, iport, protocol, desc);*/
326 if(add_filter_rule2(ext_if_name, rhost, iaddr, eport, iport, proto, desc) < 0) {
327 /* clean up the redirect rule */
328 #if !defined(__linux__)
329 delete_redirect_rule(ext_if_name, eport, proto);
330 #endif
331 return -1;
333 if(timestamp > 0) {
334 if(!nextruletoclean_timestamp || (timestamp < nextruletoclean_timestamp))
335 nextruletoclean_timestamp = timestamp;
337 #ifdef ENABLE_EVENTS
338 /* the number of port mappings changed, we must
339 * inform the subscribers */
340 upnp_event_var_change_notify(EWanIPC);
341 #endif
342 return 0;
347 /* Firewall independant code which call the FW dependant code. */
349 upnp_get_redirection_infos(unsigned short eport, const char * protocol,
350 unsigned short * iport,
351 char * iaddr, int iaddrlen,
352 char * desc, int desclen,
353 char * rhost, int rhostlen,
354 unsigned int * leaseduration)
356 int r;
357 unsigned int timestamp;
358 time_t current_time;
360 if(desc && (desclen > 0))
361 desc[0] = '\0';
362 if(rhost && (rhostlen > 0))
363 rhost[0] = '\0';
364 r = get_redirect_rule(ext_if_name, eport, proto_atoi(protocol),
365 iaddr, iaddrlen, iport, desc, desclen,
366 rhost, rhostlen, &timestamp,
367 0, 0);
368 if(r == 0 && timestamp > 0 && timestamp > (current_time = time(NULL))) {
369 *leaseduration = timestamp - current_time;
370 } else {
371 *leaseduration = 0;
373 return r;
377 upnp_get_redirection_infos_by_index(int index,
378 unsigned short * eport, char * protocol,
379 unsigned short * iport,
380 char * iaddr, int iaddrlen,
381 char * desc, int desclen,
382 char * rhost, int rhostlen,
383 unsigned int * leaseduration)
385 /*char ifname[IFNAMSIZ];*/
386 int proto = 0;
387 unsigned int timestamp;
388 time_t current_time;
390 if(desc && (desclen > 0))
391 desc[0] = '\0';
392 if(rhost && (rhost > 0))
393 rhost[0] = '\0';
394 if(get_redirect_rule_by_index(index, 0/*ifname*/, eport, iaddr, iaddrlen,
395 iport, &proto, desc, desclen,
396 rhost, rhostlen, &timestamp,
397 0, 0) < 0)
398 return -1;
399 else
401 current_time = time(NULL);
402 *leaseduration = (timestamp > current_time)
403 ? (timestamp - current_time)
404 : 0;
405 if(proto == IPPROTO_TCP)
406 memcpy(protocol, "TCP", 4);
407 else
408 memcpy(protocol, "UDP", 4);
409 return 0;
413 /* called from natpmp.c too */
415 _upnp_delete_redir(unsigned short eport, int proto)
417 int r;
418 #if defined(__linux__)
419 r = delete_redirect_and_filter_rules(eport, proto);
420 #else
421 r = delete_redirect_rule(ext_if_name, eport, proto);
422 delete_filter_rule(ext_if_name, eport, proto);
423 #endif
424 #ifdef ENABLE_LEASEFILE
425 lease_file_remove( eport, proto);
426 #endif
428 #ifdef ENABLE_EVENTS
429 upnp_event_var_change_notify(EWanIPC);
430 #endif
431 return r;
435 upnp_delete_redirection(unsigned short eport, const char * protocol)
437 syslog(LOG_INFO, "removing redirect rule port %hu %s", eport, protocol);
438 return _upnp_delete_redir(eport, proto_atoi(protocol));
441 /* upnp_get_portmapping_number_of_entries()
442 * TODO: improve this code. */
444 upnp_get_portmapping_number_of_entries()
446 int n = 0, r = 0;
447 unsigned short eport, iport;
448 char protocol[4], iaddr[32], desc[64], rhost[32];
449 unsigned int leaseduration;
450 do {
451 protocol[0] = '\0'; iaddr[0] = '\0'; desc[0] = '\0';
452 r = upnp_get_redirection_infos_by_index(n, &eport, protocol, &iport,
453 iaddr, sizeof(iaddr),
454 desc, sizeof(desc),
455 rhost, sizeof(rhost),
456 &leaseduration);
457 n++;
458 } while(r==0);
459 return (n-1);
462 /* functions used to remove unused rules
463 * As a side effect, delete expired rules (based on LeaseDuration) */
464 struct rule_state *
465 get_upnp_rules_state_list(int max_rules_number_target)
467 /*char ifname[IFNAMSIZ];*/
468 int proto;
469 unsigned short iport;
470 unsigned int timestamp;
471 struct rule_state * tmp;
472 struct rule_state * list = 0;
473 struct rule_state * * p;
474 int i = 0;
475 time_t current_time;
477 /*ifname[0] = '\0';*/
478 tmp = malloc(sizeof(struct rule_state));
479 if(!tmp)
480 return 0;
481 current_time = time(NULL);
482 nextruletoclean_timestamp = 0;
483 while(get_redirect_rule_by_index(i, /*ifname*/0, &tmp->eport, 0, 0,
484 &iport, &proto, 0, 0, 0,0, &timestamp,
485 &tmp->packets, &tmp->bytes) >= 0)
487 tmp->to_remove = 0;
488 if(timestamp > 0) {
489 /* need to remove this port mapping ? */
490 if(timestamp <= current_time)
491 tmp->to_remove = 1;
492 else if((nextruletoclean_timestamp <= current_time)
493 || (timestamp < nextruletoclean_timestamp))
494 nextruletoclean_timestamp = timestamp;
496 tmp->proto = (short)proto;
497 /* add tmp to list */
498 tmp->next = list;
499 list = tmp;
500 /* prepare next iteration */
501 i++;
502 tmp = malloc(sizeof(struct rule_state));
503 if(!tmp)
504 break;
506 free(tmp);
507 /* remove the redirections that need to be removed */
508 for(p = &list, tmp = list; tmp; tmp = *p)
510 if(tmp->to_remove)
512 syslog(LOG_NOTICE, "remove port mapping %hu %s because it has expired",
513 tmp->eport, (tmp->proto==IPPROTO_TCP)?"TCP":"UDP");
514 _upnp_delete_redir(tmp->eport, tmp->proto);
515 *p = tmp->next;
516 free(tmp);
517 i--;
518 } else {
519 p = &(tmp->next);
522 /* return empty list if not enough redirections */
523 if(i<=max_rules_number_target)
524 while(list)
526 tmp = list;
527 list = tmp->next;
528 free(tmp);
530 /* return list */
531 return list;
534 void
535 remove_unused_rules(struct rule_state * list)
537 char ifname[IFNAMSIZ];
538 unsigned short iport;
539 struct rule_state * tmp;
540 u_int64_t packets;
541 u_int64_t bytes;
542 unsigned int timestamp;
543 int n = 0;
545 while(list)
547 /* remove the rule if no traffic has used it */
548 if(get_redirect_rule(ifname, list->eport, list->proto,
549 0, 0, &iport, 0, 0, 0, 0, &timestamp,
550 &packets, &bytes) >= 0)
552 if(packets == list->packets && bytes == list->bytes)
554 if(_upnp_delete_redir(list->eport, list->proto) >= 0)
555 n++;
558 tmp = list;
559 list = tmp->next;
560 free(tmp);
562 if(n>0)
563 syslog(LOG_NOTICE, "removed %d unused rules", n);
566 /* upnp_get_portmappings_in_range()
567 * return a list of all "external" ports for which a port
568 * mapping exists */
569 unsigned short *
570 upnp_get_portmappings_in_range(unsigned short startport,
571 unsigned short endport,
572 const char * protocol,
573 unsigned int * number)
575 int proto;
576 proto = proto_atoi(protocol);
577 if(!number)
578 return NULL;
579 return get_portmappings_in_range(startport, endport, proto, number);
582 #ifdef ENABLE_6FC_SERVICE
584 upnp_check_outbound_pinhole(int proto, int * timeout)
586 #if 0
587 int s, tmptimeout, tmptime_out;
588 switch(proto)
590 case IPPROTO_UDP:
591 s = retrieve_timeout("udp_timeout", timeout);
592 return s;
593 break;
594 case IPPROTO_UDPLITE:
595 s = retrieve_timeout("udp_timeout_stream", timeout);
596 return s;
597 break;
598 case IPPROTO_TCP:
599 s = retrieve_timeout("tcp_timeout_established", timeout);
600 return s;
601 break;
602 case 65535:
603 s = retrieve_timeout("udp_timeout", timeout);
604 s = retrieve_timeout("udp_timeout_stream", &tmptimeout);
605 s = retrieve_timeout("tcp_timeout_established", &tmptime_out);
606 if(tmptimeout<tmptime_out)
608 if(tmptimeout<*timeout)
609 *timeout = tmptimeout;
611 else
613 if(tmptime_out<*timeout)
614 *timeout = tmptimeout;
616 return s;
617 break;
618 default:
619 return -5;
620 break;
622 #endif
623 return 0;
626 /* upnp_add_inboundpinhole()
627 * returns: 0 on success
628 * -1 failed to add pinhole
629 * -2 already created
630 * -3 inbound pinhole disabled
633 upnp_add_inboundpinhole(const char * raddr,
634 unsigned short rport,
635 const char * iaddr,
636 unsigned short iport,
637 const char * protocol,
638 const char * leaseTime,
639 int * uid)
641 int r, s, t, lt=0;
642 char iaddr_old[40]="", proto[6]="", idfound[5]="", leaseTmp[12]; // IPv6 Modification
643 snprintf(proto, sizeof(proto), "%.5d", atoi(protocol));
644 unsigned short iport_old = 0;
645 time_t current = time(NULL);
646 /*struct in6_addr address; // IPv6 Modification
647 if(inet_pton(AF_INET6, iaddr, &address) < 0) // IPv6 Modification
649 syslog(LOG_ERR, "inet_pton(%s) : %m", iaddr);
650 return 0;
653 #if 0
654 r = get_rule_from_file(raddr, rport, iaddr_old, &iport_old, proto, 0, 0, idfound);
655 #endif
656 r = 0;
658 lt = (int) current + atoi(leaseTime);
659 snprintf(leaseTmp, sizeof(leaseTmp), "%d", lt);
660 printf("LeaseTime: %d / %d -> %s\n", atoi(leaseTime), (int)current, leaseTmp);
662 printf("\tCompare addr: %s // port: %d\n\t to addr: %s // port: %d\n", iaddr, iport, iaddr_old, iport_old);
663 if(r == 1 && strcmp(iaddr, iaddr_old)==0 && iport==iport_old)
665 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);
666 t = upnp_update_inboundpinhole(idfound, leaseTime);
667 *uid = atoi(idfound);
668 return t;
670 else
672 syslog(LOG_INFO, "Adding pinhole for inbound traffic from [%s]:%hu to [%s]:%hu with protocol %s and %s lease time.", raddr, rport, iaddr, iport, protocol, leaseTime);
673 s = upnp_add_inboundpinhole_internal(raddr, rport, iaddr, iport, protocol, uid);
674 #if 0
675 if(rule_file_add(raddr, rport, iaddr, iport, protocol, leaseTmp, uid)<0)
676 return -8;
677 else
679 if(nextpinholetoclean_timestamp == 0 || (atoi(leaseTmp) <= nextpinholetoclean_timestamp))
681 printf("Initializing the nextpinholetoclean variables. uid = %d\n", *uid);
682 snprintf(nextpinholetoclean_uid, 5, "%.4d", *uid);
683 nextpinholetoclean_timestamp = atoi(leaseTmp);
685 return s;
687 #endif
689 return 0;
693 upnp_add_inboundpinhole_internal(const char * raddr, unsigned short rport,
694 const char * iaddr, unsigned short iport,
695 const char * proto, int * uid)
697 int c = 9999;
698 char cmd[256], cmd_raw[256], cuid[42];
699 #if 0
700 static const char cmdval_full_udptcp[] = "ip6tables -I %s %d -p %s -i %s -s %s --sport %hu -d %s --dport %hu -j ACCEPT";
701 static const char cmdval_udptcp[] = "ip6tables -I %s %d -p %s -i %s --sport %hu -d %s --dport %hu -j ACCEPT";
702 static const char cmdval_full_udplite[] = "ip6tables -I %s %d -p %s -i %s -s %s -d %s -j ACCEPT";
703 static const char cmdval_udplite[] = "ip6tables -I %s %d -p %s -i %s -d %s -j ACCEPT";
704 // raw table command
705 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";
706 static const char cmdval_udptcp_raw[] = "ip6tables -t raw -I PREROUTING %d -p %s -i %s --sport %hu -d %s --dport %hu -j TRACE";
707 static const char cmdval_full_udplite_raw[] = "ip6tables -t raw -I PREROUTING %d -p %s -i %s -s %s -d %s -j TRACE";
708 static const char cmdval_udplite_raw[] = "ip6tables -t raw -I PREROUTING %d -p %s -i %s -d %s -j TRACE";
709 #endif
710 //printf("%s\n", raddr);
711 if(raddr!=NULL)
713 #ifdef IPPROTO_UDPLITE
714 if(atoi(proto) == IPPROTO_UDPLITE)
716 /* snprintf(cmd, sizeof(cmd), cmdval_full_udplite, miniupnpd_forward_chain, line_number, proto, ext_if_name, raddr, iaddr);
717 snprintf(cmd_raw, sizeof(cmd_raw), cmdval_full_udplite_raw, line_number, proto, ext_if_name, raddr, iaddr);*/
719 else
720 #endif
722 /* snprintf(cmd, sizeof(cmd), cmdval_full_udptcp, miniupnpd_forward_chain, line_number, proto, ext_if_name, raddr, rport, iaddr, iport);
723 snprintf(cmd_raw, sizeof(cmd_raw), cmdval_full_udptcp_raw, line_number, proto, ext_if_name, raddr, rport, iaddr, iport);*/
726 else
728 #ifdef IPPROTO_UDPLITE
729 if(atoi(proto) == IPPROTO_UDPLITE)
731 /*snprintf(cmd, sizeof(cmd), cmdval_udplite, miniupnpd_forward_chain, line_number, proto, ext_if_name, iaddr);
732 snprintf(cmd_raw, sizeof(cmd_raw), cmdval_udplite_raw, line_number, proto, ext_if_name, iaddr);*/
734 else
735 #endif
737 /*snprintf(cmd, sizeof(cmd), cmdval_udptcp, miniupnpd_forward_chain, line_number, proto, ext_if_name, rport, iaddr, iport);
738 snprintf(cmd_raw, sizeof(cmd_raw), cmdval_udptcp_raw, line_number, proto, ext_if_name, rport, iaddr, iport);
742 #ifdef DEBUG
743 syslog(LOG_INFO, "Adding following ip6tables rule:");
744 syslog(LOG_INFO, " -> %s", cmd);
745 syslog(LOG_INFO, " -> %s", cmd_raw);
746 #endif
747 // TODO Add a better checking error.
748 if(system(cmd) < 0 || system(cmd_raw) < 0)
750 return 0;
752 srand(time(NULL));
753 snprintf(cuid, sizeof(cuid), "%.4d", rand()%c);
754 *uid = atoi(cuid);
755 printf("\t_add_ uid: %s\n", cuid);
756 return 1;
760 upnp_get_pinhole_info(const char * raddr,
761 unsigned short rport,
762 char * iaddr,
763 unsigned short * iport,
764 char * proto,
765 const char * uid,
766 char * lt)
768 /* TODO : to be done
769 * Call Firewall specific code to get IPv6 pinhole infos */
770 return 0;
774 upnp_update_inboundpinhole(const char * uid, const char * leasetime)
776 /* TODO : to be implemented */
777 #if 0
778 int r, n;
779 syslog(LOG_INFO, "Updating pinhole for inbound traffic with ID: %s", uid);
780 r = check_rule_from_file(uid, 0);
781 if(r < 0)
782 return r;
783 else
785 n = rule_file_update(uid, leasetime);
786 upnp_update_expiredpinhole();
787 return n;
789 #else
790 return -1;
791 #endif
795 upnp_delete_inboundpinhole(const char * uid)
797 /* TODO : to be implemented */
798 #if 0
799 /* this is a alpha implementation calling ip6tables via system(),
800 * it can be usefull as an example to code the netfilter version */
801 int r, s, linenum=0;
802 char cmd[256], cmd_raw[256];
803 syslog(LOG_INFO, "Removing pinhole for inbound traffic with ID: %s", uid);
804 r = check_rule_from_file(uid, &linenum);
805 if(r > 0)
807 s = rule_file_remove(uid, linenum);
808 if(s < 0)
809 return s;
810 else
812 snprintf(cmd, sizeof(cmd), "ip6tables -t filter -D %s %d", miniupnpd_forward_chain, linenum);
813 snprintf(cmd_raw, sizeof(cmd_raw), "ip6tables -t raw -D PREROUTING %d", linenum -1);
814 #ifdef DEBUG
815 syslog(LOG_INFO, "Deleting ip6tables rule:");
816 syslog(LOG_INFO, " -> %s", cmd);
817 syslog(LOG_INFO, " -> %s", cmd_raw);
818 #endif
819 // TODO Add a better checking error.
820 if(system(cmd) < 0 || system(cmd_raw) < 0)
822 return 0;
826 upnp_update_expiredpinhole();
827 return r;
828 #else
829 return -1;
830 #endif
834 * Result:
835 * 1: Found Result
836 * -4: No result
837 * -5: Result in another table
838 * -6: Result in another chain
839 * -7: Result in a chain not a rule
842 upnp_check_pinhole_working(const char * uid,
843 char * eaddr,
844 char * iaddr,
845 unsigned short * eport,
846 unsigned short * iport,
847 char * protocol,
848 int * rulenum_used)
850 /* TODO : to be implemented */
851 #if 0
852 FILE * fd;
853 time_t expire = time(NULL);
854 char buf[1024], filename[] = "/var/log/kern.log", expire_time[32]="";
855 int res = -4, str_len;
857 str_len = strftime(expire_time, sizeof(expire_time), "%b %d %H:%M:%S", localtime(&expire));
859 fd = fopen(filename, "r");
860 if (fd==NULL)
862 syslog(LOG_ERR, "Get_rule: could not open file: %s", filename);
863 return -1;
866 syslog(LOG_INFO, "Get_rule: Starting getting info in file %s for %s\n", filename, uid);
867 buf[sizeof(buf)-1] = 0;
868 while(fgets(buf, sizeof(buf)-1, fd) != NULL && res != 1)
870 //printf("line: %s\n", buf);
871 char * r, * t, * c, * p;
872 // looking for something like filter:FORWARD:rule: or filter:MINIUPNPD:rule:
873 r = strstr(buf, ":rule:");
874 p = strstr(buf, ":policy:");
875 t = strstr(buf, "TRACE:"); // table pointeur
876 t += 7;
877 c = t + 7; // chain pointeur
878 if(r)
880 printf("\t** Found %.*s\n", 24 ,t);
881 char * src, * dst, * sport, * dport, * proto, * line;
882 char time[15]="", src_addr[40], dst_addr[40], proto_tmp[8];
883 int proto_int;
884 strncpy(time, buf, sizeof(time));
885 /*if(compare_time(time, expire_time)<0)
887 printf("\t\tNot corresponding time\n");
888 continue;
891 line = r + 6;
892 printf("\trule line = %d\n", atoi(line));
894 src = strstr(buf, "SRC=");
895 src += 4;
896 snprintf(src_addr, sizeof(src_addr), "%.*s", 39, src);
897 #if 0
898 del_char(src_addr);
899 add_char(src_addr);
900 #endif
902 dst = strstr(buf, "DST=");
903 dst += 4;
904 snprintf(dst_addr, sizeof(dst_addr), "%.*s", 39, dst);
905 #if 0
906 del_char(dst_addr);
907 add_char(dst_addr);
908 #endif
910 proto = strstr(buf, "PROTO=");
911 proto += 6;
912 proto_int = atoi(protocol);
913 if(proto_int == IPPROTO_UDP)
914 strcpy(proto_tmp, "UDP");
915 else if(proto_int == IPPROTO_TCP)
916 strcpy(proto_tmp, "TCP");
917 #ifdef IPPROTO_UDPLITE
918 else if(proto_int == IPPROTO_UDPLITE)
919 strcpy(proto_tmp, "UDPLITE");
920 #endif
921 else
922 strcpy(proto_tmp, "UnsupportedProto");
924 // printf("\tCompare eaddr: %s // protocol: %s\n\t to addr: %s // protocol: %.*s\n", eaddr, proto_tmp, src_addr, strlen(proto_tmp), proto);
925 // printf("\tCompare iaddr: %s // protocol: %s\n\t to addr: %s // protocol: %.*s\n", iaddr, proto_tmp, dst_addr, strlen(proto_tmp), proto);
926 // TODO Check time
927 // Check that the paquet found in trace correspond to the one we are looking for
928 if( /*(strcmp(eaddr, src_addr) == 0) &&*/ (strcmp(iaddr, dst_addr) == 0) && (strncmp(proto_tmp, proto, strlen(proto_tmp))==0))
930 sport = strstr(buf, "SPT=");
931 sport += 4;
932 dport = strstr(buf, "DPT=");
933 dport += 4;
934 printf("\tCompare eport: %hu\n\t to port: %d\n", *eport, atoi(sport));
935 printf("\tCompare iport: %hu\n\t to port: %d\n", *iport, atoi(dport));
936 if(/*eport != atoi(sport) &&*/ *iport != atoi(dport))
938 printf("\t\tPort not corresponding\n");
939 continue;
941 printf("\ttable found: %.*s\n", 6, t);
942 printf("\tchain found: %.*s\n", 9, c);
943 // Check that the table correspond to the filter table
944 if(strncmp(t, "filter", 6)==0)
946 // Check that the table correspond to the MINIUPNP table
947 if(strncmp(c, "MINIUPNPD", 9)==0)
949 *rulenum_used = atoi(line);
950 res = 1;
952 else
954 res = -6;
955 continue;
958 else
960 res = -5;
961 continue;
964 else
966 printf("Packet information not corresponding\n");
967 continue;
970 if(!r && p)
972 printf("\t** Policy case\n");
973 char * src, * dst, * sport, * dport, * proto, * line;
974 char time[15], src_addr[40], dst_addr[40], proto_tmp[8];
975 int proto_int;
976 strncpy(time, buf, sizeof(time));
977 /*if(compare_time(time, expire_time)<0)
979 printf("\t\tNot corresponding time\n");
980 continue;
983 line = p + 8;
984 printf("\trule line = %d\n", atoi(line));
986 src = strstr(buf, "SRC=");
987 src += 4;
988 snprintf(src_addr, sizeof(src_addr), "%.*s", 39, src);
989 #if 0
990 del_char(src_addr);
991 add_char(src_addr);
992 #endif
994 dst = strstr(buf, "DST=");
995 dst += 4;
996 snprintf(dst_addr, sizeof(dst_addr), "%.*s", 39, dst);
997 #if 0
998 del_char(dst_addr);
999 add_char(dst_addr);
1000 #endif
1002 proto = strstr(buf, "PROTO=");
1003 proto += 6;
1004 proto_int = atoi(protocol);
1005 if(proto_int == IPPROTO_UDP)
1006 strcpy(proto_tmp, "UDP");
1007 else if(proto_int == IPPROTO_TCP)
1008 strcpy(proto_tmp, "TCP");
1009 #ifdef IPPROTO_UDPLITE
1010 else if(proto_int == IPPROTO_UDPLITE)
1011 strcpy(proto_tmp, "UDPLITE");
1012 #endif
1013 else
1014 strcpy(proto_tmp, "UnsupportedProto");
1016 // printf("\tCompare eaddr: %s // protocol: %s\n\t to addr: %s // protocol: %.*s\n", eaddr, proto_tmp, src_addr, strlen(proto_tmp), proto);
1017 // printf("\tCompare iaddr: %s // protocol: %s\n\t to addr: %s // protocol: %.*s\n", iaddr, proto_tmp, dst_addr, strlen(proto_tmp), proto);
1018 // Check that the paquet found in trace correspond to the one we are looking for
1019 if( (strcmp(eaddr, src_addr) == 0) && (strcmp(iaddr, dst_addr) == 0) && (strncmp(proto_tmp, proto, 5)==0))
1021 sport = strstr(buf, "SPT=");
1022 sport += 4;
1023 dport = strstr(buf, "DPT=");
1024 dport += 4;
1025 printf("\tCompare eport: %hu\n\t to port: %d\n", *eport, atoi(sport));
1026 printf("\tCompare iport: %hu\n\t to port: %d\n", *iport, atoi(dport));
1027 if(*eport != atoi(sport) && *iport != atoi(dport))
1029 printf("\t\tPort not corresponding\n");
1030 continue;
1032 else
1034 printf("Find a corresponding policy trace in the chain: %.*s\n", 10, c);
1035 res = -7;
1036 continue;
1039 else
1040 continue;
1043 fclose(fd);
1044 return res;
1045 #else
1046 return -4;
1047 #endif
1051 upnp_get_pinhole_packets(const char * uid, int * packets)
1053 /* TODO : to be implemented */
1054 #if 0
1055 int line=0, r;
1056 char cmd[256];
1057 r = check_rule_from_file(uid, &line);
1058 if(r < 0)
1059 return r;
1060 else
1062 snprintf(cmd, sizeof(cmd), "ip6tables -L MINIUPNPD %d -v", line);
1063 return retrieve_packets(cmd, &line, packets);
1065 #else
1066 return 0;
1067 #endif
1071 upnp_update_expiredpinhole(void)
1073 #if 0
1074 int r;
1075 char uid[5], leaseTime[12];
1077 r = get_rule_from_leasetime(uid, leaseTime);
1078 if(r<0)
1079 return r;
1080 else
1082 strcpy(nextpinholetoclean_uid, uid);
1083 nextpinholetoclean_timestamp = atoi(leaseTime);
1084 return 1;
1086 #endif
1087 return 0;
1091 upnp_clean_expiredpinhole()
1093 #if 0
1094 upnp_delete_inboundpinhole(nextpinholetoclean_uid);
1096 return upnp_update_expiredpinhole();
1097 #endif
1098 return 0;
1100 #endif
1102 /* stuff for miniupnpdctl */
1103 #ifdef USE_MINIUPNPDCTL
1104 void
1105 write_ruleset_details(int s)
1107 int proto = 0;
1108 unsigned short eport, iport;
1109 char desc[64];
1110 char iaddr[32];
1111 char rhost[32];
1112 unsigned int timestamp;
1113 u_int64_t packets;
1114 u_int64_t bytes;
1115 int i = 0;
1116 char buffer[256];
1117 int n;
1119 write(s, "Ruleset :\n", 10);
1120 while(get_redirect_rule_by_index(i, 0/*ifname*/, &eport, iaddr, sizeof(iaddr),
1121 &iport, &proto, desc, sizeof(desc),
1122 rhost, sizeof(rhost),
1123 &timestamp,
1124 &packets, &bytes) >= 0)
1126 n = snprintf(buffer, sizeof(buffer),
1127 "%2d %s %s:%hu->%s:%hu "
1128 "'%s' %u %" PRIu64 " %" PRIu64 "\n",
1129 /*"'%s' %llu %llu\n",*/
1130 i, proto==IPPROTO_TCP?"TCP":"UDP", rhost,
1131 eport, iaddr, iport, desc, timestamp, packets, bytes);
1132 write(s, buffer, n);
1133 i++;
1136 #endif