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 50
get_syslog_level(struct vtclog *vl, const char *lvl)
103
{
104
        int i;
105
106 325
        for (i = 0; syslog_levels[i]; i++)
107 325
                if (!strcmp(lvl, syslog_levels[i]))
108 50
                        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 25
VUDP_Check(int a)
119
{
120 25
        if (a == 0)
121 25
                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 25
}
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 25
VUDP_close(int *s)
150
{
151
        int i;
152
153 25
        i = close(*s);
154
155 25
        assert(VUDP_Check(i));
156 25
        *s = -1;
157 25
}
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 25
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 25
        if (errp != NULL)
179 25
                *errp = NULL;
180
181 25
        proto = VSA_Get_Proto(sa);
182 25
        sd = socket(proto, SOCK_DGRAM, 0);
183 25
        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 25
        so = VSA_Get_Sockaddr(sa, &sl);
203 25
        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 25
        return (sd);
212 25
}
213
214
/*--------------------------------------------------------------------*/
215
216
struct udp_helper {
217
        const char      **errp;
218
};
219
220
static int v_matchproto_(vss_resolved_f)
221 25
vudp_lo_cb(void *priv, const struct suckaddr *sa)
222
{
223
        int sock;
224 25
        struct udp_helper *hp = priv;
225
226 25
        sock = VUDP_bind(sa, hp->errp);
227 25
        if (sock > 0) {
228 25
                *hp->errp = NULL;
229 25
                return (sock);
230
        }
231 0
        AN(*hp->errp);
232 0
        return (0);
233 25
}
234
235
static int
236 25
VUDP_bind_on(const char *addr, const char *def_port, const char **errp)
237
{
238
        struct udp_helper h;
239
        int sock;
240
241 25
        h.errp = errp;
242
243 25
        sock = VSS_resolver_socktype(
244 25
            addr, def_port, vudp_lo_cb, &h, errp, SOCK_DGRAM);
245 25
        if (*errp != NULL)
246 0
                return (-1);
247 25
        return (sock);
248 25
}
249
250
/**********************************************************************
251
 * Allocate and initialize a syslog
252
 */
253
254
static struct syslog_srv *
255 25
syslog_new(const char *name, struct vtclog *vl)
256
{
257
        struct syslog_srv *s;
258
259 25
        VTC_CHECK_NAME(vl, name, "Syslog", 'S');
260 25
        ALLOC_OBJ(s, SYSLOG_SRV_MAGIC);
261 25
        AN(s);
262 25
        REPLACE(s->name, name);
263 25
        s->vl = vtc_logopen("%s", s->name);
264 25
        AN(s->vl);
265 25
        vtc_log_set_cmd(s->vl, syslog_cmds);
266
267 25
        bprintf(s->bind, "%s", default_listen_addr);
268 25
        s->repeat = 1;
269 25
        s->sock = -1;
270 25
        s->lvl = -1;
271 25
        s->timeout = vtc_maxdur * .5;           // XXX
272
273 25
        vl = vtc_logopen("%s", s->name);
274 25
        AN(vl);
275
276 25
        s->rxbuf_sz = s->rxbuf_left = 2048*1024;
277 25
        s->rxbuf = malloc(s->rxbuf_sz);         /* XXX */
278 25
        AN(s->rxbuf);
279
280 25
        PTOK(pthread_mutex_lock(&syslog_mtx));
281 25
        VTAILQ_INSERT_TAIL(&syslogs, s, list);
282 25
        PTOK(pthread_mutex_unlock(&syslog_mtx));
283 25
        return (s);
284
}
285
286
/**********************************************************************
287
 * Clean up a syslog
288
 */
289
290
static void
291 25
syslog_delete(struct syslog_srv *s)
292
{
293
294 25
        CHECK_OBJ_NOTNULL(s, SYSLOG_SRV_MAGIC);
295 25
        macro_undef(s->vl, s->name, "addr");
296 25
        macro_undef(s->vl, s->name, "port");
297 25
        macro_undef(s->vl, s->name, "sock");
298 25
        vtc_logclose(s->vl);
299 25
        free(s->name);
300 25
        free(s->rxbuf);
301
        /* XXX: MEMLEAK (?) (VSS ??) */
302 25
        FREE_OBJ(s);
303 25
}
304
305
static void
306 25
syslog_rx(const struct syslog_srv *s, int lvl)
307
{
308
        ssize_t ret;
309
310 25
        while (!vtc_error) {
311
                /* Pointers to syslog priority value (see <PRIVAL>, rfc5424). */
312
                char *prib, *prie, *end;
313
                unsigned int prival;
314
315 25
                VTCP_set_read_timeout(s->sock, s->timeout);
316
317 25
                ret = recv(s->sock, s->rxbuf, s->rxbuf_sz - 1, 0);
318 25
                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 25
                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 25
                s->rxbuf[ret] = '\0';
332 25
                vtc_dump(s->vl, 4, "syslog", s->rxbuf, ret);
333
334 25
                prib = s->rxbuf;
335 25
                if (*prib++ != '<')
336 0
                        vtc_fatal(s->vl, "syslog PRI, no '<'");
337 25
                prie = strchr(prib, '>');
338 25
                if (prie == NULL)
339 0
                        vtc_fatal(s->vl, "syslog PRI, no '>'");
340
341 25
                prival = strtoul(prib, &end, 10);
342 25
                if (end != prie)
343 0
                        vtc_fatal(s->vl, "syslog PRI, bad number");
344
345 25
                if (lvl >= 0 && lvl == (prival & 0x7))
346 25
                        return;
347
        }
348 25
}
349
350
/**********************************************************************
351
 * Syslog server bind
352
 */
