void genIPTablesRules(const std::string &filter, QueryData &results) { Row r; r["filter_name"] = filter; // Initialize the access to iptc auto handle = (struct iptc_handle *)iptc_init(filter.c_str()); if (handle == nullptr) { return; } // Iterate through chains for (auto chain = iptc_first_chain(handle); chain != nullptr; chain = iptc_next_chain(handle)) { r["chain"] = TEXT(chain); struct ipt_counters counters; auto policy = iptc_get_policy(chain, &counters, handle); if (policy != nullptr) { r["policy"] = TEXT(policy); r["packets"] = INTEGER(counters.pcnt); r["bytes"] = INTEGER(counters.bcnt); } else { r["policy"] = ""; r["packets"] = "0"; r["bytes"] = "0"; } const struct ipt_entry *prev_rule = nullptr; // Iterating through all the rules per chain for (const struct ipt_entry *chain_rule = iptc_first_rule(chain, handle); chain_rule; chain_rule = iptc_next_rule(prev_rule, handle)) { prev_rule = chain_rule; auto target = iptc_get_target(chain_rule, handle); if (target != nullptr) { r["target"] = TEXT(target); } else { r["target"] = ""; } if (chain_rule->target_offset) { r["match"] = "yes"; // fill protocol port details parseEntryMatch(chain_rule, r); } else { r["match"] = "no"; r["src_port"] = ""; r["dst_port"] = ""; } const struct ipt_ip *ip = &chain_rule->ip; parseIpEntry(ip, r); results.push_back(r); } // Rule iteration results.push_back(r); } // Chain iteration iptc_free(handle); }
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; }
/* 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; }
/* 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; }
/* 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) { /* need to increase the capacity of the array */ array = realloc(array, sizeof(unsigned short)*capacity); if(!array) { syslog(LOG_ERR, "get_portmappings_in_range() : realloc(%u) error", (unsigned)sizeof(unsigned short)*capacity); *number = 0; break; } array[*number] = eport; (*number)++; } } } } } if(h) #ifdef IPTABLES_143 iptc_free(h); #else iptc_free(&h); #endif return array; }
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; }
static int do_output(const char *tablename) { struct iptc_handle *h; const char *chain = NULL; if (!tablename) return for_each_table(&do_output); h = iptc_init(tablename); if (h == NULL) { xtables_load_ko(xtables_modprobe_program, false); h = iptc_init(tablename); } if (!h) xtables_error(OTHER_PROBLEM, "Cannot initialize: %s\n", iptc_strerror(errno)); if (!show_binary) { time_t now = time(NULL); printf("# Generated by iptables-save v%s on %s", IPTABLES_VERSION, ctime(&now)); printf("*%s\n", tablename); for (chain = iptc_first_chain(h); chain; chain = iptc_next_chain(h)) { printf(":%s ", chain); if (iptc_builtin(chain, h)) { struct ipt_counters count; printf("%s ", iptc_get_policy(chain, &count, h)); printf("[%llu:%llu]\n", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt); } else { printf("- [0:0]\n"); } } for (chain = iptc_first_chain(h); chain; chain = iptc_next_chain(h)) { const struct ipt_entry *e; e = iptc_first_rule(chain, h); while(e) { print_rule4(e, h, chain, show_counters); e = iptc_next_rule(e, h); } } now = time(NULL); printf("COMMIT\n"); printf("# Completed on %s", ctime(&now)); } else { xtables_error(OTHER_PROBLEM, "Binary NYI\n"); } iptc_free(h); return 1; }
/* 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 fwd_ipt_addif(struct fwd_handle *h, const char *net) { struct fwd_data *e; struct fwd_zone *z; struct fwd_rule *c; struct fwd_redirect *r; struct fwd_forwarding *f; struct fwd_cidr *a, *a2; struct fwd_network *n, *n2; struct fwd_proto p; struct fwd_xt_rule *x; struct xtables_match *m; struct xtables_target *t; struct iptc_handle *h_filter, *h_nat; if( !(h_filter = iptc_init("filter")) || !(h_nat = iptc_init("nat")) ) fwd_fatal("Unable to obtain libiptc handle"); if( !(z = fwd_lookup_zone(h, net)) ) return; if( !(n = fwd_lookup_network(z, net)) ) return; if( !(a = n->addr) || fwd_empty_cidr(a) ) return; fwd_log_info("Adding network %s (interface %s)", n->name, n->ifname); /* Build masquerading rule */ if( z->masq ) { if( (x = fwd_xt_init_rule(h_nat)) != NULL ) { fwd_xt_parse_out(x, n, 0); /* -o ... */ fwd_xt_get_target(x, "MASQUERADE"); /* -j MASQUERADE */ fwd_r_add_comment(x, "masq", z, n); /* -m comment ... */ fwd_xt_append_rule(x, "zonemasq"); /* -A zonemasq */ } } /* Build MSS fix rule */ if( z->mtu_fix ) { if( (x = fwd_xt_init_rule(h_filter)) != NULL ) { p.type = FWD_PR_TCP; fwd_xt_parse_out(x, n, 0); /* -o ... */ fwd_xt_parse_proto(x, &p, 0); /* -p tcp */ /* -m tcp --tcp-flags SYN,RST SYN */ if( (m = fwd_xt_get_match(x, "tcp")) != NULL ) fwd_xt_parse_match(x, m, "--tcp-flags", "SYN,RST", "SYN"); /* -j TCPMSS --clamp-mss-to-pmtu */ if( (t = fwd_xt_get_target(x, "TCPMSS")) != NULL ) fwd_xt_parse_target(x, t, "--clamp-mss-to-pmtu"); /* -m comment ... */ fwd_r_add_comment(x, "mssfix", z, n); /* -A mssfix */ fwd_xt_append_rule(x, "mssfix"); } } /* Build intra-zone forwarding rules */ for( n2 = z->networks; n2; n2 = n2->next ) { if( (a2 = n2->addr) != NULL ) { if( (x = fwd_xt_init_rule(h_filter)) != NULL ) { fwd_xt_parse_in(x, n, 0); /* -i ... */ fwd_xt_parse_out(x, n2, 0); /* -o ... */ fwd_r_add_policytarget(x, z->forward); /* -j handle_... */ fwd_r_add_comment(x, "zone", z, n); /* -m comment ... */ fwd_xt_append_rule(x, "zones"); /* -A zones */ } } } /* Build inter-zone forwarding rules */ for( e = z->forwardings; e && (f = &e->section.forwarding); e = e->next ) { for( n2 = f->dest->networks; n2; n2 = n2->next ) { /* Build forwarding rule */ if( (x = fwd_xt_init_rule(h_filter)) != NULL ) { fwd_xt_parse_in(x, n, 0); /* -i ... */ fwd_xt_parse_out(x, n2, 0); /* -o ... */ fwd_r_add_policytarget(x, FWD_P_ACCEPT); /* -j handle_... */ fwd_r_add_comment(x, "forward", z, n); /* -m comment ... */ fwd_xt_append_rule(x, "forwardings"); /* -A forwardings */ } } } /* Build DNAT rules */ for( e = z->redirects; e && (r = &e->section.redirect); e = e->next ) { /* DNAT */ if( (x = fwd_xt_init_rule(h_nat)) != NULL ) { fwd_xt_parse_in(x, n, 0); /* -i ... */ fwd_xt_parse_src(x, r->src_ip, 0); /* -s ... */ fwd_xt_parse_dest(x, a, 0); /* -d ... */ fwd_xt_parse_proto(x, r->proto, 0); /* -p ... */ fwd_r_add_sport(x, r->src_port); /* --sport ... */ fwd_r_add_dport(x, r->src_dport); /* --dport ... */ fwd_r_add_srcmac(x, r->src_mac); /* -m mac --mac-source ... */ fwd_r_add_dnattarget(x, r->dest_ip, r->dest_port); /* -j DNAT ... */ fwd_r_add_comment(x, "redir", z, n); /* -m comment ... */ fwd_xt_append_rule(x, "redirects"); /* -A redirects */ } /* Forward */ if( (x = fwd_xt_init_rule(h_filter)) != NULL ) { fwd_xt_parse_in(x, n, 0); /* -i ... */ fwd_xt_parse_src(x, r->src_ip, 0); /* -s ... */ fwd_xt_parse_dest(x, r->dest_ip, 0); /* -d ... */ fwd_xt_parse_proto(x, r->proto, 0); /* -p ... */ fwd_r_add_srcmac(x, r->src_mac); /* -m mac --mac-source ... */ fwd_r_add_sport(x, r->src_port); /* --sport ... */ fwd_r_add_dport(x, r->dest_port); /* --dport ... */ fwd_r_add_policytarget(x, FWD_P_ACCEPT); /* -j handle_accept */ fwd_r_add_comment(x, "redir", z, n); /* -m comment ... */ fwd_xt_append_rule(x, "redirects"); /* -A redirects */ } /* Add loopback rule if neither src_ip nor src_mac are defined */ if( !r->src_ip && !r->src_mac ) { if( (x = fwd_xt_init_rule(h_nat)) != NULL ) { fwd_xt_parse_in(x, n, 1); /* -i ! ... */ fwd_xt_parse_dest(x, r->dest_ip, 0); /* -d ... */ fwd_xt_parse_proto(x, r->proto, 0); /* -p ... */ fwd_r_add_sport(x, r->src_port); /* --sport ... */ fwd_r_add_dport(x, r->src_dport); /* --dport ... */ fwd_xt_get_target(x, "MASQUERADE"); /* -j MASQUERADE */ fwd_r_add_comment(x, "redir", z, n); /* -m comment ... */ fwd_xt_append_rule(x, "loopback"); /* -A loopback */ } } } /* Build rules */ for( e = z->rules; e && (c = &e->section.rule); e = e->next ) { /* Has destination, add forward rule for each network in target zone */ if( c->dest ) { for( n2 = c->dest->networks; n2; n2 = n2->next ) { if( (x = fwd_xt_init_rule(h_filter)) != NULL ) { fwd_xt_parse_in(x, n, 0); /* -i ... */ fwd_xt_parse_out(x, n2, 0); /* -o ... */ fwd_xt_parse_src(x, c->src_ip, 0); /* -s ... */ fwd_xt_parse_dest(x, c->dest_ip, 0); /* -d ... */ fwd_xt_parse_proto(x, c->proto, 0); /* -p ... */ fwd_r_add_icmptype(x, c->icmp_type); /* --icmp-type ... */ fwd_r_add_srcmac(x, c->src_mac); /* --mac-source ... */ fwd_r_add_sport(x, c->src_port); /* --sport ... */ fwd_r_add_dport(x, c->dest_port); /* --dport ... */ fwd_r_add_policytarget(x, c->target); /* -j handle_... */ fwd_r_add_comment(x, "rule", z, n); /* -m comment ... */ fwd_xt_append_rule(x, "rules"); /* -A rules */ } } } /* No destination specified, treat it as input rule */ else { if( (x = fwd_xt_init_rule(h_filter)) != NULL ) { fwd_xt_parse_in(x, n, 0); /* -i ... */ fwd_xt_parse_src(x, c->src_ip, 0); /* -s ... */ fwd_xt_parse_dest(x, c->dest_ip, 0); /* -d ... */ fwd_xt_parse_proto(x, c->proto, 0); /* -p ... */ fwd_r_add_icmptype(x, c->icmp_type); /* --icmp-type ... */ fwd_r_add_srcmac(x, c->src_mac); /* --mac-source ... */ fwd_r_add_sport(x, c->src_port); /* --sport ... */ fwd_r_add_dport(x, c->dest_port); /* --dport ... */ fwd_r_add_policytarget(x, c->target); /* -j handle_... */ fwd_r_add_comment(x, "rule", z, n); /* -m comment ... */ fwd_xt_append_rule(x, "rules"); /* -A rules */ } } } if( !iptc_commit(h_nat) ) fwd_fatal("Cannot commit nat table: %s", iptc_strerror(errno)); if( !iptc_commit(h_filter) ) fwd_fatal("Cannot commit filter table: %s", iptc_strerror(errno)); iptc_free(h_nat); iptc_free(h_filter); }
static void fwd_ipt_defaults_create(struct fwd_data *d) { struct fwd_defaults *def = &d->section.defaults; struct iptc_handle *h_filter, *h_nat; if( !(h_filter = iptc_init("filter")) || !(h_nat = iptc_init("nat")) ) fwd_fatal("Unable to obtain libiptc handle"); /* policies */ fwd_r_set_policy(h_filter, "INPUT", def->input == FWD_P_ACCEPT ? "ACCEPT" : "DROP"); fwd_r_set_policy(h_filter, "OUTPUT", def->output == FWD_P_ACCEPT ? "ACCEPT" : "DROP"); fwd_r_set_policy(h_filter, "FORWARD", def->forward == FWD_P_ACCEPT ? "ACCEPT" : "DROP"); /* invalid state drop */ if( def->drop_invalid ) { fwd_r_drop_invalid(h_filter, "INPUT"); fwd_r_drop_invalid(h_filter, "OUTPUT"); fwd_r_drop_invalid(h_filter, "FORWARD"); } /* default accept related */ fwd_r_accept_related(h_filter, "INPUT"); fwd_r_accept_related(h_filter, "OUTPUT"); fwd_r_accept_related(h_filter, "FORWARD"); /* default accept on lo */ fwd_r_accept_lo(h_filter); /* syn flood protection */ if( def->syn_flood ) { fwd_r_add_synflood(h_filter, def); } /* rule container chains */ fwd_r_new_chain(h_filter, "mssfix"); fwd_r_new_chain(h_filter, "zones"); fwd_r_new_chain(h_filter, "rules"); fwd_r_new_chain(h_filter, "redirects"); fwd_r_new_chain(h_filter, "forwardings"); fwd_r_jump_chain(h_filter, "INPUT", "rules"); fwd_r_jump_chain(h_filter, "FORWARD", "mssfix"); fwd_r_jump_chain(h_filter, "FORWARD", "zones"); fwd_r_jump_chain(h_filter, "FORWARD", "rules"); fwd_r_jump_chain(h_filter, "FORWARD", "redirects"); fwd_r_jump_chain(h_filter, "FORWARD", "forwardings"); fwd_r_new_chain(h_nat, "zonemasq"); fwd_r_new_chain(h_nat, "redirects"); fwd_r_new_chain(h_nat, "loopback"); fwd_r_jump_chain(h_nat, "POSTROUTING", "zonemasq"); fwd_r_jump_chain(h_nat, "PREROUTING", "redirects"); fwd_r_jump_chain(h_nat, "POSTROUTING", "loopback"); /* standard drop, accept, reject chain */ fwd_r_handle_drop(h_filter); fwd_r_handle_accept(h_filter); fwd_r_handle_reject(h_filter); if( !iptc_commit(h_nat) ) fwd_fatal("Cannot commit nat table: %s", iptc_strerror(errno)); if( !iptc_commit(h_filter) ) fwd_fatal("Cannot commit filter table: %s", iptc_strerror(errno)); iptc_free(h_nat); iptc_free(h_filter); }
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_extensions4(); #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], "re"); 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_chain4(flush_entries4, verbose, 1, handle); DEBUGP("Deleting all user-defined chains " "of table '%s'\n", table); for_each_chain4(delete_chain4, 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", policy, chain, 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(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_command4(%u, argv, &%s, handle):\n", newargc, curtable); for (a = 0; a < newargc; a++) DEBUGP("argv[%u]: %s\n", a, newargv[a]); ret = do_command4(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 main ( int argc, char * argv[] ) { int have_committed = 1; // prevent double commits, 'clean' state to begin with int c; program_name = argv[0]; program_name = "ipbatch CLI"; // this is really important for locating shared libs program_version = IPTABLES_VERSION; c = xtables_init_all(&iptables_globals, NFPROTO_IPV4); if (c < 0) { fprintf(stderr, "%s/%s Failed to initialize xtables\n", program_name, program_version); exit(1); } openlog( "SmoothIPSubsys", LOG_NDELAY | LOG_CONS, LOG_DAEMON ); /* lib_dir = getenv("IPTABLES_LIB_DIR");*/ /* if (!lib_dir)*/ /* lib_dir = IPT_LIB_DIR;*/ /* read lines from STDIN */ char buffer[ BUFFER_SIZE ]; int error = 0; // syslog( LOG_ERR, "Checking input" ); // there are two special commands end is the same as eof and commit // does an early commit rather than the changes only being committed at the end while ( fgets( buffer, BUFFER_SIZE - 2, stdin ) != NULL ){ /* terminate the line at the carriage return */ if ( strlen( buffer ) > BUFFER_SIZE ){ // silently ignore long lines continue; } buffer[ strlen( buffer ) - 1 ] = '\0'; //syslog( LOG_ERR, "Received command %s", buffer ); if ( strcmp( buffer, "end" ) == 0 ){ break; } if ( strcmp( buffer, "commit" ) == 0 ){ /* commit changes */ error = iptc_commit(handle); iptc_free(handle); handle = NULL; have_committed = 1; } else { /* excute the command */ if(!have_committed) { if(table_changed(buffer)) { //syslog( LOG_ERR, "Table change for %s", buffer ); error = iptc_commit(handle); iptc_free(handle); handle = NULL; have_committed = 1; } } if(*buffer) error = execute( buffer ); have_committed = 0; } if ( !error ){ /* if an error has occured then we're */ /* in trouble and might as well just */ /* leave */ syslog( LOG_ERR, "error: %s", iptc_strerror(errno)); return !error; } } //syslog( LOG_ERR, "Finished" ); /* commit the changes, that is flush */ /* the iptables buffer */ if(!have_committed) { error = iptc_commit(handle); iptc_free(handle); handle = NULL; syslog( LOG_ERR, "Unable to commit IPTables rules \"%s\"", iptc_strerror( errno ) ); } return !error; }
/* * Get a list of the current firewall entries * @param fw_list list of firewall entries * @return 0 on success and errno on failure */ int netconf_get_fw(netconf_fw_t *fw_list) { const char **table; const char *chain; const struct ipt_entry *entry; struct iptc_handle *handle = NULL; /* Initialize list */ netconf_list_init(fw_list); /* Search all default tables */ for (table = &netconf_table_names[0]; *table; table++) { if (strcmp(*table, "filter") && strcmp(*table, "nat")) continue; if (!(handle = iptc_init(*table))) { fprintf(stderr, "%s\n", iptc_strerror(errno)); goto err; } /* Search all default chains */ for (chain = iptc_first_chain(handle); chain; chain = iptc_next_chain(handle)) { if (strcmp(chain, "INPUT") && strcmp(chain, "FORWARD") && strcmp(chain, "OUTPUT") && strcmp(chain, "PREROUTING") && strcmp(chain, "POSTROUTING") && strcmp(chain, "VSERVER") && strcmp(chain, "UPNP")) continue; /* Search all entries */ for (entry = iptc_first_rule(chain, handle); entry; entry = iptc_next_rule(entry, handle)) { int num = target_num(entry, handle); netconf_fw_t *fw = NULL; netconf_filter_t *filter = NULL; netconf_nat_t *nat = NULL; netconf_app_t *app = NULL; const struct ipt_entry_match *match; const struct ipt_entry_target *target; struct ipt_mac_info *mac = NULL; struct ipt_state_info *state = NULL; struct ipt_conntrack_info *conntrack = NULL; struct ipt_time_info *time = NULL; /* Only know about TCP/UDP */ if (!netconf_valid_ipproto(entry->ip.proto)) continue; /* Only know about target types in the specified tables */ if (!netconf_valid_target(num) || (netconf_table_name[num] && strncmp(netconf_table_name[num], *table, IPT_FUNCTION_MAXNAMELEN) != 0)) continue; /* Only know about specified target types */ if (netconf_valid_filter(num)) fw = (netconf_fw_t *) (filter = calloc(1, sizeof(netconf_filter_t))); else if (netconf_valid_nat(num)) fw = (netconf_fw_t *) (nat = calloc(1, sizeof(netconf_nat_t))); else if (num == NETCONF_APP) fw = (netconf_fw_t *) (app = calloc(1, sizeof(netconf_app_t))); else continue; if (!fw) { perror("calloc"); goto err; } netconf_list_add(fw, fw_list); /* Get IP addresses */ fw->match.src.ipaddr.s_addr = entry->ip.src.s_addr; fw->match.src.netmask.s_addr = entry->ip.smsk.s_addr; fw->match.dst.ipaddr.s_addr = entry->ip.dst.s_addr; fw->match.dst.netmask.s_addr = entry->ip.dmsk.s_addr; fw->match.flags |= (entry->ip.invflags & IPT_INV_SRCIP) ? NETCONF_INV_SRCIP : 0; fw->match.flags |= (entry->ip.invflags & IPT_INV_DSTIP) ? NETCONF_INV_DSTIP : 0; /* Get interface names */ strncpy(fw->match.in.name, entry->ip.iniface, IFNAMSIZ); strncpy(fw->match.out.name, entry->ip.outiface, IFNAMSIZ); fw->match.flags |= (entry->ip.invflags & IPT_INV_VIA_IN) ? NETCONF_INV_IN : 0; fw->match.flags |= (entry->ip.invflags & IPT_INV_VIA_OUT) ? NETCONF_INV_OUT : 0; fw->match.ipproto = entry->ip.proto; /* Get TCP port(s) */ if (entry->ip.proto == IPPROTO_TCP) { struct ipt_tcp *tcp = NULL; for_each_ipt_match(match, entry) { if (strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN) != 0) continue; tcp = (struct ipt_tcp *) &match->data[0]; break; } if (tcp) { /* Match ports stored in host order for some stupid reason */ fw->match.src.ports[0] = htons(tcp->spts[0]); fw->match.src.ports[1] = htons(tcp->spts[1]); fw->match.dst.ports[0] = htons(tcp->dpts[0]); fw->match.dst.ports[1] = htons(tcp->dpts[1]); fw->match.flags |= (tcp->invflags & IPT_TCP_INV_SRCPT) ? NETCONF_INV_SRCPT : 0; fw->match.flags |= (tcp->invflags & IPT_TCP_INV_DSTPT) ? NETCONF_INV_DSTPT : 0; } } /* Get UDP port(s) */ else if (entry->ip.proto == IPPROTO_UDP) { struct ipt_udp *udp = NULL; for_each_ipt_match(match, entry) { if (strncmp(match->u.user.name, "udp", IPT_FUNCTION_MAXNAMELEN) != 0) continue; udp = (struct ipt_udp *) &match->data[0]; break; } if (udp) { /* Match ports stored in host order for some stupid reason */ fw->match.src.ports[0] = htons(udp->spts[0]); fw->match.src.ports[1] = htons(udp->spts[1]); fw->match.dst.ports[0] = htons(udp->dpts[0]); fw->match.dst.ports[1] = htons(udp->dpts[1]); fw->match.flags |= (udp->invflags & IPT_UDP_INV_SRCPT) ? NETCONF_INV_SRCPT : 0; fw->match.flags |= (udp->invflags & IPT_UDP_INV_DSTPT) ? NETCONF_INV_DSTPT : 0; } } /* Get source MAC address */ for_each_ipt_match(match, entry) { if (strncmp(match->u.user.name, "mac", IPT_FUNCTION_MAXNAMELEN) != 0) continue; mac = (struct ipt_mac_info *) &match->data[0]; break; } if (mac) { memcpy(fw->match.mac.octet, mac->srcaddr, ETHER_ADDR_LEN); fw->match.flags |= mac->invert ? NETCONF_INV_MAC : 0; } /* Get packet state */ for_each_ipt_match(match, entry) { if (strncmp(match->u.user.name, "state", IPT_FUNCTION_MAXNAMELEN) == 0) { state = (struct ipt_state_info *) &match->data[0]; break; } else if (strncmp(match->u.user.name, "conntrack", IPT_FUNCTION_MAXNAMELEN) == 0) { conntrack = (struct ipt_conntrack_info *) &match->data[0]; break; } } if (conntrack && (conntrack->match_flags & XT_CONNTRACK_STATE)) { fw->match.state |= (conntrack->state_mask & XT_CONNTRACK_STATE_INVALID) ? NETCONF_INVALID : 0; fw->match.state |= (conntrack->state_mask & XT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED)) ? NETCONF_ESTABLISHED : 0; fw->match.state |= (conntrack->state_mask & XT_CONNTRACK_STATE_BIT(IP_CT_RELATED)) ? NETCONF_RELATED : 0; fw->match.state |= (conntrack->state_mask & XT_CONNTRACK_STATE_BIT(IP_CT_NEW)) ? NETCONF_NEW : 0; fw->match.state |= (conntrack->state_mask & XT_CONNTRACK_STATE_UNTRACKED) ? NETCONF_UNTRACKED : 0; fw->match.state |= (conntrack->state_mask & XT_CONNTRACK_STATE_SNAT) ? NETCONF_STATE_SNAT : 0; fw->match.state |= (conntrack->state_mask & XT_CONNTRACK_STATE_DNAT) ? NETCONF_STATE_DNAT : 0; } else if (state) { fw->match.state |= (state->statemask & IPT_STATE_INVALID) ? NETCONF_INVALID : 0; fw->match.state |= (state->statemask & IPT_STATE_BIT(IP_CT_ESTABLISHED)) ? NETCONF_ESTABLISHED : 0; fw->match.state |= (state->statemask & IPT_STATE_BIT(IP_CT_RELATED)) ? NETCONF_RELATED : 0; fw->match.state |= (state->statemask & IPT_STATE_BIT(IP_CT_NEW)) ? NETCONF_NEW : 0; } /* Get local time */ for_each_ipt_match(match, entry) { if (strncmp(match->u.user.name, "time", IPT_FUNCTION_MAXNAMELEN) != 0) continue; /* We added 8 bytes of day range at the end */ if (match->u.match_size < (IPT_ALIGN(sizeof(struct ipt_entry_match)) + IPT_ALIGN(sizeof(struct ipt_time_info) + 8))) continue; time = (struct ipt_time_info *) &match->data[0]; break; } if (time) { fw->match.days = time->weekdays_match; fw->match.secs[0] = time->daytime_start; fw->match.secs[1] = time->daytime_stop; } /* Set target type */ fw->target = num; target = (struct ipt_entry_target *) ((int) entry + entry->target_offset); /* Get filter target information */ if (filter) { if (!netconf_valid_dir(filter->dir = filter_dir(chain))) { fprintf(stderr, "error direction in %s\n", chain); goto err; } } /* Get NAT target information */ else if (nat) { struct ip_nat_multi_range *mr = (struct ip_nat_multi_range *) &target->data[0]; struct ip_nat_range *range = (struct ip_nat_range *) &mr->range[0]; /* Get mapped IP address */ nat->ipaddr.s_addr = range->min_ip; /* Get mapped TCP port(s) */ if (entry->ip.proto == IPPROTO_TCP) { nat->ports[0] = range->min.tcp.port; nat->ports[1] = range->max.tcp.port; } /* Get mapped UDP port(s) */ else if (entry->ip.proto == IPPROTO_UDP) { nat->ports[0] = range->min.udp.port; nat->ports[1] = range->max.udp.port; } } /* Get application specific port forward information */ else if (app) { struct ip_autofw_info *info = (struct ip_autofw_info *) &target->data[0]; app->proto = info->proto; app->dport[0] = info->dport[0]; app->dport[1] = info->dport[1]; app->to[0] = info->to[0]; app->to[1] = info->to[1]; } } } if (!iptc_commit(handle)) { fprintf(stderr, "%s\n", iptc_strerror(errno)); goto err; } iptc_free(handle); handle = NULL; }