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 <xtables.h>
9 #include <linux/netfilter/xt_addrtype.h>
10
11 enum {
12 O_SRC_TYPE = 0,
13 O_DST_TYPE,
14 O_LIMIT_IFACE_IN,
15 O_LIMIT_IFACE_OUT,
16 F_SRC_TYPE = 1 << O_SRC_TYPE,
17 F_DST_TYPE = 1 << O_DST_TYPE,
18 F_LIMIT_IFACE_IN = 1 << O_LIMIT_IFACE_IN,
19 F_LIMIT_IFACE_OUT = 1 << O_LIMIT_IFACE_OUT,
20 };
21
22 /* from linux/rtnetlink.h, must match order of enumeration */
23 static const char *const rtn_names[] = {
24 "UNSPEC",
25 "UNICAST",
26 "LOCAL",
27 "BROADCAST",
28 "ANYCAST",
29 "MULTICAST",
30 "BLACKHOLE",
31 "UNREACHABLE",
32 "PROHIBIT",
33 "THROW",
34 "NAT",
35 "XRESOLVE",
36 NULL
37 };
38
addrtype_help_types(void)39 static void addrtype_help_types(void)
40 {
41 int i;
42
43 for (i = 0; rtn_names[i]; i++)
44 printf(" %s\n", rtn_names[i]);
45 }
46
addrtype_help_v0(void)47 static void addrtype_help_v0(void)
48 {
49 printf(
50 "Address type match options:\n"
51 " [!] --src-type type[,...] Match source address type\n"
52 " [!] --dst-type type[,...] Match destination address type\n"
53 "\n"
54 "Valid types: \n");
55 addrtype_help_types();
56 }
57
addrtype_help_v1(void)58 static void addrtype_help_v1(void)
59 {
60 printf(
61 "Address type match options:\n"
62 " [!] --src-type type[,...] Match source address type\n"
63 " [!] --dst-type type[,...] Match destination address type\n"
64 " --limit-iface-in Match only on the packet's incoming device\n"
65 " --limit-iface-out Match only on the packet's outgoing device\n"
66 "\n"
67 "Valid types: \n");
68 addrtype_help_types();
69 }
70
71 static int
parse_type(const char * name,size_t len,uint16_t * mask)72 parse_type(const char *name, size_t len, uint16_t *mask)
73 {
74 int i;
75
76 for (i = 0; rtn_names[i]; i++)
77 if (strncasecmp(name, rtn_names[i], len) == 0) {
78 /* build up bitmask for kernel module */
79 *mask |= (1 << i);
80 return 1;
81 }
82
83 return 0;
84 }
85
parse_types(const char * arg,uint16_t * mask)86 static void parse_types(const char *arg, uint16_t *mask)
87 {
88 const char *comma;
89
90 while ((comma = strchr(arg, ',')) != NULL) {
91 if (comma == arg || !parse_type(arg, comma-arg, mask))
92 xtables_error(PARAMETER_PROBLEM,
93 "addrtype: bad type `%s'", arg);
94 arg = comma + 1;
95 }
96
97 if (strlen(arg) == 0 || !parse_type(arg, strlen(arg), mask))
98 xtables_error(PARAMETER_PROBLEM, "addrtype: bad type \"%s\"", arg);
99 }
100
addrtype_parse_v0(struct xt_option_call * cb)101 static void addrtype_parse_v0(struct xt_option_call *cb)
102 {
103 struct xt_addrtype_info *info = cb->data;
104
105 xtables_option_parse(cb);
106 switch (cb->entry->id) {
107 case O_SRC_TYPE:
108 parse_types(cb->arg, &info->source);
109 if (cb->invert)
110 info->invert_source = 1;
111 break;
112 case O_DST_TYPE:
113 parse_types(cb->arg, &info->dest);
114 if (cb->invert)
115 info->invert_dest = 1;
116 break;
117 }
118 }
119
addrtype_parse_v1(struct xt_option_call * cb)120 static void addrtype_parse_v1(struct xt_option_call *cb)
121 {
122 struct xt_addrtype_info_v1 *info = cb->data;
123
124 xtables_option_parse(cb);
125 switch (cb->entry->id) {
126 case O_SRC_TYPE:
127 parse_types(cb->arg, &info->source);
128 if (cb->invert)
129 info->flags |= XT_ADDRTYPE_INVERT_SOURCE;
130 break;
131 case O_DST_TYPE:
132 parse_types(cb->arg, &info->dest);
133 if (cb->invert)
134 info->flags |= XT_ADDRTYPE_INVERT_DEST;
135 break;
136 case O_LIMIT_IFACE_IN:
137 info->flags |= XT_ADDRTYPE_LIMIT_IFACE_IN;
138 break;
139 case O_LIMIT_IFACE_OUT:
140 info->flags |= XT_ADDRTYPE_LIMIT_IFACE_OUT;
141 break;
142 }
143 }
144
addrtype_check(struct xt_fcheck_call * cb)145 static void addrtype_check(struct xt_fcheck_call *cb)
146 {
147 if (!(cb->xflags & (F_SRC_TYPE | F_DST_TYPE)))
148 xtables_error(PARAMETER_PROBLEM,
149 "addrtype: you must specify --src-type or --dst-type");
150 }
151
print_types(uint16_t mask)152 static void print_types(uint16_t mask)
153 {
154 const char *sep = "";
155 int i;
156
157 for (i = 0; rtn_names[i]; i++)
158 if (mask & (1 << i)) {
159 printf("%s%s", sep, rtn_names[i]);
160 sep = ",";
161 }
162 }
163
addrtype_print_v0(const void * ip,const struct xt_entry_match * match,int numeric)164 static void addrtype_print_v0(const void *ip, const struct xt_entry_match *match,
165 int numeric)
166 {
167 const struct xt_addrtype_info *info = (const void *)match->data;
168
169 printf(" ADDRTYPE match");
170 if (info->source) {
171 printf(" src-type ");
172 if (info->invert_source)
173 printf("!");
174 print_types(info->source);
175 }
176 if (info->dest) {
177 printf(" dst-type");
178 if (info->invert_dest)
179 printf("!");
180 print_types(info->dest);
181 }
182 }
183
addrtype_print_v1(const void * ip,const struct xt_entry_match * match,int numeric)184 static void addrtype_print_v1(const void *ip, const struct xt_entry_match *match,
185 int numeric)
186 {
187 const struct xt_addrtype_info_v1 *info = (const void *)match->data;
188
189 printf(" ADDRTYPE match");
190 if (info->source) {
191 printf(" src-type ");
192 if (info->flags & XT_ADDRTYPE_INVERT_SOURCE)
193 printf("!");
194 print_types(info->source);
195 }
196 if (info->dest) {
197 printf(" dst-type ");
198 if (info->flags & XT_ADDRTYPE_INVERT_DEST)
199 printf("!");
200 print_types(info->dest);
201 }
202 if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN)
203 printf(" limit-in");
204 if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT)
205 printf(" limit-out");
206 }
207
addrtype_save_v0(const void * ip,const struct xt_entry_match * match)208 static void addrtype_save_v0(const void *ip, const struct xt_entry_match *match)
209 {
210 const struct xt_addrtype_info *info = (const void *)match->data;
211
212 if (info->source) {
213 if (info->invert_source)
214 printf(" !");
215 printf(" --src-type ");
216 print_types(info->source);
217 }
218 if (info->dest) {
219 if (info->invert_dest)
220 printf(" !");
221 printf(" --dst-type ");
222 print_types(info->dest);
223 }
224 }
225
addrtype_save_v1(const void * ip,const struct xt_entry_match * match)226 static void addrtype_save_v1(const void *ip, const struct xt_entry_match *match)
227 {
228 const struct xt_addrtype_info_v1 *info = (const void *)match->data;
229
230 if (info->source) {
231 if (info->flags & XT_ADDRTYPE_INVERT_SOURCE)
232 printf(" !");
233 printf(" --src-type ");
234 print_types(info->source);
235 }
236 if (info->dest) {
237 if (info->flags & XT_ADDRTYPE_INVERT_DEST)
238 printf(" !");
239 printf(" --dst-type ");
240 print_types(info->dest);
241 }
242 if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN)
243 printf(" --limit-iface-in");
244 if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT)
245 printf(" --limit-iface-out");
246 }
247
248 static const struct xt_option_entry addrtype_opts_v0[] = {
249 {.name = "src-type", .id = O_SRC_TYPE, .type = XTTYPE_STRING,
250 .flags = XTOPT_INVERT},
251 {.name = "dst-type", .id = O_DST_TYPE, .type = XTTYPE_STRING,
252 .flags = XTOPT_INVERT},
253 XTOPT_TABLEEND,
254 };
255
256 static const struct xt_option_entry addrtype_opts_v1[] = {
257 {.name = "src-type", .id = O_SRC_TYPE, .type = XTTYPE_STRING,
258 .flags = XTOPT_INVERT},
259 {.name = "dst-type", .id = O_DST_TYPE, .type = XTTYPE_STRING,
260 .flags = XTOPT_INVERT},
261 {.name = "limit-iface-in", .id = O_LIMIT_IFACE_IN,
262 .type = XTTYPE_NONE, .excl = F_LIMIT_IFACE_OUT},
263 {.name = "limit-iface-out", .id = O_LIMIT_IFACE_OUT,
264 .type = XTTYPE_NONE, .excl = F_LIMIT_IFACE_IN},
265 XTOPT_TABLEEND,
266 };
267
268 static struct xtables_match addrtype_mt_reg[] = {
269 {
270 .name = "addrtype",
271 .version = XTABLES_VERSION,
272 .family = NFPROTO_IPV4,
273 .size = XT_ALIGN(sizeof(struct xt_addrtype_info)),
274 .userspacesize = XT_ALIGN(sizeof(struct xt_addrtype_info)),
275 .help = addrtype_help_v0,
276 .print = addrtype_print_v0,
277 .save = addrtype_save_v0,
278 .x6_parse = addrtype_parse_v0,
279 .x6_fcheck = addrtype_check,
280 .x6_options = addrtype_opts_v0,
281 },
282 {
283 .name = "addrtype",
284 .revision = 1,
285 .version = XTABLES_VERSION,
286 .family = NFPROTO_UNSPEC,
287 .size = XT_ALIGN(sizeof(struct xt_addrtype_info_v1)),
288 .userspacesize = XT_ALIGN(sizeof(struct xt_addrtype_info_v1)),
289 .help = addrtype_help_v1,
290 .print = addrtype_print_v1,
291 .save = addrtype_save_v1,
292 .x6_parse = addrtype_parse_v1,
293 .x6_fcheck = addrtype_check,
294 .x6_options = addrtype_opts_v1,
295 },
296 };
297
298
_init(void)299 void _init(void)
300 {
301 xtables_register_matches(addrtype_mt_reg, ARRAY_SIZE(addrtype_mt_reg));
302 }
303