353
354
static void
355 25
syslog_bind(struct syslog_srv *s)
356
{
357
        const char *err;
358
        char aaddr[VTCP_ADDRBUFSIZE];
359
        char aport[VTCP_PORTBUFSIZE];
360 25
        char buf[vsa_suckaddr_len];
361
        const struct suckaddr *sua;
362
363 25
        CHECK_OBJ_NOTNULL(s, SYSLOG_SRV_MAGIC);
364
365 25
        if (s->sock >= 0)
366 0
                VUDP_close(&s->sock);
367 25
        s->sock = VUDP_bind_on(s->bind, "0", &err);
368 25
        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 25
        assert(s->sock > 0);
373 25
        sua = VSA_getsockname(s->sock, buf, sizeof buf);
374 25
        AN(sua);
375 25
        VTCP_name(sua, aaddr, sizeof aaddr, aport, sizeof aport);
376 25
        macro_def(s->vl, s->name, "addr", "%s", aaddr);
377 25
        macro_def(s->vl, s->name, "port", "%s", aport);
378 25
        if (VSA_Get_Proto(sua) == AF_INET)
379 25
                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 25
        bprintf(s->bind, "%s %s", aaddr, aport);
384 25
}
385
386
static void v_matchproto_(cmd_f)
387 25
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 25
        (void)vl;
396 25
        CAST_OBJ_NOTNULL(s, priv, SYSLOG_SRV_MAGIC);
397 25
        AZ(strcmp(av[0], "expect"));
398 25
        av++;
399
400 25
        cmp = av[0];
401 25
        spec = av[1];
402 25
        AN(cmp);
403 25
        AN(spec);
404 25
        AZ(av[2]);
405
406 25
        assert(!strcmp(cmp, "~") || !strcmp(cmp, "!~"));
407
408 25
        vre = VRE_compile(spec, 0, &error, &erroroffset, 1);
409 25
        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 25
        i = VRE_match(vre, s->rxbuf, 0, 0, NULL);
419
420 25
        VRE_free(&vre);
421
422 25
        ret = (i >= 0 && *cmp == '~') || (i < 0 && *cmp == '!');
423 25
        if (!ret)
424 0
                vtc_fatal(s->vl, "EXPECT FAILED %s \"%s\"", cmp, spec);
425
        else
426 25
                vtc_log(s->vl, 4, "EXPECT MATCH %s \"%s\"", cmp, spec);
427 25
}
428
429
static void v_matchproto_(cmd_f)
430 25
cmd_syslog_recv(CMD_ARGS)
431
{
432
        int lvl;
433
        struct syslog_srv *s;
434
435 25
        CAST_OBJ_NOTNULL(s, priv, SYSLOG_SRV_MAGIC);
436 25
        (void)vl;
437 25
        AZ(strcmp(av[0], "recv"));
438 25
        av++;
439 25
        if (av[0] == NULL)
440 0
                lvl = s->lvl;
441
        else
442 25
                lvl = get_syslog_level(vl, av[0]);
443
444 25
        syslog_rx(s, lvl);
445 25
}
446
447
/**********************************************************************
448
 * Syslog server thread
449
 */
450
451
static void *
452 25
syslog_thread(void *priv)
453
{
454
        struct syslog_srv *s;
455
        int i;
456
457 25
        CAST_OBJ_NOTNULL(s, priv, SYSLOG_SRV_MAGIC);
458 25
        assert(s->sock >= 0);
459
460 25
        vtc_log(s->vl, 2, "Started on %s (level: %d)", s->bind, s->lvl);
461 50
        for (i = 0; i < s->repeat; i++) {
462 25
                if (s->repeat > 1)
463 0
                        vtc_log(s->vl, 3, "Iteration %d", i);
464 25
                parse_string(s->vl, s, s->spec);
465 25
                vtc_log(s->vl, 3, "shutting fd %d", s->sock);
466 25
        }
467 25
        VUDP_close(&s->sock);
468 25
        vtc_log(s->vl, 2, "Ending");
469 25
        return (NULL);
470
}
471
472
/**********************************************************************
473
 * Start the syslog thread
474
 */
