1: /* $Id: upnpredirect.c,v 1.1.1.2 2012/05/29 12:55:57 misho 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 */
7:
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>
16:
17: #include <stdio.h>
18: #include <ctype.h>
19: #include <unistd.h>
20:
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
44:
45: /* from <inttypes.h> */
46: #ifndef PRIu64
47: #define PRIu64 "llu"
48: #endif
49:
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)
54: {
55: int proto = IPPROTO_TCP;
56: if(strcmp(protocol, "UDP") == 0)
57: proto = IPPROTO_UDP;
58: return proto;
59: }
60:
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)
69: {
70: FILE * fd;
71:
72: if (lease_file == NULL) return 0;
73:
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;
78: }
79:
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);
84:
85: return 0;
86: }
87:
88: static int
89: lease_file_remove(unsigned short eport, int proto)
90: {
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;
97:
98:
99: if (lease_file == NULL) return 0;
100:
101: if (strlen( lease_file) + 7 > sizeof(tmpfilename)) {
102: syslog(LOG_ERR, "Lease filename is too long");
103: return -1;
104: }
105:
106: strncpy( tmpfilename, lease_file, sizeof(tmpfilename) );
107: strncat( tmpfilename, "XXXXXX", sizeof(tmpfilename) - strlen(tmpfilename));
108:
109: fd = fopen( lease_file, "r");
110: if (fd==NULL) {
111: return 0;
112: }
113:
114: snprintf( str, sizeof(str), "%s:%u", ((proto==IPPROTO_TCP)?"TCP":"UDP"), eport);
115: str_size = strlen(str);
116:
117: tmp = mkstemp(tmpfilename);
118: if (tmp==-1) {
119: fclose(fd);
120: syslog(LOG_ERR, "could not open temporary lease file");
121: return -1;
122: }
123: fchmod(tmp, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
124: fdt = fdopen(tmp, "a");
125:
126: buf[sizeof(buf)-1] = 0;
127: while( fgets(buf, sizeof(buf)-1, fd) != NULL) {
128: buf_size = strlen(buf);
129:
130: if (buf_size < str_size || strncmp(str, buf, str_size)!=0) {
131: fwrite(buf, buf_size, 1, fdt);
132: }
133: }
134: fclose(fdt);
135: fclose(fd);
136:
137: if (rename(tmpfilename, lease_file) < 0) {
138: syslog(LOG_ERR, "could not rename temporary lease file to %s", lease_file);
139: remove(tmpfilename);
140: }
141:
142: return 0;
143:
144: }
145:
146: /* reload_from_lease_file()
147: * read lease_file and add the rules contained
148: */
149: int reload_from_lease_file()
150: {
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;
163:
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;
169: }
170: if(unlink(lease_file) < 0) {
171: syslog(LOG_WARNING, "could not unlink file %s : %m", lease_file);
172: }
173:
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;
182: }
183: *(p++) = '\0';
184: iaddr = strchr(p, ':');
185: if(!iaddr) {
186: syslog(LOG_ERR, "unrecognized data in lease file");
187: continue;
188: }
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;
195: }
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;
202: }
203: *(p++) = '\0';
204: desc = strchr(p, ':');
205: if(!desc) {
206: syslog(LOG_ERR, "unrecognized data in lease file");
207: continue;
208: }
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';
219:
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;
226: }
227: } else {
228: leaseduration = 0; /* default value */
229: }
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);
239: }
240: }
241: fclose(fd);
242:
243: return 0;
244: }
245: #endif
246:
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
254: */
255: int
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)
260: {
261: int proto, r;
262: char iaddr_old[32];
263: unsigned short iport_old;
264: struct in_addr address;
265: unsigned int timestamp;
266:
267: proto = proto_atoi(protocol);
268: if(inet_aton(iaddr, &address) < 0) {
269: syslog(LOG_ERR, "inet_aton(%s) : %m", iaddr);
270: return -1;
271: }
272:
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;
278: }
279: r = get_redirect_rule(ext_if_name, eport, proto,
280: iaddr_old, sizeof(iaddr_old), &iport_old, 0, 0,
281: 0, 0,
282: ×tamp, 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: syslog(LOG_INFO, "ignoring redirect request as it matches existing redirect");
289: } else {
290:
291: syslog(LOG_INFO, "port %hu protocol %s already redirected to %s:%hu",
292: eport, protocol, iaddr_old, iport_old);
293: return -2;
294: }
295: } else {
296: timestamp = (leaseduration > 0) ? time(NULL) + leaseduration : 0;
297: syslog(LOG_INFO, "redirecting port %hu to %s:%hu protocol %s for: %s",
298: eport, iaddr, iport, protocol, desc);
299: return upnp_redirect_internal(rhost, eport, iaddr, iport, proto,
300: desc, timestamp);
301: }
302:
303: return 0;
304: }
305:
306: int
307: upnp_redirect_internal(const char * rhost, unsigned short eport,
308: const char * iaddr, unsigned short iport,
309: int proto, const char * desc,
310: unsigned int timestamp)
311: {
312: /*syslog(LOG_INFO, "redirecting port %hu to %s:%hu protocol %s for: %s",
313: eport, iaddr, iport, protocol, desc); */
314: if(add_redirect_rule2(ext_if_name, rhost, eport, iaddr, iport, proto,
315: desc, timestamp) < 0) {
316: return -1;
317: }
318:
319: #ifdef ENABLE_LEASEFILE
320: lease_file_add( eport, iaddr, iport, proto, desc, timestamp);
321: #endif
322: /* syslog(LOG_INFO, "creating pass rule to %s:%hu protocol %s for: %s",
323: iaddr, iport, protocol, desc);*/
324: if(add_filter_rule2(ext_if_name, rhost, iaddr, eport, iport, proto, desc) < 0) {
325: /* clean up the redirect rule */
326: #if !defined(__linux__)
327: delete_redirect_rule(ext_if_name, eport, proto);
328: #endif
329: return -1;
330: }
331: if(timestamp > 0) {
332: if(!nextruletoclean_timestamp || (timestamp < nextruletoclean_timestamp))
333: nextruletoclean_timestamp = timestamp;
334: }
335: #ifdef ENABLE_EVENTS
336: /* the number of port mappings changed, we must
337: * inform the subscribers */
338: upnp_event_var_change_notify(EWanIPC);
339: #endif
340: return 0;
341: }
342:
343:
344:
345: /* Firewall independant code which call the FW dependant code. */
346: int
347: upnp_get_redirection_infos(unsigned short eport, const char * protocol,
348: unsigned short * iport,
349: char * iaddr, int iaddrlen,
350: char * desc, int desclen,
351: char * rhost, int rhostlen,
352: unsigned int * leaseduration)
353: {
354: int r;
355: unsigned int timestamp;
356: time_t current_time;
357:
358: if(desc && (desclen > 0))
359: desc[0] = '\0';
360: if(rhost && (rhostlen > 0))
361: rhost[0] = '\0';
362: r = get_redirect_rule(ext_if_name, eport, proto_atoi(protocol),
363: iaddr, iaddrlen, iport, desc, desclen,
364: rhost, rhostlen, ×tamp,
365: 0, 0);
366: if(r == 0 && timestamp > 0 && timestamp > (current_time = time(NULL))) {
367: *leaseduration = timestamp - current_time;
368: } else {
369: *leaseduration = 0;
370: }
371: return r;
372: }
373:
374: int
375: upnp_get_redirection_infos_by_index(int index,
376: unsigned short * eport, char * protocol,
377: unsigned short * iport,
378: char * iaddr, int iaddrlen,
379: char * desc, int desclen,
380: char * rhost, int rhostlen,
381: unsigned int * leaseduration)
382: {
383: /*char ifname[IFNAMSIZ];*/
384: int proto = 0;
385: unsigned int timestamp;
386: time_t current_time;
387:
388: if(desc && (desclen > 0))
389: desc[0] = '\0';
390: if(rhost && (rhost > 0))
391: rhost[0] = '\0';
392: if(get_redirect_rule_by_index(index, 0/*ifname*/, eport, iaddr, iaddrlen,
393: iport, &proto, desc, desclen,
394: rhost, rhostlen, ×tamp,
395: 0, 0) < 0)
396: return -1;
397: else
398: {
399: current_time = time(NULL);
400: *leaseduration = (timestamp > current_time)
401: ? (timestamp - current_time)
402: : 0;
403: if(proto == IPPROTO_TCP)
404: memcpy(protocol, "TCP", 4);
405: else
406: memcpy(protocol, "UDP", 4);
407: return 0;
408: }
409: }
410:
411: /* called from natpmp.c too */
412: int
413: _upnp_delete_redir(unsigned short eport, int proto)
414: {
415: int r;
416: #if defined(__linux__)
417: r = delete_redirect_and_filter_rules(eport, proto);
418: #else
419: r = delete_redirect_rule(ext_if_name, eport, proto);
420: delete_filter_rule(ext_if_name, eport, proto);
421: #endif
422: #ifdef ENABLE_LEASEFILE
423: lease_file_remove( eport, proto);
424: #endif
425:
426: #ifdef ENABLE_EVENTS
427: upnp_event_var_change_notify(EWanIPC);
428: #endif
429: return r;
430: }
431:
432: int
433: upnp_delete_redirection(unsigned short eport, const char * protocol)
434: {
435: syslog(LOG_INFO, "removing redirect rule port %hu %s", eport, protocol);
436: return _upnp_delete_redir(eport, proto_atoi(protocol));
437: }
438:
439: /* upnp_get_portmapping_number_of_entries()
440: * TODO: improve this code. */
441: int
442: upnp_get_portmapping_number_of_entries()
443: {
444: int n = 0, r = 0;
445: unsigned short eport, iport;
446: char protocol[4], iaddr[32], desc[64], rhost[32];
447: unsigned int leaseduration;
448: do {
449: protocol[0] = '\0'; iaddr[0] = '\0'; desc[0] = '\0';
450: r = upnp_get_redirection_infos_by_index(n, &eport, protocol, &iport,
451: iaddr, sizeof(iaddr),
452: desc, sizeof(desc),
453: rhost, sizeof(rhost),
454: &leaseduration);
455: n++;
456: } while(r==0);
457: return (n-1);
458: }
459:
460: /* functions used to remove unused rules
461: * As a side effect, delete expired rules (based on LeaseDuration) */
462: struct rule_state *
463: get_upnp_rules_state_list(int max_rules_number_target)
464: {
465: /*char ifname[IFNAMSIZ];*/
466: int proto;
467: unsigned short iport;
468: unsigned int timestamp;
469: struct rule_state * tmp;
470: struct rule_state * list = 0;
471: struct rule_state * * p;
472: int i = 0;
473: time_t current_time;
474:
475: /*ifname[0] = '\0';*/
476: tmp = malloc(sizeof(struct rule_state));
477: if(!tmp)
478: return 0;
479: current_time = time(NULL);
480: nextruletoclean_timestamp = 0;
481: while(get_redirect_rule_by_index(i, /*ifname*/0, &tmp->eport, 0, 0,
482: &iport, &proto, 0, 0, 0,0, ×tamp,
483: &tmp->packets, &tmp->bytes) >= 0)
484: {
485: tmp->to_remove = 0;
486: if(timestamp > 0) {
487: /* need to remove this port mapping ? */
488: if(timestamp <= current_time)
489: tmp->to_remove = 1;
490: else if((nextruletoclean_timestamp <= current_time)
491: || (timestamp < nextruletoclean_timestamp))
492: nextruletoclean_timestamp = timestamp;
493: }
494: tmp->proto = (short)proto;
495: /* add tmp to list */
496: tmp->next = list;
497: list = tmp;
498: /* prepare next iteration */
499: i++;
500: tmp = malloc(sizeof(struct rule_state));
501: if(!tmp)
502: break;
503: }
504: free(tmp);
505: /* remove the redirections that need to be removed */
506: for(p = &list, tmp = list; tmp; tmp = *p)
507: {
508: if(tmp->to_remove)
509: {
510: syslog(LOG_NOTICE, "remove port mapping %hu %s because it has expired",
511: tmp->eport, (tmp->proto==IPPROTO_TCP)?"TCP":"UDP");
512: _upnp_delete_redir(tmp->eport, tmp->proto);
513: *p = tmp->next;
514: free(tmp);
515: i--;
516: } else {
517: p = &(tmp->next);
518: }
519: }
520: /* return empty list if not enough redirections */
521: if(i<=max_rules_number_target)
522: while(list)
523: {
524: tmp = list;
525: list = tmp->next;
526: free(tmp);
527: }
528: /* return list */
529: return list;
530: }
531:
532: void
533: remove_unused_rules(struct rule_state * list)
534: {
535: char ifname[IFNAMSIZ];
536: unsigned short iport;
537: struct rule_state * tmp;
538: u_int64_t packets;
539: u_int64_t bytes;
540: unsigned int timestamp;
541: int n = 0;
542:
543: while(list)
544: {
545: /* remove the rule if no traffic has used it */
546: if(get_redirect_rule(ifname, list->eport, list->proto,
547: 0, 0, &iport, 0, 0, 0, 0, ×tamp,
548: &packets, &bytes) >= 0)
549: {
550: if(packets == list->packets && bytes == list->bytes)
551: {
552: _upnp_delete_redir(list->eport, list->proto);
553: n++;
554: }
555: }
556: tmp = list;
557: list = tmp->next;
558: free(tmp);
559: }
560: if(n>0)
561: syslog(LOG_NOTICE, "removed %d unused rules", n);
562: }
563:
564: /* upnp_get_portmappings_in_range()
565: * return a list of all "external" ports for which a port
566: * mapping exists */
567: unsigned short *
568: upnp_get_portmappings_in_range(unsigned short startport,
569: unsigned short endport,
570: const char * protocol,
571: unsigned int * number)
572: {
573: int proto;
574: proto = proto_atoi(protocol);
575: if(!number)
576: return NULL;
577: return get_portmappings_in_range(startport, endport, proto, number);
578: }
579:
580: #ifdef ENABLE_6FC_SERVICE
581: int
582: upnp_check_outbound_pinhole(int proto, int * timeout)
583: {
584: #if 0
585: int s, tmptimeout, tmptime_out;
586: switch(proto)
587: {
588: case IPPROTO_UDP:
589: s = retrieve_timeout("udp_timeout", timeout);
590: return s;
591: break;
592: case IPPROTO_UDPLITE:
593: s = retrieve_timeout("udp_timeout_stream", timeout);
594: return s;
595: break;
596: case IPPROTO_TCP:
597: s = retrieve_timeout("tcp_timeout_established", timeout);
598: return s;
599: break;
600: case 65535:
601: s = retrieve_timeout("udp_timeout", timeout);
602: s = retrieve_timeout("udp_timeout_stream", &tmptimeout);
603: s = retrieve_timeout("tcp_timeout_established", &tmptime_out);
604: if(tmptimeout<tmptime_out)
605: {
606: if(tmptimeout<*timeout)
607: *timeout = tmptimeout;
608: }
609: else
610: {
611: if(tmptime_out<*timeout)
612: *timeout = tmptimeout;
613: }
614: return s;
615: break;
616: default:
617: return -5;
618: break;
619: }
620: #endif
621: return 0;
622: }
623:
624: /* upnp_add_inboundpinhole()
625: * returns: 0 on success
626: * -1 failed to add pinhole
627: * -2 already created
628: * -3 inbound pinhole disabled
629: */
630: int
631: upnp_add_inboundpinhole(const char * raddr,
632: unsigned short rport,
633: const char * iaddr,
634: unsigned short iport,
635: const char * protocol,
636: const char * leaseTime,
637: int * uid)
638: {
639: int r, s, t, lt=0;
640: char iaddr_old[40]="", proto[6]="", idfound[5]="", leaseTmp[12]; // IPv6 Modification
641: snprintf(proto, sizeof(proto), "%.5d", atoi(protocol));
642: unsigned short iport_old = 0;
643: time_t current = time(NULL);
644: /*struct in6_addr address; // IPv6 Modification
645: if(inet_pton(AF_INET6, iaddr, &address) < 0) // IPv6 Modification
646: {
647: syslog(LOG_ERR, "inet_pton(%s) : %m", iaddr);
648: return 0;
649: }*/
650:
651: #if 0
652: r = get_rule_from_file(raddr, rport, iaddr_old, &iport_old, proto, 0, 0, idfound);
653: #endif
654: r = 0;
655:
656: lt = (int) current + atoi(leaseTime);
657: snprintf(leaseTmp, sizeof(leaseTmp), "%d", lt);
658: printf("LeaseTime: %d / %d -> %s\n", atoi(leaseTime), (int)current, leaseTmp);
659:
660: printf("\tCompare addr: %s // port: %d\n\t to addr: %s // port: %d\n", iaddr, iport, iaddr_old, iport_old);
661: if(r == 1 && strcmp(iaddr, iaddr_old)==0 && iport==iport_old)
662: {
663: 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);
664: t = upnp_update_inboundpinhole(idfound, leaseTime);
665: *uid = atoi(idfound);
666: return t;
667: }
668: else
669: {
670: 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);
671: s = upnp_add_inboundpinhole_internal(raddr, rport, iaddr, iport, protocol, uid);
672: #if 0
673: if(rule_file_add(raddr, rport, iaddr, iport, protocol, leaseTmp, uid)<0)
674: return -8;
675: else
676: {
677: if(nextpinholetoclean_timestamp == 0 || (atoi(leaseTmp) <= nextpinholetoclean_timestamp))
678: {
679: printf("Initializing the nextpinholetoclean variables. uid = %d\n", *uid);
680: snprintf(nextpinholetoclean_uid, 5, "%.4d", *uid);
681: nextpinholetoclean_timestamp = atoi(leaseTmp);
682: }
683: return s;
684: }
685: #endif
686: }
687: return 0;
688: }
689:
690: int
691: upnp_add_inboundpinhole_internal(const char * raddr, unsigned short rport,
692: const char * iaddr, unsigned short iport,
693: const char * proto, int * uid)
694: {
695: int c = 9999;
696: char cmd[256], cmd_raw[256], cuid[42];
697: #if 0
698: static const char cmdval_full_udptcp[] = "ip6tables -I %s %d -p %s -i %s -s %s --sport %hu -d %s --dport %hu -j ACCEPT";
699: static const char cmdval_udptcp[] = "ip6tables -I %s %d -p %s -i %s --sport %hu -d %s --dport %hu -j ACCEPT";
700: static const char cmdval_full_udplite[] = "ip6tables -I %s %d -p %s -i %s -s %s -d %s -j ACCEPT";
701: static const char cmdval_udplite[] = "ip6tables -I %s %d -p %s -i %s -d %s -j ACCEPT";
702: // raw table command
703: 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";
704: static const char cmdval_udptcp_raw[] = "ip6tables -t raw -I PREROUTING %d -p %s -i %s --sport %hu -d %s --dport %hu -j TRACE";
705: static const char cmdval_full_udplite_raw[] = "ip6tables -t raw -I PREROUTING %d -p %s -i %s -s %s -d %s -j TRACE";
706: static const char cmdval_udplite_raw[] = "ip6tables -t raw -I PREROUTING %d -p %s -i %s -d %s -j TRACE";
707: #endif
708: //printf("%s\n", raddr);
709: if(raddr!=NULL)
710: {
711: #ifdef IPPROTO_UDPLITE
712: if(atoi(proto) == IPPROTO_UDPLITE)
713: {
714: /* snprintf(cmd, sizeof(cmd), cmdval_full_udplite, miniupnpd_forward_chain, line_number, proto, ext_if_name, raddr, iaddr);
715: snprintf(cmd_raw, sizeof(cmd_raw), cmdval_full_udplite_raw, line_number, proto, ext_if_name, raddr, iaddr);*/
716: }
717: else
718: #endif
719: {
720: /* snprintf(cmd, sizeof(cmd), cmdval_full_udptcp, miniupnpd_forward_chain, line_number, proto, ext_if_name, raddr, rport, iaddr, iport);
721: snprintf(cmd_raw, sizeof(cmd_raw), cmdval_full_udptcp_raw, line_number, proto, ext_if_name, raddr, rport, iaddr, iport);*/
722: }
723: }
724: else
725: {
726: #ifdef IPPROTO_UDPLITE
727: if(atoi(proto) == IPPROTO_UDPLITE)
728: {
729: /*snprintf(cmd, sizeof(cmd), cmdval_udplite, miniupnpd_forward_chain, line_number, proto, ext_if_name, iaddr);
730: snprintf(cmd_raw, sizeof(cmd_raw), cmdval_udplite_raw, line_number, proto, ext_if_name, iaddr);*/
731: }
732: else
733: #endif
734: {
735: /*snprintf(cmd, sizeof(cmd), cmdval_udptcp, miniupnpd_forward_chain, line_number, proto, ext_if_name, rport, iaddr, iport);
736: snprintf(cmd_raw, sizeof(cmd_raw), cmdval_udptcp_raw, line_number, proto, ext_if_name, rport, iaddr, iport);
737: */
738: }
739: }
740: #ifdef DEBUG
741: syslog(LOG_INFO, "Adding following ip6tables rule:");
742: syslog(LOG_INFO, " -> %s", cmd);
743: syslog(LOG_INFO, " -> %s", cmd_raw);
744: #endif
745: // TODO Add a better checking error.
746: if(system(cmd) < 0 || system(cmd_raw) < 0)
747: {
748: return 0;
749: }
750: srand(time(NULL));
751: snprintf(cuid, sizeof(cuid), "%.4d", rand()%c);
752: *uid = atoi(cuid);
753: printf("\t_add_ uid: %s\n", cuid);
754: return 1;
755: }
756:
757: int
758: upnp_get_pinhole_info(const char * raddr,
759: unsigned short rport,
760: char * iaddr,
761: unsigned short * iport,
762: char * proto,
763: const char * uid,
764: char * lt)
765: {
766: /* TODO : to be done
767: * Call Firewall specific code to get IPv6 pinhole infos */
768: return 0;
769: }
770:
771: int
772: upnp_update_inboundpinhole(const char * uid, const char * leasetime)
773: {
774: /* TODO : to be implemented */
775: #if 0
776: int r, n;
777: syslog(LOG_INFO, "Updating pinhole for inbound traffic with ID: %s", uid);
778: r = check_rule_from_file(uid, 0);
779: if(r < 0)
780: return r;
781: else
782: {
783: n = rule_file_update(uid, leasetime);
784: upnp_update_expiredpinhole();
785: return n;
786: }
787: #else
788: return -1;
789: #endif
790: }
791:
792: int
793: upnp_delete_inboundpinhole(const char * uid)
794: {
795: /* TODO : to be implemented */
796: #if 0
797: /* this is a alpha implementation calling ip6tables via system(),
798: * it can be usefull as an example to code the netfilter version */
799: int r, s, linenum=0;
800: char cmd[256], cmd_raw[256];
801: syslog(LOG_INFO, "Removing pinhole for inbound traffic with ID: %s", uid);
802: r = check_rule_from_file(uid, &linenum);
803: if(r > 0)
804: {
805: s = rule_file_remove(uid, linenum);
806: if(s < 0)
807: return s;
808: else
809: {
810: snprintf(cmd, sizeof(cmd), "ip6tables -t filter -D %s %d", miniupnpd_forward_chain, linenum);
811: snprintf(cmd_raw, sizeof(cmd_raw), "ip6tables -t raw -D PREROUTING %d", linenum -1);
812: #ifdef DEBUG
813: syslog(LOG_INFO, "Deleting ip6tables rule:");
814: syslog(LOG_INFO, " -> %s", cmd);
815: syslog(LOG_INFO, " -> %s", cmd_raw);
816: #endif
817: // TODO Add a better checking error.
818: if(system(cmd) < 0 || system(cmd_raw) < 0)
819: {
820: return 0;
821: }
822: }
823: }
824: upnp_update_expiredpinhole();
825: return r;
826: #else
827: return -1;
828: #endif
829: }
830:
831: /*
832: * Result:
833: * 1: Found Result
834: * -4: No result
835: * -5: Result in another table
836: * -6: Result in another chain
837: * -7: Result in a chain not a rule
838: */
839: int
840: upnp_check_pinhole_working(const char * uid,
841: char * eaddr,
842: char * iaddr,
843: unsigned short * eport,
844: unsigned short * iport,
845: char * protocol,
846: int * rulenum_used)
847: {
848: /* TODO : to be implemented */
849: #if 0
850: FILE * fd;
851: time_t expire = time(NULL);
852: char buf[1024], filename[] = "/var/log/kern.log", expire_time[32]="";
853: int res = -4, str_len;
854:
855: str_len = strftime(expire_time, sizeof(expire_time), "%b %d %H:%M:%S", localtime(&expire));
856:
857: fd = fopen(filename, "r");
858: if (fd==NULL)
859: {
860: syslog(LOG_ERR, "Get_rule: could not open file: %s", filename);
861: return -1;
862: }
863:
864: syslog(LOG_INFO, "Get_rule: Starting getting info in file %s for %s\n", filename, uid);
865: buf[sizeof(buf)-1] = 0;
866: while(fgets(buf, sizeof(buf)-1, fd) != NULL && res != 1)
867: {
868: //printf("line: %s\n", buf);
869: char * r, * t, * c, * p;
870: // looking for something like filter:FORWARD:rule: or filter:MINIUPNPD:rule:
871: r = strstr(buf, ":rule:");
872: p = strstr(buf, ":policy:");
873: t = strstr(buf, "TRACE:"); // table pointeur
874: t += 7;
875: c = t + 7; // chain pointeur
876: if(r)
877: {
878: printf("\t** Found %.*s\n", 24 ,t);
879: char * src, * dst, * sport, * dport, * proto, * line;
880: char time[15]="", src_addr[40], dst_addr[40], proto_tmp[8];
881: int proto_int;
882: strncpy(time, buf, sizeof(time));
883: /*if(compare_time(time, expire_time)<0)
884: {
885: printf("\t\tNot corresponding time\n");
886: continue;
887: }*/
888:
889: line = r + 6;
890: printf("\trule line = %d\n", atoi(line));
891:
892: src = strstr(buf, "SRC=");
893: src += 4;
894: snprintf(src_addr, sizeof(src_addr), "%.*s", 39, src);
895: #if 0
896: del_char(src_addr);
897: add_char(src_addr);
898: #endif
899:
900: dst = strstr(buf, "DST=");
901: dst += 4;
902: snprintf(dst_addr, sizeof(dst_addr), "%.*s", 39, dst);
903: #if 0
904: del_char(dst_addr);
905: add_char(dst_addr);
906: #endif
907:
908: proto = strstr(buf, "PROTO=");
909: proto += 6;
910: proto_int = atoi(protocol);
911: if(proto_int == IPPROTO_UDP)
912: strcpy(proto_tmp, "UDP");
913: else if(proto_int == IPPROTO_TCP)
914: strcpy(proto_tmp, "TCP");
915: #ifdef IPPROTO_UDPLITE
916: else if(proto_int == IPPROTO_UDPLITE)
917: strcpy(proto_tmp, "UDPLITE");
918: #endif
919: else
920: strcpy(proto_tmp, "UnsupportedProto");
921:
922: // printf("\tCompare eaddr: %s // protocol: %s\n\t to addr: %s // protocol: %.*s\n", eaddr, proto_tmp, src_addr, strlen(proto_tmp), proto);
923: // printf("\tCompare iaddr: %s // protocol: %s\n\t to addr: %s // protocol: %.*s\n", iaddr, proto_tmp, dst_addr, strlen(proto_tmp), proto);
924: // TODO Check time
925: // Check that the paquet found in trace correspond to the one we are looking for
926: if( /*(strcmp(eaddr, src_addr) == 0) &&*/ (strcmp(iaddr, dst_addr) == 0) && (strncmp(proto_tmp, proto, strlen(proto_tmp))==0))
927: {
928: sport = strstr(buf, "SPT=");
929: sport += 4;
930: dport = strstr(buf, "DPT=");
931: dport += 4;
932: printf("\tCompare eport: %hu\n\t to port: %d\n", *eport, atoi(sport));
933: printf("\tCompare iport: %hu\n\t to port: %d\n", *iport, atoi(dport));
934: if(/*eport != atoi(sport) &&*/ *iport != atoi(dport))
935: {
936: printf("\t\tPort not corresponding\n");
937: continue;
938: }
939: printf("\ttable found: %.*s\n", 6, t);
940: printf("\tchain found: %.*s\n", 9, c);
941: // Check that the table correspond to the filter table
942: if(strncmp(t, "filter", 6)==0)
943: {
944: // Check that the table correspond to the MINIUPNP table
945: if(strncmp(c, "MINIUPNPD", 9)==0)
946: {
947: *rulenum_used = atoi(line);
948: res = 1;
949: }
950: else
951: {
952: res = -6;
953: continue;
954: }
955: }
956: else
957: {
958: res = -5;
959: continue;
960: }
961: }
962: else
963: {
964: printf("Packet information not corresponding\n");
965: continue;
966: }
967: }
968: if(!r && p)
969: {
970: printf("\t** Policy case\n");
971: char * src, * dst, * sport, * dport, * proto, * line;
972: char time[15], src_addr[40], dst_addr[40], proto_tmp[8];
973: int proto_int;
974: strncpy(time, buf, sizeof(time));
975: /*if(compare_time(time, expire_time)<0)
976: {
977: printf("\t\tNot corresponding time\n");
978: continue;
979: }*/
980:
981: line = p + 8;
982: printf("\trule line = %d\n", atoi(line));
983:
984: src = strstr(buf, "SRC=");
985: src += 4;
986: snprintf(src_addr, sizeof(src_addr), "%.*s", 39, src);
987: #if 0
988: del_char(src_addr);
989: add_char(src_addr);
990: #endif
991:
992: dst = strstr(buf, "DST=");
993: dst += 4;
994: snprintf(dst_addr, sizeof(dst_addr), "%.*s", 39, dst);
995: #if 0
996: del_char(dst_addr);
997: add_char(dst_addr);
998: #endif
999:
1000: proto = strstr(buf, "PROTO=");
1001: proto += 6;
1002: proto_int = atoi(protocol);
1003: if(proto_int == IPPROTO_UDP)
1004: strcpy(proto_tmp, "UDP");
1005: else if(proto_int == IPPROTO_TCP)
1006: strcpy(proto_tmp, "TCP");
1007: #ifdef IPPROTO_UDPLITE
1008: else if(proto_int == IPPROTO_UDPLITE)
1009: strcpy(proto_tmp, "UDPLITE");
1010: #endif
1011: else
1012: strcpy(proto_tmp, "UnsupportedProto");
1013:
1014: // printf("\tCompare eaddr: %s // protocol: %s\n\t to addr: %s // protocol: %.*s\n", eaddr, proto_tmp, src_addr, strlen(proto_tmp), proto);
1015: // printf("\tCompare iaddr: %s // protocol: %s\n\t to addr: %s // protocol: %.*s\n", iaddr, proto_tmp, dst_addr, strlen(proto_tmp), proto);
1016: // Check that the paquet found in trace correspond to the one we are looking for
1017: if( (strcmp(eaddr, src_addr) == 0) && (strcmp(iaddr, dst_addr) == 0) && (strncmp(proto_tmp, proto, 5)==0))
1018: {
1019: sport = strstr(buf, "SPT=");
1020: sport += 4;
1021: dport = strstr(buf, "DPT=");
1022: dport += 4;
1023: printf("\tCompare eport: %hu\n\t to port: %d\n", *eport, atoi(sport));
1024: printf("\tCompare iport: %hu\n\t to port: %d\n", *iport, atoi(dport));
1025: if(*eport != atoi(sport) && *iport != atoi(dport))
1026: {
1027: printf("\t\tPort not corresponding\n");
1028: continue;
1029: }
1030: else
1031: {
1032: printf("Find a corresponding policy trace in the chain: %.*s\n", 10, c);
1033: res = -7;
1034: continue;
1035: }
1036: }
1037: else
1038: continue;
1039: }
1040: }
1041: fclose(fd);
1042: return res;
1043: #else
1044: return -4;
1045: #endif
1046: }
1047:
1048: int
1049: upnp_get_pinhole_packets(const char * uid, int * packets)
1050: {
1051: /* TODO : to be implemented */
1052: #if 0
1053: int line=0, r;
1054: char cmd[256];
1055: r = check_rule_from_file(uid, &line);
1056: if(r < 0)
1057: return r;
1058: else
1059: {
1060: snprintf(cmd, sizeof(cmd), "ip6tables -L MINIUPNPD %d -v", line);
1061: return retrieve_packets(cmd, &line, packets);
1062: }
1063: #else
1064: return 0;
1065: #endif
1066: }
1067:
1068: int
1069: upnp_update_expiredpinhole(void)
1070: {
1071: #if 0
1072: int r;
1073: char uid[5], leaseTime[12];
1074:
1075: r = get_rule_from_leasetime(uid, leaseTime);
1076: if(r<0)
1077: return r;
1078: else
1079: {
1080: strcpy(nextpinholetoclean_uid, uid);
1081: nextpinholetoclean_timestamp = atoi(leaseTime);
1082: return 1;
1083: }
1084: #endif
1085: return 0;
1086: }
1087:
1088: int
1089: upnp_clean_expiredpinhole()
1090: {
1091: #if 0
1092: upnp_delete_inboundpinhole(nextpinholetoclean_uid);
1093:
1094: return upnp_update_expiredpinhole();
1095: #endif
1096: return 0;
1097: }
1098: #endif
1099:
1100: /* stuff for miniupnpdctl */
1101: #ifdef USE_MINIUPNPDCTL
1102: void
1103: write_ruleset_details(int s)
1104: {
1105: int proto = 0;
1106: unsigned short eport, iport;
1107: char desc[64];
1108: char iaddr[32];
1109: char rhost[32];
1110: unsigned int timestamp;
1111: u_int64_t packets;
1112: u_int64_t bytes;
1113: int i = 0;
1114: char buffer[256];
1115: int n;
1116:
1117: write(s, "Ruleset :\n", 10);
1118: while(get_redirect_rule_by_index(i, 0/*ifname*/, &eport, iaddr, sizeof(iaddr),
1119: &iport, &proto, desc, sizeof(desc),
1120: rhost, sizeof(rhost),
1121: ×tamp,
1122: &packets, &bytes) >= 0)
1123: {
1124: n = snprintf(buffer, sizeof(buffer),
1125: "%2d %s %s:%hu->%s:%hu "
1126: "'%s' %u %" PRIu64 " %" PRIu64 "\n",
1127: /*"'%s' %llu %llu\n",*/
1128: i, proto==IPPROTO_TCP?"TCP":"UDP", rhost,
1129: eport, iaddr, iport, desc, timestamp, packets, bytes);
1130: write(s, buffer, n);
1131: i++;
1132: }
1133: }
1134: #endif
1135:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>