1254219Scy#include "ipf.h" 2254219Scy#include <ctype.h> 3254219Scy 4254219Scy 5254219Scytypedef struct ipfopentry { 6254219Scy int ipoe_cmd; 7254219Scy int ipoe_nbasearg; 8254219Scy int ipoe_maxarg; 9254219Scy int ipoe_argsize; 10254219Scy char *ipoe_word; 11254219Scy} ipfopentry_t; 12254219Scy 13254219Scystatic ipfopentry_t opwords[17] = { 14254219Scy { IPF_EXP_IP_ADDR, 2, 0, 1, "ip.addr" }, 15254219Scy { IPF_EXP_IP6_ADDR, 2, 0, 4, "ip6.addr" }, 16254219Scy { IPF_EXP_IP_PR, 1, 0, 1, "ip.p" }, 17254219Scy { IPF_EXP_IP_SRCADDR, 2, 0, 1, "ip.src" }, 18254219Scy { IPF_EXP_IP_DSTADDR, 2, 0, 1, "ip.dst" }, 19254219Scy { IPF_EXP_IP6_SRCADDR, 2, 0, 4, "ip6.src" }, 20254219Scy { IPF_EXP_IP6_DSTADDR, 2, 0, 4, "ip6.dst" }, 21254219Scy { IPF_EXP_TCP_PORT, 1, 0, 1, "tcp.port" }, 22254219Scy { IPF_EXP_TCP_DPORT, 1, 0, 1, "tcp.dport" }, 23254219Scy { IPF_EXP_TCP_SPORT, 1, 0, 1, "tcp.sport" }, 24254219Scy { IPF_EXP_TCP_FLAGS, 2, 0, 1, "tcp.flags" }, 25254219Scy { IPF_EXP_UDP_PORT, 1, 0, 1, "udp.port" }, 26254219Scy { IPF_EXP_UDP_DPORT, 1, 0, 1, "udp.dport" }, 27254219Scy { IPF_EXP_UDP_SPORT, 1, 0, 1, "udp.sport" }, 28254219Scy { IPF_EXP_TCP_STATE, 1, 0, 1, "tcp.state" }, 29254219Scy { IPF_EXP_IDLE_GT, 1, 1, 1, "idle-gt" }, 30254219Scy { -1, 0, 0, 0, NULL } 31254219Scy}; 32254219Scy 33254219Scy 34254219Scyint * 35254219Scyparseipfexpr(line, errorptr) 36254219Scy char *line; 37254219Scy char **errorptr; 38254219Scy{ 39254219Scy int not, items, asize, *oplist, osize, i; 40254219Scy char *temp, *arg, *s, *t, *ops, *error; 41254219Scy ipfopentry_t *e; 42254219Scy ipfexp_t *ipfe; 43254219Scy 44254219Scy asize = 0; 45254219Scy error = NULL; 46254219Scy oplist = NULL; 47254219Scy 48254219Scy temp = strdup(line); 49254219Scy if (temp == NULL) { 50254219Scy error = "strdup failed"; 51254219Scy goto parseerror; 52254219Scy } 53254219Scy 54254219Scy /* 55254219Scy * Eliminate any white spaces to make parsing easier. 56254219Scy */ 57254219Scy for (s = temp; *s != '\0'; ) { 58254219Scy if (ISSPACE(*s)) 59254219Scy strcpy(s, s + 1); 60254219Scy else 61254219Scy s++; 62254219Scy } 63254219Scy 64254219Scy /* 65254219Scy * Parse the string. 66254219Scy * It should be sets of "ip.dst=1.2.3.4/32;" things. 67254219Scy * There must be a "=" or "!=" and it must end in ";". 68254219Scy */ 69254219Scy if (temp[strlen(temp) - 1] != ';') { 70254219Scy error = "last character not ';'"; 71254219Scy goto parseerror; 72254219Scy } 73254219Scy 74254219Scy /* 75254219Scy * Work through the list of complete operands present. 76254219Scy */ 77254219Scy for (ops = strtok(temp, ";"); ops != NULL; ops = strtok(NULL, ";")) { 78254219Scy arg = strchr(ops, '='); 79254219Scy if ((arg < ops + 2) || (arg == NULL)) { 80254219Scy error = "bad 'arg' vlaue"; 81254219Scy goto parseerror; 82254219Scy } 83254219Scy 84254219Scy if (*(arg - 1) == '!') { 85254219Scy *(arg - 1) = '\0'; 86254219Scy not = 1; 87254219Scy } else { 88254219Scy not = 0; 89254219Scy } 90254219Scy *arg++ = '\0'; 91254219Scy 92254219Scy 93254219Scy for (e = opwords; e->ipoe_word; e++) { 94254219Scy if (strcmp(ops, e->ipoe_word) == 0) 95254219Scy break; 96254219Scy } 97254219Scy if (e->ipoe_word == NULL) { 98254219Scy error = malloc(32); 99254219Scy if (error != NULL) { 100254219Scy sprintf(error, "keyword (%.10s) not found", 101254219Scy ops); 102254219Scy } 103254219Scy goto parseerror; 104254219Scy } 105254219Scy 106254219Scy /* 107254219Scy * Count the number of commas so we know how big to 108254219Scy * build the array 109254219Scy */ 110254219Scy for (s = arg, items = 1; *s != '\0'; s++) 111254219Scy if (*s == ',') 112254219Scy items++; 113254219Scy 114254219Scy if ((e->ipoe_maxarg != 0) && (items > e->ipoe_maxarg)) { 115254219Scy error = "too many items"; 116254219Scy goto parseerror; 117254219Scy } 118254219Scy 119254219Scy /* 120254219Scy * osize will mark the end of where we have filled up to 121254219Scy * and is thus where we start putting new data. 122254219Scy */ 123254219Scy osize = asize; 124254219Scy asize += 4 + (items * e->ipoe_nbasearg * e->ipoe_argsize); 125254219Scy if (oplist == NULL) 126254219Scy oplist = calloc(1, sizeof(int) * (asize + 2)); 127254219Scy else 128254219Scy oplist = realloc(oplist, sizeof(int) * (asize + 2)); 129254219Scy if (oplist == NULL) { 130254219Scy error = "oplist alloc failed"; 131254219Scy goto parseerror; 132254219Scy } 133254219Scy ipfe = (ipfexp_t *)(oplist + osize); 134254219Scy osize += 4; 135254219Scy ipfe->ipfe_cmd = e->ipoe_cmd; 136254219Scy ipfe->ipfe_not = not; 137254219Scy ipfe->ipfe_narg = items * e->ipoe_nbasearg; 138254219Scy ipfe->ipfe_size = items * e->ipoe_nbasearg * e->ipoe_argsize; 139254219Scy ipfe->ipfe_size += 4; 140254219Scy 141254219Scy for (s = arg; (*s != '\0') && (osize < asize); s = t) { 142254219Scy /* 143254219Scy * Look for the end of this arg or the ',' to say 144254219Scy * there is another following. 145254219Scy */ 146254219Scy for (t = s; (*t != '\0') && (*t != ','); t++) 147254219Scy ; 148254219Scy if (*t == ',') 149254219Scy *t++ = '\0'; 150254219Scy 151254219Scy if (!strcasecmp(ops, "ip.addr") || 152254219Scy !strcasecmp(ops, "ip.src") || 153254219Scy !strcasecmp(ops, "ip.dst")) { 154254219Scy i6addr_t mask, addr; 155254219Scy char *delim; 156254219Scy 157254219Scy delim = strchr(s, '/'); 158254219Scy if (delim != NULL) { 159254219Scy *delim++ = '\0'; 160254219Scy if (genmask(AF_INET, delim, 161254219Scy &mask) == -1) { 162254219Scy error = "genmask failed"; 163254219Scy goto parseerror; 164254219Scy } 165254219Scy } else { 166254219Scy mask.in4.s_addr = 0xffffffff; 167254219Scy } 168254219Scy if (gethost(AF_INET, s, &addr) == -1) { 169254219Scy error = "gethost failed"; 170254219Scy goto parseerror; 171254219Scy } 172254219Scy 173254219Scy oplist[osize++] = addr.in4.s_addr; 174254219Scy oplist[osize++] = mask.in4.s_addr; 175254219Scy 176254219Scy#ifdef USE_INET6 177254219Scy } else if (!strcasecmp(ops, "ip6.addr") || 178254219Scy !strcasecmp(ops, "ip6.src") || 179254219Scy !strcasecmp(ops, "ip6.dst")) { 180254219Scy i6addr_t mask, addr; 181254219Scy char *delim; 182254219Scy 183254219Scy delim = strchr(s, '/'); 184254219Scy if (delim != NULL) { 185254219Scy *delim++ = '\0'; 186254219Scy if (genmask(AF_INET6, delim, 187254219Scy &mask) == -1) { 188254219Scy error = "genmask failed"; 189254219Scy goto parseerror; 190254219Scy } 191254219Scy } else { 192254219Scy mask.i6[0] = 0xffffffff; 193254219Scy mask.i6[1] = 0xffffffff; 194254219Scy mask.i6[2] = 0xffffffff; 195254219Scy mask.i6[3] = 0xffffffff; 196254219Scy } 197254219Scy if (gethost(AF_INET6, s, &addr) == -1) { 198254219Scy error = "gethost failed"; 199254219Scy goto parseerror; 200254219Scy } 201254219Scy 202254219Scy oplist[osize++] = addr.i6[0]; 203254219Scy oplist[osize++] = addr.i6[1]; 204254219Scy oplist[osize++] = addr.i6[2]; 205254219Scy oplist[osize++] = addr.i6[3]; 206254219Scy oplist[osize++] = mask.i6[0]; 207254219Scy oplist[osize++] = mask.i6[1]; 208254219Scy oplist[osize++] = mask.i6[2]; 209254219Scy oplist[osize++] = mask.i6[3]; 210254219Scy#endif 211254219Scy 212254219Scy } else if (!strcasecmp(ops, "ip.p")) { 213254219Scy int p; 214254219Scy 215254219Scy p = getproto(s); 216254219Scy if (p == -1) 217254219Scy goto parseerror; 218254219Scy oplist[osize++] = p; 219254219Scy 220254219Scy } else if (!strcasecmp(ops, "tcp.flags")) { 221254219Scy u_32_t mask, flags; 222254219Scy char *delim; 223254219Scy 224254219Scy delim = strchr(s, '/'); 225254219Scy if (delim != NULL) { 226254219Scy *delim++ = '\0'; 227254219Scy mask = tcpflags(delim); 228254219Scy } else { 229254219Scy mask = 0xff; 230254219Scy } 231254219Scy flags = tcpflags(s); 232254219Scy 233254219Scy oplist[osize++] = flags; 234254219Scy oplist[osize++] = mask; 235254219Scy 236254219Scy 237254219Scy } else if (!strcasecmp(ops, "tcp.port") || 238254219Scy !strcasecmp(ops, "tcp.sport") || 239254219Scy !strcasecmp(ops, "tcp.dport") || 240254219Scy !strcasecmp(ops, "udp.port") || 241254219Scy !strcasecmp(ops, "udp.sport") || 242254219Scy !strcasecmp(ops, "udp.dport")) { 243254219Scy char proto[4]; 244254219Scy u_short port; 245254219Scy 246254219Scy strncpy(proto, ops, 3); 247254219Scy proto[3] = '\0'; 248254219Scy if (getport(NULL, s, &port, proto) == -1) 249254219Scy goto parseerror; 250254219Scy oplist[osize++] = port; 251254219Scy 252254219Scy } else if (!strcasecmp(ops, "tcp.state")) { 253254219Scy oplist[osize++] = atoi(s); 254254219Scy 255254219Scy } else { 256254219Scy error = "unknown word"; 257254219Scy goto parseerror; 258254219Scy } 259254219Scy } 260254219Scy } 261254219Scy 262254219Scy free(temp); 263254219Scy 264254219Scy if (errorptr != NULL) 265254219Scy *errorptr = NULL; 266254219Scy 267254219Scy for (i = asize; i > 0; i--) 268254219Scy oplist[i] = oplist[i - 1]; 269254219Scy 270254219Scy oplist[0] = asize + 2; 271254219Scy oplist[asize + 1] = IPF_EXP_END; 272254219Scy 273254219Scy return oplist; 274254219Scy 275254219Scyparseerror: 276254219Scy if (errorptr != NULL) 277254219Scy *errorptr = error; 278254219Scy if (oplist != NULL) 279254219Scy free(oplist); 280254219Scy if (temp != NULL) 281254219Scy free(temp); 282254219Scy return NULL; 283254219Scy} 284