1ead75a59SLuigi Rizzo /* 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 74ead75a59SLuigi Rizzo print_unreach6_code(uint16_t code) 75ead75a59SLuigi Rizzo { 76ead75a59SLuigi Rizzo char const *s = match_value(icmp6codes, code); 77ead75a59SLuigi Rizzo 78ead75a59SLuigi Rizzo if (s != NULL) 79ead75a59SLuigi Rizzo printf("unreach6 %s", s); 80ead75a59SLuigi Rizzo else 81ead75a59SLuigi Rizzo printf("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*912430f6SAlexander V. Chernikov print_ip6(struct buf_pr *bp, ipfw_insn_ip6 *cmd, char const *s) 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 95*912430f6SAlexander V. Chernikov bprintf(bp, "%s%s ", cmd->o.len & F_NOT ? " not": "", s); 96ead75a59SLuigi Rizzo 97ead75a59SLuigi Rizzo if (cmd->o.opcode == O_IP6_SRC_ME || cmd->o.opcode == O_IP6_DST_ME) { 98*912430f6SAlexander V. Chernikov bprintf(bp, "me6"); 99ead75a59SLuigi Rizzo return; 100ead75a59SLuigi Rizzo } 101ead75a59SLuigi Rizzo if (cmd->o.opcode == O_IP6) { 102*912430f6SAlexander V. Chernikov bprintf(bp, " ip6"); 103ead75a59SLuigi Rizzo return; 104ead75a59SLuigi Rizzo } 105ead75a59SLuigi Rizzo 106ead75a59SLuigi Rizzo /* 107ead75a59SLuigi Rizzo * len == 4 indicates a single IP, whereas lists of 1 or more 108ead75a59SLuigi Rizzo * addr/mask pairs have len = (2n+1). We convert len to n so we 109ead75a59SLuigi Rizzo * use that to count the number of entries. 110ead75a59SLuigi Rizzo */ 111ead75a59SLuigi Rizzo 112ead75a59SLuigi Rizzo for (len = len / 4; len > 0; len -= 2, a += 2) { 113ead75a59SLuigi Rizzo int mb = /* mask length */ 114ead75a59SLuigi Rizzo (cmd->o.opcode == O_IP6_SRC || cmd->o.opcode == O_IP6_DST) ? 115ead75a59SLuigi Rizzo 128 : contigmask((uint8_t *)&(a[1]), 128); 116ead75a59SLuigi Rizzo 117ead75a59SLuigi Rizzo if (mb == 128 && co.do_resolv) 118ead75a59SLuigi Rizzo he = gethostbyaddr((char *)a, sizeof(*a), AF_INET6); 119ead75a59SLuigi Rizzo if (he != NULL) /* resolved to name */ 120*912430f6SAlexander V. Chernikov bprintf(bp, "%s", he->h_name); 121ead75a59SLuigi Rizzo else if (mb == 0) /* any */ 122*912430f6SAlexander V. Chernikov bprintf(bp, "any"); 123ead75a59SLuigi Rizzo else { /* numeric IP followed by some kind of mask */ 124ead75a59SLuigi Rizzo if (inet_ntop(AF_INET6, a, trad, sizeof( trad ) ) == NULL) 125*912430f6SAlexander V. Chernikov bprintf(bp, "Error ntop in print_ip6\n"); 126*912430f6SAlexander V. Chernikov bprintf(bp, "%s", trad ); 127ead75a59SLuigi Rizzo if (mb < 0) /* XXX not really legal... */ 128*912430f6SAlexander V. Chernikov bprintf(bp, ":%s", 129ead75a59SLuigi Rizzo inet_ntop(AF_INET6, &a[1], trad, sizeof(trad))); 130ead75a59SLuigi Rizzo else if (mb < 128) 131*912430f6SAlexander V. Chernikov bprintf(bp, "/%d", mb); 132ead75a59SLuigi Rizzo } 133ead75a59SLuigi Rizzo if (len > 2) 134*912430f6SAlexander V. Chernikov bprintf(bp, ","); 135ead75a59SLuigi Rizzo } 136ead75a59SLuigi Rizzo } 137ead75a59SLuigi Rizzo 138ead75a59SLuigi Rizzo void 139579ed7bdSAlexander V. Chernikov fill_icmp6types(ipfw_insn_icmp6 *cmd, char *av, int cblen) 140ead75a59SLuigi Rizzo { 141ead75a59SLuigi Rizzo uint8_t type; 142ead75a59SLuigi Rizzo 143579ed7bdSAlexander V. Chernikov CHECK_LENGTH(cblen, F_INSN_SIZE(ipfw_insn_icmp6)); 144579ed7bdSAlexander V. Chernikov 145ead75a59SLuigi Rizzo bzero(cmd, sizeof(*cmd)); 146ead75a59SLuigi Rizzo while (*av) { 147ead75a59SLuigi Rizzo if (*av == ',') 148ead75a59SLuigi Rizzo av++; 149ead75a59SLuigi Rizzo type = strtoul(av, &av, 0); 150ead75a59SLuigi Rizzo if (*av != ',' && *av != '\0') 151ead75a59SLuigi Rizzo errx(EX_DATAERR, "invalid ICMP6 type"); 152ead75a59SLuigi Rizzo /* 153ead75a59SLuigi Rizzo * XXX: shouldn't this be 0xFF? I can't see any reason why 154ead75a59SLuigi Rizzo * we shouldn't be able to filter all possiable values 155ead75a59SLuigi Rizzo * regardless of the ability of the rest of the kernel to do 156ead75a59SLuigi Rizzo * anything useful with them. 157ead75a59SLuigi Rizzo */ 158ead75a59SLuigi Rizzo if (type > ICMP6_MAXTYPE) 159ead75a59SLuigi Rizzo errx(EX_DATAERR, "ICMP6 type out of range"); 160ead75a59SLuigi Rizzo cmd->d[type / 32] |= ( 1 << (type % 32)); 161ead75a59SLuigi Rizzo } 162ead75a59SLuigi Rizzo cmd->o.opcode = O_ICMP6TYPE; 163ead75a59SLuigi Rizzo cmd->o.len |= F_INSN_SIZE(ipfw_insn_icmp6); 164ead75a59SLuigi Rizzo } 165ead75a59SLuigi Rizzo 166ead75a59SLuigi Rizzo 167ead75a59SLuigi Rizzo void 168*912430f6SAlexander V. Chernikov print_icmp6types(struct buf_pr *bp, ipfw_insn_u32 *cmd) 169ead75a59SLuigi Rizzo { 170ead75a59SLuigi Rizzo int i, j; 171ead75a59SLuigi Rizzo char sep= ' '; 172ead75a59SLuigi Rizzo 173*912430f6SAlexander V. Chernikov bprintf(bp, " ip6 icmp6types"); 174ead75a59SLuigi Rizzo for (i = 0; i < 7; i++) 175ead75a59SLuigi Rizzo for (j=0; j < 32; ++j) { 176ead75a59SLuigi Rizzo if ( (cmd->d[i] & (1 << (j))) == 0) 177ead75a59SLuigi Rizzo continue; 178*912430f6SAlexander V. Chernikov bprintf(bp, "%c%d", sep, (i*32 + j)); 179ead75a59SLuigi Rizzo sep = ','; 180ead75a59SLuigi Rizzo } 181ead75a59SLuigi Rizzo } 182ead75a59SLuigi Rizzo 183ead75a59SLuigi Rizzo void 184*912430f6SAlexander V. Chernikov print_flow6id(struct buf_pr *bp, ipfw_insn_u32 *cmd) 185ead75a59SLuigi Rizzo { 186ead75a59SLuigi Rizzo uint16_t i, limit = cmd->o.arg1; 187ead75a59SLuigi Rizzo char sep = ','; 188ead75a59SLuigi Rizzo 189*912430f6SAlexander V. Chernikov bprintf(bp, " flow-id "); 190ead75a59SLuigi Rizzo for( i=0; i < limit; ++i) { 191ead75a59SLuigi Rizzo if (i == limit - 1) 192ead75a59SLuigi Rizzo sep = ' '; 193*912430f6SAlexander V. Chernikov bprintf(bp, "%d%c", cmd->d[i], sep); 194ead75a59SLuigi Rizzo } 195ead75a59SLuigi Rizzo } 196ead75a59SLuigi Rizzo 197ead75a59SLuigi Rizzo /* structure and define for the extension header in ipv6 */ 198ead75a59SLuigi Rizzo static struct _s_x ext6hdrcodes[] = { 199ead75a59SLuigi Rizzo { "frag", EXT_FRAGMENT }, 200ead75a59SLuigi Rizzo { "hopopt", EXT_HOPOPTS }, 201ead75a59SLuigi Rizzo { "route", EXT_ROUTING }, 202ead75a59SLuigi Rizzo { "dstopt", EXT_DSTOPTS }, 203ead75a59SLuigi Rizzo { "ah", EXT_AH }, 204ead75a59SLuigi Rizzo { "esp", EXT_ESP }, 205ead75a59SLuigi Rizzo { "rthdr0", EXT_RTHDR0 }, 206ead75a59SLuigi Rizzo { "rthdr2", EXT_RTHDR2 }, 207ead75a59SLuigi Rizzo { NULL, 0 } 208ead75a59SLuigi Rizzo }; 209ead75a59SLuigi Rizzo 210ead75a59SLuigi Rizzo /* fills command for the extension header filtering */ 211ead75a59SLuigi Rizzo int 212ead75a59SLuigi Rizzo fill_ext6hdr( ipfw_insn *cmd, char *av) 213ead75a59SLuigi Rizzo { 214ead75a59SLuigi Rizzo int tok; 215ead75a59SLuigi Rizzo char *s = av; 216ead75a59SLuigi Rizzo 217ead75a59SLuigi Rizzo cmd->arg1 = 0; 218ead75a59SLuigi Rizzo 219ead75a59SLuigi Rizzo while(s) { 220ead75a59SLuigi Rizzo av = strsep( &s, ",") ; 221ead75a59SLuigi Rizzo tok = match_token(ext6hdrcodes, av); 222ead75a59SLuigi Rizzo switch (tok) { 223ead75a59SLuigi Rizzo case EXT_FRAGMENT: 224ead75a59SLuigi Rizzo cmd->arg1 |= EXT_FRAGMENT; 225ead75a59SLuigi Rizzo break; 226ead75a59SLuigi Rizzo 227ead75a59SLuigi Rizzo case EXT_HOPOPTS: 228ead75a59SLuigi Rizzo cmd->arg1 |= EXT_HOPOPTS; 229ead75a59SLuigi Rizzo break; 230ead75a59SLuigi Rizzo 231ead75a59SLuigi Rizzo case EXT_ROUTING: 232ead75a59SLuigi Rizzo cmd->arg1 |= EXT_ROUTING; 233ead75a59SLuigi Rizzo break; 234ead75a59SLuigi Rizzo 235ead75a59SLuigi Rizzo case EXT_DSTOPTS: 236ead75a59SLuigi Rizzo cmd->arg1 |= EXT_DSTOPTS; 237ead75a59SLuigi Rizzo break; 238ead75a59SLuigi Rizzo 239ead75a59SLuigi Rizzo case EXT_AH: 240ead75a59SLuigi Rizzo cmd->arg1 |= EXT_AH; 241ead75a59SLuigi Rizzo break; 242ead75a59SLuigi Rizzo 243ead75a59SLuigi Rizzo case EXT_ESP: 244ead75a59SLuigi Rizzo cmd->arg1 |= EXT_ESP; 245ead75a59SLuigi Rizzo break; 246ead75a59SLuigi Rizzo 247ead75a59SLuigi Rizzo case EXT_RTHDR0: 248ead75a59SLuigi Rizzo cmd->arg1 |= EXT_RTHDR0; 249ead75a59SLuigi Rizzo break; 250ead75a59SLuigi Rizzo 251ead75a59SLuigi Rizzo case EXT_RTHDR2: 252ead75a59SLuigi Rizzo cmd->arg1 |= EXT_RTHDR2; 253ead75a59SLuigi Rizzo break; 254ead75a59SLuigi Rizzo 255ead75a59SLuigi Rizzo default: 256ead75a59SLuigi Rizzo errx( EX_DATAERR, "invalid option for ipv6 exten header" ); 257ead75a59SLuigi Rizzo break; 258ead75a59SLuigi Rizzo } 259ead75a59SLuigi Rizzo } 260ead75a59SLuigi Rizzo if (cmd->arg1 == 0 ) 261ead75a59SLuigi Rizzo return 0; 262ead75a59SLuigi Rizzo cmd->opcode = O_EXT_HDR; 263ead75a59SLuigi Rizzo cmd->len |= F_INSN_SIZE( ipfw_insn ); 264ead75a59SLuigi Rizzo return 1; 265ead75a59SLuigi Rizzo } 266ead75a59SLuigi Rizzo 267ead75a59SLuigi Rizzo void 268*912430f6SAlexander V. Chernikov print_ext6hdr(struct buf_pr *bp, ipfw_insn *cmd ) 269ead75a59SLuigi Rizzo { 270ead75a59SLuigi Rizzo char sep = ' '; 271ead75a59SLuigi Rizzo 272*912430f6SAlexander V. Chernikov bprintf(bp, " extension header:"); 273ead75a59SLuigi Rizzo if (cmd->arg1 & EXT_FRAGMENT ) { 274*912430f6SAlexander V. Chernikov bprintf(bp, "%cfragmentation", sep); 275ead75a59SLuigi Rizzo sep = ','; 276ead75a59SLuigi Rizzo } 277ead75a59SLuigi Rizzo if (cmd->arg1 & EXT_HOPOPTS ) { 278*912430f6SAlexander V. Chernikov bprintf(bp, "%chop options", sep); 279ead75a59SLuigi Rizzo sep = ','; 280ead75a59SLuigi Rizzo } 281ead75a59SLuigi Rizzo if (cmd->arg1 & EXT_ROUTING ) { 282*912430f6SAlexander V. Chernikov bprintf(bp, "%crouting options", sep); 283ead75a59SLuigi Rizzo sep = ','; 284ead75a59SLuigi Rizzo } 285ead75a59SLuigi Rizzo if (cmd->arg1 & EXT_RTHDR0 ) { 286*912430f6SAlexander V. Chernikov bprintf(bp, "%crthdr0", sep); 287ead75a59SLuigi Rizzo sep = ','; 288ead75a59SLuigi Rizzo } 289ead75a59SLuigi Rizzo if (cmd->arg1 & EXT_RTHDR2 ) { 290*912430f6SAlexander V. Chernikov bprintf(bp, "%crthdr2", sep); 291ead75a59SLuigi Rizzo sep = ','; 292ead75a59SLuigi Rizzo } 293ead75a59SLuigi Rizzo if (cmd->arg1 & EXT_DSTOPTS ) { 294*912430f6SAlexander V. Chernikov bprintf(bp, "%cdestination options", sep); 295ead75a59SLuigi Rizzo sep = ','; 296ead75a59SLuigi Rizzo } 297ead75a59SLuigi Rizzo if (cmd->arg1 & EXT_AH ) { 298*912430f6SAlexander V. Chernikov bprintf(bp, "%cauthentication header", sep); 299ead75a59SLuigi Rizzo sep = ','; 300ead75a59SLuigi Rizzo } 301ead75a59SLuigi Rizzo if (cmd->arg1 & EXT_ESP ) { 302*912430f6SAlexander V. Chernikov bprintf(bp, "%cencapsulated security payload", sep); 303ead75a59SLuigi Rizzo } 304ead75a59SLuigi Rizzo } 305ead75a59SLuigi Rizzo 306ead75a59SLuigi Rizzo /* Try to find ipv6 address by hostname */ 307ead75a59SLuigi Rizzo static int 308ead75a59SLuigi Rizzo lookup_host6 (char *host, struct in6_addr *ip6addr) 309ead75a59SLuigi Rizzo { 310ead75a59SLuigi Rizzo struct hostent *he; 311ead75a59SLuigi Rizzo 312ead75a59SLuigi Rizzo if (!inet_pton(AF_INET6, host, ip6addr)) { 313ead75a59SLuigi Rizzo if ((he = gethostbyname2(host, AF_INET6)) == NULL) 314ead75a59SLuigi Rizzo return(-1); 315ead75a59SLuigi Rizzo memcpy(ip6addr, he->h_addr_list[0], sizeof( struct in6_addr)); 316ead75a59SLuigi Rizzo } 317ead75a59SLuigi Rizzo return(0); 318ead75a59SLuigi Rizzo } 319ead75a59SLuigi Rizzo 320ead75a59SLuigi Rizzo 321ead75a59SLuigi Rizzo /* 322ead75a59SLuigi Rizzo * fill the addr and mask fields in the instruction as appropriate from av. 323ead75a59SLuigi Rizzo * Update length as appropriate. 324ead75a59SLuigi Rizzo * The following formats are allowed: 325ead75a59SLuigi Rizzo * any matches any IP6. Actually returns an empty instruction. 326ead75a59SLuigi Rizzo * me returns O_IP6_*_ME 327ead75a59SLuigi Rizzo * 328ead75a59SLuigi Rizzo * 03f1::234:123:0342 single IP6 addres 329ead75a59SLuigi Rizzo * 03f1::234:123:0342/24 address/mask 330ead75a59SLuigi Rizzo * 03f1::234:123:0342/24,03f1::234:123:0343/ List of address 331ead75a59SLuigi Rizzo * 332ead75a59SLuigi Rizzo * Set of address (as in ipv6) not supported because ipv6 address 333ead75a59SLuigi Rizzo * are typically random past the initial prefix. 334ead75a59SLuigi Rizzo * Return 1 on success, 0 on failure. 335ead75a59SLuigi Rizzo */ 336ead75a59SLuigi Rizzo static int 337579ed7bdSAlexander V. Chernikov fill_ip6(ipfw_insn_ip6 *cmd, char *av, int cblen) 338ead75a59SLuigi Rizzo { 339ead75a59SLuigi Rizzo int len = 0; 340ead75a59SLuigi Rizzo struct in6_addr *d = &(cmd->addr6); 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) { 3637e00325dSAlexander V. Chernikov char *p = strchr(av + 6, ','); 3647e00325dSAlexander V. Chernikov uint32_t *dm = ((ipfw_insn_u32 *)cmd)->d; 3657e00325dSAlexander V. Chernikov 3667e00325dSAlexander V. Chernikov if (p) 3677e00325dSAlexander V. Chernikov *p++ = '\0'; 3687e00325dSAlexander V. Chernikov cmd->o.opcode = O_IP_DST_LOOKUP; 3697e00325dSAlexander V. Chernikov cmd->o.arg1 = strtoul(av + 6, NULL, 0); 3707e00325dSAlexander V. Chernikov if (p) { 3717e00325dSAlexander V. Chernikov cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32); 3727e00325dSAlexander V. Chernikov dm[0] = strtoul(p, NULL, 0); 3737e00325dSAlexander V. Chernikov } else 3747e00325dSAlexander V. Chernikov cmd->o.len |= F_INSN_SIZE(ipfw_insn); 3757e00325dSAlexander V. Chernikov return (1); 3767e00325dSAlexander V. Chernikov } 3777e00325dSAlexander V. Chernikov 378ead75a59SLuigi Rizzo av = strdup(av); 379ead75a59SLuigi Rizzo while (av) { 380ead75a59SLuigi Rizzo /* 381ead75a59SLuigi Rizzo * After the address we can have '/' indicating a mask, 382ead75a59SLuigi Rizzo * or ',' indicating another address follows. 383ead75a59SLuigi Rizzo */ 384ead75a59SLuigi Rizzo 385ead75a59SLuigi Rizzo char *p; 386ead75a59SLuigi Rizzo int masklen; 387ead75a59SLuigi Rizzo char md = '\0'; 388ead75a59SLuigi Rizzo 389579ed7bdSAlexander V. Chernikov CHECK_LENGTH(cblen, 1 + len + 2 * F_INSN_SIZE(struct in6_addr)); 390579ed7bdSAlexander V. Chernikov 391ead75a59SLuigi Rizzo if ((p = strpbrk(av, "/,")) ) { 392ead75a59SLuigi Rizzo md = *p; /* save the separator */ 393ead75a59SLuigi Rizzo *p = '\0'; /* terminate address string */ 394ead75a59SLuigi Rizzo p++; /* and skip past it */ 395ead75a59SLuigi Rizzo } 396ead75a59SLuigi Rizzo /* now p points to NULL, mask or next entry */ 397ead75a59SLuigi Rizzo 398ead75a59SLuigi Rizzo /* lookup stores address in *d as a side effect */ 399ead75a59SLuigi Rizzo if (lookup_host6(av, d) != 0) { 400ead75a59SLuigi Rizzo /* XXX: failed. Free memory and go */ 401ead75a59SLuigi Rizzo errx(EX_DATAERR, "bad address \"%s\"", av); 402ead75a59SLuigi Rizzo } 403ead75a59SLuigi Rizzo /* next, look at the mask, if any */ 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); 409ead75a59SLuigi Rizzo 410ead75a59SLuigi Rizzo APPLY_MASK(d, &d[1]) /* mask base address with mask */ 411ead75a59SLuigi Rizzo 412ead75a59SLuigi Rizzo /* find next separator */ 413ead75a59SLuigi Rizzo 414ead75a59SLuigi Rizzo if (md == '/') { /* find separator past the mask */ 415ead75a59SLuigi Rizzo p = strpbrk(p, ","); 416ead75a59SLuigi Rizzo if (p != NULL) 417ead75a59SLuigi Rizzo p++; 418ead75a59SLuigi Rizzo } 419ead75a59SLuigi Rizzo av = p; 420ead75a59SLuigi Rizzo 421ead75a59SLuigi Rizzo /* Check this entry */ 422ead75a59SLuigi Rizzo if (masklen == 0) { 423ead75a59SLuigi Rizzo /* 424ead75a59SLuigi Rizzo * 'any' turns the entire list into a NOP. 425ead75a59SLuigi Rizzo * 'not any' never matches, so it is removed from the 426ead75a59SLuigi Rizzo * list unless it is the only item, in which case we 427ead75a59SLuigi Rizzo * report an error. 428ead75a59SLuigi Rizzo */ 429ead75a59SLuigi Rizzo if (cmd->o.len & F_NOT && av == NULL && len == 0) 430ead75a59SLuigi Rizzo errx(EX_DATAERR, "not any never matches"); 431ead75a59SLuigi Rizzo continue; 432ead75a59SLuigi Rizzo } 433ead75a59SLuigi Rizzo 434ead75a59SLuigi Rizzo /* 435ead75a59SLuigi Rizzo * A single IP can be stored alone 436ead75a59SLuigi Rizzo */ 437ead75a59SLuigi Rizzo if (masklen == 128 && av == NULL && len == 0) { 438ead75a59SLuigi Rizzo len = F_INSN_SIZE(struct in6_addr); 439ead75a59SLuigi Rizzo break; 440ead75a59SLuigi Rizzo } 441ead75a59SLuigi Rizzo 442ead75a59SLuigi Rizzo /* Update length and pointer to arguments */ 443ead75a59SLuigi Rizzo len += F_INSN_SIZE(struct in6_addr)*2; 444ead75a59SLuigi Rizzo d += 2; 445ead75a59SLuigi Rizzo } /* end while */ 446ead75a59SLuigi Rizzo 447ead75a59SLuigi Rizzo /* 448ead75a59SLuigi Rizzo * Total length of the command, remember that 1 is the size of 449ead75a59SLuigi Rizzo * the base command. 450ead75a59SLuigi Rizzo */ 451ead75a59SLuigi Rizzo if (len + 1 > F_LEN_MASK) 452ead75a59SLuigi Rizzo errx(EX_DATAERR, "address list too long"); 453ead75a59SLuigi Rizzo cmd->o.len |= len+1; 454ead75a59SLuigi Rizzo free(av); 455ead75a59SLuigi Rizzo return (1); 456ead75a59SLuigi Rizzo } 457ead75a59SLuigi Rizzo 458ead75a59SLuigi Rizzo /* 459ead75a59SLuigi Rizzo * fills command for ipv6 flow-id filtering 460ead75a59SLuigi Rizzo * note that the 20 bit flow number is stored in a array of u_int32_t 461ead75a59SLuigi Rizzo * it's supported lists of flow-id, so in the o.arg1 we store how many 462ead75a59SLuigi Rizzo * additional flow-id we want to filter, the basic is 1 463ead75a59SLuigi Rizzo */ 464ead75a59SLuigi Rizzo void 465579ed7bdSAlexander V. Chernikov fill_flow6( ipfw_insn_u32 *cmd, char *av, int cblen) 466ead75a59SLuigi Rizzo { 467ead75a59SLuigi Rizzo u_int32_t type; /* Current flow number */ 468ead75a59SLuigi Rizzo u_int16_t nflow = 0; /* Current flow index */ 469ead75a59SLuigi Rizzo char *s = av; 470ead75a59SLuigi Rizzo cmd->d[0] = 0; /* Initializing the base number*/ 471ead75a59SLuigi Rizzo 472ead75a59SLuigi Rizzo while (s) { 473579ed7bdSAlexander V. Chernikov CHECK_LENGTH(cblen, F_INSN_SIZE(ipfw_insn_u32) + nflow + 1); 474579ed7bdSAlexander V. Chernikov 475ead75a59SLuigi Rizzo av = strsep( &s, ",") ; 476ead75a59SLuigi Rizzo type = strtoul(av, &av, 0); 477ead75a59SLuigi Rizzo if (*av != ',' && *av != '\0') 478ead75a59SLuigi Rizzo errx(EX_DATAERR, "invalid ipv6 flow number %s", av); 479ead75a59SLuigi Rizzo if (type > 0xfffff) 480ead75a59SLuigi Rizzo errx(EX_DATAERR, "flow number out of range %s", av); 481ead75a59SLuigi Rizzo cmd->d[nflow] |= type; 482ead75a59SLuigi Rizzo nflow++; 483ead75a59SLuigi Rizzo } 484ead75a59SLuigi Rizzo if( nflow > 0 ) { 485ead75a59SLuigi Rizzo cmd->o.opcode = O_FLOW6ID; 486ead75a59SLuigi Rizzo cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32) + nflow; 487ead75a59SLuigi Rizzo cmd->o.arg1 = nflow; 488ead75a59SLuigi Rizzo } 489ead75a59SLuigi Rizzo else { 490ead75a59SLuigi Rizzo errx(EX_DATAERR, "invalid ipv6 flow number %s", av); 491ead75a59SLuigi Rizzo } 492ead75a59SLuigi Rizzo } 493ead75a59SLuigi Rizzo 494ead75a59SLuigi Rizzo ipfw_insn * 495579ed7bdSAlexander V. Chernikov add_srcip6(ipfw_insn *cmd, char *av, int cblen) 496ead75a59SLuigi Rizzo { 497ead75a59SLuigi Rizzo 498579ed7bdSAlexander V. Chernikov fill_ip6((ipfw_insn_ip6 *)cmd, av, cblen); 4997e00325dSAlexander V. Chernikov if (cmd->opcode == O_IP_DST_SET) /* set */ 5007e00325dSAlexander V. Chernikov cmd->opcode = O_IP_SRC_SET; 5017e00325dSAlexander V. Chernikov else if (cmd->opcode == O_IP_DST_LOOKUP) /* table */ 5027e00325dSAlexander V. Chernikov cmd->opcode = O_IP_SRC_LOOKUP; 5037e00325dSAlexander V. Chernikov else if (F_LEN(cmd) == 0) { /* any */ 504ead75a59SLuigi Rizzo } else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) { /* "me" */ 505ead75a59SLuigi Rizzo cmd->opcode = O_IP6_SRC_ME; 506ead75a59SLuigi Rizzo } else if (F_LEN(cmd) == 507ead75a59SLuigi Rizzo (F_INSN_SIZE(struct in6_addr) + F_INSN_SIZE(ipfw_insn))) { 508ead75a59SLuigi Rizzo /* single IP, no mask*/ 509ead75a59SLuigi Rizzo cmd->opcode = O_IP6_SRC; 510ead75a59SLuigi Rizzo } else { /* addr/mask opt */ 511ead75a59SLuigi Rizzo cmd->opcode = O_IP6_SRC_MASK; 512ead75a59SLuigi Rizzo } 513ead75a59SLuigi Rizzo return cmd; 514ead75a59SLuigi Rizzo } 515ead75a59SLuigi Rizzo 516ead75a59SLuigi Rizzo ipfw_insn * 517579ed7bdSAlexander V. Chernikov add_dstip6(ipfw_insn *cmd, char *av, int cblen) 518ead75a59SLuigi Rizzo { 519ead75a59SLuigi Rizzo 520579ed7bdSAlexander V. Chernikov fill_ip6((ipfw_insn_ip6 *)cmd, av, cblen); 5217e00325dSAlexander V. Chernikov if (cmd->opcode == O_IP_DST_SET) /* set */ 5227e00325dSAlexander V. Chernikov ; 5237e00325dSAlexander V. Chernikov else if (cmd->opcode == O_IP_DST_LOOKUP) /* table */ 5247e00325dSAlexander V. Chernikov ; 5257e00325dSAlexander V. Chernikov else if (F_LEN(cmd) == 0) { /* any */ 526ead75a59SLuigi Rizzo } else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) { /* "me" */ 527ead75a59SLuigi Rizzo cmd->opcode = O_IP6_DST_ME; 528ead75a59SLuigi Rizzo } else if (F_LEN(cmd) == 529ead75a59SLuigi Rizzo (F_INSN_SIZE(struct in6_addr) + F_INSN_SIZE(ipfw_insn))) { 530ead75a59SLuigi Rizzo /* single IP, no mask*/ 531ead75a59SLuigi Rizzo cmd->opcode = O_IP6_DST; 532ead75a59SLuigi Rizzo } else { /* addr/mask opt */ 533ead75a59SLuigi Rizzo cmd->opcode = O_IP6_DST_MASK; 534ead75a59SLuigi Rizzo } 535ead75a59SLuigi Rizzo return cmd; 536ead75a59SLuigi Rizzo } 537