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 * $FreeBSD$ 21ead75a59SLuigi Rizzo * 22ead75a59SLuigi Rizzo * ipv6 support 23ead75a59SLuigi Rizzo */ 24ead75a59SLuigi Rizzo 25ead75a59SLuigi Rizzo #include <sys/types.h> 26ead75a59SLuigi Rizzo #include <sys/socket.h> 27ead75a59SLuigi Rizzo 28ead75a59SLuigi Rizzo #include "ipfw2.h" 29ead75a59SLuigi Rizzo 30ead75a59SLuigi Rizzo #include <err.h> 31ead75a59SLuigi Rizzo #include <netdb.h> 32ead75a59SLuigi Rizzo #include <stdio.h> 33ead75a59SLuigi Rizzo #include <stdlib.h> 34ead75a59SLuigi Rizzo #include <string.h> 35ead75a59SLuigi Rizzo #include <sysexits.h> 36ead75a59SLuigi Rizzo 37ead75a59SLuigi Rizzo #include <net/if.h> 38ead75a59SLuigi Rizzo #include <netinet/in.h> 39ead75a59SLuigi Rizzo #include <netinet/in_systm.h> 40ead75a59SLuigi Rizzo #include <netinet/ip.h> 41ead75a59SLuigi Rizzo #include <netinet/icmp6.h> 42ead75a59SLuigi Rizzo #include <netinet/ip_fw.h> 43ead75a59SLuigi Rizzo #include <arpa/inet.h> 44ead75a59SLuigi Rizzo 45579ed7bdSAlexander V. Chernikov #define CHECK_LENGTH(v, len) do { \ 46579ed7bdSAlexander V. Chernikov if ((v) < (len)) \ 47579ed7bdSAlexander V. Chernikov errx(EX_DATAERR, "Rule too long"); \ 48579ed7bdSAlexander V. Chernikov } while (0) 49579ed7bdSAlexander V. Chernikov 50ead75a59SLuigi Rizzo static struct _s_x icmp6codes[] = { 51ead75a59SLuigi Rizzo { "no-route", ICMP6_DST_UNREACH_NOROUTE }, 52ead75a59SLuigi Rizzo { "admin-prohib", ICMP6_DST_UNREACH_ADMIN }, 53ead75a59SLuigi Rizzo { "address", ICMP6_DST_UNREACH_ADDR }, 54ead75a59SLuigi Rizzo { "port", ICMP6_DST_UNREACH_NOPORT }, 55ead75a59SLuigi Rizzo { NULL, 0 } 56ead75a59SLuigi Rizzo }; 57ead75a59SLuigi Rizzo 58ead75a59SLuigi Rizzo void 59ead75a59SLuigi Rizzo fill_unreach6_code(u_short *codep, char *str) 60ead75a59SLuigi Rizzo { 61ead75a59SLuigi Rizzo int val; 62ead75a59SLuigi Rizzo char *s; 63ead75a59SLuigi Rizzo 64ead75a59SLuigi Rizzo val = strtoul(str, &s, 0); 65ead75a59SLuigi Rizzo if (s == str || *s != '\0' || val >= 0x100) 66ead75a59SLuigi Rizzo val = match_token(icmp6codes, str); 67ead75a59SLuigi Rizzo if (val < 0) 68ead75a59SLuigi Rizzo errx(EX_DATAERR, "unknown ICMPv6 unreachable code ``%s''", str); 69ead75a59SLuigi Rizzo *codep = val; 70ead75a59SLuigi Rizzo return; 71ead75a59SLuigi Rizzo } 72ead75a59SLuigi Rizzo 73ead75a59SLuigi Rizzo void 747b34dbe4SAndrey V. Elsukov print_unreach6_code(struct buf_pr *bp, uint16_t code) 75ead75a59SLuigi Rizzo { 76ead75a59SLuigi Rizzo char const *s = match_value(icmp6codes, code); 77ead75a59SLuigi Rizzo 78ead75a59SLuigi Rizzo if (s != NULL) 797b34dbe4SAndrey V. Elsukov bprintf(bp, "unreach6 %s", s); 80ead75a59SLuigi Rizzo else 817b34dbe4SAndrey V. Elsukov bprintf(bp, "unreach6 %u", code); 82ead75a59SLuigi Rizzo } 83ead75a59SLuigi Rizzo 84ead75a59SLuigi Rizzo /* 85ead75a59SLuigi Rizzo * Print the ip address contained in a command. 86ead75a59SLuigi Rizzo */ 87ead75a59SLuigi Rizzo void 88*bd32e335SAndrey V. Elsukov print_ip6(struct buf_pr *bp, ipfw_insn_ip6 *cmd) 89ead75a59SLuigi Rizzo { 90ead75a59SLuigi Rizzo struct hostent *he = NULL; 91ead75a59SLuigi Rizzo int len = F_LEN((ipfw_insn *) cmd) - 1; 92ead75a59SLuigi Rizzo struct in6_addr *a = &(cmd->addr6); 93ead75a59SLuigi Rizzo char trad[255]; 94ead75a59SLuigi Rizzo 95ead75a59SLuigi Rizzo if (cmd->o.opcode == O_IP6_SRC_ME || cmd->o.opcode == O_IP6_DST_ME) { 96912430f6SAlexander V. Chernikov bprintf(bp, " me6"); 97ead75a59SLuigi Rizzo return; 98ead75a59SLuigi Rizzo } 99ead75a59SLuigi Rizzo if (cmd->o.opcode == O_IP6) { 100912430f6SAlexander V. Chernikov bprintf(bp, " ip6"); 101ead75a59SLuigi Rizzo return; 102ead75a59SLuigi Rizzo } 103ead75a59SLuigi Rizzo 104ead75a59SLuigi Rizzo /* 105ead75a59SLuigi Rizzo * len == 4 indicates a single IP, whereas lists of 1 or more 106ead75a59SLuigi Rizzo * addr/mask pairs have len = (2n+1). We convert len to n so we 107ead75a59SLuigi Rizzo * use that to count the number of entries. 108ead75a59SLuigi Rizzo */ 109*bd32e335SAndrey V. Elsukov bprintf(bp, " "); 110ead75a59SLuigi Rizzo for (len = len / 4; len > 0; len -= 2, a += 2) { 111ead75a59SLuigi Rizzo int mb = /* mask length */ 112ead75a59SLuigi Rizzo (cmd->o.opcode == O_IP6_SRC || cmd->o.opcode == O_IP6_DST) ? 113ead75a59SLuigi Rizzo 128 : contigmask((uint8_t *)&(a[1]), 128); 114ead75a59SLuigi Rizzo 115ead75a59SLuigi Rizzo if (mb == 128 && co.do_resolv) 116ead75a59SLuigi Rizzo he = gethostbyaddr((char *)a, sizeof(*a), AF_INET6); 117ead75a59SLuigi Rizzo if (he != NULL) /* resolved to name */ 118912430f6SAlexander V. Chernikov bprintf(bp, "%s", he->h_name); 119ead75a59SLuigi Rizzo else if (mb == 0) /* any */ 120912430f6SAlexander V. Chernikov bprintf(bp, "any"); 121ead75a59SLuigi Rizzo else { /* numeric IP followed by some kind of mask */ 122ead75a59SLuigi Rizzo if (inet_ntop(AF_INET6, a, trad, sizeof( trad ) ) == NULL) 123912430f6SAlexander V. Chernikov bprintf(bp, "Error ntop in print_ip6\n"); 124912430f6SAlexander V. Chernikov bprintf(bp, "%s", trad ); 12523b93085SAndrey V. Elsukov if (mb < 0) /* mask not contiguous */ 12623b93085SAndrey V. Elsukov bprintf(bp, "/%s", 127ead75a59SLuigi Rizzo inet_ntop(AF_INET6, &a[1], trad, sizeof(trad))); 128ead75a59SLuigi Rizzo else if (mb < 128) 129912430f6SAlexander V. Chernikov bprintf(bp, "/%d", mb); 130ead75a59SLuigi Rizzo } 131ead75a59SLuigi Rizzo if (len > 2) 132912430f6SAlexander V. Chernikov bprintf(bp, ","); 133ead75a59SLuigi Rizzo } 134ead75a59SLuigi Rizzo } 135ead75a59SLuigi Rizzo 136ead75a59SLuigi Rizzo void 137579ed7bdSAlexander V. Chernikov fill_icmp6types(ipfw_insn_icmp6 *cmd, char *av, int cblen) 138ead75a59SLuigi Rizzo { 139ead75a59SLuigi Rizzo uint8_t type; 140ead75a59SLuigi Rizzo 141579ed7bdSAlexander V. Chernikov CHECK_LENGTH(cblen, F_INSN_SIZE(ipfw_insn_icmp6)); 142579ed7bdSAlexander V. Chernikov 143ead75a59SLuigi Rizzo bzero(cmd, sizeof(*cmd)); 144ead75a59SLuigi Rizzo while (*av) { 145ead75a59SLuigi Rizzo if (*av == ',') 146ead75a59SLuigi Rizzo av++; 147ead75a59SLuigi Rizzo type = strtoul(av, &av, 0); 148ead75a59SLuigi Rizzo if (*av != ',' && *av != '\0') 149ead75a59SLuigi Rizzo errx(EX_DATAERR, "invalid ICMP6 type"); 150ead75a59SLuigi Rizzo /* 151ead75a59SLuigi Rizzo * XXX: shouldn't this be 0xFF? I can't see any reason why 152ead75a59SLuigi Rizzo * we shouldn't be able to filter all possiable values 153ead75a59SLuigi Rizzo * regardless of the ability of the rest of the kernel to do 154ead75a59SLuigi Rizzo * anything useful with them. 155ead75a59SLuigi Rizzo */ 156ead75a59SLuigi Rizzo if (type > ICMP6_MAXTYPE) 157ead75a59SLuigi Rizzo errx(EX_DATAERR, "ICMP6 type out of range"); 158ead75a59SLuigi Rizzo cmd->d[type / 32] |= ( 1 << (type % 32)); 159ead75a59SLuigi Rizzo } 160ead75a59SLuigi Rizzo cmd->o.opcode = O_ICMP6TYPE; 161ead75a59SLuigi Rizzo cmd->o.len |= F_INSN_SIZE(ipfw_insn_icmp6); 162ead75a59SLuigi Rizzo } 163ead75a59SLuigi Rizzo 164ead75a59SLuigi Rizzo 165ead75a59SLuigi Rizzo void 166912430f6SAlexander V. Chernikov print_icmp6types(struct buf_pr *bp, ipfw_insn_u32 *cmd) 167ead75a59SLuigi Rizzo { 168ead75a59SLuigi Rizzo int i, j; 169ead75a59SLuigi Rizzo char sep= ' '; 170ead75a59SLuigi Rizzo 171912430f6SAlexander V. Chernikov bprintf(bp, " ip6 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 182912430f6SAlexander V. Chernikov print_flow6id(struct buf_pr *bp, 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 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 217ead75a59SLuigi Rizzo while(s) { 218ead75a59SLuigi Rizzo av = strsep( &s, ",") ; 219ead75a59SLuigi Rizzo tok = match_token(ext6hdrcodes, av); 220ead75a59SLuigi Rizzo switch (tok) { 221ead75a59SLuigi Rizzo case EXT_FRAGMENT: 222ead75a59SLuigi Rizzo cmd->arg1 |= EXT_FRAGMENT; 223ead75a59SLuigi Rizzo break; 224ead75a59SLuigi Rizzo 225ead75a59SLuigi Rizzo case EXT_HOPOPTS: 226ead75a59SLuigi Rizzo cmd->arg1 |= EXT_HOPOPTS; 227ead75a59SLuigi Rizzo break; 228ead75a59SLuigi Rizzo 229ead75a59SLuigi Rizzo case EXT_ROUTING: 230ead75a59SLuigi Rizzo cmd->arg1 |= EXT_ROUTING; 231ead75a59SLuigi Rizzo break; 232ead75a59SLuigi Rizzo 233ead75a59SLuigi Rizzo case EXT_DSTOPTS: 234ead75a59SLuigi Rizzo cmd->arg1 |= EXT_DSTOPTS; 235ead75a59SLuigi Rizzo break; 236ead75a59SLuigi Rizzo 237ead75a59SLuigi Rizzo case EXT_AH: 238ead75a59SLuigi Rizzo cmd->arg1 |= EXT_AH; 239ead75a59SLuigi Rizzo break; 240ead75a59SLuigi Rizzo 241ead75a59SLuigi Rizzo case EXT_ESP: 242ead75a59SLuigi Rizzo cmd->arg1 |= EXT_ESP; 243ead75a59SLuigi Rizzo break; 244ead75a59SLuigi Rizzo 245ead75a59SLuigi Rizzo case EXT_RTHDR0: 246ead75a59SLuigi Rizzo cmd->arg1 |= EXT_RTHDR0; 247ead75a59SLuigi Rizzo break; 248ead75a59SLuigi Rizzo 249ead75a59SLuigi Rizzo case EXT_RTHDR2: 250ead75a59SLuigi Rizzo cmd->arg1 |= EXT_RTHDR2; 251ead75a59SLuigi Rizzo break; 252ead75a59SLuigi Rizzo 253ead75a59SLuigi Rizzo default: 254ead75a59SLuigi Rizzo errx( EX_DATAERR, "invalid option for ipv6 exten header" ); 255ead75a59SLuigi Rizzo break; 256ead75a59SLuigi Rizzo } 257ead75a59SLuigi Rizzo } 258ead75a59SLuigi Rizzo if (cmd->arg1 == 0 ) 259ead75a59SLuigi Rizzo return 0; 260ead75a59SLuigi Rizzo cmd->opcode = O_EXT_HDR; 261ead75a59SLuigi Rizzo cmd->len |= F_INSN_SIZE( ipfw_insn ); 262ead75a59SLuigi Rizzo return 1; 263ead75a59SLuigi Rizzo } 264ead75a59SLuigi Rizzo 265ead75a59SLuigi Rizzo void 266912430f6SAlexander V. Chernikov print_ext6hdr(struct buf_pr *bp, ipfw_insn *cmd ) 267ead75a59SLuigi Rizzo { 268ead75a59SLuigi Rizzo char sep = ' '; 269ead75a59SLuigi Rizzo 270912430f6SAlexander V. Chernikov bprintf(bp, " extension header:"); 271ead75a59SLuigi Rizzo if (cmd->arg1 & EXT_FRAGMENT ) { 272912430f6SAlexander V. Chernikov bprintf(bp, "%cfragmentation", sep); 273ead75a59SLuigi Rizzo sep = ','; 274ead75a59SLuigi Rizzo } 275ead75a59SLuigi Rizzo if (cmd->arg1 & EXT_HOPOPTS ) { 276912430f6SAlexander V. Chernikov bprintf(bp, "%chop options", sep); 277ead75a59SLuigi Rizzo sep = ','; 278ead75a59SLuigi Rizzo } 279ead75a59SLuigi Rizzo if (cmd->arg1 & EXT_ROUTING ) { 280912430f6SAlexander V. Chernikov bprintf(bp, "%crouting options", sep); 281ead75a59SLuigi Rizzo sep = ','; 282ead75a59SLuigi Rizzo } 283ead75a59SLuigi Rizzo if (cmd->arg1 & EXT_RTHDR0 ) { 284912430f6SAlexander V. Chernikov bprintf(bp, "%crthdr0", sep); 285ead75a59SLuigi Rizzo sep = ','; 286ead75a59SLuigi Rizzo } 287ead75a59SLuigi Rizzo if (cmd->arg1 & EXT_RTHDR2 ) { 288912430f6SAlexander V. Chernikov bprintf(bp, "%crthdr2", sep); 289ead75a59SLuigi Rizzo sep = ','; 290ead75a59SLuigi Rizzo } 291ead75a59SLuigi Rizzo if (cmd->arg1 & EXT_DSTOPTS ) { 292912430f6SAlexander V. Chernikov bprintf(bp, "%cdestination options", sep); 293ead75a59SLuigi Rizzo sep = ','; 294ead75a59SLuigi Rizzo } 295ead75a59SLuigi Rizzo if (cmd->arg1 & EXT_AH ) { 296912430f6SAlexander V. Chernikov bprintf(bp, "%cauthentication header", sep); 297ead75a59SLuigi Rizzo sep = ','; 298ead75a59SLuigi Rizzo } 299ead75a59SLuigi Rizzo if (cmd->arg1 & EXT_ESP ) { 300912430f6SAlexander V. Chernikov bprintf(bp, "%cencapsulated security payload", sep); 301ead75a59SLuigi Rizzo } 302ead75a59SLuigi Rizzo } 303ead75a59SLuigi Rizzo 304ead75a59SLuigi Rizzo /* Try to find ipv6 address by hostname */ 305ead75a59SLuigi Rizzo static int 306ead75a59SLuigi Rizzo lookup_host6 (char *host, struct in6_addr *ip6addr) 307ead75a59SLuigi Rizzo { 308ead75a59SLuigi Rizzo struct hostent *he; 309ead75a59SLuigi Rizzo 310ead75a59SLuigi Rizzo if (!inet_pton(AF_INET6, host, ip6addr)) { 311ead75a59SLuigi Rizzo if ((he = gethostbyname2(host, AF_INET6)) == NULL) 312ead75a59SLuigi Rizzo return(-1); 313ead75a59SLuigi Rizzo memcpy(ip6addr, he->h_addr_list[0], sizeof( struct in6_addr)); 314ead75a59SLuigi Rizzo } 315ead75a59SLuigi Rizzo return(0); 316ead75a59SLuigi Rizzo } 317ead75a59SLuigi Rizzo 318ead75a59SLuigi Rizzo 319ead75a59SLuigi Rizzo /* 320ead75a59SLuigi Rizzo * fill the addr and mask fields in the instruction as appropriate from av. 321ead75a59SLuigi Rizzo * Update length as appropriate. 322ead75a59SLuigi Rizzo * The following formats are allowed: 323ead75a59SLuigi Rizzo * any matches any IP6. Actually returns an empty instruction. 324ead75a59SLuigi Rizzo * me returns O_IP6_*_ME 325ead75a59SLuigi Rizzo * 326b68ac800SPedro F. Giffuni * 03f1::234:123:0342 single IP6 address 32723b93085SAndrey V. Elsukov * 03f1::234:123:0342/24 address/masklen 32823b93085SAndrey V. Elsukov * 03f1::234:123:0342/ffff::ffff:ffff address/mask 329ead75a59SLuigi Rizzo * 03f1::234:123:0342/24,03f1::234:123:0343/ List of address 330ead75a59SLuigi Rizzo * 331ead75a59SLuigi Rizzo * Set of address (as in ipv6) not supported because ipv6 address 332ead75a59SLuigi Rizzo * are typically random past the initial prefix. 333ead75a59SLuigi Rizzo * Return 1 on success, 0 on failure. 334ead75a59SLuigi Rizzo */ 335ead75a59SLuigi Rizzo static int 336757b5d87SAndrey V. Elsukov fill_ip6(ipfw_insn_ip6 *cmd, char *av, int cblen, struct tidx *tstate) 337ead75a59SLuigi Rizzo { 338ead75a59SLuigi Rizzo int len = 0; 339ead75a59SLuigi Rizzo struct in6_addr *d = &(cmd->addr6); 340247cea8fSMarius Strobl char *oav; 341ead75a59SLuigi Rizzo /* 342ead75a59SLuigi Rizzo * Needed for multiple address. 343ead75a59SLuigi Rizzo * Note d[1] points to struct in6_add r mask6 of cmd 344ead75a59SLuigi Rizzo */ 345ead75a59SLuigi Rizzo 346ead75a59SLuigi Rizzo cmd->o.len &= ~F_LEN_MASK; /* zero len */ 347ead75a59SLuigi Rizzo 348ead75a59SLuigi Rizzo if (strcmp(av, "any") == 0) 349ead75a59SLuigi Rizzo return (1); 350ead75a59SLuigi Rizzo 351ead75a59SLuigi Rizzo 352ead75a59SLuigi Rizzo if (strcmp(av, "me") == 0) { /* Set the data for "me" opt*/ 353ead75a59SLuigi Rizzo cmd->o.len |= F_INSN_SIZE(ipfw_insn); 354ead75a59SLuigi Rizzo return (1); 355ead75a59SLuigi Rizzo } 356ead75a59SLuigi Rizzo 357ead75a59SLuigi Rizzo if (strcmp(av, "me6") == 0) { /* Set the data for "me" opt*/ 358ead75a59SLuigi Rizzo cmd->o.len |= F_INSN_SIZE(ipfw_insn); 359ead75a59SLuigi Rizzo return (1); 360ead75a59SLuigi Rizzo } 361ead75a59SLuigi Rizzo 3627e00325dSAlexander V. Chernikov if (strncmp(av, "table(", 6) == 0) { 363757b5d87SAndrey V. Elsukov fill_table(&cmd->o, av, O_IP_DST_LOOKUP, tstate); 3647e00325dSAlexander V. Chernikov return (1); 3657e00325dSAlexander V. Chernikov } 3667e00325dSAlexander V. Chernikov 367247cea8fSMarius Strobl oav = av = strdup(av); 368ead75a59SLuigi Rizzo while (av) { 369ead75a59SLuigi Rizzo /* 370ead75a59SLuigi Rizzo * After the address we can have '/' indicating a mask, 371ead75a59SLuigi Rizzo * or ',' indicating another address follows. 372ead75a59SLuigi Rizzo */ 373ead75a59SLuigi Rizzo 37423b93085SAndrey V. Elsukov char *p, *q; 375ead75a59SLuigi Rizzo int masklen; 376ead75a59SLuigi Rizzo char md = '\0'; 377ead75a59SLuigi Rizzo 378579ed7bdSAlexander V. Chernikov CHECK_LENGTH(cblen, 1 + len + 2 * F_INSN_SIZE(struct in6_addr)); 379579ed7bdSAlexander V. Chernikov 38023b93085SAndrey V. Elsukov if ((q = strchr(av, ',')) ) { 38123b93085SAndrey V. Elsukov *q = '\0'; 38223b93085SAndrey V. Elsukov q++; 38323b93085SAndrey V. Elsukov } 38423b93085SAndrey V. Elsukov 38523b93085SAndrey V. Elsukov if ((p = strchr(av, '/')) ) { 386ead75a59SLuigi Rizzo md = *p; /* save the separator */ 387ead75a59SLuigi Rizzo *p = '\0'; /* terminate address string */ 388ead75a59SLuigi Rizzo p++; /* and skip past it */ 389ead75a59SLuigi Rizzo } 390ead75a59SLuigi Rizzo /* now p points to NULL, mask or next entry */ 391ead75a59SLuigi Rizzo 392ead75a59SLuigi Rizzo /* lookup stores address in *d as a side effect */ 393ead75a59SLuigi Rizzo if (lookup_host6(av, d) != 0) { 394ead75a59SLuigi Rizzo /* XXX: failed. Free memory and go */ 395ead75a59SLuigi Rizzo errx(EX_DATAERR, "bad address \"%s\"", av); 396ead75a59SLuigi Rizzo } 397ead75a59SLuigi Rizzo /* next, look at the mask, if any */ 39823b93085SAndrey V. Elsukov if (md == '/' && strchr(p, ':')) { 39923b93085SAndrey V. Elsukov if (!inet_pton(AF_INET6, p, &d[1])) 40023b93085SAndrey V. Elsukov errx(EX_DATAERR, "bad mask \"%s\"", p); 40123b93085SAndrey V. Elsukov 40223b93085SAndrey V. Elsukov masklen = contigmask((uint8_t *)&(d[1]), 128); 40323b93085SAndrey V. Elsukov } else { 404ead75a59SLuigi Rizzo masklen = (md == '/') ? atoi(p) : 128; 405ead75a59SLuigi Rizzo if (masklen > 128 || masklen < 0) 406ead75a59SLuigi Rizzo errx(EX_DATAERR, "bad width \"%s\''", p); 407ead75a59SLuigi Rizzo else 408ead75a59SLuigi Rizzo n2mask(&d[1], masklen); 40923b93085SAndrey V. Elsukov } 410ead75a59SLuigi Rizzo 411ead75a59SLuigi Rizzo APPLY_MASK(d, &d[1]) /* mask base address with mask */ 412ead75a59SLuigi Rizzo 41323b93085SAndrey V. Elsukov av = q; 414ead75a59SLuigi Rizzo 415ead75a59SLuigi Rizzo /* Check this entry */ 416ead75a59SLuigi Rizzo if (masklen == 0) { 417ead75a59SLuigi Rizzo /* 418ead75a59SLuigi Rizzo * 'any' turns the entire list into a NOP. 419ead75a59SLuigi Rizzo * 'not any' never matches, so it is removed from the 420ead75a59SLuigi Rizzo * list unless it is the only item, in which case we 421ead75a59SLuigi Rizzo * report an error. 422ead75a59SLuigi Rizzo */ 423ead75a59SLuigi Rizzo if (cmd->o.len & F_NOT && av == NULL && len == 0) 424ead75a59SLuigi Rizzo errx(EX_DATAERR, "not any never matches"); 425ead75a59SLuigi Rizzo continue; 426ead75a59SLuigi Rizzo } 427ead75a59SLuigi Rizzo 428ead75a59SLuigi Rizzo /* 429ead75a59SLuigi Rizzo * A single IP can be stored alone 430ead75a59SLuigi Rizzo */ 431ead75a59SLuigi Rizzo if (masklen == 128 && av == NULL && len == 0) { 432ead75a59SLuigi Rizzo len = F_INSN_SIZE(struct in6_addr); 433ead75a59SLuigi Rizzo break; 434ead75a59SLuigi Rizzo } 435ead75a59SLuigi Rizzo 436ead75a59SLuigi Rizzo /* Update length and pointer to arguments */ 437ead75a59SLuigi Rizzo len += F_INSN_SIZE(struct in6_addr)*2; 438ead75a59SLuigi Rizzo d += 2; 439ead75a59SLuigi Rizzo } /* end while */ 440ead75a59SLuigi Rizzo 441ead75a59SLuigi Rizzo /* 442ead75a59SLuigi Rizzo * Total length of the command, remember that 1 is the size of 443ead75a59SLuigi Rizzo * the base command. 444ead75a59SLuigi Rizzo */ 445ead75a59SLuigi Rizzo if (len + 1 > F_LEN_MASK) 446ead75a59SLuigi Rizzo errx(EX_DATAERR, "address list too long"); 447ead75a59SLuigi Rizzo cmd->o.len |= len+1; 448247cea8fSMarius Strobl free(oav); 449ead75a59SLuigi Rizzo return (1); 450ead75a59SLuigi Rizzo } 451ead75a59SLuigi Rizzo 452ead75a59SLuigi Rizzo /* 453ead75a59SLuigi Rizzo * fills command for ipv6 flow-id filtering 454ead75a59SLuigi Rizzo * note that the 20 bit flow number is stored in a array of u_int32_t 455ead75a59SLuigi Rizzo * it's supported lists of flow-id, so in the o.arg1 we store how many 456ead75a59SLuigi Rizzo * additional flow-id we want to filter, the basic is 1 457ead75a59SLuigi Rizzo */ 458ead75a59SLuigi Rizzo void 459579ed7bdSAlexander V. Chernikov fill_flow6( ipfw_insn_u32 *cmd, char *av, int cblen) 460ead75a59SLuigi Rizzo { 461ead75a59SLuigi Rizzo u_int32_t type; /* Current flow number */ 462ead75a59SLuigi Rizzo u_int16_t nflow = 0; /* Current flow index */ 463ead75a59SLuigi Rizzo char *s = av; 464ead75a59SLuigi Rizzo cmd->d[0] = 0; /* Initializing the base number*/ 465ead75a59SLuigi Rizzo 466ead75a59SLuigi Rizzo while (s) { 467579ed7bdSAlexander V. Chernikov CHECK_LENGTH(cblen, F_INSN_SIZE(ipfw_insn_u32) + nflow + 1); 468579ed7bdSAlexander V. Chernikov 469ead75a59SLuigi Rizzo av = strsep( &s, ",") ; 470ead75a59SLuigi Rizzo type = strtoul(av, &av, 0); 471ead75a59SLuigi Rizzo if (*av != ',' && *av != '\0') 472ead75a59SLuigi Rizzo errx(EX_DATAERR, "invalid ipv6 flow number %s", av); 473ead75a59SLuigi Rizzo if (type > 0xfffff) 474ead75a59SLuigi Rizzo errx(EX_DATAERR, "flow number out of range %s", av); 475ead75a59SLuigi Rizzo cmd->d[nflow] |= type; 476ead75a59SLuigi Rizzo nflow++; 477ead75a59SLuigi Rizzo } 478ead75a59SLuigi Rizzo if( nflow > 0 ) { 479ead75a59SLuigi Rizzo cmd->o.opcode = O_FLOW6ID; 480ead75a59SLuigi Rizzo cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32) + nflow; 481ead75a59SLuigi Rizzo cmd->o.arg1 = nflow; 482ead75a59SLuigi Rizzo } 483ead75a59SLuigi Rizzo else { 484ead75a59SLuigi Rizzo errx(EX_DATAERR, "invalid ipv6 flow number %s", av); 485ead75a59SLuigi Rizzo } 486ead75a59SLuigi Rizzo } 487ead75a59SLuigi Rizzo 488ead75a59SLuigi Rizzo ipfw_insn * 489757b5d87SAndrey V. Elsukov add_srcip6(ipfw_insn *cmd, char *av, int cblen, struct tidx *tstate) 490ead75a59SLuigi Rizzo { 491ead75a59SLuigi Rizzo 492757b5d87SAndrey V. Elsukov fill_ip6((ipfw_insn_ip6 *)cmd, av, cblen, tstate); 4937e00325dSAlexander V. Chernikov if (cmd->opcode == O_IP_DST_SET) /* set */ 4947e00325dSAlexander V. Chernikov cmd->opcode = O_IP_SRC_SET; 4957e00325dSAlexander V. Chernikov else if (cmd->opcode == O_IP_DST_LOOKUP) /* table */ 4967e00325dSAlexander V. Chernikov cmd->opcode = O_IP_SRC_LOOKUP; 4977e00325dSAlexander V. Chernikov else if (F_LEN(cmd) == 0) { /* any */ 498ead75a59SLuigi Rizzo } else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) { /* "me" */ 499ead75a59SLuigi Rizzo cmd->opcode = O_IP6_SRC_ME; 500ead75a59SLuigi Rizzo } else if (F_LEN(cmd) == 501ead75a59SLuigi Rizzo (F_INSN_SIZE(struct in6_addr) + F_INSN_SIZE(ipfw_insn))) { 502ead75a59SLuigi Rizzo /* single IP, no mask*/ 503ead75a59SLuigi Rizzo cmd->opcode = O_IP6_SRC; 504ead75a59SLuigi Rizzo } else { /* addr/mask opt */ 505ead75a59SLuigi Rizzo cmd->opcode = O_IP6_SRC_MASK; 506ead75a59SLuigi Rizzo } 507ead75a59SLuigi Rizzo return cmd; 508ead75a59SLuigi Rizzo } 509ead75a59SLuigi Rizzo 510ead75a59SLuigi Rizzo ipfw_insn * 511757b5d87SAndrey V. Elsukov add_dstip6(ipfw_insn *cmd, char *av, int cblen, struct tidx *tstate) 512ead75a59SLuigi Rizzo { 513ead75a59SLuigi Rizzo 514757b5d87SAndrey V. Elsukov fill_ip6((ipfw_insn_ip6 *)cmd, av, cblen, tstate); 5157e00325dSAlexander V. Chernikov if (cmd->opcode == O_IP_DST_SET) /* set */ 5167e00325dSAlexander V. Chernikov ; 5177e00325dSAlexander V. Chernikov else if (cmd->opcode == O_IP_DST_LOOKUP) /* table */ 5187e00325dSAlexander V. Chernikov ; 5197e00325dSAlexander V. Chernikov else if (F_LEN(cmd) == 0) { /* any */ 520ead75a59SLuigi Rizzo } else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) { /* "me" */ 521ead75a59SLuigi Rizzo cmd->opcode = O_IP6_DST_ME; 522ead75a59SLuigi Rizzo } else if (F_LEN(cmd) == 523ead75a59SLuigi Rizzo (F_INSN_SIZE(struct in6_addr) + F_INSN_SIZE(ipfw_insn))) { 524ead75a59SLuigi Rizzo /* single IP, no mask*/ 525ead75a59SLuigi Rizzo cmd->opcode = O_IP6_DST; 526ead75a59SLuigi Rizzo } else { /* addr/mask opt */ 527ead75a59SLuigi Rizzo cmd->opcode = O_IP6_DST_MASK; 528ead75a59SLuigi Rizzo } 529ead75a59SLuigi Rizzo return cmd; 530ead75a59SLuigi Rizzo } 531