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 45
vcl_acl_cmp(struct acl_e *ae1, struct acl_e *ae2)
67
{
68
        unsigned char *p1, *p2;
69
        unsigned m;
70
71 45
        p1 = ae1->data;
72 45
        p2 = ae2->data;
73 45
        m = ae1->mask;
74 45
        if (ae2->mask < m)
75 6
                m = ae2->mask;
76 145
        for (; m >= 8; m -= 8) {
77 134
                CMP(*p1, *p2);
78 100
                p1++;
79 100
                p2++;
80
        }
81 11
        if (m) {
82 8
                m = 0xff00 >> m;
83 8
                m &= 0xff;
84 8
                CMP(*p1 & m, *p2 & m);
85
        }
86
        /* Long mask is less than short mask */
87 8
        CMP(ae2->mask, ae1->mask);
88
89 2
        return (0);
90
}
91
92
93
static void
94 36
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 36
        if (fam == PF_INET && ae->mask > 32) {
101 1
                VSB_printf(tl->sb,
102
                    "Too wide mask (%u) for IPv4 address\n", ae->mask);
103 1
                if (ae->t_mask != NULL)
104 1
                        vcc_ErrWhere(tl, ae->t_mask);
105
                else
106 0
                        vcc_ErrWhere(tl, ae->t_addr);
107 1
                return;
108
        }
109 35
        if (fam == PF_INET6 && ae->mask > 128) {
110 1
                VSB_printf(tl->sb,
111
                    "Too wide mask (%u) for IPv6 address\n", ae->mask);
112 1
                vcc_ErrWhere(tl, ae->t_mask);
113 1
                return;
114
        }
115
116
        /* Make a copy from the template */
117 34
        aen = TlAlloc(tl, sizeof *ae2);
118 34
        AN(aen);
119 34
        *aen = *ae;
120
121
        /* We treat family as part of address, it saves code */
122 34
        assert(fam <= 0xff);
123 34
        aen->data[0] = fam & 0xff;
124 34
        aen->mask += 8;
125
126 34
        assert(l + 1L <= sizeof aen->data);
127 34
        memcpy(aen->data + 1L, u, l);
128
129 73
        VTAILQ_FOREACH(ae2, &tl->acl, list) {
130 45
                i = vcl_acl_cmp(aen, ae2);
131 45
                if (i == 0) {
132
                        /*
133
                         * If the two rules agree, silently ignore it
134
                         * XXX: is that counter intuitive ?
135
                         */
136 2
                        if (aen->not == ae2->not)
137 1
                                return;
138 1
                        VSB_printf(tl->sb, "Conflicting ACL entries:\n");
139 1
                        vcc_ErrWhere(tl, ae2->t_addr);
140 1
                        VSB_printf(tl->sb, "vs:\n");
141 1
                        vcc_ErrWhere(tl, aen->t_addr);
142 1
                        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 43
                if (i < 0) {
155 4
                        VTAILQ_INSERT_BEFORE(ae2, aen, list);
156 4
                        return;
157
                }
158
        }
159 28
        VTAILQ_INSERT_TAIL(&tl->acl, aen, list);
160
}
161
162
static void
163 9
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 9
        memset(&hint, 0, sizeof hint);
172 9
        hint.ai_family = PF_UNSPEC;
173 9
        hint.ai_socktype = SOCK_STREAM;
174 9
        error = getaddrinfo(ae->addr, "0", &hint, &res0);
