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' value"; 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 asprintf(&error, "keyword (%.10s) not found", ops); 97 goto parseerror; 98 } 99 100 /* 101 * Count the number of commas so we know how big to 102 * build the array 103 */ 104 for (s = arg, items = 1; *s != '\0'; s++) 105 if (*s == ',') 106 items++; 107 108 if ((e->ipoe_maxarg != 0) && (items > e->ipoe_maxarg)) { 109 error = "too many items"; 110 goto parseerror; 111 } 112 113 /* 114 * osize will mark the end of where we have filled up to 115 * and is thus where we start putting new data. 116 */ 117 osize = asize; 118 asize += 4 + (items * e->ipoe_nbasearg * e->ipoe_argsize); 119 if (oplist == NULL) 120 oplist = calloc(asize + 2, sizeof(int)); 121 else 122 oplist = reallocarray(oplist, asize + 2, sizeof(int)); 123 if (oplist == NULL) { 124 error = "oplist alloc failed"; 125 goto parseerror; 126 } 127 ipfe = (ipfexp_t *)(oplist + osize); 128 osize += 4; 129 ipfe->ipfe_cmd = e->ipoe_cmd; 130 ipfe->ipfe_not = not; 131 ipfe->ipfe_narg = items * e->ipoe_nbasearg; 132 ipfe->ipfe_size = items * e->ipoe_nbasearg * e->ipoe_argsize; 133 ipfe->ipfe_size += 4; 134 135 for (s = arg; (*s != '\0') && (osize < asize); s = t) { 136 /* 137 * Look for the end of this arg or the ',' to say 138 * there is another following. 139 */ 140 for (t = s; (*t != '\0') && (*t != ','); t++) 141 ; 142 if (*t == ',') 143 *t++ = '\0'; 144 145 if (!strcasecmp(ops, "ip.addr") || 146 !strcasecmp(ops, "ip.src") || 147 !strcasecmp(ops, "ip.dst")) { 148 i6addr_t mask, addr; 149 char *delim; 150 151 delim = strchr(s, '/'); 152 if (delim != NULL) { 153 *delim++ = '\0'; 154 if (genmask(AF_INET, delim, 155 &mask) == -1) { 156 error = "genmask failed"; 157 goto parseerror; 158 } 159 } else { 160 mask.in4.s_addr = 0xffffffff; 161 } 162 if (gethost(AF_INET, s, &addr) == -1) { 163 error = "gethost failed"; 164 goto parseerror; 165 } 166 167 oplist[osize++] = addr.in4.s_addr; 168 oplist[osize++] = mask.in4.s_addr; 169 170 #ifdef USE_INET6 171 } else if (!strcasecmp(ops, "ip6.addr") || 172 !strcasecmp(ops, "ip6.src") || 173 !strcasecmp(ops, "ip6.dst")) { 174 i6addr_t mask, addr; 175 char *delim; 176 177 delim = strchr(s, '/'); 178 if (delim != NULL) { 179 *delim++ = '\0'; 180 if (genmask(AF_INET6, delim, 181 &mask) == -1) { 182 error = "genmask failed"; 183 goto parseerror; 184 } 185 } else { 186 mask.i6[0] = 0xffffffff; 187 mask.i6[1] = 0xffffffff; 188 mask.i6[2] = 0xffffffff; 189 mask.i6[3] = 0xffffffff; 190 } 191 if (gethost(AF_INET6, s, &addr) == -1) { 192 error = "gethost failed"; 193 goto parseerror; 194 } 195 196 oplist[osize++] = addr.i6[0]; 197 oplist[osize++] = addr.i6[1]; 198 oplist[osize++] = addr.i6[2]; 199 oplist[osize++] = addr.i6[3]; 200 oplist[osize++] = mask.i6[0]; 201 oplist[osize++] = mask.i6[1]; 202 oplist[osize++] = mask.i6[2]; 203 oplist[osize++] = mask.i6[3]; 204 #endif 205 206 } else if (!strcasecmp(ops, "ip.p")) { 207 int p; 208 209 p = getproto(s); 210 if (p == -1) 211 goto parseerror; 212 oplist[osize++] = p; 213 214 } else if (!strcasecmp(ops, "tcp.flags")) { 215 u_32_t mask, flags; 216 char *delim; 217 218 delim = strchr(s, '/'); 219 if (delim != NULL) { 220 *delim++ = '\0'; 221 mask = tcpflags(delim); 222 } else { 223 mask = 0xff; 224 } 225 flags = tcpflags(s); 226 227 oplist[osize++] = flags; 228 oplist[osize++] = mask; 229 230 231 } else if (!strcasecmp(ops, "tcp.port") || 232 !strcasecmp(ops, "tcp.sport") || 233 !strcasecmp(ops, "tcp.dport") || 234 !strcasecmp(ops, "udp.port") || 235 !strcasecmp(ops, "udp.sport") || 236 !strcasecmp(ops, "udp.dport")) { 237 char proto[4]; 238 u_short port; 239 240 strncpy(proto, ops, 3); 241 proto[3] = '\0'; 242 if (getport(NULL, s, &port, proto) == -1) 243 goto parseerror; 244 oplist[osize++] = port; 245 246 } else if (!strcasecmp(ops, "tcp.state")) { 247 oplist[osize++] = atoi(s); 248 249 } else { 250 error = "unknown word"; 251 goto parseerror; 252 } 253 } 254 } 255 256 free(temp); 257 258 if (errorptr != NULL) 259 *errorptr = NULL; 260 261 for (i = asize; i > 0; i--) 262 oplist[i] = oplist[i - 1]; 263 264 oplist[0] = asize + 2; 265 oplist[asize + 1] = IPF_EXP_END; 266 267 return (oplist); 268 269 parseerror: 270 if (errorptr != NULL) 271 *errorptr = error; 272 if (oplist != NULL) 273 free(oplist); 274 if (temp != NULL) 275 free(temp); 276 return (NULL); 277 } 278