varnish-cache/vmod/vmod_debug_acl.c
1
/*-
2
 * Copyright (c) 2012-2019 Varnish Software AS
3
 * All rights reserved.
4
 *
5
 * Author: Poul-Henning Kamp <phk@FreeBSD.org>
6
 *
7
 * SPDX-License-Identifier: BSD-2-Clause
8
 *
9
 * Redistribution and use in source and binary forms, with or without
10
 * modification, are permitted provided that the following conditions
11
 * are met:
12
 * 1. Redistributions of source code must retain the above copyright
13
 *    notice, this list of conditions and the following disclaimer.
14
 * 2. Redistributions in binary form must reproduce the above copyright
15
 *    notice, this list of conditions and the following disclaimer in the
16
 *    documentation and/or other materials provided with the distribution.
17
 *
18
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
22
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28
 * SUCH DAMAGE.
29
 */
30
31
#include "config.h"
32
33
#include <stdlib.h>
34
#include <stdio.h>
35
#include <string.h>
36
#include <sys/socket.h>
37
#include <unistd.h>
38
39
// #include "vdef.h"
40
//#include "vas.h"
41
#include "cache/cache.h"
42
#include "vend.h"
43
#include "vsa.h"
44
#include "vsb.h"
45
#include "vsha256.h"
46
#include "vtcp.h"
47
#include "vtim.h"
48
#include "vcc_debug_if.h"
49
50
VCL_ACL v_matchproto_(td_debug_null_acl)
51 20
xyzzy_null_acl(VRT_CTX)
52
{
53
54 20
        CHECK_OBJ_ORNULL(ctx, VRT_CTX_MAGIC);
55 20
        return (NULL);
56
}
57
58
VCL_ACL v_matchproto_(td_debug_acl)
59 10
xyzzy_acl(VRT_CTX, VCL_ACL acl)
60
{
61
62 10
        CHECK_OBJ_ORNULL(ctx, VRT_CTX_MAGIC);
63 10
        return (acl);
64
}
65
66
VCL_BOOL v_matchproto_(td_debug_match_acl)
67 20
xyzzy_match_acl(VRT_CTX, VCL_ACL acl, VCL_IP ip)
68
{
69
70 20
        CHECK_OBJ_ORNULL(ctx, VRT_CTX_MAGIC);
71 20
        assert(VSA_Sane(ip));
72
73 20
        return (VRT_acl_match(ctx, acl, ip));
74
}
75
76
/*
77
 * The code below is more intimate with VSA than anything is supposed to.
78
 */
79
80
struct acl_sweep {
81
        int                     family;
82
        const uint8_t           *ip0_p;
83
        const uint8_t           *ip1_p;
84
        struct suckaddr         *probe;
85
        uint8_t                 *probe_p;
86
        VCL_INT                 step;
87
        uint64_t                reset;
88
        uint64_t                this;
89
        uint64_t                count;
90
};
91
92
static void
93 10000
reset_sweep(struct acl_sweep *asw)
94
{
95 10000
        asw->this = asw->reset;
96 10000
}
97
98
static int
99 80
setup_sweep(VRT_CTX, struct acl_sweep *asw, VCL_IP ip0, VCL_IP ip1,
100
    VCL_INT step)
