void fill_icmp6types(ipfw_insn_icmp6 *cmd, char *av, int cblen) { uint8_t type; CHECK_LENGTH(cblen, F_INSN_SIZE(ipfw_insn_icmp6)); bzero(cmd, sizeof(*cmd)); while (*av) { if (*av == ',') av++; type = strtoul(av, &av, 0); if (*av != ',' && *av != '\0') errx(EX_DATAERR, "invalid ICMP6 type"); /* * XXX: shouldn't this be 0xFF? I can't see any reason why * we shouldn't be able to filter all possiable values * regardless of the ability of the rest of the kernel to do * anything useful with them. */ if (type > ICMP6_MAXTYPE) errx(EX_DATAERR, "ICMP6 type out of range"); cmd->d[type / 32] |= ( 1 << (type % 32)); } cmd->o.opcode = O_ICMP6TYPE; cmd->o.len |= F_INSN_SIZE(ipfw_insn_icmp6); }
/* fills command for the extension header filtering */ int fill_ext6hdr( ipfw_insn *cmd, char *av) { int tok; char *s = av; cmd->arg1 = 0; while(s) { av = strsep( &s, ",") ; tok = match_token(ext6hdrcodes, av); switch (tok) { case EXT_FRAGMENT: cmd->arg1 |= EXT_FRAGMENT; break; case EXT_HOPOPTS: cmd->arg1 |= EXT_HOPOPTS; break; case EXT_ROUTING: cmd->arg1 |= EXT_ROUTING; break; case EXT_DSTOPTS: cmd->arg1 |= EXT_DSTOPTS; break; case EXT_AH: cmd->arg1 |= EXT_AH; break; case EXT_ESP: cmd->arg1 |= EXT_ESP; break; case EXT_RTHDR0: cmd->arg1 |= EXT_RTHDR0; break; case EXT_RTHDR2: cmd->arg1 |= EXT_RTHDR2; break; default: errx( EX_DATAERR, "invalid option for ipv6 exten header" ); break; } } if (cmd->arg1 == 0 ) return 0; cmd->opcode = O_EXT_HDR; cmd->len |= F_INSN_SIZE( ipfw_insn ); return 1; }
static void fill_iface(ipfw_insn_if *cmd, char *arg) { cmd->name[0] = '\0'; cmd->o.len |= F_INSN_SIZE(ipfw_insn_if); /* Parse the interface or address */ if (!strcmp(arg, "any")){ cmd->o.len = 0; } else if (!isdigit(*arg)) { strlcpy(cmd->name, arg, sizeof(cmd->name)); cmd->p.glob = strpbrk(arg, "*?[") != NULL ? 1 : 0; } else if (!inet_aton(arg, &cmd->p.ip)) errx(EX_DATAERR, "bad ip address ``%s''", arg); }
void parse_gid(ipfw_insn **cmd, int *ac, char **av[]) { char *end; gid_t gid; struct group *grp; NEXT_ARG1; ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)(*cmd); gid = strtoul(**av, &end, 0); grp = (*end == '\0') ? getgrgid(gid) : getgrnam(**av); if (grp == NULL) errx(EX_DATAERR, "gid \"%s\" not exists", **av); cmd32->d[0] = grp->gr_gid; (*cmd)->opcode = O_LAYER4_GID; (*cmd)->module = MODULE_LAYER4_ID; (*cmd)->len |= F_INSN_SIZE(ipfw_insn_u32); NEXT_ARG1; }
void parse_uid(ipfw_insn **cmd, int *ac, char **av[]) { char *end; uid_t uid; struct passwd *pwd; NEXT_ARG1; ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)(*cmd); uid = strtoul(**av, &end, 0); pwd = (*end == '\0') ? getpwuid(uid) : getpwnam(**av); if (pwd == NULL) errx(EX_DATAERR, "uid \"%s\" not exists", **av); cmd32->d[0] = pwd->pw_uid; (*cmd)->opcode = O_LAYER4_UID; (*cmd)->module = MODULE_LAYER4_ID; (*cmd)->len |= F_INSN_SIZE(ipfw_insn_u32); NEXT_ARG1; }
/* * fill the addr and mask fields in the instruction as appropriate from av. * Update length as appropriate. * The following formats are allowed: * any matches any IP6. Actually returns an empty instruction. * me returns O_IP6_*_ME * * 03f1::234:123:0342 single IP6 address * 03f1::234:123:0342/24 address/masklen * 03f1::234:123:0342/ffff::ffff:ffff address/mask * 03f1::234:123:0342/24,03f1::234:123:0343/ List of address * * Set of address (as in ipv6) not supported because ipv6 address * are typically random past the initial prefix. * Return 1 on success, 0 on failure. */ static int fill_ip6(ipfw_insn_ip6 *cmd, char *av, int cblen, struct tidx *tstate) { int len = 0; struct in6_addr *d = &(cmd->addr6); /* * Needed for multiple address. * Note d[1] points to struct in6_add r mask6 of cmd */ cmd->o.len &= ~F_LEN_MASK; /* zero len */ if (strcmp(av, "any") == 0) return (1); if (strcmp(av, "me") == 0) { /* Set the data for "me" opt*/ cmd->o.len |= F_INSN_SIZE(ipfw_insn); return (1); } if (strcmp(av, "me6") == 0) { /* Set the data for "me" opt*/ cmd->o.len |= F_INSN_SIZE(ipfw_insn); return (1); } if (strncmp(av, "table(", 6) == 0) { fill_table(&cmd->o, av, O_IP_DST_LOOKUP, tstate); return (1); } av = strdup(av); while (av) { /* * After the address we can have '/' indicating a mask, * or ',' indicating another address follows. */ char *p, *q; int masklen; char md = '\0'; CHECK_LENGTH(cblen, 1 + len + 2 * F_INSN_SIZE(struct in6_addr)); if ((q = strchr(av, ',')) ) { *q = '\0'; q++; } if ((p = strchr(av, '/')) ) { md = *p; /* save the separator */ *p = '\0'; /* terminate address string */ p++; /* and skip past it */ } /* now p points to NULL, mask or next entry */ /* lookup stores address in *d as a side effect */ if (lookup_host6(av, d) != 0) { /* XXX: failed. Free memory and go */ errx(EX_DATAERR, "bad address \"%s\"", av); } /* next, look at the mask, if any */ if (md == '/' && strchr(p, ':')) { if (!inet_pton(AF_INET6, p, &d[1])) errx(EX_DATAERR, "bad mask \"%s\"", p); masklen = contigmask((uint8_t *)&(d[1]), 128); } else { masklen = (md == '/') ? atoi(p) : 128; if (masklen > 128 || masklen < 0) errx(EX_DATAERR, "bad width \"%s\''", p); else n2mask(&d[1], masklen); } APPLY_MASK(d, &d[1]) /* mask base address with mask */ av = q; /* Check this entry */ if (masklen == 0) { /* * 'any' turns the entire list into a NOP. * 'not any' never matches, so it is removed from the * list unless it is the only item, in which case we * report an error. */ if (cmd->o.len & F_NOT && av == NULL && len == 0) errx(EX_DATAERR, "not any never matches"); continue; } /* * A single IP can be stored alone */ if (masklen == 128 && av == NULL && len == 0) { len = F_INSN_SIZE(struct in6_addr); break; } /* Update length and pointer to arguments */ len += F_INSN_SIZE(struct in6_addr)*2; d += 2; } /* end while */
/* * fill the addr and mask fields in the instruction as appropriate from av. * Update length as appropriate. * The following formats are allowed: * any matches any IP6. Actually returns an empty instruction. * me returns O_IP6_*_ME * * 03f1::234:123:0342 single IP6 addres * 03f1::234:123:0342/24 address/mask * 03f1::234:123:0342/24,03f1::234:123:0343/ List of address * * Set of address (as in ipv6) not supported because ipv6 address * are typically random past the initial prefix. * Return 1 on success, 0 on failure. */ static int fill_ip6(ipfw_insn_ip6 *cmd, char *av) { int len = 0; struct in6_addr *d = &(cmd->addr6); /* * Needed for multiple address. * Note d[1] points to struct in6_add r mask6 of cmd */ cmd->o.len &= ~F_LEN_MASK; /* zero len */ if (strcmp(av, "any") == 0) return (1); if (strcmp(av, "me") == 0) { /* Set the data for "me" opt*/ cmd->o.len |= F_INSN_SIZE(ipfw_insn); return (1); } if (strcmp(av, "me6") == 0) { /* Set the data for "me" opt*/ cmd->o.len |= F_INSN_SIZE(ipfw_insn); return (1); } if (strncmp(av, "table(", 6) == 0) { char *p = strchr(av + 6, ','); uint32_t *dm = ((ipfw_insn_u32 *)cmd)->d; if (p) *p++ = '\0'; cmd->o.opcode = O_IP_DST_LOOKUP; cmd->o.arg1 = strtoul(av + 6, NULL, 0); if (p) { cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32); dm[0] = strtoul(p, NULL, 0); } else cmd->o.len |= F_INSN_SIZE(ipfw_insn); return (1); } av = strdup(av); while (av) { /* * After the address we can have '/' indicating a mask, * or ',' indicating another address follows. */ char *p; int masklen; char md = '\0'; if ((p = strpbrk(av, "/,")) ) { md = *p; /* save the separator */ *p = '\0'; /* terminate address string */ p++; /* and skip past it */ } /* now p points to NULL, mask or next entry */ /* lookup stores address in *d as a side effect */ if (lookup_host6(av, d) != 0) { /* XXX: failed. Free memory and go */ errx(EX_DATAERR, "bad address \"%s\"", av); } /* next, look at the mask, if any */ masklen = (md == '/') ? atoi(p) : 128; if (masklen > 128 || masklen < 0) errx(EX_DATAERR, "bad width \"%s\''", p); else n2mask(&d[1], masklen); APPLY_MASK(d, &d[1]) /* mask base address with mask */ /* find next separator */ if (md == '/') { /* find separator past the mask */ p = strpbrk(p, ","); if (p != NULL) p++; } av = p; /* Check this entry */ if (masklen == 0) { /* * 'any' turns the entire list into a NOP. * 'not any' never matches, so it is removed from the * list unless it is the only item, in which case we * report an error. */ if (cmd->o.len & F_NOT && av == NULL && len == 0) errx(EX_DATAERR, "not any never matches"); continue; } /* * A single IP can be stored alone */ if (masklen == 128 && av == NULL && len == 0) { len = F_INSN_SIZE(struct in6_addr); break; } /* Update length and pointer to arguments */ len += F_INSN_SIZE(struct in6_addr)*2; d += 2; } /* end while */
void parse_to(ipfw_insn **cmd, int *ac, char **av[]) { ipfw_insn_ip *p = (ipfw_insn_ip *)(*cmd); double port; int i; (*cmd)->module = MODULE_BASIC_ID; NEXT_ARG1; if (strcmp(**av, "table") == 0) { NEXT_ARG1; NEED(*ac, 1, "table id missing"); (*cmd)->len = F_INSN_SIZE(ipfw_insn); (*cmd)->opcode = O_BASIC_IP_DST_LOOKUP; (*cmd)->arg1 = strtoul(**av, NULL, 10); } else if (strcmp(**av, "any") == 0) { (*cmd)->len &= ~F_LEN_MASK; } else if (strcmp(**av, "me") == 0) { (*cmd)->len |= F_INSN_SIZE(ipfw_insn); (*cmd)->opcode = O_BASIC_IP_DST_ME; } else { char *c = NULL, md = 0; c = strchr(**av, '/'); if (!c) c = strchr(**av, ':'); if (c) { md = *c; *c++ = '\0'; } if (lookup_host(**av, &p->addr) != 0) errx(EX_NOHOST, "hostname ``%s'' unknown", **av); switch (md) { case ':': port = strtol(c, NULL, 0); if (port <= 0 || port >= 65535) errx(EX_NOHOST, "port `%s' invalid", c); (*cmd)->arg1 = port; (*cmd)->len |= F_INSN_SIZE(ipfw_insn_ip); (*cmd)->opcode = O_BASIC_IP_DST_N_PORT; break; case '/': i = atoi(c); if (i == 0) p->mask.s_addr = htonl(0); else if (i > 32) errx(EX_DATAERR, "bad width ``%s''", c); else p->mask.s_addr = htonl(~0 << (32 - i)); (*cmd)->len |= F_INSN_SIZE(ipfw_insn_ip); (*cmd)->opcode = O_BASIC_IP_DST_MASK; p->addr.s_addr &= p->mask.s_addr; break; default: p->mask.s_addr = htonl(~0); (*cmd)->len |= F_INSN_SIZE(ipfw_insn_u32); (*cmd)->opcode = O_BASIC_IP_DST; break; } } NEXT_ARG1; }