1 #include "ipf.h" 2 #include <ctype.h> 3 4 5 typedef struct ipfopentry { 6 int ipoe_cmd; 7 int ipoe_nbasearg; 8 int ipoe_maxarg; 9 int ipoe_argsize; 10 char *ipoe_word; 11 } ipfopentry_t; 12 13 static ipfopentry_t opwords[17] = { 14 { IPF_EXP_IP_ADDR, 2, 0, 1, "ip.addr" }, 15 { IPF_EXP_IP6_ADDR, 2, 0, 4, "ip6.addr" }, 16 { IPF_EXP_IP_PR, 1, 0, 1, "ip.p" }, 17 { IPF_EXP_IP_SRCADDR, 2, 0, 1, "ip.src" }, 18 { IPF_EXP_IP_DSTADDR, 2, 0, 1, "ip.dst" }, 19 { IPF_EXP_IP6_SRCADDR, 2, 0, 4, "ip6.src" }, 20 { IPF_EXP_IP6_DSTADDR, 2, 0, 4, "ip6.dst" }, 21 { IPF_EXP_TCP_PORT, 1, 0, 1, "tcp.port" }, 22 { IPF_EXP_TCP_DPORT, 1, 0, 1, "tcp.dport" }, 23 { IPF_EXP_TCP_SPORT, 1, 0, 1, "tcp.sport" }, 24 { IPF_EXP_TCP_FLAGS, 2, 0, 1, "tcp.flags" }, 25 { IPF_EXP_UDP_PORT, 1, 0, 1, "udp.port" }, 26 { IPF_EXP_UDP_DPORT, 1, 0, 1, "udp.dport" }, 27 { IPF_EXP_UDP_SPORT, 1, 0, 1, "udp.sport" }, 28 { IPF_EXP_TCP_STATE, 1, 0, 1, "tcp.state" }, 29 { IPF_EXP_IDLE_GT, 1, 1, 1, "idle-gt" }, 30 { -1, 0, 0, 0, NULL } 31 }; 32 33 34 int * 35 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 snprintf(error, sizeof(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 += 4 + (items * e->ipoe_nbasearg * e->ipoe_argsize); 125 if (oplist == NULL) 126 oplist = calloc(asize + 2, sizeof(int)); 127 else 128 oplist = reallocarray(oplist, asize + 2, sizeof(int)); 129 if (oplist == NULL) { 130 error = "oplist alloc failed"; 131 goto parseerror; 132 } 133 ipfe = (ipfexp_t *)(oplist + osize); 134 osize += 4; 135 ipfe->ipfe_cmd = e->ipoe_cmd; 136 ipfe->ipfe_not = not; 137 ipfe->ipfe_narg = items * e->ipoe_nbasearg; 138 ipfe->ipfe_size = items * e->ipoe_nbasearg * e->ipoe_argsize; 139 ipfe->ipfe_size += 4; 140 141 for (s = arg; (*s != '\0') && (osize < asize); s = t) { 142 /* 143 * Look for the end of this arg or the ',' to say 144 * there is another following. 145 */ 146 for (t = s; (*t != '\0') && (*t != ','); t++) 147 ; 148 if (*t == ',') 149 *t++ = '\0'; 150 151 if (!strcasecmp(ops, "ip.addr") || 152 !strcasecmp(ops, "ip.src") || 153 !strcasecmp(ops, "ip.dst")) { 154 i6addr_t mask, addr; 155 char *delim; 156 157 delim = strchr(s, '/'); 158 if (delim != NULL) { 159 *delim++ = '\0'; 160 if (genmask(AF_INET, delim, 161 &mask) == -1) { 162 error = "genmask failed"; 163 goto parseerror; 164 } 165 } else { 166 mask.in4.s_addr = 0xffffffff; 167 } 168 if (gethost(AF_INET, s, &addr) == -1) { 169 error = "gethost failed"; 170 goto parseerror; 171 } 172 173 oplist[osize++] = addr.in4.s_addr; 174 oplist[osize++] = mask.in4.s_addr; 175 176 #ifdef USE_INET6 177 } else if (!strcasecmp(ops, "ip6.addr") || 178 !strcasecmp(ops, "ip6.src") || 179 !strcasecmp(ops, "ip6.dst")) { 180 i6addr_t mask, addr; 181 char *delim; 182 183 delim = strchr(s, '/'); 184 if (delim != NULL) { 185 *delim++ = '\0'; 186 if (genmask(AF_INET6, delim, 187 &mask) == -1) { 188 error = "genmask failed"; 189 goto parseerror; 190 } 191 } else { 192 mask.i6[0] = 0xffffffff; 193 mask.i6[1] = 0xffffffff; 194 mask.i6[2] = 0xffffffff; 195 mask.i6[3] = 0xffffffff; 196 } 197 if (gethost(AF_INET6, s, &addr) == -1) { 198 error = "gethost failed"; 199 goto parseerror; 200 } 201 202 oplist[osize++] = addr.i6[0]; 203 oplist[osize++] = addr.i6[1]; 204 oplist[osize++] = addr.i6[2]; 205 oplist[osize++] = addr.i6[3]; 206 oplist[osize++] = mask.i6[0]; 207 oplist[osize++] = mask.i6[1]; 208 oplist[osize++] = mask.i6[2]; 209 oplist[osize++] = mask.i6[3]; 210 #endif 211 212 } else if (!strcasecmp(ops, "ip.p")) { 213 int p; 214 215 p = getproto(s); 216 if (p == -1) 217 goto parseerror; 218 oplist[osize++] = p; 219 220 } else if (!strcasecmp(ops, "tcp.flags")) { 221 u_32_t mask, flags; 222 char *delim; 223 224 delim = strchr(s, '/'); 225 if (delim != NULL) { 226 *delim++ = '\0'; 227 mask = tcpflags(delim); 228 } else { 229 mask = 0xff; 230 } 231 flags = tcpflags(s); 232 233 oplist[osize++] = flags; 234 oplist[osize++] = mask; 235 236 237 } else if (!strcasecmp(ops, "tcp.port") || 238 !strcasecmp(ops, "tcp.sport") || 239 !strcasecmp(ops, "tcp.dport") || 240 !strcasecmp(ops, "udp.port") || 241 !strcasecmp(ops, "udp.sport") || 242 !strcasecmp(ops, "udp.dport")) { 243 char proto[4]; 244 u_short port; 245 246 strncpy(proto, ops, 3); 247 proto[3] = '\0'; 248 if (getport(NULL, s, &port, proto) == -1) 249 goto parseerror; 250 oplist[osize++] = port; 251 252 } else if (!strcasecmp(ops, "tcp.state")) { 253 oplist[osize++] = atoi(s); 254 255 } else { 256 error = "unknown word"; 257 goto parseerror; 258 } 259 } 260 } 261 262 free(temp); 263 264 if (errorptr != NULL) 265 *errorptr = NULL; 266 267 for (i = asize; i > 0; i--) 268 oplist[i] = oplist[i - 1]; 269 270 oplist[0] = asize + 2; 271 oplist[asize + 1] = IPF_EXP_END; 272 273 return oplist; 274 275 parseerror: 276 if (errorptr != NULL) 277 *errorptr = error; 278 if (oplist != NULL) 279 free(oplist); 280 if (temp != NULL) 281 free(temp); 282 return NULL; 283 } 284