101
{
102
        int fam0, fam1;
103
        const uint8_t *ptr;
104
105 80
        AN(asw);
106 80
        memset(asw, 0, sizeof *asw);
107
108 80
        AN(ip0);
109 80
        AN(ip1);
110 80
        fam0 = VSA_GetPtr(ip0, &asw->ip0_p);
111 80
        fam1 = VSA_GetPtr(ip1, &asw->ip1_p);
112 80
        if (fam0 != fam1) {
113 0
                VRT_fail(ctx, "IPs have different families (0x%x vs 0x%x)",
114 0
                    fam0, fam1);
115 0
                return (-1);
116
        }
117
118 80
        asw->family = fam0;
119 80
        if (asw->family == PF_INET) {
120 30
                if (memcmp(asw->ip0_p, asw->ip1_p, 4) > 0) {
121 0
                        VRT_fail(ctx, "Sweep: ipv4.end < ipv4.start");
122 0
                        return (-1);
123
                }
124 30
                asw->reset = vbe32dec(asw->ip0_p);
125 30
        } else {
126 50
                if (memcmp(asw->ip0_p, asw->ip1_p, 16) > 0) {
127 0
                        VRT_fail(ctx, "Sweep: ipv6.end < ipv6.start");
128 0
                        return (-1);
129
                }
130 50
                asw->reset = vbe64dec(asw->ip0_p + 8);
131
        }
132 80
        asw->this = asw->reset;
133
134 80
        asw->probe = VSA_Clone(ip0);
135 80
        (void)VSA_GetPtr(asw->probe, &ptr);
136 80
        asw->probe_p = TRUST_ME(ptr);
137
138 80
        asw->step = step;
139
140 80
        return (0);
141 80
}
142
143
static void
144 80
cleanup_sweep(struct acl_sweep *asw)
145
{
146 80
        free(asw->probe);
147 80
        memset(asw, 0, sizeof *asw);
148 80
}
149
150
static int
151 963900
step_sweep(struct acl_sweep *asw)
152
{
153
154 963900
        AN(asw);
155 963900
        asw->count++;
156 963900
        asw->this += asw->step;
157 963900
        if (asw->family == PF_INET) {
158 990
                vbe32enc(asw->probe_p, asw->this);
159 990
                return (memcmp(asw->probe_p, asw->ip1_p, 4));
160
        } else {
161 962910
                vbe64enc(asw->probe_p + 8, asw->this);
162 962910
                return (memcmp(asw->probe_p, asw->ip1_p, 16));
163
        }
164 963900
}
165
166
167
VCL_BLOB
168 70
xyzzy_sweep_acl(VRT_CTX, VCL_ACL acl, VCL_IP ip0, VCL_IP ip1, VCL_INT step)
169
{
170
        struct acl_sweep asw[1];
171
        int i, j;
172
        struct vsb *vsb;
173
        char abuf[VTCP_ADDRBUFSIZE];
174
        char pbuf[VTCP_PORTBUFSIZE];
175
        unsigned char digest[VSHA256_DIGEST_LENGTH];
176
        struct VSHA256Context vsha[1];
177
        struct vrt_blob *b;
178
        ssize_t sz;
179
180 70
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
181 70
        AN(acl);
182 70
        AN(ip0);
183 70
        AN(ip1);
184 70
        assert(step > 0);
185 70
        if (setup_sweep(ctx, asw, ip0, ip1, step))
186 0
                return(NULL);
187
188 70
        vsb = VSB_new_auto();
189 70
        AN(vsb);
190
191 70
        VSHA256_Init(vsha);
192 2940
        for (j = 0; ; j++) {
193 2940
                if ((j & 0x3f) == 0x00) {
194 160
                        VTCP_name(asw->probe, abuf, sizeof abuf,
195 80
                            pbuf, sizeof pbuf);
196 80
                        VSB_printf(vsb, "Sweep: %-15s", abuf);
197 80
                }
198 2940
                i = VRT_acl_match(ctx, acl, asw->probe);
199 2940
                assert(0 <= i && i <= 1);
200 2940
                VSB_putc(vsb, "-X"[i]);
201 2940
                if ((j & 0x3f) == 0x3f) {
202 10
                        AZ(VSB_finish(vsb));
203 10
                        VSLb(ctx->vsl, SLT_Debug, "%s", VSB_data(vsb));
204 10
                        sz =VSB_len(vsb);
205 10
                        assert (sz > 0);
206 10
                        VSHA256_Update(vsha, VSB_data(vsb), sz);
207 10
                        VSB_clear(vsb);
208 10
                }
209 2940
                if (step_sweep(asw) > 0)
210 70
                        break;
211 2870
        }
212 70
        if (VSB_len(vsb)) {
213 70
                AZ(VSB_finish(vsb));
214 70
                VSLb(ctx->vsl, SLT_Debug, "%s", VSB_data(vsb));
215 70
                sz =VSB_len(vsb);
216 70
                assert (sz > 0);
217 70
                VSHA256_Update(vsha, VSB_data(vsb), sz);
218 70
                VSB_clear(vsb);
219 70
        }
220 70
        VSB_destroy(&vsb);
221
222 70
        VSHA256_Final(digest, vsha);
223 70
        b = WS_Alloc(ctx->ws, sizeof *b + sizeof digest);
224 70
        if (b != NULL) {
225 70
                memcpy(b + 1, digest, sizeof digest);
226 70
                b->blob = b + 1;
227 70
                b->len = sizeof digest;
228 70
        }
229 70
        cleanup_sweep(asw);
230 70
        return (b);
231 70
}
232
233
VCL_DURATION
234 10
xyzzy_time_acl(VRT_CTX, VCL_ACL acl, VCL_IP ip0, VCL_IP ip1,
235
    VCL_INT step, VCL_INT turnus)
