1 /* ipv6header match - matches IPv6 packets based
2 on whether they contain certain headers */
4 /* Original idea: Brad Chapman
5 * Rewritten by: Andras Kis-Szabo <kisza@sch.bme.hu> */
14 #include <sys/types.h>
16 #include <linux/netfilter_ipv6/ip6_tables.h>
17 #include <linux/netfilter_ipv6/ip6t_ipv6header.h>
19 /* This maybe required
21 #include <linux/in6.h>
25 /* A few hardcoded protocols for 'all' and in case the user has no
37 static const struct pprot chain_protos
[] = {
38 { "hop-by-hop", IPPROTO_HOPOPTS
},
39 { "protocol", IPPROTO_RAW
},
40 { "hop", IPPROTO_HOPOPTS
},
41 { "dst", IPPROTO_DSTOPTS
},
42 { "route", IPPROTO_ROUTING
},
43 { "frag", IPPROTO_FRAGMENT
},
44 { "auth", IPPROTO_AH
},
45 { "esp", IPPROTO_ESP
},
46 { "none", IPPROTO_NONE
},
47 { "prot", IPPROTO_RAW
},
48 { "0", IPPROTO_HOPOPTS
},
49 { "60", IPPROTO_DSTOPTS
},
50 { "43", IPPROTO_ROUTING
},
51 { "44", IPPROTO_FRAGMENT
},
53 { "50", IPPROTO_ESP
},
54 { "59", IPPROTO_NONE
},
55 { "255", IPPROTO_RAW
},
59 static const struct numflag chain_flags
[] = {
60 { IPPROTO_HOPOPTS
, MASK_HOPOPTS
},
61 { IPPROTO_DSTOPTS
, MASK_DSTOPTS
},
62 { IPPROTO_ROUTING
, MASK_ROUTING
},
63 { IPPROTO_FRAGMENT
, MASK_FRAGMENT
},
64 { IPPROTO_AH
, MASK_AH
},
65 { IPPROTO_ESP
, MASK_ESP
},
66 { IPPROTO_NONE
, MASK_NONE
},
67 { IPPROTO_RAW
, MASK_PROTO
},
71 proto_to_name(u_int8_t proto
, int nolookup
)
75 if (proto
&& !nolookup
) {
76 struct protoent
*pent
= getprotobynumber(proto
);
81 for (i
= 0; i
< sizeof(chain_protos
)/sizeof(struct pprot
); i
++)
82 if (chain_protos
[i
].num
== proto
)
83 return chain_protos
[i
].name
;
89 name_to_proto(const char *s
)
92 struct protoent
*pent
;
94 if ((pent
= getprotobyname(s
)))
95 proto
= pent
->p_proto
;
99 i
< sizeof(chain_protos
)/sizeof(struct pprot
);
101 if (strcmp(s
, chain_protos
[i
].name
) == 0) {
102 proto
= chain_protos
[i
].num
;
107 if (i
== sizeof(chain_protos
)/sizeof(struct pprot
))
108 exit_error(PARAMETER_PROBLEM
,
109 "unknown header `%s' specified",
113 return (u_int16_t
)proto
;
117 add_proto_to_mask(int proto
){
118 unsigned int i
=0, flag
=0;
121 i
< sizeof(chain_flags
)/sizeof(struct numflag
);
123 if (proto
== chain_flags
[i
].proto
){
124 flag
= chain_flags
[i
].flag
;
129 if (i
== sizeof(chain_flags
)/sizeof(struct numflag
))
130 exit_error(PARAMETER_PROBLEM
,
131 "unknown header `%d' specified",
141 "ipv6header v%s match options:\n"
142 "--header [!] headers Type of header to match, by name\n"
143 " names: hop,dst,route,frag,auth,esp,none,proto\n"
144 " long names: hop-by-hop,ipv6-opts,ipv6-route,\n"
145 " ipv6-frag,ah,esp,ipv6-nonxt,protocol\n"
146 " numbers: 0,60,43,44,51,50,59\n"
147 "--soft The header CONTAINS the specified extensions\n",
151 static struct option opts
[] = {
152 { "header", 1, 0, '1' },
153 { "soft", 0, 0, '2' },
158 init(struct ip6t_entry_match
*m
, unsigned int *nfcache
)
160 struct ip6t_ipv6header_info
*info
= (struct ip6t_ipv6header_info
*)m
->data
;
162 info
->matchflags
= 0x00;
163 info
->invflags
= 0x00;
164 info
->modeflag
= 0x00;
168 parse_header(const char *flags
) {
169 unsigned int ret
= 0;
173 buffer
= strdup(flags
);
175 for (ptr
= strtok(buffer
, ","); ptr
; ptr
= strtok(NULL
, ","))
176 ret
|= add_proto_to_mask(name_to_proto(ptr
));
182 #define IPV6_HDR_HEADER 0x01
183 #define IPV6_HDR_SOFT 0x02
185 /* Parses command options; returns 0 if it ate an option */
187 parse(int c
, char **argv
, int invert
, unsigned int *flags
,
188 const struct ip6t_entry
*entry
,
189 unsigned int *nfcache
,
190 struct ip6t_entry_match
**match
)
192 struct ip6t_ipv6header_info
*info
= (struct ip6t_ipv6header_info
*)(*match
)->data
;
196 /* Parse the provided header names */
197 if (*flags
& IPV6_HDR_HEADER
)
198 exit_error(PARAMETER_PROBLEM
,
199 "Only one `--header' allowed");
201 check_inverse(optarg
, &invert
, &optind
, 0);
203 if (! (info
->matchflags
= parse_header(argv
[optind
-1])) )
204 exit_error(PARAMETER_PROBLEM
, "ip6t_ipv6header: cannot parse header names");
207 info
->invflags
|= 0xFF;
208 *flags
|= IPV6_HDR_HEADER
;
211 /* Soft-mode requested? */
212 if (*flags
& IPV6_HDR_SOFT
)
213 exit_error(PARAMETER_PROBLEM
,
214 "Only one `--soft' allowed");
216 info
->modeflag
|= 0xFF;
217 *flags
|= IPV6_HDR_SOFT
;
226 /* Checks the flags variable */
228 final_check(unsigned int flags
)
230 if (!flags
) exit_error(PARAMETER_PROBLEM
, "ip6t_ipv6header: no options specified");
234 print_header(u_int8_t flags
){
240 for (i
= 0; (flags
& chain_flags
[i
].flag
) == 0; i
++);
245 printf("%s", proto_to_name(chain_flags
[i
].proto
,0));
248 flags
&= ~chain_flags
[i
].flag
;
255 /* Prints out the match */
257 print(const struct ip6t_ip6
*ip
,
258 const struct ip6t_entry_match
*match
,
261 const struct ip6t_ipv6header_info
*info
= (const struct ip6t_ipv6header_info
*)match
->data
;
262 printf("ipv6header ");
264 if (info
->matchflags
|| info
->invflags
) {
265 printf("flags:%s", info
->invflags
? "!" : "");
267 printf("0x%02X ", info
->matchflags
);
269 print_header(info
->matchflags
);
280 /* Saves the match */
282 save(const struct ip6t_ip6
*ip
,
283 const struct ip6t_entry_match
*match
)
286 const struct ip6t_ipv6header_info
*info
= (const struct ip6t_ipv6header_info
*)match
->data
;
289 printf("%s", info
->invflags
? "!" : "");
290 print_header(info
->matchflags
);
299 struct ip6tables_match ipv6header
= {
300 .name
= "ipv6header",
301 .version
= IPTABLES_VERSION
,
302 .size
= IP6T_ALIGN(sizeof(struct ip6t_ipv6header_info
)),
303 .userspacesize
= IP6T_ALIGN(sizeof(struct ip6t_ipv6header_info
)),
307 .final_check
= &final_check
,
315 register_match6(&ipv6header
);