1 /* Shared library add-on to ip6tables to add Routing header support. */
9 /*#include <linux/in6.h>*/
10 #include <linux/netfilter_ipv6/ip6t_rt.h>
11 #include <sys/types.h>
12 #include <sys/socket.h>
13 #include <arpa/inet.h>
17 /* Function which prints out usage message. */
23 " --rt-type [!] type match the type\n"
24 " --rt-segsleft [!] num[:num] match the Segments Left field (range)\n"
25 " --rt-len [!] length total length of this header\n"
26 " --rt-0-res check the reserved filed, too (type 0)\n"
27 " --rt-0-addrs ADDR[,ADDR...] Type=0 addresses (list, max: %d)\n"
28 " --rt-0-not-strict List of Type=0 addresses not a strict list\n",
29 IPTABLES_VERSION
, IP6T_RT_HOPS
);
32 static struct option opts
[] = {
33 { "rt-type", 1, 0, '1' },
34 { "rt-segsleft", 1, 0, '2' },
35 { "rt-len", 1, 0, '3' },
36 { "rt-0-res", 0, 0, '4' },
37 { "rt-0-addrs", 1, 0, '5' },
38 { "rt-0-not-strict", 0, 0, '6' },
43 parse_rt_num(const char *idstr
, const char *typestr
)
48 id
= strtoul(idstr
,&ep
,0) ;
51 exit_error(PARAMETER_PROBLEM
,
52 "RT no valid digits in %s `%s'", typestr
, idstr
);
54 if ( id
== ULONG_MAX
&& errno
== ERANGE
) {
55 exit_error(PARAMETER_PROBLEM
,
56 "%s `%s' specified too big: would overflow",
59 if ( *idstr
!= '\0' && *ep
!= '\0' ) {
60 exit_error(PARAMETER_PROBLEM
,
61 "RT error parsing %s `%s'", typestr
, idstr
);
63 return (u_int32_t
) id
;
67 parse_rt_segsleft(const char *idstring
, u_int32_t
*ids
)
72 buffer
= strdup(idstring
);
73 if ((cp
= strchr(buffer
, ':')) == NULL
)
74 ids
[0] = ids
[1] = parse_rt_num(buffer
,"segsleft");
79 ids
[0] = buffer
[0] ? parse_rt_num(buffer
,"segsleft") : 0;
80 ids
[1] = cp
[0] ? parse_rt_num(cp
,"segsleft") : 0xFFFFFFFF;
86 addr_to_numeric(const struct in6_addr
*addrp
)
88 static char buf
[50+1];
89 return (char *)inet_ntop(AF_INET6
, addrp
, buf
, sizeof(buf
));
92 static struct in6_addr
*
93 numeric_to_addr(const char *num
)
95 static struct in6_addr ap
;
98 if ((err
=inet_pton(AF_INET6
, num
, &ap
)) == 1)
101 fprintf(stderr
, "\nnumeric2addr: %d\n", err
);
103 exit_error(PARAMETER_PROBLEM
, "bad address: %s", num
);
105 return (struct in6_addr
*)NULL
;
110 parse_addresses(const char *addrstr
, struct in6_addr
*addrp
)
112 char *buffer
, *cp
, *next
;
115 buffer
= strdup(addrstr
);
116 if (!buffer
) exit_error(OTHER_PROBLEM
, "strdup failed");
118 for (cp
=buffer
, i
=0; cp
&& i
<IP6T_RT_HOPS
; cp
=next
,i
++)
120 next
=strchr(cp
, ',');
121 if (next
) *next
++='\0';
122 memcpy(&(addrp
[i
]), numeric_to_addr(cp
), sizeof(struct in6_addr
));
124 printf("addr str: %s\n", cp
);
125 printf("addr ip6: %s\n", addr_to_numeric((numeric_to_addr(cp
))));
126 printf("addr [%d]: %s\n", i
, addr_to_numeric(&(addrp
[i
])));
129 if (cp
) exit_error(PARAMETER_PROBLEM
, "too many addresses specified");
134 printf("addr nr: %d\n", i
);
140 /* Initialize the match. */
142 init(struct ip6t_entry_match
*m
, unsigned int *nfcache
)
144 struct ip6t_rt
*rtinfo
= (struct ip6t_rt
*)m
->data
;
146 rtinfo
->rt_type
= 0x0L
;
147 rtinfo
->segsleft
[0] = 0x0L
;
148 rtinfo
->segsleft
[1] = 0xFFFFFFFF;
151 rtinfo
->invflags
= 0;
155 /* Function which parses command options; returns true if it
158 parse(int c
, char **argv
, int invert
, unsigned int *flags
,
159 const struct ip6t_entry
*entry
,
160 unsigned int *nfcache
,
161 struct ip6t_entry_match
**match
)
163 struct ip6t_rt
*rtinfo
= (struct ip6t_rt
*)(*match
)->data
;
167 if (*flags
& IP6T_RT_TYP
)
168 exit_error(PARAMETER_PROBLEM
,
169 "Only one `--rt-type' allowed");
170 check_inverse(optarg
, &invert
, &optind
, 0);
171 rtinfo
->rt_type
= parse_rt_num(argv
[optind
-1], "type");
173 rtinfo
->invflags
|= IP6T_RT_INV_TYP
;
174 rtinfo
->flags
|= IP6T_RT_TYP
;
175 *flags
|= IP6T_RT_TYP
;
178 if (*flags
& IP6T_RT_SGS
)
179 exit_error(PARAMETER_PROBLEM
,
180 "Only one `--rt-segsleft' allowed");
181 check_inverse(optarg
, &invert
, &optind
, 0);
182 parse_rt_segsleft(argv
[optind
-1], rtinfo
->segsleft
);
184 rtinfo
->invflags
|= IP6T_RT_INV_SGS
;
185 rtinfo
->flags
|= IP6T_RT_SGS
;
186 *flags
|= IP6T_RT_SGS
;
189 if (*flags
& IP6T_RT_LEN
)
190 exit_error(PARAMETER_PROBLEM
,
191 "Only one `--rt-len' allowed");
192 check_inverse(optarg
, &invert
, &optind
, 0);
193 rtinfo
->hdrlen
= parse_rt_num(argv
[optind
-1], "length");
195 rtinfo
->invflags
|= IP6T_RT_INV_LEN
;
196 rtinfo
->flags
|= IP6T_RT_LEN
;
197 *flags
|= IP6T_RT_LEN
;
200 if (*flags
& IP6T_RT_RES
)
201 exit_error(PARAMETER_PROBLEM
,
202 "Only one `--rt-0-res' allowed");
203 if ( !(*flags
& IP6T_RT_TYP
) || (rtinfo
->rt_type
!= 0) || (rtinfo
->invflags
& IP6T_RT_INV_TYP
) )
204 exit_error(PARAMETER_PROBLEM
,
205 "`--rt-type 0' required before `--rt-0-res'");
206 rtinfo
->flags
|= IP6T_RT_RES
;
207 *flags
|= IP6T_RT_RES
;
210 if (*flags
& IP6T_RT_FST
)
211 exit_error(PARAMETER_PROBLEM
,
212 "Only one `--rt-0-addrs' allowed");
213 if ( !(*flags
& IP6T_RT_TYP
) || (rtinfo
->rt_type
!= 0) || (rtinfo
->invflags
& IP6T_RT_INV_TYP
) )
214 exit_error(PARAMETER_PROBLEM
,
215 "`--rt-type 0' required before `--rt-0-addrs'");
216 check_inverse(optarg
, &invert
, &optind
, 0);
218 exit_error(PARAMETER_PROBLEM
,
219 " '!' not allowed with `--rt-0-addrs'");
220 rtinfo
->addrnr
= parse_addresses(argv
[optind
-1], rtinfo
->addrs
);
221 rtinfo
->flags
|= IP6T_RT_FST
;
222 *flags
|= IP6T_RT_FST
;
225 if (*flags
& IP6T_RT_FST_NSTRICT
)
226 exit_error(PARAMETER_PROBLEM
,
227 "Only one `--rt-0-not-strict' allowed");
228 if ( !(*flags
& IP6T_RT_FST
) )
229 exit_error(PARAMETER_PROBLEM
,
230 "`--rt-0-addr ...' required before `--rt-0-not-strict'");
231 rtinfo
->flags
|= IP6T_RT_FST_NSTRICT
;
232 *flags
|= IP6T_RT_FST_NSTRICT
;
241 /* Final check; we don't care. */
243 final_check(unsigned int flags
)
248 print_nums(const char *name
, u_int32_t min
, u_int32_t max
,
251 const char *inv
= invert
? "!" : "";
253 if (min
!= 0 || max
!= 0xFFFFFFFF || invert
) {
269 print_addresses(int addrnr
, struct in6_addr
*addrp
)
273 for(i
=0; i
<addrnr
; i
++){
274 printf("%s%c", addr_to_numeric(&(addrp
[i
])), (i
!=addrnr
-1)?',':' ');
278 /* Prints out the union ip6t_matchinfo. */
280 print(const struct ip6t_ip6
*ip
,
281 const struct ip6t_entry_match
*match
, int numeric
)
283 const struct ip6t_rt
*rtinfo
= (struct ip6t_rt
*)match
->data
;
286 if (rtinfo
->flags
& IP6T_RT_TYP
)
287 printf("type:%s%d ", rtinfo
->invflags
& IP6T_RT_INV_TYP
? "!" : "",
289 print_nums("segsleft", rtinfo
->segsleft
[0], rtinfo
->segsleft
[1],
290 rtinfo
->invflags
& IP6T_RT_INV_SGS
);
291 if (rtinfo
->flags
& IP6T_RT_LEN
) {
293 printf(":%s", rtinfo
->invflags
& IP6T_RT_INV_LEN
? "!" : "");
294 printf("%u", rtinfo
->hdrlen
);
297 if (rtinfo
->flags
& IP6T_RT_RES
) printf("reserved ");
298 if (rtinfo
->flags
& IP6T_RT_FST
) printf("0-addrs ");
299 print_addresses(rtinfo
->addrnr
, (struct in6_addr
*)rtinfo
->addrs
);
300 if (rtinfo
->flags
& IP6T_RT_FST_NSTRICT
) printf("0-not-strict ");
301 if (rtinfo
->invflags
& ~IP6T_RT_INV_MASK
)
302 printf("Unknown invflags: 0x%X ",
303 rtinfo
->invflags
& ~IP6T_RT_INV_MASK
);
306 /* Saves the union ip6t_matchinfo in parsable form to stdout. */
307 static void save(const struct ip6t_ip6
*ip
, const struct ip6t_entry_match
*match
)
309 const struct ip6t_rt
*rtinfo
= (struct ip6t_rt
*)match
->data
;
311 if (rtinfo
->flags
& IP6T_RT_TYP
) {
312 printf("--rt-type %s%u ",
313 (rtinfo
->invflags
& IP6T_RT_INV_TYP
) ? "! " : "",
317 if (!(rtinfo
->segsleft
[0] == 0
318 && rtinfo
->segsleft
[1] == 0xFFFFFFFF)) {
319 printf("--rt-segsleft %s",
320 (rtinfo
->invflags
& IP6T_RT_INV_SGS
) ? "! " : "");
321 if (rtinfo
->segsleft
[0]
322 != rtinfo
->segsleft
[1])
325 rtinfo
->segsleft
[1]);
328 rtinfo
->segsleft
[0]);
331 if (rtinfo
->flags
& IP6T_RT_LEN
) {
332 printf("--rt-len %s%u ",
333 (rtinfo
->invflags
& IP6T_RT_INV_LEN
) ? "! " : "",
337 if (rtinfo
->flags
& IP6T_RT_RES
) printf("--rt-0-res ");
338 if (rtinfo
->flags
& IP6T_RT_FST
) printf("--rt-0-addrs ");
339 print_addresses(rtinfo
->addrnr
, (struct in6_addr
*)rtinfo
->addrs
);
340 if (rtinfo
->flags
& IP6T_RT_FST_NSTRICT
) printf("--rt-0-not-strict ");
344 static struct ip6tables_match rt
= {
346 .version
= IPTABLES_VERSION
,
347 .size
= IP6T_ALIGN(sizeof(struct ip6t_rt
)),
348 .userspacesize
= IP6T_ALIGN(sizeof(struct ip6t_rt
)),
352 .final_check
= &final_check
,
361 register_match6(&rt
);