varnish-cache/bin/varnishtest/vtc_syslog.c
0
/*-
1
 * Copyright (c) 2008-2010 Varnish Software AS
2
 * All rights reserved.
3
 *
4
 * Author: Frédéric Lécaille <flecaille@haproxy.com>
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 <sys/types.h>
33
#include <sys/socket.h>
34
35
#include <stdio.h>
36
#include <stdlib.h>
37
#include <string.h>
38
#include <unistd.h>
39
40
#include "vtc.h"
41
42
#include "vsa.h"
43
#include "vss.h"
44
#include "vtcp.h"
45
#include "vre.h"
46
47
struct syslog_srv {
48
        unsigned                        magic;
49
#define SYSLOG_SRV_MAGIC                0xbf28a692
50
        char                            *name;
51
        struct vtclog                   *vl;
52
        VTAILQ_ENTRY(syslog_srv)        list;
53
        char                            run;
54
55
        int                             repeat;
56
        char                            *spec;
57
58
        int                             sock;
59
        char                            bind[256];
60
        int                             lvl;
61
62
        pthread_t                       tp;
63
        ssize_t                         rxbuf_left;
64
        size_t                          rxbuf_sz;
65
        char                            *rxbuf;
66
        vtim_dur                        timeout;
67
};
68
69
static pthread_mutex_t                  syslog_mtx;
70
71
static VTAILQ_HEAD(, syslog_srv)        syslogs =
72
    VTAILQ_HEAD_INITIALIZER(syslogs);
73
74
#define SYSLOGCMDS \
75
        CMD_SYSLOG(expect) \
76
        CMD_SYSLOG(recv)
77
78
#define CMD_SYSLOG(nm) static cmd_f cmd_syslog_##nm;
79
SYSLOGCMDS
80
#undef CMD_SYSLOG
81
82
static const struct cmds syslog_cmds[] = {
83
#define CMD_SYSLOG(n) { #n, cmd_syslog_##n },
84
SYSLOGCMDS
85
#undef CMD_SYSLOG
86
        { NULL, NULL }
87
};
88
89
static const char * const syslog_levels[] = {
90
        "emerg",
91
        "alert",
92
        "crit",
93
        "err",
94
        "warning",
95
        "notice",
96
        "info",
97
        "debug",
98
        NULL,
99
};
100
101
static int
102 80
get_syslog_level(struct vtclog *vl, const char *lvl)
103
{
104
        int i;
105
106 520
        for (i = 0; syslog_levels[i]; i++)
107 520
                if (!strcmp(lvl, syslog_levels[i]))
108 80
                        return (i);
109 0
        vtc_fatal(vl, "wrong syslog level '%s'\n", lvl);
110
}
111
112
/*--------------------------------------------------------------------
113
 * Check if a UDP syscall return value is fatal
114
 * XXX: Largely copied from VTCP, not sure if really applicable
115
 */
116
117
static int
118 40
VUDP_Check(int a)
119
{
120 40
        if (a == 0)
121 40
                return (1);
122 0
        if (errno == ECONNRESET)
123 0
                return (1);
124
#if (defined (__SVR4) && defined (__sun)) || defined (__NetBSD__)
125
        /*
126
         * Solaris returns EINVAL if the other end unexpectedly reset the
127
         * connection.
128
         * This is a bug in Solaris and documented behaviour on NetBSD.
129
         */
130
        if (errno == EINVAL || errno == ETIMEDOUT || errno == EPIPE)
131
                return (1);
132
#elif defined (__APPLE__)
133
        /*
134
         * macOS returns EINVAL if the other end unexpectedly reset
135
         * the connection.
136
         */
137
        if (errno == EINVAL)
138
                return (1);
139
#endif
140 0
        return (0);
141 40
}
142
143
/*--------------------------------------------------------------------
144
 * When closing a UDP connection, a couple of errno's are legit, we
145
 * can't be held responsible for the other end wanting to talk to us.
146
 */
