varnish-cache/lib/libvcc/vcc_acl.c
1
/*-
2
 * Copyright (c) 2006 Verdens Gang AS
3
 * Copyright (c) 2006-2010 Varnish Software AS
4
 * All rights reserved.
5
 *
6
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 * SUCH DAMAGE.
28
 */
29
30
#include "config.h"
31
32
#include <sys/socket.h>
33
34
#include <netinet/in.h>
35
36
#include <netdb.h>
37
#include <stdlib.h>
38
#include <string.h>
39
40
#include "vcc_compile.h"
41
42
#define ACL_MAXADDR     (sizeof(struct in6_addr) + 1)
43
44
struct acl_e {
45
        VTAILQ_ENTRY(acl_e)     list;
46
        unsigned char           data[ACL_MAXADDR];
47
        unsigned                mask;
48
        unsigned                not;
49
        unsigned                para;
50
        char                    *addr;
51
        struct token            *t_addr;
52
        struct token            *t_mask;
53
};
54
55
/* Compare two acl rules for ordering */
56
57
#define CMP(a, b)                                                       \
58
        do {                                                            \
59
                if ((a) < (b))                                          \
60
                        return (-1);                                    \
61
                else if ((b) < (a))                                     \
62
                        return (1);                                     \
63
        } while (0)
64
65
static int
66 90
vcl_acl_cmp(struct acl_e *ae1, struct acl_e *ae2)
67
{
68
        unsigned char *p1, *p2;
69
        unsigned m;
70
71 90
        p1 = ae1->data;
72 90
        p2 = ae2->data;
73 90
        m = ae1->mask;
74 90
        if (ae2->mask < m)
75 12
                m = ae2->mask;
76 290
        for (; m >= 8; m -= 8) {
77 268
                CMP(*p1, *p2);
78 200
                p1++;
79 200
                p2++;
80
        }
81 22
        if (m) {
82 16
                m = 0xff00 >> m;
83 16
                m &= 0xff;
84 16
                CMP(*p1 & m, *p2 & m);
85
        }
86
        /* Long mask is less than short mask */
87 16
        CMP(ae2->mask, ae1->mask);
88
89 4
        return (0);
90
}
91
92
93
static void
94 76
vcc_acl_add_entry(struct vcc *tl, const struct acl_e *ae, int l,
95
    const unsigned char *u, int fam)
