]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/ipfilter/lib/parseipfexpr.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / ipfilter / lib / parseipfexpr.c
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 *
35 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 += 4 + (items * e->ipoe_nbasearg * e->ipoe_argsize);
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 += 4;
135                 ipfe->ipfe_cmd = e->ipoe_cmd;
136                 ipfe->ipfe_not = not;
137                 ipfe->ipfe_narg = items * e->ipoe_nbasearg;
138                 ipfe->ipfe_size = items * e->ipoe_nbasearg * e->ipoe_argsize;
139                 ipfe->ipfe_size += 4;
140
141                 for (s = arg; (*s != '\0') && (osize < asize); s = t) {
142                         /*
143                          * Look for the end of this arg or the ',' to say
144                          * there is another following.
145                          */
146                         for (t = s; (*t != '\0') && (*t != ','); t++)
147                                 ;
148                         if (*t == ',')
149                                 *t++ = '\0';
150
151                         if (!strcasecmp(ops, "ip.addr") ||
152                             !strcasecmp(ops, "ip.src") ||
153                             !strcasecmp(ops, "ip.dst")) {
154                                 i6addr_t mask, addr;
155                                 char *delim;
156
157                                 delim = strchr(s, '/');
158                                 if (delim != NULL) {
159                                         *delim++ = '\0';
160                                         if (genmask(AF_INET, delim,
161                                                     &mask) == -1) {
162                                                 error = "genmask failed";
163                                                 goto parseerror;
164                                         }
165                                 } else {
166                                         mask.in4.s_addr = 0xffffffff;
167                                 }
168                                 if (gethost(AF_INET, s, &addr) == -1) {
169                                         error = "gethost failed";
170                                         goto parseerror;
171                                 }
172
173                                 oplist[osize++] = addr.in4.s_addr;
174                                 oplist[osize++] = mask.in4.s_addr;
175
176 #ifdef USE_INET6
177                         } else if (!strcasecmp(ops, "ip6.addr") ||
178                             !strcasecmp(ops, "ip6.src") ||
179                             !strcasecmp(ops, "ip6.dst")) {
180                                 i6addr_t mask, addr;
181                                 char *delim;
182
183                                 delim = strchr(s, '/');
184                                 if (delim != NULL) {
185                                         *delim++ = '\0';
186                                         if (genmask(AF_INET6, delim,
187                                                     &mask) == -1) {
188                                                 error = "genmask failed";
189                                                 goto parseerror;
190                                         }
191                                 } else {
192                                         mask.i6[0] = 0xffffffff;
193                                         mask.i6[1] = 0xffffffff;
194                                         mask.i6[2] = 0xffffffff;
195                                         mask.i6[3] = 0xffffffff;
196                                 }
197                                 if (gethost(AF_INET6, s, &addr) == -1) {
198                                         error = "gethost failed";
199                                         goto parseerror;
200                                 }
201
202                                 oplist[osize++] = addr.i6[0];
203                                 oplist[osize++] = addr.i6[1];
204                                 oplist[osize++] = addr.i6[2];
205                                 oplist[osize++] = addr.i6[3];
206                                 oplist[osize++] = mask.i6[0];
207                                 oplist[osize++] = mask.i6[1];
208                                 oplist[osize++] = mask.i6[2];
209                                 oplist[osize++] = mask.i6[3];
210 #endif
211
212                         } else if (!strcasecmp(ops, "ip.p")) {
213                                 int p;
214
215                                 p = getproto(s);
216                                 if (p == -1)
217                                         goto parseerror;
218                                 oplist[osize++] = p;
219
220                         } else if (!strcasecmp(ops, "tcp.flags")) {
221                                 u_32_t mask, flags;
222                                 char *delim;
223
224                                 delim = strchr(s, '/');
225                                 if (delim != NULL) {
226                                         *delim++ = '\0';
227                                         mask = tcpflags(delim);
228                                 } else {
229                                         mask = 0xff;
230                                 }
231                                 flags = tcpflags(s);
232
233                                 oplist[osize++] = flags;
234                                 oplist[osize++] = mask;
235
236
237                         } else if (!strcasecmp(ops, "tcp.port") ||
238                             !strcasecmp(ops, "tcp.sport") ||
239                             !strcasecmp(ops, "tcp.dport") ||
240                             !strcasecmp(ops, "udp.port") ||
241                             !strcasecmp(ops, "udp.sport") ||
242                             !strcasecmp(ops, "udp.dport")) {
243                                 char proto[4];
244                                 u_short port;
245
246                                 strncpy(proto, ops, 3);
247                                 proto[3] = '\0';
248                                 if (getport(NULL, s, &port, proto) == -1)
249                                         goto parseerror;
250                                 oplist[osize++] = port;
251
252                         } else if (!strcasecmp(ops, "tcp.state")) {
253                                 oplist[osize++] = atoi(s);
254
255                         } else {
256                                 error = "unknown word";
257                                 goto parseerror;
258                         }
259                 }
260         }
261
262         free(temp);
263
264         if (errorptr != NULL)
265                 *errorptr = NULL;
266
267         for (i = asize; i > 0; i--)
268                 oplist[i] = oplist[i - 1];
269
270         oplist[0] = asize + 2;
271         oplist[asize + 1] = IPF_EXP_END;
272
273         return oplist;
274
275 parseerror:
276         if (errorptr != NULL)
277                 *errorptr = error;
278         if (oplist != NULL)
279                 free(oplist);
280         if (temp != NULL)
281                 free(temp);
282         return NULL;
283 }