1 /* Shared library add-on to iptables to add addrtype matching support
2 *
3 * Copyright (c) 2003-2013 Patrick McHardy <kaber@trash.net>
4 *
5 * This program is released under the terms of GNU GPL */
6 #include <stdio.h>
7 #include <string.h>
8 #include <strings.h>
9 #include <xtables.h>
10 #include <linux/netfilter/xt_addrtype.h>
11
12 enum {
13 O_SRC_TYPE = 0,
14 O_DST_TYPE,
15 O_LIMIT_IFACE_IN,
16 O_LIMIT_IFACE_OUT,
17 F_SRC_TYPE = 1 << O_SRC_TYPE,
18 F_DST_TYPE = 1 << O_DST_TYPE,
19 F_LIMIT_IFACE_IN = 1 << O_LIMIT_IFACE_IN,
20 F_LIMIT_IFACE_OUT = 1 << O_LIMIT_IFACE_OUT,
21 };
22
23 /* from linux/rtnetlink.h, must match order of enumeration */
24 static const char *const rtn_names[] = {
25 "UNSPEC",
26 "UNICAST",
27 "LOCAL",
28 "BROADCAST",
29 "ANYCAST",
30 "MULTICAST",
31 "BLACKHOLE",
32 "UNREACHABLE",
33 "PROHIBIT",
34 "THROW",
35 "NAT",
36 "XRESOLVE",
37 NULL
38 };
39
addrtype_help_types(void)40 static void addrtype_help_types(void)
41 {
42 int i;
43
44 for (i = 0; rtn_names[i]; i++)
45 printf(" %s\n", rtn_names[i]);
46 }
47
addrtype_help_v0(void)48 static void addrtype_help_v0(void)
49 {
50 printf(
51 "Address type match options:\n"
52 " [!] --src-type type[,...] Match source address type\n"
53 " [!] --dst-type type[,...] Match destination address type\n"
54 "\n"
55 "Valid types: \n");
56 addrtype_help_types();
57 }
58
addrtype_help_v1(void)59 static void addrtype_help_v1(void)
60 {
61 printf(
62 "Address type match options:\n"
63 " [!] --src-type type[,...] Match source address type\n"
64 " [!] --dst-type type[,...] Match destination address type\n"
65 " --limit-iface-in Match only on the packet's incoming device\n"
66 " --limit-iface-out Match only on the packet's outgoing device\n"
67 "\n"
68 "Valid types: \n");
69 addrtype_help_types();
70 }
71
72 static int
parse_type(const char * name,size_t len,uint16_t * mask)73 parse_type(const char *name, size_t len, uint16_t *mask)
74 {
75 int i;
76
77 for (i = 0; rtn_names[i]; i++)
78 if (strncasecmp(name, rtn_names[i], len) == 0) {
79 /* build up bitmask for kernel module */
80 *mask |= (1 << i);
81 return 1;
82 }
83
84 return 0;
85 }
86
parse_types(const char * arg,uint16_t * mask)87 static void parse_types(const char *arg, uint16_t *mask)
88 {
89 const char *comma;
90
91 while ((comma = strchr(arg, ',')) != NULL) {
92 if (comma == arg || !parse_type(arg, comma-arg, mask))
93 xtables_error(PARAMETER_PROBLEM,
94 "addrtype: bad type `%s'", arg);
95 arg = comma + 1;
96 }
97
98 if (strlen(arg) == 0 || !parse_type(arg, strlen(arg), mask))
99 xtables_error(PARAMETER_PROBLEM, "addrtype: bad type \"%s\"", arg);
100 }
101
addrtype_parse_v0(struct xt_option_call * cb)102 static void addrtype_parse_v0(struct xt_option_call *cb)
103 {
104 struct xt_addrtype_info *info = cb->data;
105
106 xtables_option_parse(cb);
107 switch (cb->entry->id) {
108 case O_SRC_TYPE:
109 parse_types(cb->arg, &info->source);
110 if (cb->invert)
111 info->invert_source = 1;
112 break;
113 case O_DST_TYPE:
114 parse_types(cb->arg, &info->dest);
115 if (cb->invert)
116 info->invert_dest = 1;
117 break;
118 }
119 }
120
addrtype_parse_v1(struct xt_option_call * cb)121 static void addrtype_parse_v1(struct xt_option_call *cb)
122 {
123 struct xt_addrtype_info_v1 *info = cb->data;
124
125 xtables_option_parse(cb);
126 switch (cb->entry->id) {
127 case O_SRC_TYPE:
128 parse_types(cb->arg, &info->source);
129 if (cb->invert)
130 info->flags |= XT_ADDRTYPE_INVERT_SOURCE;
131 break;
132 case O_DST_TYPE:
133 parse_types(cb->arg, &info->dest);
134 if (cb->invert)
135 info->flags |= XT_ADDRTYPE_INVERT_DEST;
136 break;
137 case O_LIMIT_IFACE_IN:
138 info->flags |= XT_ADDRTYPE_LIMIT_IFACE_IN;
139 break;
140 case O_LIMIT_IFACE_OUT:
141 info->flags |= XT_ADDRTYPE_LIMIT_IFACE_OUT;
142 break;
143 }
144 }
145
addrtype_check(struct xt_fcheck_call * cb)146 static void addrtype_check(struct xt_fcheck_call *cb)
147 {
148 if (!(cb->xflags & (F_SRC_TYPE | F_DST_TYPE)))
149 xtables_error(PARAMETER_PROBLEM,
150 "addrtype: you must specify --src-type or --dst-type");
151 }
152
print_types(uint16_t mask)153 static void print_types(uint16_t mask)
154 {
155 const char *sep = "";
156 int i;
157
158 for (i = 0; rtn_names[i]; i++)
159 if (mask & (1 << i)) {
160 printf("%s%s", sep, rtn_names[i]);
161 sep = ",";
162 }
163 }
164
addrtype_print_v0(const void * ip,const struct xt_entry_match * match,int numeric)165 static void addrtype_print_v0(const void *ip, const struct xt_entry_match *match,
166 int numeric)
167 {
168 const struct xt_addrtype_info *info = (const void *)match->data;
169
170 printf(" ADDRTYPE match");
171 if (info->source) {
172 printf(" src-type ");
173 if (info->invert_source)
174 printf("!");
175 print_types(info->source);
176 }
177 if (info->dest) {
178 printf(" dst-type");
179 if (info->invert_dest)
180 printf("!");
181 print_types(info->dest);
182 }
183 }
184
addrtype_print_v1(const void * ip,const struct xt_entry_match * match,int numeric)185 static void addrtype_print_v1(const void *ip, const struct xt_entry_match *match,
186 int numeric)
187 {
188 const struct xt_addrtype_info_v1 *info = (const void *)match->data;
189
190 printf(" ADDRTYPE match");
191 if (info->source) {
192 printf(" src-type ");
193 if (info->flags & XT_ADDRTYPE_INVERT_SOURCE)
194 printf("!");
195 print_types(info->source);
196 }
197 if (info->dest) {
198 printf(" dst-type ");
199 if (info->flags & XT_ADDRTYPE_INVERT_DEST)
200 printf("!");
201 print_types(info->dest);
202 }
203 if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN)
204 printf(" limit-in");
205 if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT)
206 printf(" limit-out");
207 }
208
addrtype_save_v0(const void * ip,const struct xt_entry_match * match)209 static void addrtype_save_v0(const void *ip, const struct xt_entry_match *match)
210 {
211 const struct xt_addrtype_info *info = (const void *)match->data;
212
213 if (info->source) {
214 if (info->invert_source)
215 printf(" !");
216 printf(" --src-type ");
217 print_types(info->source);
218 }
219 if (info->dest) {
220 if (info->invert_dest)
221 printf(" !");
222 printf(" --dst-type ");
223 print_types(info->dest);
224 }
225 }
226
addrtype_save_v1(const void * ip,const struct xt_entry_match * match)227 static void addrtype_save_v1(const void *ip, const struct xt_entry_match *match)
228 {
229 const struct xt_addrtype_info_v1 *info = (const void *)match->data;
230
231 if (info->source) {
232 if (info->flags & XT_ADDRTYPE_INVERT_SOURCE)
233 printf(" !");
234 printf(" --src-type ");
235 print_types(info->source);
236 }
237 if (info->dest) {
238 if (info->flags & XT_ADDRTYPE_INVERT_DEST)
239 printf(" !");
240 printf(" --dst-type ");
241 print_types(info->dest);
242 }
243 if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN)
244 printf(" --limit-iface-in");
245 if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT)
246 printf(" --limit-iface-out");
247 }
248
249 static const char *const rtn_lnames[] = {
250 "unspec",
251 "unicast",
252 "local",
253 "broadcast",
254 "anycast",
255 "multicast",
256 "blackhole",
257 "unreachable",
258 "prohibit",
259 NULL,
260 };
261
multiple_bits_set(uint16_t val)262 static bool multiple_bits_set(uint16_t val)
263 {
264 int first = ffs(val);
265
266 return first && (val >> first) > 0;
267 }
268
addrtype_xlate(struct xt_xlate * xl,const struct xt_xlate_mt_params * params)269 static int addrtype_xlate(struct xt_xlate *xl,
270 const struct xt_xlate_mt_params *params)
271 {
272 const struct xt_addrtype_info_v1 *info =
273 (const void *)params->match->data;
274 const char *sep = "";
275 bool need_braces;
276 uint16_t val;
277 int i;
278
279 xt_xlate_add(xl, "fib ");
280
281 if (info->source) {
282 xt_xlate_add(xl, "saddr ");
283 val = info->source;
284 } else {
285 xt_xlate_add(xl, "daddr ");
286 val = info->dest;
287 }
288
289 if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN)
290 xt_xlate_add(xl, ". iif ");
291 else if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT)
292 xt_xlate_add(xl, ". oif ");
293
294 xt_xlate_add(xl, "type ");
295
296 if (info->flags & (XT_ADDRTYPE_INVERT_SOURCE | XT_ADDRTYPE_INVERT_DEST))
297 xt_xlate_add(xl, "!= ");
298
299 need_braces = multiple_bits_set(val);
300
301 if (need_braces)
302 xt_xlate_add(xl, "{ ");
303
304 for (i = 0; rtn_lnames[i]; i++) {
305 if (val & (1 << i)) {
306 xt_xlate_add(xl, "%s%s", sep, rtn_lnames[i]);
307 sep = ", ";
308 }
309 }
310
311 if (need_braces)
312 xt_xlate_add(xl, " }");
313
314 return 1;
315 }
316
317 static const struct xt_option_entry addrtype_opts_v0[] = {
318 {.name = "src-type", .id = O_SRC_TYPE, .type = XTTYPE_STRING,
319 .flags = XTOPT_INVERT},
320 {.name = "dst-type", .id = O_DST_TYPE, .type = XTTYPE_STRING,
321 .flags = XTOPT_INVERT},
322 XTOPT_TABLEEND,
323 };
324
325 static const struct xt_option_entry addrtype_opts_v1[] = {
326 {.name = "src-type", .id = O_SRC_TYPE, .type = XTTYPE_STRING,
327 .flags = XTOPT_INVERT},
328 {.name = "dst-type", .id = O_DST_TYPE, .type = XTTYPE_STRING,
329 .flags = XTOPT_INVERT},
330 {.name = "limit-iface-in", .id = O_LIMIT_IFACE_IN,
331 .type = XTTYPE_NONE, .excl = F_LIMIT_IFACE_OUT},
332 {.name = "limit-iface-out", .id = O_LIMIT_IFACE_OUT,
333 .type = XTTYPE_NONE, .excl = F_LIMIT_IFACE_IN},
334 XTOPT_TABLEEND,
335 };
336
337 static struct xtables_match addrtype_mt_reg[] = {
338 {
339 .name = "addrtype",
340 .version = XTABLES_VERSION,
341 .family = NFPROTO_IPV4,
342 .size = XT_ALIGN(sizeof(struct xt_addrtype_info)),
343 .userspacesize = XT_ALIGN(sizeof(struct xt_addrtype_info)),
344 .help = addrtype_help_v0,
345 .print = addrtype_print_v0,
346 .save = addrtype_save_v0,
347 .x6_parse = addrtype_parse_v0,
348 .x6_fcheck = addrtype_check,
349 .x6_options = addrtype_opts_v0,
350 },
351 {
352 .name = "addrtype",
353 .revision = 1,
354 .version = XTABLES_VERSION,
355 .family = NFPROTO_UNSPEC,
356 .size = XT_ALIGN(sizeof(struct xt_addrtype_info_v1)),
357 .userspacesize = XT_ALIGN(sizeof(struct xt_addrtype_info_v1)),
358 .help = addrtype_help_v1,
359 .print = addrtype_print_v1,
360 .save = addrtype_save_v1,
361 .x6_parse = addrtype_parse_v1,
362 .x6_fcheck = addrtype_check,
363 .x6_options = addrtype_opts_v1,
364 .xlate = addrtype_xlate,
365 },
366 };
367
368
_init(void)369 void _init(void)
370 {
371 xtables_register_matches(addrtype_mt_reg, ARRAY_SIZE(addrtype_mt_reg));
372 }
373