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