475
476
static void
477 25
syslog_start(struct syslog_srv *s)
478
{
479 25
        CHECK_OBJ_NOTNULL(s, SYSLOG_SRV_MAGIC);
480 25
        vtc_log(s->vl, 2, "Starting syslog server");
481 25
        if (s->sock == -1)
482 0
                syslog_bind(s);
483 25
        vtc_log(s->vl, 1, "Bound on %s", s->bind);
484 25
        s->run = 1;
485 25
        PTOK(pthread_create(&s->tp, NULL, syslog_thread, s));
486 25
}
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 25
syslog_wait(struct syslog_srv *s)
511
{
512
        void *res;
513
514 25
        CHECK_OBJ_NOTNULL(s, SYSLOG_SRV_MAGIC);
515 25
        vtc_log(s->vl, 2, "Waiting for syslog server (%d)", s->sock);
516 25
        PTOK(pthread_join(s->tp, &res));
517 25
        if (res != NULL && !vtc_stop)
518 0
                vtc_fatal(s->vl, "Syslog server returned \"%p\"",
519 0
                    (char *)res);
520 25
        s->tp = 0;
521 25
        s->run = 0;
522 25
}
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 24475
cmd_syslog(CMD_ARGS)
563
{
564
        struct syslog_srv *s;
565
566 24475
        (void)priv;
567
568 24475
        if (av == NULL) {
569
                /* Reset and free */
570 24425
                do {
571 24450
                        PTOK(pthread_mutex_lock(&syslog_mtx));
572 24450
                        s = VTAILQ_FIRST(&syslogs);
573 24450
                        CHECK_OBJ_ORNULL(s, SYSLOG_SRV_MAGIC);
574 24450
                        if (s != NULL)
575 25
                                VTAILQ_REMOVE(&syslogs, s, list);
576 24450
                        PTOK(pthread_mutex_unlock(&syslog_mtx));
577 24450
                        if (s != NULL) {
578 25
                                if (s->run) {
579 0
                                        (void)pthread_cancel(s->tp);
580 0
                                        syslog_wait(s);
581 0
                                }
582 25
                                if (s->sock >= 0)
583 0
                                        VUDP_close(&s->sock);
584 25
                                syslog_delete(s);
585 25
                        }
586 24450
                } while (s != NULL);
587 24425
                return;
588
        }
589
590 50
        AZ(strcmp(av[0], "syslog"));
591 50
        av++;
592
593 50
        PTOK(pthread_mutex_lock(&syslog_mtx));
594 50
        VTAILQ_FOREACH(s, &syslogs, list)
595 25
                if (!strcmp(s->name, av[0]))
596 25
                        break;
597 50
        PTOK(pthread_mutex_unlock(&syslog_mtx));
598 50
        if (s == NULL)
599 25
                s = syslog_new(av[0], vl);
600 50
        CHECK_OBJ_NOTNULL(s, SYSLOG_SRV_MAGIC);
601 50
        av++;
602
603 175
        for (; *av != NULL; av++) {
604 125
                if (vtc_error)
605 0
                        break;
606 125
                if (!strcmp(*av, "-wait")) {
607 25
                        if (!s->run)
608 0
                                vtc_fatal(s->vl, "Syslog server not -started");
609 25
                        syslog_wait(s);
610 25
                        continue;
611
                }
612
613 100
                if (!strcmp(*av, "-stop")) {
614 0
                        syslog_stop(s);
615 0
                        continue;
616
                }
617
618
                /*
619
                 * We do an implict -wait if people muck about with a
620
                 * running syslog.
621
                 * This only works if the previous ->spec has completed
622
                 */
623 100
                if (s->run)
624 0
                        syslog_wait(s);
625
626 100
                AZ(s->run);
627 100
                if (!strcmp(*av, "-repeat")) {
628 0
                        AN(av[1]);
629 0
                        s->repeat = atoi(av[1]);
630 0
                        av++;
631 0
                        continue;
632
                }
633 100
                if (!strcmp(*av, "-bind")) {
634 25
                        AN(av[1]);
635 25
                        bprintf(s->bind, "%s", av[1]);
636 25
                        av++;
637 25
                        syslog_bind(s);
638 25
                        continue;
639
                }
640 75
                if (!strcmp(*av, "-level")) {
641 25
                        AN(av[1]);
642 25
                        s->lvl = get_syslog_level(vl, av[1]);
643 25
                        av++;
644 25
                        continue;
645
                }
646 50
                if (!strcmp(*av, "-start")) {
647 25
                        syslog_start(s);
648 25
                        continue;
649
                }
650 25
                if (**av == '-')
651 0
                        vtc_fatal(s->vl, "Unknown syslog argument: %s", *av);
652 25
                s->spec = *av;
653 25
        }
654 24475
}
655
656
void
657 24425
init_syslog(void)
658
{
659 24425
        PTOK(pthread_mutex_init(&syslog_mtx, NULL));
660 24425
}