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(char *line, char **errorptr) 36 { 37 int not, items, asize, *oplist, osize, i; 38 char *temp, *arg, *s, *t, *ops, *error; 39 ipfopentry_t *e; 40 ipfexp_t *ipfe; 41 42 asize = 0; 43 error = NULL; 44 oplist = NULL; 45 46 temp = strdup(line); 47 if (temp == NULL) { 48 error = "strdup failed"; 49 goto parseerror; 50 } 51 52 /* 53 * Eliminate any white spaces to make parsing easier. 54 */ 55 for (s = temp; *s != '\0'; ) { 56 if (ISSPACE(*s)) 57 strcpy(s, s + 1); 58 else 59 s++; 60 } 61 62 /* 63 * Parse the string. 64 * It should be sets of "ip.dst=1.2.3.4/32;" things. 65 * There must be a "=" or "!=" and it must end in ";". 66 */ 67 if (temp[strlen(temp) - 1] != ';') { 68 error = "last character not ';'"; 69 goto parseerror; 70 } 71 72 /* 73 * Work through the list of complete operands present. 74 */ 75 for (ops = strtok(temp, ";"); ops != NULL; ops = strtok(NULL, ";")) { 76 arg = strchr(ops, '='); 77 if ((arg < ops + 2) || (arg == NULL)) { 78 error = "bad 'arg' vlaue"; 79 goto parseerror; 80 } 81 82 if (*(arg - 1) == '!') { 83 *(arg - 1) = '\0'; 84 not = 1; 85 } else { 86 not = 0; 87 } 88 *arg++ = '\0'; 89 90 91 for (e = opwords; e->ipoe_word; e++) { 92 if (strcmp(ops, e->ipoe_word) == 0) 93 break; 94 } 95 if (e->ipoe_word == NULL) { 96 error = malloc(32); 97 if (error != NULL) { 98 snprintf(error, sizeof(error), "keyword (%.10s) not found", 99 ops); 100 } 101 goto parseerror; 102 } 103 104 /* 105 * Count the number of commas so we know how big to 106 * build the array 107 */ 108 for (s = arg, items = 1; *s != '\0'; s++) 109 if (*s == ',') 110 items++; 111 112 if ((e->ipoe_maxarg != 0) && (items > e->ipoe_maxarg)) { 113 error = "too many items"; 114 goto parseerror; 115 } 116 117 /* 118 * osize will mark the end of where we have filled up to 119 * and is thus where we start putting new data. 120 */ 121 osize = asize; 122 asize += 4 + (items * e->ipoe_nbasearg * e->ipoe_argsize); 123 if (oplist == NULL) 124 oplist = calloc(asize + 2, sizeof(int)); 125 else 126 oplist = reallocarray(oplist, asize + 2, sizeof(int)); 127 if (oplist == NULL) { 128 error = "oplist alloc failed"; 129 goto parseerror; 130 } 131 ipfe = (ipfexp_t *)(oplist + osize); 132 osize += 4; 133 ipfe->ipfe_cmd = e->ipoe_cmd; 134 ipfe->ipfe_not = not; 135 ipfe->ipfe_narg = items * e->ipoe_nbasearg; 136 ipfe->ipfe_size = items * e->ipoe_nbasearg * e->ipoe_argsize; 137 ipfe->ipfe_size += 4; 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