175 9
        if (error) {
176 4
                if (ae->para) {
177 2
                        VSB_printf(tl->sb,
178
                            "Warning: %s ignored\n  -- %s\n",
179
                            ae->addr, gai_strerror(error));
180 4
                        Fh(tl, 1, "/* Ignored ACL entry: %s%s",
181 4
                            ae->para ? "\"(\" " : "", ae->not ? "\"!\" " : "");
182 2
                        EncToken(tl->fh, ae->t_addr);
183 2
                        if (ae->t_mask)
184 1
                                Fh(tl, 0, "/%u", ae->mask);
185 2
                        Fh(tl, 0, "%s\n", ae->para ? " \")\"" : "");
186 2
                        Fh(tl, 1, " * getaddrinfo:  %s */\n",
187
                             gai_strerror(error));
188
                } else {
189 2
                        VSB_printf(tl->sb,
190
                            "DNS lookup(%s): %s\n",
191
                            ae->addr, gai_strerror(error));
192 2
                        vcc_ErrWhere(tl, ae->t_addr);
193
                }
194 9
                return;
195
        }
196
197 5
        i4 = i6 = 0;
198 10
        for (res = res0; res != NULL; res = res->ai_next) {
199 6
                switch (res->ai_family) {
200
                case PF_INET:
201
                        assert(PF_INET < 256);
202 1
                        sin4 = (void*)res->ai_addr;
203
                        assert(sizeof(sin4->sin_addr) == 4);
204 1
                        u = (void*)&sin4->sin_addr;
205 1
                        if (ae->t_mask == NULL)
206 1
                                ae->mask = 32;
207 1
                        i4++;
208 1
                        vcc_acl_add_entry(tl, ae, 4, u, res->ai_family);
209 1
                        break;
210
                case PF_INET6:
211
                        assert(PF_INET6 < 256);
212 5
                        sin6 = (void*)res->ai_addr;
213
                        assert(sizeof(sin6->sin6_addr) == 16);
214 5
                        u = (void*)&sin6->sin6_addr;
215 5
                        if (ae->t_mask == NULL)
216 3
                                ae->mask = 128;
217 5
                        i6++;
218 5
                        vcc_acl_add_entry(tl, ae, 16, u, res->ai_family);
219 5
                        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 6
                if (tl->err)
227 1
                        freeaddrinfo(res0);
228 6
                ERRCHK(tl);
229
        }
230 4
        freeaddrinfo(res0);
231
232 4
        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 39
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 39
        memset(b, 0, sizeof b);
257 39
        p = ae->addr;
258 115
        for (i = 0; i < 4; i++) {
259 115
                j = sscanf(p, "%u%n", &u, &k);
260 115
                if (j != 1)
261 6
                        return (0);
262 109
                if (u & ~0xff)
263 1
                        return (0);
264 108
                b[i] = (unsigned char)u;
265 108
                if (p[k] == '\0')
266 30
                        break;
267 78
                if (p[k] != '.')
268 2
                        return (0);
269 76
                p += k + 1;
270
        }
271 30
        if (ae->t_mask == NULL)
272 12
                ae->mask = 8 + 8 * i;
273 30
        vcc_acl_add_entry(tl, ae, 4, b, AF_INET);
274 30
        return (1);
275
}
276
277
static void
278 42
vcc_acl_entry(struct vcc *tl)
279
{
280
        struct acl_e *ae;
281
        char *sl, *e;
282
283 42
        ae = TlAlloc(tl, sizeof *ae);
284 42
        AN(ae);
285
286 42
        if (tl->t->tok == '!') {
287 4
                ae->not = 1;
288 4
                vcc_NextToken(tl);
289
        }
290
291 42
        if (tl->t->tok == '(') {
292 3
                ae->para = 1;
293 3
                vcc_NextToken(tl);
294
        }
295
296 42
        if (!ae->not && tl->t->tok == '!') {
297 1
                ae->not = 1;
298 1
                vcc_NextToken(tl);
299
        }
300
301 50
        ExpectErr(tl, CSTR);
302 42
        ae->t_addr = tl->t;
303 42
        ae->addr = strdup(ae->t_addr->dec);
304 42
        AN(ae->addr);
305 42
        vcc_NextToken(tl);
306
307 42
        if (strchr(ae->t_addr->dec, '/') != NULL) {
308 2
                sl = strchr(ae->addr, '/');
309 2
                AN(sl);
310 2
                *sl++ = '\0';
311 2
                e = NULL;
312 2
                ae->mask = strtoul(sl, &e, 10);
313 2
                if (*e != '\0') {
314 1
                        VSB_printf(tl->sb, ".../mask is not numeric.\n");
315 1
                        vcc_ErrWhere(tl, ae->t_addr);
316 1
                        return;
317
                }
318 1
                ae->t_mask = ae->t_addr;
319 1
                if (tl->t->tok == '/') {
320 1
                        VSB_printf(tl->sb, "/mask only allowed once.\n");
321 1
                        vcc_ErrWhere(tl, tl->t);
322 1
                        return;
323
                }
324 40
        } else if (tl->t->tok == '/') {
325 21
                vcc_NextToken(tl);
326 21
                ae->t_mask = tl->t;
327 21
                ExpectErr(tl, CNUM);
328 21
                ae->mask = vcc_UintVal(tl);
329
        }
330
331 40
        if (ae->para)
332 3
                SkipToken(tl, ')');
333
334 39
        if (!vcc_acl_try_netnotation(tl, ae)) {
335 9
                ERRCHK(tl);
336 9
                vcc_acl_try_getaddrinfo(tl, ae);
337
        }
338 39
        ERRCHK(tl);
339
}
340
341
/*********************************************************************
342
 * Emit a function to match the ACL we have collected
343
 */
