1/* $Id: iptcrdr.c,v 1.53 2015/02/08 09:10:00 nanard Exp $ */ 2/* MiniUPnP project 3 * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ 4 * (c) 2006-2015 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 <iptables.h> 17#include <linux/netfilter/xt_DSCP.h> 18#include <libiptc/libiptc.h> 19 20#include <linux/version.h> 21 22#if IPTABLES_143 23/* IPTABLES API version >= 1.4.3 */ 24 25/* added in order to compile on gentoo : 26 * http://miniupnp.tuxfamily.org/forum/viewtopic.php?p=2183 */ 27#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); })) 28#define __must_be_array(a) \ 29 BUILD_BUG_ON_ZERO(__builtin_types_compatible_p(typeof(a), typeof(&a[0]))) 30#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr)) 31#define LIST_POISON2 ((void *) 0x00200200 ) 32 33#if 0 34#include <linux/netfilter/nf_nat.h> 35#else 36#include "tiny_nf_nat.h" 37#endif 38#define ip_nat_multi_range nf_nat_multi_range 39#define ip_nat_range nf_nat_range 40#define IPTC_HANDLE struct iptc_handle * 41#else 42/* IPTABLES API version < 1.4.3 */ 43#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) 44#include <linux/netfilter_ipv4/ip_nat.h> 45#else 46#if 0 47#include <linux/netfilter/nf_nat.h> 48#else 49#include "tiny_nf_nat.h" 50#endif 51#define ip_nat_multi_range nf_nat_multi_range 52#define ip_nat_range nf_nat_range 53#endif 54#define IPTC_HANDLE iptc_handle_t 55#endif 56 57/* IPT_ALIGN was renamed XT_ALIGN in iptables-1.4.11 */ 58#ifndef IPT_ALIGN 59#define IPT_ALIGN XT_ALIGN 60#endif 61 62#include "../macros.h" 63#include "../config.h" 64#include "iptcrdr.h" 65#include "../upnpglobalvars.h" 66 67/* local functions declarations */ 68static int 69addnatrule(int proto, unsigned short eport, 70 const char * iaddr, unsigned short iport, 71 const char * rhost); 72 73static int 74add_filter_rule(int proto, const char * rhost, 75 const char * iaddr, unsigned short iport); 76 77static int 78addpeernatrule(int proto, 79 const char * eaddr, unsigned short eport, 80 const char * iaddr, unsigned short iport, 81 const char * rhost, unsigned short rport); 82 83static int 84addpeerdscprule(int proto, unsigned char dscp, 85 const char * iaddr, unsigned short iport, 86 const char * rhost, unsigned short rport); 87 88/* dummy init and shutdown functions */ 89int init_redirect(void) 90{ 91 return 0; 92} 93 94void shutdown_redirect(void) 95{ 96 return; 97} 98 99/* convert an ip address to string */ 100static int snprintip(char * dst, size_t size, uint32_t ip) 101{ 102 return snprintf(dst, size, 103 "%u.%u.%u.%u", ip >> 24, (ip >> 16) & 0xff, 104 (ip >> 8) & 0xff, ip & 0xff); 105} 106 107/* netfilter cannot store redirection descriptions, so we use our 108 * own structure to store them */ 109struct rdr_desc { 110 struct rdr_desc * next; 111 unsigned int timestamp; 112 unsigned short eport; 113 short proto; 114 char str[]; 115}; 116 117/* pointer to the chained list where descriptions are stored */ 118static struct rdr_desc * rdr_desc_list = 0; 119 120/* add a description to the list of redirection descriptions */ 121static void 122add_redirect_desc(unsigned short eport, int proto, 123 const char * desc, unsigned int timestamp) 124{ 125 struct rdr_desc * p; 126 size_t l; 127 /* set a default description if none given */ 128 if(!desc) 129 desc = "miniupnpd"; 130 l = strlen(desc) + 1; 131 p = malloc(sizeof(struct rdr_desc) + l); 132 if(p) 133 { 134 p->next = rdr_desc_list; 135 p->timestamp = timestamp; 136 p->eport = eport; 137 p->proto = (short)proto; 138 memcpy(p->str, desc, l); 139 rdr_desc_list = p; 140 } 141} 142 143/* delete a description from the list */ 144static void 145del_redirect_desc(unsigned short eport, int proto) 146{ 147 struct rdr_desc * p, * last; 148 p = rdr_desc_list; 149 last = 0; 150 while(p) 151 { 152 if(p->eport == eport && p->proto == proto) 153 { 154 if(!last) 155 rdr_desc_list = p->next; 156 else 157 last->next = p->next; 158 free(p); 159 return; 160 } 161 last = p; 162 p = p->next; 163 } 164} 165 166/* go through the list to find the description */ 167static void 168get_redirect_desc(unsigned short eport, int proto, 169 char * desc, int desclen, 170 unsigned int * timestamp) 171{ 172 struct rdr_desc * p; 173 for(p = rdr_desc_list; p; p = p->next) 174 { 175 if(p->eport == eport && p->proto == (short)proto) 176 { 177 if(desc) 178 strncpy(desc, p->str, desclen); 179 if(timestamp) 180 *timestamp = p->timestamp; 181 return; 182 } 183 } 184 /* if no description was found, return miniupnpd as default */ 185 if(desc) 186 strncpy(desc, "miniupnpd", desclen); 187 if(timestamp) 188 *timestamp = 0; 189} 190 191#if USE_INDEX_FROM_DESC_LIST 192static int 193get_redirect_desc_by_index(int index, unsigned short * eport, int * proto, 194 char * desc, int desclen, unsigned int * timestamp) 195{ 196 int i = 0; 197 struct rdr_desc * p; 198 if(!desc || (desclen == 0)) 199 return -1; 200 for(p = rdr_desc_list; p; p = p->next, i++) 201 { 202 if(i == index) 203 { 204 *eport = p->eport; 205 *proto = (int)p->proto; 206 strncpy(desc, p->str, desclen); 207 if(timestamp) 208 *timestamp = p->timestamp; 209 return 0; 210 } 211 } 212 return -1; 213} 214#endif 215 216/* add_redirect_rule2() */ 217int 218add_redirect_rule2(const char * ifname, 219 const char * rhost, unsigned short eport, 220 const char * iaddr, unsigned short iport, int proto, 221 const char * desc, unsigned int timestamp) 222{ 223 int r; 224 UNUSED(ifname); 225 226 r = addnatrule(proto, eport, iaddr, iport, rhost); 227 if(r >= 0) 228 add_redirect_desc(eport, proto, desc, timestamp); 229 return r; 230} 231 232/* add_redirect_rule2() */ 233int 234add_peer_redirect_rule2(const char * ifname, 235 const char * rhost, unsigned short rport, 236 const char * eaddr, unsigned short eport, 237 const char * iaddr, unsigned short iport, int proto, 238 const char * desc, unsigned int timestamp) 239{ 240 int r; 241 UNUSED(ifname); 242 243 r = addpeernatrule(proto, eaddr, eport, iaddr, iport, rhost, rport); 244 if(r >= 0) 245 add_redirect_desc(eport, proto, desc, timestamp); 246 return r; 247} 248 249int 250add_peer_dscp_rule2(const char * ifname, 251 const char * rhost, unsigned short rport, 252 unsigned char dscp, 253 const char * iaddr, unsigned short iport, int proto, 254 const char * desc, unsigned int timestamp) 255{ 256 int r; 257 UNUSED(ifname); 258 UNUSED(desc); 259 UNUSED(timestamp); 260 261 r = addpeerdscprule(proto, dscp, iaddr, iport, rhost, rport); 262/* if(r >= 0) 263 add_redirect_desc(dscp, proto, desc, timestamp); */ 264 return r; 265} 266 267int 268add_filter_rule2(const char * ifname, 269 const char * rhost, const char * iaddr, 270 unsigned short eport, unsigned short iport, 271 int proto, const char * desc) 272{ 273 UNUSED(ifname); 274 UNUSED(eport); 275 UNUSED(desc); 276 277 return add_filter_rule(proto, rhost, iaddr, iport); 278} 279 280/* get_redirect_rule() 281 * returns -1 if the rule is not found */ 282int 283get_redirect_rule(const char * ifname, unsigned short eport, int proto, 284 char * iaddr, int iaddrlen, unsigned short * iport, 285 char * desc, int desclen, 286 char * rhost, int rhostlen, 287 unsigned int * timestamp, 288 u_int64_t * packets, u_int64_t * bytes) 289{ 290 return get_nat_redirect_rule(miniupnpd_nat_chain, 291 ifname, eport, proto, 292 iaddr, iaddrlen, iport, 293 desc, desclen, 294 rhost, rhostlen, 295 timestamp, packets, bytes); 296} 297 298int 299get_nat_redirect_rule(const char * nat_chain_name, const char * ifname, unsigned short eport, int proto, 300 char * iaddr, int iaddrlen, unsigned short * iport, 301 char * desc, int desclen, 302 char * rhost, int rhostlen, 303 unsigned int * timestamp, 304 u_int64_t * packets, u_int64_t * bytes) 305{ 306 int r = -1; 307 IPTC_HANDLE h; 308 const struct ipt_entry * e; 309 const struct ipt_entry_target * target; 310 const struct ip_nat_multi_range * mr; 311 const struct ipt_entry_match *match; 312 UNUSED(ifname); 313 314 h = iptc_init("nat"); 315 if(!h) 316 { 317 syslog(LOG_ERR, "get_redirect_rule() : " 318 "iptc_init() failed : %s", 319 iptc_strerror(errno)); 320 return -1; 321 } 322 if(!iptc_is_chain(nat_chain_name, h)) 323 { 324 syslog(LOG_ERR, "chain %s not found", nat_chain_name); 325 } 326 else 327 { 328#ifdef IPTABLES_143 329 for(e = iptc_first_rule(nat_chain_name, h); 330 e; 331 e = iptc_next_rule(e, h)) 332#else 333 for(e = iptc_first_rule(nat_chain_name, &h); 334 e; 335 e = iptc_next_rule(e, &h)) 336#endif 337 { 338 if(proto==e->ip.proto) 339 { 340 match = (const struct ipt_entry_match *)&e->elems; 341 if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN)) 342 { 343 const struct ipt_tcp * info; 344 info = (const struct ipt_tcp *)match->data; 345 if(eport != info->dpts[0]) 346 continue; 347 } 348 else 349 { 350 const struct ipt_udp * info; 351 info = (const struct ipt_udp *)match->data; 352 if(eport != info->dpts[0]) 353 continue; 354 } 355 target = (void *)e + e->target_offset; 356 /* target = ipt_get_target(e); */ 357 mr = (const struct ip_nat_multi_range *)&target->data[0]; 358 snprintip(iaddr, iaddrlen, ntohl(mr->range[0].min_ip)); 359 *iport = ntohs(mr->range[0].min.all); 360 get_redirect_desc(eport, proto, desc, desclen, timestamp); 361 if(packets) 362 *packets = e->counters.pcnt; 363 if(bytes) 364 *bytes = e->counters.bcnt; 365 /* rhost */ 366 if(e->ip.src.s_addr && rhost) { 367 snprintip(rhost, rhostlen, ntohl(e->ip.src.s_addr)); 368 } 369 r = 0; 370 break; 371 } 372 } 373 } 374 if(h) 375#ifdef IPTABLES_143 376 iptc_free(h); 377#else 378 iptc_free(&h); 379#endif 380 return r; 381} 382 383/* get_redirect_rule_by_index() 384 * return -1 when the rule was not found */ 385int 386get_redirect_rule_by_index(int index, 387 char * ifname, unsigned short * eport, 388 char * iaddr, int iaddrlen, unsigned short * iport, 389 int * proto, char * desc, int desclen, 390 char * rhost, int rhostlen, 391 unsigned int * timestamp, 392 u_int64_t * packets, u_int64_t * bytes) 393{ 394 int r = -1; 395#if USE_INDEX_FROM_DESC_LIST 396 r = get_redirect_desc_by_index(index, eport, proto, 397 desc, desclen, timestamp); 398 if (r==0) 399 { 400 r = get_redirect_rule(ifname, *eport, *proto, iaddr, iaddrlen, iport, 401 0, 0, packets, bytes); 402 } 403#else 404 int i = 0; 405 IPTC_HANDLE h; 406 const struct ipt_entry * e; 407 const struct ipt_entry_target * target; 408 const struct ip_nat_multi_range * mr; 409 const struct ipt_entry_match *match; 410 UNUSED(ifname); 411 412 h = iptc_init("nat"); 413 if(!h) 414 { 415 syslog(LOG_ERR, "get_redirect_rule_by_index() : " 416 "iptc_init() failed : %s", 417 iptc_strerror(errno)); 418 return -1; 419 } 420 if(!iptc_is_chain(miniupnpd_nat_chain, h)) 421 { 422 syslog(LOG_ERR, "chain %s not found", miniupnpd_nat_chain); 423 } 424 else 425 { 426#ifdef IPTABLES_143 427 for(e = iptc_first_rule(miniupnpd_nat_chain, h); 428 e; 429 e = iptc_next_rule(e, h)) 430#else 431 for(e = iptc_first_rule(miniupnpd_nat_chain, &h); 432 e; 433 e = iptc_next_rule(e, &h)) 434#endif 435 { 436 if(i==index) 437 { 438 *proto = e->ip.proto; 439 match = (const struct ipt_entry_match *)&e->elems; 440 if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN)) 441 { 442 const struct ipt_tcp * info; 443 info = (const struct ipt_tcp *)match->data; 444 *eport = info->dpts[0]; 445 } 446 else 447 { 448 const struct ipt_udp * info; 449 info = (const struct ipt_udp *)match->data; 450 *eport = info->dpts[0]; 451 } 452 target = (void *)e + e->target_offset; 453 mr = (const struct ip_nat_multi_range *)&target->data[0]; 454 snprintip(iaddr, iaddrlen, ntohl(mr->range[0].min_ip)); 455 *iport = ntohs(mr->range[0].min.all); 456 get_redirect_desc(*eport, *proto, desc, desclen, timestamp); 457 if(packets) 458 *packets = e->counters.pcnt; 459 if(bytes) 460 *bytes = e->counters.bcnt; 461 /* rhost */ 462 if(rhost && rhostlen > 0) { 463 if(e->ip.src.s_addr) { 464 snprintip(rhost, rhostlen, ntohl(e->ip.src.s_addr)); 465 } else { 466 rhost[0] = '\0'; 467 } 468 } 469 r = 0; 470 break; 471 } 472 i++; 473 } 474 } 475 if(h) 476#ifdef IPTABLES_143 477 iptc_free(h); 478#else 479 iptc_free(&h); 480#endif 481#endif 482 return r; 483} 484 485/* get_peer_rule_by_index() 486 * return -1 when the rule was not found */ 487int 488get_peer_rule_by_index(int index, 489 char * ifname, unsigned short * eport, 490 char * iaddr, int iaddrlen, unsigned short * iport, 491 int * proto, char * desc, int desclen, 492 char * rhost, int rhostlen, unsigned short * rport, 493 unsigned int * timestamp, 494 u_int64_t * packets, u_int64_t * bytes) 495{ 496 int r = -1; 497#if USE_INDEX_FROM_DESC_LIST && 0 498 r = get_redirect_desc_by_index(index, eport, proto, 499 desc, desclen, timestamp); 500 if (r==0) 501 { 502 r = get_redirect_rule(ifname, *eport, *proto, iaddr, iaddrlen, iport, 503 0, 0, packets, bytes); 504 } 505#else 506 int i = 0; 507 IPTC_HANDLE h; 508 const struct ipt_entry * e; 509 const struct ipt_entry_target * target; 510 const struct ip_nat_multi_range * mr; 511 const struct ipt_entry_match *match; 512 UNUSED(ifname); 513 514 h = iptc_init("nat"); 515 if(!h) 516 { 517 syslog(LOG_ERR, "get_peer_rule_by_index() : " 518 "iptc_init() failed : %s", 519 iptc_strerror(errno)); 520 return -1; 521 } 522 if(!iptc_is_chain(miniupnpd_peer_chain, h)) 523 { 524 syslog(LOG_ERR, "chain %s not found", miniupnpd_peer_chain); 525 } 526 else 527 { 528#ifdef IPTABLES_143 529 for(e = iptc_first_rule(miniupnpd_peer_chain, h); 530 e; 531 e = iptc_next_rule(e, h)) 532#else 533 for(e = iptc_first_rule(miniupnpd_peer_chain, &h); 534 e; 535 e = iptc_next_rule(e, &h)) 536#endif 537 { 538 if(i==index) 539 { 540 *proto = e->ip.proto; 541 match = (const struct ipt_entry_match *)&e->elems; 542 if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN)) 543 { 544 const struct ipt_tcp * info; 545 info = (const struct ipt_tcp *)match->data; 546 if (rport) 547 *rport = info->dpts[0]; 548 if (iport) 549 *iport = info->spts[0]; 550 } 551 else 552 { 553 const struct ipt_udp * info; 554 info = (const struct ipt_udp *)match->data; 555 if (rport) 556 *rport = info->dpts[0]; 557 if (iport) 558 *iport = info->spts[0]; 559 } 560 target = (void *)e + e->target_offset; 561 mr = (const struct ip_nat_multi_range *)&target->data[0]; 562 *eport = ntohs(mr->range[0].min.all); 563 get_redirect_desc(*eport, *proto, desc, desclen, timestamp); 564 if(packets) 565 *packets = e->counters.pcnt; 566 if(bytes) 567 *bytes = e->counters.bcnt; 568 /* rhost */ 569 if(rhost && rhostlen > 0) { 570 if(e->ip.dst.s_addr) { 571 snprintip(rhost, rhostlen, ntohl(e->ip.dst.s_addr)); 572 } else { 573 rhost[0] = '\0'; 574 } 575 } 576 if(iaddr && iaddrlen > 0) { 577 if(e->ip.src.s_addr) { 578 snprintip(iaddr, iaddrlen, ntohl(e->ip.src.s_addr)); 579 } else { 580 rhost[0] = '\0'; 581 } 582 } 583 r = 0; 584 break; 585 } 586 i++; 587 } 588 } 589 if(h) 590#ifdef IPTABLES_143 591 iptc_free(h); 592#else 593 iptc_free(&h); 594#endif 595#endif 596 return r; 597} 598 599/* delete_rule_and_commit() : 600 * subfunction used in delete_redirect_and_filter_rules() */ 601static int 602delete_rule_and_commit(unsigned int index, IPTC_HANDLE h, 603 const char * miniupnpd_chain, 604 const char * logcaller) 605{ 606 int r = 0; 607#ifdef IPTABLES_143 608 if(!iptc_delete_num_entry(miniupnpd_chain, index, h)) 609#else 610 if(!iptc_delete_num_entry(miniupnpd_chain, index, &h)) 611#endif 612 { 613 syslog(LOG_ERR, "%s() : iptc_delete_num_entry(): %s\n", 614 logcaller, iptc_strerror(errno)); 615 r = -1; 616 } 617#ifdef IPTABLES_143 618 else if(!iptc_commit(h)) 619#else 620 else if(!iptc_commit(&h)) 621#endif 622 { 623 syslog(LOG_ERR, "%s() : iptc_commit(): %s\n", 624 logcaller, iptc_strerror(errno)); 625 r = -1; 626 } 627 if(h) 628#ifdef IPTABLES_143 629 iptc_free(h); 630#else 631 iptc_free(&h); 632#endif 633 return r; 634} 635 636/* delete_redirect_and_filter_rules() 637 */ 638int 639delete_redirect_and_filter_rules(unsigned short eport, int proto) 640{ 641 int r = -1, r2 = -1; 642 unsigned index = 0; 643 unsigned i = 0; 644 IPTC_HANDLE h; 645 const struct ipt_entry * e; 646 const struct ipt_entry_target * target; 647 const struct ip_nat_multi_range * mr; 648 const struct ipt_entry_match *match; 649 unsigned short iport = 0; 650 uint32_t iaddr = 0; 651 652 h = iptc_init("nat"); 653 if(!h) 654 { 655 syslog(LOG_ERR, "delete_redirect_and_filter_rules() : " 656 "iptc_init() failed : %s", 657 iptc_strerror(errno)); 658 return -1; 659 } 660 /* First step : find the right nat rule */ 661 if(!iptc_is_chain(miniupnpd_nat_chain, h)) 662 { 663 syslog(LOG_ERR, "chain %s not found", miniupnpd_nat_chain); 664 } 665 else 666 { 667#ifdef IPTABLES_143 668 for(e = iptc_first_rule(miniupnpd_nat_chain, h); 669 e; 670 e = iptc_next_rule(e, h), i++) 671#else 672 for(e = iptc_first_rule(miniupnpd_nat_chain, &h); 673 e; 674 e = iptc_next_rule(e, &h), i++) 675#endif 676 { 677 if(proto==e->ip.proto) 678 { 679 match = (const struct ipt_entry_match *)&e->elems; 680 if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN)) 681 { 682 const struct ipt_tcp * info; 683 info = (const struct ipt_tcp *)match->data; 684 if(eport != info->dpts[0]) 685 continue; 686 } 687 else 688 { 689 const struct ipt_udp * info; 690 info = (const struct ipt_udp *)match->data; 691 if(eport != info->dpts[0]) 692 continue; 693 } 694 /* get the index, the internal address and the internal port 695 * of the rule */ 696 index = i; 697 target = (void *)e + e->target_offset; 698 mr = (const struct ip_nat_multi_range *)&target->data[0]; 699 iaddr = mr->range[0].min_ip; 700 iport = ntohs(mr->range[0].min.all); 701 r = 0; 702 break; 703 } 704 } 705 } 706 if(h) 707#ifdef IPTABLES_143 708 iptc_free(h); 709#else 710 iptc_free(&h); 711#endif 712 if(r == 0) 713 { 714 syslog(LOG_INFO, "Trying to delete nat rule at index %u", index); 715 /* Now delete both rules */ 716 /* first delete the nat rule */ 717 h = iptc_init("nat"); 718 if(h) 719 { 720 r = delete_rule_and_commit(index, h, miniupnpd_nat_chain, "delete_redirect_rule"); 721 } 722 if((r == 0) && (h = iptc_init("filter"))) 723 { 724 i = 0; 725 /* we must find the right index for the filter rule */ 726#ifdef IPTABLES_143 727 for(e = iptc_first_rule(miniupnpd_forward_chain, h); 728 e; 729 e = iptc_next_rule(e, h), i++) 730#else 731 for(e = iptc_first_rule(miniupnpd_forward_chain, &h); 732 e; 733 e = iptc_next_rule(e, &h), i++) 734#endif 735 { 736 if(proto==e->ip.proto) 737 { 738 match = (const struct ipt_entry_match *)&e->elems; 739 /*syslog(LOG_DEBUG, "filter rule #%u: %s %s", 740 i, match->u.user.name, inet_ntoa(e->ip.dst));*/ 741 if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN)) 742 { 743 const struct ipt_tcp * info; 744 info = (const struct ipt_tcp *)match->data; 745 if(iport != info->dpts[0]) 746 continue; 747 } 748 else 749 { 750 const struct ipt_udp * info; 751 info = (const struct ipt_udp *)match->data; 752 if(iport != info->dpts[0]) 753 continue; 754 } 755 if(iaddr != e->ip.dst.s_addr) 756 continue; 757 index = i; 758 syslog(LOG_INFO, "Trying to delete filter rule at index %u", index); 759 r = delete_rule_and_commit(index, h, miniupnpd_forward_chain, "delete_filter_rule"); 760 h = NULL; 761 break; 762 } 763 } 764 } 765 if(h) 766#ifdef IPTABLES_143 767 iptc_free(h); 768#else 769 iptc_free(&h); 770#endif 771 } 772 773 /*delete PEER rule*/ 774 if((h = iptc_init("nat"))) 775 { 776 i = 0; 777 /* we must find the right index for the filter rule */ 778#ifdef IPTABLES_143 779 for(e = iptc_first_rule(miniupnpd_peer_chain, h); 780 e; 781 e = iptc_next_rule(e, h), i++) 782#else 783 for(e = iptc_first_rule(miniupnpd_peer_chain, &h); 784 e; 785 e = iptc_next_rule(e, &h), i++) 786#endif 787 { 788 if(proto==e->ip.proto) 789 { 790 target = (void *)e + e->target_offset; 791 mr = (const struct ip_nat_multi_range *)&target->data[0]; 792 if (eport != ntohs(mr->range[0].min.all)) { 793 continue; 794 } 795 iaddr = e->ip.src.s_addr; 796 match = (const struct ipt_entry_match *)&e->elems; 797 if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN)) 798 { 799 const struct ipt_tcp * info; 800 info = (const struct ipt_tcp *)match->data; 801 iport = info->spts[0]; 802 } 803 else 804 { 805 const struct ipt_udp * info; 806 info = (const struct ipt_udp *)match->data; 807 iport = info->dpts[0]; 808 } 809 810 index = i; 811 syslog(LOG_INFO, "Trying to delete peer rule at index %u", index); 812 r2 = delete_rule_and_commit(index, h, miniupnpd_peer_chain, "delete_peer_rule"); 813 h = NULL; 814 break; 815 } 816 } 817 } 818 819 if(h) 820#ifdef IPTABLES_143 821 iptc_free(h); 822#else 823 iptc_free(&h); 824#endif 825 /*delete DSCP rule*/ 826 if((r2==0)&&(h = iptc_init("mangle"))) 827 { 828 i = 0; 829 index = -1; 830 /* we must find the right index for the filter rule */ 831#ifdef IPTABLES_143 832 for(e = iptc_first_rule(miniupnpd_nat_chain, h); 833 e; 834 e = iptc_next_rule(e, h), i++) 835#else 836 for(e = iptc_first_rule(miniupnpd_nat_chain, &h); 837 e; 838 e = iptc_next_rule(e, &h), i++) 839#endif 840 { 841 if(proto==e->ip.proto) 842 { 843 match = (const struct ipt_entry_match *)&e->elems; 844 /*syslog(LOG_DEBUG, "filter rule #%u: %s %s", 845 i, match->u.user.name, inet_ntoa(e->ip.dst));*/ 846 if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN)) 847 { 848 const struct ipt_tcp * info; 849 info = (const struct ipt_tcp *)match->data; 850 if(iport != info->spts[0]) 851 continue; 852 } 853 else 854 { 855 const struct ipt_udp * info; 856 info = (const struct ipt_udp *)match->data; 857 if(iport != info->spts[0]) 858 continue; 859 } 860 if(iaddr != e->ip.src.s_addr) 861 continue; 862 index = i; 863 syslog(LOG_INFO, "Trying to delete dscp rule at index %u", index); 864 r2 = delete_rule_and_commit(index, h, miniupnpd_nat_chain, "delete_dscp_rule"); 865 h = NULL; 866 break; 867 } 868 } 869 if (h) 870 #ifdef IPTABLES_143 871 iptc_free(h); 872 #else 873 iptc_free(&h); 874 #endif 875 } 876 877 del_redirect_desc(eport, proto); 878 return r*r2; 879} 880 881/* ==================================== */ 882/* TODO : add the -m state --state NEW,ESTABLISHED,RELATED 883 * only for the filter rule */ 884static struct ipt_entry_match * 885get_tcp_match(unsigned short dport, unsigned short sport) 886{ 887 struct ipt_entry_match *match; 888 struct ipt_tcp * tcpinfo; 889 size_t size; 890 size = IPT_ALIGN(sizeof(struct ipt_entry_match)) 891 + IPT_ALIGN(sizeof(struct ipt_tcp)); 892 match = calloc(1, size); 893 match->u.match_size = size; 894 strncpy(match->u.user.name, "tcp", sizeof(match->u.user.name)); 895 tcpinfo = (struct ipt_tcp *)match->data; 896 if (sport == 0) { 897 tcpinfo->spts[0] = 0; /* all source ports */ 898 tcpinfo->spts[1] = 0xFFFF; 899 } else { 900 tcpinfo->spts[0] = sport; /* specified source port */ 901 tcpinfo->spts[1] = sport; 902 } 903 if (dport == 0) { 904 tcpinfo->dpts[0] = 0; /* all destination ports */ 905 tcpinfo->dpts[1] = 0xFFFF; 906 } else { 907 tcpinfo->dpts[0] = dport; /* specified destination port */ 908 tcpinfo->dpts[1] = dport; 909 } 910 return match; 911} 912 913static struct ipt_entry_match * 914get_udp_match(unsigned short dport, unsigned short sport) 915{ 916 struct ipt_entry_match *match; 917 struct ipt_udp * udpinfo; 918 size_t size; 919 size = IPT_ALIGN(sizeof(struct ipt_entry_match)) 920 + IPT_ALIGN(sizeof(struct ipt_udp)); 921 match = calloc(1, size); 922 match->u.match_size = size; 923 strncpy(match->u.user.name, "udp", sizeof(match->u.user.name)); 924 udpinfo = (struct ipt_udp *)match->data; 925 if (sport == 0) { 926 udpinfo->spts[0] = 0; /* all source ports */ 927 udpinfo->spts[1] = 0xFFFF; 928 } else { 929 udpinfo->spts[0] = sport; /* specified source port */ 930 udpinfo->spts[1] = sport; 931 } 932 if (dport == 0) { 933 udpinfo->dpts[0] = 0; /* all destination ports */ 934 udpinfo->dpts[1] = 0xFFFF; 935 } else { 936 udpinfo->dpts[0] = dport; /* specified destination port */ 937 udpinfo->dpts[1] = dport; 938 } 939 return match; 940} 941 942static struct ipt_entry_target * 943get_dnat_target(const char * daddr, unsigned short dport) 944{ 945 struct ipt_entry_target * target; 946 struct ip_nat_multi_range * mr; 947 struct ip_nat_range * range; 948 size_t size; 949 950 size = IPT_ALIGN(sizeof(struct ipt_entry_target)) 951 + IPT_ALIGN(sizeof(struct ip_nat_multi_range)); 952 target = calloc(1, size); 953 target->u.target_size = size; 954 strncpy(target->u.user.name, "DNAT", sizeof(target->u.user.name)); 955 /* one ip_nat_range already included in ip_nat_multi_range */ 956 mr = (struct ip_nat_multi_range *)&target->data[0]; 957 mr->rangesize = 1; 958 range = &mr->range[0]; 959 range->min_ip = range->max_ip = inet_addr(daddr); 960 range->flags |= IP_NAT_RANGE_MAP_IPS; 961 range->min.all = range->max.all = htons(dport); 962 range->flags |= IP_NAT_RANGE_PROTO_SPECIFIED; 963 return target; 964} 965 966static struct ipt_entry_target * 967get_snat_target(const char * saddr, unsigned short sport) 968{ 969 struct ipt_entry_target * target; 970 struct ip_nat_multi_range * mr; 971 struct ip_nat_range * range; 972 size_t size; 973 974 size = IPT_ALIGN(sizeof(struct ipt_entry_target)) 975 + IPT_ALIGN(sizeof(struct ip_nat_multi_range)); 976 target = calloc(1, size); 977 target->u.target_size = size; 978 strncpy(target->u.user.name, "SNAT", sizeof(target->u.user.name)); 979 /* one ip_nat_range already included in ip_nat_multi_range */ 980 mr = (struct ip_nat_multi_range *)&target->data[0]; 981 mr->rangesize = 1; 982 range = &mr->range[0]; 983 range->min_ip = range->max_ip = inet_addr(saddr); 984 range->flags |= IP_NAT_RANGE_MAP_IPS; 985 range->min.all = range->max.all = htons(sport); 986 range->flags |= IP_NAT_RANGE_PROTO_SPECIFIED; 987 return target; 988} 989 990static struct ipt_entry_target * 991get_dscp_target(unsigned char dscp) 992{ 993 struct ipt_entry_target * target; 994 struct xt_DSCP_info * di; 995 size_t size; 996 997 size = IPT_ALIGN(sizeof(struct ipt_entry_target)) 998 + IPT_ALIGN(sizeof(struct xt_DSCP_info)); 999 target = calloc(1, size); 1000 target->u.target_size = size; 1001 strncpy(target->u.user.name, "DSCP", sizeof(target->u.user.name)); 1002 /* one ip_nat_range already included in ip_nat_multi_range */ 1003 di = (struct xt_DSCP_info *)&target->data[0]; 1004 di->dscp=dscp; 1005 return target; 1006} 1007 1008/* iptc_init_verify_and_append() 1009 * return 0 on success, -1 on failure */ 1010static int 1011iptc_init_verify_and_append(const char * table, 1012 const char * miniupnpd_chain, 1013 struct ipt_entry * e, 1014 const char * logcaller) 1015{ 1016 IPTC_HANDLE h; 1017 h = iptc_init(table); 1018 if(!h) 1019 { 1020 syslog(LOG_ERR, "%s : iptc_init() error : %s\n", 1021 logcaller, iptc_strerror(errno)); 1022 return -1; 1023 } 1024 if(!iptc_is_chain(miniupnpd_chain, h)) 1025 { 1026 syslog(LOG_ERR, "%s : chain %s not found", 1027 logcaller, miniupnpd_chain); 1028 if(h) 1029#ifdef IPTABLES_143 1030 iptc_free(h); 1031#else 1032 iptc_free(&h); 1033#endif 1034 return -1; 1035 } 1036 /* iptc_insert_entry(miniupnpd_chain, e, n, h/&h) could also be used */ 1037#ifdef IPTABLES_143 1038 if(!iptc_append_entry(miniupnpd_chain, e, h)) 1039#else 1040 if(!iptc_append_entry(miniupnpd_chain, e, &h)) 1041#endif 1042 { 1043 syslog(LOG_ERR, "%s : iptc_append_entry() error : %s\n", 1044 logcaller, iptc_strerror(errno)); 1045 if(h) 1046#ifdef IPTABLES_143 1047 iptc_free(h); 1048#else 1049 iptc_free(&h); 1050#endif 1051 return -1; 1052 } 1053#ifdef IPTABLES_143 1054 if(!iptc_commit(h)) 1055#else 1056 if(!iptc_commit(&h)) 1057#endif 1058 { 1059 syslog(LOG_ERR, "%s : iptc_commit() error : %s\n", 1060 logcaller, iptc_strerror(errno)); 1061 if(h) 1062#ifdef IPTABLES_143 1063 iptc_free(h); 1064#else 1065 iptc_free(&h); 1066#endif 1067 return -1; 1068 } 1069 if(h) 1070#ifdef IPTABLES_143 1071 iptc_free(h); 1072#else 1073 iptc_free(&h); 1074#endif 1075 return 0; 1076} 1077 1078/* add nat rule 1079 * iptables -t nat -A MINIUPNPD -p proto --dport eport -j DNAT --to iaddr:iport 1080 * */ 1081static int 1082addnatrule(int proto, unsigned short eport, 1083 const char * iaddr, unsigned short iport, 1084 const char * rhost) 1085{ 1086 int r = 0; 1087 struct ipt_entry * e; 1088 struct ipt_entry * tmp; 1089 struct ipt_entry_match *match = NULL; 1090 struct ipt_entry_target *target = NULL; 1091 1092 e = calloc(1, sizeof(struct ipt_entry)); 1093 if(!e) { 1094 syslog(LOG_ERR, "%s: calloc(%d) error", "addnatrule", 1095 (int)sizeof(struct ipt_entry)); 1096 return -1; 1097 } 1098 e->ip.proto = proto; 1099 if(proto == IPPROTO_TCP) { 1100 match = get_tcp_match(eport, 0); 1101 } else { 1102 match = get_udp_match(eport, 0); 1103 } 1104 e->nfcache = NFC_IP_DST_PT; 1105 target = get_dnat_target(iaddr, iport); 1106 e->nfcache |= NFC_UNKNOWN; 1107 tmp = realloc(e, sizeof(struct ipt_entry) 1108 + match->u.match_size 1109 + target->u.target_size); 1110 if(!tmp) { 1111 syslog(LOG_ERR, "%s: realloc(%d) error", "addnatrule", 1112 (int)(sizeof(struct ipt_entry) + match->u.match_size + target->u.target_size)); 1113 free(e); 1114 free(match); 1115 free(target); 1116 return -1; 1117 } 1118 e = tmp; 1119 memcpy(e->elems, match, match->u.match_size); 1120 memcpy(e->elems + match->u.match_size, target, target->u.target_size); 1121 e->target_offset = sizeof(struct ipt_entry) 1122 + match->u.match_size; 1123 e->next_offset = sizeof(struct ipt_entry) 1124 + match->u.match_size 1125 + target->u.target_size; 1126 /* remote host */ 1127 if(rhost && (rhost[0] != '\0') && (0 != strcmp(rhost, "*"))) { 1128 e->ip.src.s_addr = inet_addr(rhost); 1129 e->ip.smsk.s_addr = INADDR_NONE; 1130 } 1131 1132 r = iptc_init_verify_and_append("nat", miniupnpd_nat_chain, e, "addnatrule()"); 1133 free(target); 1134 free(match); 1135 free(e); 1136 return r; 1137} 1138 1139/* iptables -t nat -A MINIUPNPD-PCP-PEER -s iaddr -d rhost 1140 * -p proto --sport iport --dport rport -j SNAT 1141 * --to-source ext_ip:eport */ 1142static int 1143addpeernatrule(int proto, 1144 const char * eaddr, unsigned short eport, 1145 const char * iaddr, unsigned short iport, 1146 const char * rhost, unsigned short rport) 1147{ 1148 int r = 0; 1149 struct ipt_entry * e; 1150 struct ipt_entry * tmp; 1151 struct ipt_entry_match *match = NULL; 1152 struct ipt_entry_target *target = NULL; 1153 1154 e = calloc(1, sizeof(struct ipt_entry)); 1155 if(!e) { 1156 syslog(LOG_ERR, "%s: calloc(%d) error", "addpeernatrule", 1157 (int)sizeof(struct ipt_entry)); 1158 return -1; 1159 } 1160 e->ip.proto = proto; 1161 /* TODO: Fill port matches and SNAT */ 1162 if(proto == IPPROTO_TCP) { 1163 match = get_tcp_match(rport, iport); 1164 } else { 1165 match = get_udp_match(rport, iport); 1166 } 1167 e->nfcache = NFC_IP_DST_PT | NFC_IP_SRC_PT; 1168 target = get_snat_target(eaddr, eport); 1169 e->nfcache |= NFC_UNKNOWN; 1170 tmp = realloc(e, sizeof(struct ipt_entry) 1171 + match->u.match_size 1172 + target->u.target_size); 1173 if(!tmp) { 1174 syslog(LOG_ERR, "%s: realloc(%d) error", "addpeernatrule", 1175 (int)(sizeof(struct ipt_entry) + match->u.match_size + target->u.target_size)); 1176 free(e); 1177 free(match); 1178 free(target); 1179 return -1; 1180 } 1181 e = tmp; 1182 memcpy(e->elems, match, match->u.match_size); 1183 memcpy(e->elems + match->u.match_size, target, target->u.target_size); 1184 e->target_offset = sizeof(struct ipt_entry) 1185 + match->u.match_size; 1186 e->next_offset = sizeof(struct ipt_entry) 1187 + match->u.match_size 1188 + target->u.target_size; 1189 1190 /* internal host */ 1191 if(iaddr && (iaddr[0] != '\0') && (0 != strcmp(iaddr, "*"))) 1192 { 1193 e->ip.src.s_addr = inet_addr(iaddr); 1194 e->ip.smsk.s_addr = INADDR_NONE; 1195 } 1196 /* remote host */ 1197 if(rhost && (rhost[0] != '\0') && (0 != strcmp(rhost, "*"))) 1198 { 1199 e->ip.dst.s_addr = inet_addr(rhost); 1200 e->ip.dmsk.s_addr = INADDR_NONE; 1201 } 1202 1203 r = iptc_init_verify_and_append("nat", miniupnpd_peer_chain, e, "addpeernatrule()"); 1204 free(target); 1205 free(match); 1206 free(e); 1207 return r; 1208} 1209 1210/* iptables -t mangle -A MINIUPNPD -s iaddr -d rhost 1211 * -p proto --sport iport --dport rport -j DSCP 1212 * --set-dscp 0xXXXX */ 1213static int 1214addpeerdscprule(int proto, unsigned char dscp, 1215 const char * iaddr, unsigned short iport, 1216 const char * rhost, unsigned short rport) 1217{ 1218 int r = 0; 1219 struct ipt_entry * e; 1220 struct ipt_entry * tmp; 1221 struct ipt_entry_match *match = NULL; 1222 struct ipt_entry_target *target = NULL; 1223 1224 e = calloc(1, sizeof(struct ipt_entry)); 1225 if(!e) { 1226 syslog(LOG_ERR, "%s: calloc(%d) error", "addpeerdscprule", 1227 (int)sizeof(struct ipt_entry)); 1228 return -1; 1229 } 1230 e->ip.proto = proto; 1231 /* TODO: Fill port matches and SNAT */ 1232 if(proto == IPPROTO_TCP) { 1233 match = get_tcp_match(rport, iport); 1234 } else { 1235 match = get_udp_match(rport, iport); 1236 } 1237 e->nfcache = NFC_IP_DST_PT | NFC_IP_SRC_PT; 1238 target = get_dscp_target(dscp); 1239 e->nfcache |= NFC_UNKNOWN; 1240 tmp = realloc(e, sizeof(struct ipt_entry) 1241 + match->u.match_size 1242 + target->u.target_size); 1243 if(!tmp) { 1244 syslog(LOG_ERR, "%s: realloc(%d) error", "addpeerdscprule", 1245 (int)(sizeof(struct ipt_entry) + match->u.match_size + target->u.target_size)); 1246 free(e); 1247 free(match); 1248 free(target); 1249 return -1; 1250 } 1251 e = tmp; 1252 memcpy(e->elems, match, match->u.match_size); 1253 memcpy(e->elems + match->u.match_size, target, target->u.target_size); 1254 e->target_offset = sizeof(struct ipt_entry) 1255 + match->u.match_size; 1256 e->next_offset = sizeof(struct ipt_entry) 1257 + match->u.match_size 1258 + target->u.target_size; 1259 1260 /* internal host */ 1261 if(iaddr && (iaddr[0] != '\0') && (0 != strcmp(iaddr, "*"))) 1262 { 1263 e->ip.src.s_addr = inet_addr(iaddr); 1264 e->ip.smsk.s_addr = INADDR_NONE; 1265 } 1266 /* remote host */ 1267 if(rhost && (rhost[0] != '\0') && (0 != strcmp(rhost, "*"))) 1268 { 1269 e->ip.dst.s_addr = inet_addr(rhost); 1270 e->ip.dmsk.s_addr = INADDR_NONE; 1271 } 1272 1273 r = iptc_init_verify_and_append("mangle", miniupnpd_nat_chain, e, 1274 "addpeerDSCPrule()"); 1275 free(target); 1276 free(match); 1277 free(e); 1278 return r; 1279} 1280 1281 1282/* ================================= */ 1283static struct ipt_entry_target * 1284get_accept_target(void) 1285{ 1286 struct ipt_entry_target * target = NULL; 1287 size_t size; 1288 size = IPT_ALIGN(sizeof(struct ipt_entry_target)) 1289 + IPT_ALIGN(sizeof(int)); 1290 target = calloc(1, size); 1291 target->u.user.target_size = size; 1292 strncpy(target->u.user.name, "ACCEPT", sizeof(target->u.user.name)); 1293 return target; 1294} 1295 1296/* add_filter_rule() 1297 * */ 1298static int 1299add_filter_rule(int proto, const char * rhost, 1300 const char * iaddr, unsigned short iport) 1301{ 1302 int r = 0; 1303 struct ipt_entry * e; 1304 struct ipt_entry * tmp; 1305 struct ipt_entry_match *match = NULL; 1306 struct ipt_entry_target *target = NULL; 1307 1308 e = calloc(1, sizeof(struct ipt_entry)); 1309 if(!e) { 1310 syslog(LOG_ERR, "%s: calloc(%d) error", "add_filter_rule", 1311 (int)sizeof(struct ipt_entry)); 1312 return -1; 1313 } 1314 e->ip.proto = proto; 1315 if(proto == IPPROTO_TCP) { 1316 match = get_tcp_match(iport,0); 1317 } else { 1318 match = get_udp_match(iport,0); 1319 } 1320 e->nfcache = NFC_IP_DST_PT; 1321 e->ip.dst.s_addr = inet_addr(iaddr); 1322 e->ip.dmsk.s_addr = INADDR_NONE; 1323 target = get_accept_target(); 1324 e->nfcache |= NFC_UNKNOWN; 1325 tmp = realloc(e, sizeof(struct ipt_entry) 1326 + match->u.match_size 1327 + target->u.target_size); 1328 if(!tmp) { 1329 syslog(LOG_ERR, "%s: realloc(%d) error", "add_filter_rule", 1330 (int)(sizeof(struct ipt_entry) + match->u.match_size + target->u.target_size)); 1331 free(e); 1332 free(match); 1333 free(target); 1334 return -1; 1335 } 1336 e = tmp; 1337 memcpy(e->elems, match, match->u.match_size); 1338 memcpy(e->elems + match->u.match_size, target, target->u.target_size); 1339 e->target_offset = sizeof(struct ipt_entry) 1340 + match->u.match_size; 1341 e->next_offset = sizeof(struct ipt_entry) 1342 + match->u.match_size 1343 + target->u.target_size; 1344 /* remote host */ 1345 if(rhost && (rhost[0] != '\0') && (0 != strcmp(rhost, "*"))) 1346 { 1347 e->ip.src.s_addr = inet_addr(rhost); 1348 e->ip.smsk.s_addr = INADDR_NONE; 1349 } 1350 1351 r = iptc_init_verify_and_append("filter", miniupnpd_forward_chain, e, "add_filter_rule()"); 1352 free(target); 1353 free(match); 1354 free(e); 1355 return r; 1356} 1357 1358/* return an (malloc'ed) array of "external" port for which there is 1359 * a port mapping. number is the size of the array */ 1360unsigned short * 1361get_portmappings_in_range(unsigned short startport, unsigned short endport, 1362 int proto, unsigned int * number) 1363{ 1364 unsigned short * array; 1365 unsigned int capacity; 1366 unsigned short eport; 1367 IPTC_HANDLE h; 1368 const struct ipt_entry * e; 1369 const struct ipt_entry_match *match; 1370 1371 *number = 0; 1372 capacity = 128; 1373 array = calloc(capacity, sizeof(unsigned short)); 1374 if(!array) 1375 { 1376 syslog(LOG_ERR, "get_portmappings_in_range() : calloc error"); 1377 return NULL; 1378 } 1379 1380 h = iptc_init("nat"); 1381 if(!h) 1382 { 1383 syslog(LOG_ERR, "get_redirect_rule_by_index() : " 1384 "iptc_init() failed : %s", 1385 iptc_strerror(errno)); 1386 free(array); 1387 return NULL; 1388 } 1389 if(!iptc_is_chain(miniupnpd_nat_chain, h)) 1390 { 1391 syslog(LOG_ERR, "chain %s not found", miniupnpd_nat_chain); 1392 free(array); 1393 array = NULL; 1394 } 1395 else 1396 { 1397#ifdef IPTABLES_143 1398 for(e = iptc_first_rule(miniupnpd_nat_chain, h); 1399 e; 1400 e = iptc_next_rule(e, h)) 1401#else 1402 for(e = iptc_first_rule(miniupnpd_nat_chain, &h); 1403 e; 1404 e = iptc_next_rule(e, &h)) 1405#endif 1406 { 1407 if(proto == e->ip.proto) 1408 { 1409 match = (const struct ipt_entry_match *)&e->elems; 1410 if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN)) 1411 { 1412 const struct ipt_tcp * info; 1413 info = (const struct ipt_tcp *)match->data; 1414 eport = info->dpts[0]; 1415 } 1416 else 1417 { 1418 const struct ipt_udp * info; 1419 info = (const struct ipt_udp *)match->data; 1420 eport = info->dpts[0]; 1421 } 1422 if(startport <= eport && eport <= endport) 1423 { 1424 if(*number >= capacity) 1425 { 1426 unsigned short * tmp; 1427 /* need to increase the capacity of the array */ 1428 tmp = realloc(array, sizeof(unsigned short)*capacity); 1429 if(!tmp) 1430 { 1431 syslog(LOG_ERR, "get_portmappings_in_range() : realloc(%u) error", 1432 (unsigned)sizeof(unsigned short)*capacity); 1433 *number = 0; 1434 free(array); 1435 array = NULL; 1436 break; 1437 } 1438 array = tmp; 1439 } 1440 array[*number] = eport; 1441 (*number)++; 1442 } 1443 } 1444 } 1445 } 1446 if(h) 1447#ifdef IPTABLES_143 1448 iptc_free(h); 1449#else 1450 iptc_free(&h); 1451#endif 1452 return array; 1453} 1454 1455/* ================================ */ 1456#ifdef DEBUG 1457static int 1458print_match(const struct ipt_entry_match *match) 1459{ 1460 printf("match %s\n", match->u.user.name); 1461 if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN)) 1462 { 1463 struct ipt_tcp * tcpinfo; 1464 tcpinfo = (struct ipt_tcp *)match->data; 1465 printf("srcport = %hu:%hu dstport = %hu:%hu\n", 1466 tcpinfo->spts[0], tcpinfo->spts[1], 1467 tcpinfo->dpts[0], tcpinfo->dpts[1]); 1468 } 1469 else if(0 == strncmp(match->u.user.name, "udp", IPT_FUNCTION_MAXNAMELEN)) 1470 { 1471 struct ipt_udp * udpinfo; 1472 udpinfo = (struct ipt_udp *)match->data; 1473 printf("srcport = %hu:%hu dstport = %hu:%hu\n", 1474 udpinfo->spts[0], udpinfo->spts[1], 1475 udpinfo->dpts[0], udpinfo->dpts[1]); 1476 } 1477 return 0; 1478} 1479 1480static void 1481print_iface(const char * iface, const unsigned char * mask, int invert) 1482{ 1483 unsigned i; 1484 if(mask[0] == 0) 1485 return; 1486 if(invert) 1487 printf("! "); 1488 for(i=0; i<IFNAMSIZ; i++) 1489 { 1490 if(mask[i]) 1491 { 1492 if(iface[i]) 1493 putchar(iface[i]); 1494 } 1495 else 1496 { 1497 if(iface[i-1]) 1498 putchar('+'); 1499 break; 1500 } 1501 } 1502} 1503 1504static void 1505printip(uint32_t ip) 1506{ 1507 printf("%u.%u.%u.%u", ip >> 24, (ip >> 16) & 0xff, 1508 (ip >> 8) & 0xff, ip & 0xff); 1509} 1510 1511/* for debug */ 1512/* read the "filter" and "nat" tables */ 1513int 1514list_redirect_rule(const char * ifname) 1515{ 1516 IPTC_HANDLE h; 1517 const struct ipt_entry * e; 1518 const struct ipt_entry_target * target; 1519 const struct ip_nat_multi_range * mr; 1520 const char * target_str; 1521 char addr[16], mask[16]; 1522 (void)ifname; 1523 1524 h = iptc_init("nat"); 1525 if(!h) 1526 { 1527 printf("iptc_init() error : %s\n", iptc_strerror(errno)); 1528 return -1; 1529 } 1530 if(!iptc_is_chain(miniupnpd_nat_chain, h)) 1531 { 1532 printf("chain %s not found\n", miniupnpd_nat_chain); 1533#ifdef IPTABLES_143 1534 iptc_free(h); 1535#else 1536 iptc_free(&h); 1537#endif 1538 return -1; 1539 } 1540#ifdef IPTABLES_143 1541 for(e = iptc_first_rule(miniupnpd_nat_chain, h); 1542 e; 1543 e = iptc_next_rule(e, h)) 1544 { 1545 target_str = iptc_get_target(e, h); 1546#else 1547 for(e = iptc_first_rule(miniupnpd_nat_chain, &h); 1548 e; 1549 e = iptc_next_rule(e, &h)) 1550 { 1551 target_str = iptc_get_target(e, &h); 1552#endif 1553 printf("===\n"); 1554 inet_ntop(AF_INET, &e->ip.src, addr, sizeof(addr)); 1555 inet_ntop(AF_INET, &e->ip.smsk, mask, sizeof(mask)); 1556 printf("src = %s%s/%s\n", (e->ip.invflags & IPT_INV_SRCIP)?"! ":"", 1557 /*inet_ntoa(e->ip.src), inet_ntoa(e->ip.smsk)*/ 1558 addr, mask); 1559 inet_ntop(AF_INET, &e->ip.dst, addr, sizeof(addr)); 1560 inet_ntop(AF_INET, &e->ip.dmsk, mask, sizeof(mask)); 1561 printf("dst = %s%s/%s\n", (e->ip.invflags & IPT_INV_DSTIP)?"! ":"", 1562 /*inet_ntoa(e->ip.dst), inet_ntoa(e->ip.dmsk)*/ 1563 addr, mask); 1564 /*printf("in_if = %s out_if = %s\n", e->ip.iniface, e->ip.outiface);*/ 1565 printf("in_if = "); 1566 print_iface(e->ip.iniface, e->ip.iniface_mask, 1567 e->ip.invflags & IPT_INV_VIA_IN); 1568 printf(" out_if = "); 1569 print_iface(e->ip.outiface, e->ip.outiface_mask, 1570 e->ip.invflags & IPT_INV_VIA_OUT); 1571 printf("\n"); 1572 printf("ip.proto = %s%d\n", (e->ip.invflags & IPT_INV_PROTO)?"! ":"", 1573 e->ip.proto); 1574 /* display matches stuff */ 1575 if(e->target_offset) 1576 { 1577 IPT_MATCH_ITERATE(e, print_match); 1578 /*printf("\n");*/ 1579 } 1580 printf("target = %s\n", target_str); 1581 target = (void *)e + e->target_offset; 1582 mr = (const struct ip_nat_multi_range *)&target->data[0]; 1583 printf("ips "); 1584 printip(ntohl(mr->range[0].min_ip)); 1585 printf(" "); 1586 printip(ntohl(mr->range[0].max_ip)); 1587 printf("\nports %hu %hu\n", ntohs(mr->range[0].min.all), 1588 ntohs(mr->range[0].max.all)); 1589 printf("flags = %x\n", mr->range[0].flags); 1590 } 1591 if(h) 1592#ifdef IPTABLES_143 1593 iptc_free(h); 1594#else 1595 iptc_free(&h); 1596#endif 1597 return 0; 1598} 1599#endif 1600