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