1*2ada0f0dSclaudio /* $OpenBSD: tftp-proxy.c,v 1.22 2021/01/17 13:38:52 claudio Exp $
2697c8096Sdlg *
3697c8096Sdlg * Copyright (c) 2005 DLS Internet Services
4697c8096Sdlg * Copyright (c) 2004, 2005 Camiel Dobbelaar, <cd@sentia.nl>
5697c8096Sdlg *
6697c8096Sdlg * Redistribution and use in source and binary forms, with or without
7697c8096Sdlg * modification, are permitted provided that the following conditions
8697c8096Sdlg * are met:
9697c8096Sdlg *
10697c8096Sdlg * 1. Redistributions of source code must retain the above copyright
11697c8096Sdlg * notice, this list of conditions and the following disclaimer.
12697c8096Sdlg * 2. Redistributions in binary form must reproduce the above copyright
13697c8096Sdlg * notice, this list of conditions and the following disclaimer in the
14697c8096Sdlg * documentation and/or other materials provided with the distribution.
15697c8096Sdlg * 3. The name of the author may not be used to endorse or promote products
16697c8096Sdlg * derived from this software without specific prior written permission.
17697c8096Sdlg *
18697c8096Sdlg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19697c8096Sdlg * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20697c8096Sdlg * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21697c8096Sdlg * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22697c8096Sdlg * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23697c8096Sdlg * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24697c8096Sdlg * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25697c8096Sdlg * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26697c8096Sdlg * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27697c8096Sdlg * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28697c8096Sdlg */
29697c8096Sdlg
30697c8096Sdlg #include <sys/types.h>
31b9fc9a72Sderaadt #include <sys/ioctl.h>
32697c8096Sdlg #include <sys/socket.h>
33697c8096Sdlg #include <sys/uio.h>
34697c8096Sdlg
35697c8096Sdlg #include <netinet/in.h>
36697c8096Sdlg #include <arpa/inet.h>
37697c8096Sdlg #include <arpa/tftp.h>
38697c8096Sdlg #include <net/if.h>
39697c8096Sdlg #include <net/pfvar.h>
40697c8096Sdlg #include <netdb.h>
41697c8096Sdlg
42697c8096Sdlg #include <unistd.h>
43697c8096Sdlg #include <errno.h>
44697c8096Sdlg #include <err.h>
45697c8096Sdlg #include <pwd.h>
46697c8096Sdlg #include <stdio.h>
47697c8096Sdlg #include <syslog.h>
48697c8096Sdlg #include <string.h>
49f9ed04f2Sflorian #include <stdarg.h>
50697c8096Sdlg #include <stdlib.h>
51697c8096Sdlg #include <event.h>
52697c8096Sdlg
53697c8096Sdlg #include "filter.h"
54697c8096Sdlg
55697c8096Sdlg #define CHROOT_DIR "/var/empty"
5641f70b94Sderaadt #define NOPRIV_USER "_tftp_proxy"
57697c8096Sdlg
58697c8096Sdlg #define DEFTRANSWAIT 2
59697c8096Sdlg #define NTOP_BUFS 4
60697c8096Sdlg #define PKTSIZE SEGSIZE+4
61697c8096Sdlg
62697c8096Sdlg const char *opcode(int);
63697c8096Sdlg const char *sock_ntop(struct sockaddr *);
64697c8096Sdlg static void usage(void);
65697c8096Sdlg
66697c8096Sdlg struct proxy_listener {
67697c8096Sdlg struct event ev;
68697c8096Sdlg TAILQ_ENTRY(proxy_listener) entry;
69697c8096Sdlg int (*cmsg2dst)(struct cmsghdr *, struct sockaddr_storage *);
70697c8096Sdlg int s;
71697c8096Sdlg };
72697c8096Sdlg
73697c8096Sdlg void proxy_listen(const char *, const char *, int);
74697c8096Sdlg void proxy_listener_events(void);
75697c8096Sdlg int proxy_dst4(struct cmsghdr *, struct sockaddr_storage *);
76697c8096Sdlg int proxy_dst6(struct cmsghdr *, struct sockaddr_storage *);
77697c8096Sdlg void proxy_recv(int, short, void *);
78697c8096Sdlg
79697c8096Sdlg struct fd_reply {
80697c8096Sdlg TAILQ_ENTRY(fd_reply) entry;
81697c8096Sdlg int fd;
82697c8096Sdlg };
83697c8096Sdlg
84697c8096Sdlg struct privproc {
85697c8096Sdlg struct event pop_ev;
86697c8096Sdlg struct event push_ev;
87697c8096Sdlg TAILQ_HEAD(, fd_reply) replies;
88697c8096Sdlg struct evbuffer *buf;
89697c8096Sdlg };
90697c8096Sdlg
91697c8096Sdlg void proxy_privproc(int, struct passwd *);
92697c8096Sdlg void privproc_push(int, short, void *);
93697c8096Sdlg void privproc_pop(int, short, void *);
94697c8096Sdlg
95697c8096Sdlg void unprivproc_push(int, short, void *);
96697c8096Sdlg void unprivproc_pop(int, short, void *);
97697c8096Sdlg void unprivproc_timeout(int, short, void *);
98697c8096Sdlg
99697c8096Sdlg char ntop_buf[NTOP_BUFS][INET6_ADDRSTRLEN];
100697c8096Sdlg
101697c8096Sdlg struct loggers {
102cd68c002Sflorian __dead void (*err)(int, const char *, ...)
103cd68c002Sflorian __attribute__((__format__ (printf, 2, 3)));
104cd68c002Sflorian __dead void (*errx)(int, const char *, ...)
105cd68c002Sflorian __attribute__((__format__ (printf, 2, 3)));
106cd68c002Sflorian void (*warn)(const char *, ...)
107cd68c002Sflorian __attribute__((__format__ (printf, 1, 2)));
108cd68c002Sflorian void (*warnx)(const char *, ...)
109cd68c002Sflorian __attribute__((__format__ (printf, 1, 2)));
110cd68c002Sflorian void (*info)(const char *, ...)
111cd68c002Sflorian __attribute__((__format__ (printf, 1, 2)));
112cd68c002Sflorian void (*debug)(const char *, ...)
113cd68c002Sflorian __attribute__((__format__ (printf, 1, 2)));
114697c8096Sdlg };
115697c8096Sdlg
116697c8096Sdlg const struct loggers conslogger = {
117697c8096Sdlg err,
118697c8096Sdlg errx,
119697c8096Sdlg warn,
120697c8096Sdlg warnx,
121cd68c002Sflorian warnx, /* info */
122cd68c002Sflorian warnx /* debug */
123697c8096Sdlg };
124697c8096Sdlg
125cd68c002Sflorian __dead void syslog_err(int, const char *, ...)
126cd68c002Sflorian __attribute__((__format__ (printf, 2, 3)));
127cd68c002Sflorian __dead void syslog_errx(int, const char *, ...)
128cd68c002Sflorian __attribute__((__format__ (printf, 2, 3)));
129cd68c002Sflorian void syslog_warn(const char *, ...)
130cd68c002Sflorian __attribute__((__format__ (printf, 1, 2)));
131cd68c002Sflorian void syslog_warnx(const char *, ...)
132cd68c002Sflorian __attribute__((__format__ (printf, 1, 2)));
133cd68c002Sflorian void syslog_info(const char *, ...)
134cd68c002Sflorian __attribute__((__format__ (printf, 1, 2)));
135cd68c002Sflorian void syslog_debug(const char *, ...)
136cd68c002Sflorian __attribute__((__format__ (printf, 1, 2)));
137cd68c002Sflorian void syslog_vstrerror(int, int, const char *, va_list)
138cd68c002Sflorian __attribute__((__format__ (printf, 3, 0)));
139697c8096Sdlg
140697c8096Sdlg const struct loggers syslogger = {
141697c8096Sdlg syslog_err,
142697c8096Sdlg syslog_errx,
143697c8096Sdlg syslog_warn,
144697c8096Sdlg syslog_warnx,
145697c8096Sdlg syslog_info,
146cd68c002Sflorian syslog_debug
147697c8096Sdlg };
148697c8096Sdlg
149697c8096Sdlg const struct loggers *logger = &conslogger;
150697c8096Sdlg
151697c8096Sdlg #define lerr(_e, _f...) logger->err((_e), _f)
152697c8096Sdlg #define lerrx(_e, _f...) logger->errx((_e), _f)
153697c8096Sdlg #define lwarn(_f...) logger->warn(_f)
154697c8096Sdlg #define lwarnx(_f...) logger->warnx(_f)
155697c8096Sdlg #define linfo(_f...) logger->info(_f)
156cd68c002Sflorian #define ldebug(_f...) logger->debug(_f)
157697c8096Sdlg
158697c8096Sdlg __dead void
usage(void)159697c8096Sdlg usage(void)
160697c8096Sdlg {
161697c8096Sdlg extern char *__progname;
16219875b15Sflorian fprintf(stderr, "usage: %s [-46dv] [-a address] [-l address] [-p port]"
1632c4cc476Sjmc " [-w transwait]\n", __progname);
164697c8096Sdlg exit(1);
165697c8096Sdlg }
166697c8096Sdlg
167697c8096Sdlg int debug = 0;
168697c8096Sdlg int verbose = 0;
169697c8096Sdlg struct timeval transwait = { DEFTRANSWAIT, 0 };
170697c8096Sdlg
171697c8096Sdlg int on = 1;
172697c8096Sdlg
173697c8096Sdlg struct addr_pair {
174697c8096Sdlg struct sockaddr_storage src;
175697c8096Sdlg struct sockaddr_storage dst;
176697c8096Sdlg };
177697c8096Sdlg
178697c8096Sdlg struct proxy_request {
179697c8096Sdlg char buf[SEGSIZE_MAX + 4];
180697c8096Sdlg size_t buflen;
181697c8096Sdlg
182697c8096Sdlg struct addr_pair addrs;
183697c8096Sdlg
184697c8096Sdlg struct event ev;
185697c8096Sdlg TAILQ_ENTRY(proxy_request) entry;
186697c8096Sdlg u_int32_t id;
187697c8096Sdlg };
188697c8096Sdlg
189697c8096Sdlg struct proxy_child {
190697c8096Sdlg TAILQ_HEAD(, proxy_request) fdrequests;
191697c8096Sdlg TAILQ_HEAD(, proxy_request) tmrequests;
192697c8096Sdlg struct event push_ev;
193697c8096Sdlg struct event pop_ev;
194697c8096Sdlg struct evbuffer *buf;
195697c8096Sdlg };
196697c8096Sdlg
197697c8096Sdlg struct proxy_child *child = NULL;
198697c8096Sdlg TAILQ_HEAD(, proxy_listener) proxy_listeners;
199697c8096Sdlg
20019875b15Sflorian struct src_addr {
20119875b15Sflorian TAILQ_ENTRY(src_addr) entry;
20219875b15Sflorian struct sockaddr_storage addr;
20319875b15Sflorian socklen_t addrlen;
20419875b15Sflorian };
20519875b15Sflorian TAILQ_HEAD(, src_addr) src_addrs;
20619875b15Sflorian
20719875b15Sflorian void source_addresses(const char*, int);
20819875b15Sflorian
209697c8096Sdlg int
main(int argc,char * argv[])210697c8096Sdlg main(int argc, char *argv[])
211697c8096Sdlg {
212697c8096Sdlg extern char *__progname;
213697c8096Sdlg
214697c8096Sdlg int c;
215697c8096Sdlg const char *errstr;
216697c8096Sdlg
217a4dc3638Sflorian struct src_addr *saddr, *saddr2;
218697c8096Sdlg struct passwd *pw;
219697c8096Sdlg
220697c8096Sdlg char *addr = "localhost";
221697c8096Sdlg char *port = "6969";
222697c8096Sdlg int family = AF_UNSPEC;
223697c8096Sdlg
224697c8096Sdlg int pair[2];
225697c8096Sdlg
22619875b15Sflorian TAILQ_INIT(&src_addrs);
22719875b15Sflorian
22819875b15Sflorian while ((c = getopt(argc, argv, "46a:dvl:p:w:")) != -1) {
229697c8096Sdlg switch (c) {
230697c8096Sdlg case '4':
231697c8096Sdlg family = AF_INET;
232697c8096Sdlg break;
233697c8096Sdlg case '6':
234697c8096Sdlg family = AF_INET6;
235697c8096Sdlg break;
23619875b15Sflorian case 'a':
237a4dc3638Sflorian source_addresses(optarg, family);
23819875b15Sflorian break;
239697c8096Sdlg case 'd':
240697c8096Sdlg verbose = debug = 1;
241697c8096Sdlg break;
242697c8096Sdlg case 'l':
243697c8096Sdlg addr = optarg;
244697c8096Sdlg break;
245697c8096Sdlg case 'p':
246697c8096Sdlg port = optarg;
247697c8096Sdlg break;
248697c8096Sdlg case 'v':
249697c8096Sdlg verbose = 1;
250697c8096Sdlg break;
251697c8096Sdlg case 'w':
252697c8096Sdlg transwait.tv_sec = strtonum(optarg, 1, 30, &errstr);
253697c8096Sdlg if (errstr)
254697c8096Sdlg errx(1, "wait is %s", errstr);
255697c8096Sdlg break;
256697c8096Sdlg default:
257697c8096Sdlg usage();
258697c8096Sdlg /* NOTREACHED */
259697c8096Sdlg }
260697c8096Sdlg }
261697c8096Sdlg
262697c8096Sdlg if (geteuid() != 0)
2635d08eca0Sjca lerrx(1, "need root privileges");
264697c8096Sdlg
265e18a0880Sguenther if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, PF_UNSPEC, pair)
266e18a0880Sguenther == -1)
267697c8096Sdlg lerr(1, "socketpair");
268697c8096Sdlg
269697c8096Sdlg pw = getpwnam(NOPRIV_USER);
270697c8096Sdlg if (pw == NULL)
271697c8096Sdlg lerrx(1, "no %s user", NOPRIV_USER);
272697c8096Sdlg
273a4dc3638Sflorian /* Family option may have been specified late. */
274a4dc3638Sflorian if (family != AF_UNSPEC)
275a4dc3638Sflorian TAILQ_FOREACH_SAFE(saddr, &src_addrs, entry, saddr2)
276a4dc3638Sflorian if (saddr->addr.ss_family != family) {
277a4dc3638Sflorian TAILQ_REMOVE(&src_addrs, saddr, entry);
278a4dc3638Sflorian free(saddr);
279a4dc3638Sflorian }
28019875b15Sflorian
2815d08eca0Sjca if (!debug) {
2825d08eca0Sjca if (daemon(1, 0) == -1)
2835d08eca0Sjca lerr(1, "daemon");
2845d08eca0Sjca
2855d08eca0Sjca openlog(__progname, LOG_PID|LOG_NDELAY, LOG_DAEMON);
2865d08eca0Sjca tzset();
2875d08eca0Sjca logger = &syslogger;
2885d08eca0Sjca }
2895d08eca0Sjca
290697c8096Sdlg switch (fork()) {
291697c8096Sdlg case -1:
292697c8096Sdlg lerr(1, "fork");
293697c8096Sdlg
294697c8096Sdlg case 0:
295697c8096Sdlg setproctitle("privproc");
296697c8096Sdlg close(pair[1]);
297697c8096Sdlg proxy_privproc(pair[0], pw);
298697c8096Sdlg /* this never returns */
299697c8096Sdlg
300697c8096Sdlg default:
301697c8096Sdlg setproctitle("unprivproc");
302697c8096Sdlg close(pair[0]);
303697c8096Sdlg break;
304697c8096Sdlg }
305697c8096Sdlg
306697c8096Sdlg child = calloc(1, sizeof(*child));
307697c8096Sdlg if (child == NULL)
308697c8096Sdlg lerr(1, "alloc(child)");
309697c8096Sdlg
310697c8096Sdlg child->buf = evbuffer_new();
311697c8096Sdlg if (child->buf == NULL)
312697c8096Sdlg lerr(1, "child evbuffer");
313697c8096Sdlg
314697c8096Sdlg TAILQ_INIT(&child->fdrequests);
315697c8096Sdlg TAILQ_INIT(&child->tmrequests);
316697c8096Sdlg
317697c8096Sdlg proxy_listen(addr, port, family);
318697c8096Sdlg
319697c8096Sdlg /* open /dev/pf */
320697c8096Sdlg init_filter(NULL, verbose);
321697c8096Sdlg
322697c8096Sdlg /* revoke privs */
323697c8096Sdlg if (chroot(CHROOT_DIR) == -1)
324697c8096Sdlg lerr(1, "chroot %s", CHROOT_DIR);
325697c8096Sdlg
326697c8096Sdlg if (chdir("/") == -1)
327697c8096Sdlg lerr(1, "chdir %s", CHROOT_DIR);
328697c8096Sdlg
329697c8096Sdlg if (setgroups(1, &pw->pw_gid) ||
330697c8096Sdlg setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
331697c8096Sdlg setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
332697c8096Sdlg err(1, "unable to revoke privs");
333697c8096Sdlg
334697c8096Sdlg event_init();
335697c8096Sdlg
336697c8096Sdlg proxy_listener_events();
337697c8096Sdlg
338697c8096Sdlg event_set(&child->pop_ev, pair[1], EV_READ | EV_PERSIST,
339697c8096Sdlg unprivproc_pop, NULL);
340697c8096Sdlg event_set(&child->push_ev, pair[1], EV_WRITE,
341697c8096Sdlg unprivproc_push, NULL);
342697c8096Sdlg
343697c8096Sdlg event_add(&child->pop_ev, NULL);
344697c8096Sdlg
345697c8096Sdlg event_dispatch();
346697c8096Sdlg
347697c8096Sdlg return(0);
348697c8096Sdlg }
349697c8096Sdlg
35019875b15Sflorian void
source_addresses(const char * name,int family)35119875b15Sflorian source_addresses(const char* name, int family)
35219875b15Sflorian {
35319875b15Sflorian struct addrinfo hints, *res, *res0;
35419875b15Sflorian struct src_addr *saddr;
35519875b15Sflorian int error;
35619875b15Sflorian
35719875b15Sflorian memset(&hints, 0, sizeof(hints));
35819875b15Sflorian hints.ai_family = family;
35919875b15Sflorian hints.ai_socktype = SOCK_DGRAM;
36019875b15Sflorian hints.ai_flags = AI_PASSIVE;
36119875b15Sflorian error = getaddrinfo(name, NULL, &hints, &res0);
36219875b15Sflorian if (error)
36319875b15Sflorian lerrx(1, "%s: %s", name, gai_strerror(error));
36419875b15Sflorian for (res = res0; res != NULL; res = res->ai_next) {
36519875b15Sflorian if ((saddr = calloc(1, sizeof(struct src_addr))) == NULL)
36619875b15Sflorian lerrx(1, "calloc");
36719875b15Sflorian memcpy(&(saddr->addr), res->ai_addr, res->ai_addrlen);
36819875b15Sflorian saddr->addrlen = res->ai_addrlen;
36919875b15Sflorian TAILQ_INSERT_TAIL(&src_addrs, saddr, entry);
37019875b15Sflorian }
37119875b15Sflorian freeaddrinfo(res0);
37219875b15Sflorian }
373697c8096Sdlg
374697c8096Sdlg void
proxy_privproc(int s,struct passwd * pw)375697c8096Sdlg proxy_privproc(int s, struct passwd *pw)
376697c8096Sdlg {
377697c8096Sdlg struct privproc p;
378697c8096Sdlg
379697c8096Sdlg if (chroot(CHROOT_DIR) == -1)
380697c8096Sdlg lerr(1, "chroot to %s", CHROOT_DIR);
381697c8096Sdlg
382697c8096Sdlg if (chdir("/") == -1)
383697c8096Sdlg lerr(1, "chdir to %s", CHROOT_DIR);
384697c8096Sdlg
385697c8096Sdlg if (setgroups(1, &pw->pw_gid) ||
386697c8096Sdlg setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid))
387697c8096Sdlg lerr(1, "unable to set group ids");
388697c8096Sdlg
3891179e37dSderaadt if (pledge("stdio inet sendfd", NULL) == -1)
3901179e37dSderaadt err(1, "pledge");
3911179e37dSderaadt
392697c8096Sdlg TAILQ_INIT(&p.replies);
393697c8096Sdlg
394697c8096Sdlg p.buf = evbuffer_new();
395697c8096Sdlg if (p.buf == NULL)
396697c8096Sdlg err(1, "pop evbuffer_new");
397697c8096Sdlg
398697c8096Sdlg event_init();
399697c8096Sdlg
400697c8096Sdlg event_set(&p.pop_ev, s, EV_READ | EV_PERSIST, privproc_pop, &p);
401697c8096Sdlg event_set(&p.push_ev, s, EV_WRITE, privproc_push, &p);
402697c8096Sdlg
403697c8096Sdlg event_add(&p.pop_ev, NULL);
404697c8096Sdlg
405697c8096Sdlg event_dispatch();
406697c8096Sdlg }
407697c8096Sdlg
408697c8096Sdlg void
privproc_pop(int fd,short events,void * arg)409697c8096Sdlg privproc_pop(int fd, short events, void *arg)
410697c8096Sdlg {
411697c8096Sdlg struct addr_pair req;
412697c8096Sdlg struct privproc *p = arg;
413697c8096Sdlg struct fd_reply *rep;
41419875b15Sflorian struct src_addr *saddr;
415697c8096Sdlg int add = 0;
416697c8096Sdlg
417697c8096Sdlg switch (evbuffer_read(p->buf, fd, sizeof(req))) {
418697c8096Sdlg case 0:
419697c8096Sdlg lerrx(1, "unprivproc has gone");
420697c8096Sdlg case -1:
421697c8096Sdlg switch (errno) {
422697c8096Sdlg case EAGAIN:
423697c8096Sdlg case EINTR:
424697c8096Sdlg return;
425697c8096Sdlg default:
426697c8096Sdlg lerr(1, "privproc_pop read");
427697c8096Sdlg }
428697c8096Sdlg default:
429697c8096Sdlg break;
430697c8096Sdlg }
431697c8096Sdlg
432697c8096Sdlg while (EVBUFFER_LENGTH(p->buf) >= sizeof(req)) {
433697c8096Sdlg evbuffer_remove(p->buf, &req, sizeof(req));
434697c8096Sdlg
435697c8096Sdlg /* do i really need to check this? */
436697c8096Sdlg if (req.src.ss_family != req.dst.ss_family)
437697c8096Sdlg lerrx(1, "family mismatch");
438697c8096Sdlg
439697c8096Sdlg rep = calloc(1, sizeof(*rep));
440697c8096Sdlg if (rep == NULL)
441697c8096Sdlg lerr(1, "reply calloc");
442697c8096Sdlg
443e18a0880Sguenther rep->fd = socket(req.src.ss_family, SOCK_DGRAM | SOCK_NONBLOCK,
444e18a0880Sguenther IPPROTO_UDP);
445697c8096Sdlg if (rep->fd == -1)
446697c8096Sdlg lerr(1, "privproc socket");
447697c8096Sdlg
448697c8096Sdlg if (setsockopt(rep->fd, SOL_SOCKET, SO_BINDANY,
449697c8096Sdlg &on, sizeof(on)) == -1)
450697c8096Sdlg lerr(1, "privproc setsockopt(BINDANY)");
451697c8096Sdlg
452697c8096Sdlg if (setsockopt(rep->fd, SOL_SOCKET, SO_REUSEADDR,
453697c8096Sdlg &on, sizeof(on)) == -1)
454697c8096Sdlg lerr(1, "privproc setsockopt(REUSEADDR)");
455697c8096Sdlg
456697c8096Sdlg if (setsockopt(rep->fd, SOL_SOCKET, SO_REUSEPORT,
457697c8096Sdlg &on, sizeof(on)) == -1)
458697c8096Sdlg lerr(1, "privproc setsockopt(REUSEPORT)");
459697c8096Sdlg
460b27441feSflorian TAILQ_FOREACH(saddr, &src_addrs, entry)
461b27441feSflorian if (saddr->addr.ss_family == req.src.ss_family)
462b27441feSflorian break;
463b27441feSflorian if (saddr == NULL) {
464697c8096Sdlg if (bind(rep->fd, (struct sockaddr *)&req.src,
465697c8096Sdlg req.src.ss_len) == -1)
466697c8096Sdlg lerr(1, "privproc bind");
46719875b15Sflorian } else {
468b27441feSflorian if (bind(rep->fd, (struct sockaddr*)&saddr->addr,
469b27441feSflorian saddr->addrlen) == -1)
47019875b15Sflorian lerr(1, "privproc bind");
47119875b15Sflorian }
472697c8096Sdlg
473697c8096Sdlg if (TAILQ_EMPTY(&p->replies))
474697c8096Sdlg add = 1;
475697c8096Sdlg
476697c8096Sdlg TAILQ_INSERT_TAIL(&p->replies, rep, entry);
477697c8096Sdlg }
478697c8096Sdlg
479697c8096Sdlg if (add)
480697c8096Sdlg event_add(&p->push_ev, NULL);
481697c8096Sdlg }
482697c8096Sdlg
483697c8096Sdlg void
privproc_push(int fd,short events,void * arg)484697c8096Sdlg privproc_push(int fd, short events, void *arg)
485697c8096Sdlg {
486697c8096Sdlg struct privproc *p = arg;
487697c8096Sdlg struct fd_reply *rep;
488697c8096Sdlg
489697c8096Sdlg struct msghdr msg;
490697c8096Sdlg union {
491697c8096Sdlg struct cmsghdr hdr;
492697c8096Sdlg char buf[CMSG_SPACE(sizeof(int))];
493697c8096Sdlg } cmsgbuf;
494697c8096Sdlg struct cmsghdr *cmsg;
495697c8096Sdlg struct iovec iov;
496697c8096Sdlg int result = 0;
497697c8096Sdlg
498697c8096Sdlg while ((rep = TAILQ_FIRST(&p->replies)) != NULL) {
499697c8096Sdlg memset(&msg, 0, sizeof(msg));
500697c8096Sdlg
501697c8096Sdlg msg.msg_control = (caddr_t)&cmsgbuf.buf;
502697c8096Sdlg msg.msg_controllen = sizeof(cmsgbuf.buf);
503697c8096Sdlg cmsg = CMSG_FIRSTHDR(&msg);
504697c8096Sdlg cmsg->cmsg_len = CMSG_LEN(sizeof(int));
505697c8096Sdlg cmsg->cmsg_level = SOL_SOCKET;
506697c8096Sdlg cmsg->cmsg_type = SCM_RIGHTS;
507697c8096Sdlg *(int *)CMSG_DATA(cmsg) = rep->fd;
508697c8096Sdlg
509697c8096Sdlg iov.iov_base = &result;
510697c8096Sdlg iov.iov_len = sizeof(int);
511697c8096Sdlg msg.msg_iov = &iov;
512697c8096Sdlg msg.msg_iovlen = 1;
513697c8096Sdlg
514697c8096Sdlg switch (sendmsg(fd, &msg, 0)) {
515697c8096Sdlg case sizeof(int):
516697c8096Sdlg break;
517697c8096Sdlg
518697c8096Sdlg case -1:
519697c8096Sdlg if (errno == EAGAIN)
520697c8096Sdlg goto again;
521697c8096Sdlg
522697c8096Sdlg lerr(1, "privproc sendmsg");
523697c8096Sdlg /* NOTREACHED */
524697c8096Sdlg
525697c8096Sdlg default:
526697c8096Sdlg lerrx(1, "privproc sendmsg weird len");
527697c8096Sdlg }
528697c8096Sdlg
529697c8096Sdlg TAILQ_REMOVE(&p->replies, rep, entry);
530697c8096Sdlg close(rep->fd);
531697c8096Sdlg free(rep);
532697c8096Sdlg }
533697c8096Sdlg
534697c8096Sdlg if (TAILQ_EMPTY(&p->replies))
535697c8096Sdlg return;
536697c8096Sdlg
537697c8096Sdlg again:
538697c8096Sdlg event_add(&p->push_ev, NULL);
539697c8096Sdlg }
540697c8096Sdlg
541697c8096Sdlg void
proxy_listen(const char * addr,const char * port,int family)542697c8096Sdlg proxy_listen(const char *addr, const char *port, int family)
543697c8096Sdlg {
544697c8096Sdlg struct proxy_listener *l;
545697c8096Sdlg
546697c8096Sdlg struct addrinfo hints, *res, *res0;
547697c8096Sdlg int error;
5488f072f6eSderaadt int s, on = 1;
549697c8096Sdlg int serrno;
550697c8096Sdlg const char *cause = NULL;
551697c8096Sdlg
552697c8096Sdlg memset(&hints, 0, sizeof(hints));
553697c8096Sdlg hints.ai_family = family;
554697c8096Sdlg hints.ai_socktype = SOCK_DGRAM;
555697c8096Sdlg hints.ai_flags = AI_PASSIVE;
556697c8096Sdlg
557697c8096Sdlg TAILQ_INIT(&proxy_listeners);
558697c8096Sdlg
559697c8096Sdlg error = getaddrinfo(addr, port, &hints, &res0);
560697c8096Sdlg if (error)
561697c8096Sdlg errx(1, "%s:%s: %s", addr, port, gai_strerror(error));
562697c8096Sdlg
563697c8096Sdlg for (res = res0; res != NULL; res = res->ai_next) {
564e18a0880Sguenther s = socket(res->ai_family, res->ai_socktype | SOCK_NONBLOCK,
565e18a0880Sguenther res->ai_protocol);
566697c8096Sdlg if (s == -1) {
567697c8096Sdlg cause = "socket";
568697c8096Sdlg continue;
569697c8096Sdlg }
570697c8096Sdlg
571697c8096Sdlg if (bind(s, res->ai_addr, res->ai_addrlen) == -1) {
572697c8096Sdlg cause = "bind";
573697c8096Sdlg serrno = errno;
574697c8096Sdlg close(s);
575697c8096Sdlg errno = serrno;
576697c8096Sdlg continue;
577697c8096Sdlg }
578697c8096Sdlg
579697c8096Sdlg l = calloc(1, sizeof(*l));
580697c8096Sdlg if (l == NULL)
581697c8096Sdlg err(1, "listener alloc");
582697c8096Sdlg
583697c8096Sdlg switch (res->ai_family) {
584697c8096Sdlg case AF_INET:
585697c8096Sdlg l->cmsg2dst = proxy_dst4;
586697c8096Sdlg
587697c8096Sdlg if (setsockopt(s, IPPROTO_IP, IP_RECVDSTADDR,
588697c8096Sdlg &on, sizeof(on)) == -1)
589697c8096Sdlg errx(1, "setsockopt(IP_RECVDSTADDR)");
590697c8096Sdlg if (setsockopt(s, IPPROTO_IP, IP_RECVDSTPORT,
591697c8096Sdlg &on, sizeof(on)) == -1)
592697c8096Sdlg errx(1, "setsockopt(IP_RECVDSTPORT)");
593697c8096Sdlg break;
594697c8096Sdlg case AF_INET6:
595697c8096Sdlg l->cmsg2dst = proxy_dst6;
596697c8096Sdlg
597697c8096Sdlg if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO,
598697c8096Sdlg &on, sizeof(on)) == -1)
599697c8096Sdlg errx(1, "setsockopt(IPV6_RECVPKTINFO)");
600bc7a20e3Sbenno if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVDSTPORT,
601bc7a20e3Sbenno &on, sizeof(on)) == -1)
602bc7a20e3Sbenno errx(1, "setsockopt(IPV6_RECVDSTPORT)");
603697c8096Sdlg break;
604697c8096Sdlg }
605697c8096Sdlg l->s = s;
606697c8096Sdlg
607697c8096Sdlg TAILQ_INSERT_TAIL(&proxy_listeners, l, entry);
608697c8096Sdlg }
60980b8c347Sflorian freeaddrinfo(res0);
610697c8096Sdlg
611697c8096Sdlg if (TAILQ_EMPTY(&proxy_listeners))
612697c8096Sdlg err(1, "%s", cause);
613697c8096Sdlg }
614697c8096Sdlg
615697c8096Sdlg void
proxy_listener_events(void)616697c8096Sdlg proxy_listener_events(void)
617697c8096Sdlg {
618697c8096Sdlg struct proxy_listener *l;
619697c8096Sdlg
620697c8096Sdlg TAILQ_FOREACH(l, &proxy_listeners, entry) {
621697c8096Sdlg event_set(&l->ev, l->s, EV_READ | EV_PERSIST, proxy_recv, l);
622697c8096Sdlg event_add(&l->ev, NULL);
623697c8096Sdlg }
624697c8096Sdlg }
625697c8096Sdlg
626697c8096Sdlg char safety[SEGSIZE_MAX + 4];
627697c8096Sdlg
628697c8096Sdlg int
proxy_dst4(struct cmsghdr * cmsg,struct sockaddr_storage * ss)629697c8096Sdlg proxy_dst4(struct cmsghdr *cmsg, struct sockaddr_storage *ss)
630697c8096Sdlg {
631697c8096Sdlg struct sockaddr_in *sin = (struct sockaddr_in *)ss;
632697c8096Sdlg
633697c8096Sdlg if (cmsg->cmsg_level != IPPROTO_IP)
634697c8096Sdlg return (0);
635697c8096Sdlg
636697c8096Sdlg switch (cmsg->cmsg_type) {
637697c8096Sdlg case IP_RECVDSTADDR:
638697c8096Sdlg memcpy(&sin->sin_addr, CMSG_DATA(cmsg), sizeof(sin->sin_addr));
639697c8096Sdlg if (sin->sin_addr.s_addr == INADDR_BROADCAST)
640697c8096Sdlg return (-1);
641697c8096Sdlg break;
642697c8096Sdlg
643697c8096Sdlg case IP_RECVDSTPORT:
644697c8096Sdlg memcpy(&sin->sin_port, CMSG_DATA(cmsg), sizeof(sin->sin_port));
645697c8096Sdlg break;
646697c8096Sdlg }
647697c8096Sdlg
648697c8096Sdlg return (0);
649697c8096Sdlg }
650697c8096Sdlg
651697c8096Sdlg int
proxy_dst6(struct cmsghdr * cmsg,struct sockaddr_storage * ss)652697c8096Sdlg proxy_dst6(struct cmsghdr *cmsg, struct sockaddr_storage *ss)
653697c8096Sdlg {
654697c8096Sdlg struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ss;
655697c8096Sdlg struct in6_pktinfo *ipi = (struct in6_pktinfo *)CMSG_DATA(cmsg);
656697c8096Sdlg
657697c8096Sdlg if (cmsg->cmsg_level != IPPROTO_IPV6)
658697c8096Sdlg return (0);
659697c8096Sdlg
660697c8096Sdlg switch (cmsg->cmsg_type) {
661697c8096Sdlg case IPV6_PKTINFO:
662697c8096Sdlg memcpy(&sin6->sin6_addr, &ipi->ipi6_addr,
663697c8096Sdlg sizeof(sin6->sin6_addr));
664697c8096Sdlg if (IN6_IS_ADDR_LINKLOCAL(&ipi->ipi6_addr))
665697c8096Sdlg sin6->sin6_scope_id = ipi->ipi6_ifindex;
666697c8096Sdlg break;
667bc7a20e3Sbenno case IPV6_RECVDSTPORT:
668bc7a20e3Sbenno memcpy(&sin6->sin6_port, CMSG_DATA(cmsg),
669bc7a20e3Sbenno sizeof(sin6->sin6_port));
670bc7a20e3Sbenno break;
671697c8096Sdlg }
672697c8096Sdlg
673697c8096Sdlg return (0);
674697c8096Sdlg }
675697c8096Sdlg
676697c8096Sdlg void
proxy_recv(int fd,short events,void * arg)677697c8096Sdlg proxy_recv(int fd, short events, void *arg)
678697c8096Sdlg {
679697c8096Sdlg struct proxy_listener *l = arg;
680697c8096Sdlg
681697c8096Sdlg union {
682697c8096Sdlg struct cmsghdr hdr;
683697c8096Sdlg char buf[CMSG_SPACE(sizeof(struct sockaddr_storage)) +
684697c8096Sdlg CMSG_SPACE(sizeof(in_port_t))];
685697c8096Sdlg } cmsgbuf;
686697c8096Sdlg struct cmsghdr *cmsg;
687697c8096Sdlg struct msghdr msg;
688697c8096Sdlg struct iovec iov;
689697c8096Sdlg ssize_t n;
690697c8096Sdlg
691697c8096Sdlg struct proxy_request *r;
692697c8096Sdlg struct tftphdr *tp;
693697c8096Sdlg
694697c8096Sdlg r = calloc(1, sizeof(*r));
695697c8096Sdlg if (r == NULL) {
696697c8096Sdlg recv(fd, safety, sizeof(safety), 0);
697697c8096Sdlg return;
698697c8096Sdlg }
699697c8096Sdlg r->id = arc4random(); /* XXX unique? */
700697c8096Sdlg
701697c8096Sdlg bzero(&msg, sizeof(msg));
702697c8096Sdlg iov.iov_base = r->buf;
703697c8096Sdlg iov.iov_len = sizeof(r->buf);
704697c8096Sdlg msg.msg_name = &r->addrs.src;
705697c8096Sdlg msg.msg_namelen = sizeof(r->addrs.src);
706697c8096Sdlg msg.msg_iov = &iov;
707697c8096Sdlg msg.msg_iovlen = 1;
708697c8096Sdlg msg.msg_control = &cmsgbuf.buf;
709697c8096Sdlg msg.msg_controllen = sizeof(cmsgbuf.buf);
710697c8096Sdlg
711697c8096Sdlg n = recvmsg(fd, &msg, 0);
712697c8096Sdlg if (n == -1) {
713697c8096Sdlg switch (errno) {
714697c8096Sdlg case EAGAIN:
715697c8096Sdlg case EINTR:
716697c8096Sdlg goto err;
717697c8096Sdlg default:
718697c8096Sdlg lerr(1, "recvmsg");
719697c8096Sdlg /* NOTREACHED */
720697c8096Sdlg }
721697c8096Sdlg }
722697c8096Sdlg r->buflen = n;
723697c8096Sdlg
724697c8096Sdlg /* check the packet */
725697c8096Sdlg if (n < 5) {
726697c8096Sdlg /* not enough to be a real packet */
727697c8096Sdlg goto err;
728697c8096Sdlg }
729697c8096Sdlg tp = (struct tftphdr *)r->buf;
730697c8096Sdlg switch (ntohs(tp->th_opcode)) {
731697c8096Sdlg case RRQ:
732697c8096Sdlg case WRQ:
733697c8096Sdlg break;
734697c8096Sdlg default:
735697c8096Sdlg goto err;
736697c8096Sdlg }
737697c8096Sdlg
738697c8096Sdlg r->addrs.dst.ss_family = r->addrs.src.ss_family;
739697c8096Sdlg r->addrs.dst.ss_len = r->addrs.src.ss_len;
740697c8096Sdlg
741697c8096Sdlg /* get local address if possible */
742697c8096Sdlg for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
743697c8096Sdlg cmsg = CMSG_NXTHDR(&msg, cmsg)) {
744697c8096Sdlg if (l->cmsg2dst(cmsg, &r->addrs.dst) == -1)
745697c8096Sdlg goto err;
746697c8096Sdlg }
747697c8096Sdlg
748697c8096Sdlg if (verbose) {
749697c8096Sdlg linfo("%s:%d -> %s:%d \"%s %s\"",
750697c8096Sdlg sock_ntop((struct sockaddr *)&r->addrs.src),
751697c8096Sdlg ntohs(((struct sockaddr_in *)&r->addrs.src)->sin_port),
752697c8096Sdlg sock_ntop((struct sockaddr *)&r->addrs.dst),
753697c8096Sdlg ntohs(((struct sockaddr_in *)&r->addrs.dst)->sin_port),
754697c8096Sdlg opcode(ntohs(tp->th_opcode)), tp->th_stuff);
755697c8096Sdlg /* XXX tp->th_stuff could be garbage */
756697c8096Sdlg }
757697c8096Sdlg
758697c8096Sdlg TAILQ_INSERT_TAIL(&child->fdrequests, r, entry);
759697c8096Sdlg evbuffer_add(child->buf, &r->addrs, sizeof(r->addrs));
760697c8096Sdlg event_add(&child->push_ev, NULL);
761697c8096Sdlg
762697c8096Sdlg return;
763697c8096Sdlg
764697c8096Sdlg err:
765697c8096Sdlg free(r);
766697c8096Sdlg }
767697c8096Sdlg
768697c8096Sdlg void
unprivproc_push(int fd,short events,void * arg)769697c8096Sdlg unprivproc_push(int fd, short events, void *arg)
770697c8096Sdlg {
771697c8096Sdlg if (evbuffer_write(child->buf, fd) == -1)
772697c8096Sdlg lerr(1, "child evbuffer_write");
773697c8096Sdlg
774697c8096Sdlg if (EVBUFFER_LENGTH(child->buf))
775697c8096Sdlg event_add(&child->push_ev, NULL);
776697c8096Sdlg }
777697c8096Sdlg
778697c8096Sdlg void
unprivproc_pop(int fd,short events,void * arg)779697c8096Sdlg unprivproc_pop(int fd, short events, void *arg)
780697c8096Sdlg {
781697c8096Sdlg struct proxy_request *r;
782697c8096Sdlg
783697c8096Sdlg struct msghdr msg;
784697c8096Sdlg union {
785697c8096Sdlg struct cmsghdr hdr;
786697c8096Sdlg char buf[CMSG_SPACE(sizeof(int))];
787697c8096Sdlg } cmsgbuf;
788697c8096Sdlg struct cmsghdr *cmsg;
789697c8096Sdlg struct iovec iov;
790b27441feSflorian struct src_addr *src_addr;
79119875b15Sflorian struct sockaddr_storage saddr;
79219875b15Sflorian socklen_t len;
793697c8096Sdlg int result;
794697c8096Sdlg int s;
795697c8096Sdlg
79619875b15Sflorian len = sizeof(saddr);
79719875b15Sflorian
798697c8096Sdlg do {
799697c8096Sdlg memset(&msg, 0, sizeof(msg));
800697c8096Sdlg iov.iov_base = &result;
801697c8096Sdlg iov.iov_len = sizeof(int);
802697c8096Sdlg msg.msg_iov = &iov;
803697c8096Sdlg msg.msg_iovlen = 1;
804697c8096Sdlg msg.msg_control = &cmsgbuf.buf;
805697c8096Sdlg msg.msg_controllen = sizeof(cmsgbuf.buf);
806697c8096Sdlg
807697c8096Sdlg switch (recvmsg(fd, &msg, 0)) {
808697c8096Sdlg case sizeof(int):
809697c8096Sdlg break;
810697c8096Sdlg
811697c8096Sdlg case -1:
812697c8096Sdlg switch (errno) {
813697c8096Sdlg case EAGAIN:
814697c8096Sdlg case EINTR:
815697c8096Sdlg return;
816697c8096Sdlg default:
817697c8096Sdlg lerr(1, "child recvmsg");
818697c8096Sdlg }
819697c8096Sdlg /* NOTREACHED */
820697c8096Sdlg
821697c8096Sdlg case 0:
822697c8096Sdlg lerrx(1, "privproc closed connection");
823697c8096Sdlg
824697c8096Sdlg default:
825697c8096Sdlg lerrx(1, "child recvmsg was weird");
826697c8096Sdlg /* NOTREACHED */
827697c8096Sdlg }
828697c8096Sdlg
829697c8096Sdlg if (result != 0) {
830697c8096Sdlg errno = result;
831697c8096Sdlg lerr(1, "child fdpass fail");
832697c8096Sdlg }
833697c8096Sdlg
834697c8096Sdlg cmsg = CMSG_FIRSTHDR(&msg);
835697c8096Sdlg if (cmsg == NULL)
836697c8096Sdlg lerrx(1, "%s: no message header", __func__);
837697c8096Sdlg
838697c8096Sdlg if (cmsg->cmsg_type != SCM_RIGHTS) {
839697c8096Sdlg lerrx(1, "%s: expected type %d got %d", __func__,
840697c8096Sdlg SCM_RIGHTS, cmsg->cmsg_type);
841697c8096Sdlg }
842697c8096Sdlg
843697c8096Sdlg s = (*(int *)CMSG_DATA(cmsg));
844697c8096Sdlg
845697c8096Sdlg r = TAILQ_FIRST(&child->fdrequests);
846697c8096Sdlg if (r == NULL)
847697c8096Sdlg lerrx(1, "got fd without a pending request");
848697c8096Sdlg
849697c8096Sdlg TAILQ_REMOVE(&child->fdrequests, r, entry);
850697c8096Sdlg
851697c8096Sdlg /* get ready to add rules */
852697c8096Sdlg if (prepare_commit(r->id) == -1)
853697c8096Sdlg lerr(1, "%s: prepare_commit", __func__);
854697c8096Sdlg
855b27441feSflorian TAILQ_FOREACH(src_addr, &src_addrs, entry)
856b27441feSflorian if (src_addr->addr.ss_family == r->addrs.dst.ss_family)
857b27441feSflorian break;
858b27441feSflorian if (src_addr == NULL) {
85919875b15Sflorian if (add_filter(r->id, PF_IN, (struct sockaddr *)
86019875b15Sflorian &r->addrs.dst, (struct sockaddr *)&r->addrs.src,
86119875b15Sflorian ntohs(((struct sockaddr_in *)&r->addrs.src)
86219875b15Sflorian ->sin_port), IPPROTO_UDP) == -1)
863697c8096Sdlg lerr(1, "%s: couldn't add pass in", __func__);
86419875b15Sflorian } else {
86519875b15Sflorian if (getsockname(s, (struct sockaddr*)&saddr, &len) == -1)
86619875b15Sflorian lerr(1, "%s: getsockname", __func__);
86719875b15Sflorian if (add_rdr(r->id, (struct sockaddr *)&r->addrs.dst,
86819875b15Sflorian (struct sockaddr*)&saddr,
86919875b15Sflorian ntohs(((struct sockaddr_in *)&saddr)->sin_port),
87019875b15Sflorian (struct sockaddr *)&r->addrs.src,
87119875b15Sflorian ntohs(((struct sockaddr_in *)&r->addrs.src)->
87219875b15Sflorian sin_port), IPPROTO_UDP ) == -1)
87319875b15Sflorian lerr(1, "%s: couldn't add rdr rule", __func__);
87419875b15Sflorian }
875697c8096Sdlg
876697c8096Sdlg if (add_filter(r->id, PF_OUT, (struct sockaddr *)&r->addrs.dst,
877697c8096Sdlg (struct sockaddr *)&r->addrs.src,
878697c8096Sdlg ntohs(((struct sockaddr_in *)&r->addrs.src)->sin_port),
879697c8096Sdlg IPPROTO_UDP) == -1)
880697c8096Sdlg lerr(1, "%s: couldn't add pass out", __func__);
881697c8096Sdlg
882697c8096Sdlg if (do_commit() == -1)
883697c8096Sdlg lerr(1, "%s: couldn't commit rules", __func__);
884697c8096Sdlg
885697c8096Sdlg /* forward the initial tftp request and start the insanity */
886697c8096Sdlg if (sendto(s, r->buf, r->buflen, 0,
887697c8096Sdlg (struct sockaddr *)&r->addrs.dst,
888697c8096Sdlg r->addrs.dst.ss_len) == -1)
889697c8096Sdlg lerr(1, "%s: unable to send", __func__);
890697c8096Sdlg
891697c8096Sdlg close(s);
892697c8096Sdlg
893697c8096Sdlg evtimer_set(&r->ev, unprivproc_timeout, r);
894697c8096Sdlg evtimer_add(&r->ev, &transwait);
895697c8096Sdlg
896697c8096Sdlg TAILQ_INSERT_TAIL(&child->tmrequests, r, entry);
897697c8096Sdlg } while (!TAILQ_EMPTY(&child->fdrequests));
898697c8096Sdlg }
899697c8096Sdlg
900697c8096Sdlg void
unprivproc_timeout(int fd,short events,void * arg)901697c8096Sdlg unprivproc_timeout(int fd, short events, void *arg)
902697c8096Sdlg {
903697c8096Sdlg struct proxy_request *r = arg;
904697c8096Sdlg
905697c8096Sdlg TAILQ_REMOVE(&child->tmrequests, r, entry);
906697c8096Sdlg
907697c8096Sdlg /* delete our rdr rule and clean up */
908697c8096Sdlg prepare_commit(r->id);
909697c8096Sdlg do_commit();
910697c8096Sdlg
911697c8096Sdlg free(r);
912697c8096Sdlg }
913697c8096Sdlg
914697c8096Sdlg
915697c8096Sdlg const char *
opcode(int code)916697c8096Sdlg opcode(int code)
917697c8096Sdlg {
918697c8096Sdlg static char str[6];
919697c8096Sdlg
920697c8096Sdlg switch (code) {
921697c8096Sdlg case 1:
922697c8096Sdlg (void)snprintf(str, sizeof(str), "RRQ");
923697c8096Sdlg break;
924697c8096Sdlg case 2:
925697c8096Sdlg (void)snprintf(str, sizeof(str), "WRQ");
926697c8096Sdlg break;
927697c8096Sdlg default:
928697c8096Sdlg (void)snprintf(str, sizeof(str), "(%d)", code);
929697c8096Sdlg break;
930697c8096Sdlg }
931697c8096Sdlg
932697c8096Sdlg return (str);
933697c8096Sdlg }
934697c8096Sdlg
935697c8096Sdlg const char *
sock_ntop(struct sockaddr * sa)936697c8096Sdlg sock_ntop(struct sockaddr *sa)
937697c8096Sdlg {
938697c8096Sdlg static int n = 0;
939697c8096Sdlg
940697c8096Sdlg /* Cycle to next buffer. */
941697c8096Sdlg n = (n + 1) % NTOP_BUFS;
942697c8096Sdlg ntop_buf[n][0] = '\0';
943697c8096Sdlg
944697c8096Sdlg if (sa->sa_family == AF_INET) {
945697c8096Sdlg struct sockaddr_in *sin = (struct sockaddr_in *)sa;
946697c8096Sdlg
947697c8096Sdlg return (inet_ntop(AF_INET, &sin->sin_addr, ntop_buf[n],
948697c8096Sdlg sizeof ntop_buf[0]));
949697c8096Sdlg }
950697c8096Sdlg
951697c8096Sdlg if (sa->sa_family == AF_INET6) {
952697c8096Sdlg struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
953697c8096Sdlg
954697c8096Sdlg return (inet_ntop(AF_INET6, &sin6->sin6_addr, ntop_buf[n],
955697c8096Sdlg sizeof ntop_buf[0]));
956697c8096Sdlg }
957697c8096Sdlg
958697c8096Sdlg return (NULL);
959697c8096Sdlg }
960697c8096Sdlg
961697c8096Sdlg void
syslog_vstrerror(int e,int priority,const char * fmt,va_list ap)962697c8096Sdlg syslog_vstrerror(int e, int priority, const char *fmt, va_list ap)
963697c8096Sdlg {
964697c8096Sdlg char *s;
965697c8096Sdlg
966697c8096Sdlg if (vasprintf(&s, fmt, ap) == -1) {
967697c8096Sdlg syslog(LOG_EMERG, "unable to alloc in syslog_vstrerror");
968697c8096Sdlg exit(1);
969697c8096Sdlg }
970697c8096Sdlg
971697c8096Sdlg syslog(priority, "%s: %s", s, strerror(e));
972697c8096Sdlg
973697c8096Sdlg free(s);
974697c8096Sdlg }
975697c8096Sdlg
976697c8096Sdlg void
syslog_err(int ecode,const char * fmt,...)977697c8096Sdlg syslog_err(int ecode, const char *fmt, ...)
978697c8096Sdlg {
979697c8096Sdlg va_list ap;
980697c8096Sdlg
981697c8096Sdlg va_start(ap, fmt);
982a52b97d1Sflorian syslog_vstrerror(errno, LOG_CRIT, fmt, ap);
983697c8096Sdlg va_end(ap);
984697c8096Sdlg
985697c8096Sdlg exit(ecode);
986697c8096Sdlg }
987697c8096Sdlg
988697c8096Sdlg void
syslog_errx(int ecode,const char * fmt,...)989697c8096Sdlg syslog_errx(int ecode, const char *fmt, ...)
990697c8096Sdlg {
991697c8096Sdlg va_list ap;
992697c8096Sdlg
993697c8096Sdlg va_start(ap, fmt);
994a52b97d1Sflorian vsyslog(LOG_CRIT, fmt, ap);
995697c8096Sdlg va_end(ap);
996697c8096Sdlg
997697c8096Sdlg exit(ecode);
998697c8096Sdlg }
999697c8096Sdlg
1000697c8096Sdlg void
syslog_warn(const char * fmt,...)1001697c8096Sdlg syslog_warn(const char *fmt, ...)
1002697c8096Sdlg {
1003697c8096Sdlg va_list ap;
1004697c8096Sdlg
1005697c8096Sdlg va_start(ap, fmt);
1006a52b97d1Sflorian syslog_vstrerror(errno, LOG_ERR, fmt, ap);
1007697c8096Sdlg va_end(ap);
1008697c8096Sdlg }
1009697c8096Sdlg
1010697c8096Sdlg void
syslog_warnx(const char * fmt,...)1011697c8096Sdlg syslog_warnx(const char *fmt, ...)
1012697c8096Sdlg {
1013697c8096Sdlg va_list ap;
1014697c8096Sdlg
1015697c8096Sdlg va_start(ap, fmt);
1016a52b97d1Sflorian vsyslog(LOG_ERR, fmt, ap);
1017697c8096Sdlg va_end(ap);
1018697c8096Sdlg }
1019697c8096Sdlg
1020697c8096Sdlg void
syslog_info(const char * fmt,...)1021697c8096Sdlg syslog_info(const char *fmt, ...)
1022697c8096Sdlg {
1023697c8096Sdlg va_list ap;
1024697c8096Sdlg
1025697c8096Sdlg va_start(ap, fmt);
1026697c8096Sdlg vsyslog(LOG_INFO, fmt, ap);
1027697c8096Sdlg va_end(ap);
1028697c8096Sdlg }
1029697c8096Sdlg
1030cd68c002Sflorian void
syslog_debug(const char * fmt,...)1031cd68c002Sflorian syslog_debug(const char *fmt, ...)
1032cd68c002Sflorian {
1033cd68c002Sflorian va_list ap;
1034cd68c002Sflorian
1035cd68c002Sflorian if (!debug)
1036cd68c002Sflorian return;
1037cd68c002Sflorian
1038cd68c002Sflorian va_start(ap, fmt);
1039cd68c002Sflorian vsyslog(LOG_DEBUG, fmt, ap);
1040cd68c002Sflorian va_end(ap);
1041cd68c002Sflorian }
1042