1 /* $NetBSD: parseipfexpr.c,v 1.1.1.2 2012/07/22 13:44:40 darrenr Exp $ */ 2 3 #include "ipf.h" 4 #include <ctype.h> 5 6 7 typedef struct ipfopentry { 8 int ipoe_cmd; 9 int ipoe_nbasearg; 10 int ipoe_maxarg; 11 int ipoe_argsize; 12 char *ipoe_word; 13 } ipfopentry_t; 14 15 static ipfopentry_t opwords[17] = { 16 { IPF_EXP_IP_ADDR, 2, 0, 1, "ip.addr" }, 17 { IPF_EXP_IP6_ADDR, 2, 0, 4, "ip6.addr" }, 18 { IPF_EXP_IP_PR, 1, 0, 1, "ip.p" }, 19 { IPF_EXP_IP_SRCADDR, 2, 0, 1, "ip.src" }, 20 { IPF_EXP_IP_DSTADDR, 2, 0, 1, "ip.dst" }, 21 { IPF_EXP_IP6_SRCADDR, 2, 0, 4, "ip6.src" }, 22 { IPF_EXP_IP6_DSTADDR, 2, 0, 4, "ip6.dst" }, 23 { IPF_EXP_TCP_PORT, 1, 0, 1, "tcp.port" }, 24 { IPF_EXP_TCP_DPORT, 1, 0, 1, "tcp.dport" }, 25 { IPF_EXP_TCP_SPORT, 1, 0, 1, "tcp.sport" }, 26 { IPF_EXP_TCP_FLAGS, 2, 0, 1, "tcp.flags" }, 27 { IPF_EXP_UDP_PORT, 1, 0, 1, "udp.port" }, 28 { IPF_EXP_UDP_DPORT, 1, 0, 1, "udp.dport" }, 29 { IPF_EXP_UDP_SPORT, 1, 0, 1, "udp.sport" }, 30 { IPF_EXP_TCP_STATE, 1, 0, 1, "tcp.state" }, 31 { IPF_EXP_IDLE_GT, 1, 1, 1, "idle-gt" }, 32 { -1, 0, 0, 0, NULL } 33 }; 34 35 36 int * 37 parseipfexpr(line, errorptr) 38 char *line; 39 char **errorptr; 40 { 41 int not, items, asize, *oplist, osize, i; 42 char *temp, *arg, *s, *t, *ops, *error; 43 ipfopentry_t *e; 44 ipfexp_t *ipfe; 45 46 asize = 0; 47 error = NULL; 48 oplist = NULL; 49 50 temp = strdup(line); 51 if (temp == NULL) { 52 error = "strdup failed"; 53 goto parseerror; 54 } 55 56 /* 57 * Eliminate any white spaces to make parsing easier. 58 */ 59 for (s = temp; *s != '\0'; ) { 60 if (ISSPACE(*s)) 61 strcpy(s, s + 1); 62 else 63 s++; 64 } 65 66 /* 67 * Parse the string. 68 * It should be sets of "ip.dst=1.2.3.4/32;" things. 69 * There must be a "=" or "!=" and it must end in ";". 70 */ 71 if (temp[strlen(temp) - 1] != ';') { 72 error = "last character not ';'"; 73 goto parseerror; 74 } 75 76 /* 77 * Work through the list of complete operands present. 78 */ 79 for (ops = strtok(temp, ";"); ops != NULL; ops = strtok(NULL, ";")) { 80 arg = strchr(ops, '='); 81 if ((arg < ops + 2) || (arg == NULL)) { 82 error = "bad 'arg' vlaue"; 83 goto parseerror; 84 } 85 86 if (*(arg - 1) == '!') { 87 *(arg - 1) = '\0'; 88 not = 1; 89 } else { 90 not = 0; 91 } 92 *arg++ = '\0'; 93 94 95 for (e = opwords; e->ipoe_word; e++) { 96 if (strcmp(ops, e->ipoe_word) == 0) 97 break; 98 } 99 if (e->ipoe_word == NULL) { 100 error = malloc(32); 101 if (error != NULL) { 102 sprintf(error, "keyword (%.10s) not found", 103 ops); 104 } 105 goto parseerror; 106 } 107 108 /* 109 * Count the number of commas so we know how big to 110 * build the array 111 */ 112 for (s = arg, items = 1; *s != '\0'; s++) 113 if (*s == ',') 114 items++; 115 116 if ((e->ipoe_maxarg != 0) && (items > e->ipoe_maxarg)) { 117 error = "too many items"; 118 goto parseerror; 119 } 120 121 /* 122 * osize will mark the end of where we have filled up to 123 * and is thus where we start putting new data. 124 */ 125 osize = asize; 126 asize += 4 + (items * e->ipoe_nbasearg * e->ipoe_argsize); 127 if (oplist == NULL) 128 oplist = calloc(1, sizeof(int) * (asize + 2)); 129 else 130 oplist = realloc(oplist, sizeof(int) * (asize + 2)); 131 if (oplist == NULL) { 132 error = "oplist alloc failed"; 133 goto parseerror; 134 } 135 ipfe = (ipfexp_t *)(oplist + osize); 136 osize += 4; 137 ipfe->ipfe_cmd = e->ipoe_cmd; 138 ipfe->ipfe_not = not; 139 ipfe->ipfe_narg = items * e->ipoe_nbasearg; 140 ipfe->ipfe_size = items * e->ipoe_nbasearg * e->ipoe_argsize; 141 ipfe->ipfe_size += 4; 142 143 for (s = arg; (*s != '\0') && (osize < asize); s = t) { 144 /* 145 * Look for the end of this arg or the ',' to say 146 * there is another following. 147 */ 148 for (t = s; (*t != '\0') && (*t != ','); t++) 149 ; 150 if (*t == ',') 151 *t++ = '\0'; 152 153 if (!strcasecmp(ops, "ip.addr") || 154 !strcasecmp(ops, "ip.src") || 155 !strcasecmp(ops, "ip.dst")) { 156 i6addr_t mask, addr; 157 char *delim; 158 159 delim = strchr(s, '/'); 160 if (delim != NULL) { 161 *delim++ = '\0'; 162 if (genmask(AF_INET, delim, 163 &mask) == -1) { 164 error = "genmask failed"; 165 goto parseerror; 166 } 167 } else { 168 mask.in4.s_addr = 0xffffffff; 169 } 170 if (gethost(AF_INET, s, &addr) == -1) { 171 error = "gethost failed"; 172 goto parseerror; 173 } 174 175 oplist[osize++] = addr.in4.s_addr; 176 oplist[osize++] = mask.in4.s_addr; 177 178 #ifdef USE_INET6 179 } else if (!strcasecmp(ops, "ip6.addr") || 180 !strcasecmp(ops, "ip6.src") || 181 !strcasecmp(ops, "ip6.dst")) { 182 i6addr_t mask, addr; 183 char *delim; 184 185 delim = strchr(s, '/'); 186 if (delim != NULL) { 187 *delim++ = '\0'; 188 if (genmask(AF_INET6, delim, 189 &mask) == -1) { 190 error = "genmask failed"; 191 goto parseerror; 192 } 193 } else { 194 mask.i6[0] = 0xffffffff; 195 mask.i6[1] = 0xffffffff; 196 mask.i6[2] = 0xffffffff; 197 mask.i6[3] = 0xffffffff; 198 } 199 if (gethost(AF_INET6, s, &addr) == -1) { 200 error = "gethost failed"; 201 goto parseerror; 202 } 203 204 oplist[osize++] = addr.i6[0]; 205 oplist[osize++] = addr.i6[1]; 206 oplist[osize++] = addr.i6[2]; 207 oplist[osize++] = addr.i6[3]; 208 oplist[osize++] = mask.i6[0]; 209 oplist[osize++] = mask.i6[1]; 210 oplist[osize++] = mask.i6[2]; 211 oplist[osize++] = mask.i6[3]; 212 #endif 213 214 } else if (!strcasecmp(ops, "ip.p")) { 215 int p; 216 217 p = getproto(s); 218 if (p == -1) 219 goto parseerror; 220 oplist[osize++] = p; 221 222 } else if (!strcasecmp(ops, "tcp.flags")) { 223 u_32_t mask, flags; 224 char *delim; 225 226 delim = strchr(s, '/'); 227 if (delim != NULL) { 228 *delim++ = '\0'; 229 mask = tcpflags(delim); 230 } else { 231 mask = 0xff; 232 } 233 flags = tcpflags(s); 234 235 oplist[osize++] = flags; 236 oplist[osize++] = mask; 237 238 239 } else if (!strcasecmp(ops, "tcp.port") || 240 !strcasecmp(ops, "tcp.sport") || 241 !strcasecmp(ops, "tcp.dport") || 242 !strcasecmp(ops, "udp.port") || 243 !strcasecmp(ops, "udp.sport") || 244 !strcasecmp(ops, "udp.dport")) { 245 char proto[4]; 246 u_short port; 247 248 strncpy(proto, ops, 3); 249 proto[3] = '\0'; 250 if (getport(NULL, s, &port, proto) == -1) 251 goto parseerror; 252 oplist[osize++] = port; 253 254 } else if (!strcasecmp(ops, "tcp.state")) { 255 oplist[osize++] = atoi(s); 256 257 } else { 258 error = "unknown word"; 259 goto parseerror; 260 } 261 } 262 } 263 264 free(temp); 265 266 if (errorptr != NULL) 267 *errorptr = NULL; 268 269 for (i = asize; i > 0; i--) 270 oplist[i] = oplist[i - 1]; 271 272 oplist[0] = asize + 2; 273 oplist[asize + 1] = IPF_EXP_END; 274 275 return oplist; 276 277 parseerror: 278 if (errorptr != NULL) 279 *errorptr = error; 280 if (oplist != NULL) 281 free(oplist); 282 if (temp != NULL) 283 free(temp); 284 return NULL; 285 } 286