96
{
97
        struct acl_e *ae2, *aen;
98
        int i;
99
100 76
        if (fam == PF_INET && ae->mask > 32) {
101 2
                VSB_printf(tl->sb,
102
                    "Too wide mask (%u) for IPv4 address\n", ae->mask);
103 2
                if (ae->t_mask != NULL)
104 2
                        vcc_ErrWhere(tl, ae->t_mask);
105
                else
106 0
                        vcc_ErrWhere(tl, ae->t_addr);
107 2
                return;
108
        }
109 74
        if (fam == PF_INET6 && ae->mask > 128) {
110 2
                VSB_printf(tl->sb,
111
                    "Too wide mask (%u) for IPv6 address\n", ae->mask);
112 2
                vcc_ErrWhere(tl, ae->t_mask);
113 2
                return;
114
        }
115
116
        /* Make a copy from the template */
117 72
        aen = TlAlloc(tl, sizeof *ae2);
118 72
        AN(aen);
119 72
        *aen = *ae;
120
121
        /* We treat family as part of address, it saves code */
122 72
        assert(fam <= 0xff);
123 72
        aen->data[0] = fam & 0xff;
124 72
        aen->mask += 8;
125
126 72
        assert(l + 1L <= sizeof aen->data);
127 72
        memcpy(aen->data + 1L, u, l);
128
129 150
        VTAILQ_FOREACH(ae2, &tl->acl, list) {
130 90
                i = vcl_acl_cmp(aen, ae2);
131 90
                if (i == 0) {
132
                        /*
133
                         * If the two rules agree, silently ignore it
134
                         * XXX: is that counter intuitive ?
135
                         */
136 4
                        if (aen->not == ae2->not)
137 2
                                return;
138 2
                        VSB_printf(tl->sb, "Conflicting ACL entries:\n");
139 2
                        vcc_ErrWhere(tl, ae2->t_addr);
140 2
                        VSB_printf(tl->sb, "vs:\n");
141 2
                        vcc_ErrWhere(tl, aen->t_addr);
142 2
                        return;
143
                }
144
                /*
145
                 * We could eliminate pointless rules here, for instance in:
146
                 *      "10.1.0.1";
147
                 *      "10.1";
148
                 * The first rule is clearly pointless, as the second one
149
                 * covers it.
150
                 *
151
                 * We do not do this however, because the shmlog may
152
                 * be used to gather statistics.
153
                 */
154 86
                if (i < 0) {
155 8
                        VTAILQ_INSERT_BEFORE(ae2, aen, list);
156 8
                        return;
157
                }
158
        }
159 60
        VTAILQ_INSERT_TAIL(&tl->acl, aen, list);
160
}
161
162
static void
163 18
vcc_acl_try_getaddrinfo(struct vcc *tl, struct acl_e *ae)
164
{
165
        struct addrinfo *res0, *res, hint;
166
        struct sockaddr_in *sin4;
167
        struct sockaddr_in6 *sin6;
168
        unsigned char *u, i4, i6;
169
        int error;
170
171 18
        memset(&hint, 0, sizeof hint);
172 18
        hint.ai_family = PF_UNSPEC;
173 18
        hint.ai_socktype = SOCK_STREAM;
174 18
        error = getaddrinfo(ae->addr, "0", &hint, &res0);
175 18
        if (error) {
176 8
                if (ae->para) {
177 4
                        VSB_printf(tl->sb,
178
                            "Warning: %s ignored\n  -- %s\n",
179
                            ae->addr, gai_strerror(error));
180 8
                        Fh(tl, 1, "/* Ignored ACL entry: %s%s",
181 8
                            ae->para ? "\"(\" " : "", ae->not ? "\"!\" " : "");
182 4
                        EncToken(tl->fh, ae->t_addr);
183 4
                        if (ae->t_mask)
184 2
                                Fh(tl, 0, "/%u", ae->mask);
185 4
                        Fh(tl, 0, "%s\n", ae->para ? " \")\"" : "");
186 4
                        Fh(tl, 1, " * getaddrinfo:  %s */\n",
187
                             gai_strerror(error));
188
                } else {
189 4
                        VSB_printf(tl->sb,
190
                            "DNS lookup(%s): %s\n",
191
                            ae->addr, gai_strerror(error));
192 4
                        vcc_ErrWhere(tl, ae->t_addr);
193
                }
194 18
                return;
195
        }
196
197 10
        i4 = i6 = 0;
198 20
        for (res = res0; res != NULL; res = res->ai_next) {
199 12
                switch (res->ai_family) {
200
                case PF_INET:
201
                        assert(PF_INET < 256);
202 2
                        sin4 = (void*)res->ai_addr;
203
                        assert(sizeof(sin4->sin_addr) == 4);
204 2
                        u = (void*)&sin4->sin_addr;
205 2
                        if (ae->t_mask == NULL)
206 2
                                ae->mask = 32;
207 2
                        i4++;
208 2
                        vcc_acl_add_entry(tl, ae, 4, u, res->ai_family);
209 2
                        break;
210
                case PF_INET6:
211
                        assert(PF_INET6 < 256);
212 10
                        sin6 = (void*)res->ai_addr;
213
                        assert(sizeof(sin6->sin6_addr) == 16);
214 10
                        u = (void*)&sin6->sin6_addr;
215 10
                        if (ae->t_mask == NULL)
216 6
                                ae->mask = 128;
217 10
                        i6++;
218 10
                        vcc_acl_add_entry(tl, ae, 16, u, res->ai_family);
219 10
                        break;
220
                default:
221 0
                        VSB_printf(tl->sb,
222
                            "Ignoring unknown protocol family (%d) for %.*s\n",
223 0
                                res->ai_family, PF(ae->t_addr));
224 0
                        continue;
225
                }
226 12
                if (tl->err)
227 2
                        freeaddrinfo(res0);
228 12
                ERRCHK(tl);
229
        }
230 8
        freeaddrinfo(res0);
231
232 8
        if (ae->t_mask != NULL && i4 > 0 && i6 > 0) {
233 0
                VSB_printf(tl->sb,
234
                    "Mask (%u) specified, but string resolves to"
235
                    " both IPv4 and IPv6 addresses.\n", ae->mask);
236 0
                vcc_ErrWhere(tl, ae->t_mask);
237 0
                return;
238
        }
239
}
240
241
/*--------------------------------------------------------------------
242
 * Ancient stupidity on the part of X/Open and other standards orgs
243
 * dictate that "192.168" be translated to 192.0.0.168.  Ever since
244
 * CIDR happened, "192.168/16" notation has been used, but apparently
245
 * no API supports parsing this, so roll our own.
246
 */