147
148
static void
149 40
VUDP_close(int *s)
150
{
151
        int i;
152
153 40
        i = close(*s);
154
155 40
        assert(VUDP_Check(i));
156 40
        *s = -1;
157 40
}
158
159
/*--------------------------------------------------------------------
160
 * Given a struct suckaddr, open a socket of the appropriate type, and bind
161
 * it to the requested address.
162
 *
163
 * If the address is an IPv6 address, the IPV6_V6ONLY option is set to
164
 * avoid conflicts between INADDR_ANY and IN6ADDR_ANY.
165
 */
166
167
static int
168 40
VUDP_bind(const struct suckaddr *sa, const char **errp)
169
{
170
#ifdef IPV6_V6ONLY
171
        int val;
172
#endif
173
        int sd, e;
174
        socklen_t sl;
175
        const struct sockaddr *so;
176
        int proto;
177
178 40
        if (errp != NULL)
179 40
                *errp = NULL;
180
181 40
        proto = VSA_Get_Proto(sa);
182 40
        sd = socket(proto, SOCK_DGRAM, 0);
183 40
        if (sd < 0) {
184 0
                if (errp != NULL)
185 0
                        *errp = "socket(2)";
186 0
                return (-1);
187
        }
188
189
#ifdef IPV6_V6ONLY
190
        /* forcibly use separate sockets for IPv4 and IPv6 */
191
        val = 1;
192
        if (proto == AF_INET6 &&
193
            setsockopt(sd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof val) != 0) {
194
                if (errp != NULL)
195
                        *errp = "setsockopt(IPV6_V6ONLY, 1)";
196
                e = errno;
197
                closefd(&sd);
198
                errno = e;
199
                return (-1);
200
        }
201
#endif
202 40
        so = VSA_Get_Sockaddr(sa, &sl);
203 40
        if (bind(sd, so, sl) != 0) {
204 0
                if (errp != NULL)
205 0
                        *errp = "bind(2)";
206 0
                e = errno;
207 0
                closefd(&sd);
208 0
                errno = e;
209 0
                return (-1);
210
        }
211 40
        return (sd);
212 40
}
213
214
/*--------------------------------------------------------------------*/
215
216
struct udp_helper {
217
        const char      **errp;
218
};
219
220
static int v_matchproto_(vss_resolved_f)
221 40
vudp_lo_cb(void *priv, const struct suckaddr *sa)
222
{
223
        int sock;
224 40
        struct udp_helper *hp = priv;
225
226 40
        sock = VUDP_bind(sa, hp->errp);
227 40
        if (sock > 0) {
228 40
                *hp->errp = NULL;
229 40
                return (sock);
230
        }
231 0
        AN(*hp->errp);
232 0
        return (0);
233 40
}
234
235
static int
236 40
VUDP_bind_on(const char *addr, const char *def_port, const char **errp)
237
{
238
        struct udp_helper h;
239
        int sock;
240
241 40
        h.errp = errp;
242
243 40
        sock = VSS_resolver_socktype(
244 40
            addr, def_port, vudp_lo_cb, &h, errp, SOCK_DGRAM);
245 40
        if (*errp != NULL)
246 0
                return (-1);
247 40
        return (sock);
248 40
}
249
250
/**********************************************************************
251
 * Allocate and initialize a syslog
252
 */
