vinyl-cache/vmod/vmod_debug_acl.c
0
/*-
1
 * Copyright (c) 2012-2019 Varnish Software AS
2
 * All rights reserved.
3
 *
4
 * Author: Poul-Henning Kamp <phk@FreeBSD.org>
5
 *
6
 * SPDX-License-Identifier: BSD-2-Clause
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 <stdlib.h>
33
#include <stdio.h>
34
#include <string.h>
35
#include <sys/socket.h>
36
#include <unistd.h>
37
38
// #include "vdef.h"
39
//#include "vas.h"
40
#include "cache/cache.h"
41
#include "vend.h"
42
#include "vsa.h"
43
#include "vsb.h"
44
#include "vsha256.h"
45
#include "vtcp.h"
46
#include "vtim.h"
47
#include "vcc_debug_if.h"
48
49
VCL_ACL v_matchproto_(td_debug_null_acl)
50 42
xyzzy_null_acl(VRT_CTX)
51
{
52
53 42
        CHECK_OBJ_ORNULL(ctx, VRT_CTX_MAGIC);
54 42
        return (NULL);
55
}
56
57
VCL_ACL v_matchproto_(td_debug_acl)
58 21
xyzzy_acl(VRT_CTX, VCL_ACL acl)
59
{
60
61 21
        CHECK_OBJ_ORNULL(ctx, VRT_CTX_MAGIC);
62 21
        return (acl);
63
}
64
65
VCL_BOOL v_matchproto_(td_debug_match_acl)
66 42
xyzzy_match_acl(VRT_CTX, VCL_ACL acl, VCL_IP ip)
67
{
68
69 42
        CHECK_OBJ_ORNULL(ctx, VRT_CTX_MAGIC);
70 42
        assert(VSA_Sane(ip));
71
72 42
        return (VRT_acl_match(ctx, acl, ip));
73
}
74
75
/*
76
 * The code below is more intimate with VSA than anything is supposed to.
77
 */
78
79
struct acl_sweep {
80
        int                     family;
81
        const uint8_t           *ip0_p;
82
        const uint8_t           *ip1_p;
83
        struct suckaddr         *probe;
84
        uint8_t                 *probe_p;
85
        VCL_INT                 step;
86
        uint64_t                reset;
87
        uint64_t                that;
88
        uint64_t                count;
89
};
90
91
static void
92 21000
reset_sweep(struct acl_sweep *asw)
93
{
94 21000
        asw->that = asw->reset;
95 21000
}
96
97
static int
98 168
setup_sweep(VRT_CTX, struct acl_sweep *asw, VCL_IP ip0, VCL_IP ip1,
99
    VCL_INT step)
