OSDN Git Service

2013.10.24
[uclinux-h8/uClinux-dist.git] / user / iptables / extensions / libip6t_hbh.c
1 /* Shared library add-on to ip6tables to add Hop-by-Hop header support. */
2 #include <stdio.h>
3 #include <netdb.h>
4 #include <string.h>
5 #include <stdlib.h>
6 #include <getopt.h>
7 #include <errno.h>
8 #include <xtables.h>
9 /*#include <linux/in6.h>*/
10 #include <linux/netfilter_ipv6/ip6t_opts.h>
11 #include <sys/types.h>
12 #include <sys/socket.h>
13 #include <arpa/inet.h>
14
15 #define DEBUG           0
16
17 static void hbh_help(void)
18 {
19         printf(
20 "hbh match options:\n"
21 "[!] --hbh-len length            total length of this header\n"
22 "  --hbh-opts TYPE[:LEN][,TYPE[:LEN]...] \n"
23 "                                Options and its length (list, max: %d)\n",
24 IP6T_OPTS_OPTSNR);
25 }
26
27 static const struct option hbh_opts[] = {
28         { "hbh-len", 1, NULL, '1' },
29         { "hbh-opts", 1, NULL, '2' },
30         { "hbh-not-strict", 1, NULL, '3' },
31         { .name = NULL }
32 };
33
34 static u_int32_t
35 parse_opts_num(const char *idstr, const char *typestr)
36 {
37         unsigned long int id;
38         char* ep;
39
40         id =  strtoul(idstr,&ep,0) ;
41
42         if ( idstr == ep ) {
43                 xtables_error(PARAMETER_PROBLEM,
44                            "hbh: no valid digits in %s `%s'", typestr, idstr);
45         }
46         if ( id == ULONG_MAX  && errno == ERANGE ) {
47                 xtables_error(PARAMETER_PROBLEM,
48                            "%s `%s' specified too big: would overflow",
49                            typestr, idstr);
50         }       
51         if ( *idstr != '\0'  && *ep != '\0' ) {
52                 xtables_error(PARAMETER_PROBLEM,
53                            "hbh: error parsing %s `%s'", typestr, idstr);
54         }
55         return id;
56 }
57
58 static int
59 parse_options(const char *optsstr, u_int16_t *opts)
60 {
61         char *buffer, *cp, *next, *range;
62         unsigned int i;
63         
64         buffer = strdup(optsstr);
65         if (!buffer) xtables_error(OTHER_PROBLEM, "strdup failed");
66                         
67         for (cp=buffer, i=0; cp && i<IP6T_OPTS_OPTSNR; cp=next,i++)
68         {
69                 next=strchr(cp, ',');
70                 if (next) *next++='\0';
71                 range = strchr(cp, ':');
72                 if (range) {
73                         if (i == IP6T_OPTS_OPTSNR-1)
74                                 xtables_error(PARAMETER_PROBLEM,
75                                            "too many ports specified");
76                         *range++ = '\0';
77                 }
78                 opts[i] = (parse_opts_num(cp, "opt") & 0xFF) << 8;
79                 if (range) {
80                         if (opts[i] == 0)
81                                 xtables_error(PARAMETER_PROBLEM, "PAD0 has not got length");
82                         opts[i] |= parse_opts_num(range, "length") & 0xFF;
83                 } else {
84                         opts[i] |= (0x00FF);
85                 }
86
87 #if DEBUG
88                 printf("opts str: %s %s\n", cp, range);
89                 printf("opts opt: %04X\n", opts[i]);
90 #endif
91         }
92         if (cp) xtables_error(PARAMETER_PROBLEM, "too many addresses specified");
93
94         free(buffer);
95
96 #if DEBUG
97         printf("addr nr: %d\n", i);
98 #endif
99
100         return i;
101 }
102
103 static void hbh_init(struct xt_entry_match *m)
104 {
105         struct ip6t_opts *optinfo = (struct ip6t_opts *)m->data;
106
107         optinfo->hdrlen = 0;
108         optinfo->flags = 0;
109         optinfo->invflags = 0;
110         optinfo->optsnr = 0;
111 }
112
113 static int hbh_parse(int c, char **argv, int invert, unsigned int *flags,
114                      const void *entry, struct xt_entry_match **match)
115 {
116         struct ip6t_opts *optinfo = (struct ip6t_opts *)(*match)->data;
117
118         switch (c) {
119         case '1':
120                 if (*flags & IP6T_OPTS_LEN)
121                         xtables_error(PARAMETER_PROBLEM,
122                                    "Only one `--hbh-len' allowed");
123                 xtables_check_inverse(optarg, &invert, &optind, 0);
124                 optinfo->hdrlen = parse_opts_num(argv[optind-1], "length");
125                 if (invert)
126                         optinfo->invflags |= IP6T_OPTS_INV_LEN;
127                 optinfo->flags |= IP6T_OPTS_LEN;
128                 *flags |= IP6T_OPTS_LEN;
129                 break;
130         case '2':
131                 if (*flags & IP6T_OPTS_OPTS)
132                         xtables_error(PARAMETER_PROBLEM,
133                                    "Only one `--hbh-opts' allowed");
134                 xtables_check_inverse(optarg, &invert, &optind, 0);
135                 if (invert)
136                         xtables_error(PARAMETER_PROBLEM,
137                                 " '!' not allowed with `--hbh-opts'");
138                 optinfo->optsnr = parse_options(argv[optind-1], optinfo->opts);
139                 optinfo->flags |= IP6T_OPTS_OPTS;
140                 *flags |= IP6T_OPTS_OPTS;
141                 break;
142         case '3':
143                 if (*flags & IP6T_OPTS_NSTRICT)
144                         xtables_error(PARAMETER_PROBLEM,
145                                    "Only one `--hbh-not-strict' allowed");
146                 if ( !(*flags & IP6T_OPTS_OPTS) )
147                         xtables_error(PARAMETER_PROBLEM,
148                                    "`--hbh-opts ...' required before `--hbh-not-strict'");
149                 optinfo->flags |= IP6T_OPTS_NSTRICT;
150                 *flags |= IP6T_OPTS_NSTRICT;
151                 break;
152         default:
153                 return 0;
154         }
155
156         return 1;
157 }
158
159 static void
160 print_options(unsigned int optsnr, u_int16_t *optsp)
161 {
162         unsigned int i;
163
164         for(i=0; i<optsnr; i++){
165                 printf("%d", (optsp[i] & 0xFF00)>>8);
166                 if ((optsp[i] & 0x00FF) != 0x00FF){
167                         printf(":%d", (optsp[i] & 0x00FF));
168                 } 
169                 printf("%c", (i!=optsnr-1)?',':' ');
170         }
171 }
172
173 static void hbh_print(const void *ip, const struct xt_entry_match *match,
174                       int numeric)
175 {
176         const struct ip6t_opts *optinfo = (struct ip6t_opts *)match->data;
177
178         printf("hbh ");
179         if (optinfo->flags & IP6T_OPTS_LEN) {
180                 printf("length");
181                 printf(":%s", optinfo->invflags & IP6T_OPTS_INV_LEN ? "!" : "");
182                 printf("%u", optinfo->hdrlen);
183                 printf(" ");
184         }
185         if (optinfo->flags & IP6T_OPTS_OPTS) printf("opts ");
186         print_options(optinfo->optsnr, (u_int16_t *)optinfo->opts);
187         if (optinfo->flags & IP6T_OPTS_NSTRICT) printf("not-strict ");
188         if (optinfo->invflags & ~IP6T_OPTS_INV_MASK)
189                 printf("Unknown invflags: 0x%X ",
190                        optinfo->invflags & ~IP6T_OPTS_INV_MASK);
191 }
192
193 static void hbh_save(const void *ip, const struct xt_entry_match *match)
194 {
195         const struct ip6t_opts *optinfo = (struct ip6t_opts *)match->data;
196
197         if (optinfo->flags & IP6T_OPTS_LEN) {
198                 printf("%s--hbh-len %u ",
199                         (optinfo->invflags & IP6T_OPTS_INV_LEN) ? "! " : "", 
200                         optinfo->hdrlen);
201         }
202
203         if (optinfo->flags & IP6T_OPTS_OPTS)
204                 printf("--hbh-opts ");
205         print_options(optinfo->optsnr, (u_int16_t *)optinfo->opts);
206         if (optinfo->flags & IP6T_OPTS_NSTRICT)
207                 printf("--hbh-not-strict ");
208 }
209
210 static struct xtables_match hbh_mt6_reg = {
211         .name           = "hbh",
212         .version        = XTABLES_VERSION,
213         .family         = NFPROTO_IPV6,
214         .size           = XT_ALIGN(sizeof(struct ip6t_opts)),
215         .userspacesize  = XT_ALIGN(sizeof(struct ip6t_opts)),
216         .help           = hbh_help,
217         .init           = hbh_init,
218         .parse          = hbh_parse,
219         .print          = hbh_print,
220         .save           = hbh_save,
221         .extra_opts     = hbh_opts,
222 };
223
224 void
225 _init(void)
226 {
227         xtables_register_match(&hbh_mt6_reg);
228 }