1 #include <errno.h>
2 #include <stdbool.h>
3 #include <string.h>
4 #include <stdio.h>
5 #include <stdint.h>
6 #include <xtables.h>
7 #include <linux/netfilter/xt_connlabel.h>
8 #include <libnetfilter_conntrack/libnetfilter_conntrack.h>
9
10 enum {
11 O_LABEL = 0,
12 O_SET = 1,
13 };
14
15 static struct nfct_labelmap *map;
16
connlabel_mt_help(void)17 static void connlabel_mt_help(void)
18 {
19 puts(
20 "connlabel match options:\n"
21 "[!] --label name Match if label has been set on connection\n"
22 " --set Set label on connection");
23 }
24
25 static const struct xt_option_entry connlabel_mt_opts[] = {
26 {.name = "label", .id = O_LABEL, .type = XTTYPE_STRING,
27 .min = 1, .flags = XTOPT_MAND|XTOPT_INVERT},
28 {.name = "set", .id = O_SET, .type = XTTYPE_NONE},
29 XTOPT_TABLEEND,
30 };
31
connlabel_mt_parse(struct xt_option_call * cb)32 static void connlabel_mt_parse(struct xt_option_call *cb)
33 {
34 struct xt_connlabel_mtinfo *info = cb->data;
35 int tmp;
36
37 xtables_option_parse(cb);
38
39 switch (cb->entry->id) {
40 case O_LABEL:
41 tmp = nfct_labelmap_get_bit(map, cb->arg);
42 if (tmp < 0)
43 xtables_error(PARAMETER_PROBLEM, "label '%s' not found", cb->arg);
44 info->bit = tmp;
45 if (cb->invert)
46 info->options |= XT_CONNLABEL_OP_INVERT;
47 break;
48 case O_SET:
49 info->options |= XT_CONNLABEL_OP_SET;
50 break;
51 }
52
53 }
54
connlabel_get_name(int b)55 static const char *connlabel_get_name(int b)
56 {
57 const char *name = nfct_labelmap_get_name(map, b);
58 if (name && strcmp(name, ""))
59 return name;
60 return NULL;
61 }
62
63 static void
connlabel_mt_print_op(const struct xt_connlabel_mtinfo * info,const char * prefix)64 connlabel_mt_print_op(const struct xt_connlabel_mtinfo *info, const char *prefix)
65 {
66 if (info->options & XT_CONNLABEL_OP_SET)
67 printf(" %sset", prefix);
68 }
69
70 static void
connlabel_mt_print(const void * ip,const struct xt_entry_match * match,int numeric)71 connlabel_mt_print(const void *ip, const struct xt_entry_match *match, int numeric)
72 {
73 const struct xt_connlabel_mtinfo *info = (const void *)match->data;
74 const char *name = connlabel_get_name(info->bit);
75
76 printf(" connlabel");
77 if (info->options & XT_CONNLABEL_OP_INVERT)
78 printf(" !");
79 if (numeric || name == NULL) {
80 printf(" %u", info->bit);
81 } else {
82 printf(" '%s'", name);
83 }
84 connlabel_mt_print_op(info, "");
85 }
86
87 static void
connlabel_mt_save(const void * ip,const struct xt_entry_match * match)88 connlabel_mt_save(const void *ip, const struct xt_entry_match *match)
89 {
90 const struct xt_connlabel_mtinfo *info = (const void *)match->data;
91 const char *name = connlabel_get_name(info->bit);
92
93 if (info->options & XT_CONNLABEL_OP_INVERT)
94 printf(" !");
95 if (name)
96 printf(" --label \"%s\"", name);
97 else
98 printf(" --label \"%u\"", info->bit);
99 connlabel_mt_print_op(info, "--");
100 }
101
102 static struct xtables_match connlabel_mt_reg = {
103 .family = NFPROTO_UNSPEC,
104 .name = "connlabel",
105 .version = XTABLES_VERSION,
106 .size = XT_ALIGN(sizeof(struct xt_connlabel_mtinfo)),
107 .userspacesize = offsetof(struct xt_connlabel_mtinfo, bit),
108 .help = connlabel_mt_help,
109 .print = connlabel_mt_print,
110 .save = connlabel_mt_save,
111 .x6_parse = connlabel_mt_parse,
112 .x6_options = connlabel_mt_opts,
113 };
114
_init(void)115 void _init(void)
116 {
117 map = nfct_labelmap_new(NULL);
118 if (!map) {
119 fprintf(stderr, "cannot open connlabel.conf, not registering '%s' match: %s\n",
120 connlabel_mt_reg.name, strerror(errno));
121 return;
122 }
123 xtables_register_match(&connlabel_mt_reg);
124 }
125