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