344
345
static void
346 15
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 15
        func = VSB_new_auto();
356 15
        AN(func);
357 15
        VSB_printf(func, "match_acl_%s_", anon ? "anon" : "named");
358 15
        VCC_PrintCName(func, name, NULL);
359 15
        AZ(VSB_finish(func));
360
361 15
        Fh(tl, 0, "\nstatic int v_matchproto_(acl_match_f)\n");
362 15
        Fh(tl, 0, "%s(VRT_CTX, const VCL_IP p)\n", VSB_data(func));
363 15
        Fh(tl, 0, "{\n");
364 15
        Fh(tl, 0, "\tconst unsigned char *a;\n");
365 15
        Fh(tl, 0, "\tint fam;\n");
366 15
        Fh(tl, 0, "\n");
367 15
        Fh(tl, 0, "\tfam = VRT_VSA_GetPtr(p, &a);\n");
368 15
        Fh(tl, 0, "\tif (fam < 0) {\n");
369 15
        Fh(tl, 0, "\t\tVRT_acl_log(ctx, \"NO_FAM %s\");\n", name);
370 15
        Fh(tl, 0, "\t\treturn(0);\n");
371 15
        Fh(tl, 0, "\t}\n\n");
372 15
        if (!tl->err_unref && !anon) {
373 1
                ifp = New_IniFin(tl);
374 1
                VSB_printf(ifp->ini,
375
                        "\tif (0) %s(0, 0);\n", VSB_data(func));
376
        }
377 15
        depth = -1;
378 15
        at[0] = 256;