100
{
101
        int fam0, fam1;
102
        const uint8_t *ptr;
103
104 168
        AN(asw);
105 168
        memset(asw, 0, sizeof *asw);
106
107 168
        AN(ip0);
108 168
        AN(ip1);
109 168
        fam0 = VSA_GetPtr(ip0, &asw->ip0_p);
110 168
        fam1 = VSA_GetPtr(ip1, &asw->ip1_p);
111 168
        if (fam0 != fam1) {
112 0
                VRT_fail(ctx, "IPs have different families (0x%x vs 0x%x)",
113 0
                    fam0, fam1);
114 0
                return (-1);
115
        }
116
117 168
        asw->family = fam0;
118 168
        if (asw->family == PF_INET) {
119 63
                if (memcmp(asw->ip0_p, asw->ip1_p, 4) > 0) {
120 0
                        VRT_fail(ctx, "Sweep: ipv4.end < ipv4.start");
121 0
                        return (-1);
122
                }
123 63
                asw->reset = vbe32dec(asw->ip0_p);
124 63
        } else {
125 105
                if (memcmp(asw->ip0_p, asw->ip1_p, 16) > 0) {
126 0
                        VRT_fail(ctx, "Sweep: ipv6.end < ipv6.start");
127 0
                        return (-1);
128
                }
129 105
                asw->reset = vbe64dec(asw->ip0_p + 8);
130
        }
131 168
        asw->that = asw->reset;
132
133
        /* Dont try this at home */
134 168
        asw->probe = malloc(vsa_suckaddr_len);
135 168
        AN(asw->probe);
136 168
        vmemcpy(asw->probe, ip0, vsa_suckaddr_len);
137 168
        (void)VSA_GetPtr(asw->probe, &ptr);
138 168
        asw->probe_p = ((uint8_t*)(asw->probe)) + (ptr - (uint8_t*)asw->probe);
139
140 168
        asw->step = step;
141
142 168
        return (0);
143 168
}
144
145
static void
146 168
cleanup_sweep(struct acl_sweep *asw)
147
{
148 168
        free(asw->probe);
149 168
        memset(asw, 0, sizeof *asw);
150 168
}
151
152
static int
153 2024190
step_sweep(struct acl_sweep *asw)
154
{
155
156 2024190
        AN(asw);
157 2024190
        asw->count++;
158 2024190
        asw->that += asw->step;
159 2024190
        if (asw->family == PF_INET) {
160 2079
                vbe32enc(asw->probe_p, asw->that);
161 2079
                return (memcmp(asw->probe_p, asw->ip1_p, 4));
162
        } else {
163 2022111
                vbe64enc(asw->probe_p + 8, asw->that);
164 2022111
                return (memcmp(asw->probe_p, asw->ip1_p, 16));
165
        }
166 2024190
}
167
168
169
VCL_BLOB
170 147
xyzzy_sweep_acl(VRT_CTX, VCL_ACL acl, VCL_IP ip0, VCL_IP ip1, VCL_INT step)
171
{
172
        struct acl_sweep asw[1];
173
        int i, j;
174
        struct vsb *vsb;
175
        char abuf[VTCP_ADDRBUFSIZE];
176
        char pbuf[VTCP_PORTBUFSIZE];
177
        unsigned char digest[VSHA256_DIGEST_LENGTH];
178
        struct VSHA256Context vsha[1];
179
        struct vrt_blob *b;
180
        ssize_t sz;
181
182 147
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
183 147
        AN(acl);
184 147
        AN(ip0);
185 147
        AN(ip1);
186 147
        assert(step > 0);
187 147
        if (setup_sweep(ctx, asw, ip0, ip1, step))
188 0
                return (NULL);
189
190 147
        vsb = VSB_new_auto();
191 147
        AN(vsb);
192
193 147
        VSHA256_Init(vsha);
194 6174
        for (j = 0; ; j++) {
195 6174
                if ((j & 0x3f) == 0x00) {
196 336
                        VTCP_name(asw->probe, abuf, sizeof abuf,
197 168
                            pbuf, sizeof pbuf);
198 168
                        VSB_printf(vsb, "Sweep: %-15s", abuf);
199 168
                }
200 6174
                i = VRT_acl_match(ctx, acl, asw->probe);
201 6174
                assert(0 <= i && i <= 1);
202 6174
                VSB_putc(vsb, "-X"[i]);
203 6174
                if ((j & 0x3f) == 0x3f) {
204 21
                        AZ(VSB_finish(vsb));
205 21
                        VSLbs(ctx->vsl, SLT_Debug, TOSTRAND(VSB_data(vsb)));
206 21
                        sz =VSB_len(vsb);
207 21
                        assert (sz > 0);
208 21
                        VSHA256_Update(vsha, VSB_data(vsb), sz);
209 21
                        VSB_clear(vsb);
210 21
                }
211 6174
                if (step_sweep(asw) > 0)
212 147
                        break;
213 6027
        }
214 147
        if (VSB_len(vsb)) {
215 147
                AZ(VSB_finish(vsb));
216 147
                VSLbs(ctx->vsl, SLT_Debug, TOSTRAND(VSB_data(vsb)));
217 147
                sz =VSB_len(vsb);
218 147
                assert (sz > 0);
219 147
                VSHA256_Update(vsha, VSB_data(vsb), sz);
220 147
                VSB_clear(vsb);
221 147
        }
222 147
        VSB_destroy(&vsb);
223
224 147
        VSHA256_Final(digest, vsha);
225 147
        b = WS_Alloc(ctx->ws, sizeof *b + sizeof digest);
226 147
        if (b != NULL) {
227 147
                vmemcpy(b + 1, digest, sizeof digest);
228 147
                b->magic = VRT_BLOB_MAGIC;
229 147
                b->blob = b + 1;
230 147
                b->len = sizeof digest;
231 147
        }
232 147
        cleanup_sweep(asw);
233 147
        return (b);
234 147
}
235
236
VCL_DURATION
237 21
xyzzy_time_acl(VRT_CTX, VCL_ACL acl, VCL_IP ip0, VCL_IP ip1,
238
    VCL_INT step, VCL_INT turnus)
