struct ethertypeent *parseethertypebynumber(int type) { if (type < 1536) ebt_print_error("Ethernet protocols have values >= 0x0600"); if (type > 0xffff) ebt_print_error("Ethernet protocols have values <= 0xffff"); return getethertypebynumber(type); }
static void final_check(const struct ebt_u_entry *entry, const struct ebt_entry_target *target, const char *name, unsigned int hookmask, unsigned int time) { struct ebt_mark_t_info *markinfo = (struct ebt_mark_t_info *)target->data; if (time == 0 && mark_supplied == 0) { ebt_print_error("No mark value supplied"); } else if (BASE_CHAIN && (markinfo->target|~EBT_VERDICT_BITS) == EBT_RETURN) ebt_print_error("--mark-target RETURN not allowed on base chain"); }
static void final_check_arpnat(const struct ebt_u_entry *entry, const struct ebt_entry_target *target, const char *name, unsigned int hookmask, unsigned int time) { struct ebt_nat_info *natinfo = (struct ebt_nat_info *)target->data; if (BASE_CHAIN && natinfo->target == EBT_RETURN) ebt_print_error("--arpnat-target RETURN not allowed on base chain"); CLEAR_BASE_CHAIN_BIT; if (((hookmask & ~((1 << NF_BR_PRE_ROUTING) | (1 << NF_BR_POST_ROUTING))) || strcmp(name, "nat"))) ebt_print_error("Wrong chain for arpnat"); }
void ebt_parse_ip6_address(char *address, struct in6_addr *addr, struct in6_addr *msk) { struct in6_addr *tmp_addr; char buf[256]; char *p; int i; int err; strncpy(buf, address, sizeof(buf) - 1); buf[sizeof(buf) - 1] = '\0'; if ((p = strrchr(buf, '/')) != NULL) { *p = '\0'; tmp_addr = parse_ip6_mask(p + 1); } else tmp_addr = parse_ip6_mask(NULL); in6addrcpy(msk, tmp_addr); if (!memcmp(msk, &in6addr_any, sizeof(in6addr_any))) strcpy(buf, "::"); if ((err=inet_pton(AF_INET6, buf, addr)) < 1) { ebt_print_error("Invalid IPv6 Address '%s' specified", buf); return; } for (i = 0; i < 4; i++) addr->s6_addr32[i] &= msk->s6_addr32[i]; }
static void final_check_s(const struct ebt_u_entry *entry, const struct ebt_entry_target *target, const char *name, unsigned int hookmask, unsigned int time) { struct ebt_nat_info *natinfo = (struct ebt_nat_info *)target->data; if (BASE_CHAIN && (natinfo->target | ~EBT_VERDICT_BITS) == EBT_RETURN) { ebt_print_error("--snat-target RETURN not allowed on base chain"); return; } CLEAR_BASE_CHAIN_BIT; if ((hookmask & ~(1 << NF_BR_POST_ROUTING)) || strcmp(name, "nat")) { ebt_print_error("Wrong chain for snat"); } else if (time == 0 && to_source_supplied == 0) ebt_print_error("No snat address supplied"); }
static int parse(int c, char **argv, int argc, const struct ebt_u_entry *entry, unsigned int *flags, struct ebt_entry_match **match) { struct ebt_vlan_info *vlaninfo = (struct ebt_vlan_info *) (*match)->data; char *end; struct ebt_vlan_info local; switch (c) { case VLAN_ID: ebt_check_option2(flags, OPT_VLAN_ID); if (ebt_check_inverse2(optarg)) vlaninfo->invflags |= EBT_VLAN_ID; #if 1 /*Rodney_20090724*/ parse_id_range(optarg, vlaninfo->id); #else local.id = strtoul(optarg, &end, 10); if (local.id > 4094 || *end != '\0') ebt_print_error2("Invalid --vlan-id range ('%s')", optarg); vlaninfo->id = local.id; #endif vlaninfo->bitmask |= EBT_VLAN_ID; break; case VLAN_PRIO: ebt_check_option2(flags, OPT_VLAN_PRIO); if (ebt_check_inverse2(optarg)) vlaninfo->invflags |= EBT_VLAN_PRIO; #if 1 /*Rodney_20090724*/ parse_prio_range(optarg, vlaninfo->prio); #else local.prio = strtoul(optarg, &end, 10); if (local.prio >= 8 || *end != '\0') ebt_print_error2("Invalid --vlan-prio range ('%s')", optarg); vlaninfo->prio = local.prio; #endif vlaninfo->bitmask |= EBT_VLAN_PRIO; break; case VLAN_ENCAP: ebt_check_option2(flags, OPT_VLAN_ENCAP); if (ebt_check_inverse2(optarg)) vlaninfo->invflags |= EBT_VLAN_ENCAP; local.encap = strtoul(optarg, &end, 16); if (*end != '\0') { ethent = getethertypebyname(optarg); if (ethent == NULL) ebt_print_error("Unknown --vlan-encap value ('%s')", optarg); local.encap = ethent->e_ethertype; } if (local.encap < ETH_ZLEN) ebt_print_error2("Invalid --vlan-encap range ('%s')", optarg); vlaninfo->encap = htons(local.encap); vlaninfo->bitmask |= EBT_VLAN_ENCAP; break; default: return 0; } return 1; }
static struct in6_addr *parse_ip6_mask(char *mask) { static struct in6_addr maskaddr; struct in6_addr *addrp; unsigned int bits; if (mask == NULL) { memset(&maskaddr, 0xff, sizeof maskaddr); return &maskaddr; } if ((addrp = numeric_to_addr(mask)) != NULL) return addrp; if (string_to_number(mask, 0, 128, &bits) == -1) ebt_print_error("Invalid IPv6 Mask '%s' specified", mask); if (bits != 0) { char *p = (char *)&maskaddr; memset(p, 0xff, bits / 8); memset(p + (bits / 8) + 1, 0, (128 - bits) / 8); p[bits / 8] = 0xff << (8 - (bits & 7)); return &maskaddr; } memset(&maskaddr, 0, sizeof maskaddr); return &maskaddr; }
static void final_check(const struct ebt_u_entry *entry, const struct ebt_entry_match *match, const char *name, unsigned int hookmask, unsigned int time) { if (entry->ethproto != ETH_P_8021Q || entry->invflags & EBT_IPROTO) ebt_print_error("For vlan filtering the protocol must be specified as 802_1Q"); }
static void final_check(const struct ebt_u_entry *entry, const struct ebt_entry_match *match, const char *name, unsigned int hookmask, unsigned int time) { if ((entry->ethproto != ETH_P_ARP && entry->ethproto != ETH_P_RARP) || entry->invflags & EBT_IPROTO) ebt_print_error("For (R)ARP filtering the protocol must be specified as ARP or RARP"); }
static void final_check_d(const struct ebt_u_entry *entry, const struct ebt_entry_target *target, const char *name, unsigned int hookmask, unsigned int time) { struct ebt_nat_info *natinfo = (struct ebt_nat_info *)target->data; if (BASE_CHAIN && natinfo->target == EBT_RETURN) { ebt_print_error("--dnat-target RETURN not allowed on base chain"); return; } CLEAR_BASE_CHAIN_BIT; if (((hookmask & ~((1 << NF_BR_PRE_ROUTING) | (1 << NF_BR_LOCAL_OUT))) || strcmp(name, "nat")) && ((hookmask & ~(1 << NF_BR_BROUTING)) || strcmp(name, "broute"))) { ebt_print_error("Wrong chain for dnat"); } else if (time == 0 && to_dest_supplied == 0) ebt_print_error("No dnat address supplied"); }
static void final_check(const struct ebt_u_entry *entry, const struct ebt_entry_target *target, const char *name, unsigned int hookmask, unsigned int time) { struct ebt_arpreply_info *replyinfo = (struct ebt_arpreply_info *)target->data; if (entry->ethproto != ETH_P_ARP || entry->invflags & EBT_IPROTO) { ebt_print_error("For ARP replying the protocol must be specified as ARP"); } else if (time == 0 && mac_supplied == 0) { ebt_print_error("No arpreply mac supplied"); } else if (BASE_CHAIN && replyinfo->target == EBT_RETURN) { ebt_print_error("--arpreply-target RETURN not allowed on base chain"); } else { CLEAR_BASE_CHAIN_BIT; if (strcmp(name, "nat") || hookmask & ~(1 << NF_BR_PRE_ROUTING)) ebt_print_error("arpreply only allowed in PREROUTING"); } }
static void final_check(const struct ebt_u_entry *entry, const struct ebt_entry_match *match, const char *name, unsigned int hookmask, unsigned int time) { struct ebt_ip6_info *ipinfo = (struct ebt_ip6_info *)match->data; if (entry->ethproto != ETH_P_IPV6 || entry->invflags & EBT_IPROTO) { ebt_print_error("For IPv6 filtering the protocol must be " "specified as IPv6"); } else if (ipinfo->bitmask & (EBT_IP6_SPORT|EBT_IP6_DPORT) && (!(ipinfo->bitmask & EBT_IP6_PROTO) || ipinfo->invflags & EBT_IP6_PROTO || (ipinfo->protocol!=IPPROTO_TCP && ipinfo->protocol!=IPPROTO_UDP && ipinfo->protocol!=IPPROTO_SCTP && ipinfo->protocol!=IPPROTO_DCCP))) ebt_print_error("For port filtering the IP protocol must be " "either 6 (tcp), 17 (udp), 33 (dccp) or " "132 (sctp)"); }
void ebt_parse_ip_address(char *address, uint32_t *addr, uint32_t *msk) { char *p; if ((p = strrchr(address, '/')) != NULL) { *p = '\0'; if (ip_mask(p + 1, (unsigned char *)msk)) { ebt_print_error("Problem with the IP mask '%s'", p + 1); return; } } else *msk = 0xFFFFFFFF; if (undot_ip(address, (unsigned char *)addr)) { ebt_print_error("Problem with the IP address '%s'", address); return; } *addr = *addr & *msk; }
static int parse_iface(char *iface, char *option) { char *c; if ((c = strchr(iface, '+'))) { if (*(c + 1) != '\0') { ebt_print_error("Spurious characters after '+' wildcard for '%s'", option); return -1; } else *c = IF_WILDCARD; } return 0; }
static void final_check(const struct ebt_u_entry *entry, const struct ebt_entry_match *match, const char *name, unsigned int hookmask, unsigned int time) { if (entry->ethproto != ETH_P_8021Q || entry->invflags & EBT_IPROTO) ebt_print_error("For vlan filtering the protocol must be specified as 802_1Q"); /* Check if specified vlan-id=0 (priority-tagged frame condition) * when vlan-prio was specified. */ /* I see no reason why a user should be prohibited to match on a perhaps impossible situation <BDS> if (vlaninfo->bitmask & EBT_VLAN_PRIO && vlaninfo->id && vlaninfo->bitmask & EBT_VLAN_ID) ebt_print_error("When setting --vlan-prio the specified --vlan-id must be 0");*/ }
static uint8_t parse_prio(const char *name) { struct servent *service; char *end; uint8_t prio; prio = (uint8_t)strtol(name, &end, 16); if (prio >= 0 || prio <= 0x07) { return prio; } ebt_print_error("Problem with specified vlanPRIO '%s'", name); return 0; }
/* * option inverse flags definition */ #define OPT_VLAN_ID 0x01 #define OPT_VLAN_PRIO 0x02 #define OPT_VLAN_ENCAP 0x04 #define OPT_VLAN_FLAGS (OPT_VLAN_ID | OPT_VLAN_PRIO | OPT_VLAN_ENCAP) struct ethertypeent *ethent; #if 1 /*Rodney_20090724*/ static uint16_t parse_id(const char *name) { struct servent *service; char *end; uint16_t id; id = strtol(name, &end, 10); if (id >= 0 || id <= 0xFFFF) { return id; } ebt_print_error("Problem with specified vlanID '%s'", name); return 0; }
int _ebt_check_inverse(const char option[], int argc, char **argv) { if (!option) return ebt_invert; if (strcmp(option, "!") == 0) { if (ebt_invert == 1) ebt_print_error("Double use of '!' not allowed"); if (optind >= argc) optarg = NULL; else optarg = argv[optind]; optind++; ebt_invert = 1; return 1; } return ebt_invert; }
/* transform a protocol and service name into a port number */ static uint16_t parse_port(const char *protocol, const char *name) { struct servent *service; char *end; int port; port = strtol(name, &end, 10); if (*end != '\0') { if (protocol && (service = getservbyname(name, protocol)) != NULL) return ntohs(service->s_port); } else if (port >= 0 || port <= 0xFFFF) { return port; } ebt_print_error("Problem with specified %s port '%s'", protocol?protocol:"", name); return 0; }
static void print(const struct ebt_u_entry *entry, const struct ebt_entry_target *target) { struct ebt_mark_t_info *markinfo = (struct ebt_mark_t_info *)target->data; int tmp; tmp = markinfo->target & ~EBT_VERDICT_BITS; if (tmp == MARK_SET_VALUE) printf("--mark-set"); else if (tmp == MARK_OR_VALUE) printf("--mark-or"); else if (tmp == MARK_XOR_VALUE) printf("--mark-xor"); else if (tmp == MARK_AND_VALUE) printf("--mark-and"); else ebt_print_error("oops, unknown mark action, try a later version of ebtables"); printf(" 0x%lx", markinfo->mark); tmp = markinfo->target | ~EBT_VERDICT_BITS; printf(" --mark-target %s", TARGET_NAME(tmp)); }
static void parse_id_range(const char *portstring, uint16_t *id) { char *buffer; char *cp; buffer = strdup(portstring); if ((cp = strchr(buffer, ':')) == NULL) id[0] = id[1] = parse_id(buffer); else { *cp = '\0'; cp++; id[0] = buffer[0] ? parse_id(buffer) : 0; if (ebt_errormsg[0] != '\0') return; id[1] = cp[0] ? parse_id(cp) : 0xFFFF; if (ebt_errormsg[0] != '\0') return; if (id[0] > id[1]) ebt_print_error("Invalid VlanID range (min > max)"); } free(buffer); }
static void parse_prio_range(const char *portstring, uint8_t *prio) { char *buffer; char *cp; buffer = strdup(portstring); if ((cp = strchr(buffer, ':')) == NULL) prio[0] = prio[1] = parse_prio(buffer); else { *cp = '\0'; cp++; prio[0] = buffer[0] ? parse_prio(buffer) : 0; if (ebt_errormsg[0] != '\0') return; prio[1] = cp[0] ? parse_prio(cp) : 0x07; if (ebt_errormsg[0] != '\0') return; if (prio[0] > prio[1]) ebt_print_error("Invalid VlanPrio range (min > max)"); } free(buffer); }
static void parse_port_range(const char *protocol, const char *portstring, uint16_t *ports) { char *buffer; char *cp; buffer = strdup(portstring); if ((cp = strchr(buffer, ':')) == NULL) ports[0] = ports[1] = parse_port(protocol, buffer); else { *cp = '\0'; cp++; ports[0] = buffer[0] ? parse_port(protocol, buffer) : 0; if (ebt_errormsg[0] != '\0') return; ports[1] = cp[0] ? parse_port(protocol, cp) : 0xFFFF; if (ebt_errormsg[0] != '\0') return; if (ports[0] > ports[1]) ebt_print_error("Invalid portrange (min > max)"); } free(buffer); }
static int parse(int c, char **argv, int argc, const struct ebt_u_entry *entry, unsigned int *flags, struct ebt_entry_match **match) { struct ebt_ip6_info *ipinfo = (struct ebt_ip6_info *)(*match)->data; char *end; long int i; switch (c) { case IP_SOURCE: ebt_check_option2(flags, OPT_SOURCE); ipinfo->bitmask |= EBT_IP6_SOURCE; if (ebt_check_inverse2(optarg)) { ipinfo->invflags |= EBT_IP6_SOURCE; } ebt_parse_ip6_address(optarg, &ipinfo->saddr, &ipinfo->smsk); break; case IP_DEST: ebt_check_option2(flags, OPT_DEST); ipinfo->bitmask |= EBT_IP6_DEST; if (ebt_check_inverse2(optarg)) { ipinfo->invflags |= EBT_IP6_DEST; } ebt_parse_ip6_address(optarg, &ipinfo->daddr, &ipinfo->dmsk); break; case IP_SPORT: case IP_DPORT: if (c == IP_SPORT) { ebt_check_option2(flags, OPT_SPORT); ipinfo->bitmask |= EBT_IP6_SPORT; if (ebt_check_inverse2(optarg)) ipinfo->invflags |= EBT_IP6_SPORT; } else { ebt_check_option2(flags, OPT_DPORT); ipinfo->bitmask |= EBT_IP6_DPORT; if (ebt_check_inverse2(optarg)) ipinfo->invflags |= EBT_IP6_DPORT; } if (c == IP_SPORT) parse_port_range(NULL, optarg, ipinfo->sport); else parse_port_range(NULL, optarg, ipinfo->dport); break; case IP_TCLASS: ebt_check_option2(flags, OPT_TCLASS); if (ebt_check_inverse2(optarg)) ipinfo->invflags |= EBT_IP6_TCLASS; i = strtol(optarg, &end, 16); if (i < 0 || i > 255 || *end != '\0') ebt_print_error2("Problem with specified IPv6 traffic class"); ipinfo->tclass = i; ipinfo->bitmask |= EBT_IP6_TCLASS; break; case IP_PROTO: ebt_check_option2(flags, OPT_PROTO); if (ebt_check_inverse2(optarg)) ipinfo->invflags |= EBT_IP6_PROTO; i = strtoul(optarg, &end, 10); if (*end != '\0') { struct protoent *pe; pe = getprotobyname(optarg); if (pe == NULL) ebt_print_error("Unknown specified IP protocol - %s", argv[optind - 1]); ipinfo->protocol = pe->p_proto; } else { ipinfo->protocol = (unsigned char) i; } ipinfo->bitmask |= EBT_IP6_PROTO; break; default: return 0; } return 1; }
/* We use exec_style instead of #ifdef's because ebtables.so is a shared object. */ int do_command(int argc, char *argv[], int exec_style, struct ebt_u_replace *replace_) { char *buffer; int c, i; int zerochain = -1; /* Needed for the -Z option (we can have -Z <this> -L <that>) */ int chcounter; /* Needed for -C */ int policy = 0; int rule_nr = 0; int rule_nr_end = 0; struct ebt_u_target *t; struct ebt_u_match *m; struct ebt_u_watcher *w; struct ebt_u_match_list *m_l; struct ebt_u_watcher_list *w_l; struct ebt_u_entries *entries; opterr = 0; ebt_modprobe = NULL; replace = replace_; /* The daemon doesn't use the environment variable */ if (exec_style == EXEC_STYLE_PRG) { buffer = getenv(ATOMIC_ENV_VARIABLE); if (buffer) { replace->filename = malloc(strlen(buffer) + 1); if (!replace->filename) ebt_print_memory(); strcpy(replace->filename, buffer); buffer = NULL; } } replace->flags &= OPT_KERNELDATA; /* ebtablesd needs OPT_KERNELDATA */ replace->selected_chain = -1; replace->command = 'h'; if (!new_entry) { new_entry = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry)); if (!new_entry) ebt_print_memory(); } /* Put some sane values in our new entry */ ebt_initialize_entry(new_entry); new_entry->replace = replace; /* The scenario induced by this loop makes that: * '-t' ,'-M' and --atomic (if specified) have to come * before '-A' and the like */ /* Getopt saves the day */ while ((c = getopt_long(argc, argv, "-A:D:C:I:N:E:X::L::Z::F::P:Vhi:o:j:c:p:s:d:t:M:", ebt_options, NULL)) != -1) { switch (c) { case 'A': /* Add a rule */ case 'D': /* Delete a rule */ case 'C': /* Change counters */ case 'P': /* Define policy */ case 'I': /* Insert a rule */ case 'N': /* Make a user defined chain */ case 'E': /* Rename chain */ case 'X': /* Delete chain */ /* We allow -N chainname -P policy */ if (replace->command == 'N' && c == 'P') { replace->command = c; optind--; /* No table specified */ goto handle_P; } if (OPT_COMMANDS) ebt_print_error2("Multiple commands are not allowed"); replace->command = c; replace->flags |= OPT_COMMAND; if (!(replace->flags & OPT_KERNELDATA)) ebt_get_kernel_table(replace, 0); if (optarg && (optarg[0] == '-' || !strcmp(optarg, "!"))) ebt_print_error2("No chain name specified"); if (c == 'N') { if (ebt_get_chainnr(replace, optarg) != -1) ebt_print_error2("Chain %s already exists", optarg); else if (ebt_find_target(optarg)) ebt_print_error2("Target with name %s exists", optarg); else if (strlen(optarg) >= EBT_CHAIN_MAXNAMELEN) ebt_print_error2("Chain name length can't exceed %d", EBT_CHAIN_MAXNAMELEN - 1); else if (strchr(optarg, ' ') != NULL) ebt_print_error2("Use of ' ' not allowed in chain names"); ebt_new_chain(replace, optarg, EBT_ACCEPT); /* This is needed to get -N x -P y working */ replace->selected_chain = ebt_get_chainnr(replace, optarg); break; } else if (c == 'X') { if (optind >= argc) { replace->selected_chain = -1; ebt_delete_chain(replace); break; } if (optind < argc - 1) ebt_print_error2("No extra options allowed with -X"); if ((replace->selected_chain = ebt_get_chainnr(replace, argv[optind])) == -1) ebt_print_error2("Chain '%s' doesn't exist", argv[optind]); ebt_delete_chain(replace); if (ebt_errormsg[0] != '\0') return -1; optind++; break; } if ((replace->selected_chain = ebt_get_chainnr(replace, optarg)) == -1) ebt_print_error2("Chain '%s' doesn't exist", optarg); if (c == 'E') { if (optind >= argc) ebt_print_error2("No new chain name specified"); else if (optind < argc - 1) ebt_print_error2("No extra options allowed with -E"); else if (strlen(argv[optind]) >= EBT_CHAIN_MAXNAMELEN) ebt_print_error2("Chain name length can't exceed %d characters", EBT_CHAIN_MAXNAMELEN - 1); else if (ebt_get_chainnr(replace, argv[optind]) != -1) ebt_print_error2("Chain '%s' already exists", argv[optind]); else if (ebt_find_target(argv[optind])) ebt_print_error2("Target with name '%s' exists", argv[optind]); else if (strchr(argv[optind], ' ') != NULL) ebt_print_error2("Use of ' ' not allowed in chain names"); ebt_rename_chain(replace, argv[optind]); optind++; break; } else if (c == 'D' && optind < argc && (argv[optind][0] != '-' || (argv[optind][1] >= '0' && argv[optind][1] <= '9'))) { if (optind != argc - 1) ebt_print_error2("No extra options allowed with -D start_nr[:end_nr]"); if (parse_rule_range(argv[optind], &rule_nr, &rule_nr_end)) ebt_print_error2("Problem with the specified rule number(s) '%s'", argv[optind]); optind++; } else if (c == 'C') { if ((chcounter = parse_change_counters_rule(argc, argv, &rule_nr, &rule_nr_end, exec_style)) == -1) return -1; } else if (c == 'I') { if (optind >= argc || (argv[optind][0] == '-' && (argv[optind][1] < '0' || argv[optind][1] > '9'))) rule_nr = 1; else { rule_nr = strtol(argv[optind], &buffer, 10); if (*buffer != '\0') ebt_print_error2("Problem with the specified rule number '%s'", argv[optind]); optind++; } } else if (c == 'P') { handle_P: if (optind >= argc) ebt_print_error2("No policy specified"); for (i = 0; i < NUM_STANDARD_TARGETS; i++) if (!strcmp(argv[optind], ebt_standard_targets[i])) { policy = -i -1; if (policy == EBT_CONTINUE) ebt_print_error2("Wrong policy '%s'", argv[optind]); break; } if (i == NUM_STANDARD_TARGETS) ebt_print_error2("Unknown policy '%s'", argv[optind]); optind++; } break; case 'L': /* List */ case 'F': /* Flush */ case 'Z': /* Zero counters */ if (c == 'Z') { if ((replace->flags & OPT_ZERO) || (replace->flags & OPT_COMMAND && replace->command != 'L')) print_zero: ebt_print_error2("Command -Z only allowed together with command -L"); replace->flags |= OPT_ZERO; } else { if (replace->flags & OPT_COMMAND) ebt_print_error2("Multiple commands are not allowed"); replace->command = c; replace->flags |= OPT_COMMAND; if (replace->flags & OPT_ZERO && c != 'L') goto print_zero; } #ifdef SILENT_DAEMON if (c== 'L' && exec_style == EXEC_STYLE_DAEMON) ebt_print_error2("-L not supported in daemon mode"); #endif if (!(replace->flags & OPT_KERNELDATA)) ebt_get_kernel_table(replace, 0); i = -1; if (optind < argc && argv[optind][0] != '-') { if ((i = ebt_get_chainnr(replace, argv[optind])) == -1) ebt_print_error2("Chain '%s' doesn't exist", argv[optind]); optind++; } if (i != -1) { if (c == 'Z') zerochain = i; else replace->selected_chain = i; } break; case 'V': /* Version */ if (OPT_COMMANDS) ebt_print_error2("Multiple commands are not allowed"); replace->command = 'V'; if (exec_style == EXEC_STYLE_DAEMON) ebt_print_error2(PROGNAME" v"PROGVERSION" ("PROGDATE")\n"); PRINT_VERSION; exit(0); case 'M': /* Modprobe */ if (OPT_COMMANDS) ebt_print_error2("Please put the -M option earlier"); free(ebt_modprobe); ebt_modprobe = optarg; break; case 'h': /* Help */ #ifdef SILENT_DAEMON if (exec_style == EXEC_STYLE_DAEMON) ebt_print_error2("-h not supported in daemon mode"); #endif if (OPT_COMMANDS) ebt_print_error2("Multiple commands are not allowed"); replace->command = 'h'; /* All other arguments should be extension names */ while (optind < argc) { struct ebt_u_match *m; struct ebt_u_watcher *w; if (!strcasecmp("list_extensions", argv[optind])) { ebt_list_extensions(); exit(0); } if ((m = ebt_find_match(argv[optind]))) ebt_add_match(new_entry, m); else if ((w = ebt_find_watcher(argv[optind]))) ebt_add_watcher(new_entry, w); else { if (!(t = ebt_find_target(argv[optind]))) ebt_print_error2("Extension '%s' not found", argv[optind]); if (replace->flags & OPT_JUMP) ebt_print_error2("Sorry, you can only see help for one target extension at a time"); replace->flags |= OPT_JUMP; new_entry->t = (struct ebt_entry_target *)t; } optind++; } break; case 't': /* Table */ if (OPT_COMMANDS) ebt_print_error2("Please put the -t option first"); ebt_check_option2(&(replace->flags), OPT_TABLE); if (strlen(optarg) > EBT_TABLE_MAXNAMELEN - 1) ebt_print_error2("Table name length cannot exceed %d characters", EBT_TABLE_MAXNAMELEN - 1); strcpy(replace->name, optarg); break; case 'i': /* Input interface */ case 2 : /* Logical input interface */ case 'o': /* Output interface */ case 3 : /* Logical output interface */ case 'j': /* Target */ case 'p': /* Net family protocol */ case 's': /* Source mac */ case 'd': /* Destination mac */ case 'c': /* Set counters */ if (!OPT_COMMANDS) ebt_print_error2("No command specified"); if (replace->command != 'A' && replace->command != 'D' && replace->command != 'I' && replace->command != 'C') ebt_print_error2("Command and option do not match"); if (c == 'i') { ebt_check_option2(&(replace->flags), OPT_IN); if (replace->selected_chain > 2 && replace->selected_chain < NF_BR_BROUTING) ebt_print_error2("Use -i only in INPUT, FORWARD, PREROUTING and BROUTING chains"); if (ebt_check_inverse2(optarg)) new_entry->invflags |= EBT_IIN; if (strlen(optarg) >= IFNAMSIZ) big_iface_length: ebt_print_error2("Interface name length cannot exceed %d characters", IFNAMSIZ - 1); strcpy(new_entry->in, optarg); if (parse_iface(new_entry->in, "-i")) return -1; break; } else if (c == 2) { ebt_check_option2(&(replace->flags), OPT_LOGICALIN); if (replace->selected_chain > 2 && replace->selected_chain < NF_BR_BROUTING) ebt_print_error2("Use --logical-in only in INPUT, FORWARD, PREROUTING and BROUTING chains"); if (ebt_check_inverse2(optarg)) new_entry->invflags |= EBT_ILOGICALIN; if (strlen(optarg) >= IFNAMSIZ) goto big_iface_length; strcpy(new_entry->logical_in, optarg); if (parse_iface(new_entry->logical_in, "--logical-in")) return -1; break; } else if (c == 'o') { ebt_check_option2(&(replace->flags), OPT_OUT); if (replace->selected_chain < 2 )//|| replace->selected_chain == NF_BR_BROUTING) ebt_print_error2("Use -o only in OUTPUT, FORWARD and POSTROUTING chains"); if (ebt_check_inverse2(optarg)) new_entry->invflags |= EBT_IOUT; if (strlen(optarg) >= IFNAMSIZ) goto big_iface_length; strcpy(new_entry->out, optarg); if (parse_iface(new_entry->out, "-o")) return -1; break; } else if (c == 3) { ebt_check_option2(&(replace->flags), OPT_LOGICALOUT); if (replace->selected_chain < 2 || replace->selected_chain == NF_BR_BROUTING) ebt_print_error2("Use --logical-out only in OUTPUT, FORWARD and POSTROUTING chains"); if (ebt_check_inverse2(optarg)) new_entry->invflags |= EBT_ILOGICALOUT; if (strlen(optarg) >= IFNAMSIZ) goto big_iface_length; strcpy(new_entry->logical_out, optarg); if (parse_iface(new_entry->logical_out, "--logical-out")) return -1; break; } else if (c == 'j') { ebt_check_option2(&(replace->flags), OPT_JUMP); for (i = 0; i < NUM_STANDARD_TARGETS; i++) if (!strcmp(optarg, ebt_standard_targets[i])) { t = ebt_find_target(EBT_STANDARD_TARGET); ((struct ebt_standard_target *) t->t)->verdict = -i - 1; break; } if (-i - 1 == EBT_RETURN && replace->selected_chain < NF_BR_NUMHOOKS) { ebt_print_error2("Return target only for user defined chains"); } else if (i != NUM_STANDARD_TARGETS) break; if ((i = ebt_get_chainnr(replace, optarg)) != -1) { if (i < NF_BR_NUMHOOKS) ebt_print_error2("Don't jump to a standard chain"); t = ebt_find_target(EBT_STANDARD_TARGET); ((struct ebt_standard_target *) t->t)->verdict = i - NF_BR_NUMHOOKS; break; } else { /* Must be an extension then */ struct ebt_u_target *t; t = ebt_find_target(optarg); /* -j standard not allowed either */ if (!t || t == (struct ebt_u_target *)new_entry->t) ebt_print_error2("Illegal target name '%s'", optarg); new_entry->t = (struct ebt_entry_target *)t; ebt_find_target(EBT_STANDARD_TARGET)->used = 0; t->used = 1; } break; } else if (c == 's') { ebt_check_option2(&(replace->flags), OPT_SOURCE); if (ebt_check_inverse2(optarg)) new_entry->invflags |= EBT_ISOURCE; if (ebt_get_mac_and_mask(optarg, new_entry->sourcemac, new_entry->sourcemsk)) ebt_print_error2("Problem with specified source mac '%s'", optarg); new_entry->bitmask |= EBT_SOURCEMAC; break; } else if (c == 'd') { ebt_check_option2(&(replace->flags), OPT_DEST); if (ebt_check_inverse2(optarg)) new_entry->invflags |= EBT_IDEST; if (ebt_get_mac_and_mask(optarg, new_entry->destmac, new_entry->destmsk)) ebt_print_error2("Problem with specified destination mac '%s'", optarg); new_entry->bitmask |= EBT_DESTMAC; break; } else if (c == 'c') { ebt_check_option2(&(replace->flags), OPT_COUNT); if (ebt_check_inverse2(optarg)) ebt_print_error2("Unexpected '!' after -c"); if (optind >= argc || optarg[0] == '-' || argv[optind][0] == '-') ebt_print_error2("Option -c needs 2 arguments"); new_entry->cnt.pcnt = strtoull(optarg, &buffer, 10); if (*buffer != '\0') ebt_print_error2("Packet counter '%s' invalid", optarg); new_entry->cnt.bcnt = strtoull(argv[optind], &buffer, 10); if (*buffer != '\0') ebt_print_error2("Packet counter '%s' invalid", argv[optind]); optind++; break; } ebt_check_option2(&(replace->flags), OPT_PROTOCOL); if (ebt_check_inverse2(optarg)) new_entry->invflags |= EBT_IPROTO; new_entry->bitmask &= ~((unsigned int)EBT_NOPROTO); i = strtol(optarg, &buffer, 16); if (*buffer == '\0' && (i < 0 || i > 0xFFFF)) ebt_print_error2("Problem with the specified protocol"); if (*buffer != '\0') { struct ethertypeent *ent; if (!strcasecmp(optarg, "LENGTH")) { new_entry->bitmask |= EBT_802_3; break; } ent = getethertypebyname(optarg); if (!ent) ebt_print_error2("Problem with the specified Ethernet protocol '%s', perhaps "_PATH_ETHERTYPES " is missing", optarg); new_entry->ethproto = ent->e_ethertype; } else new_entry->ethproto = i; if (new_entry->ethproto < 0x0600) ebt_print_error2("Sorry, protocols have values above or equal to 0x0600"); break; case 4 : /* Lc */ #ifdef SILENT_DAEMON if (exec_style == EXEC_STYLE_DAEMON) ebt_print_error2("--Lc is not supported in daemon mode"); #endif ebt_check_option2(&(replace->flags), LIST_C); if (replace->command != 'L') ebt_print_error("Use --Lc with -L"); replace->flags |= LIST_C; break; case 5 : /* Ln */ #ifdef SILENT_DAEMON if (exec_style == EXEC_STYLE_DAEMON) ebt_print_error2("--Ln is not supported in daemon mode"); #endif ebt_check_option2(&(replace->flags), LIST_N); if (replace->command != 'L') ebt_print_error2("Use --Ln with -L"); if (replace->flags & LIST_X) ebt_print_error2("--Lx is not compatible with --Ln"); replace->flags |= LIST_N; break; case 6 : /* Lx */ #ifdef SILENT_DAEMON if (exec_style == EXEC_STYLE_DAEMON) ebt_print_error2("--Lx is not supported in daemon mode"); #endif ebt_check_option2(&(replace->flags), LIST_X); if (replace->command != 'L') ebt_print_error2("Use --Lx with -L"); if (replace->flags & LIST_N) ebt_print_error2("--Lx is not compatible with --Ln"); replace->flags |= LIST_X; break; case 12 : /* Lmac2 */ #ifdef SILENT_DAEMON if (exec_style == EXEC_STYLE_DAEMON) ebt_print_error("--Lmac2 is not supported in daemon mode"); #endif ebt_check_option2(&(replace->flags), LIST_MAC2); if (replace->command != 'L') ebt_print_error2("Use --Lmac2 with -L"); replace->flags |= LIST_MAC2; break; case 8 : /* atomic-commit */ if (exec_style == EXEC_STYLE_DAEMON) ebt_print_error2("--atomic-commit is not supported in daemon mode"); replace->command = c; if (OPT_COMMANDS) ebt_print_error2("Multiple commands are not allowed"); replace->flags |= OPT_COMMAND; if (!replace->filename) ebt_print_error2("No atomic file specified"); /* Get the information from the file */ ebt_get_table(replace, 0); /* We don't want the kernel giving us its counters, * they would overwrite the counters extracted from * the file */ replace->num_counters = 0; /* Make sure the table will be written to the kernel */ free(replace->filename); replace->filename = NULL; break; case 7 : /* atomic-init */ case 10: /* atomic-save */ case 11: /* init-table */ if (exec_style == EXEC_STYLE_DAEMON) { if (c == 7) { ebt_print_error2("--atomic-init is not supported in daemon mode"); } else if (c == 10) ebt_print_error2("--atomic-save is not supported in daemon mode"); ebt_print_error2("--init-table is not supported in daemon mode"); } replace->command = c; if (OPT_COMMANDS) ebt_print_error2("Multiple commands are not allowed"); if (c != 11 && !replace->filename) ebt_print_error2("No atomic file specified"); replace->flags |= OPT_COMMAND; { char *tmp = replace->filename; /* Get the kernel table */ replace->filename = NULL; ebt_get_kernel_table(replace, c == 10 ? 0 : 1); replace->filename = tmp; } break; case 9 : /* atomic */ if (exec_style == EXEC_STYLE_DAEMON) ebt_print_error2("--atomic is not supported in daemon mode"); if (OPT_COMMANDS) ebt_print_error2("--atomic has to come before the command"); /* A possible memory leak here, but this is not * executed in daemon mode */ replace->filename = (char *)malloc(strlen(optarg) + 1); strcpy(replace->filename, optarg); break; case 13 : /* concurrent */ signal(SIGINT, sighandler); signal(SIGTERM, sighandler); use_lockfd = 1; break; case 1 : if (!strcmp(optarg, "!")) ebt_check_inverse2(optarg); else ebt_print_error2("Bad argument : '%s'", optarg); /* ebt_check_inverse() did optind++ */ optind--; continue; default: /* Is it a target option? */ t = (struct ebt_u_target *)new_entry->t; if ((t->parse(c - t->option_offset, argv, argc, new_entry, &t->flags, &t->t))) { if (ebt_errormsg[0] != '\0') return -1; goto check_extension; } /* Is it a match_option? */ for (m = ebt_matches; m; m = m->next) if (m->parse(c - m->option_offset, argv, argc, new_entry, &m->flags, &m->m)) break; if (m != NULL) { if (ebt_errormsg[0] != '\0') return -1; if (m->used == 0) { ebt_add_match(new_entry, m); m->used = 1; } goto check_extension; } /* Is it a watcher option? */ for (w = ebt_watchers; w; w = w->next) if (w->parse(c - w->option_offset, argv, argc, new_entry, &w->flags, &w->w)) break; if (w == NULL && c == '?') ebt_print_error2("Unknown argument: '%s'", argv[optind - 1], (char)optopt, (char)c); else if (w == NULL) { if (!strcmp(t->name, "standard")) ebt_print_error2("Unknown argument: don't forget the -t option"); else ebt_print_error2("Target-specific option does not correspond with specified target"); } if (ebt_errormsg[0] != '\0') return -1; if (w->used == 0) { ebt_add_watcher(new_entry, w); w->used = 1; } check_extension: if (replace->command != 'A' && replace->command != 'I' && replace->command != 'D' && replace->command != 'C') ebt_print_error2("Extensions only for -A, -I, -D and -C"); } ebt_invert = 0; } /* Just in case we didn't catch an error */ if (ebt_errormsg[0] != '\0') return -1; if (!(table = ebt_find_table(replace->name))) ebt_print_error2("Bad table name"); if (replace->command == 'h' && !(replace->flags & OPT_ZERO)) { print_help(); if (exec_style == EXEC_STYLE_PRG) exit(0); } /* Do the final checks */ if (replace->command == 'A' || replace->command == 'I' || replace->command == 'D' || replace->command == 'C') { /* This will put the hook_mask right for the chains */ ebt_check_for_loops(replace); if (ebt_errormsg[0] != '\0') return -1; entries = ebt_to_chain(replace); m_l = new_entry->m_list; w_l = new_entry->w_list; t = (struct ebt_u_target *)new_entry->t; while (m_l) { m = (struct ebt_u_match *)(m_l->m); m->final_check(new_entry, m->m, replace->name, entries->hook_mask, 0); if (ebt_errormsg[0] != '\0') return -1; m_l = m_l->next; } while (w_l) { w = (struct ebt_u_watcher *)(w_l->w); w->final_check(new_entry, w->w, replace->name, entries->hook_mask, 0); if (ebt_errormsg[0] != '\0') return -1; w_l = w_l->next; } t->final_check(new_entry, t->t, replace->name, entries->hook_mask, 0); if (ebt_errormsg[0] != '\0') return -1; } /* So, the extensions can work with the host endian. * The kernel does not have to do this of course */ new_entry->ethproto = htons(new_entry->ethproto); if (replace->command == 'P') { if (replace->selected_chain < NF_BR_NUMHOOKS && policy == EBT_RETURN) ebt_print_error2("Policy RETURN only allowed for user defined chains"); ebt_change_policy(replace, policy); if (ebt_errormsg[0] != '\0') return -1; } else if (replace->command == 'L') { list_rules(); if (!(replace->flags & OPT_ZERO) && exec_style == EXEC_STYLE_PRG) exit(0); } if (replace->flags & OPT_ZERO) { replace->selected_chain = zerochain; ebt_zero_counters(replace); } else if (replace->command == 'F') { ebt_flush_chains(replace); } else if (replace->command == 'A' || replace->command == 'I') { ebt_add_rule(replace, new_entry, rule_nr); if (ebt_errormsg[0] != '\0') return -1; /* Makes undoing the add easier (jumps to delete_the_rule) */ if (rule_nr <= 0) rule_nr--; rule_nr_end = rule_nr; /* a jump to a udc requires checking for loops */ if (!strcmp(new_entry->t->u.name, EBT_STANDARD_TARGET) && ((struct ebt_standard_target *)(new_entry->t))->verdict >= 0) { /* FIXME: this can be done faster */ ebt_check_for_loops(replace); if (ebt_errormsg[0] != '\0') goto delete_the_rule; } /* Do the final_check(), for all entries. * This is needed when adding a rule that has a chain target */ i = -1; while (++i != replace->num_chains) { struct ebt_u_entry *e; entries = replace->chains[i]; if (!entries) { if (i < NF_BR_NUMHOOKS) continue; else ebt_print_bug("whoops\n"); } e = entries->entries->next; while (e != entries->entries) { /* Userspace extensions use host endian */ e->ethproto = ntohs(e->ethproto); ebt_do_final_checks(replace, e, entries); if (ebt_errormsg[0] != '\0') goto delete_the_rule; e->ethproto = htons(e->ethproto); e = e->next; } } /* Don't reuse the added rule */ new_entry = NULL; } else if (replace->command == 'D') { delete_the_rule: ebt_delete_rule(replace, new_entry, rule_nr, rule_nr_end); if (ebt_errormsg[0] != '\0') return -1; } else if (replace->command == 'C') { ebt_change_counters(replace, new_entry, rule_nr, rule_nr_end, &(new_entry->cnt_surplus), chcounter); if (ebt_errormsg[0] != '\0') return -1; } /* Commands -N, -E, -X, --atomic-commit, --atomic-commit, --atomic-save, * --init-table fall through */ if (ebt_errormsg[0] != '\0') return -1; if (table->check) table->check(replace); if (exec_style == EXEC_STYLE_PRG) {/* Implies ebt_errormsg[0] == '\0' */ ebt_deliver_table(replace); if (replace->nentries) ebt_deliver_counters(replace); } return 0; }
static struct ebt_mac_wormhash *create_wormhash(const char *arg) { const char *pc = arg; const char *anchor; char *endptr; struct ebt_mac_wormhash *workcopy, *result, *h; unsigned char mac[6]; unsigned char ip[4]; int nmacs = 0; int i; char token[4]; if (!(workcopy = new_wormhash(1024))) { ebt_print_memory(); } while (1) { /* remember current position, we'll need it on error */ anchor = pc; /* collect MAC; all its bytes are followed by ':' (colon), * except for the last one which can be followed by * ',' (comma), '=' or '\0' */ for (i = 0; i < 5; i++) { if (read_until(&pc, ":", token, 2) < 0 || token[0] == 0) { ebt_print_error("MAC parse error: %.20s", anchor); return NULL; } mac[i] = strtol(token, &endptr, 16); if (*endptr) { ebt_print_error("MAC parse error: %.20s", anchor); return NULL; } pc++; } if (read_until(&pc, "=,", token, 2) == -2 || token[0] == 0) { ebt_print_error("MAC parse error: %.20s", anchor); return NULL; } mac[i] = strtol(token, &endptr, 16); if (*endptr) { ebt_print_error("MAC parse error: %.20s", anchor); return NULL; } if (*pc == '=') { /* an IP follows the MAC; collect similarly to MAC */ pc++; anchor = pc; for (i = 0; i < 3; i++) { if (read_until(&pc, ".", token, 3) < 0 || token[0] == 0) { ebt_print_error("IP parse error: %.20s", anchor); return NULL; } ip[i] = strtol(token, &endptr, 10); if (*endptr) { ebt_print_error("IP parse error: %.20s", anchor); return NULL; } pc++; } if (read_until(&pc, ",", token, 3) == -2 || token[0] == 0) { ebt_print_error("IP parse error: %.20s", anchor); return NULL; } ip[3] = strtol(token, &endptr, 10); if (*endptr) { ebt_print_error("IP parse error: %.20s", anchor); return NULL; } if (*(uint32_t*)ip == 0) { ebt_print_error("Illegal IP 0.0.0.0"); return NULL; } } else { /* no IP, we set it to 0.0.0.0 */ memset(ip, 0, 4); } /* we have collected MAC and IP, so we add an entry */ memcpy(((char *) workcopy->pool[nmacs].cmp) + 2, mac, 6); workcopy->pool[nmacs].ip = *(const uint32_t *) ip; nmacs++; /* re-allocate memory if needed */ if (*pc && nmacs >= workcopy->poolsize) { if (!(h = new_wormhash(nmacs * 2))) { ebt_print_memory(); } copy_wormhash(h, workcopy); free(workcopy); workcopy = h; } /* check if end of string was reached */ if (!*pc) { break; } /* now `pc' points to comma if we are here; */ /* increment this to the next char */ /* but first assert :-> */ if (*pc != ',') { ebt_print_error("Something went wrong; no comma...\n"); return NULL; } pc++; /* again check if end of string was reached; */ /* we allow an ending comma */ if (!*pc) { break; } } if (!(result = new_wormhash(nmacs))) { ebt_print_memory(); } copy_wormhash(result, workcopy); free(workcopy); qsort(&result->pool, result->poolsize, sizeof(struct ebt_mac_wormhash_tuple), fcmp); index_table(result); return result; }
int main(int argc_, char *argv_[]) { char *argv[EBTD_ARGC_MAX], *args[4], name[] = "mkdir", mkdir_option[] = "-p", mkdir_dir[] = EBTD_PIPE_DIR, cmdline[EBTD_CMDLINE_MAXLN]; int readfd, base = 0, offset = 0, n = 0, ret = 0, quotemode = 0; args[0] = name; args[1] = mkdir_option; args[2] = mkdir_dir; args[3] = NULL; switch (fork()) { case 0: execvp(args[0], args); exit(0); case -1: return -1; default: wait(NULL); } if (mkfifo(EBTD_PIPE, 0600) < 0 && errno != EEXIST) { printf("Error creating FIFO " EBTD_PIPE "\n"); ret = -1; goto do_exit; } if ((readfd = open(EBTD_PIPE, O_RDONLY | O_NONBLOCK, 0)) == -1) { perror("open"); ret = -1; goto do_exit; } if (signal(SIGPIPE, sigpipe_handler) == SIG_ERR) { perror("signal"); ret = -1; goto do_exit; } ebt_silent = 1; copy_table_names(); ebt_early_init_once(); while (1) { int n2, i, argc, table_nr, ntot; ntot = read(readfd, cmdline+offset, EBTD_CMDLINE_MAXLN-offset-1); if (ntot <= 0) continue; ntot += offset; continue_read: for (; offset < ntot; n++, offset++) { if (cmdline[offset] == '\"') { quotemode ^= 1; cmdline[offset] = '\0'; } else if (!quotemode && cmdline[offset] == ' ') { cmdline[offset] = '\0'; } else if (cmdline[offset] == '\n') { if (quotemode) ebt_print_error("ebtablesd: wrong number of \" delimiters"); cmdline[offset] = '\0'; break; } } if (n == 0) { if (offset == ntot) { base = 0; offset = 0; continue; } offset++; base = offset; n = 0; goto continue_read; } if (offset == ntot) { if (base == 0) { ebt_print_error("ebtablesd: the maximum command line length is %d", EBTD_CMDLINE_MAXLN-1); goto write_msg; } memmove(cmdline, cmdline+base+offset, ntot-offset); offset -= base; offset++; base = 0; continue; } table_nr = 0; n2 = 0; argc = 0; while (n2 < n && argc < EBTD_ARGC_MAX) { if (*(cmdline + base + n2) == '\0') { n2++; continue; } argv[argc++] = cmdline + base + n2; n2 += strlen(cmdline + base + n2) + 1; } offset++; base = offset; if (argc > EBTD_ARGC_MAX) { ebt_print_error("ebtablesd: maximum %d arguments " "allowed", EBTD_ARGC_MAX - 1); goto write_msg; } if (argc == 1) { ebt_print_error("ebtablesd: no arguments"); goto write_msg; } if (!strcmp(argv[1], "-t")) { if (argc < 3) { ebt_print_error("ebtablesd: -t but no table"); goto write_msg; } for (i = 0; i < 3; i++) if (!strcmp(replace[i].name, argv[2])) break; if (i == 3) { ebt_print_error("ebtablesd: table '%s' was " "not recognized", argv[2]); goto write_msg; } table_nr = i; } else if (!strcmp(argv[1], "free")) { if (argc != 3) { ebt_print_error("ebtablesd: command free " "needs exactly one argument"); goto write_msg; } for (i = 0; i < 3; i++) if (!strcmp(replace[i].name, argv[2])) break; if (i == 3) { ebt_print_error("ebtablesd: table '%s' was " "not recognized", argv[2]); goto write_msg; } if (!(replace[i].flags & OPT_KERNELDATA)) { ebt_print_error("ebtablesd: table %s has not " "been opened"); goto write_msg; } ebt_cleanup_replace(&replace[i]); copy_table_names(); replace[i].flags &= ~OPT_KERNELDATA; goto write_msg; } else if (!strcmp(argv[1], "open")) { if (argc != 3) { ebt_print_error("ebtablesd: command open " "needs exactly one argument"); goto write_msg; } for (i = 0; i < 3; i++) if (!strcmp(replace[i].name, argv[2])) break; if (i == 3) { ebt_print_error("ebtablesd: table '%s' was " "not recognized", argv[2]); goto write_msg; } if (replace[i].flags & OPT_KERNELDATA) { ebt_print_error("ebtablesd: table %s needs to " "be freed before it can be " "opened"); goto write_msg; } if (!ebt_get_kernel_table(&replace[i], 0)) { replace[i].flags |= OPT_KERNELDATA; open_method[i] = OPEN_METHOD_KERNEL; } goto write_msg; } else if (!strcmp(argv[1], "fopen")) { struct ebt_u_replace tmp; memset(&tmp, 0, sizeof(tmp)); if (argc != 4) { ebt_print_error("ebtablesd: command fopen " "needs exactly two arguments"); goto write_msg; } for (i = 0; i < 3; i++) if (!strcmp(replace[i].name, argv[2])) break; if (i == 3) { ebt_print_error("ebtablesd: table '%s' was " "not recognized", argv[2]); goto write_msg; } if (replace[i].flags & OPT_KERNELDATA) { ebt_print_error("ebtablesd: table %s needs to " "be freed before it can be " "opened"); goto write_msg; } tmp.filename = (char *)malloc(strlen(argv[3]) + 1); if (!tmp.filename) { ebt_print_error("Out of memory"); goto write_msg; } strcpy(tmp.filename, argv[3]); strcpy(tmp.name, "filter"); tmp.command = 'L'; ebt_get_kernel_table(&tmp, 0); free(tmp.filename); tmp.filename = NULL; if (ebt_errormsg[0] != '\0') goto write_msg; if (strcmp(tmp.name, argv[2])) { ebt_print_error("ebtablesd: opened file with " "wrong table name '%s'", tmp.name); ebt_cleanup_replace(&tmp); goto write_msg; } replace[i] = tmp; replace[i].command = '\0'; replace[i].flags |= OPT_KERNELDATA; open_method[i] = OPEN_METHOD_FILE; goto write_msg; } else if (!strcmp(argv[1], "commit")) { if (argc != 3) { ebt_print_error("ebtablesd: command commit " "needs exactly one argument"); goto write_msg; } for (i = 0; i < 3; i++) if (!strcmp(replace[i].name, argv[2])) break; if (i == 3) { ebt_print_error("ebtablesd: table '%s' was " "not recognized", argv[2]); goto write_msg; } if (!(replace[i].flags & OPT_KERNELDATA)) { ebt_print_error("ebtablesd: table %s has not " "been opened"); goto write_msg; } if (open_method[i] == OPEN_METHOD_FILE) replace[i].num_counters = 0; ebt_deliver_table(&replace[i]); if (ebt_errormsg[0] == '\0' && open_method[i] == OPEN_METHOD_KERNEL) ebt_deliver_counters(&replace[i]); goto write_msg; } else if (!strcmp(argv[1], "fcommit")) { if (argc != 4) { ebt_print_error("ebtablesd: command commit " "needs exactly two argument"); goto write_msg; } for (i = 0; i < 3; i++) if (!strcmp(replace[i].name, argv[2])) break; if (i == 3) { ebt_print_error("ebtablesd: table '%s' was " "not recognized", argv[2]); goto write_msg; } if (!(replace[i].flags & OPT_KERNELDATA)) { ebt_print_error("ebtablesd: table %s has not " "been opened"); goto write_msg; } replace[i].filename = (char *)malloc(strlen(argv[3]) + 1); if (!replace[i].filename) { ebt_print_error("Out of memory"); goto write_msg; } strcpy(replace[i].filename, argv[3]); ebt_deliver_table(&replace[i]); if (ebt_errormsg[0] == '\0' && open_method[i] == OPEN_METHOD_KERNEL) ebt_deliver_counters(&replace[i]); free(replace[i].filename); replace[i].filename = NULL; goto write_msg; }else if (!strcmp(argv[1], "quit")) { if (argc != 2) { ebt_print_error("ebtablesd: command quit does " "not take any arguments"); goto write_msg; } break; } if (!(replace[table_nr].flags & OPT_KERNELDATA)) { ebt_print_error("ebtablesd: table %s has not been " "opened", replace[table_nr].name); goto write_msg; } optind = 0; do_command(argc, argv, EXEC_STYLE_DAEMON, &replace[table_nr]); ebt_reinit_extensions(); write_msg: #ifndef SILENT_DAEMON if (ebt_errormsg[0] != '\0') printf("%s.\n", ebt_errormsg); #endif ebt_errormsg[0]= '\0'; n = 0; goto continue_read; } do_exit: unlink(EBTD_PIPE); return 0; }
static int parse(int c, char **argv, int argc, const struct ebt_u_entry *entry, unsigned int *flags, struct ebt_entry_match **match) { struct ebt_among_info *info = (struct ebt_among_info *) (*match)->data; struct ebt_mac_wormhash *wh; struct ebt_entry_match *h; int new_size; long flen; int fd; switch (c) { case AMONG_DST_F: case AMONG_SRC_F: case AMONG_DST: case AMONG_SRC: if (c == AMONG_DST || c == AMONG_DST_F) { ebt_check_option2(flags, OPT_DST); } else { ebt_check_option2(flags, OPT_SRC); } if (ebt_check_inverse2(optarg)) { if (c == AMONG_DST || c == AMONG_DST_F) info->bitmask |= EBT_AMONG_DST_NEG; else info->bitmask |= EBT_AMONG_SRC_NEG; } if (c == AMONG_DST_F || c == AMONG_SRC_F) { struct stat stats; if ((fd = open(optarg, O_RDONLY)) == -1) ebt_print_error("Couldn't open file '%s'", optarg); fstat(fd, &stats); flen = stats.st_size; /* use mmap because the file will probably be big */ optarg = mmap(0, flen, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); if (optarg == MAP_FAILED) ebt_print_error("Couldn't map file to memory"); if (optarg[flen-1] != '\n') ebt_print_error("File should end with a newline"); if (strchr(optarg, '\n') != optarg+flen-1) ebt_print_error("File should only contain one line"); optarg[flen-1] = '\0'; if (ebt_errormsg[0] != '\0') { munmap(argv, flen); close(fd); exit(-1); } } wh = create_wormhash(optarg); if (ebt_errormsg[0] != '\0') break; new_size = old_size+ebt_mac_wormhash_size(wh); h = malloc(sizeof(struct ebt_entry_match)+EBT_ALIGN(new_size)); if (!h) ebt_print_memory(); memcpy(h, *match, old_size+sizeof(struct ebt_entry_match)); memcpy((char *)h+old_size+sizeof(struct ebt_entry_match), wh, ebt_mac_wormhash_size(wh)); h->match_size = EBT_ALIGN(new_size); info = (struct ebt_among_info *) h->data; if (c == AMONG_DST) { info->wh_dst_ofs = old_size; } else { info->wh_src_ofs = old_size; } old_size = new_size; free(*match); *match = h; free(wh); if (c == AMONG_DST_F || c == AMONG_SRC_F) { munmap(argv, flen); close(fd); } break; default: return 0; } return 1; }
void ebt_check_option(unsigned int *flags, unsigned int mask) { if (*flags & mask) ebt_print_error("Multiple use of same option not allowed"); *flags |= mask; }