Annotation of embedaddon/miniupnpd/ipfw/ipfwrdr.c, revision 1.1.1.2
1.1.1.2 ! misho 1: /* $Id: ipfwrdr.c,v 1.11 2011/07/12 19:17:05 nanard Exp $ */
1.1 misho 2: /*
3: * MiniUPnP project
4: * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
5: * (c) 2009 Jardel Weyrich
1.1.1.2 ! misho 6: * (c) 2011 Thomas Bernard
1.1 misho 7: * This software is subject to the conditions detailed
8: * in the LICENCE file provided within the distribution
9: */
10:
1.1.1.2 ! misho 11: #include "../config.h"
! 12:
1.1 misho 13: #include <sys/param.h>
14: #include <sys/types.h>
15: #include <sys/file.h>
16:
17: //
18: // This is a workaround for <sys/uio.h> troubles on FreeBSD, HPUX, OpenBSD.
19: // Needed here because on some systems <sys/uio.h> gets included by things
20: // like <sys/socket.h>
21: //
22: #ifndef _KERNEL
23: # define ADD_KERNEL
24: # define _KERNEL
25: # define KERNEL
26: #endif
27: #ifdef __OpenBSD__
28: struct file;
29: #endif
30: #include <sys/uio.h>
31: #ifdef ADD_KERNEL
32: # undef _KERNEL
33: # undef KERNEL
34: #endif
35:
36: #include <sys/time.h>
37: #include <sys/socket.h>
38: #include <sys/syslog.h>
39: #include <sys/ioctl.h>
40: #include <net/if.h>
41: #if __FreeBSD_version >= 300000
42: # include <net/if_var.h>
43: #endif
44: #include <netinet/in.h>
45: #include <netinet/in_systm.h>
46: #include <netinet/ip.h>
47: #include <netinet/ip_icmp.h>
48: #include <netinet/tcp.h>
49: #include <netinet/udp.h>
50: #include <arpa/inet.h>
51:
52: #include <sys/types.h>
53: #include <sys/queue.h>
54: #include <sys/socket.h>
55: #include <errno.h>
56: #include <limits.h>
57: #include <netdb.h>
58: #include <stdlib.h>
59: #include <fcntl.h>
60: #include <syslog.h>
61: #include <stddef.h>
62: #include <stdio.h>
63: #include <strings.h>
64: #include <string.h>
65: #include <unistd.h>
66: #include <netinet/ip_fw.h>
67: #include "ipfwaux.h"
1.1.1.2 ! misho 68: #include "ipfwrdr.h"
1.1 misho 69:
70: #include "../upnpglobalvars.h"
71:
1.1.1.2 ! misho 72: /* init and shutdown functions */
1.1 misho 73:
74: int init_redirect(void) {
1.1.1.2 ! misho 75: return ipfw_exec(IP_FW_INIT, NULL, 0);
1.1 misho 76: }
77:
78: void shutdown_redirect(void) {
79: ipfw_exec(IP_FW_TERM, NULL, 0);
80: }
81:
1.1.1.2 ! misho 82: /* ipfw cannot store descriptions and timestamp for port mappings so we keep
! 83: * our own list in memory */
! 84: struct mapping_desc_time {
! 85: struct mapping_desc_time * next;
! 86: unsigned int timestamp;
! 87: unsigned short eport;
! 88: short proto;
! 89: char desc[];
! 90: };
! 91:
! 92: static struct mapping_desc_time * mappings_list = NULL;
! 93:
! 94: /* add an element to the port mappings descriptions & timestamp list */
! 95: static void
! 96: add_desc_time(unsigned short eport, int proto,
! 97: const char * desc, unsigned int timestamp)
! 98: {
! 99: struct mapping_desc_time * tmp;
! 100: size_t l;
! 101: if(!desc)
! 102: desc = "miniupnpd";
! 103: l = strlen(desc) + 1;
! 104: tmp = malloc(sizeof(struct mapping_desc_time) + l);
! 105: if(tmp) {
! 106: /* fill the element and insert it as head of the list */
! 107: tmp->next = mappings_list;
! 108: tmp->timestamp = timestamp;
! 109: tmp->eport = eport;
! 110: tmp->proto = (short)proto;
! 111: memcpy(tmp->desc, desc, l);
! 112: mappings_list = tmp;
! 113: }
! 114: }
! 115:
! 116: /* remove an element to the port mappings descriptions & timestamp list */
! 117: static void
! 118: del_desc_time(unsigned short eport, int proto)
! 119: {
! 120: struct mapping_desc_time * e;
! 121: struct mapping_desc_time * * p;
! 122: p = &mappings_list;
! 123: e = *p;
! 124: while(e) {
! 125: if(e->eport == eport && e->proto == (short)proto) {
! 126: *p = e->next;
! 127: free(e);
! 128: return;
! 129: } else {
! 130: p = &e->next;
! 131: e = *p;
! 132: }
! 133: }
! 134: }
! 135:
! 136: /* go through the list and find the description and timestamp */
! 137: static void
! 138: get_desc_time(unsigned short eport, int proto,
! 139: char * desc, int desclen,
! 140: unsigned int * timestamp)
! 141: {
! 142: struct mapping_desc_time * e;
! 143:
! 144: for(e = mappings_list; e; e = e->next) {
! 145: if(e->eport == eport && e->proto == (short)proto) {
! 146: if(desc)
! 147: strlcpy(desc, e->desc, desclen);
! 148: if(timestamp)
! 149: *timestamp = e->timestamp;
! 150: return;
! 151: }
! 152: }
! 153: }
! 154:
! 155: /* --- */
1.1 misho 156: int add_redirect_rule2(
157: const char * ifname,
1.1.1.2 ! misho 158: const char * rhost,
1.1 misho 159: unsigned short eport,
160: const char * iaddr,
161: unsigned short iport,
162: int proto,
1.1.1.2 ! misho 163: const char * desc,
! 164: unsigned int timestamp)
1.1 misho 165: {
166: struct ip_fw rule;
1.1.1.2 ! misho 167: int r;
1.1 misho 168:
169: if (ipfw_validate_protocol(proto) < 0)
170: return -1;
171: if (ipfw_validate_ifname(ifname) < 0)
172: return -1;
173:
174: memset(&rule, 0, sizeof(struct ip_fw));
175: rule.version = IP_FW_CURRENT_API_VERSION;
176: //rule.fw_number = 1000; // rule number
1.1.1.2 ! misho 177: //rule.context = (void *)desc; // The description is kept in a separate list
1.1 misho 178: rule.fw_prot = proto; // protocol
179: rule.fw_flg |= IP_FW_F_IIFACE; // interfaces to check
180: rule.fw_flg |= IP_FW_F_IIFNAME; // interfaces to check by name
181: rule.fw_flg |= (IP_FW_F_IN | IP_FW_F_OUT); // packet direction
182: rule.fw_flg |= IP_FW_F_FWD; // forward action
183: #ifdef USE_IFNAME_IN_RULES
184: if (ifname != NULL) {
1.1.1.2 ! misho 185: strlcpy(rule.fw_in_if.fu_via_if.name, ifname, IFNAMSIZ); // src interface
1.1 misho 186: rule.fw_in_if.fu_via_if.unit = -1;
187: }
188: #endif
189: if (inet_aton(iaddr, &rule.fw_out_if.fu_via_ip) == 0) {
190: syslog(LOG_ERR, "inet_aton(): %m");
191: return -1;
192: }
193: memcpy(&rule.fw_dst, &rule.fw_out_if.fu_via_ip, sizeof(struct in_addr));
194: memcpy(&rule.fw_fwd_ip.sin_addr, &rule.fw_out_if.fu_via_ip, sizeof(struct in_addr));
1.1.1.2 ! misho 195: rule.fw_dmsk.s_addr = INADDR_BROADCAST; //TODO check this
1.1 misho 196: IP_FW_SETNDSTP(&rule, 1); // number of external ports
197: rule.fw_uar.fw_pts[0] = eport; // external port
198: rule.fw_fwd_ip.sin_port = iport; // internal port
1.1.1.2 ! misho 199: if (rhost && rhost[0] != '\0') {
! 200: inet_aton(rhost, &rule.fw_src);
! 201: rule.fw_smsk.s_addr = htonl(INADDR_NONE);
! 202: }
1.1 misho 203:
1.1.1.2 ! misho 204: r = ipfw_exec(IP_FW_ADD, &rule, sizeof(rule));
! 205: if(r >= 0)
! 206: add_desc_time(eport, proto, desc, timestamp);
! 207: return r;
1.1 misho 208: }
209:
210: /* get_redirect_rule()
211: * return value : 0 success (found)
212: * -1 = error or rule not found */
213: int get_redirect_rule(
214: const char * ifname,
215: unsigned short eport,
216: int proto,
217: char * iaddr,
218: int iaddrlen,
219: unsigned short * iport,
220: char * desc,
221: int desclen,
1.1.1.2 ! misho 222: char * rhost,
! 223: int rhostlen,
! 224: unsigned int * timestamp,
1.1 misho 225: u_int64_t * packets,
226: u_int64_t * bytes)
227: {
228: int i, count_rules, total_rules = 0;
229: struct ip_fw * rules = NULL;
230:
231: if (ipfw_validate_protocol(proto) < 0)
232: return -1;
233: if (ipfw_validate_ifname(ifname) < 0)
234: return -1;
1.1.1.2 ! misho 235: if (timestamp)
! 236: *timestamp = 0;
! 237:
1.1 misho 238: do {
239: count_rules = ipfw_fetch_ruleset(&rules, &total_rules, 10);
240: if (count_rules < 0)
241: goto error;
242: } while (count_rules == 10);
243:
244: for (i=0; i<total_rules-1; i++) {
245: const struct ip_fw const * ptr = &rules[i];
246: if (proto == ptr->fw_prot && eport == ptr->fw_uar.fw_pts[0]) {
247: if (packets != NULL)
248: *packets = ptr->fw_pcnt;
249: if (bytes != NULL)
250: *bytes = ptr->fw_bcnt;
251: if (iport != NULL)
252: *iport = ptr->fw_fwd_ip.sin_port;
253: if (iaddr != NULL && iaddrlen > 0) {
1.1.1.2 ! misho 254: /* looks like fw_out_if.fu_via_ip is zero */
! 255: //if (inet_ntop(AF_INET, &ptr->fw_out_if.fu_via_ip, iaddr, iaddrlen) == NULL) {
! 256: if (inet_ntop(AF_INET, &ptr->fw_fwd_ip.sin_addr, iaddr, iaddrlen) == NULL) {
! 257: syslog(LOG_ERR, "inet_ntop(): %m");
! 258: goto error;
! 259: }
! 260: }
! 261: if (rhost != NULL && rhostlen > 0) {
! 262: if (ptr->fw_src.s_addr == 0)
! 263: rhost[0] = '\0';
! 264: else if (inet_ntop(AF_INET, &ptr->fw_src.s_addr, rhost, rhostlen) == NULL) {
1.1 misho 265: syslog(LOG_ERR, "inet_ntop(): %m");
266: goto error;
267: }
268: }
269: // And what if we found more than 1 matching rule?
270: ipfw_free_ruleset(&rules);
1.1.1.2 ! misho 271: get_desc_time(eport, proto, desc, desclen, timestamp);
1.1 misho 272: return 0;
273: }
274: }
275:
276: error:
277: if (rules != NULL)
278: ipfw_free_ruleset(&rules);
279: return -1;
280: }
281:
282: int delete_redirect_rule(
283: const char * ifname,
284: unsigned short eport,
285: int proto)
286: {
287: int i, count_rules, total_rules = 0;
288: struct ip_fw * rules = NULL;
289:
290: if (ipfw_validate_protocol(proto) < 0)
291: return -1;
292: if (ipfw_validate_ifname(ifname) < 0)
293: return -1;
294:
295: do {
296: count_rules = ipfw_fetch_ruleset(&rules, &total_rules, 10);
297: if (count_rules < 0)
298: goto error;
299: } while (count_rules == 10);
300:
301: for (i=0; i<total_rules-1; i++) {
302: const struct ip_fw const * ptr = &rules[i];
303: if (proto == ptr->fw_prot && eport == ptr->fw_uar.fw_pts[0]) {
304: if (ipfw_exec(IP_FW_DEL, (struct ip_fw *)ptr, sizeof(*ptr)) < 0)
305: goto error;
306: // And what if we found more than 1 matching rule?
307: ipfw_free_ruleset(&rules);
1.1.1.2 ! misho 308: del_desc_time(eport, proto);
1.1 misho 309: return 0;
310: }
311: }
312:
313: error:
314: if (rules != NULL)
315: ipfw_free_ruleset(&rules);
316: return -1;
317: }
318:
319: int add_filter_rule2(
320: const char * ifname,
1.1.1.2 ! misho 321: const char * rhost,
1.1 misho 322: const char * iaddr,
323: unsigned short eport,
324: unsigned short iport,
325: int proto,
326: const char * desc)
327: {
1.1.1.2 ! misho 328: //return -1;
! 329: return 0; /* nothing to do, always success */
1.1 misho 330: }
331:
332: int delete_filter_rule(
333: const char * ifname,
334: unsigned short eport,
335: int proto)
336: {
1.1.1.2 ! misho 337: //return -1;
! 338: return 0; /* nothing to do, always success */
1.1 misho 339: }
340:
341: int get_redirect_rule_by_index(
342: int index,
343: char * ifname,
344: unsigned short * eport,
345: char * iaddr,
346: int iaddrlen,
347: unsigned short * iport,
348: int * proto,
349: char * desc,
350: int desclen,
1.1.1.2 ! misho 351: char * rhost,
! 352: int rhostlen,
! 353: unsigned int * timestamp,
1.1 misho 354: u_int64_t * packets,
355: u_int64_t * bytes)
356: {
357: int total_rules = 0;
358: struct ip_fw * rules = NULL;
359:
360: if (index < 0) // TODO shouldn't we also validate the maximum?
361: return -1;
362:
1.1.1.2 ! misho 363: if(timestamp)
! 364: *timestamp = 0;
! 365:
1.1 misho 366: ipfw_fetch_ruleset(&rules, &total_rules, index + 1);
367:
1.1.1.2 ! misho 368: if (total_rules > index) {
1.1 misho 369: const struct ip_fw const * ptr = &rules[index];
1.1.1.2 ! misho 370: if (ptr->fw_prot == 0) // invalid rule
! 371: goto error;
1.1 misho 372: if (proto != NULL)
373: *proto = ptr->fw_prot;
374: if (eport != NULL)
375: *eport = ptr->fw_uar.fw_pts[0];
376: if (iport != NULL)
377: *iport = ptr->fw_fwd_ip.sin_port;
378: if (ifname != NULL)
379: strlcpy(ifname, ptr->fw_in_if.fu_via_if.name, IFNAMSIZ);
380: if (packets != NULL)
381: *packets = ptr->fw_pcnt;
382: if (bytes != NULL)
383: *bytes = ptr->fw_bcnt;
384: if (iport != NULL)
385: *iport = ptr->fw_fwd_ip.sin_port;
386: if (iaddr != NULL && iaddrlen > 0) {
1.1.1.2 ! misho 387: /* looks like fw_out_if.fu_via_ip is zero */
! 388: //if (inet_ntop(AF_INET, &ptr->fw_out_if.fu_via_ip, iaddr, iaddrlen) == NULL) {
! 389: if (inet_ntop(AF_INET, &ptr->fw_fwd_ip.sin_addr, iaddr, iaddrlen) == NULL) {
! 390: syslog(LOG_ERR, "inet_ntop(): %m");
! 391: goto error;
! 392: }
! 393: }
! 394: if (rhost != NULL && rhostlen > 0) {
! 395: if (ptr->fw_src.s_addr == 0)
! 396: rhost[0] = '\0';
! 397: else if (inet_ntop(AF_INET, &ptr->fw_src.s_addr, rhost, rhostlen) == NULL) {
1.1 misho 398: syslog(LOG_ERR, "inet_ntop(): %m");
399: goto error;
400: }
401: }
402: ipfw_free_ruleset(&rules);
1.1.1.2 ! misho 403: get_desc_time(*eport, *proto, desc, desclen, timestamp);
1.1 misho 404: return 0;
405: }
406:
407: error:
408: if (rules != NULL)
409: ipfw_free_ruleset(&rules);
410: return -1;
411: }
1.1.1.2 ! misho 412:
! 413: /* upnp_get_portmappings_in_range()
! 414: * return a list of all "external" ports for which a port
! 415: * mapping exists */
! 416: unsigned short *
! 417: get_portmappings_in_range(unsigned short startport,
! 418: unsigned short endport,
! 419: int proto,
! 420: unsigned int * number)
! 421: {
! 422: unsigned short * array = NULL;
! 423: unsigned int capacity = 128;
! 424: int i, count_rules, total_rules = 0;
! 425: struct ip_fw * rules = NULL;
! 426:
! 427: if (ipfw_validate_protocol(proto) < 0)
! 428: return NULL;
! 429:
! 430: do {
! 431: count_rules = ipfw_fetch_ruleset(&rules, &total_rules, 10);
! 432: if (count_rules < 0)
! 433: goto error;
! 434: } while (count_rules == 10);
! 435:
! 436: array = calloc(capacity, sizeof(unsigned short));
! 437: if(!array) {
! 438: syslog(LOG_ERR, "get_portmappings_in_range() : calloc error");
! 439: goto error;
! 440: }
! 441: *number = 0;
! 442:
! 443: for (i=0; i<total_rules-1; i++) {
! 444: const struct ip_fw const * ptr = &rules[i];
! 445: unsigned short eport = ptr->fw_uar.fw_pts[0];
! 446: if (proto == ptr->fw_prot
! 447: && startport <= eport
! 448: && eport <= endport) {
! 449: if(*number >= capacity) {
! 450: capacity += 128;
! 451: array = realloc(array, sizeof(unsigned short)*capacity);
! 452: if(!array) {
! 453: syslog(LOG_ERR, "get_portmappings_in_range() : realloc(%lu) error", sizeof(unsigned short)*capacity);
! 454: *number = 0;
! 455: goto error;
! 456: }
! 457: }
! 458: array[*number] = eport;
! 459: (*number)++;
! 460: }
! 461: }
! 462: error:
! 463: if (rules != NULL)
! 464: ipfw_free_ruleset(&rules);
! 465: return array;
! 466: }
! 467:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>