253
254
static struct syslog_srv *
255 40
syslog_new(const char *name, struct vtclog *vl)
256
{
257
        struct syslog_srv *s;
258
259 40
        VTC_CHECK_NAME(vl, name, "Syslog", 'S');
260 40
        ALLOC_OBJ(s, SYSLOG_SRV_MAGIC);
261 40
        AN(s);
262 40
        REPLACE(s->name, name);
263 40
        s->vl = vtc_logopen("%s", s->name);
264 40
        AN(s->vl);
265 40
        vtc_log_set_cmd(s->vl, syslog_cmds);
266
267 40
        bprintf(s->bind, "%s", default_listen_addr);
268 40
        s->repeat = 1;
269 40
        s->sock = -1;
270 40
        s->lvl = -1;
271 40
        s->timeout = vtc_maxdur * .5;           // XXX
272
273 40
        vl = vtc_logopen("%s", s->name);
274 40
        AN(vl);
275
276 40
        s->rxbuf_sz = s->rxbuf_left = 2048*1024;
277 40
        s->rxbuf = malloc(s->rxbuf_sz);         /* XXX */
278 40
        AN(s->rxbuf);
279
280 40
        PTOK(pthread_mutex_lock(&syslog_mtx));
281 40
        VTAILQ_INSERT_TAIL(&syslogs, s, list);
282 40
        PTOK(pthread_mutex_unlock(&syslog_mtx));
283 40
        return (s);
284
}
285
286
/**********************************************************************
287
 * Clean up a syslog
288
 */
289
290
static void
291 40
syslog_delete(struct syslog_srv *s)
292
{
293
294 40
        CHECK_OBJ_NOTNULL(s, SYSLOG_SRV_MAGIC);
295 40
        macro_undef(s->vl, s->name, "addr");
296 40
        macro_undef(s->vl, s->name, "port");
297 40
        macro_undef(s->vl, s->name, "sock");
298 40
        vtc_logclose(s->vl);
299 40
        free(s->name);
300 40
        free(s->rxbuf);
301
        /* XXX: MEMLEAK (?) (VSS ??) */
302 40
        FREE_OBJ(s);
303 40
}
304
305
static void
306 40
syslog_rx(const struct syslog_srv *s, int lvl)
307
{
308
        ssize_t ret;
309
310 40
        while (!vtc_error) {
311
                /* Pointers to syslog priority value (see <PRIVAL>, rfc5424). */
312
                char *prib, *prie, *end;
313
                unsigned int prival;
314
315 40
                VTCP_set_read_timeout(s->sock, s->timeout);
316
317 40
                ret = recv(s->sock, s->rxbuf, s->rxbuf_sz - 1, 0);
318 40
                if (ret < 0) {
319 0
                        if (errno == EINTR || errno == EAGAIN)
320 0
                                continue;
321
322 0
                        vtc_fatal(s->vl,
323
                            "%s: recv failed (fd: %d read: %s", __func__,
324 0
                            s->sock, strerror(errno));
325
                }
326 40
                if (ret == 0)
327 0
                        vtc_fatal(s->vl,
328
                            "syslog rx timeout (fd: %d %.3fs ret: %zd)",
329 0
                            s->sock, s->timeout, ret);
330
331 40
                s->rxbuf[ret] = '\0';
332 40
                vtc_dump(s->vl, 4, "syslog", s->rxbuf, ret);
333
334 40
                prib = s->rxbuf;
335 40
                if (*prib++ != '<')
336 0
                        vtc_fatal(s->vl, "syslog PRI, no '<'");
337 40
                prie = strchr(prib, '>');
338 40
                if (prie == NULL)
339 0
                        vtc_fatal(s->vl, "syslog PRI, no '>'");
340
341 40
                prival = strtoul(prib, &end, 10);
342 40
                if (end != prie)
343 0
                        vtc_fatal(s->vl, "syslog PRI, bad number");
344
345 40
                if (lvl >= 0 && lvl == (prival & 0x7))
346 40
                        return;
347
        }
348 40
}
349
350
/**********************************************************************
351
 * Syslog server bind
352
 */
