141edb306SCy Schubert #include "ipf.h" 241edb306SCy Schubert #include <ctype.h> 341edb306SCy Schubert 441edb306SCy Schubert 541edb306SCy Schubert typedef struct ipfopentry { 641edb306SCy Schubert int ipoe_cmd; 741edb306SCy Schubert int ipoe_nbasearg; 841edb306SCy Schubert int ipoe_maxarg; 941edb306SCy Schubert int ipoe_argsize; 1041edb306SCy Schubert char *ipoe_word; 1141edb306SCy Schubert } ipfopentry_t; 1241edb306SCy Schubert 1341edb306SCy Schubert static ipfopentry_t opwords[17] = { 1441edb306SCy Schubert { IPF_EXP_IP_ADDR, 2, 0, 1, "ip.addr" }, 1541edb306SCy Schubert { IPF_EXP_IP6_ADDR, 2, 0, 4, "ip6.addr" }, 1641edb306SCy Schubert { IPF_EXP_IP_PR, 1, 0, 1, "ip.p" }, 1741edb306SCy Schubert { IPF_EXP_IP_SRCADDR, 2, 0, 1, "ip.src" }, 1841edb306SCy Schubert { IPF_EXP_IP_DSTADDR, 2, 0, 1, "ip.dst" }, 1941edb306SCy Schubert { IPF_EXP_IP6_SRCADDR, 2, 0, 4, "ip6.src" }, 2041edb306SCy Schubert { IPF_EXP_IP6_DSTADDR, 2, 0, 4, "ip6.dst" }, 2141edb306SCy Schubert { IPF_EXP_TCP_PORT, 1, 0, 1, "tcp.port" }, 2241edb306SCy Schubert { IPF_EXP_TCP_DPORT, 1, 0, 1, "tcp.dport" }, 2341edb306SCy Schubert { IPF_EXP_TCP_SPORT, 1, 0, 1, "tcp.sport" }, 2441edb306SCy Schubert { IPF_EXP_TCP_FLAGS, 2, 0, 1, "tcp.flags" }, 2541edb306SCy Schubert { IPF_EXP_UDP_PORT, 1, 0, 1, "udp.port" }, 2641edb306SCy Schubert { IPF_EXP_UDP_DPORT, 1, 0, 1, "udp.dport" }, 2741edb306SCy Schubert { IPF_EXP_UDP_SPORT, 1, 0, 1, "udp.sport" }, 2841edb306SCy Schubert { IPF_EXP_TCP_STATE, 1, 0, 1, "tcp.state" }, 2941edb306SCy Schubert { IPF_EXP_IDLE_GT, 1, 1, 1, "idle-gt" }, 3041edb306SCy Schubert { -1, 0, 0, 0, NULL } 3141edb306SCy Schubert }; 3241edb306SCy Schubert 3341edb306SCy Schubert 3441edb306SCy Schubert int * 35*efeb8bffSCy Schubert parseipfexpr(char *line, char **errorptr) 3641edb306SCy Schubert { 3741edb306SCy Schubert int not, items, asize, *oplist, osize, i; 3841edb306SCy Schubert char *temp, *arg, *s, *t, *ops, *error; 3941edb306SCy Schubert ipfopentry_t *e; 4041edb306SCy Schubert ipfexp_t *ipfe; 4141edb306SCy Schubert 4241edb306SCy Schubert asize = 0; 4341edb306SCy Schubert error = NULL; 4441edb306SCy Schubert oplist = NULL; 4541edb306SCy Schubert 4641edb306SCy Schubert temp = strdup(line); 4741edb306SCy Schubert if (temp == NULL) { 4841edb306SCy Schubert error = "strdup failed"; 4941edb306SCy Schubert goto parseerror; 5041edb306SCy Schubert } 5141edb306SCy Schubert 5241edb306SCy Schubert /* 5341edb306SCy Schubert * Eliminate any white spaces to make parsing easier. 5441edb306SCy Schubert */ 5541edb306SCy Schubert for (s = temp; *s != '\0'; ) { 5641edb306SCy Schubert if (ISSPACE(*s)) 5741edb306SCy Schubert strcpy(s, s + 1); 5841edb306SCy Schubert else 5941edb306SCy Schubert s++; 6041edb306SCy Schubert } 6141edb306SCy Schubert 6241edb306SCy Schubert /* 6341edb306SCy Schubert * Parse the string. 6441edb306SCy Schubert * It should be sets of "ip.dst=1.2.3.4/32;" things. 6541edb306SCy Schubert * There must be a "=" or "!=" and it must end in ";". 6641edb306SCy Schubert */ 6741edb306SCy Schubert if (temp[strlen(temp) - 1] != ';') { 6841edb306SCy Schubert error = "last character not ';'"; 6941edb306SCy Schubert goto parseerror; 7041edb306SCy Schubert } 7141edb306SCy Schubert 7241edb306SCy Schubert /* 7341edb306SCy Schubert * Work through the list of complete operands present. 7441edb306SCy Schubert */ 7541edb306SCy Schubert for (ops = strtok(temp, ";"); ops != NULL; ops = strtok(NULL, ";")) { 7641edb306SCy Schubert arg = strchr(ops, '='); 7741edb306SCy Schubert if ((arg < ops + 2) || (arg == NULL)) { 7841edb306SCy Schubert error = "bad 'arg' vlaue"; 7941edb306SCy Schubert goto parseerror; 8041edb306SCy Schubert } 8141edb306SCy Schubert 8241edb306SCy Schubert if (*(arg - 1) == '!') { 8341edb306SCy Schubert *(arg - 1) = '\0'; 8441edb306SCy Schubert not = 1; 8541edb306SCy Schubert } else { 8641edb306SCy Schubert not = 0; 8741edb306SCy Schubert } 8841edb306SCy Schubert *arg++ = '\0'; 8941edb306SCy Schubert 9041edb306SCy Schubert 9141edb306SCy Schubert for (e = opwords; e->ipoe_word; e++) { 9241edb306SCy Schubert if (strcmp(ops, e->ipoe_word) == 0) 9341edb306SCy Schubert break; 9441edb306SCy Schubert } 9541edb306SCy Schubert if (e->ipoe_word == NULL) { 9641edb306SCy Schubert error = malloc(32); 9741edb306SCy Schubert if (error != NULL) { 9841edb306SCy Schubert snprintf(error, sizeof(error), "keyword (%.10s) not found", 9941edb306SCy Schubert ops); 10041edb306SCy Schubert } 10141edb306SCy Schubert goto parseerror; 10241edb306SCy Schubert } 10341edb306SCy Schubert 10441edb306SCy Schubert /* 10541edb306SCy Schubert * Count the number of commas so we know how big to 10641edb306SCy Schubert * build the array 10741edb306SCy Schubert */ 10841edb306SCy Schubert for (s = arg, items = 1; *s != '\0'; s++) 10941edb306SCy Schubert if (*s == ',') 11041edb306SCy Schubert items++; 11141edb306SCy Schubert 11241edb306SCy Schubert if ((e->ipoe_maxarg != 0) && (items > e->ipoe_maxarg)) { 11341edb306SCy Schubert error = "too many items"; 11441edb306SCy Schubert goto parseerror; 11541edb306SCy Schubert } 11641edb306SCy Schubert 11741edb306SCy Schubert /* 11841edb306SCy Schubert * osize will mark the end of where we have filled up to 11941edb306SCy Schubert * and is thus where we start putting new data. 12041edb306SCy Schubert */ 12141edb306SCy Schubert osize = asize; 12241edb306SCy Schubert asize += 4 + (items * e->ipoe_nbasearg * e->ipoe_argsize); 12341edb306SCy Schubert if (oplist == NULL) 12441edb306SCy Schubert oplist = calloc(asize + 2, sizeof(int)); 12541edb306SCy Schubert else 12641edb306SCy Schubert oplist = reallocarray(oplist, asize + 2, sizeof(int)); 12741edb306SCy Schubert if (oplist == NULL) { 12841edb306SCy Schubert error = "oplist alloc failed"; 12941edb306SCy Schubert goto parseerror; 13041edb306SCy Schubert } 13141edb306SCy Schubert ipfe = (ipfexp_t *)(oplist + osize); 13241edb306SCy Schubert osize += 4; 13341edb306SCy Schubert ipfe->ipfe_cmd = e->ipoe_cmd; 13441edb306SCy Schubert ipfe->ipfe_not = not; 13541edb306SCy Schubert ipfe->ipfe_narg = items * e->ipoe_nbasearg; 13641edb306SCy Schubert ipfe->ipfe_size = items * e->ipoe_nbasearg * e->ipoe_argsize; 13741edb306SCy Schubert ipfe->ipfe_size += 4; 13841edb306SCy Schubert 13941edb306SCy Schubert for (s = arg; (*s != '\0') && (osize < asize); s = t) { 14041edb306SCy Schubert /* 14141edb306SCy Schubert * Look for the end of this arg or the ',' to say 14241edb306SCy Schubert * there is another following. 14341edb306SCy Schubert */ 14441edb306SCy Schubert for (t = s; (*t != '\0') && (*t != ','); t++) 14541edb306SCy Schubert ; 14641edb306SCy Schubert if (*t == ',') 14741edb306SCy Schubert *t++ = '\0'; 14841edb306SCy Schubert 14941edb306SCy Schubert if (!strcasecmp(ops, "ip.addr") || 15041edb306SCy Schubert !strcasecmp(ops, "ip.src") || 15141edb306SCy Schubert !strcasecmp(ops, "ip.dst")) { 15241edb306SCy Schubert i6addr_t mask, addr; 15341edb306SCy Schubert char *delim; 15441edb306SCy Schubert 15541edb306SCy Schubert delim = strchr(s, '/'); 15641edb306SCy Schubert if (delim != NULL) { 15741edb306SCy Schubert *delim++ = '\0'; 15841edb306SCy Schubert if (genmask(AF_INET, delim, 15941edb306SCy Schubert &mask) == -1) { 16041edb306SCy Schubert error = "genmask failed"; 16141edb306SCy Schubert goto parseerror; 16241edb306SCy Schubert } 16341edb306SCy Schubert } else { 16441edb306SCy Schubert mask.in4.s_addr = 0xffffffff; 16541edb306SCy Schubert } 16641edb306SCy Schubert if (gethost(AF_INET, s, &addr) == -1) { 16741edb306SCy Schubert error = "gethost failed"; 16841edb306SCy Schubert goto parseerror; 16941edb306SCy Schubert } 17041edb306SCy Schubert 17141edb306SCy Schubert oplist[osize++] = addr.in4.s_addr; 17241edb306SCy Schubert oplist[osize++] = mask.in4.s_addr; 17341edb306SCy Schubert 17441edb306SCy Schubert #ifdef USE_INET6 17541edb306SCy Schubert } else if (!strcasecmp(ops, "ip6.addr") || 17641edb306SCy Schubert !strcasecmp(ops, "ip6.src") || 17741edb306SCy Schubert !strcasecmp(ops, "ip6.dst")) { 17841edb306SCy Schubert i6addr_t mask, addr; 17941edb306SCy Schubert char *delim; 18041edb306SCy Schubert 18141edb306SCy Schubert delim = strchr(s, '/'); 18241edb306SCy Schubert if (delim != NULL) { 18341edb306SCy Schubert *delim++ = '\0'; 18441edb306SCy Schubert if (genmask(AF_INET6, delim, 18541edb306SCy Schubert &mask) == -1) { 18641edb306SCy Schubert error = "genmask failed"; 18741edb306SCy Schubert goto parseerror; 18841edb306SCy Schubert } 18941edb306SCy Schubert } else { 19041edb306SCy Schubert mask.i6[0] = 0xffffffff; 19141edb306SCy Schubert mask.i6[1] = 0xffffffff; 19241edb306SCy Schubert mask.i6[2] = 0xffffffff; 19341edb306SCy Schubert mask.i6[3] = 0xffffffff; 19441edb306SCy Schubert } 19541edb306SCy Schubert if (gethost(AF_INET6, s, &addr) == -1) { 19641edb306SCy Schubert error = "gethost failed"; 19741edb306SCy Schubert goto parseerror; 19841edb306SCy Schubert } 19941edb306SCy Schubert 20041edb306SCy Schubert oplist[osize++] = addr.i6[0]; 20141edb306SCy Schubert oplist[osize++] = addr.i6[1]; 20241edb306SCy Schubert oplist[osize++] = addr.i6[2]; 20341edb306SCy Schubert oplist[osize++] = addr.i6[3]; 20441edb306SCy Schubert oplist[osize++] = mask.i6[0]; 20541edb306SCy Schubert oplist[osize++] = mask.i6[1]; 20641edb306SCy Schubert oplist[osize++] = mask.i6[2]; 20741edb306SCy Schubert oplist[osize++] = mask.i6[3]; 20841edb306SCy Schubert #endif 20941edb306SCy Schubert 21041edb306SCy Schubert } else if (!strcasecmp(ops, "ip.p")) { 21141edb306SCy Schubert int p; 21241edb306SCy Schubert 21341edb306SCy Schubert p = getproto(s); 21441edb306SCy Schubert if (p == -1) 21541edb306SCy Schubert goto parseerror; 21641edb306SCy Schubert oplist[osize++] = p; 21741edb306SCy Schubert 21841edb306SCy Schubert } else if (!strcasecmp(ops, "tcp.flags")) { 21941edb306SCy Schubert u_32_t mask, flags; 22041edb306SCy Schubert char *delim; 22141edb306SCy Schubert 22241edb306SCy Schubert delim = strchr(s, '/'); 22341edb306SCy Schubert if (delim != NULL) { 22441edb306SCy Schubert *delim++ = '\0'; 22541edb306SCy Schubert mask = tcpflags(delim); 22641edb306SCy Schubert } else { 22741edb306SCy Schubert mask = 0xff; 22841edb306SCy Schubert } 22941edb306SCy Schubert flags = tcpflags(s); 23041edb306SCy Schubert 23141edb306SCy Schubert oplist[osize++] = flags; 23241edb306SCy Schubert oplist[osize++] = mask; 23341edb306SCy Schubert 23441edb306SCy Schubert 23541edb306SCy Schubert } else if (!strcasecmp(ops, "tcp.port") || 23641edb306SCy Schubert !strcasecmp(ops, "tcp.sport") || 23741edb306SCy Schubert !strcasecmp(ops, "tcp.dport") || 23841edb306SCy Schubert !strcasecmp(ops, "udp.port") || 23941edb306SCy Schubert !strcasecmp(ops, "udp.sport") || 24041edb306SCy Schubert !strcasecmp(ops, "udp.dport")) { 24141edb306SCy Schubert char proto[4]; 24241edb306SCy Schubert u_short port; 24341edb306SCy Schubert 24441edb306SCy Schubert strncpy(proto, ops, 3); 24541edb306SCy Schubert proto[3] = '\0'; 24641edb306SCy Schubert if (getport(NULL, s, &port, proto) == -1) 24741edb306SCy Schubert goto parseerror; 24841edb306SCy Schubert oplist[osize++] = port; 24941edb306SCy Schubert 25041edb306SCy Schubert } else if (!strcasecmp(ops, "tcp.state")) { 25141edb306SCy Schubert oplist[osize++] = atoi(s); 25241edb306SCy Schubert 25341edb306SCy Schubert } else { 25441edb306SCy Schubert error = "unknown word"; 25541edb306SCy Schubert goto parseerror; 25641edb306SCy Schubert } 25741edb306SCy Schubert } 25841edb306SCy Schubert } 25941edb306SCy Schubert 26041edb306SCy Schubert free(temp); 26141edb306SCy Schubert 26241edb306SCy Schubert if (errorptr != NULL) 26341edb306SCy Schubert *errorptr = NULL; 26441edb306SCy Schubert 26541edb306SCy Schubert for (i = asize; i > 0; i--) 26641edb306SCy Schubert oplist[i] = oplist[i - 1]; 26741edb306SCy Schubert 26841edb306SCy Schubert oplist[0] = asize + 2; 26941edb306SCy Schubert oplist[asize + 1] = IPF_EXP_END; 27041edb306SCy Schubert 27141edb306SCy Schubert return oplist; 27241edb306SCy Schubert 27341edb306SCy Schubert parseerror: 27441edb306SCy Schubert if (errorptr != NULL) 27541edb306SCy Schubert *errorptr = error; 27641edb306SCy Schubert if (oplist != NULL) 27741edb306SCy Schubert free(oplist); 27841edb306SCy Schubert if (temp != NULL) 27941edb306SCy Schubert free(temp); 28041edb306SCy Schubert return NULL; 28141edb306SCy Schubert } 282