236
{
237
        struct acl_sweep asw[1];
238
        vtim_mono t0, t1;
239
        vtim_dur d;
240
        VCL_INT cnt;
241
242 10
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
243 10
        AN(acl);
244 10
        AN(ip0);
245 10
        AN(ip1);
246 10
        assert(step > 0);
247 10
        assert(turnus > 0);
248
249 10
        if (setup_sweep(ctx, asw, ip0, ip1, step))
250 0
                return(-1);
251 10
        do {
252 960
                (void)VRT_acl_match(ctx, acl, asw->probe);
253 960
        } while (step_sweep(asw) <= 0);
254 10
        asw->count = 0;
255 10
        t0 = VTIM_mono();
256 10010
        for (cnt = 0; cnt < turnus; cnt++) {
257 10000
                reset_sweep(asw);
258 10000
                do {
259 960000
                        (void)VRT_acl_match(ctx, acl, asw->probe);
260 960000
                } while (step_sweep(asw) <= 0);
261 10000
        }
262 10
        t1 = VTIM_mono();
263 10
        cnt = asw->count;
264 10
        assert(cnt > 0);
265 10
        d = (t1 - t0) / cnt;
266 20
        VSLb(ctx->vsl, SLT_Debug,
267
            "Timed ACL: %.9f -> %.9f = %.9f %.9f/round, %.9f/IP %ju IPs",
268 10
            t0, t1, t1 - t0, (t1-t0) / turnus, d, (intmax_t)cnt);
269 10
        cleanup_sweep(asw);
270 10
        return (d);
271 10
}
272
273
struct xyzzy_debug_aclobj {
274
        unsigned                        magic;
275
#define VMOD_DEBUG_ACLOBJ_MAGIC 0xac10ac10
276
        char *                          vcl_name;
277
        VCL_ACL                 acl;
278
};
279
280
VCL_VOID v_matchproto_(td_xyzzy_debug_aclobj__init)
281 20
xyzzy_aclobj__init(VRT_CTX, struct VPFX(debug_aclobj) **op,
282
    const char *vcl_name, VCL_ACL acl)
283
{
284
        struct VPFX(debug_aclobj) *o;
285
286 20
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
287 20
        AN(op);
288 20
        AZ(*op);
289 20
        ALLOC_OBJ(o, VMOD_DEBUG_ACLOBJ_MAGIC);
290 20
        AN(o);
291 20
        REPLACE(o->vcl_name, vcl_name);
292 20
        o->acl = acl;
293 20
        *op = o;
294 20
}
295
296
VCL_VOID v_matchproto_(td_xyzzy_debug_aclobj__fini)
297 0
xyzzy_aclobj__fini(struct VPFX(debug_aclobj) **op)
298
{
299
        struct VPFX(debug_aclobj) *o;
300
301 0
        TAKE_OBJ_NOTNULL(o, op, VMOD_DEBUG_ACLOBJ_MAGIC);
302 0
        REPLACE(o->vcl_name, NULL);
303 0
        FREE_OBJ(o);
304 0
}
305
306
VCL_ACL v_matchproto_(td_xyzzy_debug_aclobj_get)
307 20
xyzzy_aclobj_get(VRT_CTX, struct VPFX(debug_aclobj) *o)
308
{
309 20
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
310 20
        CHECK_OBJ_NOTNULL(o, VMOD_DEBUG_ACLOBJ_MAGIC);
311 20
        return (o->acl);
312
}