Annotation of embedaddon/miniupnpd/netfilter/iptcrdr.c, revision 1.1
1.1 ! misho 1: /* $Id: iptcrdr.c,v 1.33 2010/09/27 09:17:59 nanard Exp $ */
! 2: /* MiniUPnP project
! 3: * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
! 4: * (c) 2006-2008 Thomas Bernard
! 5: * This software is subject to the conditions detailed
! 6: * in the LICENCE file provided within the distribution */
! 7: #include <stdio.h>
! 8: #include <stdlib.h>
! 9: #include <string.h>
! 10: #include <syslog.h>
! 11: #include <sys/errno.h>
! 12: #include <sys/socket.h>
! 13: #include <netinet/in.h>
! 14: #include <arpa/inet.h>
! 15: #include <dlfcn.h>
! 16: #include <libiptc/libiptc.h>
! 17: #include <iptables.h>
! 18:
! 19: #include <linux/version.h>
! 20:
! 21: #if IPTABLES_143
! 22: /* IPTABLES API version >= 1.4.3 */
! 23: #include <net/netfilter/nf_nat.h>
! 24: #define ip_nat_multi_range nf_nat_multi_range
! 25: #define ip_nat_range nf_nat_range
! 26: #define IPTC_HANDLE struct iptc_handle *
! 27: #else
! 28: /* IPTABLES API version < 1.4.3 */
! 29: #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
! 30: #include <linux/netfilter_ipv4/ip_nat.h>
! 31: #else
! 32: #include <linux/netfilter/nf_nat.h>
! 33: #endif
! 34: #define IPTC_HANDLE iptc_handle_t
! 35: #endif
! 36:
! 37: #include "iptcrdr.h"
! 38: #include "../upnpglobalvars.h"
! 39:
! 40: /* dummy init and shutdown functions */
! 41: int init_redirect(void)
! 42: {
! 43: return 0;
! 44: }
! 45:
! 46: void shutdown_redirect(void)
! 47: {
! 48: return;
! 49: }
! 50:
! 51: /* convert an ip address to string */
! 52: static int snprintip(char * dst, size_t size, uint32_t ip)
! 53: {
! 54: return snprintf(dst, size,
! 55: "%u.%u.%u.%u", ip >> 24, (ip >> 16) & 0xff,
! 56: (ip >> 8) & 0xff, ip & 0xff);
! 57: }
! 58:
! 59: /* netfilter cannot store redirection descriptions, so we use our
! 60: * own structure to store them */
! 61: struct rdr_desc {
! 62: struct rdr_desc * next;
! 63: unsigned short eport;
! 64: short proto;
! 65: char str[];
! 66: };
! 67:
! 68: /* pointer to the chained list where descriptions are stored */
! 69: static struct rdr_desc * rdr_desc_list = 0;
! 70:
! 71: static void
! 72: add_redirect_desc(unsigned short eport, int proto, const char * desc)
! 73: {
! 74: struct rdr_desc * p;
! 75: size_t l;
! 76: /* if(desc)
! 77: {*/
! 78: if ((l = strlen(desc) + 1) == 1) l = 5;
! 79: p = malloc(sizeof(struct rdr_desc) + l);
! 80: if(p)
! 81: {
! 82: p->next = rdr_desc_list;
! 83: p->eport = eport;
! 84: p->proto = (short)proto;
! 85: if(desc) memcpy(p->str, desc, l); else memcpy(p->str, "upnp", 4);
! 86: rdr_desc_list = p;
! 87: }
! 88: /* }*/
! 89: }
! 90:
! 91: static void
! 92: del_redirect_desc(unsigned short eport, int proto)
! 93: {
! 94: struct rdr_desc * p, * last;
! 95: p = rdr_desc_list;
! 96: last = 0;
! 97: while(p)
! 98: {
! 99: if(p->eport == eport && p->proto == proto)
! 100: {
! 101: if(!last)
! 102: rdr_desc_list = p->next;
! 103: else
! 104: last->next = p->next;
! 105: free(p);
! 106: return;
! 107: }
! 108: last = p;
! 109: p = p->next;
! 110: }
! 111: }
! 112:
! 113: static void
! 114: get_redirect_desc(unsigned short eport, int proto,
! 115: char * desc, int desclen)
! 116: {
! 117: struct rdr_desc * p;
! 118: if(!desc || (desclen == 0))
! 119: return;
! 120: for(p = rdr_desc_list; p; p = p->next)
! 121: {
! 122: if(p->eport == eport && p->proto == (short)proto)
! 123: {
! 124: strncpy(desc, p->str, desclen);
! 125: return;
! 126: }
! 127: }
! 128: /* if no description was found, return miniupnpd as default */
! 129: strncpy(desc, "miniupnpd", desclen);
! 130: }
! 131:
! 132: int
! 133: get_redirect_desc_by_index(int index, unsigned short * eport, int * proto,
! 134: char * desc, int desclen)
! 135: {
! 136: int i = 0;
! 137: struct rdr_desc * p;
! 138: if(!desc || (desclen == 0))
! 139: return -1;
! 140: for(p = rdr_desc_list; p; p = p->next, i++)
! 141: {
! 142: if(i == index)
! 143: {
! 144: *eport = p->eport;
! 145: *proto = (int)p->proto;
! 146: strncpy(desc, p->str, desclen);
! 147: return 0;
! 148: }
! 149: }
! 150: return -1;
! 151: }
! 152:
! 153: /* add_redirect_rule2() */
! 154: int
! 155: add_redirect_rule2(const char * ifname, unsigned short eport,
! 156: const char * iaddr, unsigned short iport, int proto,
! 157: const char * desc)
! 158: {
! 159: int r = addnatrule(proto, eport, iaddr, iport);
! 160: if(r >= 0)
! 161: add_redirect_desc(eport, proto, desc);
! 162: return r;
! 163: }
! 164:
! 165: int
! 166: add_filter_rule2(const char * ifname, const char * iaddr,
! 167: unsigned short eport, unsigned short iport,
! 168: int proto, const char * desc)
! 169: {
! 170: return add_filter_rule(proto, iaddr, iport);
! 171: }
! 172:
! 173: /* get_redirect_rule()
! 174: * returns -1 if the rule is not found */
! 175: int
! 176: get_redirect_rule(const char * ifname, unsigned short eport, int proto,
! 177: char * iaddr, int iaddrlen, unsigned short * iport,
! 178: char * desc, int desclen,
! 179: u_int64_t * packets, u_int64_t * bytes)
! 180: {
! 181: int r = -1;
! 182: IPTC_HANDLE h;
! 183: const struct ipt_entry * e;
! 184: const struct ipt_entry_target * target;
! 185: const struct ip_nat_multi_range * mr;
! 186: const struct ipt_entry_match *match;
! 187:
! 188: h = iptc_init("nat");
! 189: if(!h)
! 190: {
! 191: syslog(LOG_ERR, "get_redirect_rule() : "
! 192: "iptc_init() failed : %s",
! 193: iptc_strerror(errno));
! 194: return -1;
! 195: }
! 196: if(!iptc_is_chain(miniupnpd_nat_chain, h))
! 197: {
! 198: syslog(LOG_ERR, "chain %s not found", miniupnpd_nat_chain);
! 199: }
! 200: else
! 201: {
! 202: #ifdef IPTABLES_143
! 203: for(e = iptc_first_rule(miniupnpd_nat_chain, h);
! 204: e;
! 205: e = iptc_next_rule(e, h))
! 206: #else
! 207: for(e = iptc_first_rule(miniupnpd_nat_chain, &h);
! 208: e;
! 209: e = iptc_next_rule(e, &h))
! 210: #endif
! 211: {
! 212: if(proto==e->ip.proto)
! 213: {
! 214: match = (const struct ipt_entry_match *)&e->elems;
! 215: if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN))
! 216: {
! 217: const struct ipt_tcp * info;
! 218: info = (const struct ipt_tcp *)match->data;
! 219: if(eport != info->dpts[0])
! 220: continue;
! 221: }
! 222: else
! 223: {
! 224: const struct ipt_udp * info;
! 225: info = (const struct ipt_udp *)match->data;
! 226: if(eport != info->dpts[0])
! 227: continue;
! 228: }
! 229: target = (void *)e + e->target_offset;
! 230: //target = ipt_get_target(e);
! 231: mr = (const struct ip_nat_multi_range *)&target->data[0];
! 232: snprintip(iaddr, iaddrlen, ntohl(mr->range[0].min_ip));
! 233: *iport = ntohs(mr->range[0].min.all);
! 234: /*if(desc)
! 235: strncpy(desc, "miniupnpd", desclen);*/
! 236: get_redirect_desc(eport, proto, desc, desclen);
! 237: if(packets)
! 238: *packets = e->counters.pcnt;
! 239: if(bytes)
! 240: *bytes = e->counters.bcnt;
! 241: r = 0;
! 242: break;
! 243: }
! 244: }
! 245: }
! 246: if(h)
! 247: #ifdef IPTABLES_143
! 248: iptc_free(h);
! 249: #else
! 250: iptc_free(&h);
! 251: #endif
! 252: return r;
! 253: }
! 254:
! 255: /* get_redirect_rule_by_index()
! 256: * return -1 when the rule was not found */
! 257: int
! 258: get_redirect_rule_by_index(int index,
! 259: char * ifname, unsigned short * eport,
! 260: char * iaddr, int iaddrlen, unsigned short * iport,
! 261: int * proto, char * desc, int desclen,
! 262: u_int64_t * packets, u_int64_t * bytes)
! 263: {
! 264: int r = -1;
! 265: r = get_redirect_desc_by_index(index, eport, proto, desc, desclen);
! 266: if (r==0)
! 267: r = get_redirect_rule(ifname, *eport, *proto, iaddr, iaddrlen, iport,
! 268: 0, 0, packets, bytes);
! 269: #if 0
! 270: int i = 0;
! 271: IPTC_HANDLE h;
! 272: const struct ipt_entry * e;
! 273: const struct ipt_entry_target * target;
! 274: const struct ip_nat_multi_range * mr;
! 275: const struct ipt_entry_match *match;
! 276:
! 277: h = iptc_init("nat");
! 278: if(!h)
! 279: {
! 280: syslog(LOG_ERR, "get_redirect_rule_by_index() : "
! 281: "iptc_init() failed : %s",
! 282: iptc_strerror(errno));
! 283: return -1;
! 284: }
! 285: if(!iptc_is_chain(miniupnpd_nat_chain, h))
! 286: {
! 287: syslog(LOG_ERR, "chain %s not found", miniupnpd_nat_chain);
! 288: }
! 289: else
! 290: {
! 291: #ifdef IPTABLES_143
! 292: for(e = iptc_first_rule(miniupnpd_nat_chain, h);
! 293: e;
! 294: e = iptc_next_rule(e, h))
! 295: #else
! 296: for(e = iptc_first_rule(miniupnpd_nat_chain, &h);
! 297: e;
! 298: e = iptc_next_rule(e, &h))
! 299: #endif
! 300: {
! 301: if(i==index)
! 302: {
! 303: *proto = e->ip.proto;
! 304: match = (const struct ipt_entry_match *)&e->elems;
! 305: if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN))
! 306: {
! 307: const struct ipt_tcp * info;
! 308: info = (const struct ipt_tcp *)match->data;
! 309: *eport = info->dpts[0];
! 310: }
! 311: else
! 312: {
! 313: const struct ipt_udp * info;
! 314: info = (const struct ipt_udp *)match->data;
! 315: *eport = info->dpts[0];
! 316: }
! 317: target = (void *)e + e->target_offset;
! 318: mr = (const struct ip_nat_multi_range *)&target->data[0];
! 319: snprintip(iaddr, iaddrlen, ntohl(mr->range[0].min_ip));
! 320: *iport = ntohs(mr->range[0].min.all);
! 321: /*if(desc)
! 322: strncpy(desc, "miniupnpd", desclen);*/
! 323: get_redirect_desc(*eport, *proto, desc, desclen);
! 324: if(packets)
! 325: *packets = e->counters.pcnt;
! 326: if(bytes)
! 327: *bytes = e->counters.bcnt;
! 328: r = 0;
! 329: break;
! 330: }
! 331: i++;
! 332: }
! 333: }
! 334: if(h)
! 335: #ifdef IPTABLES_143
! 336: iptc_free(h);
! 337: #else
! 338: iptc_free(&h);
! 339: #endif
! 340: #endif /*0*/
! 341: return r;
! 342: }
! 343:
! 344: /* delete_rule_and_commit() :
! 345: * subfunction used in delete_redirect_and_filter_rules() */
! 346: int
! 347: delete_rule_and_commit(const char * table,
! 348: const char * miniupnpd_chain,
! 349: unsigned short eport, int proto,
! 350: const char * logcaller)
! 351: {
! 352: int r = -1;
! 353: unsigned index = 0;
! 354: unsigned i = 0;
! 355: IPTC_HANDLE h;
! 356: const struct ipt_entry * e;
! 357: const struct ipt_entry_match *match;
! 358:
! 359: h = iptc_init(table);
! 360: if(!h)
! 361: {
! 362: syslog(LOG_ERR, "get_index_rules() : "
! 363: "iptc_init(%s) failed : %s",
! 364: table,
! 365: iptc_strerror(errno));
! 366: return -1;
! 367: }
! 368: if(!iptc_is_chain(miniupnpd_chain, h))
! 369: {
! 370: syslog(LOG_ERR, "chain %s not found", miniupnpd_chain);
! 371: }
! 372: else
! 373: {
! 374: #ifdef IPTABLES_143
! 375: for(e = iptc_first_rule(miniupnpd_chain, h);
! 376: e;
! 377: e = iptc_next_rule(e, h), i++)
! 378: #else
! 379: for(e = iptc_first_rule(miniupnpd_chain, &h);
! 380: e;
! 381: e = iptc_next_rule(e, &h), i++)
! 382: #endif
! 383: {
! 384: if(proto==e->ip.proto)
! 385: {
! 386: match = (const struct ipt_entry_match *)&e->elems;
! 387: if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN))
! 388: {
! 389: const struct ipt_tcp * info;
! 390: info = (const struct ipt_tcp *)match->data;
! 391: if(eport != info->dpts[0])
! 392: continue;
! 393: }
! 394: else
! 395: {
! 396: const struct ipt_udp * info;
! 397: info = (const struct ipt_udp *)match->data;
! 398: if(eport != info->dpts[0])
! 399: continue;
! 400: }
! 401: r = 0;
! 402: index = i;
! 403: break;
! 404: }
! 405: }
! 406: }
! 407: if(h)
! 408: #ifdef IPTABLES_143
! 409: iptc_free(h);
! 410: #else
! 411: iptc_free(&h);
! 412: #endif
! 413: if ((r == 0) && (h = iptc_init(table))) {
! 414: syslog(LOG_INFO, "Trying to delete rules at index %u", index);
! 415: /* Now delete both rules */
! 416: #ifdef IPTABLES_143
! 417: if(!iptc_delete_num_entry(miniupnpd_chain, index, h))
! 418: #else
! 419: if(!iptc_delete_num_entry(miniupnpd_chain, index, &h))
! 420: #endif
! 421: {
! 422: syslog(LOG_ERR, "%s() : iptc_delete_num_entry(): %s\n",
! 423: logcaller, iptc_strerror(errno));
! 424: r = -1;
! 425: }
! 426: #ifdef IPTABLES_143
! 427: else if(!iptc_commit(h))
! 428: #else
! 429: else if(!iptc_commit(&h))
! 430: #endif
! 431: {
! 432: syslog(LOG_ERR, "%s() : iptc_commit(): %s\n",
! 433: logcaller, iptc_strerror(errno));
! 434: r = -1;
! 435: }
! 436: if(h)
! 437: #ifdef IPTABLES_143
! 438: iptc_free(h);
! 439: #else
! 440: iptc_free(&h);
! 441: #endif
! 442: }
! 443: return r;
! 444: }
! 445:
! 446: /* delete_redirect_and_filter_rules()
! 447: */
! 448: int
! 449: delete_redirect_and_filter_rules(unsigned short eport, int proto)
! 450: {
! 451: int r = -1;
! 452: if ((r = delete_rule_and_commit("nat", miniupnpd_nat_chain, eport, proto, "delete_redirect_rule") &&
! 453: delete_rule_and_commit("filter", miniupnpd_forward_chain, eport, proto, "delete_filter_rule")) == 0)
! 454: del_redirect_desc(eport, proto);
! 455: return r;
! 456: }
! 457:
! 458: /* ==================================== */
! 459: /* TODO : add the -m state --state NEW,ESTABLISHED,RELATED
! 460: * only for the filter rule */
! 461: static struct ipt_entry_match *
! 462: get_tcp_match(unsigned short dport)
! 463: {
! 464: struct ipt_entry_match *match;
! 465: struct ipt_tcp * tcpinfo;
! 466: size_t size;
! 467: size = IPT_ALIGN(sizeof(struct ipt_entry_match))
! 468: + IPT_ALIGN(sizeof(struct ipt_tcp));
! 469: match = calloc(1, size);
! 470: match->u.match_size = size;
! 471: strncpy(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN);
! 472: tcpinfo = (struct ipt_tcp *)match->data;
! 473: tcpinfo->spts[0] = 0; /* all source ports */
! 474: tcpinfo->spts[1] = 0xFFFF;
! 475: tcpinfo->dpts[0] = dport; /* specified destination port */
! 476: tcpinfo->dpts[1] = dport;
! 477: return match;
! 478: }
! 479:
! 480: static struct ipt_entry_match *
! 481: get_udp_match(unsigned short dport)
! 482: {
! 483: struct ipt_entry_match *match;
! 484: struct ipt_udp * udpinfo;
! 485: size_t size;
! 486: size = IPT_ALIGN(sizeof(struct ipt_entry_match))
! 487: + IPT_ALIGN(sizeof(struct ipt_udp));
! 488: match = calloc(1, size);
! 489: match->u.match_size = size;
! 490: strncpy(match->u.user.name, "udp", IPT_FUNCTION_MAXNAMELEN);
! 491: udpinfo = (struct ipt_udp *)match->data;
! 492: udpinfo->spts[0] = 0; /* all source ports */
! 493: udpinfo->spts[1] = 0xFFFF;
! 494: udpinfo->dpts[0] = dport; /* specified destination port */
! 495: udpinfo->dpts[1] = dport;
! 496: return match;
! 497: }
! 498:
! 499: static struct ipt_entry_target *
! 500: get_dnat_target(const char * daddr, unsigned short dport)
! 501: {
! 502: struct ipt_entry_target * target;
! 503: struct ip_nat_multi_range * mr;
! 504: struct ip_nat_range * range;
! 505: size_t size;
! 506:
! 507: size = IPT_ALIGN(sizeof(struct ipt_entry_target))
! 508: + IPT_ALIGN(sizeof(struct ip_nat_multi_range));
! 509: target = calloc(1, size);
! 510: target->u.target_size = size;
! 511: strncpy(target->u.user.name, "DNAT", IPT_FUNCTION_MAXNAMELEN);
! 512: /* one ip_nat_range already included in ip_nat_multi_range */
! 513: mr = (struct ip_nat_multi_range *)&target->data[0];
! 514: mr->rangesize = 1;
! 515: range = &mr->range[0];
! 516: range->min_ip = range->max_ip = inet_addr(daddr);
! 517: range->flags |= IP_NAT_RANGE_MAP_IPS;
! 518: range->min.all = range->max.all = htons(dport);
! 519: range->flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
! 520: return target;
! 521: }
! 522:
! 523: /* iptc_init_verify_and_append()
! 524: * return 0 on success, -1 on failure */
! 525: static int
! 526: iptc_init_verify_and_append(const char * table, const char * miniupnpd_chain, struct ipt_entry * e,
! 527: const char * logcaller)
! 528: {
! 529: IPTC_HANDLE h;
! 530: h = iptc_init(table);
! 531: if(!h)
! 532: {
! 533: syslog(LOG_ERR, "%s : iptc_init() error : %s\n",
! 534: logcaller, iptc_strerror(errno));
! 535: return -1;
! 536: }
! 537: if(!iptc_is_chain(miniupnpd_chain, h))
! 538: {
! 539: syslog(LOG_ERR, "%s : iptc_is_chain() error : %s\n",
! 540: logcaller, iptc_strerror(errno));
! 541: if(h)
! 542: #ifdef IPTABLES_143
! 543: iptc_free(h);
! 544: #else
! 545: iptc_free(&h);
! 546: #endif
! 547: return -1;
! 548: }
! 549: /* iptc_insert_entry(miniupnpd_chain, e, n, h/&h) could also be used */
! 550: #ifdef IPTABLES_143
! 551: if(!iptc_append_entry(miniupnpd_chain, e, h))
! 552: #else
! 553: if(!iptc_append_entry(miniupnpd_chain, e, &h))
! 554: #endif
! 555: {
! 556: syslog(LOG_ERR, "%s : iptc_append_entry() error : %s\n",
! 557: logcaller, iptc_strerror(errno));
! 558: if(h)
! 559: #ifdef IPTABLES_143
! 560: iptc_free(h);
! 561: #else
! 562: iptc_free(&h);
! 563: #endif
! 564: return -1;
! 565: }
! 566: #ifdef IPTABLES_143
! 567: if(!iptc_commit(h))
! 568: #else
! 569: if(!iptc_commit(&h))
! 570: #endif
! 571: {
! 572: syslog(LOG_ERR, "%s : iptc_commit() error : %s\n",
! 573: logcaller, iptc_strerror(errno));
! 574: if(h)
! 575: #ifdef IPTABLES_143
! 576: iptc_free(h);
! 577: #else
! 578: iptc_free(&h);
! 579: #endif
! 580: return -1;
! 581: }
! 582: if(h)
! 583: #ifdef IPTABLES_143
! 584: iptc_free(h);
! 585: #else
! 586: iptc_free(&h);
! 587: #endif
! 588: return 0;
! 589: }
! 590:
! 591: /* add nat rule
! 592: * iptables -t nat -A MINIUPNPD -p proto --dport eport -j DNAT --to iaddr:iport
! 593: * */
! 594: int
! 595: addnatrule(int proto, unsigned short eport,
! 596: const char * iaddr, unsigned short iport)
! 597: {
! 598: int r = 0;
! 599: struct ipt_entry * e;
! 600: struct ipt_entry_match *match = NULL;
! 601: struct ipt_entry_target *target = NULL;
! 602:
! 603: e = calloc(1, sizeof(struct ipt_entry));
! 604: e->ip.proto = proto;
! 605: if(proto == IPPROTO_TCP)
! 606: {
! 607: match = get_tcp_match(eport);
! 608: }
! 609: else
! 610: {
! 611: match = get_udp_match(eport);
! 612: }
! 613: e->nfcache = NFC_IP_DST_PT;
! 614: target = get_dnat_target(iaddr, iport);
! 615: e->nfcache |= NFC_UNKNOWN;
! 616: e = realloc(e, sizeof(struct ipt_entry)
! 617: + match->u.match_size
! 618: + target->u.target_size);
! 619: memcpy(e->elems, match, match->u.match_size);
! 620: memcpy(e->elems + match->u.match_size, target, target->u.target_size);
! 621: e->target_offset = sizeof(struct ipt_entry)
! 622: + match->u.match_size;
! 623: e->next_offset = sizeof(struct ipt_entry)
! 624: + match->u.match_size
! 625: + target->u.target_size;
! 626:
! 627: r = iptc_init_verify_and_append("nat", miniupnpd_nat_chain, e, "addnatrule()");
! 628: free(target);
! 629: free(match);
! 630: free(e);
! 631: return r;
! 632: }
! 633: /* ================================= */
! 634: static struct ipt_entry_target *
! 635: get_accept_target(void)
! 636: {
! 637: struct ipt_entry_target * target = NULL;
! 638: size_t size;
! 639: size = IPT_ALIGN(sizeof(struct ipt_entry_target))
! 640: + IPT_ALIGN(sizeof(int));
! 641: target = calloc(1, size);
! 642: target->u.user.target_size = size;
! 643: strncpy(target->u.user.name, "ACCEPT", IPT_FUNCTION_MAXNAMELEN);
! 644: return target;
! 645: }
! 646:
! 647: /* add_filter_rule()
! 648: * */
! 649: int
! 650: add_filter_rule(int proto, const char * iaddr, unsigned short iport)
! 651: {
! 652: int r = 0;
! 653: struct ipt_entry * e;
! 654: struct ipt_entry_match *match = NULL;
! 655: struct ipt_entry_target *target = NULL;
! 656:
! 657: e = calloc(1, sizeof(struct ipt_entry));
! 658: e->ip.proto = proto;
! 659: if(proto == IPPROTO_TCP)
! 660: {
! 661: match = get_tcp_match(iport);
! 662: }
! 663: else
! 664: {
! 665: match = get_udp_match(iport);
! 666: }
! 667: e->nfcache = NFC_IP_DST_PT;
! 668: e->ip.dst.s_addr = inet_addr(iaddr);
! 669: e->ip.dmsk.s_addr = INADDR_NONE;
! 670: target = get_accept_target();
! 671: e->nfcache |= NFC_UNKNOWN;
! 672: e = realloc(e, sizeof(struct ipt_entry)
! 673: + match->u.match_size
! 674: + target->u.target_size);
! 675: memcpy(e->elems, match, match->u.match_size);
! 676: memcpy(e->elems + match->u.match_size, target, target->u.target_size);
! 677: e->target_offset = sizeof(struct ipt_entry)
! 678: + match->u.match_size;
! 679: e->next_offset = sizeof(struct ipt_entry)
! 680: + match->u.match_size
! 681: + target->u.target_size;
! 682:
! 683: r = iptc_init_verify_and_append("filter", miniupnpd_forward_chain, e, "add_filter_rule()");
! 684: free(target);
! 685: free(match);
! 686: free(e);
! 687: return r;
! 688: }
! 689:
! 690: /* ================================ */
! 691: static int
! 692: print_match(const struct ipt_entry_match *match)
! 693: {
! 694: printf("match %s\n", match->u.user.name);
! 695: if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN))
! 696: {
! 697: struct ipt_tcp * tcpinfo;
! 698: tcpinfo = (struct ipt_tcp *)match->data;
! 699: printf("srcport = %hu:%hu dstport = %hu:%hu\n",
! 700: tcpinfo->spts[0], tcpinfo->spts[1],
! 701: tcpinfo->dpts[0], tcpinfo->dpts[1]);
! 702: }
! 703: else if(0 == strncmp(match->u.user.name, "udp", IPT_FUNCTION_MAXNAMELEN))
! 704: {
! 705: struct ipt_udp * udpinfo;
! 706: udpinfo = (struct ipt_udp *)match->data;
! 707: printf("srcport = %hu:%hu dstport = %hu:%hu\n",
! 708: udpinfo->spts[0], udpinfo->spts[1],
! 709: udpinfo->dpts[0], udpinfo->dpts[1]);
! 710: }
! 711: return 0;
! 712: }
! 713:
! 714: static void
! 715: print_iface(const char * iface, const unsigned char * mask, int invert)
! 716: {
! 717: unsigned i;
! 718: if(mask[0] == 0)
! 719: return;
! 720: if(invert)
! 721: printf("! ");
! 722: for(i=0; i<IFNAMSIZ; i++)
! 723: {
! 724: if(mask[i])
! 725: {
! 726: if(iface[i])
! 727: putchar(iface[i]);
! 728: }
! 729: else
! 730: {
! 731: if(iface[i-1])
! 732: putchar('+');
! 733: break;
! 734: }
! 735: }
! 736: }
! 737:
! 738: static void
! 739: printip(uint32_t ip)
! 740: {
! 741: printf("%u.%u.%u.%u", ip >> 24, (ip >> 16) & 0xff,
! 742: (ip >> 8) & 0xff, ip & 0xff);
! 743: }
! 744:
! 745: /* for debug */
! 746: /* read the "filter" and "nat" tables */
! 747: int
! 748: list_redirect_rule(const char * ifname)
! 749: {
! 750: IPTC_HANDLE h;
! 751: const struct ipt_entry * e;
! 752: const struct ipt_entry_target * target;
! 753: const struct ip_nat_multi_range * mr;
! 754: const char * target_str;
! 755:
! 756: h = iptc_init("nat");
! 757: if(!h)
! 758: {
! 759: printf("iptc_init() error : %s\n", iptc_strerror(errno));
! 760: return -1;
! 761: }
! 762: if(!iptc_is_chain(miniupnpd_nat_chain, h))
! 763: {
! 764: printf("chain %s not found\n", miniupnpd_nat_chain);
! 765: #ifdef IPTABLES_143
! 766: iptc_free(h);
! 767: #else
! 768: iptc_free(&h);
! 769: #endif
! 770: return -1;
! 771: }
! 772: #ifdef IPTABLES_143
! 773: for(e = iptc_first_rule(miniupnpd_nat_chain, h);
! 774: e;
! 775: e = iptc_next_rule(e, h))
! 776: {
! 777: target_str = iptc_get_target(e, h);
! 778: #else
! 779: for(e = iptc_first_rule(miniupnpd_nat_chain, &h);
! 780: e;
! 781: e = iptc_next_rule(e, &h))
! 782: {
! 783: target_str = iptc_get_target(e, &h);
! 784: #endif
! 785: printf("===\n");
! 786: printf("src = %s%s/%s\n", (e->ip.invflags & IPT_INV_SRCIP)?"! ":"",
! 787: inet_ntoa(e->ip.src), inet_ntoa(e->ip.smsk));
! 788: printf("dst = %s%s/%s\n", (e->ip.invflags & IPT_INV_DSTIP)?"! ":"",
! 789: inet_ntoa(e->ip.dst), inet_ntoa(e->ip.dmsk));
! 790: /*printf("in_if = %s out_if = %s\n", e->ip.iniface, e->ip.outiface);*/
! 791: printf("in_if = ");
! 792: print_iface(e->ip.iniface, e->ip.iniface_mask,
! 793: e->ip.invflags & IPT_INV_VIA_IN);
! 794: printf(" out_if = ");
! 795: print_iface(e->ip.outiface, e->ip.outiface_mask,
! 796: e->ip.invflags & IPT_INV_VIA_OUT);
! 797: printf("\n");
! 798: printf("ip.proto = %s%d\n", (e->ip.invflags & IPT_INV_PROTO)?"! ":"",
! 799: e->ip.proto);
! 800: /* display matches stuff */
! 801: if(e->target_offset)
! 802: {
! 803: IPT_MATCH_ITERATE(e, print_match);
! 804: /*printf("\n");*/
! 805: }
! 806: printf("target = %s\n", target_str);
! 807: target = (void *)e + e->target_offset;
! 808: mr = (const struct ip_nat_multi_range *)&target->data[0];
! 809: printf("ips ");
! 810: printip(ntohl(mr->range[0].min_ip));
! 811: printf(" ");
! 812: printip(ntohl(mr->range[0].max_ip));
! 813: printf("\nports %hu %hu\n", ntohs(mr->range[0].min.all),
! 814: ntohs(mr->range[0].max.all));
! 815: printf("flags = %x\n", mr->range[0].flags);
! 816: }
! 817: if(h)
! 818: #ifdef IPTABLES_143
! 819: iptc_free(h);
! 820: #else
! 821: iptc_free(&h);
! 822: #endif
! 823: return 0;
! 824: }
! 825:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>