blob: 5b060334409661d32cbec002697ec9f42ca7e110 [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
András Kis-Szabó2ea56492002-04-29 13:51:37 +000014/* Function which prints out usage message. */
Jan Engelhardt997045f2007-10-04 16:29:21 +000015static void dst_help(void)
András Kis-Szabó2ea56492002-04-29 13:51:37 +000016{
17 printf(
Jan Engelhardte2f588a2007-10-04 16:30:40 +000018"dst v%s options:\n"
19" --dst-len [!] length total length of this header\n"
20" --dst-opts TYPE[:LEN][,TYPE[:LEN]...]\n"
21" Options and its length (list, max: %d)\n",
Harald Weltead8d1ab2003-09-04 21:55:10 +000022IPTABLES_VERSION, IP6T_OPTS_OPTSNR);
András Kis-Szabó2ea56492002-04-29 13:51:37 +000023}
24
Jan Engelhardt997045f2007-10-04 16:29:21 +000025static const struct option dst_opts[] = {
Jan Engelhardte2f588a2007-10-04 16:30:40 +000026 { .name = "dst-len", .has_arg = 1, .val = '1' },
27 { .name = "dst-opts", .has_arg = 1, .val = '2' },
28 { .name = "dst-not-strict", .has_arg = 1, .val = '3' },
Max Kellermann9ee386a2008-01-29 13:48:05 +000029 { .name = NULL }
András Kis-Szabó2ea56492002-04-29 13:51:37 +000030};
András Kis-Szabó2ea56492002-04-29 13:51:37 +000031
32static u_int32_t
33parse_opts_num(const char *idstr, const char *typestr)
34{
35 unsigned long int id;
36 char* ep;
37
Stephane Ouellette703575d2003-08-23 18:41:47 +000038 id = strtoul(idstr, &ep, 0);
András Kis-Szabó2ea56492002-04-29 13:51:37 +000039
40 if ( idstr == ep ) {
41 exit_error(PARAMETER_PROBLEM,
Jan Engelhardte2f588a2007-10-04 16:30:40 +000042 "dst: no valid digits in %s `%s'", typestr, idstr);
András Kis-Szabó2ea56492002-04-29 13:51:37 +000043 }
44 if ( id == ULONG_MAX && errno == ERANGE ) {
45 exit_error(PARAMETER_PROBLEM,
46 "%s `%s' specified too big: would overflow",
47 typestr, idstr);
Harald Weltead8d1ab2003-09-04 21:55:10 +000048 }
András Kis-Szabó2ea56492002-04-29 13:51:37 +000049 if ( *idstr != '\0' && *ep != '\0' ) {
50 exit_error(PARAMETER_PROBLEM,
Jan Engelhardte2f588a2007-10-04 16:30:40 +000051 "dst: error parsing %s `%s'", typestr, idstr);
András Kis-Szabó2ea56492002-04-29 13:51:37 +000052 }
53 return (u_int32_t) id;
54}
55
56static int
57parse_options(const char *optsstr, u_int16_t *opts)
58{
59 char *buffer, *cp, *next, *range;
60 unsigned int i;
61
62 buffer = strdup(optsstr);
Harald Weltead8d1ab2003-09-04 21:55:10 +000063 if (!buffer)
64 exit_error(OTHER_PROBLEM, "strdup failed");
András Kis-Szabó2ea56492002-04-29 13:51:37 +000065
Harald Weltead8d1ab2003-09-04 21:55:10 +000066 for (cp = buffer, i = 0; cp && i < IP6T_OPTS_OPTSNR; cp = next, i++)
András Kis-Szabó2ea56492002-04-29 13:51:37 +000067 {
Harald Weltead8d1ab2003-09-04 21:55:10 +000068 next = strchr(cp, ',');
69
70 if (next)
71 *next++='\0';
72
András Kis-Szabó2ea56492002-04-29 13:51:37 +000073 range = strchr(cp, ':');
Harald Weltead8d1ab2003-09-04 21:55:10 +000074
András Kis-Szabó2ea56492002-04-29 13:51:37 +000075 if (range) {
76 if (i == IP6T_OPTS_OPTSNR-1)
77 exit_error(PARAMETER_PROBLEM,
78 "too many ports specified");
79 *range++ = '\0';
80 }
Harald Weltead8d1ab2003-09-04 21:55:10 +000081
András Kis-Szabó2ea56492002-04-29 13:51:37 +000082 opts[i] = (u_int16_t)((parse_opts_num(cp,"opt") & 0x000000FF)<<8);
83 if (range) {
84 if (opts[i] == 0)
Harald Weltead8d1ab2003-09-04 21:55:10 +000085 exit_error(PARAMETER_PROBLEM,
86 "PAD0 hasn't got length");
András Kis-Szabó2ea56492002-04-29 13:51:37 +000087 opts[i] |= (u_int16_t)(parse_opts_num(range,"length") &
88 0x000000FF);
Harald Weltead8d1ab2003-09-04 21:55:10 +000089 } else
András Kis-Szabó2ea56492002-04-29 13:51:37 +000090 opts[i] |= (0x00FF);
András Kis-Szabó2ea56492002-04-29 13:51:37 +000091
Harald Weltead8d1ab2003-09-04 21:55:10 +000092#ifdef DEBUG
András Kis-Szabó2ea56492002-04-29 13:51:37 +000093 printf("opts str: %s %s\n", cp, range);
94 printf("opts opt: %04X\n", opts[i]);
95#endif
96 }
Harald Weltead8d1ab2003-09-04 21:55:10 +000097
98 if (cp)
99 exit_error(PARAMETER_PROBLEM, "too many addresses specified");
András Kis-Szabó2ea56492002-04-29 13:51:37 +0000100
101 free(buffer);
102
Harald Weltead8d1ab2003-09-04 21:55:10 +0000103#ifdef DEBUG
András Kis-Szabó2ea56492002-04-29 13:51:37 +0000104 printf("addr nr: %d\n", i);
105#endif
106
107 return i;
108}
109
110/* Initialize the match. */
Jan Engelhardt997045f2007-10-04 16:29:21 +0000111static void dst_init(struct xt_entry_match *m)
András Kis-Szabó2ea56492002-04-29 13:51:37 +0000112{
113 struct ip6t_opts *optinfo = (struct ip6t_opts *)m->data;
114
115 optinfo->hdrlen = 0;
116 optinfo->flags = 0;
117 optinfo->invflags = 0;
118 optinfo->optsnr = 0;
119}
120
121/* Function which parses command options; returns true if it
122 ate an option */
Jan Engelhardt997045f2007-10-04 16:29:21 +0000123static int dst_parse(int c, char **argv, int invert, unsigned int *flags,
124 const void *entry, struct xt_entry_match **match)
András Kis-Szabó2ea56492002-04-29 13:51:37 +0000125{
126 struct ip6t_opts *optinfo = (struct ip6t_opts *)(*match)->data;
127
128 switch (c) {
129 case '1':
130 if (*flags & IP6T_OPTS_LEN)
131 exit_error(PARAMETER_PROBLEM,
Jan Engelhardte2f588a2007-10-04 16:30:40 +0000132 "Only one `--dst-len' allowed");
András Kis-Szabó2ea56492002-04-29 13:51:37 +0000133 check_inverse(optarg, &invert, &optind, 0);
134 optinfo->hdrlen = parse_opts_num(argv[optind-1], "length");
135 if (invert)
136 optinfo->invflags |= IP6T_OPTS_INV_LEN;
137 optinfo->flags |= IP6T_OPTS_LEN;
138 *flags |= IP6T_OPTS_LEN;
139 break;
140 case '2':
141 if (*flags & IP6T_OPTS_OPTS)
142 exit_error(PARAMETER_PROBLEM,
Jan Engelhardte2f588a2007-10-04 16:30:40 +0000143 "Only one `--dst-opts' allowed");
András Kis-Szabó2ea56492002-04-29 13:51:37 +0000144 check_inverse(optarg, &invert, &optind, 0);
145 if (invert)
146 exit_error(PARAMETER_PROBLEM,
Jan Engelhardte2f588a2007-10-04 16:30:40 +0000147 " '!' not allowed with `--dst-opts'");
András Kis-Szabó2ea56492002-04-29 13:51:37 +0000148 optinfo->optsnr = parse_options(argv[optind-1], optinfo->opts);
149 optinfo->flags |= IP6T_OPTS_OPTS;
150 *flags |= IP6T_OPTS_OPTS;
151 break;
152 case '3':
153 if (*flags & IP6T_OPTS_NSTRICT)
154 exit_error(PARAMETER_PROBLEM,
Jan Engelhardte2f588a2007-10-04 16:30:40 +0000155 "Only one `--dst-not-strict' allowed");
András Kis-Szabó2ea56492002-04-29 13:51:37 +0000156 if ( !(*flags & IP6T_OPTS_OPTS) )
157 exit_error(PARAMETER_PROBLEM,
Jan Engelhardte2f588a2007-10-04 16:30:40 +0000158 "`--dst-opts ...' required before "
159 "`--dst-not-strict'");
András Kis-Szabó2ea56492002-04-29 13:51:37 +0000160 optinfo->flags |= IP6T_OPTS_NSTRICT;
161 *flags |= IP6T_OPTS_NSTRICT;
162 break;
163 default:
164 return 0;
165 }
166
167 return 1;
168}
169
András Kis-Szabó2ea56492002-04-29 13:51:37 +0000170static void
Jan Engelhardt7a236f42008-03-03 12:30:41 +0100171print_options(unsigned int optsnr, u_int16_t *optsp)
András Kis-Szabó2ea56492002-04-29 13:51:37 +0000172{
173 unsigned int i;
174
Harald Weltead8d1ab2003-09-04 21:55:10 +0000175 for(i = 0; i < optsnr; i++) {
176 printf("%d", (optsp[i] & 0xFF00) >> 8);
177
178 if ((optsp[i] & 0x00FF) != 0x00FF)
András Kis-Szabó2ea56492002-04-29 13:51:37 +0000179 printf(":%d", (optsp[i] & 0x00FF));
Harald Weltead8d1ab2003-09-04 21:55:10 +0000180
181 printf("%c", (i != optsnr - 1) ? ',' : ' ');
András Kis-Szabó2ea56492002-04-29 13:51:37 +0000182 }
183}
184
185/* Prints out the union ip6t_matchinfo. */
Jan Engelhardt997045f2007-10-04 16:29:21 +0000186static void dst_print(const void *ip, const struct xt_entry_match *match,
187 int numeric)
András Kis-Szabó2ea56492002-04-29 13:51:37 +0000188{
189 const struct ip6t_opts *optinfo = (struct ip6t_opts *)match->data;
190
Jan Engelhardte2f588a2007-10-04 16:30:40 +0000191 printf("dst ");
Stephane Ouellette703575d2003-08-23 18:41:47 +0000192 if (optinfo->flags & IP6T_OPTS_LEN)
193 printf("length:%s%u ",
194 optinfo->invflags & IP6T_OPTS_INV_LEN ? "!" : "",
195 optinfo->hdrlen);
196
197 if (optinfo->flags & IP6T_OPTS_OPTS)
198 printf("opts ");
199
Fabrice MARIEae31bb62002-06-14 07:38:16 +0000200 print_options(optinfo->optsnr, (u_int16_t *)optinfo->opts);
Stephane Ouellette703575d2003-08-23 18:41:47 +0000201
202 if (optinfo->flags & IP6T_OPTS_NSTRICT)
203 printf("not-strict ");
204
András Kis-Szabó2ea56492002-04-29 13:51:37 +0000205 if (optinfo->invflags & ~IP6T_OPTS_INV_MASK)
206 printf("Unknown invflags: 0x%X ",
207 optinfo->invflags & ~IP6T_OPTS_INV_MASK);
208}
209
210/* Saves the union ip6t_matchinfo in parsable form to stdout. */
Jan Engelhardt997045f2007-10-04 16:29:21 +0000211static void dst_save(const void *ip, const struct xt_entry_match *match)
András Kis-Szabó2ea56492002-04-29 13:51:37 +0000212{
213 const struct ip6t_opts *optinfo = (struct ip6t_opts *)match->data;
214
215 if (optinfo->flags & IP6T_OPTS_LEN) {
Jan Engelhardte2f588a2007-10-04 16:30:40 +0000216 printf("--dst-len %s%u ",
András Kis-Szabó2ea56492002-04-29 13:51:37 +0000217 (optinfo->invflags & IP6T_OPTS_INV_LEN) ? "! " : "",
218 optinfo->hdrlen);
219 }
220
Stephane Ouellette703575d2003-08-23 18:41:47 +0000221 if (optinfo->flags & IP6T_OPTS_OPTS)
Jan Engelhardte2f588a2007-10-04 16:30:40 +0000222 printf("--dst-opts ");
András Kis-Szabó2ea56492002-04-29 13:51:37 +0000223
Stephane Ouellette703575d2003-08-23 18:41:47 +0000224 print_options(optinfo->optsnr, (u_int16_t *)optinfo->opts);
225
226 if (optinfo->flags & IP6T_OPTS_NSTRICT)
Jan Engelhardte2f588a2007-10-04 16:30:40 +0000227 printf("--dst-not-strict ");
András Kis-Szabó2ea56492002-04-29 13:51:37 +0000228}
229
Jan Engelhardt997045f2007-10-04 16:29:21 +0000230static struct ip6tables_match dst_match6 = {
Jan Engelhardte2f588a2007-10-04 16:30:40 +0000231 .name = "dst",
Stephane Ouellette703575d2003-08-23 18:41:47 +0000232 .version = IPTABLES_VERSION,
233 .size = IP6T_ALIGN(sizeof(struct ip6t_opts)),
234 .userspacesize = IP6T_ALIGN(sizeof(struct ip6t_opts)),
Jan Engelhardt997045f2007-10-04 16:29:21 +0000235 .help = dst_help,
236 .init = dst_init,
237 .parse = dst_parse,
238 .print = dst_print,
239 .save = dst_save,
240 .extra_opts = dst_opts,
András Kis-Szabó2ea56492002-04-29 13:51:37 +0000241};
242
243void
244_init(void)
245{
Jan Engelhardt997045f2007-10-04 16:29:21 +0000246 register_match6(&dst_match6);
András Kis-Szabó2ea56492002-04-29 13:51:37 +0000247}