• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Shared library add-on to iptables to add devgroup matching support.
2  *
3  * Copyright (c) 2011 Patrick McHardy <kaber@trash.net>
4  */
5 #include <stdio.h>
6 #include <string.h>
7 #include <stdlib.h>
8 #include <errno.h>
9 #include <xtables.h>
10 #include <linux/netfilter/xt_devgroup.h>
11 
devgroup_help(void)12 static void devgroup_help(void)
13 {
14 	printf(
15 "devgroup match options:\n"
16 "[!] --src-group value[/mask]	Match device group of incoming device\n"
17 "[!] --dst-group value[/mask]	Match device group of outgoing device\n"
18 		);
19 }
20 
21 enum {
22 	O_SRC_GROUP = 0,
23 	O_DST_GROUP,
24 };
25 
26 static const struct xt_option_entry devgroup_opts[] = {
27 	{.name = "src-group", .id = O_SRC_GROUP, .type = XTTYPE_STRING,
28 	 .flags = XTOPT_INVERT},
29 	{.name = "dst-group", .id = O_DST_GROUP, .type = XTTYPE_STRING,
30 	 .flags = XTOPT_INVERT},
31 	XTOPT_TABLEEND,
32 };
33 
34 /* array of devgroups from /etc/iproute2/group */
35 static struct xtables_lmap *devgroups;
36 
devgroup_init(struct xt_entry_match * match)37 static void devgroup_init(struct xt_entry_match *match)
38 {
39 	const char file[] = "/etc/iproute2/group";
40 	devgroups = xtables_lmap_init(file);
41 	if (devgroups == NULL && errno != ENOENT)
42 		fprintf(stderr, "Warning: %s: %s\n", file, strerror(errno));
43 }
44 
devgroup_parse_groupspec(const char * arg,unsigned int * group,unsigned int * mask)45 static void devgroup_parse_groupspec(const char *arg, unsigned int *group,
46 				     unsigned int *mask)
47 {
48 	char *end;
49 	bool ok;
50 
51 	ok = xtables_strtoui(arg, &end, group, 0, UINT32_MAX);
52 	if (ok && (*end == '/' || *end == '\0')) {
53 		if (*end == '/')
54 			ok = xtables_strtoui(end + 1, NULL, mask,
55 			                     0, UINT32_MAX);
56 		else
57 			*mask = ~0U;
58 		if (!ok)
59 			xtables_error(PARAMETER_PROBLEM,
60 				      "Bad group value \"%s\"", arg);
61 	} else {
62 		*group = xtables_lmap_name2id(devgroups, arg);
63 		if (*group == -1)
64 			xtables_error(PARAMETER_PROBLEM,
65 				      "Device group \"%s\" not found", arg);
66 		*mask = ~0U;
67 	}
68 }
69 
devgroup_parse(struct xt_option_call * cb)70 static void devgroup_parse(struct xt_option_call *cb)
71 {
72 	struct xt_devgroup_info *info = cb->data;
73 	unsigned int id, mask;
74 
75 	xtables_option_parse(cb);
76 	switch (cb->entry->id) {
77 	case O_SRC_GROUP:
78 		devgroup_parse_groupspec(cb->arg, &id, &mask);
79 		info->src_group = id;
80 		info->src_mask  = mask;
81 		info->flags |= XT_DEVGROUP_MATCH_SRC;
82 		if (cb->invert)
83 			info->flags |= XT_DEVGROUP_INVERT_SRC;
84 		break;
85 	case O_DST_GROUP:
86 		devgroup_parse_groupspec(cb->arg, &id, &mask);
87 		info->dst_group = id;
88 		info->dst_mask  = mask;
89 		info->flags |= XT_DEVGROUP_MATCH_DST;
90 		if (cb->invert)
91 			info->flags |= XT_DEVGROUP_INVERT_DST;
92 		break;
93 	}
94 }
95 
96 static void
print_devgroup(unsigned int id,unsigned int mask,int numeric)97 print_devgroup(unsigned int id, unsigned int mask, int numeric)
98 {
99 	const char *name = NULL;
100 
101 	if (mask != 0xffffffff)
102 		printf("0x%x/0x%x", id, mask);
103 	else {
104 		if (numeric == 0)
105 			name = xtables_lmap_id2name(devgroups, id);
106 		if (name)
107 			printf("%s", name);
108 		else
109 			printf("0x%x", id);
110 	}
111 }
112 
devgroup_show(const char * pfx,const struct xt_devgroup_info * info,int numeric)113 static void devgroup_show(const char *pfx, const struct xt_devgroup_info *info,
114 			  int numeric)
115 {
116 	if (info->flags & XT_DEVGROUP_MATCH_SRC) {
117 		if (info->flags & XT_DEVGROUP_INVERT_SRC)
118 			printf(" !");
119 		printf(" %ssrc-group ", pfx);
120 		print_devgroup(info->src_group, info->src_mask, numeric);
121 	}
122 
123 	if (info->flags & XT_DEVGROUP_MATCH_DST) {
124 		if (info->flags & XT_DEVGROUP_INVERT_DST)
125 			printf(" !");
126 		printf(" %sdst-group ", pfx);
127 		print_devgroup(info->dst_group, info->dst_mask, numeric);
128 	}
129 }
130 
devgroup_print(const void * ip,const struct xt_entry_match * match,int numeric)131 static void devgroup_print(const void *ip, const struct xt_entry_match *match,
132                         int numeric)
133 {
134 	const struct xt_devgroup_info *info = (const void *)match->data;
135 
136 	devgroup_show("", info, numeric);
137 }
138 
devgroup_save(const void * ip,const struct xt_entry_match * match)139 static void devgroup_save(const void *ip, const struct xt_entry_match *match)
140 {
141 	const struct xt_devgroup_info *info = (const void *)match->data;
142 
143 	devgroup_show("--", info, 0);
144 }
145 
devgroup_check(struct xt_fcheck_call * cb)146 static void devgroup_check(struct xt_fcheck_call *cb)
147 {
148 	if (cb->xflags == 0)
149 		xtables_error(PARAMETER_PROBLEM,
150 			      "devgroup match: You must specify either "
151 			      "'--src-group' or '--dst-group'");
152 }
153 
154 static void
print_devgroup_xlate(unsigned int id,uint32_t op,unsigned int mask,struct xt_xlate * xl,int numeric)155 print_devgroup_xlate(unsigned int id, uint32_t op,  unsigned int mask,
156 		     struct xt_xlate *xl, int numeric)
157 {
158 	const char *name = NULL;
159 
160 	if (mask != 0xffffffff)
161 		xt_xlate_add(xl, "and 0x%x %s 0x%x", mask,
162 			   op == XT_OP_EQ ? "==" : "!=", id);
163 	else {
164 		if (numeric == 0)
165 			name = xtables_lmap_id2name(devgroups, id);
166 
167 		xt_xlate_add(xl, "%s", op == XT_OP_EQ ? "" : "!= ");
168 		if (name)
169 			xt_xlate_add(xl, "%s", name);
170 		else
171 			xt_xlate_add(xl, "0x%x", id);
172 	}
173 }
174 
devgroup_show_xlate(const struct xt_devgroup_info * info,struct xt_xlate * xl,int numeric)175 static void devgroup_show_xlate(const struct xt_devgroup_info *info,
176 				struct xt_xlate *xl, int numeric)
177 {
178 	enum xt_op op = XT_OP_EQ;
179 	char *space = "";
180 
181 	if (info->flags & XT_DEVGROUP_MATCH_SRC) {
182 		if (info->flags & XT_DEVGROUP_INVERT_SRC)
183 			op = XT_OP_NEQ;
184 		xt_xlate_add(xl, "iifgroup ");
185 		print_devgroup_xlate(info->src_group, op,
186 				     info->src_mask, xl, numeric);
187 		space = " ";
188 	}
189 
190 	if (info->flags & XT_DEVGROUP_MATCH_DST) {
191 		if (info->flags & XT_DEVGROUP_INVERT_DST)
192 			op = XT_OP_NEQ;
193 		xt_xlate_add(xl, "%soifgroup ", space);
194 		print_devgroup_xlate(info->dst_group, op,
195 				     info->dst_mask, xl, numeric);
196 	}
197 }
198 
devgroup_xlate(struct xt_xlate * xl,const struct xt_xlate_mt_params * params)199 static int devgroup_xlate(struct xt_xlate *xl,
200 			  const struct xt_xlate_mt_params *params)
201 {
202 	const struct xt_devgroup_info *info = (const void *)params->match->data;
203 
204 	devgroup_show_xlate(info, xl, 0);
205 
206 	return 1;
207 }
208 
209 static struct xtables_match devgroup_mt_reg = {
210 	.name		= "devgroup",
211 	.version	= XTABLES_VERSION,
212 	.family		= NFPROTO_UNSPEC,
213 	.size		= XT_ALIGN(sizeof(struct xt_devgroup_info)),
214 	.userspacesize	= XT_ALIGN(sizeof(struct xt_devgroup_info)),
215 	.init		= devgroup_init,
216 	.help		= devgroup_help,
217 	.print		= devgroup_print,
218 	.save		= devgroup_save,
219 	.x6_parse	= devgroup_parse,
220 	.x6_fcheck	= devgroup_check,
221 	.x6_options	= devgroup_opts,
222 	.xlate		= devgroup_xlate,
223 };
224 
_init(void)225 void _init(void)
226 {
227 	xtables_register_match(&devgroup_mt_reg);
228 }
229