353
354
static void
355 40
syslog_bind(struct syslog_srv *s)
356
{
357
        const char *err;
358
        char aaddr[VTCP_ADDRBUFSIZE];
359
        char aport[VTCP_PORTBUFSIZE];
360 40
        char buf[vsa_suckaddr_len];
361
        const struct suckaddr *sua;
362
363 40
        CHECK_OBJ_NOTNULL(s, SYSLOG_SRV_MAGIC);
364
365 40
        if (s->sock >= 0)
366 0
                VUDP_close(&s->sock);
367 40
        s->sock = VUDP_bind_on(s->bind, "0", &err);
368 40
        if (err != NULL)
369 0
                vtc_fatal(s->vl,
370
                    "Syslog server bind address (%s) cannot be resolved: %s",
371 0
                    s->bind, err);
372 40
        assert(s->sock > 0);
373 40
        sua = VSA_getsockname(s->sock, buf, sizeof buf);
374 40
        AN(sua);
375 40
        VTCP_name(sua, aaddr, sizeof aaddr, aport, sizeof aport);
376 40
        macro_def(s->vl, s->name, "addr", "%s", aaddr);
377 40
        macro_def(s->vl, s->name, "port", "%s", aport);
378 40
        if (VSA_Get_Proto(sua) == AF_INET)
379 40
                macro_def(s->vl, s->name, "sock", "%s:%s", aaddr, aport);
380
        else
381 0
                macro_def(s->vl, s->name, "sock", "[%s]:%s", aaddr, aport);
382
        /* Record the actual port, and reuse it on subsequent starts */
383 40
        bprintf(s->bind, "%s %s", aaddr, aport);
384 40
}
385
386
static void v_matchproto_(cmd_f)
387 40
cmd_syslog_expect(CMD_ARGS)
388
{
389
        struct syslog_srv *s;
390
        struct vsb vsb[1];
391
        vre_t *vre;
392
        int error, erroroffset, i, ret;
393
        char *cmp, *spec, errbuf[VRE_ERROR_LEN];
394
395 40
        (void)vl;
396 40
        CAST_OBJ_NOTNULL(s, priv, SYSLOG_SRV_MAGIC);
397 40
        AZ(strcmp(av[0], "expect"));
398 40
        av++;
399
400 40
        cmp = av[0];
401 40
        spec = av[1];
402 40
        AN(cmp);
403 40
        AN(spec);
404 40
        AZ(av[2]);
405
406 40
        assert(!strcmp(cmp, "~") || !strcmp(cmp, "!~"));
407
408 40
        vre = VRE_compile(spec, 0, &error, &erroroffset, 1);
409 40
        if (vre == NULL) {
410 0
                AN(VSB_init(vsb, errbuf, sizeof errbuf));
411 0
                AZ(VRE_error(vsb, error));
412 0
                AZ(VSB_finish(vsb));
413 0
                VSB_fini(vsb);
414 0
                vtc_fatal(s->vl, "REGEXP error: '%s' (@%d) (%s)",
415 0
                    errbuf, erroroffset, spec);
416
        }
417
418 40
        i = VRE_match(vre, s->rxbuf, 0, 0, NULL);
419
420 40
        VRE_free(&vre);
421
422 40
        ret = (i >= 0 && *cmp == '~') || (i < 0 && *cmp == '!');
423 40
        if (!ret)
424 0
                vtc_fatal(s->vl, "EXPECT FAILED %s \"%s\"", cmp, spec);
425
        else
426 40
                vtc_log(s->vl, 4, "EXPECT MATCH %s \"%s\"", cmp, spec);
427 40
}
428
429
static void v_matchproto_(cmd_f)
430 40
cmd_syslog_recv(CMD_ARGS)
431
{
432
        int lvl;
433
        struct syslog_srv *s;
434
435 40
        CAST_OBJ_NOTNULL(s, priv, SYSLOG_SRV_MAGIC);
436 40
        (void)vl;
437 40
        AZ(strcmp(av[0], "recv"));
438 40
        av++;
439 40
        if (av[0] == NULL)
440 0
                lvl = s->lvl;
441
        else
442 40
                lvl = get_syslog_level(vl, av[0]);
443
444 40
        syslog_rx(s, lvl);
445 40
}
446
447
/**********************************************************************
448
 * Syslog server thread
449
 */
