• 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 	int tmp;
74 
75 	xtables_option_parse(cb);
76 
77 	switch (cb->entry->id) {
78 	case O_LABEL:
79 		tmp = connlabel_value_parse(cb->arg);
80 		if (tmp < 0 && !connlabel_open())
81 			tmp = nfct_labelmap_get_bit(map, cb->arg);
82 		if (tmp < 0)
83 			xtables_error(PARAMETER_PROBLEM,
84 				      "label '%s' not found or invalid value",
85 				      cb->arg);
86 
87 		info->bit = tmp;
88 		if (cb->invert)
89 			info->options |= XT_CONNLABEL_OP_INVERT;
90 		break;
91 	case O_SET:
92 		info->options |= XT_CONNLABEL_OP_SET;
93 		break;
94 	}
95 
96 }
97 
connlabel_get_name(int b)98 static const char *connlabel_get_name(int b)
99 {
100 	const char *name;
101 
102 	if (connlabel_open())
103 		return NULL;
104 
105 	name = nfct_labelmap_get_name(map, b);
106 	if (name && strcmp(name, ""))
107 		return name;
108 	return NULL;
109 }
110 
111 static void
connlabel_mt_print_op(const struct xt_connlabel_mtinfo * info,const char * prefix)112 connlabel_mt_print_op(const struct xt_connlabel_mtinfo *info, const char *prefix)
113 {
114 	if (info->options & XT_CONNLABEL_OP_SET)
115 		printf(" %sset", prefix);
116 }
117 
118 static void
connlabel_mt_print(const void * ip,const struct xt_entry_match * match,int numeric)119 connlabel_mt_print(const void *ip, const struct xt_entry_match *match, int numeric)
120 {
121 	const struct xt_connlabel_mtinfo *info = (const void *)match->data;
122 	const char *name = connlabel_get_name(info->bit);
123 
124 	printf(" connlabel");
125 	if (info->options & XT_CONNLABEL_OP_INVERT)
126 		printf(" !");
127 	if (numeric || name == NULL) {
128 		printf(" %u", info->bit);
129 	} else {
130 		printf(" '%s'", name);
131 	}
132 	connlabel_mt_print_op(info, "");
133 }
134 
135 static void
connlabel_mt_save(const void * ip,const struct xt_entry_match * match)136 connlabel_mt_save(const void *ip, const struct xt_entry_match *match)
137 {
138 	const struct xt_connlabel_mtinfo *info = (const void *)match->data;
139 	const char *name = connlabel_get_name(info->bit);
140 
141 	if (info->options & XT_CONNLABEL_OP_INVERT)
142 		printf(" !");
143 	if (name)
144 		printf(" --label \"%s\"", name);
145 	else
146 		printf(" --label \"%u\"", info->bit);
147 	connlabel_mt_print_op(info, "--");
148 }
149 
connlabel_mt_xlate(struct xt_xlate * xl,const struct xt_xlate_mt_params * params)150 static int connlabel_mt_xlate(struct xt_xlate *xl,
151 			      const struct xt_xlate_mt_params *params)
152 {
153 	const struct xt_connlabel_mtinfo *info =
154 		(const void *)params->match->data;
155 	const char *name = connlabel_get_name(info->bit);
156 	char *valbuf = NULL;
157 
158 	if (name == NULL) {
159 		if (asprintf(&valbuf, "%u", info->bit) < 0)
160 			return 0;
161 		name = valbuf;
162 	}
163 
164 	if (info->options & XT_CONNLABEL_OP_SET)
165 		xt_xlate_add(xl, "ct label set %s ", name);
166 
167 	xt_xlate_add(xl, "ct label ");
168 	if (info->options & XT_CONNLABEL_OP_INVERT)
169 		xt_xlate_add(xl, "and %s != ", name);
170 	xt_xlate_add(xl, "%s", name);
171 
172 	free(valbuf);
173 	return 1;
174 }
175 
176 static struct xtables_match connlabel_mt_reg = {
177 	.family        = NFPROTO_UNSPEC,
178 	.name          = "connlabel",
179 	.version       = XTABLES_VERSION,
180 	.size          = XT_ALIGN(sizeof(struct xt_connlabel_mtinfo)),
181 	.userspacesize = offsetof(struct xt_connlabel_mtinfo, bit),
182 	.help          = connlabel_mt_help,
183 	.print         = connlabel_mt_print,
184 	.save          = connlabel_mt_save,
185 	.x6_parse      = connlabel_mt_parse,
186 	.x6_options    = connlabel_mt_opts,
187 	.xlate	       = connlabel_mt_xlate,
188 };
189 
_init(void)190 void _init(void)
191 {
192 	xtables_register_match(&connlabel_mt_reg);
193 }
194