OSDN Git Service

2013.10.24
[uclinux-h8/uClinux-dist.git] / user / iptables / extensions / libip6t_ipv6header.c
1 /* ipv6header match - matches IPv6 packets based
2 on whether they contain certain headers */
3
4 /* Original idea: Brad Chapman 
5  * Rewritten by: Andras Kis-Szabo <kisza@sch.bme.hu> */
6
7 #include <getopt.h>
8 #include <xtables.h>
9 #include <stddef.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <netdb.h>
14 #include <sys/types.h>
15
16 #include <linux/netfilter_ipv6/ip6t_ipv6header.h>
17
18 /* This maybe required 
19 #include <linux/in.h>
20 #include <linux/in6.h>
21 */
22
23
24 /* A few hardcoded protocols for 'all' and in case the user has no
25  *    /etc/protocols */
26 struct pprot {
27         char *name;
28         u_int8_t num;
29 };
30
31 struct numflag {
32         u_int8_t proto;
33         u_int8_t flag;
34 };
35
36 static const struct pprot chain_protos[] = {
37         { "hop-by-hop", IPPROTO_HOPOPTS },
38         { "protocol", IPPROTO_RAW },
39         { "hop", IPPROTO_HOPOPTS },
40         { "dst", IPPROTO_DSTOPTS },
41         { "route", IPPROTO_ROUTING },
42         { "frag", IPPROTO_FRAGMENT },
43         { "auth", IPPROTO_AH },
44         { "esp", IPPROTO_ESP },
45         { "none", IPPROTO_NONE },
46         { "prot", IPPROTO_RAW },
47         { "0", IPPROTO_HOPOPTS },
48         { "60", IPPROTO_DSTOPTS },
49         { "43", IPPROTO_ROUTING },
50         { "44", IPPROTO_FRAGMENT },
51         { "51", IPPROTO_AH },
52         { "50", IPPROTO_ESP },
53         { "59", IPPROTO_NONE },
54         { "255", IPPROTO_RAW },
55         /* { "all", 0 }, */
56 };
57
58 static const struct numflag chain_flags[] = {
59         { IPPROTO_HOPOPTS, MASK_HOPOPTS },
60         { IPPROTO_DSTOPTS, MASK_DSTOPTS },
61         { IPPROTO_ROUTING, MASK_ROUTING },
62         { IPPROTO_FRAGMENT, MASK_FRAGMENT },
63         { IPPROTO_AH, MASK_AH },
64         { IPPROTO_ESP, MASK_ESP },
65         { IPPROTO_NONE, MASK_NONE },
66         { IPPROTO_RAW, MASK_PROTO },
67 };
68
69 static char *
70 proto_to_name(u_int8_t proto, int nolookup)
71 {
72         unsigned int i;
73
74         if (proto && !nolookup) {
75                 struct protoent *pent = getprotobynumber(proto);
76                 if (pent)
77                         return pent->p_name;
78         }
79
80         for (i = 0; i < sizeof(chain_protos)/sizeof(struct pprot); i++)
81                 if (chain_protos[i].num == proto)
82                         return chain_protos[i].name;
83
84         return NULL;
85 }
86
87 static u_int16_t
88 name_to_proto(const char *s)
89 {
90         unsigned int proto=0;
91         struct protoent *pent;
92
93         if ((pent = getprotobyname(s)))
94                 proto = pent->p_proto;
95         else {
96                 unsigned int i;
97                 for (i = 0;
98                         i < sizeof(chain_protos)/sizeof(struct pprot);
99                         i++) {
100                         if (strcmp(s, chain_protos[i].name) == 0) {
101                                 proto = chain_protos[i].num;
102                                 break;
103                         }
104                 }
105
106                 if (i == sizeof(chain_protos)/sizeof(struct pprot))
107                         xtables_error(PARAMETER_PROBLEM,
108                                 "unknown header `%s' specified",
109                                 s);
110         }
111
112         return proto;
113 }
114
115 static unsigned int 
116 add_proto_to_mask(int proto){
117         unsigned int i=0, flag=0;
118
119         for (i = 0;
120                 i < sizeof(chain_flags)/sizeof(struct numflag);
121                 i++) {
122                         if (proto == chain_flags[i].proto){
123                                 flag = chain_flags[i].flag;
124                                 break;
125                         }
126         }
127
128         if (i == sizeof(chain_flags)/sizeof(struct numflag))
129                 xtables_error(PARAMETER_PROBLEM,
130                 "unknown header `%d' specified",
131                 proto);
132         
133         return flag;
134 }       
135
136 static void ipv6header_help(void)
137 {
138         printf(
139 "ipv6header match options:\n"
140 "[!] --header headers     Type of header to match, by name\n"
141 "                         names: hop,dst,route,frag,auth,esp,none,proto\n"
142 "                    long names: hop-by-hop,ipv6-opts,ipv6-route,\n"
143 "                                ipv6-frag,ah,esp,ipv6-nonxt,protocol\n"
144 "                       numbers: 0,60,43,44,51,50,59\n"
145 "--soft                    The header CONTAINS the specified extensions\n");
146 }
147
148 static const struct option ipv6header_opts[] = {
149         { "header", 1, NULL, '1' },
150         { "soft", 0, NULL, '2' },
151         { .name = NULL }
152 };
153
154 static void ipv6header_init(struct xt_entry_match *m)
155 {
156         struct ip6t_ipv6header_info *info = (struct ip6t_ipv6header_info *)m->data;
157
158         info->matchflags = 0x00;
159         info->invflags = 0x00;
160         info->modeflag = 0x00;
161 }
162
163 static unsigned int
164 parse_header(const char *flags) {
165         unsigned int ret = 0;
166         char *ptr;
167         char *buffer;
168
169         buffer = strdup(flags);
170
171         for (ptr = strtok(buffer, ","); ptr; ptr = strtok(NULL, ",")) 
172                 ret |= add_proto_to_mask(name_to_proto(ptr));
173                 
174         free(buffer);
175         return ret;
176 }
177
178 #define IPV6_HDR_HEADER 0x01
179 #define IPV6_HDR_SOFT   0x02
180
181 static int
182 ipv6header_parse(int c, char **argv, int invert, unsigned int *flags,
183                  const void *entry, struct xt_entry_match **match)
184 {
185         struct ip6t_ipv6header_info *info = (struct ip6t_ipv6header_info *)(*match)->data;
186
187         switch (c) {
188                 case '1' : 
189                         /* Parse the provided header names */
190                         if (*flags & IPV6_HDR_HEADER)
191                                 xtables_error(PARAMETER_PROBLEM,
192                                         "Only one `--header' allowed");
193
194                         xtables_check_inverse(optarg, &invert, &optind, 0);
195
196                         if (! (info->matchflags = parse_header(argv[optind-1])) )
197                                 xtables_error(PARAMETER_PROBLEM, "ip6t_ipv6header: cannot parse header names");
198
199                         if (invert) 
200                                 info->invflags |= 0xFF;
201                         *flags |= IPV6_HDR_HEADER;
202                         break;
203                 case '2' : 
204                         /* Soft-mode requested? */
205                         if (*flags & IPV6_HDR_SOFT)
206                                 xtables_error(PARAMETER_PROBLEM,
207                                         "Only one `--soft' allowed");
208
209                         info->modeflag |= 0xFF;
210                         *flags |= IPV6_HDR_SOFT;
211                         break;
212                 default:
213                         return 0;
214         }
215
216         return 1;
217 }
218
219 static void ipv6header_check(unsigned int flags)
220 {
221         if (!flags) xtables_error(PARAMETER_PROBLEM, "ip6t_ipv6header: no options specified");
222 }
223
224 static void
225 print_header(u_int8_t flags){
226         int have_flag = 0;
227
228         while (flags) {
229                 unsigned int i;
230
231                 for (i = 0; (flags & chain_flags[i].flag) == 0; i++);
232
233                 if (have_flag)
234                         printf(",");
235
236                 printf("%s", proto_to_name(chain_flags[i].proto,0));
237                 have_flag = 1;
238
239                 flags &= ~chain_flags[i].flag;
240         }
241
242         if (!have_flag)
243                 printf("NONE");
244 }
245
246 static void ipv6header_print(const void *ip,
247                              const struct xt_entry_match *match, int numeric)
248 {
249         const struct ip6t_ipv6header_info *info = (const struct ip6t_ipv6header_info *)match->data;
250         printf("ipv6header ");
251
252         if (info->matchflags || info->invflags) {
253                 printf("flags:%s", info->invflags ? "!" : "");
254                 if (numeric)
255                         printf("0x%02X ", info->matchflags);
256                 else {
257                         print_header(info->matchflags);
258                         printf(" ");
259                 }
260         }
261
262         if (info->modeflag)
263                 printf("soft ");
264 }
265
266 static void ipv6header_save(const void *ip, const struct xt_entry_match *match)
267 {
268
269         const struct ip6t_ipv6header_info *info = (const struct ip6t_ipv6header_info *)match->data;
270
271         printf("%s--header ", info->invflags ? "! " : "");
272         print_header(info->matchflags);
273         printf(" ");
274         if (info->modeflag)
275                 printf("--soft ");
276 }
277
278 static struct xtables_match ipv6header_mt6_reg = {
279         .name           = "ipv6header",
280         .version        = XTABLES_VERSION,
281         .family         = NFPROTO_IPV6,
282         .size           = XT_ALIGN(sizeof(struct ip6t_ipv6header_info)),
283         .userspacesize  = XT_ALIGN(sizeof(struct ip6t_ipv6header_info)),
284         .help           = ipv6header_help,
285         .init           = ipv6header_init,
286         .parse          = ipv6header_parse,
287         .final_check    = ipv6header_check,
288         .print          = ipv6header_print,
289         .save           = ipv6header_save,
290         .extra_opts     = ipv6header_opts,
291 };
292
293 void _init(void)
294 {
295         xtables_register_match(&ipv6header_mt6_reg);
296 }