450
451
static void *
452 40
syslog_thread(void *priv)
453
{
454
        struct syslog_srv *s;
455
        int i;
456
457 40
        CAST_OBJ_NOTNULL(s, priv, SYSLOG_SRV_MAGIC);
458 40
        assert(s->sock >= 0);
459
460 40
        vtc_log(s->vl, 2, "Started on %s (level: %d)", s->bind, s->lvl);
461 80
        for (i = 0; i < s->repeat; i++) {
462 40
                if (s->repeat > 1)
463 0
                        vtc_log(s->vl, 3, "Iteration %d", i);
464 40
                parse_string(s->vl, s, s->spec);
465 40
                vtc_log(s->vl, 3, "shutting fd %d", s->sock);
466 40
        }
467 40
        VUDP_close(&s->sock);
468 40
        vtc_log(s->vl, 2, "Ending");
469 40
        return (NULL);
470
}
471
472
/**********************************************************************
473
 * Start the syslog thread
474
 */
475
476
static void
477 40
syslog_start(struct syslog_srv *s)
478
{
479 40
        CHECK_OBJ_NOTNULL(s, SYSLOG_SRV_MAGIC);
480 40
        vtc_log(s->vl, 2, "Starting syslog server");
481 40
        if (s->sock == -1)
482 0
                syslog_bind(s);
483 40
        vtc_log(s->vl, 1, "Bound on %s", s->bind);
484 40
        s->run = 1;
485 40
        PTOK(pthread_create(&s->tp, NULL, syslog_thread, s));
486 40
}
487
488
/**********************************************************************
489
 * Force stop the syslog thread
490
 */
491
492
static void
493 0
syslog_stop(struct syslog_srv *s)
494
{
495
        void *res;
496
497 0
        CHECK_OBJ_NOTNULL(s, SYSLOG_SRV_MAGIC);
498 0
        vtc_log(s->vl, 2, "Stopping for syslog server");
499 0
        (void)pthread_cancel(s->tp);
500 0
        PTOK(pthread_join(s->tp, &res));
501 0
        s->tp = 0;
502 0
        s->run = 0;
503 0
}
504
505
/**********************************************************************
506
 * Wait for syslog thread to stop
507
 */
508
509
static void
510 40
syslog_wait(struct syslog_srv *s)
511
{
512
        void *res;
513
514 40
        CHECK_OBJ_NOTNULL(s, SYSLOG_SRV_MAGIC);
515 40
        vtc_log(s->vl, 2, "Waiting for syslog server (%d)", s->sock);
516 40
        PTOK(pthread_join(s->tp, &res));
517 40
        if (res != NULL && !vtc_stop)
518 0
                vtc_fatal(s->vl, "Syslog server returned \"%p\"",
519 0
                    (char *)res);
520 40
        s->tp = 0;
521 40
        s->run = 0;
522 40
}
523
524
/* SECTION: syslog syslog
525
 *
526
 * Define and interact with syslog instances (for use with haproxy)
527
 *
528
 * To define a syslog server, you'll use this syntax::
529
 *
530
 *     syslog SNAME
531
 *
532
 * Arguments:
533
 *
534
 * SNAME
535
 *     Identify the syslog server with a string which must start with 'S'.
536
 *
537
 * \-level STRING
538
 *         Set the default syslog priority level used by any subsequent "recv"
539
 *         command.
540
 *         Any syslog dgram with a different level will be skipped by
541
 *         "recv" command. This default level value may be superseded
542
 *         by "recv" command if supplied as first argument: "recv <level>".
543
 *
544
 * \-start
545
 *         Start the syslog server thread in the background.
546
 *
547
 * \-repeat
548
 *         Instead of processing the specification only once, do it
549
 *         NUMBER times.
550
 *
551
 * \-bind
552
 *         Bind the syslog socket to a local address.
553
 *
554
 * \-wait
555
 *         Wait for that thread to terminate.
556
 *
557
 * \-stop
558
 *         Stop the syslog server thread.
559
 */
