/* iptc_init_verify_and_append() * return 0 on success, -1 on failure */ static int iptc_init_verify_and_append(const char * table, struct ipt_entry * e, const char * logcaller) { iptc_handle_t h; h = iptc_init(table); if(!h) { syslog(LOG_ERR, "%s : iptc_init() error : %s\n", logcaller, iptc_strerror(errno)); return -1; } if(!iptc_is_chain(miniupnpd_chain, h)) { syslog(LOG_ERR, "%s : iptc_is_chain() error : %s\n", logcaller, iptc_strerror(errno)); return -1; } if(!iptc_append_entry(miniupnpd_chain, e, &h)) { syslog(LOG_ERR, "%s : iptc_append_entry() error : %s\n", logcaller, iptc_strerror(errno)); return -1; } if(!iptc_commit(&h)) { syslog(LOG_ERR, "%s : iptc_commit() error : %s\n", logcaller, iptc_strerror(errno)); return -1; } return 0; }
int delete_ntk_forward_chain(iptc_handle_t * t) { int res; res = iptc_is_chain(NTK_MARK_CHAIN, *t); if (!res) return 0; res = iptc_flush_entries(NTK_MARK_CHAIN, t); if (!res) goto cannot_delete; res = iptc_delete_chain(NTK_MARK_CHAIN, t); if (!res) goto cannot_delete; return 0; cannot_delete: error("In delete_ntk_forward_chain: -> %s", iptc_strerror(errno)); err_ret(ERR_NETDEL, -1); }
/* * Build the chain ntk_mark_chain on * mangle table. */ int ntk_mark_chain_init(iptc_handle_t * t) { int res; res = iptc_is_chain(NTK_MARK_CHAIN, *t); if (res) { debug(DBG_NORMAL, "In mark_init: bizarre, ntk mangle" "chain is present yet. it will be flushed."); res = iptc_flush_entries(NTK_MARK_CHAIN, t); if (!res) goto dontwork; } else { res = iptc_create_chain(NTK_MARK_CHAIN, t); if (!res) goto dontwork; } return 0; dontwork: error("In ntk_mark_chain_init: -> %s", iptc_strerror(errno)); err_ret(ERR_NETCHA, -1) }
/* delete_redirect_and_filter_rules() */ int delete_redirect_and_filter_rules(unsigned short eport, int proto) { int r = -1; unsigned index = 0; unsigned i = 0; iptc_handle_t h; const struct ipt_entry * e; const struct ipt_entry_match *match; h = iptc_init("nat"); if(!h) { syslog(LOG_ERR, "delete_redirect_and_filter_rules() : " "iptc_init() failed : %s", iptc_strerror(errno)); return -1; } if(!iptc_is_chain(miniupnpd_chain, h)) { syslog(LOG_ERR, "chain %s not found", miniupnpd_chain); } else { for(e = iptc_first_rule(miniupnpd_chain, &h); e; e = iptc_next_rule(e, &h), i++) { if(proto==e->ip.proto) { match = (const struct ipt_entry_match *)&e->elems; if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN)) { const struct ipt_tcp * info; info = (const struct ipt_tcp *)match->data; if(eport != info->dpts[0]) continue; } else { const struct ipt_udp * info; info = (const struct ipt_udp *)match->data; if(eport != info->dpts[0]) continue; } index = i; r = 0; break; } } } iptc_free(&h); if(r == 0) { syslog(LOG_INFO, "Trying to delete rules at index %u", index); /* Now delete both rules */ h = iptc_init("nat"); if(h) { r = delete_rule_and_commit(index, &h, "delete_redirect_rule"); } h = iptc_init("filter"); if(h && (r == 0)) { r = delete_rule_and_commit(index, &h, "delete_filter_rule"); } } del_redirect_desc(eport, proto); return r; }
/* get_redirect_rule_by_index() * return -1 when the rule was not found */ int get_redirect_rule_by_index(int index, char * ifname, unsigned short * eport, char * iaddr, int iaddrlen, unsigned short * iport, int * proto, char * desc, int desclen, u_int64_t * packets, u_int64_t * bytes) { int r = -1; int i = 0; iptc_handle_t h; const struct ipt_entry * e; const struct ipt_entry_target * target; const struct ip_nat_multi_range * mr; const struct ipt_entry_match *match; h = iptc_init("nat"); if(!h) { syslog(LOG_ERR, "get_redirect_rule_by_index() : " "iptc_init() failed : %s", iptc_strerror(errno)); return -1; } if(!iptc_is_chain(miniupnpd_chain, h)) { syslog(LOG_ERR, "chain %s not found", miniupnpd_chain); } else { for(e = iptc_first_rule(miniupnpd_chain, &h); e; e = iptc_next_rule(e, &h)) { if(i==index) { *proto = e->ip.proto; match = (const struct ipt_entry_match *)&e->elems; if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN)) { const struct ipt_tcp * info; info = (const struct ipt_tcp *)match->data; *eport = info->dpts[0]; } else { const struct ipt_udp * info; info = (const struct ipt_udp *)match->data; *eport = info->dpts[0]; } target = (void *)e + e->target_offset; mr = (const struct ip_nat_multi_range *)&target->data[0]; snprintip(iaddr, iaddrlen, ntohl(mr->range[0].min_ip)); *iport = ntohs(mr->range[0].min.all); /*if(desc) strncpy(desc, "miniupnpd", desclen);*/ get_redirect_desc(*eport, *proto, desc, desclen); if(packets) *packets = e->counters.pcnt; if(bytes) *bytes = e->counters.bcnt; r = 0; break; } i++; } } iptc_free(&h); return r; }
int main(int argc, char *argv[]) #endif { iptc_handle_t handle = NULL; char buffer[10240]; int c; char curtable[IPT_TABLE_MAXNAMELEN + 1]; FILE *in; const char *modprobe = 0; int in_table = 0, testing = 0; program_name = "iptables-restore"; program_version = IPTABLES_VERSION; line = 0; lib_dir = getenv("IPTABLES_LIB_DIR"); if (!lib_dir) lib_dir = IPT_LIB_DIR; #ifdef NO_SHARED_LIBS init_extensions(); #endif while ((c = getopt_long(argc, argv, "bcvthnM:", options, NULL)) != -1) { switch (c) { case 'b': binary = 1; break; case 'c': counters = 1; break; case 'v': verbose = 1; break; case 't': testing = 1; break; case 'h': print_usage("iptables-restore", IPTABLES_VERSION); break; case 'n': noflush = 1; break; case 'M': modprobe = optarg; break; } } if (optind == argc - 1) { in = fopen(argv[optind], "r"); if (!in) { fprintf(stderr, "Can't open %s: %s", argv[optind], strerror(errno)); exit(1); } } else if (optind < argc) { fprintf(stderr, "Unknown arguments found on commandline"); exit(1); } else in = stdin; /* Grab standard input. */ while (fgets(buffer, sizeof(buffer), in)) { int ret = 0; line++; if (buffer[0] == '\n') continue; else if (buffer[0] == '#') { if (verbose) fputs(buffer, stdout); continue; } else if ((strcmp(buffer, "COMMIT\n") == 0) && (in_table)) { if (!testing) { DEBUGP("Calling commit\n"); ret = iptc_commit(&handle); } else { DEBUGP("Not calling commit, testing\n"); ret = 1; } in_table = 0; } else if ((buffer[0] == '*') && (!in_table)) { /* New table */ char *table; table = strtok(buffer+1, " \t\n"); DEBUGP("line %u, table '%s'\n", line, table); if (!table) { exit_error(PARAMETER_PROBLEM, "%s: line %u table name invalid\n", program_name, line); exit(1); } strncpy(curtable, table, IPT_TABLE_MAXNAMELEN); curtable[IPT_TABLE_MAXNAMELEN] = '\0'; if (handle) iptc_free(&handle); handle = create_handle(table, modprobe); if (noflush == 0) { DEBUGP("Cleaning all chains of table '%s'\n", table); for_each_chain(flush_entries, verbose, 1, &handle); DEBUGP("Deleting all user-defined chains " "of table '%s'\n", table); for_each_chain(delete_chain, verbose, 0, &handle) ; } ret = 1; in_table = 1; } else if ((buffer[0] == ':') && (in_table)) { /* New chain. */ char *policy, *chain; chain = strtok(buffer+1, " \t\n"); DEBUGP("line %u, chain '%s'\n", line, chain); if (!chain) { exit_error(PARAMETER_PROBLEM, "%s: line %u chain name invalid\n", program_name, line); exit(1); } if (iptc_builtin(chain, handle) <= 0) { if (noflush && iptc_is_chain(chain, handle)) { DEBUGP("Flushing existing user defined chain '%s'\n", chain); if (!iptc_flush_entries(chain, &handle)) exit_error(PARAMETER_PROBLEM, "error flushing chain " "'%s':%s\n", chain, strerror(errno)); } else { DEBUGP("Creating new chain '%s'\n", chain); if (!iptc_create_chain(chain, &handle)) exit_error(PARAMETER_PROBLEM, "error creating chain " "'%s':%s\n", chain, strerror(errno)); } } policy = strtok(NULL, " \t\n"); DEBUGP("line %u, policy '%s'\n", line, policy); if (!policy) { exit_error(PARAMETER_PROBLEM, "%s: line %u policy invalid\n", program_name, line); exit(1); } if (strcmp(policy, "-") != 0) { struct ipt_counters count; if (counters) { char *ctrs; ctrs = strtok(NULL, " \t\n"); if (!ctrs || !parse_counters(ctrs, &count)) exit_error(PARAMETER_PROBLEM, "invalid policy counters " "for chain '%s'\n", chain); } else { memset(&count, 0, sizeof(struct ipt_counters)); } DEBUGP("Setting policy of chain %s to %s\n", chain, policy); if (!iptc_set_policy(chain, policy, &count, &handle)) exit_error(OTHER_PROBLEM, "Can't set policy `%s'" " on `%s' line %u: %s\n", chain, policy, line, iptc_strerror(errno)); } ret = 1; } else if (in_table) { int a; char *ptr = buffer; char *pcnt = NULL; char *bcnt = NULL; char *parsestart; /* the parser */ char *param_start, *curchar; int quote_open; /* reset the newargv */ newargc = 0; if (buffer[0] == '[') { /* we have counters in our input */ ptr = strchr(buffer, ']'); if (!ptr) exit_error(PARAMETER_PROBLEM, "Bad line %u: need ]\n", line); pcnt = strtok(buffer+1, ":"); if (!pcnt) exit_error(PARAMETER_PROBLEM, "Bad line %u: need :\n", line); bcnt = strtok(NULL, "]"); if (!bcnt) exit_error(PARAMETER_PROBLEM, "Bad line %u: need ]\n", line); /* start command parsing after counter */ parsestart = ptr + 1; } else { /* start command parsing at start of line */ parsestart = buffer; } add_argv(argv[0]); add_argv("-t"); add_argv((char *) &curtable); if (counters && pcnt && bcnt) { add_argv("--set-counters"); add_argv((char *) pcnt); add_argv((char *) bcnt); } /* After fighting with strtok enough, here's now * a 'real' parser. According to Rusty I'm now no * longer a real hacker, but I can live with that */ quote_open = 0; param_start = parsestart; for (curchar = parsestart; *curchar; curchar++) { if (*curchar == '"') { /* quote_open cannot be true if there * was no previous character. Thus, * curchar-1 has to be within bounds */ if (quote_open && *(curchar-1) != '\\') { quote_open = 0; *curchar = ' '; } else { quote_open = 1; param_start++; } } if (*curchar == ' ' || *curchar == '\t' || * curchar == '\n') { char param_buffer[1024]; int param_len = curchar-param_start; if (quote_open) continue; if (!param_len) { /* two spaces? */ param_start++; continue; } /* end of one parameter */ strncpy(param_buffer, param_start, param_len); *(param_buffer+param_len) = '\0'; /* check if table name specified */ if (!strncmp(param_buffer, "-t", 3) || !strncmp(param_buffer, "--table", 8)) { exit_error(PARAMETER_PROBLEM, "Line %u seems to have a " "-t table option.\n", line); exit(1); } add_argv(param_buffer); param_start += param_len + 1; } else { /* regular character, skip */ } } DEBUGP("calling do_command(%u, argv, &%s, handle):\n", newargc, curtable); for (a = 0; a < newargc; a++) DEBUGP("argv[%u]: %s\n", a, newargv[a]); ret = do_command(newargc, newargv, &newargv[2], &handle); free_argv(); } if (!ret) { fprintf(stderr, "%s: line %u failed\n", program_name, line); exit(1); } } if (in_table) { fprintf(stderr, "%s: COMMIT expected at line %u\n", program_name, line + 1); exit(1); } return 0; }
/* delete_redirect_and_filter_rules() */ int delete_redirect_and_filter_rules(unsigned short eport, int proto) { int r = -1, r2 = -1; unsigned index = 0; unsigned i = 0; IPTC_HANDLE h; const struct ipt_entry * e; const struct ipt_entry_target * target; const struct ip_nat_multi_range * mr; const struct ipt_entry_match *match; unsigned short iport = 0; uint32_t iaddr = 0; h = iptc_init("nat"); if(!h) { syslog(LOG_ERR, "delete_redirect_and_filter_rules() : " "iptc_init() failed : %s", iptc_strerror(errno)); return -1; } /* First step : find the right nat rule */ if(!iptc_is_chain(miniupnpd_nat_chain, h)) { syslog(LOG_ERR, "chain %s not found", miniupnpd_nat_chain); } else { #ifdef IPTABLES_143 for(e = iptc_first_rule(miniupnpd_nat_chain, h); e; e = iptc_next_rule(e, h), i++) #else for(e = iptc_first_rule(miniupnpd_nat_chain, &h); e; e = iptc_next_rule(e, &h), i++) #endif { if(proto==e->ip.proto) { match = (const struct ipt_entry_match *)&e->elems; if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN)) { const struct ipt_tcp * info; info = (const struct ipt_tcp *)match->data; if(eport != info->dpts[0]) continue; } else { const struct ipt_udp * info; info = (const struct ipt_udp *)match->data; if(eport != info->dpts[0]) continue; } /* get the index, the internal address and the internal port * of the rule */ index = i; target = (void *)e + e->target_offset; mr = (const struct ip_nat_multi_range *)&target->data[0]; iaddr = mr->range[0].min_ip; iport = ntohs(mr->range[0].min.all); r = 0; break; } } } if(h) #ifdef IPTABLES_143 iptc_free(h); #else iptc_free(&h); #endif if(r == 0) { syslog(LOG_INFO, "Trying to delete nat rule at index %u", index); /* Now delete both rules */ /* first delete the nat rule */ h = iptc_init("nat"); if(h) { r = delete_rule_and_commit(index, h, miniupnpd_nat_chain, "delete_redirect_rule"); } if((r == 0) && (h = iptc_init("filter"))) { i = 0; /* we must find the right index for the filter rule */ #ifdef IPTABLES_143 for(e = iptc_first_rule(miniupnpd_forward_chain, h); e; e = iptc_next_rule(e, h), i++) #else for(e = iptc_first_rule(miniupnpd_forward_chain, &h); e; e = iptc_next_rule(e, &h), i++) #endif { if(proto==e->ip.proto) { match = (const struct ipt_entry_match *)&e->elems; /*syslog(LOG_DEBUG, "filter rule #%u: %s %s", i, match->u.user.name, inet_ntoa(e->ip.dst));*/ if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN)) { const struct ipt_tcp * info; info = (const struct ipt_tcp *)match->data; if(iport != info->dpts[0]) continue; } else { const struct ipt_udp * info; info = (const struct ipt_udp *)match->data; if(iport != info->dpts[0]) continue; } if(iaddr != e->ip.dst.s_addr) continue; index = i; syslog(LOG_INFO, "Trying to delete filter rule at index %u", index); r = delete_rule_and_commit(index, h, miniupnpd_forward_chain, "delete_filter_rule"); h = NULL; break; } } } if(h) #ifdef IPTABLES_143 iptc_free(h); #else iptc_free(&h); #endif } /*delete PEER rule*/ if((h = iptc_init("nat"))) { i = 0; /* we must find the right index for the filter rule */ #ifdef IPTABLES_143 for(e = iptc_first_rule(miniupnpd_peer_chain, h); e; e = iptc_next_rule(e, h), i++) #else for(e = iptc_first_rule(miniupnpd_peer_chain, &h); e; e = iptc_next_rule(e, &h), i++) #endif { if(proto==e->ip.proto) { target = (void *)e + e->target_offset; mr = (const struct ip_nat_multi_range *)&target->data[0]; if (eport != ntohs(mr->range[0].min.all)) { continue; } iaddr = e->ip.src.s_addr; match = (const struct ipt_entry_match *)&e->elems; if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN)) { const struct ipt_tcp * info; info = (const struct ipt_tcp *)match->data; iport = info->spts[0]; } else { const struct ipt_udp * info; info = (const struct ipt_udp *)match->data; iport = info->dpts[0]; } index = i; syslog(LOG_INFO, "Trying to delete peer rule at index %u", index); r2 = delete_rule_and_commit(index, h, miniupnpd_peer_chain, "delete_peer_rule"); h = NULL; break; } } } if(h) #ifdef IPTABLES_143 iptc_free(h); #else iptc_free(&h); #endif /*delete DSCP rule*/ if((r2==0)&&(h = iptc_init("mangle"))) { i = 0; index = -1; /* we must find the right index for the filter rule */ #ifdef IPTABLES_143 for(e = iptc_first_rule(miniupnpd_nat_chain, h); e; e = iptc_next_rule(e, h), i++) #else for(e = iptc_first_rule(miniupnpd_nat_chain, &h); e; e = iptc_next_rule(e, &h), i++) #endif { if(proto==e->ip.proto) { match = (const struct ipt_entry_match *)&e->elems; /*syslog(LOG_DEBUG, "filter rule #%u: %s %s", i, match->u.user.name, inet_ntoa(e->ip.dst));*/ if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN)) { const struct ipt_tcp * info; info = (const struct ipt_tcp *)match->data; if(iport != info->spts[0]) continue; } else { const struct ipt_udp * info; info = (const struct ipt_udp *)match->data; if(iport != info->spts[0]) continue; } if(iaddr != e->ip.src.s_addr) continue; index = i; syslog(LOG_INFO, "Trying to delete dscp rule at index %u", index); r2 = delete_rule_and_commit(index, h, miniupnpd_nat_chain, "delete_dscp_rule"); h = NULL; break; } } if (h) #ifdef IPTABLES_143 iptc_free(h); #else iptc_free(&h); #endif } del_redirect_desc(eport, proto); return r*r2; }
/* get_peer_rule_by_index() * return -1 when the rule was not found */ int get_peer_rule_by_index(int index, char * ifname, unsigned short * eport, char * iaddr, int iaddrlen, unsigned short * iport, int * proto, char * desc, int desclen, char * rhost, int rhostlen, unsigned short * rport, unsigned int * timestamp, u_int64_t * packets, u_int64_t * bytes) { int r = -1; #if USE_INDEX_FROM_DESC_LIST && 0 r = get_redirect_desc_by_index(index, eport, proto, desc, desclen, timestamp); if (r==0) { r = get_redirect_rule(ifname, *eport, *proto, iaddr, iaddrlen, iport, 0, 0, packets, bytes); } #else int i = 0; IPTC_HANDLE h; const struct ipt_entry * e; const struct ipt_entry_target * target; const struct ip_nat_multi_range * mr; const struct ipt_entry_match *match; UNUSED(ifname); h = iptc_init("nat"); if(!h) { syslog(LOG_ERR, "get_peer_rule_by_index() : " "iptc_init() failed : %s", iptc_strerror(errno)); return -1; } if(!iptc_is_chain(miniupnpd_peer_chain, h)) { syslog(LOG_ERR, "chain %s not found", miniupnpd_peer_chain); } else { #ifdef IPTABLES_143 for(e = iptc_first_rule(miniupnpd_peer_chain, h); e; e = iptc_next_rule(e, h)) #else for(e = iptc_first_rule(miniupnpd_peer_chain, &h); e; e = iptc_next_rule(e, &h)) #endif { if(i==index) { *proto = e->ip.proto; match = (const struct ipt_entry_match *)&e->elems; if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN)) { const struct ipt_tcp * info; info = (const struct ipt_tcp *)match->data; if (rport) *rport = info->dpts[0]; if (iport) *iport = info->spts[0]; } else { const struct ipt_udp * info; info = (const struct ipt_udp *)match->data; if (rport) *rport = info->dpts[0]; if (iport) *iport = info->spts[0]; } target = (void *)e + e->target_offset; mr = (const struct ip_nat_multi_range *)&target->data[0]; *eport = ntohs(mr->range[0].min.all); get_redirect_desc(*eport, *proto, desc, desclen, timestamp); if(packets) *packets = e->counters.pcnt; if(bytes) *bytes = e->counters.bcnt; /* rhost */ if(rhost && rhostlen > 0) { if(e->ip.dst.s_addr) { snprintip(rhost, rhostlen, ntohl(e->ip.dst.s_addr)); } else { rhost[0] = '\0'; } } if(iaddr && iaddrlen > 0) { if(e->ip.src.s_addr) { snprintip(iaddr, iaddrlen, ntohl(e->ip.src.s_addr)); } else { rhost[0] = '\0'; } } r = 0; break; } i++; } } if(h) #ifdef IPTABLES_143 iptc_free(h); #else iptc_free(&h); #endif #endif return r; }
int get_nat_redirect_rule(const char * nat_chain_name, const char * ifname, unsigned short eport, int proto, char * iaddr, int iaddrlen, unsigned short * iport, char * desc, int desclen, char * rhost, int rhostlen, unsigned int * timestamp, u_int64_t * packets, u_int64_t * bytes) { int r = -1; IPTC_HANDLE h; const struct ipt_entry * e; const struct ipt_entry_target * target; const struct ip_nat_multi_range * mr; const struct ipt_entry_match *match; UNUSED(ifname); h = iptc_init("nat"); if(!h) { syslog(LOG_ERR, "get_redirect_rule() : " "iptc_init() failed : %s", iptc_strerror(errno)); return -1; } if(!iptc_is_chain(nat_chain_name, h)) { syslog(LOG_ERR, "chain %s not found", nat_chain_name); } else { #ifdef IPTABLES_143 for(e = iptc_first_rule(nat_chain_name, h); e; e = iptc_next_rule(e, h)) #else for(e = iptc_first_rule(nat_chain_name, &h); e; e = iptc_next_rule(e, &h)) #endif { if(proto==e->ip.proto) { match = (const struct ipt_entry_match *)&e->elems; if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN)) { const struct ipt_tcp * info; info = (const struct ipt_tcp *)match->data; if(eport != info->dpts[0]) continue; } else { const struct ipt_udp * info; info = (const struct ipt_udp *)match->data; if(eport != info->dpts[0]) continue; } target = (void *)e + e->target_offset; /* target = ipt_get_target(e); */ mr = (const struct ip_nat_multi_range *)&target->data[0]; snprintip(iaddr, iaddrlen, ntohl(mr->range[0].min_ip)); *iport = ntohs(mr->range[0].min.all); get_redirect_desc(eport, proto, desc, desclen, timestamp); if(packets) *packets = e->counters.pcnt; if(bytes) *bytes = e->counters.bcnt; /* rhost */ if(e->ip.src.s_addr && rhost) { snprintip(rhost, rhostlen, ntohl(e->ip.src.s_addr)); } r = 0; break; } } } if(h) #ifdef IPTABLES_143 iptc_free(h); #else iptc_free(&h); #endif return r; }
/* return an (malloc'ed) array of "external" port for which there is * a port mapping. number is the size of the array */ unsigned short * get_portmappings_in_range(unsigned short startport, unsigned short endport, int proto, unsigned int * number) { unsigned short * array; unsigned int capacity; unsigned short eport; IPTC_HANDLE h; const struct ipt_entry * e; const struct ipt_entry_match *match; *number = 0; capacity = 128; array = calloc(capacity, sizeof(unsigned short)); if(!array) { syslog(LOG_ERR, "get_portmappings_in_range() : calloc error"); return NULL; } h = iptc_init("nat"); if(!h) { syslog(LOG_ERR, "get_redirect_rule_by_index() : " "iptc_init() failed : %s", iptc_strerror(errno)); free(array); return NULL; } if(!iptc_is_chain(miniupnpd_nat_chain, h)) { syslog(LOG_ERR, "chain %s not found", miniupnpd_nat_chain); free(array); array = NULL; } else { #ifdef IPTABLES_143 for(e = iptc_first_rule(miniupnpd_nat_chain, h); e; e = iptc_next_rule(e, h)) #else for(e = iptc_first_rule(miniupnpd_nat_chain, &h); e; e = iptc_next_rule(e, &h)) #endif { if(proto == e->ip.proto) { match = (const struct ipt_entry_match *)&e->elems; if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN)) { const struct ipt_tcp * info; info = (const struct ipt_tcp *)match->data; eport = info->dpts[0]; } else { const struct ipt_udp * info; info = (const struct ipt_udp *)match->data; eport = info->dpts[0]; } if(startport <= eport && eport <= endport) { if(*number >= capacity) { unsigned short * tmp; /* need to increase the capacity of the array */ tmp = realloc(array, sizeof(unsigned short)*capacity); if(!tmp) { syslog(LOG_ERR, "get_portmappings_in_range() : realloc(%u) error", (unsigned)sizeof(unsigned short)*capacity); *number = 0; free(array); array = NULL; break; } array = tmp; } array[*number] = eport; (*number)++; } } } } if(h) #ifdef IPTABLES_143 iptc_free(h); #else iptc_free(&h); #endif return array; }
/* iptc_init_verify_and_append() * return 0 on success, -1 on failure */ static int iptc_init_verify_and_append(const char * table, const char * miniupnpd_chain, struct ipt_entry * e, const char * logcaller) { IPTC_HANDLE h; h = iptc_init(table); if(!h) { syslog(LOG_ERR, "%s : iptc_init() error : %s\n", logcaller, iptc_strerror(errno)); return -1; } if(!iptc_is_chain(miniupnpd_chain, h)) { syslog(LOG_ERR, "%s : chain %s not found", logcaller, miniupnpd_chain); if(h) #ifdef IPTABLES_143 iptc_free(h); #else iptc_free(&h); #endif return -1; } /* iptc_insert_entry(miniupnpd_chain, e, n, h/&h) could also be used */ #ifdef IPTABLES_143 if(!iptc_append_entry(miniupnpd_chain, e, h)) #else if(!iptc_append_entry(miniupnpd_chain, e, &h)) #endif { syslog(LOG_ERR, "%s : iptc_append_entry() error : %s\n", logcaller, iptc_strerror(errno)); if(h) #ifdef IPTABLES_143 iptc_free(h); #else iptc_free(&h); #endif return -1; } #ifdef IPTABLES_143 if(!iptc_commit(h)) #else if(!iptc_commit(&h)) #endif { syslog(LOG_ERR, "%s : iptc_commit() error : %s\n", logcaller, iptc_strerror(errno)); if(h) #ifdef IPTABLES_143 iptc_free(h); #else iptc_free(&h); #endif return -1; } if(h) #ifdef IPTABLES_143 iptc_free(h); #else iptc_free(&h); #endif return 0; }
void iptc_add_rule(const char *table, const char *chain, const char *protocol, const char *iniface, const char *outiface, const char *src, const char *dest, const char *srcports, const char *destports, const char *target, const char *dnat_to, const int append) { iptc_handle_t handle; struct ipt_entry *chain_entry; struct ipt_entry_match *entry_match = NULL; struct ipt_entry_target *entry_target = NULL; ipt_chainlabel labelit; long match_size; int result = 0; chain_entry = calloc(1, sizeof(*chain_entry)); if (src) { chain_entry->ip.src.s_addr = inet_addr(src); chain_entry->ip.smsk.s_addr = inet_addr("255.255.255.255"); } if (dest) { chain_entry->ip.dst.s_addr = inet_addr(dest); chain_entry->ip.dmsk.s_addr = inet_addr("255.255.255.255"); } if (iniface) strncpy(chain_entry->ip.iniface, iniface, IFNAMSIZ); if (outiface) strncpy(chain_entry->ip.outiface, outiface, IFNAMSIZ); if (strcmp(protocol, "TCP") == 0) { chain_entry->ip.proto = IPPROTO_TCP; entry_match = get_tcp_match(srcports, destports, &chain_entry->nfcache); } else if (strcmp(protocol, "UDP") == 0) { chain_entry->ip.proto = IPPROTO_UDP; entry_match = get_udp_match(srcports, destports, &chain_entry->nfcache); } else { trace(1, "Unsupported protocol: %s", protocol); return; } if (strcmp(target, "") == 0 || strcmp(target, IPTC_LABEL_ACCEPT) == 0 || strcmp(target, IPTC_LABEL_DROP) == 0 || strcmp(target, IPTC_LABEL_QUEUE) == 0 || strcmp(target, IPTC_LABEL_RETURN) == 0) { size_t size; size = IPT_ALIGN(sizeof(struct ipt_entry_target)) + IPT_ALIGN(sizeof(int)); entry_target = calloc(1, size); entry_target->u.user.target_size = size; strncpy(entry_target->u.user.name, target, IPT_FUNCTION_MAXNAMELEN); } else if (strcmp(target, "DNAT") == 0) { entry_target = get_dnat_target(dnat_to, &chain_entry->nfcache); } if (entry_match) match_size = entry_match->u.match_size; else match_size = 0; chain_entry = realloc(chain_entry, sizeof(*chain_entry) + match_size + entry_target->u.target_size); memcpy(chain_entry->elems + match_size, entry_target, entry_target->u.target_size); chain_entry->target_offset = sizeof(*chain_entry) + match_size; chain_entry->next_offset = sizeof(*chain_entry) + match_size + entry_target->u.target_size; if (entry_match) memcpy(chain_entry->elems, entry_match, match_size); handle = iptc_init(table); if (!handle) { trace(1, "libiptc error: Can't initialize table %s, %s", table, iptc_strerror(errno)); return; } strncpy(labelit, chain, sizeof(ipt_chainlabel)); result = iptc_is_chain(chain, handle); if (!result) { trace(1, "libiptc error: Chain %s does not exist!", chain); return; } if (append) result = iptc_append_entry(labelit, chain_entry, &handle); else result = iptc_insert_entry(labelit, chain_entry, 0, &handle); if (!result) { trace(1, "libiptc error: Can't add, %s", iptc_strerror(errno)); return; } result = iptc_commit(&handle); if (!result) { trace(1, "libiptc error: Commit error, %s", iptc_strerror(errno)); return; } else trace(3, "added new rule to block successfully"); if (entry_match) free(entry_match); free(entry_target); free(chain_entry); }
void iptc_delete_rule(const char *table, const char *chain, const char *protocol, const char *iniface, const char *outiface, const char *src, const char *dest, const char *srcports, const char *destports, const char *target, const char *dnat_to) { iptc_handle_t handle; const struct ipt_entry *e; ipt_chainlabel labelit; int i, result; unsigned long int s_src = INADDR_NONE, s_dest = INADDR_NONE; if (src) s_src = inet_addr(src); if (dest) s_dest = inet_addr(dest); handle = iptc_init(table); if (!handle) { trace(1, "libiptc error: Can't initialize table %s, %s", table, iptc_strerror(errno)); return; } strncpy(labelit, chain, sizeof(ipt_chainlabel)); result = iptc_is_chain(chain, handle); if (!result) { trace(1, "libiptc error: Chain %s does not exist!", chain); return; } /* check through rules to find match */ for (e = iptc_first_rule(chain, &handle), i=0; e; e = iptc_next_rule(e, &handle), i++) { if (s_src != INADDR_NONE && e->ip.src.s_addr != s_src) continue; if (s_dest != INADDR_NONE && e->ip.dst.s_addr != s_dest) continue; if (iniface && strcmp(e->ip.iniface, iniface) != 0) continue; if (outiface && strcmp(e->ip.outiface, outiface) != 0) continue; if (protocol && strcmp(protocol, "TCP") == 0 && e->ip.proto != IPPROTO_TCP) continue; if (protocol && strcmp(protocol, "UDP") == 0 && e->ip.proto != IPPROTO_UDP) continue; if ((srcports || destports) && IPT_MATCH_ITERATE(e, matchcmp, srcports, destports) == 0) continue; if (target && strcmp(target, iptc_get_target(e, &handle)) != 0) continue; if (dnat_to && strcmp(target, "DNAT") == 0) { struct ipt_entry_target *t; struct ip_nat_multi_range *mr; struct ip_nat_range *r, range; t = (void *) e+e->target_offset; mr = (void *) &t->data; if (mr->rangesize != 1) continue; /* we have only single dnat_to target now */ r = mr->range; parse_range(dnat_to, &range); if (r->flags == range.flags && r->min_ip == range.min_ip && r->max_ip == range.max_ip && r->min.all == range.min.all && r->max.all == range.max.all) { break; } } break; } if (!e) return; result = iptc_delete_num_entry(chain, i, &handle); if (!result) { trace(1, "libiptc error: Delete error, %s", iptc_strerror(errno)); return; } result = iptc_commit(&handle); if (!result) { trace(1, "libiptc error: Commit error, %s", iptc_strerror(errno)); return; } else trace(3, "deleted rule from block successfully"); }
int main(int argc, char *argv[]) #endif { struct iptc_handle *handle = NULL; char buffer[10240]; int c; char curtable[IPT_TABLE_MAXNAMELEN + 1]; FILE *in; int in_table = 0, testing = 0; const char *tablename = NULL; line = 0; iptables_globals.program_name = "iptables-restore"; c = xtables_init_all(&iptables_globals, NFPROTO_IPV4); if (c < 0) { fprintf(stderr, "%s/%s Failed to initialize xtables\n", iptables_globals.program_name, iptables_globals.program_version); exit(1); } #if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS) init_extensions(); #endif while ((c = getopt_long(argc, argv, "bcvthnM:T:", options, NULL)) != -1) { switch (c) { case 'b': binary = 1; break; case 'c': counters = 1; break; case 'v': verbose = 1; break; case 't': testing = 1; break; case 'h': print_usage("iptables-restore", IPTABLES_VERSION); break; case 'n': noflush = 1; break; case 'M': xtables_modprobe_program = optarg; break; case 'T': tablename = optarg; break; } } if (optind == argc - 1) { in = fopen(argv[optind], "r"); if (!in) { fprintf(stderr, "Can't open %s: %s\n", argv[optind], strerror(errno)); exit(1); } } else if (optind < argc) { fprintf(stderr, "Unknown arguments found on commandline\n"); exit(1); } else in = stdin; /* Grab standard input. */ while (fgets(buffer, sizeof(buffer), in)) { int ret = 0; line++; if (buffer[0] == '\n') continue; else if (buffer[0] == '#') { if (verbose) fputs(buffer, stdout); continue; } else if ((strcmp(buffer, "COMMIT\n") == 0) && (in_table)) { if (!testing) { DEBUGP("Calling commit\n"); ret = iptc_commit(handle); iptc_free(handle); handle = NULL; } else { DEBUGP("Not calling commit, testing\n"); ret = 1; } in_table = 0; } else if ((buffer[0] == '*') && (!in_table)) { /* New table */ char *table; table = strtok(buffer+1, " \t\n"); DEBUGP("line %u, table '%s'\n", line, table); if (!table) { xtables_error(PARAMETER_PROBLEM, "%s: line %u table name invalid\n", prog_name, line); exit(1); } strncpy(curtable, table, IPT_TABLE_MAXNAMELEN); curtable[IPT_TABLE_MAXNAMELEN] = '\0'; if (tablename && (strcmp(tablename, table) != 0)) continue; if (handle) iptc_free(handle); handle = create_handle(table); if (noflush == 0) { DEBUGP("Cleaning all chains of table '%s'\n", table); for_each_chain(flush_entries, verbose, 1, handle); DEBUGP("Deleting all user-defined chains " "of table '%s'\n", table); for_each_chain(delete_chain, verbose, 0, handle); } ret = 1; in_table = 1; } else if ((buffer[0] == ':') && (in_table)) { /* New chain. */ char *policy, *chain; chain = strtok(buffer+1, " \t\n"); DEBUGP("line %u, chain '%s'\n", line, chain); if (!chain) { xtables_error(PARAMETER_PROBLEM, "%s: line %u chain name invalid\n", prog_name, line); exit(1); } if (strlen(chain) >= XT_EXTENSION_MAXNAMELEN) xtables_error(PARAMETER_PROBLEM, "Invalid chain name `%s' " "(%u chars max)", chain, XT_EXTENSION_MAXNAMELEN - 1); if (iptc_builtin(chain, handle) <= 0) { if (noflush && iptc_is_chain(chain, handle)) { DEBUGP("Flushing existing user defined chain '%s'\n", chain); if (!iptc_flush_entries(chain, handle)) xtables_error(PARAMETER_PROBLEM, "error flushing chain " "'%s':%s\n", chain, strerror(errno)); } else { DEBUGP("Creating new chain '%s'\n", chain); if (!iptc_create_chain(chain, handle)) xtables_error(PARAMETER_PROBLEM, "error creating chain " "'%s':%s\n", chain, strerror(errno)); } } policy = strtok(NULL, " \t\n"); DEBUGP("line %u, policy '%s'\n", line, policy); if (!policy) { xtables_error(PARAMETER_PROBLEM, "%s: line %u policy invalid\n", prog_name, line); exit(1); } if (strcmp(policy, "-") != 0) { struct ipt_counters count; if (counters) { char *ctrs; ctrs = strtok(NULL, " \t\n"); if (!ctrs || !parse_counters(ctrs, &count)) xtables_error(PARAMETER_PROBLEM, "invalid policy counters " "for chain '%s'\n", chain); } else { memset(&count, 0, sizeof(struct ipt_counters)); } DEBUGP("Setting policy of chain %s to %s\n", chain, policy); if (!iptc_set_policy(chain, policy, &count, handle)) xtables_error(OTHER_PROBLEM, "Can't set policy `%s'" " on `%s' line %u: %s\n", chain, policy, line, iptc_strerror(errno)); } ret = 1; } else if (in_table) { int a; char *ptr = buffer; char *pcnt = NULL; char *bcnt = NULL; char *parsestart; /* the parser */ char *curchar; int quote_open, escaped; size_t param_len; /* reset the newargv */ newargc = 0; if (buffer[0] == '[') { /* we have counters in our input */ ptr = strchr(buffer, ']'); if (!ptr) xtables_error(PARAMETER_PROBLEM, "Bad line %u: need ]\n", line); pcnt = strtok(buffer+1, ":"); if (!pcnt) xtables_error(PARAMETER_PROBLEM, "Bad line %u: need :\n", line); bcnt = strtok(NULL, "]"); if (!bcnt) xtables_error(PARAMETER_PROBLEM, "Bad line %u: need ]\n", line); /* start command parsing after counter */ parsestart = ptr + 1; } else { /* start command parsing at start of line */ parsestart = buffer; } add_argv(argv[0]); add_argv("-t"); add_argv((char *) &curtable); if (counters && pcnt && bcnt) { add_argv("--set-counters"); add_argv((char *) pcnt); add_argv((char *) bcnt); } /* After fighting with strtok enough, here's now * a 'real' parser. According to Rusty I'm now no * longer a real hacker, but I can live with that */ quote_open = 0; escaped = 0; param_len = 0; for (curchar = parsestart; *curchar; curchar++) { char param_buffer[1024]; if (quote_open) { if (escaped) { param_buffer[param_len++] = *curchar; escaped = 0; continue; } else if (*curchar == '\\') { escaped = 1; continue; } else if (*curchar == '"') { quote_open = 0; *curchar = ' '; } else { param_buffer[param_len++] = *curchar; continue; } } else { if (*curchar == '"') { quote_open = 1; continue; } } if (*curchar == ' ' || *curchar == '\t' || * curchar == '\n') { if (!param_len) { /* two spaces? */ continue; } param_buffer[param_len] = '\0'; /* check if table name specified */ if (!strncmp(param_buffer, "-t", 2) || !strncmp(param_buffer, "--table", 8)) { xtables_error(PARAMETER_PROBLEM, "Line %u seems to have a " "-t table option.\n", line); exit(1); } add_argv(param_buffer); param_len = 0; } else { /* regular character, copy to buffer */ param_buffer[param_len++] = *curchar; if (param_len >= sizeof(param_buffer)) xtables_error(PARAMETER_PROBLEM, "Parameter too long!"); } } DEBUGP("calling do_command(%u, argv, &%s, handle):\n", newargc, curtable); for (a = 0; a < newargc; a++) DEBUGP("argv[%u]: %s\n", a, newargv[a]); ret = do_command(newargc, newargv, &newargv[2], &handle); free_argv(); fflush(stdout); } if (tablename && (strcmp(tablename, curtable) != 0)) continue; if (!ret) { fprintf(stderr, "%s: line %u failed\n", prog_name, line); exit(1); } } if (in_table) { fprintf(stderr, "%s: COMMIT expected at line %u\n", prog_name, line + 1); exit(1); } if (in != NULL) fclose(in); return 0; }
int ip4tables_is_chain(struct iptc_handle* handle, const char* chain_name) { return iptc_is_chain(chain_name, handle); }