1 /* $Id: upnppinhole.c,v 1.4 2012/05/08 20:41:45 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 #if defined(USE_NETFILTER)
27 #include "netfilter/iptpinhole.h"
30 #include "pf/pfpinhole.h"
37 #ifdef ENABLE_6FC_SERVICE
40 upnp_check_outbound_pinhole(int proto
, int * timeout
)
42 int s
, tmptimeout
, tmptime_out
;
46 s
= retrieve_timeout("udp_timeout", timeout
);
50 s
= retrieve_timeout("udp_timeout_stream", timeout
);
54 s
= retrieve_timeout("tcp_timeout_established", timeout
);
58 s
= retrieve_timeout("udp_timeout", timeout
);
59 s
= retrieve_timeout("udp_timeout_stream", &tmptimeout
);
60 s
= retrieve_timeout("tcp_timeout_established", &tmptime_out
);
61 if(tmptimeout
<tmptime_out
)
63 if(tmptimeout
<*timeout
)
64 *timeout
= tmptimeout
;
68 if(tmptime_out
<*timeout
)
69 *timeout
= tmptimeout
;
81 /* upnp_add_inboundpinhole()
82 * returns: 0 on success
83 * -1 failed to add pinhole
85 * -3 inbound pinhole disabled
86 * TODO : return uid on success (positive) or error value (negative)
89 upnp_add_inboundpinhole(const char * raddr
,
94 unsigned int leasetime
,
99 unsigned int timestamp
;
100 struct in6_addr address
;
102 if(inet_pton(AF_INET6
, iaddr
, &address
) < 0)
104 syslog(LOG_ERR
, "inet_pton(%s) : %m", iaddr
);
107 current
= time(NULL
);
108 timestamp
= current
+ leasetime
;
112 if(r
== 1 && strcmp(iaddr
, iaddr_old
)==0 && iport
==iport_old
)
114 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
);
115 t
= upnp_update_inboundpinhole(idfound
, leaseTime
);
116 *uid
= atoi(idfound
);
122 #if defined(USE_PF) || defined(USE_NETFILTER)
123 *uid
= add_pinhole (0/*ext_if_name*/, raddr
, rport
,
124 iaddr
, iport
, proto
, timestamp
);
127 return -42; /* not implemented */
134 upnp_add_inboundpinhole_internal(const char * raddr
, unsigned short rport
,
135 const char * iaddr
, unsigned short iport
,
136 const char * proto
, int * uid
)
139 char cmd
[256], cmd_raw
[256], cuid
[42];
141 static const char cmdval_full_udptcp
[] = "ip6tables -I %s %d -p %s -i %s -s %s --sport %hu -d %s --dport %hu -j ACCEPT";
142 static const char cmdval_udptcp
[] = "ip6tables -I %s %d -p %s -i %s --sport %hu -d %s --dport %hu -j ACCEPT";
143 static const char cmdval_full_udplite
[] = "ip6tables -I %s %d -p %s -i %s -s %s -d %s -j ACCEPT";
144 static const char cmdval_udplite
[] = "ip6tables -I %s %d -p %s -i %s -d %s -j ACCEPT";
146 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";
147 static const char cmdval_udptcp_raw
[] = "ip6tables -t raw -I PREROUTING %d -p %s -i %s --sport %hu -d %s --dport %hu -j TRACE";
148 static const char cmdval_full_udplite_raw
[] = "ip6tables -t raw -I PREROUTING %d -p %s -i %s -s %s -d %s -j TRACE";
149 static const char cmdval_udplite_raw
[] = "ip6tables -t raw -I PREROUTING %d -p %s -i %s -d %s -j TRACE";
151 /*printf("%s\n", raddr);*/
154 #ifdef IPPROTO_UDPLITE
155 if(atoi(proto
) == IPPROTO_UDPLITE
)
157 /* snprintf(cmd, sizeof(cmd), cmdval_full_udplite, miniupnpd_forward_chain, line_number, proto, ext_if_name, raddr, iaddr);
158 snprintf(cmd_raw, sizeof(cmd_raw), cmdval_full_udplite_raw, line_number, proto, ext_if_name, raddr, iaddr);*/
163 /* snprintf(cmd, sizeof(cmd), cmdval_full_udptcp, miniupnpd_forward_chain, line_number, proto, ext_if_name, raddr, rport, iaddr, iport);
164 snprintf(cmd_raw, sizeof(cmd_raw), cmdval_full_udptcp_raw, line_number, proto, ext_if_name, raddr, rport, iaddr, iport);*/
169 #ifdef IPPROTO_UDPLITE
170 if(atoi(proto
) == IPPROTO_UDPLITE
)
172 /*snprintf(cmd, sizeof(cmd), cmdval_udplite, miniupnpd_forward_chain, line_number, proto, ext_if_name, iaddr);
173 snprintf(cmd_raw, sizeof(cmd_raw), cmdval_udplite_raw, line_number, proto, ext_if_name, iaddr);*/
178 /*snprintf(cmd, sizeof(cmd), cmdval_udptcp, miniupnpd_forward_chain, line_number, proto, ext_if_name, rport, iaddr, iport);
179 snprintf(cmd_raw, sizeof(cmd_raw), cmdval_udptcp_raw, line_number, proto, ext_if_name, rport, iaddr, iport);
184 syslog(LOG_INFO
, "Adding following ip6tables rule:");
185 syslog(LOG_INFO
, " -> %s", cmd
);
186 syslog(LOG_INFO
, " -> %s", cmd_raw
);
188 /* TODO Add a better checking error.*/
189 if(system(cmd
) < 0 || system(cmd_raw
) < 0)
194 snprintf(cuid
, sizeof(cuid
), "%.4d", rand()%c
);
196 printf("\t_add_ uid: %s\n", cuid
);
201 /* upnp_get_pinhole_info()
205 * -2 NOT FOUND (no such entry)
207 * -42 Not implemented
210 upnp_get_pinhole_info(unsigned short uid
,
211 char * raddr
, int raddrlen
,
212 unsigned short * rport
,
213 char * iaddr
, int iaddrlen
,
214 unsigned short * iport
,
216 unsigned int * leasetime
,
217 unsigned int * packets
)
219 /* Call Firewall specific code to get IPv6 pinhole infos */
220 #if defined(USE_PF) || defined(USE_NETFILTER)
222 unsigned int timestamp
;
223 u_int64_t packets_tmp
;
224 /*u_int64_t bytes_tmp;*/
226 r
= get_pinhole_info(uid
, raddr
, raddrlen
, rport
,
227 iaddr
, iaddrlen
, iport
, proto
,
228 leasetime
? ×tamp
: NULL
,
229 packets
? &packets_tmp
: NULL
,
234 current_time
= time(NULL
);
235 if(timestamp
> (unsigned int)current_time
)
236 *leasetime
= timestamp
- current_time
;
241 *packets
= (unsigned int)packets_tmp
;
246 UNUSED(raddr
); UNUSED(raddrlen
); UNUSED(rport
);
247 UNUSED(iaddr
); UNUSED(iaddrlen
); UNUSED(iport
);
248 UNUSED(proto
); UNUSED(leasetime
); UNUSED(packets
);
249 return -42; /* not implemented */
254 upnp_update_inboundpinhole(unsigned short uid
, unsigned int leasetime
)
256 #if defined(USE_PF) || defined(USE_NETFILTER)
257 unsigned int timestamp
;
259 timestamp
= time(NULL
) + leasetime
;
260 return update_pinhole(uid
, timestamp
);
262 UNUSED(uid
); UNUSED(leasetime
);
264 return -42; /* not implemented */
269 upnp_delete_inboundpinhole(unsigned short uid
)
271 #if defined(USE_PF) || defined(USE_NETFILTER)
272 return delete_pinhole(uid
);
285 * -5: Result in another table
286 * -6: Result in another chain
287 * -7: Result in a chain not a rule
290 upnp_check_pinhole_working(const char * uid
,
293 unsigned short * eport
,
294 unsigned short * iport
,
298 /* TODO : to be implemented */
301 time_t expire
= time(NULL
);
302 char buf
[1024], filename
[] = "/var/log/kern.log", expire_time
[32]="";
303 int res
= -4, str_len
;
305 str_len
= strftime(expire_time
, sizeof(expire_time
), "%b %d %H:%M:%S", localtime(&expire
));
307 fd
= fopen(filename
, "r");
310 syslog(LOG_ERR
, "Get_rule: could not open file: %s", filename
);
314 syslog(LOG_INFO
, "Get_rule: Starting getting info in file %s for %s\n", filename
, uid
);
315 buf
[sizeof(buf
)-1] = 0;
316 while(fgets(buf
, sizeof(buf
)-1, fd
) != NULL
&& res
!= 1)
318 //printf("line: %s\n", buf);
319 char * r
, * t
, * c
, * p
;
320 // looking for something like filter:FORWARD:rule: or filter:MINIUPNPD:rule:
321 r
= strstr(buf
, ":rule:");
322 p
= strstr(buf
, ":policy:");
323 t
= strstr(buf
, "TRACE:"); // table pointeur
325 c
= t
+ 7; // chain pointeur
328 printf("\t** Found %.*s\n", 24 ,t
);
329 char * src
, * dst
, * sport
, * dport
, * proto
, * line
;
330 char time
[15]="", src_addr
[40], dst_addr
[40], proto_tmp
[8];
332 strncpy(time
, buf
, sizeof(time
));
333 /*if(compare_time(time, expire_time)<0)
335 printf("\t\tNot corresponding time\n");
340 printf("\trule line = %d\n", atoi(line
));
342 src
= strstr(buf
, "SRC=");
344 snprintf(src_addr
, sizeof(src_addr
), "%.*s", 39, src
);
350 dst
= strstr(buf
, "DST=");
352 snprintf(dst_addr
, sizeof(dst_addr
), "%.*s", 39, dst
);
358 proto
= strstr(buf
, "PROTO=");
360 proto_int
= atoi(protocol
);
361 if(proto_int
== IPPROTO_UDP
)
362 strcpy(proto_tmp
, "UDP");
363 else if(proto_int
== IPPROTO_TCP
)
364 strcpy(proto_tmp
, "TCP");
365 #ifdef IPPROTO_UDPLITE
366 else if(proto_int
== IPPROTO_UDPLITE
)
367 strcpy(proto_tmp
, "UDPLITE");
370 strcpy(proto_tmp
, "UnsupportedProto");
372 // printf("\tCompare eaddr: %s // protocol: %s\n\t to addr: %s // protocol: %.*s\n", eaddr, proto_tmp, src_addr, strlen(proto_tmp), proto);
373 // printf("\tCompare iaddr: %s // protocol: %s\n\t to addr: %s // protocol: %.*s\n", iaddr, proto_tmp, dst_addr, strlen(proto_tmp), proto);
375 // Check that the paquet found in trace correspond to the one we are looking for
376 if( /*(strcmp(eaddr, src_addr) == 0) &&*/ (strcmp(iaddr
, dst_addr
) == 0) && (strncmp(proto_tmp
, proto
, strlen(proto_tmp
))==0))
378 sport
= strstr(buf
, "SPT=");
380 dport
= strstr(buf
, "DPT=");
382 printf("\tCompare eport: %hu\n\t to port: %d\n", *eport
, atoi(sport
));
383 printf("\tCompare iport: %hu\n\t to port: %d\n", *iport
, atoi(dport
));
384 if(/*eport != atoi(sport) &&*/ *iport
!= atoi(dport
))
386 printf("\t\tPort not corresponding\n");
389 printf("\ttable found: %.*s\n", 6, t
);
390 printf("\tchain found: %.*s\n", 9, c
);
391 // Check that the table correspond to the filter table
392 if(strncmp(t
, "filter", 6)==0)
394 // Check that the table correspond to the MINIUPNP table
395 if(strncmp(c
, "MINIUPNPD", 9)==0)
397 *rulenum_used
= atoi(line
);
414 printf("Packet information not corresponding\n");
420 printf("\t** Policy case\n");
421 char * src
, * dst
, * sport
, * dport
, * proto
, * line
;
422 char time
[15], src_addr
[40], dst_addr
[40], proto_tmp
[8];
424 strncpy(time
, buf
, sizeof(time
));
425 /*if(compare_time(time, expire_time)<0)
427 printf("\t\tNot corresponding time\n");
432 printf("\trule line = %d\n", atoi(line
));
434 src
= strstr(buf
, "SRC=");
436 snprintf(src_addr
, sizeof(src_addr
), "%.*s", 39, src
);
442 dst
= strstr(buf
, "DST=");
444 snprintf(dst_addr
, sizeof(dst_addr
), "%.*s", 39, dst
);
450 proto
= strstr(buf
, "PROTO=");
452 proto_int
= atoi(protocol
);
453 if(proto_int
== IPPROTO_UDP
)
454 strcpy(proto_tmp
, "UDP");
455 else if(proto_int
== IPPROTO_TCP
)
456 strcpy(proto_tmp
, "TCP");
457 #ifdef IPPROTO_UDPLITE
458 else if(proto_int
== IPPROTO_UDPLITE
)
459 strcpy(proto_tmp
, "UDPLITE");
462 strcpy(proto_tmp
, "UnsupportedProto");
464 // printf("\tCompare eaddr: %s // protocol: %s\n\t to addr: %s // protocol: %.*s\n", eaddr, proto_tmp, src_addr, strlen(proto_tmp), proto);
465 // printf("\tCompare iaddr: %s // protocol: %s\n\t to addr: %s // protocol: %.*s\n", iaddr, proto_tmp, dst_addr, strlen(proto_tmp), proto);
466 // Check that the paquet found in trace correspond to the one we are looking for
467 if( (strcmp(eaddr
, src_addr
) == 0) && (strcmp(iaddr
, dst_addr
) == 0) && (strncmp(proto_tmp
, proto
, 5)==0))
469 sport
= strstr(buf
, "SPT=");
471 dport
= strstr(buf
, "DPT=");
473 printf("\tCompare eport: %hu\n\t to port: %d\n", *eport
, atoi(sport
));
474 printf("\tCompare iport: %hu\n\t to port: %d\n", *iport
, atoi(dport
));
475 if(*eport
!= atoi(sport
) && *iport
!= atoi(dport
))
477 printf("\t\tPort not corresponding\n");
482 printf("Find a corresponding policy trace in the chain: %.*s\n", 10, c
);
494 return -42; /* to be implemented */
500 upnp_clean_expired_pinholes(unsigned int * next_timestamp
)
502 #if defined(USE_PF) || defined(USE_NETFILTER)
503 return clean_pinhole_list(next_timestamp
);
505 UNUSED(next_timestamp
);
507 return 0; /* nothing to do */