1*41edb306SCy Schubert #include "ipf.h" 2*41edb306SCy Schubert #include <ctype.h> 3*41edb306SCy Schubert 4*41edb306SCy Schubert 5*41edb306SCy Schubert typedef struct ipfopentry { 6*41edb306SCy Schubert int ipoe_cmd; 7*41edb306SCy Schubert int ipoe_nbasearg; 8*41edb306SCy Schubert int ipoe_maxarg; 9*41edb306SCy Schubert int ipoe_argsize; 10*41edb306SCy Schubert char *ipoe_word; 11*41edb306SCy Schubert } ipfopentry_t; 12*41edb306SCy Schubert 13*41edb306SCy Schubert static ipfopentry_t opwords[17] = { 14*41edb306SCy Schubert { IPF_EXP_IP_ADDR, 2, 0, 1, "ip.addr" }, 15*41edb306SCy Schubert { IPF_EXP_IP6_ADDR, 2, 0, 4, "ip6.addr" }, 16*41edb306SCy Schubert { IPF_EXP_IP_PR, 1, 0, 1, "ip.p" }, 17*41edb306SCy Schubert { IPF_EXP_IP_SRCADDR, 2, 0, 1, "ip.src" }, 18*41edb306SCy Schubert { IPF_EXP_IP_DSTADDR, 2, 0, 1, "ip.dst" }, 19*41edb306SCy Schubert { IPF_EXP_IP6_SRCADDR, 2, 0, 4, "ip6.src" }, 20*41edb306SCy Schubert { IPF_EXP_IP6_DSTADDR, 2, 0, 4, "ip6.dst" }, 21*41edb306SCy Schubert { IPF_EXP_TCP_PORT, 1, 0, 1, "tcp.port" }, 22*41edb306SCy Schubert { IPF_EXP_TCP_DPORT, 1, 0, 1, "tcp.dport" }, 23*41edb306SCy Schubert { IPF_EXP_TCP_SPORT, 1, 0, 1, "tcp.sport" }, 24*41edb306SCy Schubert { IPF_EXP_TCP_FLAGS, 2, 0, 1, "tcp.flags" }, 25*41edb306SCy Schubert { IPF_EXP_UDP_PORT, 1, 0, 1, "udp.port" }, 26*41edb306SCy Schubert { IPF_EXP_UDP_DPORT, 1, 0, 1, "udp.dport" }, 27*41edb306SCy Schubert { IPF_EXP_UDP_SPORT, 1, 0, 1, "udp.sport" }, 28*41edb306SCy Schubert { IPF_EXP_TCP_STATE, 1, 0, 1, "tcp.state" }, 29*41edb306SCy Schubert { IPF_EXP_IDLE_GT, 1, 1, 1, "idle-gt" }, 30*41edb306SCy Schubert { -1, 0, 0, 0, NULL } 31*41edb306SCy Schubert }; 32*41edb306SCy Schubert 33*41edb306SCy Schubert 34*41edb306SCy Schubert int * 35*41edb306SCy Schubert parseipfexpr(line, errorptr) 36*41edb306SCy Schubert char *line; 37*41edb306SCy Schubert char **errorptr; 38*41edb306SCy Schubert { 39*41edb306SCy Schubert int not, items, asize, *oplist, osize, i; 40*41edb306SCy Schubert char *temp, *arg, *s, *t, *ops, *error; 41*41edb306SCy Schubert ipfopentry_t *e; 42*41edb306SCy Schubert ipfexp_t *ipfe; 43*41edb306SCy Schubert 44*41edb306SCy Schubert asize = 0; 45*41edb306SCy Schubert error = NULL; 46*41edb306SCy Schubert oplist = NULL; 47*41edb306SCy Schubert 48*41edb306SCy Schubert temp = strdup(line); 49*41edb306SCy Schubert if (temp == NULL) { 50*41edb306SCy Schubert error = "strdup failed"; 51*41edb306SCy Schubert goto parseerror; 52*41edb306SCy Schubert } 53*41edb306SCy Schubert 54*41edb306SCy Schubert /* 55*41edb306SCy Schubert * Eliminate any white spaces to make parsing easier. 56*41edb306SCy Schubert */ 57*41edb306SCy Schubert for (s = temp; *s != '\0'; ) { 58*41edb306SCy Schubert if (ISSPACE(*s)) 59*41edb306SCy Schubert strcpy(s, s + 1); 60*41edb306SCy Schubert else 61*41edb306SCy Schubert s++; 62*41edb306SCy Schubert } 63*41edb306SCy Schubert 64*41edb306SCy Schubert /* 65*41edb306SCy Schubert * Parse the string. 66*41edb306SCy Schubert * It should be sets of "ip.dst=1.2.3.4/32;" things. 67*41edb306SCy Schubert * There must be a "=" or "!=" and it must end in ";". 68*41edb306SCy Schubert */ 69*41edb306SCy Schubert if (temp[strlen(temp) - 1] != ';') { 70*41edb306SCy Schubert error = "last character not ';'"; 71*41edb306SCy Schubert goto parseerror; 72*41edb306SCy Schubert } 73*41edb306SCy Schubert 74*41edb306SCy Schubert /* 75*41edb306SCy Schubert * Work through the list of complete operands present. 76*41edb306SCy Schubert */ 77*41edb306SCy Schubert for (ops = strtok(temp, ";"); ops != NULL; ops = strtok(NULL, ";")) { 78*41edb306SCy Schubert arg = strchr(ops, '='); 79*41edb306SCy Schubert if ((arg < ops + 2) || (arg == NULL)) { 80*41edb306SCy Schubert error = "bad 'arg' vlaue"; 81*41edb306SCy Schubert goto parseerror; 82*41edb306SCy Schubert } 83*41edb306SCy Schubert 84*41edb306SCy Schubert if (*(arg - 1) == '!') { 85*41edb306SCy Schubert *(arg - 1) = '\0'; 86*41edb306SCy Schubert not = 1; 87*41edb306SCy Schubert } else { 88*41edb306SCy Schubert not = 0; 89*41edb306SCy Schubert } 90*41edb306SCy Schubert *arg++ = '\0'; 91*41edb306SCy Schubert 92*41edb306SCy Schubert 93*41edb306SCy Schubert for (e = opwords; e->ipoe_word; e++) { 94*41edb306SCy Schubert if (strcmp(ops, e->ipoe_word) == 0) 95*41edb306SCy Schubert break; 96*41edb306SCy Schubert } 97*41edb306SCy Schubert if (e->ipoe_word == NULL) { 98*41edb306SCy Schubert error = malloc(32); 99*41edb306SCy Schubert if (error != NULL) { 100*41edb306SCy Schubert snprintf(error, sizeof(error), "keyword (%.10s) not found", 101*41edb306SCy Schubert ops); 102*41edb306SCy Schubert } 103*41edb306SCy Schubert goto parseerror; 104*41edb306SCy Schubert } 105*41edb306SCy Schubert 106*41edb306SCy Schubert /* 107*41edb306SCy Schubert * Count the number of commas so we know how big to 108*41edb306SCy Schubert * build the array 109*41edb306SCy Schubert */ 110*41edb306SCy Schubert for (s = arg, items = 1; *s != '\0'; s++) 111*41edb306SCy Schubert if (*s == ',') 112*41edb306SCy Schubert items++; 113*41edb306SCy Schubert 114*41edb306SCy Schubert if ((e->ipoe_maxarg != 0) && (items > e->ipoe_maxarg)) { 115*41edb306SCy Schubert error = "too many items"; 116*41edb306SCy Schubert goto parseerror; 117*41edb306SCy Schubert } 118*41edb306SCy Schubert 119*41edb306SCy Schubert /* 120*41edb306SCy Schubert * osize will mark the end of where we have filled up to 121*41edb306SCy Schubert * and is thus where we start putting new data. 122*41edb306SCy Schubert */ 123*41edb306SCy Schubert osize = asize; 124*41edb306SCy Schubert asize += 4 + (items * e->ipoe_nbasearg * e->ipoe_argsize); 125*41edb306SCy Schubert if (oplist == NULL) 126*41edb306SCy Schubert oplist = calloc(asize + 2, sizeof(int)); 127*41edb306SCy Schubert else 128*41edb306SCy Schubert oplist = reallocarray(oplist, asize + 2, sizeof(int)); 129*41edb306SCy Schubert if (oplist == NULL) { 130*41edb306SCy Schubert error = "oplist alloc failed"; 131*41edb306SCy Schubert goto parseerror; 132*41edb306SCy Schubert } 133*41edb306SCy Schubert ipfe = (ipfexp_t *)(oplist + osize); 134*41edb306SCy Schubert osize += 4; 135*41edb306SCy Schubert ipfe->ipfe_cmd = e->ipoe_cmd; 136*41edb306SCy Schubert ipfe->ipfe_not = not; 137*41edb306SCy Schubert ipfe->ipfe_narg = items * e->ipoe_nbasearg; 138*41edb306SCy Schubert ipfe->ipfe_size = items * e->ipoe_nbasearg * e->ipoe_argsize; 139*41edb306SCy Schubert ipfe->ipfe_size += 4; 140*41edb306SCy Schubert 141*41edb306SCy Schubert for (s = arg; (*s != '\0') && (osize < asize); s = t) { 142*41edb306SCy Schubert /* 143*41edb306SCy Schubert * Look for the end of this arg or the ',' to say 144*41edb306SCy Schubert * there is another following. 145*41edb306SCy Schubert */ 146*41edb306SCy Schubert for (t = s; (*t != '\0') && (*t != ','); t++) 147*41edb306SCy Schubert ; 148*41edb306SCy Schubert if (*t == ',') 149*41edb306SCy Schubert *t++ = '\0'; 150*41edb306SCy Schubert 151*41edb306SCy Schubert if (!strcasecmp(ops, "ip.addr") || 152*41edb306SCy Schubert !strcasecmp(ops, "ip.src") || 153*41edb306SCy Schubert !strcasecmp(ops, "ip.dst")) { 154*41edb306SCy Schubert i6addr_t mask, addr; 155*41edb306SCy Schubert char *delim; 156*41edb306SCy Schubert 157*41edb306SCy Schubert delim = strchr(s, '/'); 158*41edb306SCy Schubert if (delim != NULL) { 159*41edb306SCy Schubert *delim++ = '\0'; 160*41edb306SCy Schubert if (genmask(AF_INET, delim, 161*41edb306SCy Schubert &mask) == -1) { 162*41edb306SCy Schubert error = "genmask failed"; 163*41edb306SCy Schubert goto parseerror; 164*41edb306SCy Schubert } 165*41edb306SCy Schubert } else { 166*41edb306SCy Schubert mask.in4.s_addr = 0xffffffff; 167*41edb306SCy Schubert } 168*41edb306SCy Schubert if (gethost(AF_INET, s, &addr) == -1) { 169*41edb306SCy Schubert error = "gethost failed"; 170*41edb306SCy Schubert goto parseerror; 171*41edb306SCy Schubert } 172*41edb306SCy Schubert 173*41edb306SCy Schubert oplist[osize++] = addr.in4.s_addr; 174*41edb306SCy Schubert oplist[osize++] = mask.in4.s_addr; 175*41edb306SCy Schubert 176*41edb306SCy Schubert #ifdef USE_INET6 177*41edb306SCy Schubert } else if (!strcasecmp(ops, "ip6.addr") || 178*41edb306SCy Schubert !strcasecmp(ops, "ip6.src") || 179*41edb306SCy Schubert !strcasecmp(ops, "ip6.dst")) { 180*41edb306SCy Schubert i6addr_t mask, addr; 181*41edb306SCy Schubert char *delim; 182*41edb306SCy Schubert 183*41edb306SCy Schubert delim = strchr(s, '/'); 184*41edb306SCy Schubert if (delim != NULL) { 185*41edb306SCy Schubert *delim++ = '\0'; 186*41edb306SCy Schubert if (genmask(AF_INET6, delim, 187*41edb306SCy Schubert &mask) == -1) { 188*41edb306SCy Schubert error = "genmask failed"; 189*41edb306SCy Schubert goto parseerror; 190*41edb306SCy Schubert } 191*41edb306SCy Schubert } else { 192*41edb306SCy Schubert mask.i6[0] = 0xffffffff; 193*41edb306SCy Schubert mask.i6[1] = 0xffffffff; 194*41edb306SCy Schubert mask.i6[2] = 0xffffffff; 195*41edb306SCy Schubert mask.i6[3] = 0xffffffff; 196*41edb306SCy Schubert } 197*41edb306SCy Schubert if (gethost(AF_INET6, s, &addr) == -1) { 198*41edb306SCy Schubert error = "gethost failed"; 199*41edb306SCy Schubert goto parseerror; 200*41edb306SCy Schubert } 201*41edb306SCy Schubert 202*41edb306SCy Schubert oplist[osize++] = addr.i6[0]; 203*41edb306SCy Schubert oplist[osize++] = addr.i6[1]; 204*41edb306SCy Schubert oplist[osize++] = addr.i6[2]; 205*41edb306SCy Schubert oplist[osize++] = addr.i6[3]; 206*41edb306SCy Schubert oplist[osize++] = mask.i6[0]; 207*41edb306SCy Schubert oplist[osize++] = mask.i6[1]; 208*41edb306SCy Schubert oplist[osize++] = mask.i6[2]; 209*41edb306SCy Schubert oplist[osize++] = mask.i6[3]; 210*41edb306SCy Schubert #endif 211*41edb306SCy Schubert 212*41edb306SCy Schubert } else if (!strcasecmp(ops, "ip.p")) { 213*41edb306SCy Schubert int p; 214*41edb306SCy Schubert 215*41edb306SCy Schubert p = getproto(s); 216*41edb306SCy Schubert if (p == -1) 217*41edb306SCy Schubert goto parseerror; 218*41edb306SCy Schubert oplist[osize++] = p; 219*41edb306SCy Schubert 220*41edb306SCy Schubert } else if (!strcasecmp(ops, "tcp.flags")) { 221*41edb306SCy Schubert u_32_t mask, flags; 222*41edb306SCy Schubert char *delim; 223*41edb306SCy Schubert 224*41edb306SCy Schubert delim = strchr(s, '/'); 225*41edb306SCy Schubert if (delim != NULL) { 226*41edb306SCy Schubert *delim++ = '\0'; 227*41edb306SCy Schubert mask = tcpflags(delim); 228*41edb306SCy Schubert } else { 229*41edb306SCy Schubert mask = 0xff; 230*41edb306SCy Schubert } 231*41edb306SCy Schubert flags = tcpflags(s); 232*41edb306SCy Schubert 233*41edb306SCy Schubert oplist[osize++] = flags; 234*41edb306SCy Schubert oplist[osize++] = mask; 235*41edb306SCy Schubert 236*41edb306SCy Schubert 237*41edb306SCy Schubert } else if (!strcasecmp(ops, "tcp.port") || 238*41edb306SCy Schubert !strcasecmp(ops, "tcp.sport") || 239*41edb306SCy Schubert !strcasecmp(ops, "tcp.dport") || 240*41edb306SCy Schubert !strcasecmp(ops, "udp.port") || 241*41edb306SCy Schubert !strcasecmp(ops, "udp.sport") || 242*41edb306SCy Schubert !strcasecmp(ops, "udp.dport")) { 243*41edb306SCy Schubert char proto[4]; 244*41edb306SCy Schubert u_short port; 245*41edb306SCy Schubert 246*41edb306SCy Schubert strncpy(proto, ops, 3); 247*41edb306SCy Schubert proto[3] = '\0'; 248*41edb306SCy Schubert if (getport(NULL, s, &port, proto) == -1) 249*41edb306SCy Schubert goto parseerror; 250*41edb306SCy Schubert oplist[osize++] = port; 251*41edb306SCy Schubert 252*41edb306SCy Schubert } else if (!strcasecmp(ops, "tcp.state")) { 253*41edb306SCy Schubert oplist[osize++] = atoi(s); 254*41edb306SCy Schubert 255*41edb306SCy Schubert } else { 256*41edb306SCy Schubert error = "unknown word"; 257*41edb306SCy Schubert goto parseerror; 258*41edb306SCy Schubert } 259*41edb306SCy Schubert } 260*41edb306SCy Schubert } 261*41edb306SCy Schubert 262*41edb306SCy Schubert free(temp); 263*41edb306SCy Schubert 264*41edb306SCy Schubert if (errorptr != NULL) 265*41edb306SCy Schubert *errorptr = NULL; 266*41edb306SCy Schubert 267*41edb306SCy Schubert for (i = asize; i > 0; i--) 268*41edb306SCy Schubert oplist[i] = oplist[i - 1]; 269*41edb306SCy Schubert 270*41edb306SCy Schubert oplist[0] = asize + 2; 271*41edb306SCy Schubert oplist[asize + 1] = IPF_EXP_END; 272*41edb306SCy Schubert 273*41edb306SCy Schubert return oplist; 274*41edb306SCy Schubert 275*41edb306SCy Schubert parseerror: 276*41edb306SCy Schubert if (errorptr != NULL) 277*41edb306SCy Schubert *errorptr = error; 278*41edb306SCy Schubert if (oplist != NULL) 279*41edb306SCy Schubert free(oplist); 280*41edb306SCy Schubert if (temp != NULL) 281*41edb306SCy Schubert free(temp); 282*41edb306SCy Schubert return NULL; 283*41edb306SCy Schubert } 284