560
561
void v_matchproto_(cmd_f)
562 40240
cmd_syslog(CMD_ARGS)
563
{
564
        struct syslog_srv *s;
565
566 40240
        (void)priv;
567
568 40240
        if (av == NULL) {
569
                /* Reset and free */
570 40160
                do {
571 40200
                        PTOK(pthread_mutex_lock(&syslog_mtx));
572 40200
                        s = VTAILQ_FIRST(&syslogs);
573 40200
                        CHECK_OBJ_ORNULL(s, SYSLOG_SRV_MAGIC);
574 40200
                        if (s != NULL)
575 40
                                VTAILQ_REMOVE(&syslogs, s, list);
576 40200
                        PTOK(pthread_mutex_unlock(&syslog_mtx));
577 40200
                        if (s != NULL) {
578 40
                                if (s->run) {
579 0
                                        (void)pthread_cancel(s->tp);
580 0
                                        syslog_wait(s);
581 0
                                }
582 40
                                if (s->sock >= 0)
583 0
                                        VUDP_close(&s->sock);
584 40
                                syslog_delete(s);
585 40
                        }
586 40200
                } while (s != NULL);
587 40160
                return;
588
        }
589
590 80
        AZ(strcmp(av[0], "syslog"));
591 80
        av++;
592
593 80
        PTOK(pthread_mutex_lock(&syslog_mtx));
594 80
        VTAILQ_FOREACH(s, &syslogs, list)
595 40
                if (!strcmp(s->name, av[0]))
596 40
                        break;
597 80
        PTOK(pthread_mutex_unlock(&syslog_mtx));
598 80
        if (s == NULL)
599 40
                s = syslog_new(av[0], vl);
600 80
        CHECK_OBJ_NOTNULL(s, SYSLOG_SRV_MAGIC);
601 80
        av++;
602
603 280
        for (; *av != NULL; av++) {
604 200
                if (vtc_error)
605 0
                        break;
606 200
                if (!strcmp(*av, "-wait")) {
607 40
                        if (!s->run)
608 0
                                vtc_fatal(s->vl, "Syslog server not -started");
609 40
                        syslog_wait(s);
610 40
                        continue;
611
                }
612
613 160
                if (!strcmp(*av, "-stop")) {
614 0
                        syslog_stop(s);
615 0
                        continue;
616
                }
617
618
                /*
619
                 * We do an implicit -wait if people muck about with a
620
                 * running syslog.
621
                 * This only works if the previous ->spec has completed
622
                 */
623 160
                if (s->run)
624 0
                        syslog_wait(s);
625
626 160
                AZ(s->run);
627 160
                if (!strcmp(*av, "-repeat")) {
628 0
                        AN(av[1]);
629 0
                        s->repeat = atoi(av[1]);
630 0
                        av++;
631 0
                        continue;
632
                }
633 160
                if (!strcmp(*av, "-bind")) {
634 40
                        AN(av[1]);
635 40
                        bprintf(s->bind, "%s", av[1]);
636 40
                        av++;
637 40
                        syslog_bind(s);
638 40
                        continue;
639
                }
640 120
                if (!strcmp(*av, "-level")) {
641 40
                        AN(av[1]);
642 40
                        s->lvl = get_syslog_level(vl, av[1]);
643 40
                        av++;
644 40
                        continue;
645
                }
646 80
                if (!strcmp(*av, "-start")) {
647 40
                        syslog_start(s);
648 40
                        continue;
649
                }
650 40
                if (**av == '-')
651 0
                        vtc_fatal(s->vl, "Unknown syslog argument: %s", *av);
652 40
                s->spec = *av;
653 40
        }
654 40240
}
655
656
void
657 40160
init_syslog(void)
658
{
659 40160
        PTOK(pthread_mutex_init(&syslog_mtx, NULL));
660 40160
}