379 45
        VTAILQ_FOREACH(ae, &tl->acl, list) {
380
381
                /* Find how much common prefix we have */
382 63
                for (l = 0; l <= depth && l * 8 < ae->mask - 7; l++) {
383 40
                        assert(l >= 0);
384 40
                        if (ae->data[l] != at[l])
385 7
                                break;
386
                }
387
388
                /* Back down, if necessary */
389 108
                while (l <= depth) {
390 48
                        Fh(tl, 0, "\t%*s}\n", -depth, "");
391 48
                        depth--;
392
                }
393
394 30
                m = ae->mask;
395 30
                m -= l * 8;
396 30
                assert(m >= 0);
397
398
                /* Do whole byte compares */
399 155
                for (i = l; m >= 8; m -= 8, i++) {
400 125
                        if (i == 0)
401 18
                                Fh(tl, 0, "\t%*s%sif (fam == %d) {\n",
402 18
                                    -i, "", "", ae->data[i]);
403
                        else
404 107
                                Fh(tl, 0, "\t%*s%sif (a[%d] == %d) {\n",
405 107
                                    -i, "", "", i - 1, ae->data[i]);
406 125
                        at[i] = ae->data[i];
407 125
                        depth = i;
408
                }
409
410 30
                if (m > 0) {
411
                        /* Do fractional byte compares */
412 36
                        Fh(tl, 0, "\t%*s%sif ((a[%d] & 0x%x) == %d) {\n",
413 12
                            -i, "", "", i - 1, (0xff00 >> m) & 0xff,
414 24
                            ae->data[i] & ((0xff00 >> m) & 0xff));
415 12
                        at[i] = 256;
416 12
                        depth = i;
417
                }
418
419 30
                i = (ae->mask + 7) / 8;
420
421 30
                if (!anon) {
422 30
                        Fh(tl, 0, "\t%*sVRT_acl_log(ctx, \"%sMATCH %s \" ",
423 30
                            -i, "", ae->not ? "NEG_" : "", name);
424 30
                        t = ae->t_addr;
425
                        do {
426 64
                                if (t->tok == CSTR) {
427 30
                                        Fh(tl, 0, " \"\\\"\" ");
428 30
                                        EncToken(tl->fh, t);
429 30
                                        Fh(tl, 0, " \"\\\"\" ");
430
                                } else
431 34
                                        Fh(tl, 0, " \"%.*s\"", PF(t));
432 64
                                if (t == ae->t_mask)
433 17
                                        break;
434 47
                                t = VTAILQ_NEXT(t, list);
435 47
                                AN(t);
436 47
                        } while (ae->t_mask != NULL);
437 30
                        Fh(tl, 0, ");\n");
438
                }
439
440 30
                Fh(tl, 0, "\t%*sreturn (%d);\n", -i, "", ae->not ? 0 : 1);
441
        }
442
443
        /* Unwind */
444 104
        for (; 0 <= depth; depth--)
445 89
                Fh(tl, 0, "\t%*.*s}\n", depth, depth, "");
446
447
        /* Deny by default */
448 15
        if (!anon)
449 15
                Fh(tl, 0, "\tVRT_acl_log(ctx, \"NO_MATCH %s\");\n", name);
450 15
        Fh(tl, 0, "\treturn (0);\n}\n");
451
452 15
        if (!anon) {
453
                /* Emit the struct that will be referenced */
454 15
                Fh(tl, 0, "\nconst struct vrt_acl %s[] = {{\n", rname);
455 15
                Fh(tl, 0, "\t.magic = VRT_ACL_MAGIC,\n");
456 15
                Fh(tl, 0, "\t.match = &%s,\n", VSB_data(func));
457 15
                Fh(tl, 0, "}};\n\n");
458
        }
459 15
        VSB_destroy(&func);
460 15
}
461
462
void
463 25
vcc_ParseAcl(struct vcc *tl)
464
{
465
        struct token *an;
466
        struct symbol *sym;
467
468 25
        vcc_NextToken(tl);
469 25
        VTAILQ_INIT(&tl->acl);
470
471 25
        vcc_ExpectVid(tl, "ACL");
472 25
        ERRCHK(tl);
473 24
        an = tl->t;
474 24
        vcc_NextToken(tl);
475
476 24
        sym = VCC_HandleSymbol(tl, an, ACL, ACL_SYMBOL_PREFIX);
477 24
        ERRCHK(tl);
478 24
        AN(sym);
479
480 24
        SkipToken(tl, '{');
481
482 81
        while (tl->t->tok != '}') {
483 42
                vcc_acl_entry(tl);
484 42
                ERRCHK(tl);
485 34
                SkipToken(tl, ';');
486
        }
487 15
        SkipToken(tl, '}');
488
489 15
        vcc_acl_emit(tl, sym->name, sym->rname, 0);
490
}