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