Annotation of embedaddon/miniupnpd/ipf/ipfrdr.c, revision 1.1
1.1 ! misho 1: /* $Id: ipfrdr.c,v 1.11 2009/10/10 18:34:39 nanard Exp $ */
! 2: /* MiniUPnP project
! 3: * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
! 4: * (c) 2007 Darren Reed
! 5: * This software is subject to the conditions detailed
! 6: * in the LICENCE file provided within the distribution */
! 7:
! 8: #include <sys/param.h>
! 9: #include <sys/types.h>
! 10: #include <sys/file.h>
! 11: /*
! 12: * This is a workaround for <sys/uio.h> troubles on FreeBSD, HPUX, OpenBSD.
! 13: * Needed here because on some systems <sys/uio.h> gets included by things
! 14: * like <sys/socket.h>
! 15: */
! 16: #ifndef _KERNEL
! 17: # define ADD_KERNEL
! 18: # define _KERNEL
! 19: # define KERNEL
! 20: #endif
! 21: #ifdef __OpenBSD__
! 22: struct file;
! 23: #endif
! 24: #include <sys/uio.h>
! 25: #ifdef ADD_KERNEL
! 26: # undef _KERNEL
! 27: # undef KERNEL
! 28: #endif
! 29: #include <sys/time.h>
! 30: #include <sys/socket.h>
! 31: #include <sys/syslog.h>
! 32: #include <sys/ioctl.h>
! 33: #include <net/if.h>
! 34: #if __FreeBSD_version >= 300000
! 35: # include <net/if_var.h>
! 36: #endif
! 37: #include <netinet/in.h>
! 38: #include <netinet/in_systm.h>
! 39: #include <netinet/ip.h>
! 40: #include <netinet/ip_icmp.h>
! 41: #ifndef TCP_PAWS_IDLE /* IRIX */
! 42: # include <netinet/tcp.h>
! 43: #endif
! 44: #include <netinet/udp.h>
! 45:
! 46: #include <arpa/inet.h>
! 47:
! 48: #include <errno.h>
! 49: #include <limits.h>
! 50: #include <netdb.h>
! 51: #include <stdlib.h>
! 52: #include <fcntl.h>
! 53: #include <syslog.h>
! 54: #include <stddef.h>
! 55: #include <stdio.h>
! 56: #if !defined(__SVR4) && !defined(__svr4__) && defined(sun)
! 57: # include <strings.h>
! 58: #endif
! 59: #include <string.h>
! 60: #include <unistd.h>
! 61:
! 62: #include "../config.h"
! 63: #include "netinet/ipl.h"
! 64: #include "netinet/ip_compat.h"
! 65: #include "netinet/ip_fil.h"
! 66: #include "netinet/ip_nat.h"
! 67: #include "netinet/ip_state.h"
! 68:
! 69:
! 70: #ifndef __P
! 71: # ifdef __STDC__
! 72: # define __P(x) x
! 73: # else
! 74: # define __P(x) ()
! 75: # endif
! 76: #endif
! 77: #ifndef __STDC__
! 78: # undef const
! 79: # define const
! 80: #endif
! 81:
! 82: #ifndef U_32_T
! 83: # define U_32_T 1
! 84: # if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) || \
! 85: defined(__sgi)
! 86: typedef u_int32_t u_32_t;
! 87: # else
! 88: # if defined(__alpha__) || defined(__alpha) || defined(_LP64)
! 89: typedef unsigned int u_32_t;
! 90: # else
! 91: # if SOLARIS2 >= 6
! 92: typedef uint32_t u_32_t;
! 93: # else
! 94: typedef unsigned int u_32_t;
! 95: # endif
! 96: # endif
! 97: # endif /* __NetBSD__ || __OpenBSD__ || __FreeBSD__ || __sgi */
! 98: #endif /* U_32_T */
! 99:
! 100:
! 101: #if defined(__NetBSD__) || defined(__OpenBSD__) || \
! 102: (_BSDI_VERSION >= 199701) || (__FreeBSD_version >= 300000) || \
! 103: SOLARIS || defined(__sgi) || defined(__osf__) || defined(linux)
! 104: # include <stdarg.h>
! 105: typedef int (* ioctlfunc_t) __P((int, ioctlcmd_t, ...));
! 106: #else
! 107: typedef int (* ioctlfunc_t) __P((dev_t, ioctlcmd_t, void *));
! 108: #endif
! 109: typedef void (* addfunc_t) __P((int, ioctlfunc_t, void *));
! 110: typedef int (* copyfunc_t) __P((void *, void *, size_t));
! 111:
! 112:
! 113: /*
! 114: * SunOS4
! 115: */
! 116: #if defined(sun) && !defined(__SVR4) && !defined(__svr4__)
! 117: extern int ioctl __P((int, int, void *));
! 118: #endif
! 119:
! 120: #include "../upnpglobalvars.h"
! 121:
! 122: /* group name */
! 123: static const char group_name[] = "miniupnpd";
! 124:
! 125: static int dev = -1;
! 126: static int dev_ipl = -1;
! 127:
! 128: /* IPFilter cannot store redirection descriptions, so we use our
! 129: * own structure to store them */
! 130: struct rdr_desc {
! 131: struct rdr_desc * next;
! 132: unsigned short eport;
! 133: int proto;
! 134: char str[];
! 135: };
! 136:
! 137: /* pointer to the chained list where descriptions are stored */
! 138: static struct rdr_desc * rdr_desc_list;
! 139:
! 140: static void
! 141: add_redirect_desc(unsigned short eport, int proto, const char * desc)
! 142: {
! 143: struct rdr_desc * p;
! 144: size_t l;
! 145:
! 146: if (desc != NULL) {
! 147: l = strlen(desc) + 1;
! 148: p = malloc(sizeof(struct rdr_desc) + l);
! 149: if (p) {
! 150: p->next = rdr_desc_list;
! 151: p->eport = eport;
! 152: p->proto = proto;
! 153: memcpy(p->str, desc, l);
! 154: rdr_desc_list = p;
! 155: }
! 156: }
! 157: }
! 158:
! 159: static void
! 160: del_redirect_desc(unsigned short eport, int proto)
! 161: {
! 162: struct rdr_desc * p, * last;
! 163:
! 164: last = NULL;
! 165: for (p = rdr_desc_list; p; p = p->next) {
! 166: if(p->eport == eport && p->proto == proto) {
! 167: if (last == NULL)
! 168: rdr_desc_list = p->next;
! 169: else
! 170: last->next = p->next;
! 171: free(p);
! 172: return;
! 173: }
! 174: }
! 175: }
! 176:
! 177: static void
! 178: get_redirect_desc(unsigned short eport, int proto, char * desc, int desclen)
! 179: {
! 180: struct rdr_desc * p;
! 181:
! 182: if (desc == NULL || desclen == 0)
! 183: return;
! 184: for (p = rdr_desc_list; p; p = p->next) {
! 185: if (p->eport == eport && p->proto == proto)
! 186: {
! 187: strncpy(desc, p->str, desclen);
! 188: return;
! 189: }
! 190: }
! 191: }
! 192:
! 193: int init_redirect(void)
! 194: {
! 195:
! 196: dev = open(IPNAT_NAME, O_RDWR);
! 197: if (dev < 0) {
! 198: syslog(LOG_ERR, "open(\"%s\"): %m", IPNAT_NAME);
! 199: return -1;
! 200: }
! 201: dev_ipl = open(IPL_NAME, O_RDWR);
! 202: if (dev_ipl < 0) {
! 203: syslog(LOG_ERR, "open(\"%s\"): %m", IPL_NAME);
! 204: return -1;
! 205: }
! 206: return 0;
! 207: }
! 208:
! 209: void shutdown_redirect(void)
! 210: {
! 211:
! 212: if (dev >= 0) {
! 213: close(dev);
! 214: dev = -1;
! 215: }
! 216: if (dev_ipl >= 0) {
! 217: close(dev_ipl);
! 218: dev = -1;
! 219: }
! 220: return;
! 221: }
! 222:
! 223: int
! 224: add_redirect_rule2(const char * ifname, unsigned short eport,
! 225: const char * iaddr, unsigned short iport, int proto,
! 226: const char * desc)
! 227: {
! 228: struct ipnat ipnat;
! 229: struct ipfobj obj;
! 230: int r;
! 231:
! 232: if (dev < 0) {
! 233: syslog(LOG_ERR, "%s not open", IPNAT_NAME);
! 234: return -1;
! 235: }
! 236:
! 237: memset(&obj, 0, sizeof(obj));
! 238: memset(&ipnat, 0, sizeof(ipnat));
! 239:
! 240: ipnat.in_redir = NAT_REDIRECT;
! 241: ipnat.in_p = proto;
! 242: if (proto == IPPROTO_TCP)
! 243: ipnat.in_flags = IPN_TCP;
! 244: if (proto == IPPROTO_UDP)
! 245: ipnat.in_flags = IPN_UDP;
! 246: ipnat.in_dcmp = FR_EQUAL;
! 247: ipnat.in_pmin = htons(eport);
! 248: ipnat.in_pmax = htons(eport);
! 249: ipnat.in_pnext = htons(iport);
! 250: ipnat.in_v = 4;
! 251: strlcpy(ipnat.in_tag.ipt_tag, group_name, IPFTAG_LEN);
! 252:
! 253: #ifdef USE_IFNAME_IN_RULES
! 254: if (ifname) {
! 255: strlcpy(ipnat.in_ifnames[0], ifname, IFNAMSIZ);
! 256: strlcpy(ipnat.in_ifnames[1], ifname, IFNAMSIZ);
! 257: }
! 258: #endif
! 259:
! 260: inet_pton(AF_INET, iaddr, &ipnat.in_in[0].in4);
! 261: ipnat.in_in[1].in4.s_addr = 0xffffffff;
! 262:
! 263: obj.ipfo_rev = IPFILTER_VERSION;
! 264: obj.ipfo_size = sizeof(ipnat);
! 265: obj.ipfo_ptr = &ipnat;
! 266: obj.ipfo_type = IPFOBJ_IPNAT;
! 267:
! 268: r = ioctl(dev, SIOCADNAT, &obj);
! 269: if (r == -1)
! 270: syslog(LOG_ERR, "ioctl(SIOCADNAT): %m");
! 271: else
! 272: add_redirect_desc(eport, proto, desc);
! 273: return r;
! 274: }
! 275:
! 276: /* get_redirect_rule()
! 277: * return value : 0 success (found)
! 278: * -1 = error or rule not found */
! 279: int
! 280: get_redirect_rule(const char * ifname, unsigned short eport, int proto,
! 281: char * iaddr, int iaddrlen, unsigned short * iport,
! 282: char * desc, int desclen,
! 283: u_int64_t * packets, u_int64_t * bytes)
! 284: {
! 285: ipfgeniter_t iter;
! 286: ipfobj_t obj;
! 287: ipnat_t ipn;
! 288: int r;
! 289:
! 290: memset(&obj, 0, sizeof(obj));
! 291: obj.ipfo_rev = IPFILTER_VERSION;
! 292: obj.ipfo_type = IPFOBJ_GENITER;
! 293: obj.ipfo_size = sizeof(iter);
! 294: obj.ipfo_ptr = &iter;
! 295:
! 296: iter.igi_type = IPFGENITER_IPNAT;
! 297: #if IPFILTER_VERSION > 4011300
! 298: iter.igi_nitems = 1;
! 299: #endif
! 300: iter.igi_data = &ipn;
! 301:
! 302: if (dev < 0) {
! 303: syslog(LOG_ERR, "%s not open", IPNAT_NAME);
! 304: return -1;
! 305: }
! 306:
! 307: r = -1;
! 308: do {
! 309: if (ioctl(dev, SIOCGENITER, &obj) == -1) {
! 310: syslog(LOG_ERR, "ioctl(dev, SIOCGENITER): %m");
! 311: break;
! 312: }
! 313: if (eport == ntohs(ipn.in_pmin) &&
! 314: eport == ntohs(ipn.in_pmax) &&
! 315: strcmp(ipn.in_tag.ipt_tag, group_name) == 0 &&
! 316: ipn.in_p == proto)
! 317: {
! 318: strlcpy(desc, "", desclen);
! 319: if (packets != NULL)
! 320: *packets = 0;
! 321: if (bytes != NULL)
! 322: *bytes = 0;
! 323: if (iport != NULL)
! 324: *iport = ntohs(ipn.in_pnext);
! 325: if (desc != NULL)
! 326: get_redirect_desc(eport, proto, desc, desclen);
! 327: inet_ntop(AF_INET, &ipn.in_in[0].in4, iaddr, iaddrlen);
! 328: r = 0;
! 329: }
! 330: } while (ipn.in_next != NULL);
! 331: return r;
! 332: }
! 333:
! 334:
! 335: int
! 336: get_redirect_rule_by_index(int index,
! 337: char * ifname, unsigned short * eport,
! 338: char * iaddr, int iaddrlen, unsigned short * iport,
! 339: int * proto, char * desc, int desclen,
! 340: u_int64_t * packets, u_int64_t * bytes)
! 341: {
! 342: ipfgeniter_t iter;
! 343: ipfobj_t obj;
! 344: ipnat_t ipn;
! 345: int n, r;
! 346:
! 347: if (index < 0)
! 348: return -1;
! 349:
! 350: if (dev < 0) {
! 351: syslog(LOG_ERR, "%s not open", IPNAT_NAME);
! 352: return -1;
! 353: }
! 354:
! 355: memset(&obj, 0, sizeof(obj));
! 356: obj.ipfo_rev = IPFILTER_VERSION;
! 357: obj.ipfo_ptr = &iter;
! 358: obj.ipfo_size = sizeof(iter);
! 359: obj.ipfo_type = IPFOBJ_GENITER;
! 360:
! 361: iter.igi_type = IPFGENITER_IPNAT;
! 362: #if IPFILTER_VERSION > 4011300
! 363: iter.igi_nitems = 1;
! 364: #endif
! 365: iter.igi_data = &ipn;
! 366:
! 367: n = 0;
! 368: r = -1;
! 369: do {
! 370: if (ioctl(dev, SIOCGENITER, &obj) == -1) {
! 371: syslog(LOG_ERR, "%s:ioctl(SIOCGENITER): %m",
! 372: "get_redirect_rule_by_index");
! 373: break;
! 374: }
! 375:
! 376: if (strcmp(ipn.in_tag.ipt_tag, group_name) != 0)
! 377: continue;
! 378:
! 379: if (index == n++) {
! 380: *proto = ipn.in_p;
! 381: *eport = ntohs(ipn.in_pmax);
! 382: *iport = ntohs(ipn.in_pnext);
! 383:
! 384: if (ifname)
! 385: strlcpy(ifname, ipn.in_ifnames[0], IFNAMSIZ);
! 386: if (packets != NULL)
! 387: *packets = 0;
! 388: if (bytes != NULL)
! 389: *bytes = 0;
! 390: if (desc != NULL)
! 391: get_redirect_desc(*eport, *proto, desc, desclen);
! 392: inet_ntop(AF_INET, &ipn.in_in[0].in4, iaddr, iaddrlen);
! 393: r = 0;
! 394: }
! 395: } while (ipn.in_next != NULL);
! 396: return r;
! 397: }
! 398:
! 399: static int
! 400: real_delete_redirect_rule(const char * ifname, unsigned short eport, int proto)
! 401: {
! 402: ipfgeniter_t iter;
! 403: ipfobj_t obj;
! 404: ipnat_t ipn;
! 405: int r;
! 406:
! 407: memset(&obj, 0, sizeof(obj));
! 408: obj.ipfo_rev = IPFILTER_VERSION;
! 409: obj.ipfo_type = IPFOBJ_GENITER;
! 410: obj.ipfo_size = sizeof(iter);
! 411: obj.ipfo_ptr = &iter;
! 412:
! 413: iter.igi_type = IPFGENITER_IPNAT;
! 414: #if IPFILTER_VERSION > 4011300
! 415: iter.igi_nitems = 1;
! 416: #endif
! 417: iter.igi_data = &ipn;
! 418:
! 419: if (dev < 0) {
! 420: syslog(LOG_ERR, "%s not open", IPNAT_NAME);
! 421: return -1;
! 422: }
! 423:
! 424: r = -1;
! 425: do {
! 426: if (ioctl(dev, SIOCGENITER, &obj) == -1) {
! 427: syslog(LOG_ERR, "%s:ioctl(SIOCGENITER): %m",
! 428: "delete_redirect_rule");
! 429: break;
! 430: }
! 431: if (eport == ntohs(ipn.in_pmin) &&
! 432: eport == ntohs(ipn.in_pmax) &&
! 433: strcmp(ipn.in_tag.ipt_tag, group_name) == 0 &&
! 434: ipn.in_p == proto)
! 435: {
! 436: obj.ipfo_rev = IPFILTER_VERSION;
! 437: obj.ipfo_size = sizeof(ipn);
! 438: obj.ipfo_ptr = &ipn;
! 439: obj.ipfo_type = IPFOBJ_IPNAT;
! 440: r = ioctl(dev, SIOCRMNAT, &obj);
! 441: if (r == -1)
! 442: syslog(LOG_ERR, "%s:ioctl(SIOCRMNAT): %m",
! 443: "delete_redirect_rule");
! 444: /* Delete the desc even if the above failed */
! 445: del_redirect_desc(eport, proto);
! 446: break;
! 447: }
! 448: } while (ipn.in_next != NULL);
! 449: return r;
! 450: }
! 451:
! 452: /* FIXME: For some reason, the iter isn't reset every other delete,
! 453: * so we attempt 2 deletes. */
! 454: int
! 455: delete_redirect_rule(const char * ifname, unsigned short eport, int proto)
! 456: {
! 457: int r;
! 458:
! 459: r = real_delete_redirect_rule(ifname, eport, proto);
! 460: if (r == -1)
! 461: r = real_delete_redirect_rule(ifname, eport, proto);
! 462: return r;
! 463: }
! 464:
! 465: /* thanks to Seth Mos for this function */
! 466: int
! 467: add_filter_rule2(const char * ifname, const char * iaddr,
! 468: unsigned short eport, unsigned short iport,
! 469: int proto, const char * desc)
! 470: {
! 471: ipfobj_t obj;
! 472: frentry_t fr;
! 473: fripf_t ipffr;
! 474: int r;
! 475:
! 476: if (dev_ipl < 0) {
! 477: syslog(LOG_ERR, "%s not open", IPL_NAME);
! 478: return -1;
! 479: }
! 480:
! 481: memset(&obj, 0, sizeof(obj));
! 482: memset(&fr, 0, sizeof(fr));
! 483: memset(&ipffr, 0, sizeof(ipffr));
! 484:
! 485: fr.fr_flags = FR_PASS|FR_KEEPSTATE|FR_QUICK|FR_INQUE;
! 486: if (GETFLAG(LOGPACKETSMASK))
! 487: fr.fr_flags |= FR_LOG|FR_LOGFIRST;
! 488: fr.fr_v = 4;
! 489:
! 490: fr.fr_type = FR_T_IPF;
! 491: fr.fr_dun.fru_ipf = &ipffr;
! 492: fr.fr_dsize = sizeof(ipffr);
! 493: fr.fr_isc = (void *)-1;
! 494:
! 495: fr.fr_proto = proto;
! 496: fr.fr_mproto = 0xff;
! 497: fr.fr_dcmp = FR_EQUAL;
! 498: fr.fr_dport = eport;
! 499: #ifdef USE_IFNAME_IN_RULES
! 500: if (ifname)
! 501: strlcpy(fr.fr_ifnames[0], ifname, IFNAMSIZ);
! 502: #endif
! 503: strlcpy(fr.fr_group, group_name, sizeof(fr.fr_group));
! 504:
! 505: if (proto == IPPROTO_TCP) {
! 506: fr.fr_tcpf = TH_SYN;
! 507: fr.fr_tcpfm = TH_SYN|TH_ACK|TH_RST|TH_FIN|TH_URG|TH_PUSH;
! 508: }
! 509:
! 510: inet_pton(AF_INET, iaddr, &fr.fr_daddr);
! 511: fr.fr_dmask = 0xffffffff;
! 512:
! 513: obj.ipfo_rev = IPFILTER_VERSION;
! 514: obj.ipfo_ptr = &fr;
! 515: obj.ipfo_size = sizeof(fr);
! 516:
! 517: r = ioctl(dev_ipl, SIOCINAFR, &obj);
! 518: if (r == -1) {
! 519: if (errno == ESRCH)
! 520: syslog(LOG_ERR,
! 521: "SIOCINAFR(missing 'head %s' rule?):%m",
! 522: group_name);
! 523: else
! 524: syslog(LOG_ERR, "SIOCINAFR:%m");
! 525: }
! 526: return r;
! 527: }
! 528:
! 529: int
! 530: delete_filter_rule(const char * ifname, unsigned short eport, int proto)
! 531: {
! 532: ipfobj_t wobj, dobj;
! 533: ipfruleiter_t rule;
! 534: u_long darray[1000];
! 535: u_long array[1000];
! 536: friostat_t fio;
! 537: frentry_t *fp;
! 538: int r;
! 539:
! 540: if (dev_ipl < 0) {
! 541: syslog(LOG_ERR, "%s not open", IPL_NAME);
! 542: return -1;
! 543: }
! 544:
! 545: wobj.ipfo_rev = IPFILTER_VERSION;
! 546: wobj.ipfo_type = IPFOBJ_IPFSTAT;
! 547: wobj.ipfo_size = sizeof(fio);
! 548: wobj.ipfo_ptr = &fio;
! 549:
! 550: if (ioctl(dev_ipl, SIOCGETFS, &wobj) == -1) {
! 551: syslog(LOG_ERR, "ioctl(SIOCGETFS): %m");
! 552: return -1;
! 553: }
! 554:
! 555: wobj.ipfo_rev = IPFILTER_VERSION;
! 556: wobj.ipfo_ptr = &rule;
! 557: wobj.ipfo_size = sizeof(rule);
! 558: wobj.ipfo_type = IPFOBJ_IPFITER;
! 559:
! 560: fp = (frentry_t *)array;
! 561: fp->fr_dun.fru_data = darray;
! 562: fp->fr_dsize = sizeof(darray);
! 563:
! 564: rule.iri_inout = 0;
! 565: rule.iri_active = fio.f_active;
! 566: #if IPFILTER_VERSION > 4011300
! 567: rule.iri_nrules = 1;
! 568: rule.iri_v = 4;
! 569: #endif
! 570: rule.iri_rule = fp;
! 571: strlcpy(rule.iri_group, group_name, sizeof(rule.iri_group));
! 572:
! 573: dobj.ipfo_rev = IPFILTER_VERSION;
! 574: dobj.ipfo_size = sizeof(*fp);
! 575: dobj.ipfo_type = IPFOBJ_FRENTRY;
! 576:
! 577: r = -1;
! 578: do {
! 579: memset(array, 0xff, sizeof(array));
! 580:
! 581: if (ioctl(dev_ipl, SIOCIPFITER, &wobj) == -1) {
! 582: syslog(LOG_ERR, "ioctl(SIOCIPFITER): %m");
! 583: break;
! 584: }
! 585:
! 586: if (fp->fr_data != NULL)
! 587: fp->fr_data = (char *)fp + sizeof(*fp);
! 588: if ((fp->fr_type & ~FR_T_BUILTIN) == FR_T_IPF &&
! 589: fp->fr_dport == eport &&
! 590: fp->fr_proto == proto)
! 591: {
! 592: dobj.ipfo_ptr = fp;
! 593:
! 594: r = ioctl(dev_ipl, SIOCRMAFR, &dobj);
! 595: if (r == -1)
! 596: syslog(LOG_ERR, "ioctl(SIOCRMAFR): %m");
! 597: break;
! 598: }
! 599: } while (fp->fr_next != NULL);
! 600: return r;
! 601: }
! 602:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>