summaryrefslogtreecommitdiff
path: root/src/conntrack.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/conntrack.c')
-rw-r--r--src/conntrack.c340
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();