247
248
static int
249 82
vcc_acl_try_netnotation(struct vcc *tl, struct acl_e *ae)
250
{
251
        unsigned char b[4];
252
        int i, j, k;
253
        unsigned u;
254
        const char *p;
255
256 82
        memset(b, 0, sizeof b);
257 82
        p = ae->addr;
258 246
        for (i = 0; i < 4; i++) {
259 246
                j = sscanf(p, "%u%n", &u, &k);
260 246
                if (j != 1)
261 12
                        return (0);
262 234
                if (u & ~0xff)
263 2
                        return (0);
264 232
                b[i] = (unsigned char)u;
265 232
                if (p[k] == '\0')
266 64
                        break;
267 168
                if (p[k] != '.')
268 4
                        return (0);
269 164
                p += k + 1;
270
        }
271 64
        if (ae->t_mask == NULL)
272 28
                ae->mask = 8 + 8 * i;
273 64
        vcc_acl_add_entry(tl, ae, 4, b, AF_INET);
274 64
        return (1);
275
}
276
277
static void
278 90
vcc_acl_entry(struct vcc *tl)
279
{
280
        struct acl_e *ae;
281
        char *sl, *e;
282
283 90
        ae = TlAlloc(tl, sizeof *ae);
284 90
        AN(ae);
285
286 90
        if (tl->t->tok == '!') {
287 8
                ae->not = 1;
288 8
                vcc_NextToken(tl);
289
        }
290
291 90
        if (tl->t->tok == '(') {
292 6
                ae->para = 1;
293 6
                vcc_NextToken(tl);
294
        }
295
296 90
        if (!ae->not && tl->t->tok == '!') {
297 2
                ae->not = 1;
298 2
                vcc_NextToken(tl);
299
        }
300
301 108
        ExpectErr(tl, CSTR);
302 90
        ae->t_addr = tl->t;
303 90
        ae->addr = strdup(ae->t_addr->dec);
304 90
        AN(ae->addr);
305 90
        vcc_NextToken(tl);
306
307 90
        if (strchr(ae->t_addr->dec, '/') != NULL) {
308 6
                sl = strchr(ae->addr, '/');
309 6
                AN(sl);
310 6
                *sl++ = '\0';
311 6
                e = NULL;
312 6
                ae->mask = strtoul(sl, &e, 10);
313 6
                if (*e != '\0') {
314 4
                        VSB_printf(tl->sb, ".../mask is not numeric.\n");
315 4
                        vcc_ErrWhere(tl, ae->t_addr);
316 4
                        return;
317
                }
318 2
                ae->t_mask = ae->t_addr;
319 2
                if (tl->t->tok == '/') {
320 2
                        VSB_printf(tl->sb, "/mask only allowed once.\n");
321 2
                        vcc_ErrWhere(tl, tl->t);
322 2
                        return;
323
                }
324 84
        } else if (tl->t->tok == '/') {
325 42
                vcc_NextToken(tl);
326 42
                ae->t_mask = tl->t;
327 42
                ExpectErr(tl, CNUM);
328 42
                ae->mask = vcc_UintVal(tl);
329
        }
330
331 84
        if (ae->para)
332 6
                SkipToken(tl, ')');
333
334 82
        if (!vcc_acl_try_netnotation(tl, ae)) {
335 18
                ERRCHK(tl);
336 18
                vcc_acl_try_getaddrinfo(tl, ae);
337
        }
338 82
        ERRCHK(tl);
339
}
340
341
/*********************************************************************
342
 * Emit a function to match the ACL we have collected
343
 */