239
{
240
        struct acl_sweep asw[1];
241
        vtim_mono t0, t1;
242
        vtim_dur d;
243
        VCL_INT cnt;
244
245 21
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
246 21
        AN(acl);
247 21
        AN(ip0);
248 21
        AN(ip1);
249 21
        assert(step > 0);
250 21
        assert(turnus > 0);
251
252 21
        if (setup_sweep(ctx, asw, ip0, ip1, step))
253 0
                return (-1);
254 21
        do {
255 2016
                (void)VRT_acl_match(ctx, acl, asw->probe);
256 2016
        } while (step_sweep(asw) <= 0);
257 21
        asw->count = 0;
258 21
        t0 = VTIM_mono();
259 21021
        for (cnt = 0; cnt < turnus; cnt++) {
260 21000
                reset_sweep(asw);
261 21000
                do {
262 2016000
                        (void)VRT_acl_match(ctx, acl, asw->probe);
263 2016000
                } while (step_sweep(asw) <= 0);
264 21000
        }
265 21
        t1 = VTIM_mono();
266 21
        cnt = asw->count;
267 21
        assert(cnt > 0);
268 21
        d = (t1 - t0) / cnt;
269 42
        VSLb(ctx->vsl, SLT_Debug,
270
            "Timed ACL: %.9f -> %.9f = %.9f %.9f/round, %.9f/IP %ju IPs",
271 21
            t0, t1, t1 - t0, (t1-t0) / turnus, d, (intmax_t)cnt);
272 21
        cleanup_sweep(asw);
273 21
        return (d);
274 21
}
275
276
struct xyzzy_debug_aclobj {
277
        unsigned                        magic;
278
#define VMOD_DEBUG_ACLOBJ_MAGIC 0xac10ac10
279
        char *                          vcl_name;
280
        VCL_ACL                 acl;
281
};
282
283
VCL_VOID v_matchproto_(td_xyzzy_debug_aclobj__init)
284 42
xyzzy_aclobj__init(VRT_CTX, struct VPFX(debug_aclobj) **op,
285
    const char *vcl_name, VCL_ACL acl)
286
{
287
        struct VPFX(debug_aclobj) *o;
288
289 42
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
290 42
        AN(op);
291 42
        AZ(*op);
292 42
        ALLOC_OBJ(o, VMOD_DEBUG_ACLOBJ_MAGIC);
293 42
        AN(o);
294 42
        REPLACE(o->vcl_name, vcl_name);
295 42
        o->acl = acl;
296 42
        *op = o;
297 42
}
298
299
VCL_VOID v_matchproto_(td_xyzzy_debug_aclobj__fini)
300 0
xyzzy_aclobj__fini(struct VPFX(debug_aclobj) **op)
301
{
302
        struct VPFX(debug_aclobj) *o;
303
304 0
        TAKE_OBJ_NOTNULL(o, op, VMOD_DEBUG_ACLOBJ_MAGIC);
305 0
        REPLACE(o->vcl_name, NULL);
306 0
        FREE_OBJ(o);
307 0
}
308
309
VCL_ACL v_matchproto_(td_xyzzy_debug_aclobj_get)
310 42
xyzzy_aclobj_get(VRT_CTX, struct VPFX(debug_aclobj) *o)
311
{
312 42
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
313 42
        CHECK_OBJ_NOTNULL(o, VMOD_DEBUG_ACLOBJ_MAGIC);
314 42
        return (o->acl);
315
}