1 /* $Id: upnpredirect.c,v 1.60 2011/06/22 20:34:39 nanard Exp $ */
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 */
11 #include <sys/types.h>
12 #include <sys/socket.h>
13 #include <netinet/in.h>
15 #include <arpa/inet.h>
22 #include "upnpredirect.h"
23 #include "upnpglobalvars.h"
24 #include "upnpevents.h"
25 #if defined(USE_NETFILTER)
26 #include "netfilter/iptcrdr.h"
29 #include "pf/obsdrdr.h"
32 #include "ipf/ipfrdr.h"
35 #include "ipfw/ipfwrdr.h"
37 #ifdef USE_MINIUPNPDCTL
41 #ifdef ENABLE_LEASEFILE
45 /* from <inttypes.h> */
51 * convert the string "UDP" or "TCP" to IPPROTO_UDP and IPPROTO_UDP */
53 proto_atoi(const char * protocol
)
55 int proto
= IPPROTO_TCP
;
56 if(strcmp(protocol
, "UDP") == 0)
61 #ifdef ENABLE_LEASEFILE
63 lease_file_add(unsigned short eport
,
68 unsigned int timestamp
)
72 if (lease_file
== NULL
) return 0;
74 fd
= fopen( lease_file
, "a");
76 syslog(LOG_ERR
, "could not open lease file: %s", lease_file
);
80 fprintf(fd
, "%s:%hu:%s:%hu:%u:%s\n",
81 ((proto
==IPPROTO_TCP
)?"TCP":"UDP"), eport
, iaddr
, iport
,
89 lease_file_remove(unsigned short eport
, int proto
)
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");
106 strncpy( tmpfilename
, lease_file
, sizeof(tmpfilename
) );
107 strncat( tmpfilename
, "XXXXXX", sizeof(tmpfilename
) - strlen(tmpfilename
));
109 fd
= fopen( lease_file
, "r");
114 snprintf( str
, sizeof(str
), "%s:%u", ((proto
==IPPROTO_TCP
)?"TCP":"UDP"), eport
);
115 str_size
= strlen(str
);
117 tmp
= mkstemp(tmpfilename
);
120 syslog(LOG_ERR
, "could not open temporary lease file");
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
);
137 if (rename(tmpfilename
, lease_file
) < 0) {
138 syslog(LOG_ERR
, "could not rename temporary lease file to %s", lease_file
);
146 /* reload_from_lease_file()
147 * read lease_file and add the rules contained
149 int reload_from_lease_file()
153 unsigned short eport
, iport
;
158 unsigned int leaseduration
;
159 unsigned int timestamp
;
164 if(!lease_file
) return -1;
165 fd
= fopen( lease_file
, "r");
167 syslog(LOG_ERR
, "could not open lease file: %s", lease_file
);
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
);
178 p
= strchr(line
, ':');
180 syslog(LOG_ERR
, "unrecognized data in lease file");
184 iaddr
= strchr(p
, ':');
186 syslog(LOG_ERR
, "unrecognized data in lease file");
190 eport
= (unsigned short)atoi(p
);
191 p
= strchr(iaddr
, ':');
193 syslog(LOG_ERR
, "unrecognized data in lease file");
197 timestamp
= (unsigned int)atoi(p
);
200 syslog(LOG_ERR
, "unrecognized data in lease file");
204 desc
= strchr(p
, ':');
206 syslog(LOG_ERR
, "unrecognized data in lease file");
210 iport
= (unsigned short)atoi(p
);
211 /* trim description */
212 while(isspace(*desc
))
217 while(isspace(*p
) && (p
> desc
))
221 if(timestamp
<= current_time
) {
222 syslog(LOG_NOTICE
, "already expired lease in lease file");
225 leaseduration
= current_time
- timestamp
;
228 leaseduration
= 0; /* default value */
231 r
= upnp_redirect(rhost
, eport
, iaddr
, iport
, proto
, desc
, leaseduration
);
233 syslog(LOG_ERR
, "Failed to redirect %hu -> %s:%hu protocol %s",
234 eport
, iaddr
, iport
, proto
);
236 /* Add the redirection again to the lease file */
237 lease_file_add(eport
, iaddr
, iport
, proto_atoi(proto
),
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
)
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
);
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
);
279 r
= get_redirect_rule(ext_if_name
, eport
, proto
,
280 iaddr_old
, sizeof(iaddr_old
), &iport_old
, 0, 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");
296 syslog(LOG_INFO
, "port %hu protocol %s already redirected to %s:%hu",
297 eport
, protocol
, iaddr_old
, iport_old
);
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
,
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) {
321 #ifdef ENABLE_LEASEFILE
322 lease_file_add( eport
, iaddr
, iport
, proto
, desc
, timestamp
);
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
);
334 if(!nextruletoclean_timestamp
|| (timestamp
< nextruletoclean_timestamp
))
335 nextruletoclean_timestamp
= timestamp
;
338 /* the number of port mappings changed, we must
339 * inform the subscribers */
340 upnp_event_var_change_notify(EWanIPC
);
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
)
357 unsigned int timestamp
;
360 if(desc
&& (desclen
> 0))
362 if(rhost
&& (rhostlen
> 0))
364 r
= get_redirect_rule(ext_if_name
, eport
, proto_atoi(protocol
),
365 iaddr
, iaddrlen
, iport
, desc
, desclen
,
366 rhost
, rhostlen
, ×tamp
,
368 if(r
== 0 && timestamp
> 0 && timestamp
> (current_time
= time(NULL
))) {
369 *leaseduration
= timestamp
- current_time
;
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];*/
387 unsigned int timestamp
;
390 if(desc
&& (desclen
> 0))
392 if(rhost
&& (rhost
> 0))
394 if(get_redirect_rule_by_index(index
, 0/*ifname*/, eport
, iaddr
, iaddrlen
,
395 iport
, &proto
, desc
, desclen
,
396 rhost
, rhostlen
, ×tamp
,
401 current_time
= time(NULL
);
402 *leaseduration
= (timestamp
> current_time
)
403 ? (timestamp
- current_time
)
405 if(proto
== IPPROTO_TCP
)
406 memcpy(protocol
, "TCP", 4);
408 memcpy(protocol
, "UDP", 4);
413 /* called from natpmp.c too */
415 _upnp_delete_redir(unsigned short eport
, int proto
)
418 #if defined(__linux__)
419 r
= delete_redirect_and_filter_rules(eport
, proto
);
421 r
= delete_redirect_rule(ext_if_name
, eport
, proto
);
422 delete_filter_rule(ext_if_name
, eport
, proto
);
424 #ifdef ENABLE_LEASEFILE
425 lease_file_remove( eport
, proto
);
429 upnp_event_var_change_notify(EWanIPC
);
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()
447 unsigned short eport
, iport
;
448 char protocol
[4], iaddr
[32], desc
[64], rhost
[32];
449 unsigned int leaseduration
;
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
),
455 rhost
, sizeof(rhost
),
462 /* functions used to remove unused rules
463 * As a side effect, delete expired rules (based on LeaseDuration) */
465 get_upnp_rules_state_list(int max_rules_number_target
)
467 /*char ifname[IFNAMSIZ];*/
469 unsigned short iport
;
470 unsigned int timestamp
;
471 struct rule_state
* tmp
;
472 struct rule_state
* list
= 0;
473 struct rule_state
* * p
;
477 /*ifname[0] = '\0';*/
478 tmp
= malloc(sizeof(struct rule_state
));
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, ×tamp
,
485 &tmp
->packets
, &tmp
->bytes
) >= 0)
489 /* need to remove this port mapping ? */
490 if(timestamp
<= current_time
)
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 */
500 /* prepare next iteration */
502 tmp
= malloc(sizeof(struct rule_state
));
507 /* remove the redirections that need to be removed */
508 for(p
= &list
, tmp
= list
; tmp
; tmp
= *p
)
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
);
522 /* return empty list if not enough redirections */
523 if(i
<=max_rules_number_target
)
535 remove_unused_rules(struct rule_state
* list
)
537 char ifname
[IFNAMSIZ
];
538 unsigned short iport
;
539 struct rule_state
* tmp
;
542 unsigned int timestamp
;
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, ×tamp
,
550 &packets
, &bytes
) >= 0)
552 if(packets
== list
->packets
&& bytes
== list
->bytes
)
554 if(_upnp_delete_redir(list
->eport
, list
->proto
) >= 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
570 upnp_get_portmappings_in_range(unsigned short startport
,
571 unsigned short endport
,
572 const char * protocol
,
573 unsigned int * number
)
576 proto
= proto_atoi(protocol
);
579 return get_portmappings_in_range(startport
, endport
, proto
, number
);
582 #ifdef ENABLE_6FC_SERVICE
584 upnp_check_outbound_pinhole(int proto
, int * timeout
)
587 int s
, tmptimeout
, tmptime_out
;
591 s
= retrieve_timeout("udp_timeout", timeout
);
594 case IPPROTO_UDPLITE
:
595 s
= retrieve_timeout("udp_timeout_stream", timeout
);
599 s
= retrieve_timeout("tcp_timeout_established", timeout
);
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
;
613 if(tmptime_out
<*timeout
)
614 *timeout
= tmptimeout
;
626 /* upnp_add_inboundpinhole()
627 * returns: 0 on success
628 * -1 failed to add pinhole
630 * -3 inbound pinhole disabled
633 upnp_add_inboundpinhole(const char * raddr
,
634 unsigned short rport
,
636 unsigned short iport
,
637 const char * protocol
,
638 const char * leaseTime
,
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);
654 r
= get_rule_from_file(raddr
, rport
, iaddr_old
, &iport_old
, proto
, 0, 0, idfound
);
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
);
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
);
675 if(rule_file_add(raddr
, rport
, iaddr
, iport
, protocol
, leaseTmp
, uid
)<0)
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
);
693 upnp_add_inboundpinhole_internal(const char * raddr
, unsigned short rport
,
694 const char * iaddr
, unsigned short iport
,
695 const char * proto
, int * uid
)
698 char cmd
[256], cmd_raw
[256], cuid
[42];
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";
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";
710 //printf("%s\n", raddr);
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);*/
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);*/
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);*/
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);
743 syslog(LOG_INFO
, "Adding following ip6tables rule:");
744 syslog(LOG_INFO
, " -> %s", cmd
);
745 syslog(LOG_INFO
, " -> %s", cmd_raw
);
747 // TODO Add a better checking error.
748 if(system(cmd
) < 0 || system(cmd_raw
) < 0)
753 snprintf(cuid
, sizeof(cuid
), "%.4d", rand()%c
);
755 printf("\t_add_ uid: %s\n", cuid
);
760 upnp_get_pinhole_info(const char * raddr
,
761 unsigned short rport
,
763 unsigned short * iport
,
769 * Call Firewall specific code to get IPv6 pinhole infos */
774 upnp_update_inboundpinhole(const char * uid
, const char * leasetime
)
776 /* TODO : to be implemented */
779 syslog(LOG_INFO
, "Updating pinhole for inbound traffic with ID: %s", uid
);
780 r
= check_rule_from_file(uid
, 0);
785 n
= rule_file_update(uid
, leasetime
);
786 upnp_update_expiredpinhole();
795 upnp_delete_inboundpinhole(const char * uid
)
797 /* TODO : to be implemented */
799 /* this is a alpha implementation calling ip6tables via system(),
800 * it can be usefull as an example to code the netfilter version */
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
);
807 s
= rule_file_remove(uid
, linenum
);
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);
815 syslog(LOG_INFO
, "Deleting ip6tables rule:");
816 syslog(LOG_INFO
, " -> %s", cmd
);
817 syslog(LOG_INFO
, " -> %s", cmd_raw
);
819 // TODO Add a better checking error.
820 if(system(cmd
) < 0 || system(cmd_raw
) < 0)
826 upnp_update_expiredpinhole();
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
,
845 unsigned short * eport
,
846 unsigned short * iport
,
850 /* TODO : to be implemented */
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");
862 syslog(LOG_ERR
, "Get_rule: could not open file: %s", filename
);
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
877 c
= t
+ 7; // chain pointeur
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];
884 strncpy(time
, buf
, sizeof(time
));
885 /*if(compare_time(time, expire_time)<0)
887 printf("\t\tNot corresponding time\n");
892 printf("\trule line = %d\n", atoi(line
));
894 src
= strstr(buf
, "SRC=");
896 snprintf(src_addr
, sizeof(src_addr
), "%.*s", 39, src
);
902 dst
= strstr(buf
, "DST=");
904 snprintf(dst_addr
, sizeof(dst_addr
), "%.*s", 39, dst
);
910 proto
= strstr(buf
, "PROTO=");
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");
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);
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=");
932 dport
= strstr(buf
, "DPT=");
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");
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
);
966 printf("Packet information not corresponding\n");
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];
976 strncpy(time
, buf
, sizeof(time
));
977 /*if(compare_time(time, expire_time)<0)
979 printf("\t\tNot corresponding time\n");
984 printf("\trule line = %d\n", atoi(line
));
986 src
= strstr(buf
, "SRC=");
988 snprintf(src_addr
, sizeof(src_addr
), "%.*s", 39, src
);
994 dst
= strstr(buf
, "DST=");
996 snprintf(dst_addr
, sizeof(dst_addr
), "%.*s", 39, dst
);
1002 proto
= strstr(buf
, "PROTO=");
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");
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=");
1023 dport
= strstr(buf
, "DPT=");
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");
1034 printf("Find a corresponding policy trace in the chain: %.*s\n", 10, c
);
1051 upnp_get_pinhole_packets(const char * uid
, int * packets
)
1053 /* TODO : to be implemented */
1057 r
= check_rule_from_file(uid
, &line
);
1062 snprintf(cmd
, sizeof(cmd
), "ip6tables -L MINIUPNPD %d -v", line
);
1063 return retrieve_packets(cmd
, &line
, packets
);
1071 upnp_update_expiredpinhole(void)
1075 char uid
[5], leaseTime
[12];
1077 r
= get_rule_from_leasetime(uid
, leaseTime
);
1082 strcpy(nextpinholetoclean_uid
, uid
);
1083 nextpinholetoclean_timestamp
= atoi(leaseTime
);
1091 upnp_clean_expiredpinhole()
1094 upnp_delete_inboundpinhole(nextpinholetoclean_uid
);
1096 return upnp_update_expiredpinhole();
1102 /* stuff for miniupnpdctl */
1103 #ifdef USE_MINIUPNPDCTL
1105 write_ruleset_details(int s
)
1108 unsigned short eport
, iport
;
1112 unsigned int timestamp
;
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
),
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
);