1 /* ebt_ip6
2 *
3 * Authors:
4 * Kuo-Lang Tseng <kuo-lang.tseng@intel.com>
5 * Manohar Castelino <manohar.castelino@intel.com>
6 *
7 * Summary:
8 * This is just a modification of the IPv4 code written by
9 * Bart De Schuymer <bdschuym@pandora.be>
10 * with the changes required to support IPv6
11 *
12 */
13
14 #include <errno.h>
15 #include <arpa/inet.h>
16 #include <inttypes.h>
17 #include <limits.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <netdb.h>
22 #include <xtables.h>
23 #include <linux/netfilter_bridge/ebt_ip6.h>
24
25 #include "libxt_icmp.h"
26
27 /* must correspond to the bit position in EBT_IP6_* defines */
28 enum {
29 O_SOURCE = 0,
30 O_DEST,
31 O_TCLASS,
32 O_PROTO,
33 O_SPORT,
34 O_DPORT,
35 O_ICMP6,
36 F_PORT = 1 << O_ICMP6,
37 F_ICMP6 = 1 << O_SPORT | 1 << O_DPORT,
38 };
39
40 static const struct xt_option_entry brip6_opts[] = {
41 { .name = "ip6-source", .id = O_SOURCE, .type = XTTYPE_HOSTMASK,
42 .flags = XTOPT_INVERT },
43 { .name = "ip6-src", .id = O_SOURCE, .type = XTTYPE_HOSTMASK,
44 .flags = XTOPT_INVERT },
45 { .name = "ip6-destination", .id = O_DEST, .type = XTTYPE_HOSTMASK,
46 .flags = XTOPT_INVERT },
47 { .name = "ip6-dst", .id = O_DEST, .type = XTTYPE_HOSTMASK,
48 .flags = XTOPT_INVERT },
49 { .name = "ip6-tclass", .id = O_TCLASS, .type = XTTYPE_UINT8,
50 .flags = XTOPT_INVERT | XTOPT_PUT,
51 XTOPT_POINTER(struct ebt_ip6_info, tclass) },
52 { .name = "ip6-protocol", .id = O_PROTO, .type = XTTYPE_PROTOCOL,
53 .flags = XTOPT_INVERT | XTOPT_PUT,
54 XTOPT_POINTER(struct ebt_ip6_info, protocol) },
55 { .name = "ip6-proto", .id = O_PROTO, .type = XTTYPE_PROTOCOL,
56 .flags = XTOPT_INVERT | XTOPT_PUT,
57 XTOPT_POINTER(struct ebt_ip6_info, protocol) },
58 { .name = "ip6-source-port", .id = O_SPORT, .type = XTTYPE_PORTRC,
59 .excl = F_PORT, .flags = XTOPT_INVERT | XTOPT_PUT,
60 XTOPT_POINTER(struct ebt_ip6_info, sport) },
61 { .name = "ip6-sport", .id = O_SPORT, .type = XTTYPE_PORTRC,
62 .excl = F_PORT, .flags = XTOPT_INVERT | XTOPT_PUT,
63 XTOPT_POINTER(struct ebt_ip6_info, sport) },
64 { .name = "ip6-destination-port",.id = O_DPORT, .type = XTTYPE_PORTRC,
65 .excl = F_PORT, .flags = XTOPT_INVERT | XTOPT_PUT,
66 XTOPT_POINTER(struct ebt_ip6_info, dport) },
67 { .name = "ip6-dport", .id = O_DPORT, .type = XTTYPE_PORTRC,
68 .excl = F_PORT, .flags = XTOPT_INVERT | XTOPT_PUT,
69 XTOPT_POINTER(struct ebt_ip6_info, dport) },
70 { .name = "ip6-icmp-type", .id = O_ICMP6, .type = XTTYPE_STRING,
71 .excl = F_ICMP6, .flags = XTOPT_INVERT },
72 XTOPT_TABLEEND,
73 };
74
print_port_range(uint16_t * ports)75 static void print_port_range(uint16_t *ports)
76 {
77 if (ports[0] == ports[1])
78 printf("%d ", ports[0]);
79 else
80 printf("%d:%d ", ports[0], ports[1]);
81 }
82
print_icmp_code(uint8_t * code)83 static void print_icmp_code(uint8_t *code)
84 {
85 if (code[0] == code[1])
86 printf("/%"PRIu8 " ", code[0]);
87 else
88 printf("/%"PRIu8":%"PRIu8 " ", code[0], code[1]);
89 }
90
print_icmp_type(uint8_t * type,uint8_t * code)91 static void print_icmp_type(uint8_t *type, uint8_t *code)
92 {
93 unsigned int i;
94
95 if (type[0] != type[1]) {
96 printf("%"PRIu8 ":%" PRIu8, type[0], type[1]);
97 print_icmp_code(code);
98 return;
99 }
100
101 for (i = 0; i < ARRAY_SIZE(icmpv6_codes); i++) {
102 if (icmpv6_codes[i].type != type[0])
103 continue;
104
105 if (icmpv6_codes[i].code_min == code[0] &&
106 icmpv6_codes[i].code_max == code[1]) {
107 printf("%s ", icmpv6_codes[i].name);
108 return;
109 }
110 }
111 printf("%"PRIu8, type[0]);
112 print_icmp_code(code);
113 }
114
brip6_print_help(void)115 static void brip6_print_help(void)
116 {
117 printf(
118 "ip6 options:\n"
119 "[!] --ip6-src address[/mask]: ipv6 source specification\n"
120 "[!] --ip6-dst address[/mask]: ipv6 destination specification\n"
121 "[!] --ip6-tclass tclass : ipv6 traffic class specification\n"
122 "[!] --ip6-proto protocol : ipv6 protocol specification\n"
123 "[!] --ip6-sport port[:port] : tcp/udp source port or port range\n"
124 "[!] --ip6-dport port[:port] : tcp/udp destination port or port range\n"
125 "[!] --ip6-icmp-type type[[:type]/code[:code]] : ipv6-icmp type/code or type/code range\n");
126 printf("Valid ICMPv6 Types:");
127 xt_print_icmp_types(icmpv6_codes, ARRAY_SIZE(icmpv6_codes));
128 }
129
brip6_parse(struct xt_option_call * cb)130 static void brip6_parse(struct xt_option_call *cb)
131 {
132 struct ebt_ip6_info *info = cb->data;
133 unsigned int i;
134
135 /* XXX: overriding afinfo family is dangerous, but
136 * required for XTTYPE_HOSTMASK parsing */
137 xtables_set_nfproto(NFPROTO_IPV6);
138 xtables_option_parse(cb);
139 xtables_set_nfproto(NFPROTO_BRIDGE);
140
141 info->bitmask |= 1 << cb->entry->id;
142 info->invflags |= cb->invert ? 1 << cb->entry->id : 0;
143
144 switch (cb->entry->id) {
145 case O_SOURCE:
146 for (i = 0; i < ARRAY_SIZE(cb->val.haddr.all); i++)
147 cb->val.haddr.all[i] &= cb->val.hmask.all[i];
148 info->saddr = cb->val.haddr.in6;
149 info->smsk = cb->val.hmask.in6;
150 break;
151 case O_DEST:
152 for (i = 0; i < ARRAY_SIZE(cb->val.haddr.all); i++)
153 cb->val.haddr.all[i] &= cb->val.hmask.all[i];
154 info->daddr = cb->val.haddr.in6;
155 info->dmsk = cb->val.hmask.in6;
156 break;
157 case O_ICMP6:
158 ebt_parse_icmpv6(cb->arg, info->icmpv6_type, info->icmpv6_code);
159 break;
160 }
161 }
162
brip6_final_check(struct xt_fcheck_call * fc)163 static void brip6_final_check(struct xt_fcheck_call *fc)
164 {
165 if (!fc->xflags)
166 xtables_error(PARAMETER_PROBLEM,
167 "You must specify proper arguments");
168 }
169
brip6_print(const void * ip,const struct xt_entry_match * match,int numeric)170 static void brip6_print(const void *ip, const struct xt_entry_match *match,
171 int numeric)
172 {
173 struct ebt_ip6_info *ipinfo = (struct ebt_ip6_info *)match->data;
174
175 if (ipinfo->bitmask & EBT_IP6_SOURCE) {
176 if (ipinfo->invflags & EBT_IP6_SOURCE)
177 printf("! ");
178 printf("--ip6-src ");
179 printf("%s", xtables_ip6addr_to_numeric(&ipinfo->saddr));
180 printf("%s ", xtables_ip6mask_to_numeric(&ipinfo->smsk));
181 }
182 if (ipinfo->bitmask & EBT_IP6_DEST) {
183 if (ipinfo->invflags & EBT_IP6_DEST)
184 printf("! ");
185 printf("--ip6-dst ");
186 printf("%s", xtables_ip6addr_to_numeric(&ipinfo->daddr));
187 printf("%s ", xtables_ip6mask_to_numeric(&ipinfo->dmsk));
188 }
189 if (ipinfo->bitmask & EBT_IP6_TCLASS) {
190 if (ipinfo->invflags & EBT_IP6_TCLASS)
191 printf("! ");
192 printf("--ip6-tclass 0x%02X ", ipinfo->tclass);
193 }
194 if (ipinfo->bitmask & EBT_IP6_PROTO) {
195 struct protoent *pe;
196
197 if (ipinfo->invflags & EBT_IP6_PROTO)
198 printf("! ");
199 printf("--ip6-proto ");
200 pe = getprotobynumber(ipinfo->protocol);
201 if (pe == NULL) {
202 printf("%d ", ipinfo->protocol);
203 } else {
204 printf("%s ", pe->p_name);
205 }
206 }
207 if (ipinfo->bitmask & EBT_IP6_SPORT) {
208 if (ipinfo->invflags & EBT_IP6_SPORT)
209 printf("! ");
210 printf("--ip6-sport ");
211 print_port_range(ipinfo->sport);
212 }
213 if (ipinfo->bitmask & EBT_IP6_DPORT) {
214 if (ipinfo->invflags & EBT_IP6_DPORT)
215 printf("! ");
216 printf("--ip6-dport ");
217 print_port_range(ipinfo->dport);
218 }
219 if (ipinfo->bitmask & EBT_IP6_ICMP6) {
220 if (ipinfo->invflags & EBT_IP6_ICMP6)
221 printf("! ");
222 printf("--ip6-icmp-type ");
223 print_icmp_type(ipinfo->icmpv6_type, ipinfo->icmpv6_code);
224 }
225 }
226
brip_xlate_th(struct xt_xlate * xl,const struct ebt_ip6_info * info,int bit,const char * pname)227 static void brip_xlate_th(struct xt_xlate *xl,
228 const struct ebt_ip6_info *info, int bit,
229 const char *pname)
230 {
231 const uint16_t *ports;
232
233 if ((info->bitmask & bit) == 0)
234 return;
235
236 switch (bit) {
237 case EBT_IP6_SPORT:
238 if (pname)
239 xt_xlate_add(xl, "%s sport ", pname);
240 else
241 xt_xlate_add(xl, "@th,0,16 ");
242
243 ports = info->sport;
244 break;
245 case EBT_IP6_DPORT:
246 if (pname)
247 xt_xlate_add(xl, "%s dport ", pname);
248 else
249 xt_xlate_add(xl, "@th,16,16 ");
250
251 ports = info->dport;
252 break;
253 default:
254 return;
255 }
256
257 if (info->invflags & bit)
258 xt_xlate_add(xl, "!= ");
259
260 if (ports[0] == ports[1])
261 xt_xlate_add(xl, "%d ", ports[0]);
262 else
263 xt_xlate_add(xl, "%d-%d ", ports[0], ports[1]);
264 }
265
brip_xlate_nh(struct xt_xlate * xl,const struct ebt_ip6_info * info,int bit)266 static void brip_xlate_nh(struct xt_xlate *xl,
267 const struct ebt_ip6_info *info, int bit)
268 {
269 struct in6_addr *addrp, *maskp;
270
271 if ((info->bitmask & bit) == 0)
272 return;
273
274 switch (bit) {
275 case EBT_IP6_SOURCE:
276 xt_xlate_add(xl, "ip6 saddr ");
277 addrp = (struct in6_addr *)&info->saddr;
278 maskp = (struct in6_addr *)&info->smsk;
279 break;
280 case EBT_IP6_DEST:
281 xt_xlate_add(xl, "ip6 daddr ");
282 addrp = (struct in6_addr *)&info->daddr;
283 maskp = (struct in6_addr *)&info->dmsk;
284 break;
285 default:
286 return;
287 }
288
289 if (info->invflags & bit)
290 xt_xlate_add(xl, "!= ");
291
292 xt_xlate_add(xl, "%s%s ", xtables_ip6addr_to_numeric(addrp),
293 xtables_ip6mask_to_numeric(maskp));
294 }
295
brip6_xlate_proto_to_name(uint8_t proto)296 static const char *brip6_xlate_proto_to_name(uint8_t proto)
297 {
298 switch (proto) {
299 case IPPROTO_TCP:
300 return "tcp";
301 case IPPROTO_UDP:
302 return "udp";
303 case IPPROTO_UDPLITE:
304 return "udplite";
305 case IPPROTO_SCTP:
306 return "sctp";
307 case IPPROTO_DCCP:
308 return "dccp";
309 default:
310 return NULL;
311 }
312 }
313
brip6_xlate(struct xt_xlate * xl,const struct xt_xlate_mt_params * params)314 static int brip6_xlate(struct xt_xlate *xl,
315 const struct xt_xlate_mt_params *params)
316 {
317 const struct ebt_ip6_info *info = (const void *)params->match->data;
318 const char *pname = NULL;
319
320 if ((info->bitmask & (EBT_IP6_SOURCE|EBT_IP6_DEST|EBT_IP6_ICMP6|EBT_IP6_TCLASS)) == 0)
321 xt_xlate_add(xl, "ether type ip6 ");
322
323 brip_xlate_nh(xl, info, EBT_IP6_SOURCE);
324 brip_xlate_nh(xl, info, EBT_IP6_DEST);
325
326 if (info->bitmask & EBT_IP6_TCLASS) {
327 xt_xlate_add(xl, "ip6 dscp ");
328 if (info->invflags & EBT_IP6_TCLASS)
329 xt_xlate_add(xl, "!= ");
330 xt_xlate_add(xl, "0x%02x ", info->tclass & 0x3f); /* remove ECN bits */
331 }
332
333 if (info->bitmask & EBT_IP6_PROTO) {
334 struct protoent *pe;
335
336 if (info->bitmask & (EBT_IP6_SPORT|EBT_IP6_DPORT|EBT_IP6_ICMP6) &&
337 (info->invflags & EBT_IP6_PROTO) == 0) {
338 /* port number given and not inverted, no need to
339 * add explicit 'meta l4proto'.
340 */
341 pname = brip6_xlate_proto_to_name(info->protocol);
342 } else {
343 xt_xlate_add(xl, "meta l4proto ");
344 if (info->invflags & EBT_IP6_PROTO)
345 xt_xlate_add(xl, "!= ");
346 pe = getprotobynumber(info->protocol);
347 if (pe == NULL)
348 xt_xlate_add(xl, "%d ", info->protocol);
349 else
350 xt_xlate_add(xl, "%s ", pe->p_name);
351 }
352 }
353
354 brip_xlate_th(xl, info, EBT_IP6_SPORT, pname);
355 brip_xlate_th(xl, info, EBT_IP6_DPORT, pname);
356
357 if (info->bitmask & EBT_IP6_ICMP6) {
358 xt_xlate_add(xl, "icmpv6 type ");
359 if (info->invflags & EBT_IP6_ICMP6)
360 xt_xlate_add(xl, "!= ");
361
362 if (info->icmpv6_type[0] == info->icmpv6_type[1])
363 xt_xlate_add(xl, "%d ", info->icmpv6_type[0]);
364 else
365 xt_xlate_add(xl, "%d-%d ", info->icmpv6_type[0],
366 info->icmpv6_type[1]);
367
368 if (info->icmpv6_code[0] == 0 &&
369 info->icmpv6_code[1] == 0xff)
370 return 1;
371
372 xt_xlate_add(xl, "icmpv6 code ");
373 if (info->invflags & EBT_IP6_ICMP6)
374 xt_xlate_add(xl, "!= ");
375
376 if (info->icmpv6_code[0] == info->icmpv6_code[1])
377 xt_xlate_add(xl, "%d ", info->icmpv6_code[0]);
378 else
379 xt_xlate_add(xl, "%d-%d ", info->icmpv6_code[0],
380 info->icmpv6_code[1]);
381 }
382
383 return 1;
384 }
385
386 static struct xtables_match brip6_match = {
387 .name = "ip6",
388 .revision = 0,
389 .version = XTABLES_VERSION,
390 .family = NFPROTO_BRIDGE,
391 .size = XT_ALIGN(sizeof(struct ebt_ip6_info)),
392 .userspacesize = XT_ALIGN(sizeof(struct ebt_ip6_info)),
393 .help = brip6_print_help,
394 .x6_parse = brip6_parse,
395 .x6_fcheck = brip6_final_check,
396 .print = brip6_print,
397 .xlate = brip6_xlate,
398 .x6_options = brip6_opts,
399 };
400
_init(void)401 void _init(void)
402 {
403 xtables_register_match(&brip6_match);
404 }
405