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