/* Convert 'str_' (as described in the Flow Syntax section of the ovs-ofctl man * page) into 'fm' for sending the specified flow_mod 'command' to a switch. * If 'actions' is specified, an action must be in 'string' and may be expanded * or reallocated. * * To parse syntax for an OFPT_FLOW_MOD (or NXT_FLOW_MOD), use an OFPFC_* * constant for 'command'. To parse syntax for an OFPST_FLOW or * OFPST_AGGREGATE (or NXST_FLOW or NXST_AGGREGATE), use -1 for 'command'. */ void parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_, bool verbose) { enum { F_OUT_PORT = 1 << 0, F_ACTIONS = 1 << 1, F_TIMEOUT = 1 << 3, F_PRIORITY = 1 << 4, F_FLAGS = 1 << 5, } fields; char *string = xstrdup(str_); char *save_ptr = NULL; char *act_str = NULL; char *name; switch (command) { case -1: fields = F_OUT_PORT; break; case OFPFC_ADD: fields = F_ACTIONS | F_TIMEOUT | F_PRIORITY | F_FLAGS; break; case OFPFC_DELETE: fields = F_OUT_PORT; break; case OFPFC_DELETE_STRICT: fields = F_OUT_PORT | F_PRIORITY; break; case OFPFC_MODIFY: fields = F_ACTIONS | F_TIMEOUT | F_PRIORITY | F_FLAGS; break; case OFPFC_MODIFY_STRICT: fields = F_ACTIONS | F_TIMEOUT | F_PRIORITY | F_FLAGS; break; default: NOT_REACHED(); } match_init_catchall(&fm->match); fm->priority = OFP_DEFAULT_PRIORITY; fm->cookie = htonll(0); fm->cookie_mask = htonll(0); if (command == OFPFC_MODIFY || command == OFPFC_MODIFY_STRICT) { /* For modify, by default, don't update the cookie. */ fm->new_cookie = htonll(UINT64_MAX); } else{ fm->new_cookie = htonll(0); } fm->table_id = 0xff; fm->command = command; fm->idle_timeout = OFP_FLOW_PERMANENT; fm->hard_timeout = OFP_FLOW_PERMANENT; fm->buffer_id = UINT32_MAX; fm->out_port = OFPP_NONE; fm->flags = 0; if (fields & F_ACTIONS) { act_str = strstr(string, "action"); if (!act_str) { ofp_fatal(str_, verbose, "must specify an action"); } *act_str = '\0'; act_str = strchr(act_str + 1, '='); if (!act_str) { ofp_fatal(str_, verbose, "must specify an action"); } act_str++; } for (name = strtok_r(string, "=, \t\r\n", &save_ptr); name; name = strtok_r(NULL, "=, \t\r\n", &save_ptr)) { const struct protocol *p; if (parse_protocol(name, &p)) { match_set_dl_type(&fm->match, htons(p->dl_type)); if (p->nw_proto) { match_set_nw_proto(&fm->match, p->nw_proto); } } else if (fields & F_FLAGS && !strcmp(name, "send_flow_rem")) { fm->flags |= OFPFF_SEND_FLOW_REM; } else if (fields & F_FLAGS && !strcmp(name, "check_overlap")) { fm->flags |= OFPFF_CHECK_OVERLAP; } else { char *value; value = strtok_r(NULL, ", \t\r\n", &save_ptr); if (!value) { ofp_fatal(str_, verbose, "field %s missing value", name); } if (!strcmp(name, "table")) { fm->table_id = str_to_table_id(value); } else if (!strcmp(name, "out_port")) { if (!ofputil_port_from_string(name, &fm->out_port)) { ofp_fatal(str_, verbose, "%s is not a valid OpenFlow port", name); } } else if (fields & F_PRIORITY && !strcmp(name, "priority")) { fm->priority = str_to_u16(value, name); } else if (fields & F_TIMEOUT && !strcmp(name, "idle_timeout")) { fm->idle_timeout = str_to_u16(value, name); } else if (fields & F_TIMEOUT && !strcmp(name, "hard_timeout")) { fm->hard_timeout = str_to_u16(value, name); } else if (!strcmp(name, "cookie")) { char *mask = strchr(value, '/'); if (mask) { /* A mask means we're searching for a cookie. */ if (command == OFPFC_ADD) { ofp_fatal(str_, verbose, "flow additions cannot use " "a cookie mask"); } *mask = '\0'; fm->cookie = htonll(str_to_u64(value)); fm->cookie_mask = htonll(str_to_u64(mask+1)); } else { /* No mask means that the cookie is being set. */ if (command != OFPFC_ADD && command != OFPFC_MODIFY && command != OFPFC_MODIFY_STRICT) { ofp_fatal(str_, verbose, "cannot set cookie"); } fm->new_cookie = htonll(str_to_u64(value)); } } else if (mf_from_name(name)) { parse_field(mf_from_name(name), value, &fm->match); } else if (!strcmp(name, "duration") || !strcmp(name, "n_packets") || !strcmp(name, "n_bytes")) { /* Ignore these, so that users can feed the output of * "ovs-ofctl dump-flows" back into commands that parse * flows. */ } else { ofp_fatal(str_, verbose, "unknown keyword %s", name); } } } if (!fm->cookie_mask && fm->new_cookie == htonll(UINT64_MAX) && (command == OFPFC_MODIFY || command == OFPFC_MODIFY_STRICT)) { /* On modifies without a mask, we are supposed to add a flow if * one does not exist. If a cookie wasn't been specified, use a * default of zero. */ fm->new_cookie = htonll(0); } if (fields & F_ACTIONS) { struct ofpbuf ofpacts; ofpbuf_init(&ofpacts, 32); str_to_inst_ofpacts(&fm->match.flow, act_str, &ofpacts); fm->ofpacts_len = ofpacts.size; fm->ofpacts = ofpbuf_steal_data(&ofpacts); } else { fm->ofpacts_len = 0; fm->ofpacts = NULL; } free(string); }
static const struct token * match_token(char *word, const struct token table[]) { u_int i, match = 0; unsigned long int ulval; const struct token *t = NULL; char *ep; for (i = 0; table[i].type != ENDTOKEN; i++) { switch (table[i].type) { case NOTOKEN: if (word == NULL || strlen(word) == 0) { match++; t = &table[i]; } break; case KEYWORD: if (word != NULL && strncmp(word, table[i].keyword, strlen(word)) == 0) { match++; t = &table[i]; if (t->value) res.action = t->value; } break; case PPP_ID: if (word == NULL) break; errno = 0; ulval = strtoul(word, &ep, 10); if (isdigit((unsigned char)*word) && *ep == '\0' && !(errno == ERANGE && ulval == ULONG_MAX)) { res.ppp_id = ulval; res.has_ppp_id = 1; match++; t = &table[i]; } break; case ADDRESS: { struct sockaddr_in sin4 = { .sin_family = AF_INET, .sin_len = sizeof(struct sockaddr_in) }; struct sockaddr_in6 sin6 = { .sin6_family = AF_INET6, .sin6_len = sizeof(struct sockaddr_in6) }; if (word == NULL) break; if (inet_pton(AF_INET, word, &sin4.sin_addr) == 1) memcpy(&res.address, &sin4, sin4.sin_len); else if (inet_pton(AF_INET6, word, &sin6.sin6_addr) == 1) memcpy(&res.address, &sin6, sin6.sin6_len); else break; match++; t = &table[i]; } break; case INTERFACE: if (word == NULL) break; res.interface = word; match++; t = &table[i]; break; case PROTOCOL: if (word == NULL) break; if ((res.protocol = parse_protocol(word)) == PROTO_UNSPEC) break; match++; t = &table[i]; break; case REALM: if (word == NULL) break; res.realm = word; match++; t = &table[i]; break; case USERNAME: if (word == NULL) break; res.username = word; match++; t = &table[i]; break; case ENDTOKEN: break; } } if (match != 1) { if (word == NULL) fprintf(stderr, "missing argument:\n"); else if (match > 1) fprintf(stderr, "ambiguous argument: %s\n", word); else if (match < 1) fprintf(stderr, "unknown argument: %s\n", word); return (NULL); } return (t); } static void show_valid_args(const struct token table[]) { int i; for (i = 0; table[i].type != ENDTOKEN; i++) { switch (table[i].type) { case NOTOKEN: fprintf(stderr, " <cr>\n"); break; case KEYWORD: fprintf(stderr, " %s\n", table[i].keyword); break; case PPP_ID: fprintf(stderr, " <ppp-id>\n"); break; case ADDRESS: fprintf(stderr, " <address>\n"); break; case INTERFACE: fprintf(stderr, " <interface>\n"); break; case PROTOCOL: fprintf(stderr, " [ pppoe | l2tp | pptp | sstp ]\n"); break; case REALM: fprintf(stderr, " <realm>\n"); break; case USERNAME: fprintf(stderr, " <username>\n"); break; case ENDTOKEN: break; } } } enum protocol parse_protocol(const char *str) { return (strcasecmp(str, "PPTP" ) == 0)? PPTP : (strcasecmp(str, "L2TP" ) == 0)? L2TP : (strcasecmp(str, "PPPoE") == 0)? PPPOE : (strcasecmp(str, "SSTP" ) == 0)? SSTP : PROTO_UNSPEC; }
static ret_t cherokee_url_parse_guts (cherokee_url_t *url, cherokee_buffer_t *url_buf, cherokee_buffer_t *user_ret, cherokee_buffer_t *password_ret) { ret_t ret; cuint_t len = 0 ; char *port; char *slash; char *server; char *arroba; char *tmp; /* Drop protocol, if exists.. */ ret = parse_protocol (url, url_buf->buf, &len); if (unlikely(ret < ret_ok)) return ret_error; tmp = url_buf->buf + len; /* User (and password) */ arroba = strchr (tmp, '@'); if (arroba != NULL) { char *sep; sep = strchr (tmp, ':'); if (sep == NULL) { cherokee_buffer_clean (user_ret); cherokee_buffer_add (user_ret, tmp, arroba - tmp); } else { cherokee_buffer_clean (user_ret); cherokee_buffer_add (user_ret, tmp, sep - tmp); sep++; cherokee_buffer_clean (password_ret); cherokee_buffer_add (password_ret, sep, arroba - sep); } tmp = arroba + 1; } /* Split the host/request */ server = tmp; len = strlen (server); slash = strpbrk (server, "/\\"); if (slash == NULL) { cherokee_buffer_add (&url->request, "/", 1); cherokee_buffer_add (&url->host, server, len); } else { cherokee_buffer_add (&url->request, slash, len-(slash-server)); cherokee_buffer_add (&url->host, server, slash-server); } /* Drop up the port, if exists.. */ port = strchr (url->host.buf, ':'); if (port != NULL) { /* Read port number */ if (slash != NULL) *slash = '\0'; URL_PORT(url) = atoi (port+1); if (slash != NULL) *slash = '/'; /* .. and remove it */ ret = cherokee_buffer_drop_ending (&url->host, strlen(port)); if (unlikely(ret < ret_ok)) return ret; } #if 0 cherokee_url_print (url); #endif return ret_ok; }
/* Parses a specification of a flow from 's' into 'flow'. 's' must take the * form FIELD=VALUE[,FIELD=VALUE]... where each FIELD is the name of a * mf_field. Fields must be specified in a natural order for satisfying * prerequisites. * * Returns NULL on success, otherwise a malloc()'d string that explains the * problem. */ char * parse_ofp_exact_flow(struct flow *flow, const char *s) { char *pos, *key, *value_s; char *error = NULL; char *copy; memset(flow, 0, sizeof *flow); pos = copy = xstrdup(s); while (ofputil_parse_key_value(&pos, &key, &value_s)) { const struct protocol *p; if (parse_protocol(key, &p)) { if (flow->dl_type) { error = xasprintf("%s: Ethernet type set multiple times", s); goto exit; } flow->dl_type = htons(p->dl_type); if (p->nw_proto) { if (flow->nw_proto) { error = xasprintf("%s: network protocol set " "multiple times", s); goto exit; } flow->nw_proto = p->nw_proto; } } else { const struct mf_field *mf; union mf_value value; char *field_error; mf = mf_from_name(key); if (!mf) { error = xasprintf("%s: unknown field %s", s, key); goto exit; } if (!mf_are_prereqs_ok(mf, flow)) { error = xasprintf("%s: prerequisites not met for setting %s", s, key); goto exit; } if (!mf_is_zero(mf, flow)) { error = xasprintf("%s: field %s set multiple times", s, key); goto exit; } field_error = mf_parse_value(mf, value_s, &value); if (field_error) { error = xasprintf("%s: bad value for %s (%s)", s, key, field_error); free(field_error); goto exit; } mf_set_flow_value(mf, &value, flow); } } exit: free(copy); if (error) { memset(flow, 0, sizeof *flow); } return error; }
istream68_t * url68_stream_create(const char * url, int mode) { char protocol[16]; char tmp[512]; const int max = sizeof(tmp)-1; istream68_t * isf = 0; int has_protocol; /* in fact protocol:// length */ has_protocol = parse_protocol(protocol, sizeof(protocol), url); if (has_protocol) { if (!strcmp68(protocol, "PASS")) { /* This is special pass thru protocol. It allows to send any other protocol:// or whatever to the default file handler. On some OS with some libC it may be useful. */ url += has_protocol; /* Skip protocol:// part */ has_protocol = 0; /* Allow fallback open */ } else if (!strcmp68(protocol, "RSC68")) { isf = rsc68_create_url(url, mode, 0); } else if (!strcmp68(protocol, "SC68")) { /* sc68://author/hw/title/track:loop */ url += has_protocol; /* Skip protocol:// part */ strncpy(tmp, "rsc68://music/",max); strncpy(tmp+14, url, max-14); tmp[max] = 0; msg68(-1,"url is now [%s]\n",tmp); isf = rsc68_create_url(tmp, mode, 0); } else if (!strcmp68(protocol, "FILE") || !strcmp68(protocol, "LOCAL")) { url += has_protocol; /* Skip protocol:// part */ has_protocol = 0; /* Allow fallback open */ } else if (!strcmp68(protocol, "NULL")) { isf = istream68_null_create(url); } else if (!strcmp68(protocol, "AUDIO")) { url += 5+3; isf = istream68_ao_create(url,mode); } else if (!strcmp68(protocol, "STDIN")) { if (mode != 1) return 0; /* stdin is READ_ONLY */ isf = istream68_fd_create("stdin://",0,1); url = "/dev/stdin"; /* fallback */ has_protocol = 0; /* Allow fallback open */ } else if (!strcmp68(protocol, "STDOUT")) { if (mode != 2) return 0; /* stdout is WRITE_ONLY */ isf = istream68_fd_create("stdout://",1,2); url = "/dev/stdout"; /* fallback */ has_protocol = 0; /* Allow fallback open */ } else if (!strcmp68(protocol, "STDERR")) { if (mode != 2) return 0; /* stderr is WRITE_ONLY */ isf = istream68_fd_create("stderr://",2,2); url = "/dev/stderr"; /* fallback */ has_protocol = 0; /* Allow fallback open */ } else { /* Try cURL for all unknown protocol */ isf = istream68_curl_create(url,mode); } } /* Fallback open only if no protocol (or explicitly allowed) */ if (!has_protocol) { if (!isf) { /* Default open as FILE */ isf = istream68_file_create(url,mode); } if (!isf) { /* Fallback to file descriptor */ isf = istream68_fd_create(url,-1,mode); } } msg68_trace("url68: create url='%s' %c%c => [%s,'%s']\n", strnevernull68(url), (mode&1) ? 'R' : '.', (mode&2) ? 'W' : '.', strok68(!isf), istream68_filename(isf)); return isf; }
int url68_get_protocol(char * protocol, int max, const char *url) { return -!parse_protocol(protocol, max, url); }
/* Convert 'string' (as described in the Flow Syntax section of the ovs-ofctl * man page) into 'pf'. If 'actions' is specified, an action must be in * 'string' and may be expanded or reallocated. */ void parse_ofp_str(struct flow_mod *fm, uint8_t *table_idx, struct ofpbuf *actions, char *string) { char *save_ptr = NULL; char *name; if (table_idx) { *table_idx = 0xff; } cls_rule_init_catchall(&fm->cr, OFP_DEFAULT_PRIORITY); fm->cookie = htonll(0); fm->command = UINT16_MAX; fm->idle_timeout = OFP_FLOW_PERMANENT; fm->hard_timeout = OFP_FLOW_PERMANENT; fm->buffer_id = UINT32_MAX; fm->out_port = OFPP_NONE; fm->flags = 0; if (actions) { char *act_str = strstr(string, "action"); if (!act_str) { ovs_fatal(0, "must specify an action"); } *act_str = '\0'; act_str = strchr(act_str + 1, '='); if (!act_str) { ovs_fatal(0, "must specify an action"); } act_str++; str_to_action(act_str, actions); fm->actions = actions->data; fm->n_actions = actions->size / sizeof(union ofp_action); } else { fm->actions = NULL; fm->n_actions = 0; } for (name = strtok_r(string, "=, \t\r\n", &save_ptr); name; name = strtok_r(NULL, "=, \t\r\n", &save_ptr)) { const struct protocol *p; if (parse_protocol(name, &p)) { cls_rule_set_dl_type(&fm->cr, htons(p->dl_type)); if (p->nw_proto) { cls_rule_set_nw_proto(&fm->cr, p->nw_proto); } } else { const struct field *f; char *value; value = strtok_r(NULL, ", \t\r\n", &save_ptr); if (!value) { ovs_fatal(0, "field %s missing value", name); } if (table_idx && !strcmp(name, "table")) { *table_idx = atoi(value); } else if (!strcmp(name, "out_port")) { fm->out_port = atoi(value); } else if (!strcmp(name, "priority")) { fm->cr.priority = atoi(value); } else if (!strcmp(name, "idle_timeout")) { fm->idle_timeout = atoi(value); } else if (!strcmp(name, "hard_timeout")) { fm->hard_timeout = atoi(value); } else if (!strcmp(name, "cookie")) { fm->cookie = htonll(str_to_u64(value)); } else if (parse_field_name(name, &f)) { if (!strcmp(value, "*") || !strcmp(value, "ANY")) { if (f->wildcard) { fm->cr.wc.wildcards |= f->wildcard; cls_rule_zero_wildcarded_fields(&fm->cr); } else if (f->index == F_NW_SRC) { cls_rule_set_nw_src_masked(&fm->cr, 0, 0); } else if (f->index == F_NW_DST) { cls_rule_set_nw_dst_masked(&fm->cr, 0, 0); } else if (f->index == F_IPV6_SRC) { cls_rule_set_ipv6_src_masked(&fm->cr, &in6addr_any, &in6addr_any); } else if (f->index == F_IPV6_DST) { cls_rule_set_ipv6_dst_masked(&fm->cr, &in6addr_any, &in6addr_any); } else if (f->index == F_DL_VLAN) { cls_rule_set_any_vid(&fm->cr); } else if (f->index == F_DL_VLAN_PCP) { cls_rule_set_any_pcp(&fm->cr); } else { NOT_REACHED(); } } else { parse_field_value(&fm->cr, f->index, value); } } else if (!strncmp(name, "reg", 3) && isdigit((unsigned char) name[3])) { unsigned int reg_idx = atoi(name + 3); if (reg_idx >= FLOW_N_REGS) { ovs_fatal(0, "only %d registers supported", FLOW_N_REGS); } parse_reg_value(&fm->cr, reg_idx, value); } else { ovs_fatal(0, "unknown keyword %s", name); } } } }
static int policy_parse(int c, char **argv, int invert, unsigned int *flags, const void *entry, struct xt_entry_match **match) { struct ip6t_policy_info *info = (void *)(*match)->data; struct ip6t_policy_elem *e = &info->pol[info->len]; struct in6_addr *addr = NULL, mask; unsigned int naddr = 0; int mode; check_inverse(optarg, &invert, &optind, 0); switch (c) { case '1': if (info->flags & (IP6T_POLICY_MATCH_IN|IP6T_POLICY_MATCH_OUT)) exit_error(PARAMETER_PROBLEM, "policy match: double --dir option"); if (invert) exit_error(PARAMETER_PROBLEM, "policy match: can't invert --dir option"); info->flags |= parse_direction(argv[optind-1]); break; case '2': if (invert) exit_error(PARAMETER_PROBLEM, "policy match: can't invert --policy option"); info->flags |= parse_policy(argv[optind-1]); break; case '3': if (info->flags & IP6T_POLICY_MATCH_STRICT) exit_error(PARAMETER_PROBLEM, "policy match: double --strict option"); if (invert) exit_error(PARAMETER_PROBLEM, "policy match: can't invert --strict option"); info->flags |= IP6T_POLICY_MATCH_STRICT; break; case '4': if (e->match.reqid) exit_error(PARAMETER_PROBLEM, "policy match: double --reqid option"); e->match.reqid = 1; e->invert.reqid = invert; e->reqid = strtol(argv[optind-1], NULL, 10); break; case '5': if (e->match.spi) exit_error(PARAMETER_PROBLEM, "policy match: double --spi option"); e->match.spi = 1; e->invert.spi = invert; e->spi = strtol(argv[optind-1], NULL, 0x10); break; case '6': if (e->match.saddr) exit_error(PARAMETER_PROBLEM, "policy match: double --tunnel-src option"); parse_hostnetworkmask(argv[optind-1], &addr, &mask, &naddr); if (naddr > 1) exit_error(PARAMETER_PROBLEM, "policy match: name resolves to multiple IPs"); e->match.saddr = 1; e->invert.saddr = invert; in6addrcpy(&e->saddr.a6, addr); in6addrcpy(&e->smask.a6, &mask); break; case '7': if (e->match.daddr) exit_error(PARAMETER_PROBLEM, "policy match: double --tunnel-dst option"); parse_hostnetworkmask(argv[optind-1], &addr, &mask, &naddr); if (naddr > 1) exit_error(PARAMETER_PROBLEM, "policy match: name resolves to multiple IPs"); e->match.daddr = 1; e->invert.daddr = invert; in6addrcpy(&e->daddr.a6, addr); in6addrcpy(&e->dmask.a6, &mask); break; case '8': if (e->match.proto) exit_error(PARAMETER_PROBLEM, "policy match: double --proto option"); e->proto = parse_protocol(argv[optind-1]); if (e->proto != IPPROTO_AH && e->proto != IPPROTO_ESP && e->proto != IPPROTO_COMP) exit_error(PARAMETER_PROBLEM, "policy match: protocol must ah/esp/ipcomp"); e->match.proto = 1; e->invert.proto = invert; break; case '9': if (e->match.mode) exit_error(PARAMETER_PROBLEM, "policy match: double --mode option"); mode = parse_mode(argv[optind-1]); e->match.mode = 1; e->invert.mode = invert; e->mode = mode; break; case 'a': if (invert) exit_error(PARAMETER_PROBLEM, "policy match: can't invert --next option"); if (++info->len == IP6T_POLICY_MAX_ELEM) exit_error(PARAMETER_PROBLEM, "policy match: maximum policy depth reached"); break; default: return 0; } policy_info = info; return 1; }
/* 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 struct ipt_entry *entry, unsigned int *nfcache, struct ipt_entry_match **match) { struct ipt_conntrack_info *sinfo = (struct ipt_conntrack_info *)(*match)->data; char *protocol = NULL; unsigned int naddrs = 0; struct in_addr *addrs = NULL; switch (c) { case '1': check_inverse(optarg, &invert, &optind, 0); parse_states(argv[optind-1], sinfo); if (invert) { sinfo->invflags |= IPT_CONNTRACK_STATE; } sinfo->flags |= IPT_CONNTRACK_STATE; break; case '2': check_inverse(optarg, &invert, &optind, 0); if(invert) sinfo->invflags |= IPT_CONNTRACK_PROTO; /* Canonicalize into lower case */ for (protocol = argv[optind-1]; *protocol; protocol++) *protocol = tolower(*protocol); protocol = argv[optind-1]; sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum = parse_protocol(protocol); if (sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum == 0 && (sinfo->invflags & IPT_INV_PROTO)) exit_error(PARAMETER_PROBLEM, "rule would never match protocol"); sinfo->flags |= IPT_CONNTRACK_PROTO; break; case '3': check_inverse(optarg, &invert, &optind, 9); if (invert) sinfo->invflags |= IPT_CONNTRACK_ORIGSRC; parse_hostnetworkmask(argv[optind-1], &addrs, &sinfo->sipmsk[IP_CT_DIR_ORIGINAL], &naddrs); if(naddrs > 1) exit_error(PARAMETER_PROBLEM, "multiple IP addresses not allowed"); if(naddrs == 1) { sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip = addrs[0].s_addr; } sinfo->flags |= IPT_CONNTRACK_ORIGSRC; break; case '4': check_inverse(optarg, &invert, &optind, 0); if (invert) sinfo->invflags |= IPT_CONNTRACK_ORIGDST; parse_hostnetworkmask(argv[optind-1], &addrs, &sinfo->dipmsk[IP_CT_DIR_ORIGINAL], &naddrs); if(naddrs > 1) exit_error(PARAMETER_PROBLEM, "multiple IP addresses not allowed"); if(naddrs == 1) { sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip = addrs[0].s_addr; } sinfo->flags |= IPT_CONNTRACK_ORIGDST; break; case '5': check_inverse(optarg, &invert, &optind, 0); if (invert) sinfo->invflags |= IPT_CONNTRACK_REPLSRC; parse_hostnetworkmask(argv[optind-1], &addrs, &sinfo->sipmsk[IP_CT_DIR_REPLY], &naddrs); if(naddrs > 1) exit_error(PARAMETER_PROBLEM, "multiple IP addresses not allowed"); if(naddrs == 1) { sinfo->tuple[IP_CT_DIR_REPLY].src.ip = addrs[0].s_addr; } sinfo->flags |= IPT_CONNTRACK_REPLSRC; break; case '6': check_inverse(optarg, &invert, &optind, 0); if (invert) sinfo->invflags |= IPT_CONNTRACK_REPLDST; parse_hostnetworkmask(argv[optind-1], &addrs, &sinfo->dipmsk[IP_CT_DIR_REPLY], &naddrs); if(naddrs > 1) exit_error(PARAMETER_PROBLEM, "multiple IP addresses not allowed"); if(naddrs == 1) { sinfo->tuple[IP_CT_DIR_REPLY].dst.ip = addrs[0].s_addr; } sinfo->flags |= IPT_CONNTRACK_REPLDST; break; case '7': check_inverse(optarg, &invert, &optind, 0); parse_statuses(argv[optind-1], sinfo); if (invert) { sinfo->invflags |= IPT_CONNTRACK_STATUS; } sinfo->flags |= IPT_CONNTRACK_STATUS; break; case '8': check_inverse(optarg, &invert, &optind, 0); parse_expires(argv[optind-1], sinfo); if (invert) { sinfo->invflags |= IPT_CONNTRACK_EXPIRES; } sinfo->flags |= IPT_CONNTRACK_EXPIRES; break; default: return 0; } *flags = sinfo->flags; return 1; }