/* cannot do this via _init, else static builds might spew error message * for every iptables invocation. */ static int connlabel_open(void) { const char *fname; if (map) return 0; map = nfct_labelmap_new(NULL); if (map != NULL) return 0; fname = nfct_labels_get_path(); if (errno) { fprintf(stderr, "Warning: cannot open %s: %s\n", fname, strerror(errno)); } else { xtables_error(RESOURCE_PROBLEM, "cannot parse %s: no labels found", fname); } return 1; }
static uint32_t ct_parse_events(const struct event_tbl *tbl, unsigned int size, const char *events) { char str[strlen(events) + 1], *e = str, *t; unsigned int mask = 0, i; strcpy(str, events); while ((t = strsep(&e, ","))) { for (i = 0; i < size; i++) { if (strcmp(t, tbl[i].name)) continue; mask |= 1 << tbl[i].event; break; } if (i == size) xtables_error(PARAMETER_PROBLEM, "Unknown event type \"%s\"", t); } return mask; }
static int icmp_parse(int c, char **argv, int invert, unsigned int *flags, const void *entry, struct xt_entry_match **match) { struct ipt_icmp *icmpinfo = (struct ipt_icmp *)(*match)->data; switch (c) { case '1': if (*flags == 1) xtables_error(PARAMETER_PROBLEM, "icmp match: only use --icmp-type once!"); xtables_check_inverse(optarg, &invert, &optind, 0, argv); parse_icmp(optarg, &icmpinfo->type, icmpinfo->code); if (invert) icmpinfo->invflags |= IPT_ICMP_INV; *flags = 1; break; } return 1; }
static void MYSNAT_parse(struct xt_option_call *cb) { const struct ipt_entry *entry = cb->xt_entry; struct ipt_natinfo *info = (void *)(*cb->target); int portok; if (entry->ip.proto == IPPROTO_TCP || entry->ip.proto == IPPROTO_UDP || entry->ip.proto == IPPROTO_SCTP || entry->ip.proto == IPPROTO_DCCP || entry->ip.proto == IPPROTO_ICMP) portok = 1; else portok = 0; xtables_option_parse(cb); switch (cb->entry->id) { case O_TO_SRC: if (cb->xflags & F_X_TO_SRC) { if (!kernel_version) get_kernel_version(); if (kernel_version > LINUX_VERSION(2, 6, 10)) xtables_error(PARAMETER_PROBLEM, "MYSNAT: Multiple --to-source not supported"); } *cb->target = parse_to(cb->arg, portok, info); /* WTF do we need this for?? */ if (cb->xflags & F_RANDOM) info->mr.range[0].flags |= IP_NAT_RANGE_PROTO_RANDOM; cb->xflags |= F_X_TO_SRC; break; case O_RANDOM: if (cb->xflags & F_TO_SRC) info->mr.range[0].flags |= IP_NAT_RANGE_PROTO_RANDOM; break; case O_PERSISTENT: info->mr.range[0].flags |= IP_NAT_RANGE_PERSISTENT; break; } }
static void ct_parse_zone_id(const char *opt, unsigned int opt_id, uint16_t *zone_id, uint16_t *flags) { if (opt_id == O_ZONE_ORIG) *flags |= XT_CT_ZONE_DIR_ORIG; if (opt_id == O_ZONE_REPLY) *flags |= XT_CT_ZONE_DIR_REPL; *zone_id = 0; if (strcasecmp(opt, "mark") == 0) { *flags |= XT_CT_ZONE_MARK; } else { uintmax_t val; if (!xtables_strtoul(opt, NULL, &val, 0, UINT16_MAX)) xtables_error(PARAMETER_PROBLEM, "Cannot parse %s as a zone ID\n", opt); *zone_id = (uint16_t)val; } }
static void conntrack1_mt_parse(struct xt_option_call *cb) { struct xt_conntrack_mtinfo1 *info = cb->data; struct xt_conntrack_mtinfo3 up; memset(&up, 0, sizeof(up)); cinfo_transform(&up, info); up.origsrc_port_high = up.origsrc_port; up.origdst_port_high = up.origdst_port; up.replsrc_port_high = up.replsrc_port; up.repldst_port_high = up.repldst_port; cb->data = &up; conntrack_mt_parse(cb, 3); if (up.origsrc_port != up.origsrc_port_high || up.origdst_port != up.origdst_port_high || up.replsrc_port != up.replsrc_port_high || up.repldst_port != up.repldst_port_high) xtables_error(PARAMETER_PROBLEM, "conntrack rev 1 does not support port ranges"); cinfo_transform(info, &up); cb->data = info; }
static void brmark_print(const void *ip, const struct xt_entry_target *target, int numeric) { struct ebt_mark_t_info *info = (struct ebt_mark_t_info *)target->data; int tmp; tmp = info->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 xtables_error(PARAMETER_PROBLEM, "Unknown mark action"); printf(" 0x%lx", info->mark); tmp = info->target | ~EBT_VERDICT_BITS; printf(" --mark-target %s", ebt_target_name(tmp)); }
static void parse_udp_ports(const char *portstring, u_int16_t *ports) { char *buffer; char *cp; buffer = strdup(portstring); if ((cp = strchr(buffer, ':')) == NULL) ports[0] = ports[1] = xtables_parse_port(buffer, "udp"); else { *cp = '\0'; cp++; ports[0] = buffer[0] ? xtables_parse_port(buffer, "udp") : 0; ports[1] = cp[0] ? xtables_parse_port(cp, "udp") : 0xFFFF; if (ports[0] > ports[1]) xtables_error(PARAMETER_PROBLEM, "invalid portrange (min > max)"); } free(buffer); }
/* Debugging prototype. */ static int for_each_table(int (*func)(const char *tablename)) { int ret = 1; FILE *procfile = NULL; char tablename[XT_TABLE_MAXNAMELEN+1]; procfile = fopen("/proc/net/ip6_tables_names", "re"); if (!procfile) return ret; while (fgets(tablename, sizeof(tablename), procfile)) { if (tablename[strlen(tablename) - 1] != '\n') xtables_error(OTHER_PROBLEM, "Badly formed tablename `%s'\n", tablename); tablename[strlen(tablename) - 1] = '\0'; ret &= func(tablename); } fclose(procfile); return ret; }
static int comment_parse(int c, char **argv, int invert, unsigned int *flags, const void *entry, struct xt_entry_match **match) { struct xt_comment_info *commentinfo = (struct xt_comment_info *)(*match)->data; switch (c) { case '1': xtables_check_inverse(argv[optind-1], &invert, &optind, 0); if (invert) { xtables_error(PARAMETER_PROBLEM, "Sorry, you can't have an inverted comment"); } parse_comment(argv[optind-1], commentinfo); *flags = 1; break; default: return 0; } return 1; }
static void iprange_parse_range(const char *oarg, union nf_inet_addr *range, uint8_t family, const char *optname) { char *arg = strdup(oarg); char *dash; if (arg == NULL) xtables_error(RESOURCE_PROBLEM, "strdup"); dash = strchr(arg, '-'); if (dash == NULL) { iprange_parse_spec(arg, arg, range, family, optname); free(arg); return; } *dash = '\0'; iprange_parse_spec(arg, dash + 1, range, family, optname); if (memcmp(&range[0], &range[1], sizeof(*range)) > 0) fprintf(stderr, "xt_iprange: range %s-%s is reversed and " "will never match\n", arg, dash + 1); free(arg); }
static int ah_parse(int c, char **argv, int invert, unsigned int *flags, const void *entry, struct xt_entry_match **match) { struct ipt_ah *ahinfo = (struct ipt_ah *)(*match)->data; switch (c) { case '1': if (*flags & AH_SPI) xtables_error(PARAMETER_PROBLEM, "Only one `--ahspi' allowed"); xtables_check_inverse(optarg, &invert, &optind, 0, argv); parse_ah_spis(optarg, ahinfo->spis); if (invert) ahinfo->invflags |= IPT_AH_INV_SPI; *flags |= AH_SPI; break; default: return 0; } return 1; }
static void REJECT_parse(struct xt_option_call *cb) { struct ipt_reject_info *reject = cb->data; unsigned int i; xtables_option_parse(cb); for (i = 0; i < ARRAY_SIZE(reject_table); ++i) if (strncasecmp(reject_table[i].name, cb->arg, strlen(cb->arg)) == 0 || strncasecmp(reject_table[i].alias, cb->arg, strlen(cb->arg)) == 0) { reject->with = reject_table[i].with; return; } /* This due to be dropped late in 2.4 pre-release cycle --RR */ if (strncasecmp("echo-reply", cb->arg, strlen(cb->arg)) == 0 || strncasecmp("echoreply", cb->arg, strlen(cb->arg)) == 0) fprintf(stderr, "--reject-with echo-reply no longer" " supported\n"); xtables_error(PARAMETER_PROBLEM, "unknown reject type \"%s\"", cb->arg); }
static void ULOG_parse(struct xt_option_call *cb) { struct ipt_ulog_info *loginfo = cb->data; xtables_option_parse(cb); switch (cb->entry->id) { case O_ULOG_NLGROUP: loginfo->nl_group = 1 << (cb->val.u8 - 1); break; case O_ULOG_PREFIX: if (strchr(cb->arg, '\n') != NULL) xtables_error(PARAMETER_PROBLEM, "Newlines not allowed in --ulog-prefix"); break; case O_ULOG_CPRANGE: loginfo->copy_range = cb->val.u64; break; case O_ULOG_QTHR: loginfo->qthreshold = cb->val.u64; break; } }
/* Function which parses command options; returns true if it ate an option */ static int daddr_tg_parse(int c, char **argv, int invert, unsigned int *flags, const void *entry, struct xt_entry_target **target, parse_daddr_fn da_fn) { struct xt_daddr_tginfo *daddrinfo = (struct xt_daddr_tginfo *)(*target)->data; switch (c) { case '1': if (*flags) xtables_error(PARAMETER_PROBLEM, "DADDR target: Cant specify --set-daddr twice"); (da_fn)(optarg, daddrinfo); *flags = 1; break; default: return 0; } return 1; }
static int dns_parse(int c, char **argv, int invert, unsigned int *flags, const void *entry, struct xt_entry_match **match) { struct xt_dns_info *dnsinfo = (struct xt_dns_info *)(*match)->data; switch (c) { case '1': xtables_check_inverse(optarg, &invert, &optind, 0, argv); if (str2qn(optarg, dnsinfo->fqdn, sizeof(dnsinfo->fqdn))) xtables_error(PARAMETER_PROBLEM, "--dns-fqdn invalid " "fqdn"); if (invert) dnsinfo->invert = 1; *flags = 1; break; default: return 0; } return 1; }
static int mh_parse(int c, char **argv, int invert, unsigned int *flags, const void *entry, struct xt_entry_match **match) { struct ip6t_mh *mhinfo = (struct ip6t_mh *)(*match)->data; switch (c) { case '1': if (*flags & MH_TYPES) xtables_error(PARAMETER_PROBLEM, "Only one `--mh-type' allowed"); xtables_check_inverse(optarg, &invert, &optind, 0, argv); parse_mh_types(optarg, mhinfo->types); if (invert) mhinfo->invflags |= IP6T_MH_INV_TYPE; *flags |= MH_TYPES; break; default: return 0; } return 1; }
static void connlabel_mt_parse(struct xt_option_call *cb) { struct xt_connlabel_mtinfo *info = cb->data; int tmp; connlabel_open(); xtables_option_parse(cb); switch (cb->entry->id) { case O_LABEL: tmp = nfct_labelmap_get_bit(map, cb->arg); if (tmp < 0) xtables_error(PARAMETER_PROBLEM, "label '%s' not found", cb->arg); info->bit = tmp; if (cb->invert) info->options |= XT_CONNLABEL_OP_INVERT; break; case O_SET: info->options |= XT_CONNLABEL_OP_SET; break; } }
static uint16_t parse_dccp_types(const char *typestring) { uint16_t typemask = 0; char *ptr, *buffer; buffer = strdup(typestring); for (ptr = strtok(buffer, ","); ptr; ptr = strtok(NULL, ",")) { unsigned int i; for (i = 0; i < ARRAY_SIZE(dccp_pkt_types); ++i) if (!strcasecmp(dccp_pkt_types[i], ptr)) { typemask |= (1 << i); break; } if (i == ARRAY_SIZE(dccp_pkt_types)) xtables_error(PARAMETER_PROBLEM, "Unknown DCCP type `%s'", ptr); } free(buffer); return typemask; }
static void conntrack_ps_expires(struct xt_conntrack_mtinfo2 *info, const char *s) { unsigned int min, max; char *end; if (!xtables_strtoui(s, &end, &min, 0, UINT32_MAX)) xtables_param_act(XTF_BAD_VALUE, "conntrack", "--expires", s); max = min; if (*end == ':') if (!xtables_strtoui(s, &end, &max, 0, UINT32_MAX)) xtables_param_act(XTF_BAD_VALUE, "conntrack", "--expires", s); if (*end != '\0') xtables_param_act(XTF_BAD_VALUE, "conntrack", "--expires", s); if (min > max) xtables_error(PARAMETER_PROBLEM, "expire min. range value \"%u\" greater than max. " "range value \"%u\"", min, max); info->expires_min = min; info->expires_max = max; }
static int tos_tg_parse_v0(int c, char **argv, int invert, unsigned int *flags, const void *entry, struct xt_entry_target **target) { struct ipt_tos_target_info *info = (void *)(*target)->data; struct tos_value_mask tvm; switch (c) { case '=': xtables_param_act(XTF_ONLY_ONCE, "TOS", "--set-tos", *flags & FLAG_TOS); xtables_param_act(XTF_NO_INVERT, "TOS", "--set-tos", invert); if (!tos_parse_symbolic(optarg, &tvm, 0xFF)) xtables_param_act(XTF_BAD_VALUE, "TOS", "--set-tos", optarg); if (tvm.mask != 0xFF) xtables_error(PARAMETER_PROBLEM, "tos match: Your kernel " "is too old to support anything besides " "/0xFF as a mask."); info->tos = tvm.value; *flags |= FLAG_TOS; return true; } return false; }
static void parse_tos(const char *s, struct ipt_tos_target_info *info) { unsigned int i, tos; if (xtables_strtoui(s, NULL, &tos, 0, UINT8_MAX)) { if (tos == IPTOS_LOWDELAY || tos == IPTOS_THROUGHPUT || tos == IPTOS_RELIABILITY || tos == IPTOS_MINCOST || tos == IPTOS_NORMALSVC) { info->tos = (u_int8_t )tos; return; } } else { for (i = 0; i<sizeof(TOS_values)/sizeof(struct TOS_value); i++) if (strcasecmp(s,TOS_values[i].name) == 0) { info->tos = TOS_values[i].TOS; return; } } xtables_error(PARAMETER_PROBLEM, "Bad TOS value `%s'", s); }
/* Function which parses command options; returns true if it ate an option */ static int parse(int c, char **argv, int invert, unsigned int *flags, const void *entry, struct xt_entry_target **target) { struct ipt_tos_target_info *tosinfo = (struct ipt_tos_target_info *)(*target)->data; switch (c) { case '1': if (*flags) xtables_error(PARAMETER_PROBLEM, "TOS target: Cant specify --set-tos twice"); parse_tos(optarg, tosinfo); *flags = 1; break; default: return 0; } return 1; }
static int ct_parse(int c, char **argv, int invert, unsigned int *flags, const void *entry, struct xt_entry_target **target) { struct xt_ct_target_info *info = (struct xt_ct_target_info *)(*target)->data; unsigned int zone; switch (c) { case CT_OPT_NOTRACK: xtables_param_act(XTF_ONLY_ONCE, "CT", "--notrack", *flags & CT_OPT_NOTRACK); info->flags |= XT_CT_NOTRACK; break; case CT_OPT_HELPER: xtables_param_act(XTF_ONLY_ONCE, "CT", "--helper", *flags & CT_OPT_HELPER); strncpy(info->helper, optarg, sizeof(info->helper)); info->helper[sizeof(info->helper) - 1] = '\0'; break; case CT_OPT_CTEVENTS: xtables_param_act(XTF_ONLY_ONCE, "CT", "--ctevents", *flags & CT_OPT_CTEVENTS); info->ct_events = ct_parse_events(ct_event_tbl, ARRAY_SIZE(ct_event_tbl), optarg); break; case CT_OPT_EXPEVENTS: xtables_param_act(XTF_ONLY_ONCE, "CT", "--expevents", *flags & CT_OPT_EXPEVENTS); info->exp_events = ct_parse_events(exp_event_tbl, ARRAY_SIZE(exp_event_tbl), optarg); break; case CT_OPT_ZONE: xtables_param_act(XTF_ONLY_ONCE, "CT", "--zone", *flags & CT_OPT_ZONE); if (!xtables_strtoui(optarg, NULL, &zone, 0, UINT16_MAX)) xtables_error(PARAMETER_PROBLEM, "Bad zone value \"%s\"", optarg); info->zone = zone; break; default: return 0; } *flags |= c; return 1; }
static void parse_interface(const char *arg, char *vianame, unsigned char *mask) { int vialen = strlen(arg); unsigned int i; memset(mask, 0, IFNAMSIZ); memset(vianame, 0, IFNAMSIZ); if (vialen + 1 > IFNAMSIZ) xtables_error(PARAMETER_PROBLEM, "interface name `%s' must be shorter than IFNAMSIZ" " (%i)", arg, IFNAMSIZ-1); strcpy(vianame, arg); if (vialen == 0) memset(mask, 0, IFNAMSIZ); else if (vianame[vialen - 1] == '+') { memset(mask, 0xFF, vialen - 1); memset(mask + vialen - 1, 0, IFNAMSIZ - vialen + 1); /* Don't remove `+' here! -HW */ } else { /* Include nul-terminator in match */ memset(mask, 0xFF, vialen + 1); memset(mask + vialen + 1, 0, IFNAMSIZ - vialen - 1); for (i = 0; vianame[i]; i++) { if (!isalnum(vianame[i]) && vianame[i] != '_' && vianame[i] != '.') { printf("Warning: wierd character in interface" " `%s' (No aliases, :, ! or *).\n", vianame); break; } } } }
static int length_parse(int c, char **argv, int invert, unsigned int *flags, const void *entry, struct xt_entry_match **match) { struct xt_length_info *info = (struct xt_length_info *)(*match)->data; switch (c) { case '1': if (*flags) xtables_error(PARAMETER_PROBLEM, "length: `--length' may only be " "specified once"); xtables_check_inverse(optarg, &invert, &optind, 0); parse_lengths(argv[optind-1], info); if (invert) info->invert = 1; *flags = 1; break; default: return 0; } return 1; }
static int tcpmss_parse(int c, char **argv, int invert, unsigned int *flags, const void *entry, struct xt_entry_match **match) { struct xt_tcpmss_match_info *mssinfo = (struct xt_tcpmss_match_info *)(*match)->data; switch (c) { case '1': if (*flags) xtables_error(PARAMETER_PROBLEM, "Only one `--mss' allowed"); xtables_check_inverse(optarg, &invert, &optind, 0, argv); parse_tcp_mssvalues(optarg, &mssinfo->mss_min, &mssinfo->mss_max); if (invert) mssinfo->invert = 1; *flags = 1; break; default: return 0; } return 1; }
/* If a single value is provided, min and max are both set to the value */ static void parse_lengths(const char *s, struct xt_length_info *info) { char *buffer; char *cp; buffer = strdup(s); if ((cp = strchr(buffer, ':')) == NULL) info->min = info->max = parse_length(buffer); else { *cp = '\0'; cp++; info->min = buffer[0] ? parse_length(buffer) : 0; info->max = cp[0] ? parse_length(cp) : 0xFFFF; } free(buffer); if (info->min > info->max) xtables_error(PARAMETER_PROBLEM, "length min. range value `%u' greater than max. " "range value `%u'", info->min, info->max); }
static int helper_parse(int c, char **argv, int invert, unsigned int *flags, const void *entry, struct xt_entry_match **match) { struct xt_helper_info *info = (struct xt_helper_info *)(*match)->data; switch (c) { case '1': if (*flags) xtables_error(PARAMETER_PROBLEM, "helper match: Only use --helper ONCE!"); xtables_check_inverse(optarg, &invert, &invert, 0); strncpy(info->name, optarg, 29); info->name[29] = '\0'; if (invert) info->invert = 1; *flags = 1; break; default: return 0; } return 1; }
static unsigned int parse_tcp_flag(const char *flags) { unsigned int ret = 0; char *ptr; char *buffer; buffer = strdup(flags); for (ptr = strtok(buffer, ","); ptr; ptr = strtok(NULL, ",")) { unsigned int i; for (i = 0; i < ARRAY_SIZE(tcp_flag_names); ++i) if (strcasecmp(tcp_flag_names[i].name, ptr) == 0) { ret |= tcp_flag_names[i].flag; break; } if (i == ARRAY_SIZE(tcp_flag_names)) xtables_error(PARAMETER_PROBLEM, "Unknown TCP flag `%s'", ptr); } free(buffer); return ret; }