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