344
345
static void
346 34
vcc_acl_emit(struct vcc *tl, const char *name, const char *rname, int anon)
347
{
348
        struct acl_e *ae;
349
        int depth, l, m, i;
350
        unsigned at[ACL_MAXADDR];
351
        struct token *t;
352
        struct inifin *ifp;
353
        struct vsb *func;
354
355 34
        func = VSB_new_auto();
356 34
        AN(func);
357 34
        VSB_printf(func, "match_acl_%s_", anon ? "anon" : "named");
358 34
        VCC_PrintCName(func, name, NULL);
359 34
        AZ(VSB_finish(func));
360
361 34
        Fh(tl, 0, "\nstatic int v_matchproto_(acl_match_f)\n");
362 34
        Fh(tl, 0, "%s(VRT_CTX, const VCL_IP p)\n", VSB_data(func));
363 34
        Fh(tl, 0, "{\n");
364 34
        Fh(tl, 0, "\tconst unsigned char *a;\n");
365 34
        Fh(tl, 0, "\tint fam;\n");
366 34
        Fh(tl, 0, "\n");
367 34
        Fh(tl, 0, "\tfam = VRT_VSA_GetPtr(p, &a);\n");
368 34
        Fh(tl, 0, "\tif (fam < 0) {\n");
369 34
        Fh(tl, 0, "\t\tVRT_acl_log(ctx, \"NO_FAM %s\");\n", name);
370 34
        Fh(tl, 0, "\t\treturn(0);\n");
371 34
        Fh(tl, 0, "\t}\n\n");
372 34
        if (!tl->err_unref && !anon) {
373 2
                ifp = New_IniFin(tl);
374 2
                VSB_printf(ifp->ini,
375
                        "\tif (0) %s(0, 0);\n", VSB_data(func));
376
        }
377 34
        depth = -1;
378 34
        at[0] = 256;
379 98
        VTAILQ_FOREACH(ae, &tl->acl, list) {
380
381
                /* Find how much common prefix we have */
382 130
                for (l = 0; l <= depth && l * 8 < ae->mask - 7; l++) {
383 80
                        assert(l >= 0);
384 80
                        if (ae->data[l] != at[l])
385 14
                                break;
386
                }
387
388
                /* Back down, if necessary */
389 224
                while (l <= depth) {
390 96
                        Fh(tl, 0, "\t%*s}\n", -depth, "");
391 96
                        depth--;
392
                }
393
394 64
                m = (int)ae->mask;
395 64
                assert(m >= l*8);
396 64
                m -= l * 8;
397
398
                /* Do whole byte compares */
399 334
                for (i = l; m >= 8; m -= 8, i++) {
400 270
                        if (i == 0)
401 40
                                Fh(tl, 0, "\t%*s%sif (fam == %d) {\n",
402 40
                                    -i, "", "", ae->data[i]);
403
                        else
404 230
                                Fh(tl, 0, "\t%*s%sif (a[%d] == %d) {\n",
405 230
                                    -i, "", "", i - 1, ae->data[i]);
406 270
                        at[i] = ae->data[i];
407 270
                        depth = i;
408
                }
409
410 64
                if (m > 0) {
411
                        /* Do fractional byte compares */
412 48
                        Fh(tl, 0, "\t%*s%sif ((a[%d] & 0x%x) == %d) {\n",
413 24
                            -i, "", "", i - 1, (0xff00 >> m) & 0xff,
414 24
                            ae->data[i] & ((0xff00 >> m) & 0xff));
415 24
                        at[i] = 256;
416 24
                        depth = i;
417
                }
418
419 64
                i = ((int)ae->mask + 7) / 8;
420
421 64
                if (!anon) {
422 64
                        Fh(tl, 0, "\t%*sVRT_acl_log(ctx, \"%sMATCH %s \" ",
423 64
                            -i, "", ae->not ? "NEG_" : "", name);
424 64
                        t = ae->t_addr;
425
                        do {
426 132
                                if (t->tok == CSTR) {
427 64
                                        Fh(tl, 0, " \"\\\"\" ");
428 64
                                        EncToken(tl->fh, t);
429 64
                                        Fh(tl, 0, " \"\\\"\" ");
430
                                } else
431 68
                                        Fh(tl, 0, " \"%.*s\"", PF(t));
432 132
                                if (t == ae->t_mask)
433 34
                                        break;
434 98
                                t = VTAILQ_NEXT(t, list);
435 98
                                AN(t);
436 98
                        } while (ae->t_mask != NULL);
437 64
                        Fh(tl, 0, ");\n");
438
                }
439
440 64
                Fh(tl, 0, "\t%*sreturn (%d);\n", -i, "", ae->not ? 0 : 1);
441
        }
442
443
        /* Unwind */
444 232
        for (; 0 <= depth; depth--)
445 198
                Fh(tl, 0, "\t%*.*s}\n", depth, depth, "");
446
447
        /* Deny by default */
448 34
        if (!anon)
449 34
                Fh(tl, 0, "\tVRT_acl_log(ctx, \"NO_MATCH %s\");\n", name);
450 34
        Fh(tl, 0, "\treturn (0);\n}\n");
451
452 34
        if (!anon) {
453
                /* Emit the struct that will be referenced */
454 34
                Fh(tl, 0, "\nconst struct vrt_acl %s[] = {{\n", rname);
455 34
                Fh(tl, 0, "\t.magic = VRT_ACL_MAGIC,\n");
456 34
                Fh(tl, 0, "\t.match = &%s,\n", VSB_data(func));
457 34
                Fh(tl, 0, "}};\n\n");
458
        }
459 34
        VSB_destroy(&func);
460 34
}
461
462
void
463 56
vcc_ParseAcl(struct vcc *tl)
464
{
465
        struct symbol *sym;
466
467 56
        vcc_NextToken(tl);
468 56
        VTAILQ_INIT(&tl->acl);
469
470 56
        vcc_ExpectVid(tl, "ACL");
471 56
        ERRCHK(tl);
472 54
        sym = VCC_HandleSymbol(tl, ACL, ACL_SYMBOL_PREFIX);
473 54
        ERRCHK(tl);
474 54
        AN(sym);
475
476 54
        SkipToken(tl, '{');
477
478 178
        while (tl->t->tok != '}') {
479 90
                vcc_acl_entry(tl);
480 90
                ERRCHK(tl);
481 72
                SkipToken(tl, ';');
482
        }
483 34
        SkipToken(tl, '}');
484
485 34
        vcc_acl_emit(tl, sym->name, sym->rname, 0);
486
}