xref: /aosp_15_r20/external/iptables/extensions/libxt_connlabel.c (revision a71a954618bbadd4a345637e5edcf36eec826889)
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