1d17aef79SPedro F. Giffuni /*-
2ead75a59SLuigi Rizzo * Copyright (c) 2002-2003 Luigi Rizzo
3ead75a59SLuigi Rizzo * Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp
4ead75a59SLuigi Rizzo * Copyright (c) 1994 Ugen J.S.Antsilevich
5ead75a59SLuigi Rizzo *
6ead75a59SLuigi Rizzo * Idea and grammar partially left from:
7ead75a59SLuigi Rizzo * Copyright (c) 1993 Daniel Boulet
8ead75a59SLuigi Rizzo *
9ead75a59SLuigi Rizzo * Redistribution and use in source forms, with and without modification,
10ead75a59SLuigi Rizzo * are permitted provided that this entire comment appears intact.
11ead75a59SLuigi Rizzo *
12ead75a59SLuigi Rizzo * Redistribution in binary form may occur without any restrictions.
13ead75a59SLuigi Rizzo * Obviously, it would be nice if you gave credit where credit is due
14ead75a59SLuigi Rizzo * but requiring it would be too onerous.
15ead75a59SLuigi Rizzo *
16ead75a59SLuigi Rizzo * This software is provided ``AS IS'' without any warranties of any kind.
17ead75a59SLuigi Rizzo *
18ead75a59SLuigi Rizzo * NEW command line interface for IP firewall facility
19ead75a59SLuigi Rizzo *
20ead75a59SLuigi Rizzo * ipv6 support
21ead75a59SLuigi Rizzo */
22ead75a59SLuigi Rizzo
23ead75a59SLuigi Rizzo #include <sys/types.h>
24ead75a59SLuigi Rizzo #include <sys/socket.h>
25ead75a59SLuigi Rizzo
26ead75a59SLuigi Rizzo #include "ipfw2.h"
27ead75a59SLuigi Rizzo
28ead75a59SLuigi Rizzo #include <err.h>
29ead75a59SLuigi Rizzo #include <netdb.h>
30ead75a59SLuigi Rizzo #include <stdio.h>
31ead75a59SLuigi Rizzo #include <stdlib.h>
32ead75a59SLuigi Rizzo #include <string.h>
33ead75a59SLuigi Rizzo #include <sysexits.h>
34ead75a59SLuigi Rizzo
35ead75a59SLuigi Rizzo #include <net/if.h>
36ead75a59SLuigi Rizzo #include <netinet/in.h>
37ead75a59SLuigi Rizzo #include <netinet/in_systm.h>
38ead75a59SLuigi Rizzo #include <netinet/ip.h>
39ead75a59SLuigi Rizzo #include <netinet/icmp6.h>
40ead75a59SLuigi Rizzo #include <netinet/ip_fw.h>
41ead75a59SLuigi Rizzo #include <arpa/inet.h>
42ead75a59SLuigi Rizzo
43579ed7bdSAlexander V. Chernikov #define CHECK_LENGTH(v, len) do { \
44579ed7bdSAlexander V. Chernikov if ((v) < (len)) \
45579ed7bdSAlexander V. Chernikov errx(EX_DATAERR, "Rule too long"); \
46579ed7bdSAlexander V. Chernikov } while (0)
47579ed7bdSAlexander V. Chernikov
48ead75a59SLuigi Rizzo static struct _s_x icmp6codes[] = {
49ead75a59SLuigi Rizzo { "no-route", ICMP6_DST_UNREACH_NOROUTE },
50ead75a59SLuigi Rizzo { "admin-prohib", ICMP6_DST_UNREACH_ADMIN },
51ead75a59SLuigi Rizzo { "address", ICMP6_DST_UNREACH_ADDR },
52ead75a59SLuigi Rizzo { "port", ICMP6_DST_UNREACH_NOPORT },
53ead75a59SLuigi Rizzo { NULL, 0 }
54ead75a59SLuigi Rizzo };
55ead75a59SLuigi Rizzo
56*2b5dd8b8SAlexander V. Chernikov uint16_t
get_unreach6_code(const char * str)57*2b5dd8b8SAlexander V. Chernikov get_unreach6_code(const char *str)
58ead75a59SLuigi Rizzo {
59ead75a59SLuigi Rizzo int val;
60ead75a59SLuigi Rizzo char *s;
61ead75a59SLuigi Rizzo
62ead75a59SLuigi Rizzo val = strtoul(str, &s, 0);
63ead75a59SLuigi Rizzo if (s == str || *s != '\0' || val >= 0x100)
64ead75a59SLuigi Rizzo val = match_token(icmp6codes, str);
65ead75a59SLuigi Rizzo if (val < 0)
66ead75a59SLuigi Rizzo errx(EX_DATAERR, "unknown ICMPv6 unreachable code ``%s''", str);
67*2b5dd8b8SAlexander V. Chernikov return (val);
68ead75a59SLuigi Rizzo }
69ead75a59SLuigi Rizzo
70ead75a59SLuigi Rizzo void
print_unreach6_code(struct buf_pr * bp,uint16_t code)717b34dbe4SAndrey V. Elsukov print_unreach6_code(struct buf_pr *bp, uint16_t code)
72ead75a59SLuigi Rizzo {
73ead75a59SLuigi Rizzo char const *s = match_value(icmp6codes, code);
74ead75a59SLuigi Rizzo
75ead75a59SLuigi Rizzo if (s != NULL)
767b34dbe4SAndrey V. Elsukov bprintf(bp, "unreach6 %s", s);
77ead75a59SLuigi Rizzo else
787b34dbe4SAndrey V. Elsukov bprintf(bp, "unreach6 %u", code);
79ead75a59SLuigi Rizzo }
80ead75a59SLuigi Rizzo
81ead75a59SLuigi Rizzo /*
82ead75a59SLuigi Rizzo * Print the ip address contained in a command.
83ead75a59SLuigi Rizzo */
84ead75a59SLuigi Rizzo void
print_ip6(struct buf_pr * bp,const ipfw_insn_ip6 * cmd)8556707beeSMark Johnston print_ip6(struct buf_pr *bp, const ipfw_insn_ip6 *cmd)
86ead75a59SLuigi Rizzo {
87ead75a59SLuigi Rizzo char trad[255];
880f71e509SAndrey V. Elsukov struct hostent *he = NULL;
8956707beeSMark Johnston const struct in6_addr *a = &(cmd->addr6);
900f71e509SAndrey V. Elsukov int len, mb;
91ead75a59SLuigi Rizzo
9256707beeSMark Johnston len = F_LEN((const ipfw_insn *)cmd) - 1;
93ead75a59SLuigi Rizzo if (cmd->o.opcode == O_IP6_SRC_ME || cmd->o.opcode == O_IP6_DST_ME) {
94912430f6SAlexander V. Chernikov bprintf(bp, " me6");
95ead75a59SLuigi Rizzo return;
96ead75a59SLuigi Rizzo }
97ead75a59SLuigi Rizzo if (cmd->o.opcode == O_IP6) {
98912430f6SAlexander V. Chernikov bprintf(bp, " ip6");
99ead75a59SLuigi Rizzo return;
100ead75a59SLuigi Rizzo }
101ead75a59SLuigi Rizzo
102ead75a59SLuigi Rizzo /*
103ead75a59SLuigi Rizzo * len == 4 indicates a single IP, whereas lists of 1 or more
104ead75a59SLuigi Rizzo * addr/mask pairs have len = (2n+1). We convert len to n so we
105ead75a59SLuigi Rizzo * use that to count the number of entries.
106ead75a59SLuigi Rizzo */
107bd32e335SAndrey V. Elsukov bprintf(bp, " ");
108ead75a59SLuigi Rizzo for (len = len / 4; len > 0; len -= 2, a += 2) {
1090f71e509SAndrey V. Elsukov /* mask length */
1100f71e509SAndrey V. Elsukov mb = (cmd->o.opcode == O_IP6_SRC ||
1110f71e509SAndrey V. Elsukov cmd->o.opcode == O_IP6_DST) ? 128:
11256707beeSMark Johnston contigmask((const uint8_t *)&(a[1]), 128);
113ead75a59SLuigi Rizzo
11456707beeSMark Johnston if (mb == 128 && g_co.do_resolv)
11556707beeSMark Johnston he = gethostbyaddr((const char *)a, sizeof(*a),
11656707beeSMark Johnston AF_INET6);
1170f71e509SAndrey V. Elsukov
118ead75a59SLuigi Rizzo if (he != NULL) /* resolved to name */
119912430f6SAlexander V. Chernikov bprintf(bp, "%s", he->h_name);
120ead75a59SLuigi Rizzo else if (mb == 0) /* any */
121912430f6SAlexander V. Chernikov bprintf(bp, "any");
122ead75a59SLuigi Rizzo else { /* numeric IP followed by some kind of mask */
1230f71e509SAndrey V. Elsukov if (inet_ntop(AF_INET6, a, trad,
1240f71e509SAndrey V. Elsukov sizeof(trad)) == NULL)
125912430f6SAlexander V. Chernikov bprintf(bp, "Error ntop in print_ip6\n");
126912430f6SAlexander V. Chernikov bprintf(bp, "%s", trad );
12723b93085SAndrey V. Elsukov if (mb < 0) /* mask not contiguous */
1280f71e509SAndrey V. Elsukov bprintf(bp, "/%s", inet_ntop(AF_INET6, &a[1],
1290f71e509SAndrey V. Elsukov trad, sizeof(trad)));
130ead75a59SLuigi Rizzo else if (mb < 128)
131912430f6SAlexander V. Chernikov bprintf(bp, "/%d", mb);
132ead75a59SLuigi Rizzo }
133ead75a59SLuigi Rizzo if (len > 2)
134912430f6SAlexander V. Chernikov bprintf(bp, ",");
135ead75a59SLuigi Rizzo }
136ead75a59SLuigi Rizzo }
137ead75a59SLuigi Rizzo
138ead75a59SLuigi Rizzo void
fill_icmp6types(ipfw_insn_icmp6 * cmd,char * av,int cblen)139579ed7bdSAlexander V. Chernikov fill_icmp6types(ipfw_insn_icmp6 *cmd, char *av, int cblen)
140ead75a59SLuigi Rizzo {
141ead75a59SLuigi Rizzo uint8_t type;
142ead75a59SLuigi Rizzo
14356707beeSMark Johnston CHECK_LENGTH(cblen, (int)F_INSN_SIZE(ipfw_insn_icmp6));
14451b15930SAndrey V. Elsukov memset(cmd, 0, sizeof(*cmd));
145ead75a59SLuigi Rizzo while (*av) {
146ead75a59SLuigi Rizzo if (*av == ',')
147ead75a59SLuigi Rizzo av++;
148ead75a59SLuigi Rizzo type = strtoul(av, &av, 0);
149ead75a59SLuigi Rizzo if (*av != ',' && *av != '\0')
150ead75a59SLuigi Rizzo errx(EX_DATAERR, "invalid ICMP6 type");
151ead75a59SLuigi Rizzo /*
152ead75a59SLuigi Rizzo * XXX: shouldn't this be 0xFF? I can't see any reason why
153ead75a59SLuigi Rizzo * we shouldn't be able to filter all possiable values
154ead75a59SLuigi Rizzo * regardless of the ability of the rest of the kernel to do
155ead75a59SLuigi Rizzo * anything useful with them.
156ead75a59SLuigi Rizzo */
157ead75a59SLuigi Rizzo if (type > ICMP6_MAXTYPE)
158ead75a59SLuigi Rizzo errx(EX_DATAERR, "ICMP6 type out of range");
159ead75a59SLuigi Rizzo cmd->d[type / 32] |= ( 1 << (type % 32));
160ead75a59SLuigi Rizzo }
161ead75a59SLuigi Rizzo cmd->o.opcode = O_ICMP6TYPE;
162ead75a59SLuigi Rizzo cmd->o.len |= F_INSN_SIZE(ipfw_insn_icmp6);
163ead75a59SLuigi Rizzo }
164ead75a59SLuigi Rizzo
165ead75a59SLuigi Rizzo void
print_icmp6types(struct buf_pr * bp,const ipfw_insn_u32 * cmd)16656707beeSMark Johnston print_icmp6types(struct buf_pr *bp, const ipfw_insn_u32 *cmd)
167ead75a59SLuigi Rizzo {
168ead75a59SLuigi Rizzo int i, j;
169ead75a59SLuigi Rizzo char sep= ' ';
170ead75a59SLuigi Rizzo
1718f47ad01SAndrey V. Elsukov bprintf(bp, " icmp6types");
172ead75a59SLuigi Rizzo for (i = 0; i < 7; i++)
173ead75a59SLuigi Rizzo for (j=0; j < 32; ++j) {
174ead75a59SLuigi Rizzo if ( (cmd->d[i] & (1 << (j))) == 0)
175ead75a59SLuigi Rizzo continue;
176912430f6SAlexander V. Chernikov bprintf(bp, "%c%d", sep, (i*32 + j));
177ead75a59SLuigi Rizzo sep = ',';
178ead75a59SLuigi Rizzo }
179ead75a59SLuigi Rizzo }
180ead75a59SLuigi Rizzo
181ead75a59SLuigi Rizzo void
print_flow6id(struct buf_pr * bp,const ipfw_insn_u32 * cmd)18256707beeSMark Johnston print_flow6id(struct buf_pr *bp, const ipfw_insn_u32 *cmd)
183ead75a59SLuigi Rizzo {
184ead75a59SLuigi Rizzo uint16_t i, limit = cmd->o.arg1;
185ead75a59SLuigi Rizzo char sep = ',';
186ead75a59SLuigi Rizzo
187912430f6SAlexander V. Chernikov bprintf(bp, " flow-id ");
188ead75a59SLuigi Rizzo for( i=0; i < limit; ++i) {
189ead75a59SLuigi Rizzo if (i == limit - 1)
190ead75a59SLuigi Rizzo sep = ' ';
191912430f6SAlexander V. Chernikov bprintf(bp, "%d%c", cmd->d[i], sep);
192ead75a59SLuigi Rizzo }
193ead75a59SLuigi Rizzo }
194ead75a59SLuigi Rizzo
195ead75a59SLuigi Rizzo /* structure and define for the extension header in ipv6 */
196ead75a59SLuigi Rizzo static struct _s_x ext6hdrcodes[] = {
197ead75a59SLuigi Rizzo { "frag", EXT_FRAGMENT },
198ead75a59SLuigi Rizzo { "hopopt", EXT_HOPOPTS },
199ead75a59SLuigi Rizzo { "route", EXT_ROUTING },
200ead75a59SLuigi Rizzo { "dstopt", EXT_DSTOPTS },
201ead75a59SLuigi Rizzo { "ah", EXT_AH },
202ead75a59SLuigi Rizzo { "esp", EXT_ESP },
203ead75a59SLuigi Rizzo { "rthdr0", EXT_RTHDR0 },
204ead75a59SLuigi Rizzo { "rthdr2", EXT_RTHDR2 },
205ead75a59SLuigi Rizzo { NULL, 0 }
206ead75a59SLuigi Rizzo };
207ead75a59SLuigi Rizzo
208ead75a59SLuigi Rizzo /* fills command for the extension header filtering */
209ead75a59SLuigi Rizzo int
fill_ext6hdr(ipfw_insn * cmd,char * av)210ead75a59SLuigi Rizzo fill_ext6hdr( ipfw_insn *cmd, char *av)
211ead75a59SLuigi Rizzo {
212ead75a59SLuigi Rizzo int tok;
213ead75a59SLuigi Rizzo char *s = av;
214ead75a59SLuigi Rizzo
215ead75a59SLuigi Rizzo cmd->arg1 = 0;
216ead75a59SLuigi Rizzo while(s) {
217ead75a59SLuigi Rizzo av = strsep( &s, ",") ;
218ead75a59SLuigi Rizzo tok = match_token(ext6hdrcodes, av);
219ead75a59SLuigi Rizzo switch (tok) {
220ead75a59SLuigi Rizzo case EXT_FRAGMENT:
221ead75a59SLuigi Rizzo cmd->arg1 |= EXT_FRAGMENT;
222ead75a59SLuigi Rizzo break;
223ead75a59SLuigi Rizzo case EXT_HOPOPTS:
224ead75a59SLuigi Rizzo cmd->arg1 |= EXT_HOPOPTS;
225ead75a59SLuigi Rizzo break;
226ead75a59SLuigi Rizzo case EXT_ROUTING:
227ead75a59SLuigi Rizzo cmd->arg1 |= EXT_ROUTING;
228ead75a59SLuigi Rizzo break;
229ead75a59SLuigi Rizzo case EXT_DSTOPTS:
230ead75a59SLuigi Rizzo cmd->arg1 |= EXT_DSTOPTS;
231ead75a59SLuigi Rizzo break;
232ead75a59SLuigi Rizzo case EXT_AH:
233ead75a59SLuigi Rizzo cmd->arg1 |= EXT_AH;
234ead75a59SLuigi Rizzo break;
235ead75a59SLuigi Rizzo case EXT_ESP:
236ead75a59SLuigi Rizzo cmd->arg1 |= EXT_ESP;
237ead75a59SLuigi Rizzo break;
238ead75a59SLuigi Rizzo case EXT_RTHDR0:
239ead75a59SLuigi Rizzo cmd->arg1 |= EXT_RTHDR0;
240ead75a59SLuigi Rizzo break;
241ead75a59SLuigi Rizzo case EXT_RTHDR2:
242ead75a59SLuigi Rizzo cmd->arg1 |= EXT_RTHDR2;
243ead75a59SLuigi Rizzo break;
244ead75a59SLuigi Rizzo default:
2450f71e509SAndrey V. Elsukov errx(EX_DATAERR,
2460f71e509SAndrey V. Elsukov "invalid option for ipv6 exten header");
247ead75a59SLuigi Rizzo break;
248ead75a59SLuigi Rizzo }
249ead75a59SLuigi Rizzo }
250ead75a59SLuigi Rizzo if (cmd->arg1 == 0)
2510f71e509SAndrey V. Elsukov return (0);
252ead75a59SLuigi Rizzo cmd->opcode = O_EXT_HDR;
253ead75a59SLuigi Rizzo cmd->len |= F_INSN_SIZE(ipfw_insn);
2540f71e509SAndrey V. Elsukov return (1);
255ead75a59SLuigi Rizzo }
256ead75a59SLuigi Rizzo
257ead75a59SLuigi Rizzo void
print_ext6hdr(struct buf_pr * bp,const ipfw_insn * cmd)25856707beeSMark Johnston print_ext6hdr(struct buf_pr *bp, const ipfw_insn *cmd )
259ead75a59SLuigi Rizzo {
260ead75a59SLuigi Rizzo char sep = ' ';
261ead75a59SLuigi Rizzo
262912430f6SAlexander V. Chernikov bprintf(bp, " extension header:");
263ead75a59SLuigi Rizzo if (cmd->arg1 & EXT_FRAGMENT) {
264912430f6SAlexander V. Chernikov bprintf(bp, "%cfragmentation", sep);
265ead75a59SLuigi Rizzo sep = ',';
266ead75a59SLuigi Rizzo }
267ead75a59SLuigi Rizzo if (cmd->arg1 & EXT_HOPOPTS) {
268912430f6SAlexander V. Chernikov bprintf(bp, "%chop options", sep);
269ead75a59SLuigi Rizzo sep = ',';
270ead75a59SLuigi Rizzo }
271ead75a59SLuigi Rizzo if (cmd->arg1 & EXT_ROUTING) {
272912430f6SAlexander V. Chernikov bprintf(bp, "%crouting options", sep);
273ead75a59SLuigi Rizzo sep = ',';
274ead75a59SLuigi Rizzo }
275ead75a59SLuigi Rizzo if (cmd->arg1 & EXT_RTHDR0) {
276912430f6SAlexander V. Chernikov bprintf(bp, "%crthdr0", sep);
277ead75a59SLuigi Rizzo sep = ',';
278ead75a59SLuigi Rizzo }
279ead75a59SLuigi Rizzo if (cmd->arg1 & EXT_RTHDR2) {
280912430f6SAlexander V. Chernikov bprintf(bp, "%crthdr2", sep);
281ead75a59SLuigi Rizzo sep = ',';
282ead75a59SLuigi Rizzo }
283ead75a59SLuigi Rizzo if (cmd->arg1 & EXT_DSTOPTS) {
284912430f6SAlexander V. Chernikov bprintf(bp, "%cdestination options", sep);
285ead75a59SLuigi Rizzo sep = ',';
286ead75a59SLuigi Rizzo }
287ead75a59SLuigi Rizzo if (cmd->arg1 & EXT_AH) {
288912430f6SAlexander V. Chernikov bprintf(bp, "%cauthentication header", sep);
289ead75a59SLuigi Rizzo sep = ',';
290ead75a59SLuigi Rizzo }
291ead75a59SLuigi Rizzo if (cmd->arg1 & EXT_ESP) {
292912430f6SAlexander V. Chernikov bprintf(bp, "%cencapsulated security payload", sep);
293ead75a59SLuigi Rizzo }
294ead75a59SLuigi Rizzo }
295ead75a59SLuigi Rizzo
296ead75a59SLuigi Rizzo /* Try to find ipv6 address by hostname */
297ead75a59SLuigi Rizzo static int
lookup_host6(char * host,struct in6_addr * ip6addr)298ead75a59SLuigi Rizzo lookup_host6 (char *host, struct in6_addr *ip6addr)
299ead75a59SLuigi Rizzo {
300ead75a59SLuigi Rizzo struct hostent *he;
301ead75a59SLuigi Rizzo
302ead75a59SLuigi Rizzo if (!inet_pton(AF_INET6, host, ip6addr)) {
303ead75a59SLuigi Rizzo if ((he = gethostbyname2(host, AF_INET6)) == NULL)
304ead75a59SLuigi Rizzo return(-1);
305ead75a59SLuigi Rizzo memcpy(ip6addr, he->h_addr_list[0], sizeof( struct in6_addr));
306ead75a59SLuigi Rizzo }
307ead75a59SLuigi Rizzo return (0);
308ead75a59SLuigi Rizzo }
309ead75a59SLuigi Rizzo
310ead75a59SLuigi Rizzo
311ead75a59SLuigi Rizzo /*
312ead75a59SLuigi Rizzo * fill the addr and mask fields in the instruction as appropriate from av.
313ead75a59SLuigi Rizzo * Update length as appropriate.
314ead75a59SLuigi Rizzo * The following formats are allowed:
315ead75a59SLuigi Rizzo * any matches any IP6. Actually returns an empty instruction.
316ead75a59SLuigi Rizzo * me returns O_IP6_*_ME
317ead75a59SLuigi Rizzo *
318b68ac800SPedro F. Giffuni * 03f1::234:123:0342 single IP6 address
31923b93085SAndrey V. Elsukov * 03f1::234:123:0342/24 address/masklen
32023b93085SAndrey V. Elsukov * 03f1::234:123:0342/ffff::ffff:ffff address/mask
321ead75a59SLuigi Rizzo * 03f1::234:123:0342/24,03f1::234:123:0343/ List of address
322ead75a59SLuigi Rizzo *
323ead75a59SLuigi Rizzo * Set of address (as in ipv6) not supported because ipv6 address
324ead75a59SLuigi Rizzo * are typically random past the initial prefix.
325ead75a59SLuigi Rizzo * Return 1 on success, 0 on failure.
326ead75a59SLuigi Rizzo */
327ead75a59SLuigi Rizzo static int
fill_ip6(ipfw_insn_ip6 * cmd,char * av,int cblen,struct tidx * tstate)328757b5d87SAndrey V. Elsukov fill_ip6(ipfw_insn_ip6 *cmd, char *av, int cblen, struct tidx *tstate)
329ead75a59SLuigi Rizzo {
330ead75a59SLuigi Rizzo int len = 0;
331ead75a59SLuigi Rizzo struct in6_addr *d = &(cmd->addr6);
332247cea8fSMarius Strobl char *oav;
333ead75a59SLuigi Rizzo /*
334ead75a59SLuigi Rizzo * Needed for multiple address.
335ead75a59SLuigi Rizzo * Note d[1] points to struct in6_add r mask6 of cmd
336ead75a59SLuigi Rizzo */
337ead75a59SLuigi Rizzo
338ead75a59SLuigi Rizzo cmd->o.len &= ~F_LEN_MASK; /* zero len */
339ead75a59SLuigi Rizzo
340ead75a59SLuigi Rizzo if (strcmp(av, "any") == 0)
341ead75a59SLuigi Rizzo return (1);
342ead75a59SLuigi Rizzo
34327b3db97SMark Johnston /* Set the data for "me" opt */
34427b3db97SMark Johnston if (strcmp(av, "me") == 0 || strcmp(av, "me6") == 0) {
345ead75a59SLuigi Rizzo cmd->o.len |= F_INSN_SIZE(ipfw_insn);
346ead75a59SLuigi Rizzo return (1);
347ead75a59SLuigi Rizzo }
348ead75a59SLuigi Rizzo
3497e00325dSAlexander V. Chernikov if (strncmp(av, "table(", 6) == 0) {
350757b5d87SAndrey V. Elsukov fill_table(&cmd->o, av, O_IP_DST_LOOKUP, tstate);
3517e00325dSAlexander V. Chernikov return (1);
3527e00325dSAlexander V. Chernikov }
3537e00325dSAlexander V. Chernikov
354247cea8fSMarius Strobl oav = av = strdup(av);
355ead75a59SLuigi Rizzo while (av) {
356ead75a59SLuigi Rizzo /*
357ead75a59SLuigi Rizzo * After the address we can have '/' indicating a mask,
358ead75a59SLuigi Rizzo * or ',' indicating another address follows.
359ead75a59SLuigi Rizzo */
360ead75a59SLuigi Rizzo
36123b93085SAndrey V. Elsukov char *p, *q;
362ead75a59SLuigi Rizzo int masklen;
363ead75a59SLuigi Rizzo char md = '\0';
364ead75a59SLuigi Rizzo
36556707beeSMark Johnston CHECK_LENGTH(cblen,
36656707beeSMark Johnston 1 + len + 2 * (int)F_INSN_SIZE(struct in6_addr));
367579ed7bdSAlexander V. Chernikov
36823b93085SAndrey V. Elsukov if ((q = strchr(av, ',')) ) {
36923b93085SAndrey V. Elsukov *q = '\0';
37023b93085SAndrey V. Elsukov q++;
37123b93085SAndrey V. Elsukov }
37223b93085SAndrey V. Elsukov
37323b93085SAndrey V. Elsukov if ((p = strchr(av, '/')) ) {
374ead75a59SLuigi Rizzo md = *p; /* save the separator */
375ead75a59SLuigi Rizzo *p = '\0'; /* terminate address string */
376ead75a59SLuigi Rizzo p++; /* and skip past it */
377ead75a59SLuigi Rizzo }
378ead75a59SLuigi Rizzo /* now p points to NULL, mask or next entry */
379ead75a59SLuigi Rizzo
380ead75a59SLuigi Rizzo /* lookup stores address in *d as a side effect */
381ead75a59SLuigi Rizzo if (lookup_host6(av, d) != 0) {
382ead75a59SLuigi Rizzo /* XXX: failed. Free memory and go */
383ead75a59SLuigi Rizzo errx(EX_DATAERR, "bad address \"%s\"", av);
384ead75a59SLuigi Rizzo }
385ead75a59SLuigi Rizzo /* next, look at the mask, if any */
38623b93085SAndrey V. Elsukov if (md == '/' && strchr(p, ':')) {
38723b93085SAndrey V. Elsukov if (!inet_pton(AF_INET6, p, &d[1]))
38823b93085SAndrey V. Elsukov errx(EX_DATAERR, "bad mask \"%s\"", p);
38923b93085SAndrey V. Elsukov
39023b93085SAndrey V. Elsukov masklen = contigmask((uint8_t *)&(d[1]), 128);
39123b93085SAndrey V. Elsukov } else {
392ead75a59SLuigi Rizzo masklen = (md == '/') ? atoi(p) : 128;
393ead75a59SLuigi Rizzo if (masklen > 128 || masklen < 0)
394ead75a59SLuigi Rizzo errx(EX_DATAERR, "bad width \"%s\''", p);
395ead75a59SLuigi Rizzo else
396ead75a59SLuigi Rizzo n2mask(&d[1], masklen);
39723b93085SAndrey V. Elsukov }
398ead75a59SLuigi Rizzo
3995786c6b9SAndrey V. Elsukov APPLY_MASK(d, &d[1]); /* mask base address with mask */
400ead75a59SLuigi Rizzo
40123b93085SAndrey V. Elsukov av = q;
402ead75a59SLuigi Rizzo
403ead75a59SLuigi Rizzo /* Check this entry */
404ead75a59SLuigi Rizzo if (masklen == 0) {
405ead75a59SLuigi Rizzo /*
406ead75a59SLuigi Rizzo * 'any' turns the entire list into a NOP.
407ead75a59SLuigi Rizzo * 'not any' never matches, so it is removed from the
408ead75a59SLuigi Rizzo * list unless it is the only item, in which case we
409ead75a59SLuigi Rizzo * report an error.
410ead75a59SLuigi Rizzo */
411ead75a59SLuigi Rizzo if (cmd->o.len & F_NOT && av == NULL && len == 0)
412ead75a59SLuigi Rizzo errx(EX_DATAERR, "not any never matches");
413ead75a59SLuigi Rizzo continue;
414ead75a59SLuigi Rizzo }
415ead75a59SLuigi Rizzo
416ead75a59SLuigi Rizzo /*
417ead75a59SLuigi Rizzo * A single IP can be stored alone
418ead75a59SLuigi Rizzo */
419ead75a59SLuigi Rizzo if (masklen == 128 && av == NULL && len == 0) {
420ead75a59SLuigi Rizzo len = F_INSN_SIZE(struct in6_addr);
421ead75a59SLuigi Rizzo break;
422ead75a59SLuigi Rizzo }
423ead75a59SLuigi Rizzo
424ead75a59SLuigi Rizzo /* Update length and pointer to arguments */
425ead75a59SLuigi Rizzo len += F_INSN_SIZE(struct in6_addr)*2;
426ead75a59SLuigi Rizzo d += 2;
427ead75a59SLuigi Rizzo } /* end while */
428ead75a59SLuigi Rizzo
429ead75a59SLuigi Rizzo /*
430ead75a59SLuigi Rizzo * Total length of the command, remember that 1 is the size of
431ead75a59SLuigi Rizzo * the base command.
432ead75a59SLuigi Rizzo */
433ead75a59SLuigi Rizzo if (len + 1 > F_LEN_MASK)
434ead75a59SLuigi Rizzo errx(EX_DATAERR, "address list too long");
435ead75a59SLuigi Rizzo cmd->o.len |= len+1;
436247cea8fSMarius Strobl free(oav);
437ead75a59SLuigi Rizzo return (1);
438ead75a59SLuigi Rizzo }
439ead75a59SLuigi Rizzo
440ead75a59SLuigi Rizzo /*
441ead75a59SLuigi Rizzo * fills command for ipv6 flow-id filtering
442ead75a59SLuigi Rizzo * note that the 20 bit flow number is stored in a array of u_int32_t
443ead75a59SLuigi Rizzo * it's supported lists of flow-id, so in the o.arg1 we store how many
444ead75a59SLuigi Rizzo * additional flow-id we want to filter, the basic is 1
445ead75a59SLuigi Rizzo */
446ead75a59SLuigi Rizzo void
fill_flow6(ipfw_insn_u32 * cmd,char * av,int cblen)447579ed7bdSAlexander V. Chernikov fill_flow6( ipfw_insn_u32 *cmd, char *av, int cblen)
448ead75a59SLuigi Rizzo {
449ead75a59SLuigi Rizzo u_int32_t type; /* Current flow number */
450ead75a59SLuigi Rizzo u_int16_t nflow = 0; /* Current flow index */
451ead75a59SLuigi Rizzo char *s = av;
452ead75a59SLuigi Rizzo cmd->d[0] = 0; /* Initializing the base number*/
453ead75a59SLuigi Rizzo
454ead75a59SLuigi Rizzo while (s) {
45556707beeSMark Johnston CHECK_LENGTH(cblen,
45656707beeSMark Johnston (int)F_INSN_SIZE(ipfw_insn_u32) + nflow + 1);
457579ed7bdSAlexander V. Chernikov
458ead75a59SLuigi Rizzo av = strsep( &s, ",") ;
459ead75a59SLuigi Rizzo type = strtoul(av, &av, 0);
460ead75a59SLuigi Rizzo if (*av != ',' && *av != '\0')
461ead75a59SLuigi Rizzo errx(EX_DATAERR, "invalid ipv6 flow number %s", av);
462ead75a59SLuigi Rizzo if (type > 0xfffff)
463ead75a59SLuigi Rizzo errx(EX_DATAERR, "flow number out of range %s", av);
464ead75a59SLuigi Rizzo cmd->d[nflow] |= type;
465ead75a59SLuigi Rizzo nflow++;
466ead75a59SLuigi Rizzo }
467ead75a59SLuigi Rizzo if( nflow > 0 ) {
468ead75a59SLuigi Rizzo cmd->o.opcode = O_FLOW6ID;
469ead75a59SLuigi Rizzo cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32) + nflow;
470ead75a59SLuigi Rizzo cmd->o.arg1 = nflow;
471ead75a59SLuigi Rizzo }
472ead75a59SLuigi Rizzo else {
473ead75a59SLuigi Rizzo errx(EX_DATAERR, "invalid ipv6 flow number %s", av);
474ead75a59SLuigi Rizzo }
475ead75a59SLuigi Rizzo }
476ead75a59SLuigi Rizzo
477ead75a59SLuigi Rizzo ipfw_insn *
add_srcip6(ipfw_insn * cmd,char * av,int cblen,struct tidx * tstate)478757b5d87SAndrey V. Elsukov add_srcip6(ipfw_insn *cmd, char *av, int cblen, struct tidx *tstate)
479ead75a59SLuigi Rizzo {
480ead75a59SLuigi Rizzo
481757b5d87SAndrey V. Elsukov fill_ip6((ipfw_insn_ip6 *)cmd, av, cblen, tstate);
4827e00325dSAlexander V. Chernikov if (cmd->opcode == O_IP_DST_SET) /* set */
4837e00325dSAlexander V. Chernikov cmd->opcode = O_IP_SRC_SET;
4847e00325dSAlexander V. Chernikov else if (cmd->opcode == O_IP_DST_LOOKUP) /* table */
4857e00325dSAlexander V. Chernikov cmd->opcode = O_IP_SRC_LOOKUP;
4867e00325dSAlexander V. Chernikov else if (F_LEN(cmd) == 0) { /* any */
487ead75a59SLuigi Rizzo } else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) { /* "me" */
488ead75a59SLuigi Rizzo cmd->opcode = O_IP6_SRC_ME;
489ead75a59SLuigi Rizzo } else if (F_LEN(cmd) ==
490ead75a59SLuigi Rizzo (F_INSN_SIZE(struct in6_addr) + F_INSN_SIZE(ipfw_insn))) {
491ead75a59SLuigi Rizzo /* single IP, no mask*/
492ead75a59SLuigi Rizzo cmd->opcode = O_IP6_SRC;
493ead75a59SLuigi Rizzo } else { /* addr/mask opt */
494ead75a59SLuigi Rizzo cmd->opcode = O_IP6_SRC_MASK;
495ead75a59SLuigi Rizzo }
496ead75a59SLuigi Rizzo return cmd;
497ead75a59SLuigi Rizzo }
498ead75a59SLuigi Rizzo
499ead75a59SLuigi Rizzo ipfw_insn *
add_dstip6(ipfw_insn * cmd,char * av,int cblen,struct tidx * tstate)500757b5d87SAndrey V. Elsukov add_dstip6(ipfw_insn *cmd, char *av, int cblen, struct tidx *tstate)
501ead75a59SLuigi Rizzo {
502ead75a59SLuigi Rizzo
503757b5d87SAndrey V. Elsukov fill_ip6((ipfw_insn_ip6 *)cmd, av, cblen, tstate);
5047e00325dSAlexander V. Chernikov if (cmd->opcode == O_IP_DST_SET) /* set */
5057e00325dSAlexander V. Chernikov ;
5067e00325dSAlexander V. Chernikov else if (cmd->opcode == O_IP_DST_LOOKUP) /* table */
5077e00325dSAlexander V. Chernikov ;
5087e00325dSAlexander V. Chernikov else if (F_LEN(cmd) == 0) { /* any */
509ead75a59SLuigi Rizzo } else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) { /* "me" */
510ead75a59SLuigi Rizzo cmd->opcode = O_IP6_DST_ME;
511ead75a59SLuigi Rizzo } else if (F_LEN(cmd) ==
512ead75a59SLuigi Rizzo (F_INSN_SIZE(struct in6_addr) + F_INSN_SIZE(ipfw_insn))) {
513ead75a59SLuigi Rizzo /* single IP, no mask*/
514ead75a59SLuigi Rizzo cmd->opcode = O_IP6_DST;
515ead75a59SLuigi Rizzo } else { /* addr/mask opt */
516ead75a59SLuigi Rizzo cmd->opcode = O_IP6_DST_MASK;
517ead75a59SLuigi Rizzo }
518ead75a59SLuigi Rizzo return cmd;
519ead75a59SLuigi Rizzo }
520