blob: 19ca23c0876627f982c662c30036aaa1e27fede8 [file] [log] [blame]
András Kis-Szabó2ea56492002-04-29 13:51:37 +00001/* Shared library add-on to ip6tables to add Hop-by-Hop and Dst headers 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 <ip6tables.h>
András Kis-Szabó2ea56492002-04-29 13:51:37 +00009#include <linux/netfilter_ipv6/ip6t_opts.h>
10#include <sys/types.h>
11#include <sys/socket.h>
12#include <arpa/inet.h>
Harald Weltead8d1ab2003-09-04 21:55:10 +000013
14#ifdef HOPBYHOP
15#define UNAME "HBH"
16#define LNAME "hbh"
17#else
18#define UNAME "DST"
19#define LNAME "dst"
20#endif
András Kis-Szabó2ea56492002-04-29 13:51:37 +000021
22/* Function which prints out usage message. */
23static void
24help(void)
25{
26 printf(
Harald Weltead8d1ab2003-09-04 21:55:10 +000027UNAME " v%s options:\n"
28" --" LNAME "-len [!] length total length of this header\n"
29" --" LNAME "-opts TYPE[:LEN][,TYPE[:LEN]...] \n"
András Kis-Szabó2ea56492002-04-29 13:51:37 +000030" Options and its length (list, max: %d)\n",
Harald Weltead8d1ab2003-09-04 21:55:10 +000031IPTABLES_VERSION, IP6T_OPTS_OPTSNR);
András Kis-Szabó2ea56492002-04-29 13:51:37 +000032}
33
András Kis-Szabó2ea56492002-04-29 13:51:37 +000034static struct option opts[] = {
Harald Weltead8d1ab2003-09-04 21:55:10 +000035 { .name = LNAME "-len", .has_arg = 1, .flag = 0, .val = '1' },
36 { .name = LNAME "-opts", .has_arg = 1, .flag = 0, .val = '2' },
37 { .name = LNAME "-not-strict", .has_arg = 1, .flag = 0, .val = '3' },
Stephane Ouellette703575d2003-08-23 18:41:47 +000038 { .name = 0 }
András Kis-Szabó2ea56492002-04-29 13:51:37 +000039};
András Kis-Szabó2ea56492002-04-29 13:51:37 +000040
41static u_int32_t
42parse_opts_num(const char *idstr, const char *typestr)
43{
44 unsigned long int id;
45 char* ep;
46
Stephane Ouellette703575d2003-08-23 18:41:47 +000047 id = strtoul(idstr, &ep, 0);
András Kis-Szabó2ea56492002-04-29 13:51:37 +000048
49 if ( idstr == ep ) {
50 exit_error(PARAMETER_PROBLEM,
Harald Weltead8d1ab2003-09-04 21:55:10 +000051 UNAME " no valid digits in %s `%s'", typestr, idstr);
András Kis-Szabó2ea56492002-04-29 13:51:37 +000052 }
53 if ( id == ULONG_MAX && errno == ERANGE ) {
54 exit_error(PARAMETER_PROBLEM,
55 "%s `%s' specified too big: would overflow",
56 typestr, idstr);
Harald Weltead8d1ab2003-09-04 21:55:10 +000057 }
András Kis-Szabó2ea56492002-04-29 13:51:37 +000058 if ( *idstr != '\0' && *ep != '\0' ) {
59 exit_error(PARAMETER_PROBLEM,
Harald Weltead8d1ab2003-09-04 21:55:10 +000060 UNAME " error parsing %s `%s'", typestr, idstr);
András Kis-Szabó2ea56492002-04-29 13:51:37 +000061 }
62 return (u_int32_t) id;
63}
64
65static int
66parse_options(const char *optsstr, u_int16_t *opts)
67{
68 char *buffer, *cp, *next, *range;
69 unsigned int i;
70
71 buffer = strdup(optsstr);
Harald Weltead8d1ab2003-09-04 21:55:10 +000072 if (!buffer)
73 exit_error(OTHER_PROBLEM, "strdup failed");
András Kis-Szabó2ea56492002-04-29 13:51:37 +000074
Harald Weltead8d1ab2003-09-04 21:55:10 +000075 for (cp = buffer, i = 0; cp && i < IP6T_OPTS_OPTSNR; cp = next, i++)
András Kis-Szabó2ea56492002-04-29 13:51:37 +000076 {
Harald Weltead8d1ab2003-09-04 21:55:10 +000077 next = strchr(cp, ',');
78
79 if (next)
80 *next++='\0';
81
András Kis-Szabó2ea56492002-04-29 13:51:37 +000082 range = strchr(cp, ':');
Harald Weltead8d1ab2003-09-04 21:55:10 +000083
András Kis-Szabó2ea56492002-04-29 13:51:37 +000084 if (range) {
85 if (i == IP6T_OPTS_OPTSNR-1)
86 exit_error(PARAMETER_PROBLEM,
87 "too many ports specified");
88 *range++ = '\0';
89 }
Harald Weltead8d1ab2003-09-04 21:55:10 +000090
András Kis-Szabó2ea56492002-04-29 13:51:37 +000091 opts[i] = (u_int16_t)((parse_opts_num(cp,"opt") & 0x000000FF)<<8);
92 if (range) {
93 if (opts[i] == 0)
Harald Weltead8d1ab2003-09-04 21:55:10 +000094 exit_error(PARAMETER_PROBLEM,
95 "PAD0 hasn't got length");
András Kis-Szabó2ea56492002-04-29 13:51:37 +000096 opts[i] |= (u_int16_t)(parse_opts_num(range,"length") &
97 0x000000FF);
Harald Weltead8d1ab2003-09-04 21:55:10 +000098 } else
András Kis-Szabó2ea56492002-04-29 13:51:37 +000099 opts[i] |= (0x00FF);
András Kis-Szabó2ea56492002-04-29 13:51:37 +0000100
Harald Weltead8d1ab2003-09-04 21:55:10 +0000101#ifdef DEBUG
András Kis-Szabó2ea56492002-04-29 13:51:37 +0000102 printf("opts str: %s %s\n", cp, range);
103 printf("opts opt: %04X\n", opts[i]);
104#endif
105 }
Harald Weltead8d1ab2003-09-04 21:55:10 +0000106
107 if (cp)
108 exit_error(PARAMETER_PROBLEM, "too many addresses specified");
András Kis-Szabó2ea56492002-04-29 13:51:37 +0000109
110 free(buffer);
111
Harald Weltead8d1ab2003-09-04 21:55:10 +0000112#ifdef DEBUG
András Kis-Szabó2ea56492002-04-29 13:51:37 +0000113 printf("addr nr: %d\n", i);
114#endif
115
116 return i;
117}
118
119/* Initialize the match. */
120static void
121init(struct ip6t_entry_match *m, unsigned int *nfcache)
122{
123 struct ip6t_opts *optinfo = (struct ip6t_opts *)m->data;
124
125 optinfo->hdrlen = 0;
126 optinfo->flags = 0;
127 optinfo->invflags = 0;
128 optinfo->optsnr = 0;
129}
130
131/* Function which parses command options; returns true if it
132 ate an option */
133static int
134parse(int c, char **argv, int invert, unsigned int *flags,
135 const struct ip6t_entry *entry,
136 unsigned int *nfcache,
137 struct ip6t_entry_match **match)
138{
139 struct ip6t_opts *optinfo = (struct ip6t_opts *)(*match)->data;
140
141 switch (c) {
142 case '1':
143 if (*flags & IP6T_OPTS_LEN)
144 exit_error(PARAMETER_PROBLEM,
Harald Weltead8d1ab2003-09-04 21:55:10 +0000145 "Only one `--" LNAME "-len' allowed");
András Kis-Szabó2ea56492002-04-29 13:51:37 +0000146 check_inverse(optarg, &invert, &optind, 0);
147 optinfo->hdrlen = parse_opts_num(argv[optind-1], "length");
148 if (invert)
149 optinfo->invflags |= IP6T_OPTS_INV_LEN;
150 optinfo->flags |= IP6T_OPTS_LEN;
151 *flags |= IP6T_OPTS_LEN;
152 break;
153 case '2':
154 if (*flags & IP6T_OPTS_OPTS)
155 exit_error(PARAMETER_PROBLEM,
Harald Weltead8d1ab2003-09-04 21:55:10 +0000156 "Only one `--" LNAME "-opts' allowed");
András Kis-Szabó2ea56492002-04-29 13:51:37 +0000157 check_inverse(optarg, &invert, &optind, 0);
158 if (invert)
159 exit_error(PARAMETER_PROBLEM,
Harald Weltead8d1ab2003-09-04 21:55:10 +0000160 " '!' not allowed with `--" LNAME "-opts'");
András Kis-Szabó2ea56492002-04-29 13:51:37 +0000161 optinfo->optsnr = parse_options(argv[optind-1], optinfo->opts);
162 optinfo->flags |= IP6T_OPTS_OPTS;
163 *flags |= IP6T_OPTS_OPTS;
164 break;
165 case '3':
166 if (*flags & IP6T_OPTS_NSTRICT)
167 exit_error(PARAMETER_PROBLEM,
Harald Weltead8d1ab2003-09-04 21:55:10 +0000168 "Only one `--" LNAME "-not-strict' allowed");
András Kis-Szabó2ea56492002-04-29 13:51:37 +0000169 if ( !(*flags & IP6T_OPTS_OPTS) )
170 exit_error(PARAMETER_PROBLEM,
Harald Weltead8d1ab2003-09-04 21:55:10 +0000171 "`--" LNAME "-opts ...' required before `--"
172 LNAME "-not-strict'");
András Kis-Szabó2ea56492002-04-29 13:51:37 +0000173 optinfo->flags |= IP6T_OPTS_NSTRICT;
174 *flags |= IP6T_OPTS_NSTRICT;
175 break;
176 default:
177 return 0;
178 }
179
180 return 1;
181}
182
183/* Final check; we don't care. */
184static void
185final_check(unsigned int flags)
186{
187}
188
189static void
András Kis-Szabó2ea56492002-04-29 13:51:37 +0000190print_options(int optsnr, u_int16_t *optsp)
191{
192 unsigned int i;
193
Harald Weltead8d1ab2003-09-04 21:55:10 +0000194 for(i = 0; i < optsnr; i++) {
195 printf("%d", (optsp[i] & 0xFF00) >> 8);
196
197 if ((optsp[i] & 0x00FF) != 0x00FF)
András Kis-Szabó2ea56492002-04-29 13:51:37 +0000198 printf(":%d", (optsp[i] & 0x00FF));
Harald Weltead8d1ab2003-09-04 21:55:10 +0000199
200 printf("%c", (i != optsnr - 1) ? ',' : ' ');
András Kis-Szabó2ea56492002-04-29 13:51:37 +0000201 }
202}
203
204/* Prints out the union ip6t_matchinfo. */
205static void
206print(const struct ip6t_ip6 *ip,
207 const struct ip6t_entry_match *match, int numeric)
208{
209 const struct ip6t_opts *optinfo = (struct ip6t_opts *)match->data;
210
Harald Weltead8d1ab2003-09-04 21:55:10 +0000211 printf(LNAME " ");
Stephane Ouellette703575d2003-08-23 18:41:47 +0000212 if (optinfo->flags & IP6T_OPTS_LEN)
213 printf("length:%s%u ",
214 optinfo->invflags & IP6T_OPTS_INV_LEN ? "!" : "",
215 optinfo->hdrlen);
216
217 if (optinfo->flags & IP6T_OPTS_OPTS)
218 printf("opts ");
219
Fabrice MARIEae31bb62002-06-14 07:38:16 +0000220 print_options(optinfo->optsnr, (u_int16_t *)optinfo->opts);
Stephane Ouellette703575d2003-08-23 18:41:47 +0000221
222 if (optinfo->flags & IP6T_OPTS_NSTRICT)
223 printf("not-strict ");
224
András Kis-Szabó2ea56492002-04-29 13:51:37 +0000225 if (optinfo->invflags & ~IP6T_OPTS_INV_MASK)
226 printf("Unknown invflags: 0x%X ",
227 optinfo->invflags & ~IP6T_OPTS_INV_MASK);
228}
229
230/* Saves the union ip6t_matchinfo in parsable form to stdout. */
231static void save(const struct ip6t_ip6 *ip, const struct ip6t_entry_match *match)
232{
233 const struct ip6t_opts *optinfo = (struct ip6t_opts *)match->data;
234
235 if (optinfo->flags & IP6T_OPTS_LEN) {
Harald Weltead8d1ab2003-09-04 21:55:10 +0000236 printf("--" LNAME "-len %s%u ",
András Kis-Szabó2ea56492002-04-29 13:51:37 +0000237 (optinfo->invflags & IP6T_OPTS_INV_LEN) ? "! " : "",
238 optinfo->hdrlen);
239 }
240
Stephane Ouellette703575d2003-08-23 18:41:47 +0000241 if (optinfo->flags & IP6T_OPTS_OPTS)
Harald Weltead8d1ab2003-09-04 21:55:10 +0000242 printf("--" LNAME "-opts ");
András Kis-Szabó2ea56492002-04-29 13:51:37 +0000243
Stephane Ouellette703575d2003-08-23 18:41:47 +0000244 print_options(optinfo->optsnr, (u_int16_t *)optinfo->opts);
245
246 if (optinfo->flags & IP6T_OPTS_NSTRICT)
Harald Weltead8d1ab2003-09-04 21:55:10 +0000247 printf("--" LNAME "-not-strict ");
András Kis-Szabó2ea56492002-04-29 13:51:37 +0000248}
249
250static
Stephane Ouellette703575d2003-08-23 18:41:47 +0000251struct ip6tables_match optstruct = {
Harald Weltead8d1ab2003-09-04 21:55:10 +0000252 .name = LNAME,
Stephane Ouellette703575d2003-08-23 18:41:47 +0000253 .version = IPTABLES_VERSION,
254 .size = IP6T_ALIGN(sizeof(struct ip6t_opts)),
255 .userspacesize = IP6T_ALIGN(sizeof(struct ip6t_opts)),
256 .help = &help,
257 .init = &init,
258 .parse = &parse,
Harald Weltead8d1ab2003-09-04 21:55:10 +0000259 .final_check = &final_check,
Stephane Ouellette703575d2003-08-23 18:41:47 +0000260 .print = &print,
261 .save = &save,
262 .extra_opts = opts
András Kis-Szabó2ea56492002-04-29 13:51:37 +0000263};
264
265void
266_init(void)
267{
268 register_match6(&optstruct);
269}