1*a71a9546SAutomerger Merge Worker #define _GNU_SOURCE
2*a71a9546SAutomerger Merge Worker #include <errno.h>
3*a71a9546SAutomerger Merge Worker #include <stdbool.h>
4*a71a9546SAutomerger Merge Worker #include <string.h>
5*a71a9546SAutomerger Merge Worker #include <stdio.h>
6*a71a9546SAutomerger Merge Worker #include <stdint.h>
7*a71a9546SAutomerger Merge Worker #include <stdlib.h>
8*a71a9546SAutomerger Merge Worker #include <xtables.h>
9*a71a9546SAutomerger Merge Worker #include <linux/netfilter/xt_connlabel.h>
10*a71a9546SAutomerger Merge Worker #include <libnetfilter_conntrack/libnetfilter_conntrack.h>
11*a71a9546SAutomerger Merge Worker
12*a71a9546SAutomerger Merge Worker enum {
13*a71a9546SAutomerger Merge Worker O_LABEL = 0,
14*a71a9546SAutomerger Merge Worker O_SET = 1,
15*a71a9546SAutomerger Merge Worker };
16*a71a9546SAutomerger Merge Worker
17*a71a9546SAutomerger Merge Worker static struct nfct_labelmap *map;
18*a71a9546SAutomerger Merge Worker
connlabel_mt_help(void)19*a71a9546SAutomerger Merge Worker static void connlabel_mt_help(void)
20*a71a9546SAutomerger Merge Worker {
21*a71a9546SAutomerger Merge Worker puts(
22*a71a9546SAutomerger Merge Worker "connlabel match options:\n"
23*a71a9546SAutomerger Merge Worker "[!] --label name Match if label has been set on connection\n"
24*a71a9546SAutomerger Merge Worker " --set Set label on connection");
25*a71a9546SAutomerger Merge Worker }
26*a71a9546SAutomerger Merge Worker
27*a71a9546SAutomerger Merge Worker static const struct xt_option_entry connlabel_mt_opts[] = {
28*a71a9546SAutomerger Merge Worker {.name = "label", .id = O_LABEL, .type = XTTYPE_STRING,
29*a71a9546SAutomerger Merge Worker .min = 1, .flags = XTOPT_MAND|XTOPT_INVERT},
30*a71a9546SAutomerger Merge Worker {.name = "set", .id = O_SET, .type = XTTYPE_NONE},
31*a71a9546SAutomerger Merge Worker XTOPT_TABLEEND,
32*a71a9546SAutomerger Merge Worker };
33*a71a9546SAutomerger Merge Worker
34*a71a9546SAutomerger Merge Worker /* cannot do this via _init, else static builds might spew error message
35*a71a9546SAutomerger Merge Worker * for every iptables invocation.
36*a71a9546SAutomerger Merge Worker */
connlabel_open(void)37*a71a9546SAutomerger Merge Worker static int connlabel_open(void)
38*a71a9546SAutomerger Merge Worker {
39*a71a9546SAutomerger Merge Worker const char *fname;
40*a71a9546SAutomerger Merge Worker
41*a71a9546SAutomerger Merge Worker if (map)
42*a71a9546SAutomerger Merge Worker return 0;
43*a71a9546SAutomerger Merge Worker
44*a71a9546SAutomerger Merge Worker map = nfct_labelmap_new(NULL);
45*a71a9546SAutomerger Merge Worker if (map != NULL)
46*a71a9546SAutomerger Merge Worker return 0;
47*a71a9546SAutomerger Merge Worker
48*a71a9546SAutomerger Merge Worker fname = nfct_labels_get_path();
49*a71a9546SAutomerger Merge Worker if (errno) {
50*a71a9546SAutomerger Merge Worker fprintf(stderr, "Warning: cannot open %s: %s\n",
51*a71a9546SAutomerger Merge Worker fname, strerror(errno));
52*a71a9546SAutomerger Merge Worker } else {
53*a71a9546SAutomerger Merge Worker xtables_error(RESOURCE_PROBLEM,
54*a71a9546SAutomerger Merge Worker "cannot parse %s: no labels found", fname);
55*a71a9546SAutomerger Merge Worker }
56*a71a9546SAutomerger Merge Worker return 1;
57*a71a9546SAutomerger Merge Worker }
58*a71a9546SAutomerger Merge Worker
connlabel_value_parse(const char * in)59*a71a9546SAutomerger Merge Worker static int connlabel_value_parse(const char *in)
60*a71a9546SAutomerger Merge Worker {
61*a71a9546SAutomerger Merge Worker char *end;
62*a71a9546SAutomerger Merge Worker unsigned long value = strtoul(in, &end, 0);
63*a71a9546SAutomerger Merge Worker
64*a71a9546SAutomerger Merge Worker if (in[0] == '\0' || *end != '\0')
65*a71a9546SAutomerger Merge Worker return -1;
66*a71a9546SAutomerger Merge Worker
67*a71a9546SAutomerger Merge Worker return value;
68*a71a9546SAutomerger Merge Worker }
69*a71a9546SAutomerger Merge Worker
connlabel_mt_parse(struct xt_option_call * cb)70*a71a9546SAutomerger Merge Worker static void connlabel_mt_parse(struct xt_option_call *cb)
71*a71a9546SAutomerger Merge Worker {
72*a71a9546SAutomerger Merge Worker struct xt_connlabel_mtinfo *info = cb->data;
73*a71a9546SAutomerger Merge Worker int tmp;
74*a71a9546SAutomerger Merge Worker
75*a71a9546SAutomerger Merge Worker xtables_option_parse(cb);
76*a71a9546SAutomerger Merge Worker
77*a71a9546SAutomerger Merge Worker switch (cb->entry->id) {
78*a71a9546SAutomerger Merge Worker case O_LABEL:
79*a71a9546SAutomerger Merge Worker tmp = connlabel_value_parse(cb->arg);
80*a71a9546SAutomerger Merge Worker if (tmp < 0 && !connlabel_open())
81*a71a9546SAutomerger Merge Worker tmp = nfct_labelmap_get_bit(map, cb->arg);
82*a71a9546SAutomerger Merge Worker if (tmp < 0)
83*a71a9546SAutomerger Merge Worker xtables_error(PARAMETER_PROBLEM,
84*a71a9546SAutomerger Merge Worker "label '%s' not found or invalid value",
85*a71a9546SAutomerger Merge Worker cb->arg);
86*a71a9546SAutomerger Merge Worker
87*a71a9546SAutomerger Merge Worker info->bit = tmp;
88*a71a9546SAutomerger Merge Worker if (cb->invert)
89*a71a9546SAutomerger Merge Worker info->options |= XT_CONNLABEL_OP_INVERT;
90*a71a9546SAutomerger Merge Worker break;
91*a71a9546SAutomerger Merge Worker case O_SET:
92*a71a9546SAutomerger Merge Worker info->options |= XT_CONNLABEL_OP_SET;
93*a71a9546SAutomerger Merge Worker break;
94*a71a9546SAutomerger Merge Worker }
95*a71a9546SAutomerger Merge Worker
96*a71a9546SAutomerger Merge Worker }
97*a71a9546SAutomerger Merge Worker
connlabel_get_name(int b)98*a71a9546SAutomerger Merge Worker static const char *connlabel_get_name(int b)
99*a71a9546SAutomerger Merge Worker {
100*a71a9546SAutomerger Merge Worker const char *name;
101*a71a9546SAutomerger Merge Worker
102*a71a9546SAutomerger Merge Worker if (connlabel_open())
103*a71a9546SAutomerger Merge Worker return NULL;
104*a71a9546SAutomerger Merge Worker
105*a71a9546SAutomerger Merge Worker name = nfct_labelmap_get_name(map, b);
106*a71a9546SAutomerger Merge Worker if (name && strcmp(name, ""))
107*a71a9546SAutomerger Merge Worker return name;
108*a71a9546SAutomerger Merge Worker return NULL;
109*a71a9546SAutomerger Merge Worker }
110*a71a9546SAutomerger Merge Worker
111*a71a9546SAutomerger Merge Worker static void
connlabel_mt_print_op(const struct xt_connlabel_mtinfo * info,const char * prefix)112*a71a9546SAutomerger Merge Worker connlabel_mt_print_op(const struct xt_connlabel_mtinfo *info, const char *prefix)
113*a71a9546SAutomerger Merge Worker {
114*a71a9546SAutomerger Merge Worker if (info->options & XT_CONNLABEL_OP_SET)
115*a71a9546SAutomerger Merge Worker printf(" %sset", prefix);
116*a71a9546SAutomerger Merge Worker }
117*a71a9546SAutomerger Merge Worker
118*a71a9546SAutomerger Merge Worker static void
connlabel_mt_print(const void * ip,const struct xt_entry_match * match,int numeric)119*a71a9546SAutomerger Merge Worker connlabel_mt_print(const void *ip, const struct xt_entry_match *match, int numeric)
120*a71a9546SAutomerger Merge Worker {
121*a71a9546SAutomerger Merge Worker const struct xt_connlabel_mtinfo *info = (const void *)match->data;
122*a71a9546SAutomerger Merge Worker const char *name = connlabel_get_name(info->bit);
123*a71a9546SAutomerger Merge Worker
124*a71a9546SAutomerger Merge Worker printf(" connlabel");
125*a71a9546SAutomerger Merge Worker if (info->options & XT_CONNLABEL_OP_INVERT)
126*a71a9546SAutomerger Merge Worker printf(" !");
127*a71a9546SAutomerger Merge Worker if (numeric || name == NULL) {
128*a71a9546SAutomerger Merge Worker printf(" %u", info->bit);
129*a71a9546SAutomerger Merge Worker } else {
130*a71a9546SAutomerger Merge Worker printf(" '%s'", name);
131*a71a9546SAutomerger Merge Worker }
132*a71a9546SAutomerger Merge Worker connlabel_mt_print_op(info, "");
133*a71a9546SAutomerger Merge Worker }
134*a71a9546SAutomerger Merge Worker
135*a71a9546SAutomerger Merge Worker static void
connlabel_mt_save(const void * ip,const struct xt_entry_match * match)136*a71a9546SAutomerger Merge Worker connlabel_mt_save(const void *ip, const struct xt_entry_match *match)
137*a71a9546SAutomerger Merge Worker {
138*a71a9546SAutomerger Merge Worker const struct xt_connlabel_mtinfo *info = (const void *)match->data;
139*a71a9546SAutomerger Merge Worker const char *name = connlabel_get_name(info->bit);
140*a71a9546SAutomerger Merge Worker
141*a71a9546SAutomerger Merge Worker if (info->options & XT_CONNLABEL_OP_INVERT)
142*a71a9546SAutomerger Merge Worker printf(" !");
143*a71a9546SAutomerger Merge Worker if (name)
144*a71a9546SAutomerger Merge Worker printf(" --label \"%s\"", name);
145*a71a9546SAutomerger Merge Worker else
146*a71a9546SAutomerger Merge Worker printf(" --label \"%u\"", info->bit);
147*a71a9546SAutomerger Merge Worker connlabel_mt_print_op(info, "--");
148*a71a9546SAutomerger Merge Worker }
149*a71a9546SAutomerger Merge Worker
connlabel_mt_xlate(struct xt_xlate * xl,const struct xt_xlate_mt_params * params)150*a71a9546SAutomerger Merge Worker static int connlabel_mt_xlate(struct xt_xlate *xl,
151*a71a9546SAutomerger Merge Worker const struct xt_xlate_mt_params *params)
152*a71a9546SAutomerger Merge Worker {
153*a71a9546SAutomerger Merge Worker const struct xt_connlabel_mtinfo *info =
154*a71a9546SAutomerger Merge Worker (const void *)params->match->data;
155*a71a9546SAutomerger Merge Worker const char *name = connlabel_get_name(info->bit);
156*a71a9546SAutomerger Merge Worker char *valbuf = NULL;
157*a71a9546SAutomerger Merge Worker
158*a71a9546SAutomerger Merge Worker if (name == NULL) {
159*a71a9546SAutomerger Merge Worker if (asprintf(&valbuf, "%u", info->bit) < 0)
160*a71a9546SAutomerger Merge Worker return 0;
161*a71a9546SAutomerger Merge Worker name = valbuf;
162*a71a9546SAutomerger Merge Worker }
163*a71a9546SAutomerger Merge Worker
164*a71a9546SAutomerger Merge Worker if (info->options & XT_CONNLABEL_OP_SET)
165*a71a9546SAutomerger Merge Worker xt_xlate_add(xl, "ct label set %s ", name);
166*a71a9546SAutomerger Merge Worker
167*a71a9546SAutomerger Merge Worker xt_xlate_add(xl, "ct label ");
168*a71a9546SAutomerger Merge Worker if (info->options & XT_CONNLABEL_OP_INVERT)
169*a71a9546SAutomerger Merge Worker xt_xlate_add(xl, "and %s != ", name);
170*a71a9546SAutomerger Merge Worker xt_xlate_add(xl, "%s", name);
171*a71a9546SAutomerger Merge Worker
172*a71a9546SAutomerger Merge Worker free(valbuf);
173*a71a9546SAutomerger Merge Worker return 1;
174*a71a9546SAutomerger Merge Worker }
175*a71a9546SAutomerger Merge Worker
176*a71a9546SAutomerger Merge Worker static struct xtables_match connlabel_mt_reg = {
177*a71a9546SAutomerger Merge Worker .family = NFPROTO_UNSPEC,
178*a71a9546SAutomerger Merge Worker .name = "connlabel",
179*a71a9546SAutomerger Merge Worker .version = XTABLES_VERSION,
180*a71a9546SAutomerger Merge Worker .size = XT_ALIGN(sizeof(struct xt_connlabel_mtinfo)),
181*a71a9546SAutomerger Merge Worker .userspacesize = offsetof(struct xt_connlabel_mtinfo, bit),
182*a71a9546SAutomerger Merge Worker .help = connlabel_mt_help,
183*a71a9546SAutomerger Merge Worker .print = connlabel_mt_print,
184*a71a9546SAutomerger Merge Worker .save = connlabel_mt_save,
185*a71a9546SAutomerger Merge Worker .x6_parse = connlabel_mt_parse,
186*a71a9546SAutomerger Merge Worker .x6_options = connlabel_mt_opts,
187*a71a9546SAutomerger Merge Worker .xlate = connlabel_mt_xlate,
188*a71a9546SAutomerger Merge Worker };
189*a71a9546SAutomerger Merge Worker
_init(void)190*a71a9546SAutomerger Merge Worker void _init(void)
191*a71a9546SAutomerger Merge Worker {
192*a71a9546SAutomerger Merge Worker xtables_register_match(&connlabel_mt_reg);
193*a71a9546SAutomerger Merge Worker }
194