xref: /freebsd/sbin/ipf/libipf/parseipfexpr.c (revision 41edb306f05651fcaf6c74f9e3557f59f80292e1)
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