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