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