* fills the addr and mask fields in the instruction as appropriate from av. * Update length as appropriate. * The following formats are allowed: * me returns O_IP_*_ME * 1.2.3.4 single IP address * 1.2.3.4:5.6.7.8 address:mask * 1.2.3.4/24 address/mask * 1.2.3.4/26{1,6,5,4,23} set of addresses in a subnet * We can have multiple comma-separated address/mask entries. */
| 3120 | * We can have multiple comma-separated address/mask entries. |
| 3121 | */ |
| 3122 | static void |
| 3123 | fill_ip(ipfw_insn_ip *cmd, char *av, int cblen, struct tidx *tstate) |
| 3124 | { |
| 3125 | int len = 0; |
| 3126 | uint32_t *d = ((ipfw_insn_u32 *)cmd)->d; |
| 3127 | |
| 3128 | cmd->o.len &= ~F_LEN_MASK; /* zero len */ |
| 3129 | |
| 3130 | if (_substrcmp(av, "any") == 0) |
| 3131 | return; |
| 3132 | |
| 3133 | if (_substrcmp(av, "me") == 0) { |
| 3134 | cmd->o.len |= F_INSN_SIZE(ipfw_insn); |
| 3135 | return; |
| 3136 | } |
| 3137 | |
| 3138 | if (strncmp(av, "table(", 6) == 0) { |
| 3139 | fill_table(&cmd->o, av, O_IP_DST_LOOKUP, tstate); |
| 3140 | return; |
| 3141 | } |
| 3142 | |
| 3143 | while (av) { |
| 3144 | /* |
| 3145 | * After the address we can have '/' or ':' indicating a mask, |
| 3146 | * ',' indicating another address follows, '{' indicating a |
| 3147 | * set of addresses of unspecified size. |
| 3148 | */ |
| 3149 | char *t = NULL, *p = strpbrk(av, "/:,{"); |
| 3150 | int masklen; |
| 3151 | char md, nd = '\0'; |
| 3152 | |
| 3153 | CHECK_LENGTH(cblen, (int)F_INSN_SIZE(ipfw_insn) + 2 + len); |
| 3154 | |
| 3155 | if (p) { |
| 3156 | md = *p; |
| 3157 | *p++ = '\0'; |
| 3158 | if ((t = strpbrk(p, ",{")) != NULL) { |
| 3159 | nd = *t; |
| 3160 | *t = '\0'; |
| 3161 | } |
| 3162 | } else |
| 3163 | md = '\0'; |
| 3164 | |
| 3165 | if (lookup_host(av, (struct in_addr *)&d[0]) != 0) |
| 3166 | errx(EX_NOHOST, "hostname ``%s'' unknown", av); |
| 3167 | switch (md) { |
| 3168 | case ':': |
| 3169 | if (!inet_aton(p, (struct in_addr *)&d[1])) |
| 3170 | errx(EX_DATAERR, "bad netmask ``%s''", p); |
| 3171 | break; |
| 3172 | case '/': |
| 3173 | masklen = atoi(p); |
| 3174 | if (masklen == 0) |
| 3175 | d[1] = htonl(0U); /* mask */ |
| 3176 | else if (masklen > 32) |
| 3177 | errx(EX_DATAERR, "bad width ``%s''", p); |
| 3178 | else |
| 3179 | d[1] = htonl(~0U << (32 - masklen)); |
no test coverage detected