diff options
Diffstat (limited to 'src/conntrack.c')
-rw-r--r-- | src/conntrack.c | 340 |
1 files changed, 240 insertions, 100 deletions
diff --git a/src/conntrack.c b/src/conntrack.c index 7d2a365..00b09b6 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -82,6 +82,9 @@ static struct { /* Allows filtering by ctlabels */ struct nfct_bitmask *label; + + /* Allows setting/removing specific ctlabels */ + struct nfct_bitmask *label_modify; } tmpl; static int alloc_tmpl_objects(void) @@ -109,6 +112,8 @@ static void free_tmpl_objects(void) nfexp_destroy(tmpl.exp); if (tmpl.label) nfct_bitmask_destroy(tmpl.label); + if (tmpl.label_modify) + nfct_bitmask_destroy(tmpl.label_modify); } enum ct_command { @@ -255,6 +260,12 @@ enum ct_options { CT_OPT_LABEL_BIT = 24, CT_OPT_LABEL = (1 << CT_OPT_LABEL_BIT), + + CT_OPT_ADD_LABEL_BIT = 25, + CT_OPT_ADD_LABEL = (1 << CT_OPT_ADD_LABEL_BIT), + + CT_OPT_DEL_LABEL_BIT = 26, + CT_OPT_DEL_LABEL = (1 << CT_OPT_DEL_LABEL_BIT), }; /* If you add a new option, you have to update NUMBER_OF_OPT in conntrack.h */ @@ -289,6 +300,8 @@ static const char *optflags[NUMBER_OF_OPT] = { [CT_OPT_ANY_NAT_BIT] = "any-nat", [CT_OPT_ZONE_BIT] = "zone", [CT_OPT_LABEL_BIT] = "label", + [CT_OPT_ADD_LABEL_BIT] = "label-add", + [CT_OPT_DEL_LABEL_BIT] = "label-del", }; static struct option original_opts[] = { @@ -330,12 +343,14 @@ static struct option original_opts[] = { {"any-nat", 2, 0, 'j'}, {"zone", 1, 0, 'w'}, {"label", 1, 0, 'l'}, + {"label-add", 1, 0, '<'}, + {"label-del", 2, 0, '>'}, {0, 0, 0, 0} }; static const char *getopt_str = ":L::I::U::D::G::E::F::hVs:d:r:q:" "p:t:u:e:a:z[:]:{:}:m:i:f:o:n::" - "g::c:b:C::Sj::w:l:"; + "g::c:b:C::Sj::w:l:<:>::"; /* Table of legal combinations of commands and options. If any of the * given commands make an option legal, that option is legal (applies to @@ -350,26 +365,26 @@ static const char *getopt_str = ":L::I::U::D::G::E::F::hVs:d:r:q:" static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = /* Well, it's better than "Re: Linux vs FreeBSD" */ { - /* s d r q p t u z e [ ] { } a m i f n g o c b j w l*/ -/*CT_LIST*/ {2,2,2,2,2,0,2,2,0,0,0,0,0,0,2,0,2,2,2,2,2,0,2,2,2}, -/*CT_CREATE*/ {3,3,3,3,1,1,2,0,0,0,0,0,0,2,2,0,0,2,2,0,0,0,0,2,0}, -/*CT_UPDATE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,0,0}, -/*CT_DELETE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,2,0}, -/*CT_GET*/ {3,3,3,3,1,0,0,0,0,0,0,0,0,0,0,2,0,0,0,2,0,0,0,0,0}, -/*CT_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*CT_EVENT*/ {2,2,2,2,2,0,0,0,2,0,0,0,0,0,2,0,0,2,2,2,2,2,2,2,2}, -/*VERSION*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*HELP*/ {0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*EXP_LIST*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,2,0,0,0,0,0}, -/*EXP_CREATE*/{1,1,2,2,1,1,2,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0}, -/*EXP_DELETE*/{1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*EXP_GET*/ {1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*EXP_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*EXP_EVENT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0}, -/*CT_COUNT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*EXP_COUNT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*CT_STATS*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, -/*EXP_STATS*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + /* s d r q p t u z e [ ] { } a m i f n g o c b j w l < > */ +/*CT_LIST*/ {2,2,2,2,2,0,2,2,0,0,0,0,0,0,2,0,2,2,2,2,2,0,2,2,2,0,0}, +/*CT_CREATE*/ {3,3,3,3,1,1,2,0,0,0,0,0,0,2,2,0,0,2,2,0,0,0,0,2,0,2,0}, +/*CT_UPDATE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,0,2,2,2}, +/*CT_DELETE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,2,2,0,0}, +/*CT_GET*/ {3,3,3,3,1,0,0,0,0,0,0,0,0,0,0,2,0,0,0,2,0,0,0,0,2,0,0}, +/*CT_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*CT_EVENT*/ {2,2,2,2,2,0,0,0,2,0,0,0,0,0,2,0,0,2,2,2,2,2,2,2,2,0,0}, +/*VERSION*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*HELP*/ {0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*EXP_LIST*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,2,0,0,0,0,0,0,0}, +/*EXP_CREATE*/{1,1,2,2,1,1,2,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*EXP_DELETE*/{1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*EXP_GET*/ {1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*EXP_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*EXP_EVENT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0}, +/*CT_COUNT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*EXP_COUNT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*CT_STATS*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, +/*EXP_STATS*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, }; static const int cmd2type[][2] = { @@ -402,6 +417,8 @@ static const int opt2type[] = { ['j'] = CT_OPT_ANY_NAT, ['w'] = CT_OPT_ZONE, ['l'] = CT_OPT_LABEL, + ['<'] = CT_OPT_ADD_LABEL, + ['>'] = CT_OPT_DEL_LABEL, }; static const int opt2family_attr[][2] = { @@ -420,11 +437,17 @@ static const int opt2attr[] = { ['d'] = ATTR_ORIG_L3PROTO, ['r'] = ATTR_REPL_L3PROTO, ['q'] = ATTR_REPL_L3PROTO, + ['{'] = ATTR_ORIG_L3PROTO, + ['}'] = ATTR_ORIG_L3PROTO, + ['['] = ATTR_ORIG_L3PROTO, + [']'] = ATTR_ORIG_L3PROTO, ['m'] = ATTR_MARK, ['c'] = ATTR_SECMARK, ['i'] = ATTR_ID, ['w'] = ATTR_ZONE, ['l'] = ATTR_CONNLABELS, + ['<'] = ATTR_CONNLABELS, + ['>'] = ATTR_CONNLABELS, }; static char exit_msg[NUMBER_OF_CMD][64] = { @@ -472,6 +495,11 @@ static const char usage_expectation_parameters[] = " --mask-src ip\t\tSource mask address\n" " --mask-dst ip\t\tDestination mask address\n"; +static const char usage_update_parameters[] = + "Updating parameters and options:\n" + " --label-add label\tAdd label\n" + " --label-del label\tDelete label\n"; + static const char usage_parameters[] = "Common parameters and options:\n" " -s, --orig-src ip\t\tSource address from original direction\n" @@ -523,7 +551,7 @@ static struct ctproto_handler *findproto(char *name, int *pnum) /* is it in the list of supported protocol? */ list_for_each_entry(cur, &proto_list, head) { - if (strcmp(cur->name, name) == 0) { + if (strcasecmp(cur->name, name) == 0) { *pnum = cur->protonum; return cur; } @@ -890,20 +918,20 @@ add_command(unsigned int *cmd, const int newcmd) *cmd |= newcmd; } -static char *get_table(int argc, char *argv[]) +static char *get_optional_arg(int argc, char *argv[]) { - char *table = NULL; + char *arg = NULL; /* Nasty bug or feature in getopt_long ? * It seems that it behaves badly with optional arguments. * Fortunately, I just stole the fix from iptables ;) */ if (optarg) - return 0; + return arg; else if (optind < argc && argv[optind][0] != '-' && argv[optind][0] != '!') - table = argv[optind++]; + arg = argv[optind++]; - return table; + return arg; } enum { @@ -915,7 +943,7 @@ enum { static unsigned int check_type(int argc, char *argv[]) { - const char *table = get_table(argc, argv); + const char *table = get_optional_arg(argc, argv); /* default to conntrack subsystem if nothing has been specified. */ if (table == NULL) @@ -1045,6 +1073,7 @@ usage(char *prog) fprintf(stdout, "\n%s", usage_tables); fprintf(stdout, "\n%s", usage_conntrack_parameters); fprintf(stdout, "\n%s", usage_expectation_parameters); + fprintf(stdout, "\n%s", usage_update_parameters); fprintf(stdout, "\n%s\n", usage_parameters); } @@ -1349,7 +1378,7 @@ static int print_cb(enum nf_conntrack_msg_type type, if (output_mask & _O_ID) op_flags |= NFCT_OF_ID; - nfct_snprintf(buf, sizeof(buf), ct, NFCT_T_UNKNOWN, op_type, op_flags); + nfct_snprintf_labels(buf, sizeof(buf), ct, NFCT_T_UNKNOWN, op_type, op_flags, labelmap); printf("%s\n", buf); return NFCT_CB_CONTINUE; @@ -1376,6 +1405,72 @@ static void copy_status(struct nf_conntrack *tmp, const struct nf_conntrack *ct) } } +static struct nfct_bitmask *xnfct_bitmask_clone(const struct nfct_bitmask *a) +{ + struct nfct_bitmask *b = nfct_bitmask_clone(a); + if (!b) + exit_error(OTHER_PROBLEM, "out of memory"); + return b; +} + +static void copy_label(struct nf_conntrack *tmp, const struct nf_conntrack *ct) +{ + struct nfct_bitmask *ctb, *newmask; + unsigned int i; + + if ((options & (CT_OPT_ADD_LABEL|CT_OPT_DEL_LABEL)) == 0) + return; + + nfct_copy_attr(tmp, ct, ATTR_CONNLABELS); + ctb = (void *) nfct_get_attr(tmp, ATTR_CONNLABELS); + + if (options & CT_OPT_ADD_LABEL) { + if (ctb == NULL) { + nfct_set_attr(tmp, ATTR_CONNLABELS, + xnfct_bitmask_clone(tmpl.label_modify)); + return; + } + /* If we send a bitmask shorter than the kernel sent to us, the bits we + * omit will be cleared (as "padding"). So we always have to send the + * same sized bitmask as we received. + * + * Mask has to have the same size as the labels, otherwise it will not + * be encoded by libnetfilter_conntrack, as different sizes are not + * accepted by the kernel. + */ + newmask = nfct_bitmask_new(nfct_bitmask_maxbit(ctb)); + + for (i = 0; i <= nfct_bitmask_maxbit(ctb); i++) { + if (nfct_bitmask_test_bit(tmpl.label_modify, i)) { + nfct_bitmask_set_bit(ctb, i); + nfct_bitmask_set_bit(newmask, i); + } else if (nfct_bitmask_test_bit(ctb, i)) { + /* Kernel only retains old bit values that are sent as + * zeroes in BOTH labels and mask. + */ + nfct_bitmask_unset_bit(ctb, i); + } + } + nfct_set_attr(tmp, ATTR_CONNLABELS_MASK, newmask); + } else if (ctb != NULL) { + /* CT_OPT_DEL_LABEL */ + if (tmpl.label_modify == NULL) { + newmask = nfct_bitmask_new(0); + if (newmask) + nfct_set_attr(tmp, ATTR_CONNLABELS, newmask); + return; + } + + for (i = 0; i <= nfct_bitmask_maxbit(ctb); i++) { + if (nfct_bitmask_test_bit(tmpl.label_modify, i)) + nfct_bitmask_unset_bit(ctb, i); + } + + newmask = xnfct_bitmask_clone(tmpl.label_modify); + nfct_set_attr(tmp, ATTR_CONNLABELS_MASK, newmask); + } +} + static int update_cb(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data) @@ -1395,6 +1490,9 @@ static int update_cb(enum nf_conntrack_msg_type type, if (options & CT_OPT_TUPLE_REPL && !nfct_cmp(obj, ct, NFCT_CMP_REPL)) return NFCT_CB_CONTINUE; + if (filter_label(ct)) + return NFCT_CB_CONTINUE; + tmp = nfct_new(); if (tmp == NULL) exit_error(OTHER_PROBLEM, "out of memory"); @@ -1403,6 +1501,7 @@ static int update_cb(enum nf_conntrack_msg_type type, nfct_copy(tmp, obj, NFCT_CP_META); copy_mark(tmp, ct, &tmpl.mark); copy_status(tmp, ct); + copy_label(tmp, ct); /* do not send NFCT_Q_UPDATE if ct appears unchanged */ if (nfct_cmp(tmp, ct, NFCT_CMP_ALL | NFCT_CMP_MASK)) { @@ -1411,12 +1510,10 @@ static int update_cb(enum nf_conntrack_msg_type type, } res = nfct_query(ith, NFCT_Q_UPDATE, tmp); - if (res < 0) { - nfct_destroy(tmp); - exit_error(OTHER_PROBLEM, - "Operation failed: %s", + if (res < 0) + fprintf(stderr, + "Operation failed: %s\n", err2str(errno, CT_UPDATE)); - } nfct_callback_register(ith, NFCT_T_ALL, print_cb, NULL); res = nfct_query(ith, NFCT_Q_GET, tmp); @@ -1601,7 +1698,8 @@ static int nfct_mnl_socket_open(void) } static struct nlmsghdr * -nfct_mnl_nlmsghdr_put(char *buf, uint16_t subsys, uint16_t type) +nfct_mnl_nlmsghdr_put(char *buf, uint16_t subsys, uint16_t type, + uint8_t family) { struct nlmsghdr *nlh; struct nfgenmsg *nfh; @@ -1612,7 +1710,7 @@ nfct_mnl_nlmsghdr_put(char *buf, uint16_t subsys, uint16_t type) nlh->nlmsg_seq = time(NULL); nfh = mnl_nlmsg_put_extra_header(nlh, sizeof(struct nfgenmsg)); - nfh->nfgen_family = AF_INET; + nfh->nfgen_family = family; nfh->version = NFNETLINK_V0; nfh->res_id = 0; @@ -1625,13 +1723,13 @@ static void nfct_mnl_socket_close(void) } static int -nfct_mnl_dump(uint16_t subsys, uint16_t type, mnl_cb_t cb) +nfct_mnl_dump(uint16_t subsys, uint16_t type, mnl_cb_t cb, uint8_t family) { char buf[MNL_SOCKET_BUFFER_SIZE]; struct nlmsghdr *nlh; int res; - nlh = nfct_mnl_nlmsghdr_put(buf, subsys, type); + nlh = nfct_mnl_nlmsghdr_put(buf, subsys, type, family); res = mnl_socket_sendto(sock.mnl, nlh, nlh->nlmsg_len); if (res < 0) @@ -1651,13 +1749,13 @@ nfct_mnl_dump(uint16_t subsys, uint16_t type, mnl_cb_t cb) } static int -nfct_mnl_get(uint16_t subsys, uint16_t type, mnl_cb_t cb) +nfct_mnl_get(uint16_t subsys, uint16_t type, mnl_cb_t cb, uint8_t family) { char buf[MNL_SOCKET_BUFFER_SIZE]; struct nlmsghdr *nlh; int res; - nlh = nfct_mnl_nlmsghdr_put(buf, subsys, type); + nlh = nfct_mnl_nlmsghdr_put(buf, subsys, type, family); res = mnl_socket_sendto(sock.mnl, nlh, nlh->nlmsg_len); if (res < 0) @@ -1818,6 +1916,65 @@ static int mnl_nfct_dump_cb(const struct nlmsghdr *nlh, void *data) static struct ctproto_handler *h; +static void labelmap_init(void) +{ + if (labelmap) + return; + labelmap = nfct_labelmap_new(NULL); + if (!labelmap) + perror("nfct_labelmap_new"); +} + +static void merge_bitmasks(struct nfct_bitmask **current, + struct nfct_bitmask *src) +{ + unsigned int i; + + if (*current == NULL) { + *current = src; + return; + } + + /* "current" must be the larger bitmask object */ + if (nfct_bitmask_maxbit(src) > nfct_bitmask_maxbit(*current)) { + struct nfct_bitmask *tmp = *current; + *current = src; + src = tmp; + } + + for (i = 0; i <= nfct_bitmask_maxbit(src); i++) { + if (nfct_bitmask_test_bit(src, i)) + nfct_bitmask_set_bit(*current, i); + } + + nfct_bitmask_destroy(src); +} + +static void +nfct_set_addr_from_opt(int opt, struct nf_conntrack *ct, union ct_address *ad, + int *family) +{ + int l3protonum; + + options |= opt2type[opt]; + l3protonum = parse_addr(optarg, ad); + if (l3protonum == AF_UNSPEC) { + exit_error(PARAMETER_PROBLEM, + "Invalid IP address `%s'", optarg); + } + set_family(family, l3protonum); + if (l3protonum == AF_INET) { + nfct_set_attr_u32(ct, + opt2family_attr[opt][0], + ad->v4); + } else if (l3protonum == AF_INET6) { + nfct_set_attr(ct, + opt2family_attr[opt][1], + &ad->v6); + } + nfct_set_attr_u8(ct, opt2attr[opt], l3protonum); +} + int main(int argc, char *argv[]) { int c, cmd; @@ -1825,7 +1982,7 @@ int main(int argc, char *argv[]) int res = 0, partial; size_t socketbuffersize = 0; int family = AF_UNSPEC; - int l3protonum, protonum = 0; + int protonum = 0; union ct_address ad; unsigned int command = 0; @@ -1896,47 +2053,15 @@ int main(int argc, char *argv[]) case 'd': case 'r': case 'q': - options |= opt2type[c]; - - l3protonum = parse_addr(optarg, &ad); - if (l3protonum == AF_UNSPEC) { - exit_error(PARAMETER_PROBLEM, - "Invalid IP address `%s'", optarg); - } - set_family(&family, l3protonum); - if (l3protonum == AF_INET) { - nfct_set_attr_u32(tmpl.ct, - opt2family_attr[c][0], - ad.v4); - } else if (l3protonum == AF_INET6) { - nfct_set_attr(tmpl.ct, - opt2family_attr[c][1], - &ad.v6); - } - nfct_set_attr_u8(tmpl.ct, opt2attr[c], l3protonum); + nfct_set_addr_from_opt(c, tmpl.ct, &ad, &family); break; case '{': case '}': + nfct_set_addr_from_opt(c, tmpl.exptuple, &ad, &family); + break; case '[': case ']': - options |= opt2type[c]; - l3protonum = parse_addr(optarg, &ad); - if (l3protonum == AF_UNSPEC) { - exit_error(PARAMETER_PROBLEM, - "Invalid IP address `%s'", optarg); - } - set_family(&family, l3protonum); - if (l3protonum == AF_INET) { - nfct_set_attr_u32(tmpl.mask, - opt2family_attr[c][0], - ad.v4); - } else if (l3protonum == AF_INET6) { - nfct_set_attr(tmpl.mask, - opt2family_attr[c][1], - &ad.v6); - } - nfct_set_attr_u8(tmpl.mask, - ATTR_ORIG_L3PROTO, l3protonum); + nfct_set_addr_from_opt(c, tmpl.mask, &ad, &family); break; case 'p': options |= CT_OPT_PROTO; @@ -1970,12 +2095,8 @@ int main(int argc, char *argv[]) case 'o': options |= CT_OPT_OUTPUT; parse_parameter(optarg, &output_mask, PARSE_OUTPUT); - if (output_mask & _O_CL) { - if (!labelmap) - labelmap = nfct_labelmap_new(NULL); - if (!labelmap) - perror("nfct_labelmap_new"); - } + if (output_mask & _O_CL) + labelmap_init(); break; case 'z': options |= CT_OPT_ZERO; @@ -1987,12 +2108,7 @@ int main(int argc, char *argv[]) options |= opt2type[c]; - if (optarg) - continue; - else if (optind < argc && argv[optind][0] != '-' - && argv[optind][0] != '!') - tmp = argv[optind++]; - + tmp = get_optional_arg(argc, argv); if (tmp == NULL) continue; @@ -2020,19 +2136,39 @@ int main(int argc, char *argv[]) tmpl.filter_mark_kernel.mask = tmpl.mark.mask; break; case 'l': + case '<': + case '>': options |= opt2type[c]; - char *optarg2 = strdup(optarg); - if (!labelmap) - labelmap = nfct_labelmap_new(NULL); - if (!labelmap) - exit_error(OTHER_PROBLEM, "unable to open labelmap file"); + labelmap_init(); + if ((options & (CT_OPT_DEL_LABEL|CT_OPT_ADD_LABEL)) == + (CT_OPT_DEL_LABEL|CT_OPT_ADD_LABEL)) + exit_error(OTHER_PROBLEM, "cannot use --label-add and " + "--label-del at the same time"); + + if (c == '>') { /* DELETE */ + char *tmp = get_optional_arg(argc, argv); + if (tmp == NULL) /* delete all labels */ + break; + optarg = tmp; + } + + char *optarg2 = strdup(optarg); unsigned int max = parse_label_get_max(optarg); struct nfct_bitmask * b = nfct_bitmask_new(max); + if (!b) + exit_error(OTHER_PROBLEM, "out of memory"); parse_label(b, optarg2); - tmpl.label = b; + + /* join "-l foo -l bar" into single bitmask object */ + if (c == 'l') { + merge_bitmasks(&tmpl.label, b); + } else { + merge_bitmasks(&tmpl.label_modify, b); + } + free(optarg2); break; case 'a': @@ -2114,7 +2250,7 @@ int main(int argc, char *argv[]) res = nfct_mnl_dump(NFNL_SUBSYS_CTNETLINK, IPCTNL_MSG_CT_GET_DYING, - mnl_nfct_dump_cb); + mnl_nfct_dump_cb, family); nfct_mnl_socket_close(); break; @@ -2124,7 +2260,7 @@ int main(int argc, char *argv[]) res = nfct_mnl_dump(NFNL_SUBSYS_CTNETLINK, IPCTNL_MSG_CT_GET_UNCONFIRMED, - mnl_nfct_dump_cb); + mnl_nfct_dump_cb, family); nfct_mnl_socket_close(); break; @@ -2191,6 +2327,10 @@ int main(int argc, char *argv[]) if (options & CT_OPT_MARK) nfct_set_attr_u32(tmpl.ct, ATTR_MARK, tmpl.mark.value); + if (options & CT_OPT_ADD_LABEL) + nfct_set_attr(tmpl.ct, ATTR_CONNLABELS, + xnfct_bitmask_clone(tmpl.label_modify)); + cth = nfct_open(CONNTRACK, 0); if (!cth) exit_error(OTHER_PROBLEM, "Can't open handler"); @@ -2389,7 +2529,7 @@ int main(int argc, char *argv[]) res = nfct_mnl_get(NFNL_SUBSYS_CTNETLINK, IPCTNL_MSG_CT_GET_STATS, - nfct_global_stats_cb); + nfct_global_stats_cb, AF_UNSPEC); nfct_mnl_socket_close(); @@ -2434,7 +2574,7 @@ try_proc_count: res = nfct_mnl_dump(NFNL_SUBSYS_CTNETLINK, IPCTNL_MSG_CT_GET_STATS_CPU, - nfct_stats_cb); + nfct_stats_cb, AF_UNSPEC); nfct_mnl_socket_close(); @@ -2453,7 +2593,7 @@ try_proc_count: res = nfct_mnl_dump(NFNL_SUBSYS_CTNETLINK_EXP, IPCTNL_MSG_EXP_GET_STATS_CPU, - nfexp_stats_cb); + nfexp_stats_cb, AF_UNSPEC); nfct_mnl_socket_close(); |