Miniupnpd v. 1.5 (20110618)
[tomato.git] / release / src / router / miniupnpd / upnpredirect.c
blob592767574585a1488331ee9a0efba1912cd10fd7
1 /* $Id: upnpredirect.c,v 1.59 2011/06/04 08:57:40 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 &timestamp, 0, 0);
282 if(r == 0) {
283 /* if existing redirect rule matches redirect request return success
284 * xbox 360 does not keep track of the port it redirects and will
285 * redirect another port when receiving ConflictInMappingEntry */
286 if(strcmp(iaddr, iaddr_old)==0 && iport==iport_old) {
287 /* redirection allready exists */
288 syslog(LOG_INFO, "port %hu %s already redirected to %s:%hu, replacing", eport, (proto==IPPROTO_TCP)?"tcp":"udp", iaddr_old, iport_old);
289 /* remove and then add again */
290 if(_upnp_delete_redir(eport, proto) < 0) {
291 syslog(LOG_ERR, "failed to remove port mapping");
292 return 0;
294 } else {
295 syslog(LOG_INFO, "port %hu protocol %s already redirected to %s:%hu",
296 eport, protocol, iaddr_old, iport_old);
297 return -2;
300 timestamp = (leaseduration > 0) ? time(NULL) + leaseduration : 0;
301 syslog(LOG_INFO, "redirecting port %hu to %s:%hu protocol %s for: %s",
302 eport, iaddr, iport, protocol, desc);
303 return upnp_redirect_internal(rhost, eport, iaddr, iport, proto,
304 desc, timestamp);
308 upnp_redirect_internal(const char * rhost, unsigned short eport,
309 const char * iaddr, unsigned short iport,
310 int proto, const char * desc,
311 unsigned int timestamp)
313 /*syslog(LOG_INFO, "redirecting port %hu to %s:%hu protocol %s for: %s",
314 eport, iaddr, iport, protocol, desc); */
315 if(add_redirect_rule2(ext_if_name, rhost, eport, iaddr, iport, proto,
316 desc, timestamp) < 0) {
317 return -1;
320 #ifdef ENABLE_LEASEFILE
321 lease_file_add( eport, iaddr, iport, proto, desc, timestamp);
322 #endif
323 /* syslog(LOG_INFO, "creating pass rule to %s:%hu protocol %s for: %s",
324 iaddr, iport, protocol, desc);*/
325 if(add_filter_rule2(ext_if_name, rhost, iaddr, eport, iport, proto, desc) < 0) {
326 /* clean up the redirect rule */
327 #if !defined(__linux__)
328 delete_redirect_rule(ext_if_name, eport, proto);
329 #endif
330 return -1;
332 if(timestamp > 0) {
333 if(!nextruletoclean_timestamp || (timestamp < nextruletoclean_timestamp))
334 nextruletoclean_timestamp = timestamp;
336 #ifdef ENABLE_EVENTS
337 /* the number of port mappings changed, we must
338 * inform the subscribers */
339 upnp_event_var_change_notify(EWanIPC);
340 #endif
341 return 0;
346 /* Firewall independant code which call the FW dependant code. */
348 upnp_get_redirection_infos(unsigned short eport, const char * protocol,
349 unsigned short * iport,
350 char * iaddr, int iaddrlen,
351 char * desc, int desclen,
352 unsigned int * leaseduration)
354 int r;
355 unsigned int timestamp;
356 time_t current_time;
358 if(desc && (desclen > 0))
359 desc[0] = '\0';
360 r = get_redirect_rule(ext_if_name, eport, proto_atoi(protocol),
361 iaddr, iaddrlen, iport, desc, desclen, &timestamp,
362 0, 0);
363 if(r == 0 && timestamp > 0 && timestamp > (current_time = time(NULL))) {
364 *leaseduration = timestamp - current_time;
365 } else {
366 *leaseduration = 0;
368 return r;
372 upnp_get_redirection_infos_by_index(int index,
373 unsigned short * eport, char * protocol,
374 unsigned short * iport,
375 char * iaddr, int iaddrlen,
376 char * desc, int desclen,
377 char * rhost, int rhostlen,
378 unsigned int * leaseduration)
380 /*char ifname[IFNAMSIZ];*/
381 int proto = 0;
382 unsigned int timestamp;
383 time_t current_time;
385 if(desc && (desclen > 0))
386 desc[0] = '\0';
387 if(rhost && (rhost > 0))
388 rhost[0] = '\0';
389 if(get_redirect_rule_by_index(index, 0/*ifname*/, eport, iaddr, iaddrlen,
390 iport, &proto, desc, desclen,
391 rhost, rhostlen, &timestamp,
392 0, 0) < 0)
393 return -1;
394 else
396 current_time = time(NULL);
397 *leaseduration = (timestamp > current_time)
398 ? (timestamp - current_time)
399 : 0;
400 if(proto == IPPROTO_TCP)
401 memcpy(protocol, "TCP", 4);
402 else
403 memcpy(protocol, "UDP", 4);
404 return 0;
408 /* called from natpmp.c too */
410 _upnp_delete_redir(unsigned short eport, int proto)
412 int r;
413 #if defined(__linux__)
414 r = delete_redirect_and_filter_rules(eport, proto);
415 #else
416 r = delete_redirect_rule(ext_if_name, eport, proto);
417 delete_filter_rule(ext_if_name, eport, proto);
418 #endif
419 #ifdef ENABLE_LEASEFILE
420 lease_file_remove( eport, proto);
421 #endif
423 #ifdef ENABLE_EVENTS
424 upnp_event_var_change_notify(EWanIPC);
425 #endif
426 return r;
430 upnp_delete_redirection(unsigned short eport, const char * protocol)
432 syslog(LOG_INFO, "removing redirect rule port %hu %s", eport, protocol);
433 return _upnp_delete_redir(eport, proto_atoi(protocol));
436 /* upnp_get_portmapping_number_of_entries()
437 * TODO: improve this code. */
439 upnp_get_portmapping_number_of_entries()
441 int n = 0, r = 0;
442 unsigned short eport, iport;
443 char protocol[4], iaddr[32], desc[64], rhost[32];
444 unsigned int leaseduration;
445 do {
446 protocol[0] = '\0'; iaddr[0] = '\0'; desc[0] = '\0';
447 r = upnp_get_redirection_infos_by_index(n, &eport, protocol, &iport,
448 iaddr, sizeof(iaddr),
449 desc, sizeof(desc),
450 rhost, sizeof(rhost),
451 &leaseduration);
452 n++;
453 } while(r==0);
454 return (n-1);
457 /* functions used to remove unused rules
458 * As a side effect, delete expired rules (based on LeaseDuration) */
459 struct rule_state *
460 get_upnp_rules_state_list(int max_rules_number_target)
462 /*char ifname[IFNAMSIZ];*/
463 int proto;
464 unsigned short iport;
465 unsigned int timestamp;
466 struct rule_state * tmp;
467 struct rule_state * list = 0;
468 struct rule_state * * p;
469 int i = 0;
470 time_t current_time;
472 /*ifname[0] = '\0';*/
473 tmp = malloc(sizeof(struct rule_state));
474 if(!tmp)
475 return 0;
476 current_time = time(NULL);
477 nextruletoclean_timestamp = 0;
478 while(get_redirect_rule_by_index(i, /*ifname*/0, &tmp->eport, 0, 0,
479 &iport, &proto, 0, 0, 0,0, &timestamp,
480 &tmp->packets, &tmp->bytes) >= 0)
482 tmp->to_remove = 0;
483 if(timestamp > 0) {
484 /* need to remove this port mapping ? */
485 if(timestamp <= current_time)
486 tmp->to_remove = 1;
487 else if((nextruletoclean_timestamp <= current_time)
488 || (timestamp < nextruletoclean_timestamp))
489 nextruletoclean_timestamp = timestamp;
491 tmp->proto = (short)proto;
492 /* add tmp to list */
493 tmp->next = list;
494 list = tmp;
495 /* prepare next iteration */
496 i++;
497 tmp = malloc(sizeof(struct rule_state));
498 if(!tmp)
499 break;
501 free(tmp);
502 /* remove the redirections that need to be removed */
503 for(p = &list, tmp = list; tmp; tmp = *p)
505 if(tmp->to_remove)
507 syslog(LOG_NOTICE, "remove port mapping %hu %s because it has expired",
508 tmp->eport, (tmp->proto==IPPROTO_TCP)?"TCP":"UDP");
509 _upnp_delete_redir(tmp->eport, tmp->proto);
510 *p = tmp->next;
511 free(tmp);
512 i--;
513 } else {
514 p = &(tmp->next);
517 /* return empty list if not enough redirections */
518 if(i<=max_rules_number_target)
519 while(list)
521 tmp = list;
522 list = tmp->next;
523 free(tmp);
525 /* return list */
526 return list;
529 void
530 remove_unused_rules(struct rule_state * list)
532 char ifname[IFNAMSIZ];
533 unsigned short iport;
534 struct rule_state * tmp;
535 u_int64_t packets;
536 u_int64_t bytes;
537 unsigned int timestamp;
538 int n = 0;
540 while(list)
542 /* remove the rule if no traffic has used it */
543 if(get_redirect_rule(ifname, list->eport, list->proto,
544 0, 0, &iport, 0, 0, &timestamp,
545 &packets, &bytes) >= 0)
547 if(packets == list->packets && bytes == list->bytes)
549 if(_upnp_delete_redir(list->eport, list->proto) >= 0)
550 n++;
553 tmp = list;
554 list = tmp->next;
555 free(tmp);
557 if(n>0)
558 syslog(LOG_NOTICE, "removed %d unused rules", n);
561 /* upnp_get_portmappings_in_range()
562 * return a list of all "external" ports for which a port
563 * mapping exists */
564 unsigned short *
565 upnp_get_portmappings_in_range(unsigned short startport,
566 unsigned short endport,
567 const char * protocol,
568 unsigned int * number)
570 int proto;
571 proto = proto_atoi(protocol);
572 if(!number)
573 return NULL;
574 return get_portmappings_in_range(startport, endport, proto, number);
577 #ifdef ENABLE_6FC_SERVICE
579 upnp_check_outbound_pinhole(int proto, int * timeout)
581 #if 0
582 int s, tmptimeout, tmptime_out;
583 switch(proto)
585 case IPPROTO_UDP:
586 s = retrieve_timeout("udp_timeout", timeout);
587 return s;
588 break;
589 case IPPROTO_UDPLITE:
590 s = retrieve_timeout("udp_timeout_stream", timeout);
591 return s;
592 break;
593 case IPPROTO_TCP:
594 s = retrieve_timeout("tcp_timeout_established", timeout);
595 return s;
596 break;
597 case 65535:
598 s = retrieve_timeout("udp_timeout", timeout);
599 s = retrieve_timeout("udp_timeout_stream", &tmptimeout);
600 s = retrieve_timeout("tcp_timeout_established", &tmptime_out);
601 if(tmptimeout<tmptime_out)
603 if(tmptimeout<*timeout)
604 *timeout = tmptimeout;
606 else
608 if(tmptime_out<*timeout)
609 *timeout = tmptimeout;
611 return s;
612 break;
613 default:
614 return -5;
615 break;
617 #endif
618 return 0;
621 /* upnp_add_inboundpinhole()
622 * returns: 0 on success
623 * -1 failed to add pinhole
624 * -2 already created
625 * -3 inbound pinhole disabled
628 upnp_add_inboundpinhole(const char * raddr,
629 unsigned short rport,
630 const char * iaddr,
631 unsigned short iport,
632 const char * protocol,
633 const char * leaseTime,
634 int * uid)
636 int r, s, t, lt=0;
637 char iaddr_old[40]="", proto[6]="", idfound[5]="", leaseTmp[12]; // IPv6 Modification
638 snprintf(proto, sizeof(proto), "%.5d", atoi(protocol));
639 unsigned short iport_old = 0;
640 time_t current = time(NULL);
641 /*struct in6_addr address; // IPv6 Modification
642 if(inet_pton(AF_INET6, iaddr, &address) < 0) // IPv6 Modification
644 syslog(LOG_ERR, "inet_pton(%s) : %m", iaddr);
645 return 0;
648 #if 0
649 r = get_rule_from_file(raddr, rport, iaddr_old, &iport_old, proto, 0, 0, idfound);
650 #endif
651 r = 0;
653 lt = (int) current + atoi(leaseTime);
654 snprintf(leaseTmp, sizeof(leaseTmp), "%d", lt);
655 printf("LeaseTime: %d / %d -> %s\n", atoi(leaseTime), (int)current, leaseTmp);
657 printf("\tCompare addr: %s // port: %d\n\t to addr: %s // port: %d\n", iaddr, iport, iaddr_old, iport_old);
658 if(r == 1 && strcmp(iaddr, iaddr_old)==0 && iport==iport_old)
660 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);
661 t = upnp_update_inboundpinhole(idfound, leaseTime);
662 *uid = atoi(idfound);
663 return t;
665 else
667 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);
668 s = upnp_add_inboundpinhole_internal(raddr, rport, iaddr, iport, protocol, uid);
669 #if 0
670 if(rule_file_add(raddr, rport, iaddr, iport, protocol, leaseTmp, uid)<0)
671 return -8;
672 else
674 if(nextpinholetoclean_timestamp == 0 || (atoi(leaseTmp) <= nextpinholetoclean_timestamp))
676 printf("Initializing the nextpinholetoclean variables. uid = %d\n", *uid);
677 snprintf(nextpinholetoclean_uid, 5, "%.4d", *uid);
678 nextpinholetoclean_timestamp = atoi(leaseTmp);
680 return s;
682 #endif
684 return 0;
688 upnp_add_inboundpinhole_internal(const char * raddr, unsigned short rport,
689 const char * iaddr, unsigned short iport,
690 const char * proto, int * uid)
692 int c = 9999;
693 char cmd[256], cmd_raw[256], cuid[42];
694 #if 0
695 static const char cmdval_full_udptcp[] = "ip6tables -I %s %d -p %s -i %s -s %s --sport %hu -d %s --dport %hu -j ACCEPT";
696 static const char cmdval_udptcp[] = "ip6tables -I %s %d -p %s -i %s --sport %hu -d %s --dport %hu -j ACCEPT";
697 static const char cmdval_full_udplite[] = "ip6tables -I %s %d -p %s -i %s -s %s -d %s -j ACCEPT";
698 static const char cmdval_udplite[] = "ip6tables -I %s %d -p %s -i %s -d %s -j ACCEPT";
699 // raw table command
700 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";
701 static const char cmdval_udptcp_raw[] = "ip6tables -t raw -I PREROUTING %d -p %s -i %s --sport %hu -d %s --dport %hu -j TRACE";
702 static const char cmdval_full_udplite_raw[] = "ip6tables -t raw -I PREROUTING %d -p %s -i %s -s %s -d %s -j TRACE";
703 static const char cmdval_udplite_raw[] = "ip6tables -t raw -I PREROUTING %d -p %s -i %s -d %s -j TRACE";
704 #endif
705 //printf("%s\n", raddr);
706 if(raddr!=NULL)
708 #ifdef IPPROTO_UDPLITE
709 if(atoi(proto) == IPPROTO_UDPLITE)
711 /* snprintf(cmd, sizeof(cmd), cmdval_full_udplite, miniupnpd_forward_chain, line_number, proto, ext_if_name, raddr, iaddr);
712 snprintf(cmd_raw, sizeof(cmd_raw), cmdval_full_udplite_raw, line_number, proto, ext_if_name, raddr, iaddr);*/
714 else
715 #endif
717 /* snprintf(cmd, sizeof(cmd), cmdval_full_udptcp, miniupnpd_forward_chain, line_number, proto, ext_if_name, raddr, rport, iaddr, iport);
718 snprintf(cmd_raw, sizeof(cmd_raw), cmdval_full_udptcp_raw, line_number, proto, ext_if_name, raddr, rport, iaddr, iport);*/
721 else
723 #ifdef IPPROTO_UDPLITE
724 if(atoi(proto) == IPPROTO_UDPLITE)
726 /*snprintf(cmd, sizeof(cmd), cmdval_udplite, miniupnpd_forward_chain, line_number, proto, ext_if_name, iaddr);
727 snprintf(cmd_raw, sizeof(cmd_raw), cmdval_udplite_raw, line_number, proto, ext_if_name, iaddr);*/
729 else
730 #endif
732 /*snprintf(cmd, sizeof(cmd), cmdval_udptcp, miniupnpd_forward_chain, line_number, proto, ext_if_name, rport, iaddr, iport);
733 snprintf(cmd_raw, sizeof(cmd_raw), cmdval_udptcp_raw, line_number, proto, ext_if_name, rport, iaddr, iport);
737 #ifdef DEBUG
738 syslog(LOG_INFO, "Adding following ip6tables rule:");
739 syslog(LOG_INFO, " -> %s", cmd);
740 syslog(LOG_INFO, " -> %s", cmd_raw);
741 #endif
742 // TODO Add a better checking error.
743 if(system(cmd) < 0 || system(cmd_raw) < 0)
745 return 0;
747 srand(time(NULL));
748 snprintf(cuid, sizeof(cuid), "%.4d", rand()%c);
749 *uid = atoi(cuid);
750 printf("\t_add_ uid: %s\n", cuid);
751 return 1;
755 upnp_get_pinhole_info(const char * raddr,
756 unsigned short rport,
757 char * iaddr,
758 unsigned short * iport,
759 char * proto,
760 const char * uid,
761 char * lt)
763 /* TODO : to be done
764 * Call Firewall specific code to get IPv6 pinhole infos */
765 return 0;
769 upnp_update_inboundpinhole(const char * uid, const char * leasetime)
771 /* TODO : to be implemented */
772 #if 0
773 int r, n;
774 syslog(LOG_INFO, "Updating pinhole for inbound traffic with ID: %s", uid);
775 r = check_rule_from_file(uid, 0);
776 if(r < 0)
777 return r;
778 else
780 n = rule_file_update(uid, leasetime);
781 upnp_update_expiredpinhole();
782 return n;
784 #else
785 return -1;
786 #endif
790 upnp_delete_inboundpinhole(const char * uid)
792 /* TODO : to be implemented */
793 #if 0
794 /* this is a alpha implementation calling ip6tables via system(),
795 * it can be usefull as an example to code the netfilter version */
796 int r, s, linenum=0;
797 char cmd[256], cmd_raw[256];
798 syslog(LOG_INFO, "Removing pinhole for inbound traffic with ID: %s", uid);
799 r = check_rule_from_file(uid, &linenum);
800 if(r > 0)
802 s = rule_file_remove(uid, linenum);
803 if(s < 0)
804 return s;
805 else
807 snprintf(cmd, sizeof(cmd), "ip6tables -t filter -D %s %d", miniupnpd_forward_chain, linenum);
808 snprintf(cmd_raw, sizeof(cmd_raw), "ip6tables -t raw -D PREROUTING %d", linenum -1);
809 #ifdef DEBUG
810 syslog(LOG_INFO, "Deleting ip6tables rule:");
811 syslog(LOG_INFO, " -> %s", cmd);
812 syslog(LOG_INFO, " -> %s", cmd_raw);
813 #endif
814 // TODO Add a better checking error.
815 if(system(cmd) < 0 || system(cmd_raw) < 0)
817 return 0;
821 upnp_update_expiredpinhole();
822 return r;
823 #else
824 return -1;
825 #endif
829 * Result:
830 * 1: Found Result
831 * -4: No result
832 * -5: Result in another table
833 * -6: Result in another chain
834 * -7: Result in a chain not a rule
837 upnp_check_pinhole_working(const char * uid,
838 char * eaddr,
839 char * iaddr,
840 unsigned short * eport,
841 unsigned short * iport,
842 char * protocol,
843 int * rulenum_used)
845 /* TODO : to be implemented */
846 #if 0
847 FILE * fd;
848 time_t expire = time(NULL);
849 char buf[1024], filename[] = "/var/log/kern.log", expire_time[32]="";
850 int res = -4, str_len;
852 str_len = strftime(expire_time, sizeof(expire_time), "%b %d %H:%M:%S", localtime(&expire));
854 fd = fopen(filename, "r");
855 if (fd==NULL)
857 syslog(LOG_ERR, "Get_rule: could not open file: %s", filename);
858 return -1;
861 syslog(LOG_INFO, "Get_rule: Starting getting info in file %s for %s\n", filename, uid);
862 buf[sizeof(buf)-1] = 0;
863 while(fgets(buf, sizeof(buf)-1, fd) != NULL && res != 1)
865 //printf("line: %s\n", buf);
866 char * r, * t, * c, * p;
867 // looking for something like filter:FORWARD:rule: or filter:MINIUPNPD:rule:
868 r = strstr(buf, ":rule:");
869 p = strstr(buf, ":policy:");
870 t = strstr(buf, "TRACE:"); // table pointeur
871 t += 7;
872 c = t + 7; // chain pointeur
873 if(r)
875 printf("\t** Found %.*s\n", 24 ,t);
876 char * src, * dst, * sport, * dport, * proto, * line;
877 char time[15]="", src_addr[40], dst_addr[40], proto_tmp[8];
878 int proto_int;
879 strncpy(time, buf, sizeof(time));
880 /*if(compare_time(time, expire_time)<0)
882 printf("\t\tNot corresponding time\n");
883 continue;
886 line = r + 6;
887 printf("\trule line = %d\n", atoi(line));
889 src = strstr(buf, "SRC=");
890 src += 4;
891 snprintf(src_addr, sizeof(src_addr), "%.*s", 39, src);
892 #if 0
893 del_char(src_addr);
894 add_char(src_addr);
895 #endif
897 dst = strstr(buf, "DST=");
898 dst += 4;
899 snprintf(dst_addr, sizeof(dst_addr), "%.*s", 39, dst);
900 #if 0
901 del_char(dst_addr);
902 add_char(dst_addr);
903 #endif
905 proto = strstr(buf, "PROTO=");
906 proto += 6;
907 proto_int = atoi(protocol);
908 if(proto_int == IPPROTO_UDP)
909 strcpy(proto_tmp, "UDP");
910 else if(proto_int == IPPROTO_TCP)
911 strcpy(proto_tmp, "TCP");
912 #ifdef IPPROTO_UDPLITE
913 else if(proto_int == IPPROTO_UDPLITE)
914 strcpy(proto_tmp, "UDPLITE");
915 #endif
916 else
917 strcpy(proto_tmp, "UnsupportedProto");
919 // printf("\tCompare eaddr: %s // protocol: %s\n\t to addr: %s // protocol: %.*s\n", eaddr, proto_tmp, src_addr, strlen(proto_tmp), proto);
920 // printf("\tCompare iaddr: %s // protocol: %s\n\t to addr: %s // protocol: %.*s\n", iaddr, proto_tmp, dst_addr, strlen(proto_tmp), proto);
921 // TODO Check time
922 // Check that the paquet found in trace correspond to the one we are looking for
923 if( /*(strcmp(eaddr, src_addr) == 0) &&*/ (strcmp(iaddr, dst_addr) == 0) && (strncmp(proto_tmp, proto, strlen(proto_tmp))==0))
925 sport = strstr(buf, "SPT=");
926 sport += 4;
927 dport = strstr(buf, "DPT=");
928 dport += 4;
929 printf("\tCompare eport: %hu\n\t to port: %d\n", *eport, atoi(sport));
930 printf("\tCompare iport: %hu\n\t to port: %d\n", *iport, atoi(dport));
931 if(/*eport != atoi(sport) &&*/ *iport != atoi(dport))
933 printf("\t\tPort not corresponding\n");
934 continue;
936 printf("\ttable found: %.*s\n", 6, t);
937 printf("\tchain found: %.*s\n", 9, c);
938 // Check that the table correspond to the filter table
939 if(strncmp(t, "filter", 6)==0)
941 // Check that the table correspond to the MINIUPNP table
942 if(strncmp(c, "MINIUPNPD", 9)==0)
944 *rulenum_used = atoi(line);
945 res = 1;
947 else
949 res = -6;
950 continue;
953 else
955 res = -5;
956 continue;
959 else
961 printf("Packet information not corresponding\n");
962 continue;
965 if(!r && p)
967 printf("\t** Policy case\n");
968 char * src, * dst, * sport, * dport, * proto, * line;
969 char time[15], src_addr[40], dst_addr[40], proto_tmp[8];
970 int proto_int;
971 strncpy(time, buf, sizeof(time));
972 /*if(compare_time(time, expire_time)<0)
974 printf("\t\tNot corresponding time\n");
975 continue;
978 line = p + 8;
979 printf("\trule line = %d\n", atoi(line));
981 src = strstr(buf, "SRC=");
982 src += 4;
983 snprintf(src_addr, sizeof(src_addr), "%.*s", 39, src);
984 #if 0
985 del_char(src_addr);
986 add_char(src_addr);
987 #endif
989 dst = strstr(buf, "DST=");
990 dst += 4;
991 snprintf(dst_addr, sizeof(dst_addr), "%.*s", 39, dst);
992 #if 0
993 del_char(dst_addr);
994 add_char(dst_addr);
995 #endif
997 proto = strstr(buf, "PROTO=");
998 proto += 6;
999 proto_int = atoi(protocol);
1000 if(proto_int == IPPROTO_UDP)
1001 strcpy(proto_tmp, "UDP");
1002 else if(proto_int == IPPROTO_TCP)
1003 strcpy(proto_tmp, "TCP");
1004 #ifdef IPPROTO_UDPLITE
1005 else if(proto_int == IPPROTO_UDPLITE)
1006 strcpy(proto_tmp, "UDPLITE");
1007 #endif
1008 else
1009 strcpy(proto_tmp, "UnsupportedProto");
1011 // printf("\tCompare eaddr: %s // protocol: %s\n\t to addr: %s // protocol: %.*s\n", eaddr, proto_tmp, src_addr, strlen(proto_tmp), proto);
1012 // printf("\tCompare iaddr: %s // protocol: %s\n\t to addr: %s // protocol: %.*s\n", iaddr, proto_tmp, dst_addr, strlen(proto_tmp), proto);
1013 // Check that the paquet found in trace correspond to the one we are looking for
1014 if( (strcmp(eaddr, src_addr) == 0) && (strcmp(iaddr, dst_addr) == 0) && (strncmp(proto_tmp, proto, 5)==0))
1016 sport = strstr(buf, "SPT=");
1017 sport += 4;
1018 dport = strstr(buf, "DPT=");
1019 dport += 4;
1020 printf("\tCompare eport: %hu\n\t to port: %d\n", *eport, atoi(sport));
1021 printf("\tCompare iport: %hu\n\t to port: %d\n", *iport, atoi(dport));
1022 if(*eport != atoi(sport) && *iport != atoi(dport))
1024 printf("\t\tPort not corresponding\n");
1025 continue;
1027 else
1029 printf("Find a corresponding policy trace in the chain: %.*s\n", 10, c);
1030 res = -7;
1031 continue;
1034 else
1035 continue;
1038 fclose(fd);
1039 return res;
1040 #else
1041 return -4;
1042 #endif
1046 upnp_get_pinhole_packets(const char * uid, int * packets)
1048 /* TODO : to be implemented */
1049 #if 0
1050 int line=0, r;
1051 char cmd[256];
1052 r = check_rule_from_file(uid, &line);
1053 if(r < 0)
1054 return r;
1055 else
1057 snprintf(cmd, sizeof(cmd), "ip6tables -L MINIUPNPD %d -v", line);
1058 return retrieve_packets(cmd, &line, packets);
1060 #else
1061 return 0;
1062 #endif
1066 upnp_update_expiredpinhole(void)
1068 #if 0
1069 int r;
1070 char uid[5], leaseTime[12];
1072 r = get_rule_from_leasetime(uid, leaseTime);
1073 if(r<0)
1074 return r;
1075 else
1077 strcpy(nextpinholetoclean_uid, uid);
1078 nextpinholetoclean_timestamp = atoi(leaseTime);
1079 return 1;
1081 #endif
1082 return 0;
1086 upnp_clean_expiredpinhole()
1088 #if 0
1089 upnp_delete_inboundpinhole(nextpinholetoclean_uid);
1091 return upnp_update_expiredpinhole();
1092 #endif
1093 return 0;
1095 #endif
1097 /* stuff for miniupnpdctl */
1098 #ifdef USE_MINIUPNPDCTL
1099 void
1100 write_ruleset_details(int s)
1102 int proto = 0;
1103 unsigned short eport, iport;
1104 char desc[64];
1105 char iaddr[32];
1106 char rhost[32];
1107 unsigned int timestamp;
1108 u_int64_t packets;
1109 u_int64_t bytes;
1110 int i = 0;
1111 char buffer[256];
1112 int n;
1114 write(s, "Ruleset :\n", 10);
1115 while(get_redirect_rule_by_index(i, 0/*ifname*/, &eport, iaddr, sizeof(iaddr),
1116 &iport, &proto, desc, sizeof(desc),
1117 rhost, sizeof(rhost),
1118 &timestamp,
1119 &packets, &bytes) >= 0)
1121 n = snprintf(buffer, sizeof(buffer),
1122 "%2d %s %s:%hu->%s:%hu "
1123 "'%s' %u %" PRIu64 " %" PRIu64 "\n",
1124 /*"'%s' %llu %llu\n",*/
1125 i, proto==IPPROTO_TCP?"TCP":"UDP", rhost,
1126 eport, iaddr, iport, desc, timestamp, packets, bytes);
1127 write(s, buffer, n);
1128 i++;
1131 #endif