1 /* $Id: upnppinhole.c,v 1.7 2014/12/09 09:13:53 nanard Exp $ */
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 */
11 #include <sys/types.h>
12 #include <sys/socket.h>
13 #include <netinet/in.h>
15 #include <arpa/inet.h>
23 #include "upnpredirect.h"
24 #include "upnpglobalvars.h"
25 #include "upnpevents.h"
26 #include "upnppinhole.h"
28 /* XXX - Apple version of PF API seems to differ from what
29 * pf/pfpinhole.c expects so don't use that at least.. */
33 #endif /* __APPLE__ */
34 #if defined(USE_NETFILTER)
35 #include "netfilter/iptpinhole.h"
38 #include "pf/pfpinhole.h"
45 #ifdef ENABLE_UPNPPINHOLE
49 upnp_check_outbound_pinhole(int proto
, int * timeout
)
51 int s
, tmptimeout
, tmptime_out
;
55 s
= retrieve_timeout("udp_timeout", timeout
);
59 s
= retrieve_timeout("udp_timeout_stream", timeout
);
63 s
= retrieve_timeout("tcp_timeout_established", timeout
);
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
;
77 if(tmptime_out
<*timeout
)
78 *timeout
= tmptimeout
;
90 /* upnp_add_inboundpinhole()
91 * returns: 1 on success
92 * -1 Pinhole space exhausted
93 * -4 invalid arguments
95 * TODO : return uid on success (positive) or error value (negative)
98 upnp_add_inboundpinhole(const char * raddr
,
101 unsigned short iport
,
104 unsigned int leasetime
,
109 unsigned int timestamp
;
110 struct in6_addr address
;
112 r
= inet_pton(AF_INET6
, iaddr
, &address
);
114 syslog(LOG_ERR
, "inet_pton(%d, %s, %p) FAILED",
115 AF_INET6
, iaddr
, &address
);
118 current
= time(NULL
);
119 timestamp
= current
+ leasetime
;
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
);
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;
137 return -42; /* not implemented */
143 upnp_add_inboundpinhole_internal(const char * raddr
, unsigned short rport
,
144 const char * iaddr
, unsigned short iport
,
145 const char * proto
, int * uid
)
148 char cmd
[256], cmd_raw
[256], cuid
[42];
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";
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";
160 /*printf("%s\n", raddr);*/
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);*/
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);*/
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);*/
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);
193 syslog(LOG_INFO
, "Adding following ip6tables rule:");
194 syslog(LOG_INFO
, " -> %s", cmd
);
195 syslog(LOG_INFO
, " -> %s", cmd_raw
);
197 /* TODO Add a better checking error.*/
198 if(system(cmd
) < 0 || system(cmd_raw
) < 0)
203 snprintf(cuid
, sizeof(cuid
), "%.4d", rand()%c
);
205 printf("\t_add_ uid: %s\n", cuid
);
210 /* upnp_get_pinhole_info()
214 * -2 NOT FOUND (no such entry)
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)
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
? ×tamp
: NULL
,
239 packets
? &packets_tmp
: NULL
,
244 current_time
= time(NULL
);
245 if(timestamp
> (unsigned int)current_time
)
246 *leasetime
= timestamp
- current_time
;
251 *packets
= (unsigned int)packets_tmp
;
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 */
265 upnp_get_pinhole_uid_by_index(int index
)
267 #if defined (USE_NETFILTER)
268 return get_pinhole_uid_by_index(index
);
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
);
284 UNUSED(uid
); UNUSED(leasetime
);
286 return -42; /* not implemented */
291 upnp_delete_inboundpinhole(unsigned short uid
)
293 #if defined(USE_PF) || defined(USE_NETFILTER)
294 return delete_pinhole(uid
);
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
,
315 unsigned short * eport
,
316 unsigned short * iport
,
320 /* TODO : to be implemented */
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");
332 syslog(LOG_ERR
, "Get_rule: could not open file: %s", filename
);
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
347 c
= t
+ 7; // chain pointeur
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];
354 strncpy(time
, buf
, sizeof(time
));
355 /*if(compare_time(time, expire_time)<0)
357 printf("\t\tNot corresponding time\n");
362 printf("\trule line = %d\n", atoi(line
));
364 src
= strstr(buf
, "SRC=");
366 snprintf(src_addr
, sizeof(src_addr
), "%.*s", 39, src
);
372 dst
= strstr(buf
, "DST=");
374 snprintf(dst_addr
, sizeof(dst_addr
), "%.*s", 39, dst
);
380 proto
= strstr(buf
, "PROTO=");
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");
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);
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=");
402 dport
= strstr(buf
, "DPT=");
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");
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
);
436 printf("Packet information not corresponding\n");
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];
446 strncpy(time
, buf
, sizeof(time
));
447 /*if(compare_time(time, expire_time)<0)
449 printf("\t\tNot corresponding time\n");
454 printf("\trule line = %d\n", atoi(line
));
456 src
= strstr(buf
, "SRC=");
458 snprintf(src_addr
, sizeof(src_addr
), "%.*s", 39, src
);
464 dst
= strstr(buf
, "DST=");
466 snprintf(dst_addr
, sizeof(dst_addr
), "%.*s", 39, dst
);
472 proto
= strstr(buf
, "PROTO=");
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");
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=");
493 dport
= strstr(buf
, "DPT=");
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");
504 printf("Find a corresponding policy trace in the chain: %.*s\n", 10, c
);
516 return -42; /* to be implemented */
522 upnp_clean_expired_pinholes(unsigned int * next_timestamp
)
524 #if defined(USE_PF) || defined(USE_NETFILTER)
525 return clean_pinhole_list(next_timestamp
);
527 UNUSED(next_timestamp
);
529 return 0; /* nothing to do */
533 #endif /* ENABLE_UPNPPINHOLE */