File: | src/usr.sbin/tftp-proxy/tftp-proxy.c |
Warning: | line 507, column 29 Use of memory after it is freed |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: tftp-proxy.c,v 1.22 2021/01/17 13:38:52 claudio Exp $ | |||
2 | * | |||
3 | * Copyright (c) 2005 DLS Internet Services | |||
4 | * Copyright (c) 2004, 2005 Camiel Dobbelaar, <cd@sentia.nl> | |||
5 | * | |||
6 | * Redistribution and use in source and binary forms, with or without | |||
7 | * modification, are permitted provided that the following conditions | |||
8 | * are met: | |||
9 | * | |||
10 | * 1. Redistributions of source code must retain the above copyright | |||
11 | * notice, this list of conditions and the following disclaimer. | |||
12 | * 2. Redistributions in binary form must reproduce the above copyright | |||
13 | * notice, this list of conditions and the following disclaimer in the | |||
14 | * documentation and/or other materials provided with the distribution. | |||
15 | * 3. The name of the author may not be used to endorse or promote products | |||
16 | * derived from this software without specific prior written permission. | |||
17 | * | |||
18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |||
19 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
20 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |||
21 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |||
22 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |||
23 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |||
24 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |||
25 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |||
27 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
28 | */ | |||
29 | ||||
30 | #include <sys/types.h> | |||
31 | #include <sys/ioctl.h> | |||
32 | #include <sys/socket.h> | |||
33 | #include <sys/uio.h> | |||
34 | ||||
35 | #include <netinet/in.h> | |||
36 | #include <arpa/inet.h> | |||
37 | #include <arpa/tftp.h> | |||
38 | #include <net/if.h> | |||
39 | #include <net/pfvar.h> | |||
40 | #include <netdb.h> | |||
41 | ||||
42 | #include <unistd.h> | |||
43 | #include <errno(*__errno()).h> | |||
44 | #include <err.h> | |||
45 | #include <pwd.h> | |||
46 | #include <stdio.h> | |||
47 | #include <syslog.h> | |||
48 | #include <string.h> | |||
49 | #include <stdarg.h> | |||
50 | #include <stdlib.h> | |||
51 | #include <event.h> | |||
52 | ||||
53 | #include "filter.h" | |||
54 | ||||
55 | #define CHROOT_DIR"/var/empty" "/var/empty" | |||
56 | #define NOPRIV_USER"_tftp_proxy" "_tftp_proxy" | |||
57 | ||||
58 | #define DEFTRANSWAIT2 2 | |||
59 | #define NTOP_BUFS4 4 | |||
60 | #define PKTSIZE512 +4 SEGSIZE512+4 | |||
61 | ||||
62 | const char *opcode(int); | |||
63 | const char *sock_ntop(struct sockaddr *); | |||
64 | static void usage(void); | |||
65 | ||||
66 | struct proxy_listener { | |||
67 | struct event ev; | |||
68 | TAILQ_ENTRY(proxy_listener)struct { struct proxy_listener *tqe_next; struct proxy_listener **tqe_prev; } entry; | |||
69 | int (*cmsg2dst)(struct cmsghdr *, struct sockaddr_storage *); | |||
70 | int s; | |||
71 | }; | |||
72 | ||||
73 | void proxy_listen(const char *, const char *, int); | |||
74 | void proxy_listener_events(void); | |||
75 | int proxy_dst4(struct cmsghdr *, struct sockaddr_storage *); | |||
76 | int proxy_dst6(struct cmsghdr *, struct sockaddr_storage *); | |||
77 | void proxy_recv(int, short, void *); | |||
78 | ||||
79 | struct fd_reply { | |||
80 | TAILQ_ENTRY(fd_reply)struct { struct fd_reply *tqe_next; struct fd_reply **tqe_prev ; } entry; | |||
81 | int fd; | |||
82 | }; | |||
83 | ||||
84 | struct privproc { | |||
85 | struct event pop_ev; | |||
86 | struct event push_ev; | |||
87 | TAILQ_HEAD(, fd_reply)struct { struct fd_reply *tqh_first; struct fd_reply **tqh_last ; } replies; | |||
88 | struct evbuffer *buf; | |||
89 | }; | |||
90 | ||||
91 | void proxy_privproc(int, struct passwd *); | |||
92 | void privproc_push(int, short, void *); | |||
93 | void privproc_pop(int, short, void *); | |||
94 | ||||
95 | void unprivproc_push(int, short, void *); | |||
96 | void unprivproc_pop(int, short, void *); | |||
97 | void unprivproc_timeout(int, short, void *); | |||
98 | ||||
99 | char ntop_buf[NTOP_BUFS4][INET6_ADDRSTRLEN46]; | |||
100 | ||||
101 | struct loggers { | |||
102 | __dead__attribute__((__noreturn__)) void (*err)(int, const char *, ...) | |||
103 | __attribute__((__format__ (printf, 2, 3))); | |||
104 | __dead__attribute__((__noreturn__)) void (*errx)(int, const char *, ...) | |||
105 | __attribute__((__format__ (printf, 2, 3))); | |||
106 | void (*warn)(const char *, ...) | |||
107 | __attribute__((__format__ (printf, 1, 2))); | |||
108 | void (*warnx)(const char *, ...) | |||
109 | __attribute__((__format__ (printf, 1, 2))); | |||
110 | void (*info)(const char *, ...) | |||
111 | __attribute__((__format__ (printf, 1, 2))); | |||
112 | void (*debug)(const char *, ...) | |||
113 | __attribute__((__format__ (printf, 1, 2))); | |||
114 | }; | |||
115 | ||||
116 | const struct loggers conslogger = { | |||
117 | err, | |||
118 | errx, | |||
119 | warn, | |||
120 | warnx, | |||
121 | warnx, /* info */ | |||
122 | warnx /* debug */ | |||
123 | }; | |||
124 | ||||
125 | __dead__attribute__((__noreturn__)) void syslog_err(int, const char *, ...) | |||
126 | __attribute__((__format__ (printf, 2, 3))); | |||
127 | __dead__attribute__((__noreturn__)) void syslog_errx(int, const char *, ...) | |||
128 | __attribute__((__format__ (printf, 2, 3))); | |||
129 | void syslog_warn(const char *, ...) | |||
130 | __attribute__((__format__ (printf, 1, 2))); | |||
131 | void syslog_warnx(const char *, ...) | |||
132 | __attribute__((__format__ (printf, 1, 2))); | |||
133 | void syslog_info(const char *, ...) | |||
134 | __attribute__((__format__ (printf, 1, 2))); | |||
135 | void syslog_debug(const char *, ...) | |||
136 | __attribute__((__format__ (printf, 1, 2))); | |||
137 | void syslog_vstrerror(int, int, const char *, va_list) | |||
138 | __attribute__((__format__ (printf, 3, 0))); | |||
139 | ||||
140 | const struct loggers syslogger = { | |||
141 | syslog_err, | |||
142 | syslog_errx, | |||
143 | syslog_warn, | |||
144 | syslog_warnx, | |||
145 | syslog_info, | |||
146 | syslog_debug | |||
147 | }; | |||
148 | ||||
149 | const struct loggers *logger = &conslogger; | |||
150 | ||||
151 | #define lerr(_e, _f...)logger->err((_e), _f...) logger->err((_e), _f) | |||
152 | #define lerrx(_e, _f...)logger->errx((_e), _f...) logger->errx((_e), _f) | |||
153 | #define lwarn(_f...)logger->warn(_f...) logger->warn(_f) | |||
154 | #define lwarnx(_f...)logger->warnx(_f...) logger->warnx(_f) | |||
155 | #define linfo(_f...)logger->info(_f...) logger->info(_f) | |||
156 | #define ldebug(_f...)logger->debug(_f...) logger->debug(_f) | |||
157 | ||||
158 | __dead__attribute__((__noreturn__)) void | |||
159 | usage(void) | |||
160 | { | |||
161 | extern char *__progname; | |||
162 | fprintf(stderr(&__sF[2]), "usage: %s [-46dv] [-a address] [-l address] [-p port]" | |||
163 | " [-w transwait]\n", __progname); | |||
164 | exit(1); | |||
165 | } | |||
166 | ||||
167 | int debug = 0; | |||
168 | int verbose = 0; | |||
169 | struct timeval transwait = { DEFTRANSWAIT2, 0 }; | |||
170 | ||||
171 | int on = 1; | |||
172 | ||||
173 | struct addr_pair { | |||
174 | struct sockaddr_storage src; | |||
175 | struct sockaddr_storage dst; | |||
176 | }; | |||
177 | ||||
178 | struct proxy_request { | |||
179 | char buf[SEGSIZE_MAX65464 + 4]; | |||
180 | size_t buflen; | |||
181 | ||||
182 | struct addr_pair addrs; | |||
183 | ||||
184 | struct event ev; | |||
185 | TAILQ_ENTRY(proxy_request)struct { struct proxy_request *tqe_next; struct proxy_request **tqe_prev; } entry; | |||
186 | u_int32_t id; | |||
187 | }; | |||
188 | ||||
189 | struct proxy_child { | |||
190 | TAILQ_HEAD(, proxy_request)struct { struct proxy_request *tqh_first; struct proxy_request **tqh_last; } fdrequests; | |||
191 | TAILQ_HEAD(, proxy_request)struct { struct proxy_request *tqh_first; struct proxy_request **tqh_last; } tmrequests; | |||
192 | struct event push_ev; | |||
193 | struct event pop_ev; | |||
194 | struct evbuffer *buf; | |||
195 | }; | |||
196 | ||||
197 | struct proxy_child *child = NULL((void *)0); | |||
198 | TAILQ_HEAD(, proxy_listener)struct { struct proxy_listener *tqh_first; struct proxy_listener **tqh_last; } proxy_listeners; | |||
199 | ||||
200 | struct src_addr { | |||
201 | TAILQ_ENTRY(src_addr)struct { struct src_addr *tqe_next; struct src_addr **tqe_prev ; } entry; | |||
202 | struct sockaddr_storage addr; | |||
203 | socklen_t addrlen; | |||
204 | }; | |||
205 | TAILQ_HEAD(, src_addr)struct { struct src_addr *tqh_first; struct src_addr **tqh_last ; } src_addrs; | |||
206 | ||||
207 | void source_addresses(const char*, int); | |||
208 | ||||
209 | int | |||
210 | main(int argc, char *argv[]) | |||
211 | { | |||
212 | extern char *__progname; | |||
213 | ||||
214 | int c; | |||
215 | const char *errstr; | |||
216 | ||||
217 | struct src_addr *saddr, *saddr2; | |||
218 | struct passwd *pw; | |||
219 | ||||
220 | char *addr = "localhost"; | |||
221 | char *port = "6969"; | |||
222 | int family = AF_UNSPEC0; | |||
223 | ||||
224 | int pair[2]; | |||
225 | ||||
226 | TAILQ_INIT(&src_addrs)do { (&src_addrs)->tqh_first = ((void *)0); (&src_addrs )->tqh_last = &(&src_addrs)->tqh_first; } while (0); | |||
227 | ||||
228 | while ((c = getopt(argc, argv, "46a:dvl:p:w:")) != -1) { | |||
229 | switch (c) { | |||
230 | case '4': | |||
231 | family = AF_INET2; | |||
232 | break; | |||
233 | case '6': | |||
234 | family = AF_INET624; | |||
235 | break; | |||
236 | case 'a': | |||
237 | source_addresses(optarg, family); | |||
238 | break; | |||
239 | case 'd': | |||
240 | verbose = debug = 1; | |||
241 | break; | |||
242 | case 'l': | |||
243 | addr = optarg; | |||
244 | break; | |||
245 | case 'p': | |||
246 | port = optarg; | |||
247 | break; | |||
248 | case 'v': | |||
249 | verbose = 1; | |||
250 | break; | |||
251 | case 'w': | |||
252 | transwait.tv_sec = strtonum(optarg, 1, 30, &errstr); | |||
253 | if (errstr) | |||
254 | errx(1, "wait is %s", errstr); | |||
255 | break; | |||
256 | default: | |||
257 | usage(); | |||
258 | /* NOTREACHED */ | |||
259 | } | |||
260 | } | |||
261 | ||||
262 | if (geteuid() != 0) | |||
263 | lerrx(1, "need root privileges")logger->errx((1), "need root privileges"); | |||
264 | ||||
265 | if (socketpair(AF_UNIX1, SOCK_STREAM1 | SOCK_NONBLOCK0x4000, PF_UNSPEC0, pair) | |||
266 | == -1) | |||
267 | lerr(1, "socketpair")logger->err((1), "socketpair"); | |||
268 | ||||
269 | pw = getpwnam(NOPRIV_USER"_tftp_proxy"); | |||
270 | if (pw == NULL((void *)0)) | |||
271 | lerrx(1, "no %s user", NOPRIV_USER)logger->errx((1), "no %s user", "_tftp_proxy"); | |||
272 | ||||
273 | /* Family option may have been specified late. */ | |||
274 | if (family != AF_UNSPEC0) | |||
275 | TAILQ_FOREACH_SAFE(saddr, &src_addrs, entry, saddr2)for ((saddr) = ((&src_addrs)->tqh_first); (saddr) != ( (void *)0) && ((saddr2) = ((saddr)->entry.tqe_next ), 1); (saddr) = (saddr2)) | |||
276 | if (saddr->addr.ss_family != family) { | |||
277 | TAILQ_REMOVE(&src_addrs, saddr, entry)do { if (((saddr)->entry.tqe_next) != ((void *)0)) (saddr) ->entry.tqe_next->entry.tqe_prev = (saddr)->entry.tqe_prev ; else (&src_addrs)->tqh_last = (saddr)->entry.tqe_prev ; *(saddr)->entry.tqe_prev = (saddr)->entry.tqe_next; ; ; } while (0); | |||
278 | free(saddr); | |||
279 | } | |||
280 | ||||
281 | if (!debug) { | |||
282 | if (daemon(1, 0) == -1) | |||
283 | lerr(1, "daemon")logger->err((1), "daemon"); | |||
284 | ||||
285 | openlog(__progname, LOG_PID0x01|LOG_NDELAY0x08, LOG_DAEMON(3<<3)); | |||
286 | tzset(); | |||
287 | logger = &syslogger; | |||
288 | } | |||
289 | ||||
290 | switch (fork()) { | |||
291 | case -1: | |||
292 | lerr(1, "fork")logger->err((1), "fork"); | |||
293 | ||||
294 | case 0: | |||
295 | setproctitle("privproc"); | |||
296 | close(pair[1]); | |||
297 | proxy_privproc(pair[0], pw); | |||
298 | /* this never returns */ | |||
299 | ||||
300 | default: | |||
301 | setproctitle("unprivproc"); | |||
302 | close(pair[0]); | |||
303 | break; | |||
304 | } | |||
305 | ||||
306 | child = calloc(1, sizeof(*child)); | |||
307 | if (child == NULL((void *)0)) | |||
308 | lerr(1, "alloc(child)")logger->err((1), "alloc(child)"); | |||
309 | ||||
310 | child->buf = evbuffer_new(); | |||
311 | if (child->buf == NULL((void *)0)) | |||
312 | lerr(1, "child evbuffer")logger->err((1), "child evbuffer"); | |||
313 | ||||
314 | TAILQ_INIT(&child->fdrequests)do { (&child->fdrequests)->tqh_first = ((void *)0); (&child->fdrequests)->tqh_last = &(&child-> fdrequests)->tqh_first; } while (0); | |||
315 | TAILQ_INIT(&child->tmrequests)do { (&child->tmrequests)->tqh_first = ((void *)0); (&child->tmrequests)->tqh_last = &(&child-> tmrequests)->tqh_first; } while (0); | |||
316 | ||||
317 | proxy_listen(addr, port, family); | |||
318 | ||||
319 | /* open /dev/pf */ | |||
320 | init_filter(NULL((void *)0), verbose); | |||
321 | ||||
322 | /* revoke privs */ | |||
323 | if (chroot(CHROOT_DIR"/var/empty") == -1) | |||
324 | lerr(1, "chroot %s", CHROOT_DIR)logger->err((1), "chroot %s", "/var/empty"); | |||
325 | ||||
326 | if (chdir("/") == -1) | |||
327 | lerr(1, "chdir %s", CHROOT_DIR)logger->err((1), "chdir %s", "/var/empty"); | |||
328 | ||||
329 | if (setgroups(1, &pw->pw_gid) || | |||
330 | setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || | |||
331 | setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) | |||
332 | err(1, "unable to revoke privs"); | |||
333 | ||||
334 | event_init(); | |||
335 | ||||
336 | proxy_listener_events(); | |||
337 | ||||
338 | event_set(&child->pop_ev, pair[1], EV_READ0x02 | EV_PERSIST0x10, | |||
339 | unprivproc_pop, NULL((void *)0)); | |||
340 | event_set(&child->push_ev, pair[1], EV_WRITE0x04, | |||
341 | unprivproc_push, NULL((void *)0)); | |||
342 | ||||
343 | event_add(&child->pop_ev, NULL((void *)0)); | |||
344 | ||||
345 | event_dispatch(); | |||
346 | ||||
347 | return(0); | |||
348 | } | |||
349 | ||||
350 | void | |||
351 | source_addresses(const char* name, int family) | |||
352 | { | |||
353 | struct addrinfo hints, *res, *res0; | |||
354 | struct src_addr *saddr; | |||
355 | int error; | |||
356 | ||||
357 | memset(&hints, 0, sizeof(hints)); | |||
358 | hints.ai_family = family; | |||
359 | hints.ai_socktype = SOCK_DGRAM2; | |||
360 | hints.ai_flags = AI_PASSIVE1; | |||
361 | error = getaddrinfo(name, NULL((void *)0), &hints, &res0); | |||
362 | if (error) | |||
363 | lerrx(1, "%s: %s", name, gai_strerror(error))logger->errx((1), "%s: %s", name, gai_strerror(error)); | |||
364 | for (res = res0; res != NULL((void *)0); res = res->ai_next) { | |||
365 | if ((saddr = calloc(1, sizeof(struct src_addr))) == NULL((void *)0)) | |||
366 | lerrx(1, "calloc")logger->errx((1), "calloc"); | |||
367 | memcpy(&(saddr->addr), res->ai_addr, res->ai_addrlen); | |||
368 | saddr->addrlen = res->ai_addrlen; | |||
369 | TAILQ_INSERT_TAIL(&src_addrs, saddr, entry)do { (saddr)->entry.tqe_next = ((void *)0); (saddr)->entry .tqe_prev = (&src_addrs)->tqh_last; *(&src_addrs)-> tqh_last = (saddr); (&src_addrs)->tqh_last = &(saddr )->entry.tqe_next; } while (0); | |||
370 | } | |||
371 | freeaddrinfo(res0); | |||
372 | } | |||
373 | ||||
374 | void | |||
375 | proxy_privproc(int s, struct passwd *pw) | |||
376 | { | |||
377 | struct privproc p; | |||
378 | ||||
379 | if (chroot(CHROOT_DIR"/var/empty") == -1) | |||
380 | lerr(1, "chroot to %s", CHROOT_DIR)logger->err((1), "chroot to %s", "/var/empty"); | |||
381 | ||||
382 | if (chdir("/") == -1) | |||
383 | lerr(1, "chdir to %s", CHROOT_DIR)logger->err((1), "chdir to %s", "/var/empty"); | |||
384 | ||||
385 | if (setgroups(1, &pw->pw_gid) || | |||
386 | setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid)) | |||
387 | lerr(1, "unable to set group ids")logger->err((1), "unable to set group ids"); | |||
388 | ||||
389 | if (pledge("stdio inet sendfd", NULL((void *)0)) == -1) | |||
390 | err(1, "pledge"); | |||
391 | ||||
392 | TAILQ_INIT(&p.replies)do { (&p.replies)->tqh_first = ((void *)0); (&p.replies )->tqh_last = &(&p.replies)->tqh_first; } while (0); | |||
393 | ||||
394 | p.buf = evbuffer_new(); | |||
395 | if (p.buf == NULL((void *)0)) | |||
396 | err(1, "pop evbuffer_new"); | |||
397 | ||||
398 | event_init(); | |||
399 | ||||
400 | event_set(&p.pop_ev, s, EV_READ0x02 | EV_PERSIST0x10, privproc_pop, &p); | |||
401 | event_set(&p.push_ev, s, EV_WRITE0x04, privproc_push, &p); | |||
402 | ||||
403 | event_add(&p.pop_ev, NULL((void *)0)); | |||
404 | ||||
405 | event_dispatch(); | |||
406 | } | |||
407 | ||||
408 | void | |||
409 | privproc_pop(int fd, short events, void *arg) | |||
410 | { | |||
411 | struct addr_pair req; | |||
412 | struct privproc *p = arg; | |||
413 | struct fd_reply *rep; | |||
414 | struct src_addr *saddr; | |||
415 | int add = 0; | |||
416 | ||||
417 | switch (evbuffer_read(p->buf, fd, sizeof(req))) { | |||
418 | case 0: | |||
419 | lerrx(1, "unprivproc has gone")logger->errx((1), "unprivproc has gone"); | |||
420 | case -1: | |||
421 | switch (errno(*__errno())) { | |||
422 | case EAGAIN35: | |||
423 | case EINTR4: | |||
424 | return; | |||
425 | default: | |||
426 | lerr(1, "privproc_pop read")logger->err((1), "privproc_pop read"); | |||
427 | } | |||
428 | default: | |||
429 | break; | |||
430 | } | |||
431 | ||||
432 | while (EVBUFFER_LENGTH(p->buf)(p->buf)->off >= sizeof(req)) { | |||
433 | evbuffer_remove(p->buf, &req, sizeof(req)); | |||
434 | ||||
435 | /* do i really need to check this? */ | |||
436 | if (req.src.ss_family != req.dst.ss_family) | |||
437 | lerrx(1, "family mismatch")logger->errx((1), "family mismatch"); | |||
438 | ||||
439 | rep = calloc(1, sizeof(*rep)); | |||
440 | if (rep == NULL((void *)0)) | |||
441 | lerr(1, "reply calloc")logger->err((1), "reply calloc"); | |||
442 | ||||
443 | rep->fd = socket(req.src.ss_family, SOCK_DGRAM2 | SOCK_NONBLOCK0x4000, | |||
444 | IPPROTO_UDP17); | |||
445 | if (rep->fd == -1) | |||
446 | lerr(1, "privproc socket")logger->err((1), "privproc socket"); | |||
447 | ||||
448 | if (setsockopt(rep->fd, SOL_SOCKET0xffff, SO_BINDANY0x1000, | |||
449 | &on, sizeof(on)) == -1) | |||
450 | lerr(1, "privproc setsockopt(BINDANY)")logger->err((1), "privproc setsockopt(BINDANY)"); | |||
451 | ||||
452 | if (setsockopt(rep->fd, SOL_SOCKET0xffff, SO_REUSEADDR0x0004, | |||
453 | &on, sizeof(on)) == -1) | |||
454 | lerr(1, "privproc setsockopt(REUSEADDR)")logger->err((1), "privproc setsockopt(REUSEADDR)"); | |||
455 | ||||
456 | if (setsockopt(rep->fd, SOL_SOCKET0xffff, SO_REUSEPORT0x0200, | |||
457 | &on, sizeof(on)) == -1) | |||
458 | lerr(1, "privproc setsockopt(REUSEPORT)")logger->err((1), "privproc setsockopt(REUSEPORT)"); | |||
459 | ||||
460 | TAILQ_FOREACH(saddr, &src_addrs, entry)for((saddr) = ((&src_addrs)->tqh_first); (saddr) != (( void *)0); (saddr) = ((saddr)->entry.tqe_next)) | |||
461 | if (saddr->addr.ss_family == req.src.ss_family) | |||
462 | break; | |||
463 | if (saddr == NULL((void *)0)) { | |||
464 | if (bind(rep->fd, (struct sockaddr *)&req.src, | |||
465 | req.src.ss_len) == -1) | |||
466 | lerr(1, "privproc bind")logger->err((1), "privproc bind"); | |||
467 | } else { | |||
468 | if (bind(rep->fd, (struct sockaddr*)&saddr->addr, | |||
469 | saddr->addrlen) == -1) | |||
470 | lerr(1, "privproc bind")logger->err((1), "privproc bind"); | |||
471 | } | |||
472 | ||||
473 | if (TAILQ_EMPTY(&p->replies)(((&p->replies)->tqh_first) == ((void *)0))) | |||
474 | add = 1; | |||
475 | ||||
476 | TAILQ_INSERT_TAIL(&p->replies, rep, entry)do { (rep)->entry.tqe_next = ((void *)0); (rep)->entry. tqe_prev = (&p->replies)->tqh_last; *(&p->replies )->tqh_last = (rep); (&p->replies)->tqh_last = & (rep)->entry.tqe_next; } while (0); | |||
477 | } | |||
478 | ||||
479 | if (add) | |||
480 | event_add(&p->push_ev, NULL((void *)0)); | |||
481 | } | |||
482 | ||||
483 | void | |||
484 | privproc_push(int fd, short events, void *arg) | |||
485 | { | |||
486 | struct privproc *p = arg; | |||
487 | struct fd_reply *rep; | |||
488 | ||||
489 | struct msghdr msg; | |||
490 | union { | |||
491 | struct cmsghdr hdr; | |||
492 | char buf[CMSG_SPACE(sizeof(int))((((unsigned long)(sizeof(struct cmsghdr)) + (sizeof(long) - 1 )) &~(sizeof(long) - 1)) + (((unsigned long)(sizeof(int)) + (sizeof(long) - 1)) &~(sizeof(long) - 1)))]; | |||
493 | } cmsgbuf; | |||
494 | struct cmsghdr *cmsg; | |||
495 | struct iovec iov; | |||
496 | int result = 0; | |||
497 | ||||
498 | while ((rep = TAILQ_FIRST(&p->replies)((&p->replies)->tqh_first)) != NULL((void *)0)) { | |||
| ||||
499 | memset(&msg, 0, sizeof(msg)); | |||
500 | ||||
501 | msg.msg_control = (caddr_t)&cmsgbuf.buf; | |||
502 | msg.msg_controllen = sizeof(cmsgbuf.buf); | |||
503 | cmsg = CMSG_FIRSTHDR(&msg)((&msg)->msg_controllen >= sizeof(struct cmsghdr) ? (struct cmsghdr *)(&msg)->msg_control : (struct cmsghdr *)((void *)0)); | |||
504 | cmsg->cmsg_len = CMSG_LEN(sizeof(int))((((unsigned long)(sizeof(struct cmsghdr)) + (sizeof(long) - 1 )) &~(sizeof(long) - 1)) + (sizeof(int))); | |||
505 | cmsg->cmsg_level = SOL_SOCKET0xffff; | |||
506 | cmsg->cmsg_type = SCM_RIGHTS0x01; | |||
507 | *(int *)CMSG_DATA(cmsg)((unsigned char *)(cmsg) + (((unsigned long)(sizeof(struct cmsghdr )) + (sizeof(long) - 1)) &~(sizeof(long) - 1))) = rep->fd; | |||
| ||||
508 | ||||
509 | iov.iov_base = &result; | |||
510 | iov.iov_len = sizeof(int); | |||
511 | msg.msg_iov = &iov; | |||
512 | msg.msg_iovlen = 1; | |||
513 | ||||
514 | switch (sendmsg(fd, &msg, 0)) { | |||
515 | case sizeof(int): | |||
516 | break; | |||
517 | ||||
518 | case -1: | |||
519 | if (errno(*__errno()) == EAGAIN35) | |||
520 | goto again; | |||
521 | ||||
522 | lerr(1, "privproc sendmsg")logger->err((1), "privproc sendmsg"); | |||
523 | /* NOTREACHED */ | |||
524 | ||||
525 | default: | |||
526 | lerrx(1, "privproc sendmsg weird len")logger->errx((1), "privproc sendmsg weird len"); | |||
527 | } | |||
528 | ||||
529 | TAILQ_REMOVE(&p->replies, rep, entry)do { if (((rep)->entry.tqe_next) != ((void *)0)) (rep)-> entry.tqe_next->entry.tqe_prev = (rep)->entry.tqe_prev; else (&p->replies)->tqh_last = (rep)->entry.tqe_prev ; *(rep)->entry.tqe_prev = (rep)->entry.tqe_next; ; ; } while (0); | |||
530 | close(rep->fd); | |||
531 | free(rep); | |||
532 | } | |||
533 | ||||
534 | if (TAILQ_EMPTY(&p->replies)(((&p->replies)->tqh_first) == ((void *)0))) | |||
535 | return; | |||
536 | ||||
537 | again: | |||
538 | event_add(&p->push_ev, NULL((void *)0)); | |||
539 | } | |||
540 | ||||
541 | void | |||
542 | proxy_listen(const char *addr, const char *port, int family) | |||
543 | { | |||
544 | struct proxy_listener *l; | |||
545 | ||||
546 | struct addrinfo hints, *res, *res0; | |||
547 | int error; | |||
548 | int s, on = 1; | |||
549 | int serrno; | |||
550 | const char *cause = NULL((void *)0); | |||
551 | ||||
552 | memset(&hints, 0, sizeof(hints)); | |||
553 | hints.ai_family = family; | |||
554 | hints.ai_socktype = SOCK_DGRAM2; | |||
555 | hints.ai_flags = AI_PASSIVE1; | |||
556 | ||||
557 | TAILQ_INIT(&proxy_listeners)do { (&proxy_listeners)->tqh_first = ((void *)0); (& proxy_listeners)->tqh_last = &(&proxy_listeners)-> tqh_first; } while (0); | |||
558 | ||||
559 | error = getaddrinfo(addr, port, &hints, &res0); | |||
560 | if (error) | |||
561 | errx(1, "%s:%s: %s", addr, port, gai_strerror(error)); | |||
562 | ||||
563 | for (res = res0; res != NULL((void *)0); res = res->ai_next) { | |||
564 | s = socket(res->ai_family, res->ai_socktype | SOCK_NONBLOCK0x4000, | |||
565 | res->ai_protocol); | |||
566 | if (s == -1) { | |||
567 | cause = "socket"; | |||
568 | continue; | |||
569 | } | |||
570 | ||||
571 | if (bind(s, res->ai_addr, res->ai_addrlen) == -1) { | |||
572 | cause = "bind"; | |||
573 | serrno = errno(*__errno()); | |||
574 | close(s); | |||
575 | errno(*__errno()) = serrno; | |||
576 | continue; | |||
577 | } | |||
578 | ||||
579 | l = calloc(1, sizeof(*l)); | |||
580 | if (l == NULL((void *)0)) | |||
581 | err(1, "listener alloc"); | |||
582 | ||||
583 | switch (res->ai_family) { | |||
584 | case AF_INET2: | |||
585 | l->cmsg2dst = proxy_dst4; | |||
586 | ||||
587 | if (setsockopt(s, IPPROTO_IP0, IP_RECVDSTADDR7, | |||
588 | &on, sizeof(on)) == -1) | |||
589 | errx(1, "setsockopt(IP_RECVDSTADDR)"); | |||
590 | if (setsockopt(s, IPPROTO_IP0, IP_RECVDSTPORT33, | |||
591 | &on, sizeof(on)) == -1) | |||
592 | errx(1, "setsockopt(IP_RECVDSTPORT)"); | |||
593 | break; | |||
594 | case AF_INET624: | |||
595 | l->cmsg2dst = proxy_dst6; | |||
596 | ||||
597 | if (setsockopt(s, IPPROTO_IPV641, IPV6_RECVPKTINFO36, | |||
598 | &on, sizeof(on)) == -1) | |||
599 | errx(1, "setsockopt(IPV6_RECVPKTINFO)"); | |||
600 | if (setsockopt(s, IPPROTO_IPV641, IPV6_RECVDSTPORT64, | |||
601 | &on, sizeof(on)) == -1) | |||
602 | errx(1, "setsockopt(IPV6_RECVDSTPORT)"); | |||
603 | break; | |||
604 | } | |||
605 | l->s = s; | |||
606 | ||||
607 | TAILQ_INSERT_TAIL(&proxy_listeners, l, entry)do { (l)->entry.tqe_next = ((void *)0); (l)->entry.tqe_prev = (&proxy_listeners)->tqh_last; *(&proxy_listeners )->tqh_last = (l); (&proxy_listeners)->tqh_last = & (l)->entry.tqe_next; } while (0); | |||
608 | } | |||
609 | freeaddrinfo(res0); | |||
610 | ||||
611 | if (TAILQ_EMPTY(&proxy_listeners)(((&proxy_listeners)->tqh_first) == ((void *)0))) | |||
612 | err(1, "%s", cause); | |||
613 | } | |||
614 | ||||
615 | void | |||
616 | proxy_listener_events(void) | |||
617 | { | |||
618 | struct proxy_listener *l; | |||
619 | ||||
620 | TAILQ_FOREACH(l, &proxy_listeners, entry)for((l) = ((&proxy_listeners)->tqh_first); (l) != ((void *)0); (l) = ((l)->entry.tqe_next)) { | |||
621 | event_set(&l->ev, l->s, EV_READ0x02 | EV_PERSIST0x10, proxy_recv, l); | |||
622 | event_add(&l->ev, NULL((void *)0)); | |||
623 | } | |||
624 | } | |||
625 | ||||
626 | char safety[SEGSIZE_MAX65464 + 4]; | |||
627 | ||||
628 | int | |||
629 | proxy_dst4(struct cmsghdr *cmsg, struct sockaddr_storage *ss) | |||
630 | { | |||
631 | struct sockaddr_in *sin = (struct sockaddr_in *)ss; | |||
632 | ||||
633 | if (cmsg->cmsg_level != IPPROTO_IP0) | |||
634 | return (0); | |||
635 | ||||
636 | switch (cmsg->cmsg_type) { | |||
637 | case IP_RECVDSTADDR7: | |||
638 | memcpy(&sin->sin_addr, CMSG_DATA(cmsg)((unsigned char *)(cmsg) + (((unsigned long)(sizeof(struct cmsghdr )) + (sizeof(long) - 1)) &~(sizeof(long) - 1))), sizeof(sin->sin_addr)); | |||
639 | if (sin->sin_addr.s_addr == INADDR_BROADCAST((u_int32_t)(0xffffffff))) | |||
640 | return (-1); | |||
641 | break; | |||
642 | ||||
643 | case IP_RECVDSTPORT33: | |||
644 | memcpy(&sin->sin_port, CMSG_DATA(cmsg)((unsigned char *)(cmsg) + (((unsigned long)(sizeof(struct cmsghdr )) + (sizeof(long) - 1)) &~(sizeof(long) - 1))), sizeof(sin->sin_port)); | |||
645 | break; | |||
646 | } | |||
647 | ||||
648 | return (0); | |||
649 | } | |||
650 | ||||
651 | int | |||
652 | proxy_dst6(struct cmsghdr *cmsg, struct sockaddr_storage *ss) | |||
653 | { | |||
654 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ss; | |||
655 | struct in6_pktinfo *ipi = (struct in6_pktinfo *)CMSG_DATA(cmsg)((unsigned char *)(cmsg) + (((unsigned long)(sizeof(struct cmsghdr )) + (sizeof(long) - 1)) &~(sizeof(long) - 1))); | |||
656 | ||||
657 | if (cmsg->cmsg_level != IPPROTO_IPV641) | |||
658 | return (0); | |||
659 | ||||
660 | switch (cmsg->cmsg_type) { | |||
661 | case IPV6_PKTINFO46: | |||
662 | memcpy(&sin6->sin6_addr, &ipi->ipi6_addr, | |||
663 | sizeof(sin6->sin6_addr)); | |||
664 | if (IN6_IS_ADDR_LINKLOCAL(&ipi->ipi6_addr)(((&ipi->ipi6_addr)->__u6_addr.__u6_addr8[0] == 0xfe ) && (((&ipi->ipi6_addr)->__u6_addr.__u6_addr8 [1] & 0xc0) == 0x80))) | |||
665 | sin6->sin6_scope_id = ipi->ipi6_ifindex; | |||
666 | break; | |||
667 | case IPV6_RECVDSTPORT64: | |||
668 | memcpy(&sin6->sin6_port, CMSG_DATA(cmsg)((unsigned char *)(cmsg) + (((unsigned long)(sizeof(struct cmsghdr )) + (sizeof(long) - 1)) &~(sizeof(long) - 1))), | |||
669 | sizeof(sin6->sin6_port)); | |||
670 | break; | |||
671 | } | |||
672 | ||||
673 | return (0); | |||
674 | } | |||
675 | ||||
676 | void | |||
677 | proxy_recv(int fd, short events, void *arg) | |||
678 | { | |||
679 | struct proxy_listener *l = arg; | |||
680 | ||||
681 | union { | |||
682 | struct cmsghdr hdr; | |||
683 | char buf[CMSG_SPACE(sizeof(struct sockaddr_storage))((((unsigned long)(sizeof(struct cmsghdr)) + (sizeof(long) - 1 )) &~(sizeof(long) - 1)) + (((unsigned long)(sizeof(struct sockaddr_storage)) + (sizeof(long) - 1)) &~(sizeof(long) - 1))) + | |||
684 | CMSG_SPACE(sizeof(in_port_t))((((unsigned long)(sizeof(struct cmsghdr)) + (sizeof(long) - 1 )) &~(sizeof(long) - 1)) + (((unsigned long)(sizeof(in_port_t )) + (sizeof(long) - 1)) &~(sizeof(long) - 1)))]; | |||
685 | } cmsgbuf; | |||
686 | struct cmsghdr *cmsg; | |||
687 | struct msghdr msg; | |||
688 | struct iovec iov; | |||
689 | ssize_t n; | |||
690 | ||||
691 | struct proxy_request *r; | |||
692 | struct tftphdr *tp; | |||
693 | ||||
694 | r = calloc(1, sizeof(*r)); | |||
695 | if (r == NULL((void *)0)) { | |||
696 | recv(fd, safety, sizeof(safety), 0); | |||
697 | return; | |||
698 | } | |||
699 | r->id = arc4random(); /* XXX unique? */ | |||
700 | ||||
701 | bzero(&msg, sizeof(msg)); | |||
702 | iov.iov_base = r->buf; | |||
703 | iov.iov_len = sizeof(r->buf); | |||
704 | msg.msg_name = &r->addrs.src; | |||
705 | msg.msg_namelen = sizeof(r->addrs.src); | |||
706 | msg.msg_iov = &iov; | |||
707 | msg.msg_iovlen = 1; | |||
708 | msg.msg_control = &cmsgbuf.buf; | |||
709 | msg.msg_controllen = sizeof(cmsgbuf.buf); | |||
710 | ||||
711 | n = recvmsg(fd, &msg, 0); | |||
712 | if (n == -1) { | |||
713 | switch (errno(*__errno())) { | |||
714 | case EAGAIN35: | |||
715 | case EINTR4: | |||
716 | goto err; | |||
717 | default: | |||
718 | lerr(1, "recvmsg")logger->err((1), "recvmsg"); | |||
719 | /* NOTREACHED */ | |||
720 | } | |||
721 | } | |||
722 | r->buflen = n; | |||
723 | ||||
724 | /* check the packet */ | |||
725 | if (n < 5) { | |||
726 | /* not enough to be a real packet */ | |||
727 | goto err; | |||
728 | } | |||
729 | tp = (struct tftphdr *)r->buf; | |||
730 | switch (ntohs(tp->th_opcode)(__uint16_t)(__builtin_constant_p(tp->th_opcode) ? (__uint16_t )(((__uint16_t)(tp->th_opcode) & 0xffU) << 8 | ( (__uint16_t)(tp->th_opcode) & 0xff00U) >> 8) : __swap16md (tp->th_opcode))) { | |||
731 | case RRQ01: | |||
732 | case WRQ02: | |||
733 | break; | |||
734 | default: | |||
735 | goto err; | |||
736 | } | |||
737 | ||||
738 | r->addrs.dst.ss_family = r->addrs.src.ss_family; | |||
739 | r->addrs.dst.ss_len = r->addrs.src.ss_len; | |||
740 | ||||
741 | /* get local address if possible */ | |||
742 | for (cmsg = CMSG_FIRSTHDR(&msg)((&msg)->msg_controllen >= sizeof(struct cmsghdr) ? (struct cmsghdr *)(&msg)->msg_control : (struct cmsghdr *)((void *)0)); cmsg != NULL((void *)0); | |||
743 | cmsg = CMSG_NXTHDR(&msg, cmsg)(((char *)(cmsg) + (((unsigned long)((cmsg)->cmsg_len) + ( sizeof(long) - 1)) &~(sizeof(long) - 1)) + (((unsigned long )(sizeof(struct cmsghdr)) + (sizeof(long) - 1)) &~(sizeof (long) - 1)) > ((char *)(&msg)->msg_control) + (& msg)->msg_controllen) ? (struct cmsghdr *)((void *)0) : (struct cmsghdr *)((char *)(cmsg) + (((unsigned long)((cmsg)->cmsg_len ) + (sizeof(long) - 1)) &~(sizeof(long) - 1))))) { | |||
744 | if (l->cmsg2dst(cmsg, &r->addrs.dst) == -1) | |||
745 | goto err; | |||
746 | } | |||
747 | ||||
748 | if (verbose) { | |||
749 | linfo("%s:%d -> %s:%d \"%s %s\"",logger->info("%s:%d -> %s:%d \"%s %s\"", sock_ntop((struct sockaddr *)&r->addrs.src), (__uint16_t)(__builtin_constant_p (((struct sockaddr_in *)&r->addrs.src)->sin_port) ? (__uint16_t)(((__uint16_t)(((struct sockaddr_in *)&r-> addrs.src)->sin_port) & 0xffU) << 8 | ((__uint16_t )(((struct sockaddr_in *)&r->addrs.src)->sin_port) & 0xff00U) >> 8) : __swap16md(((struct sockaddr_in *)& r->addrs.src)->sin_port)), sock_ntop((struct sockaddr * )&r->addrs.dst), (__uint16_t)(__builtin_constant_p(((struct sockaddr_in *)&r->addrs.dst)->sin_port) ? (__uint16_t )(((__uint16_t)(((struct sockaddr_in *)&r->addrs.dst)-> sin_port) & 0xffU) << 8 | ((__uint16_t)(((struct sockaddr_in *)&r->addrs.dst)->sin_port) & 0xff00U) >> 8) : __swap16md(((struct sockaddr_in *)&r->addrs.dst) ->sin_port)), opcode((__uint16_t)(__builtin_constant_p(tp-> th_opcode) ? (__uint16_t)(((__uint16_t)(tp->th_opcode) & 0xffU) << 8 | ((__uint16_t)(tp->th_opcode) & 0xff00U ) >> 8) : __swap16md(tp->th_opcode))), tp->th_u.tu_stuff ) | |||
750 | sock_ntop((struct sockaddr *)&r->addrs.src),logger->info("%s:%d -> %s:%d \"%s %s\"", sock_ntop((struct sockaddr *)&r->addrs.src), (__uint16_t)(__builtin_constant_p (((struct sockaddr_in *)&r->addrs.src)->sin_port) ? (__uint16_t)(((__uint16_t)(((struct sockaddr_in *)&r-> addrs.src)->sin_port) & 0xffU) << 8 | ((__uint16_t )(((struct sockaddr_in *)&r->addrs.src)->sin_port) & 0xff00U) >> 8) : __swap16md(((struct sockaddr_in *)& r->addrs.src)->sin_port)), sock_ntop((struct sockaddr * )&r->addrs.dst), (__uint16_t)(__builtin_constant_p(((struct sockaddr_in *)&r->addrs.dst)->sin_port) ? (__uint16_t )(((__uint16_t)(((struct sockaddr_in *)&r->addrs.dst)-> sin_port) & 0xffU) << 8 | ((__uint16_t)(((struct sockaddr_in *)&r->addrs.dst)->sin_port) & 0xff00U) >> 8) : __swap16md(((struct sockaddr_in *)&r->addrs.dst) ->sin_port)), opcode((__uint16_t)(__builtin_constant_p(tp-> th_opcode) ? (__uint16_t)(((__uint16_t)(tp->th_opcode) & 0xffU) << 8 | ((__uint16_t)(tp->th_opcode) & 0xff00U ) >> 8) : __swap16md(tp->th_opcode))), tp->th_u.tu_stuff ) | |||
751 | ntohs(((struct sockaddr_in *)&r->addrs.src)->sin_port),logger->info("%s:%d -> %s:%d \"%s %s\"", sock_ntop((struct sockaddr *)&r->addrs.src), (__uint16_t)(__builtin_constant_p (((struct sockaddr_in *)&r->addrs.src)->sin_port) ? (__uint16_t)(((__uint16_t)(((struct sockaddr_in *)&r-> addrs.src)->sin_port) & 0xffU) << 8 | ((__uint16_t )(((struct sockaddr_in *)&r->addrs.src)->sin_port) & 0xff00U) >> 8) : __swap16md(((struct sockaddr_in *)& r->addrs.src)->sin_port)), sock_ntop((struct sockaddr * )&r->addrs.dst), (__uint16_t)(__builtin_constant_p(((struct sockaddr_in *)&r->addrs.dst)->sin_port) ? (__uint16_t )(((__uint16_t)(((struct sockaddr_in *)&r->addrs.dst)-> sin_port) & 0xffU) << 8 | ((__uint16_t)(((struct sockaddr_in *)&r->addrs.dst)->sin_port) & 0xff00U) >> 8) : __swap16md(((struct sockaddr_in *)&r->addrs.dst) ->sin_port)), opcode((__uint16_t)(__builtin_constant_p(tp-> th_opcode) ? (__uint16_t)(((__uint16_t)(tp->th_opcode) & 0xffU) << 8 | ((__uint16_t)(tp->th_opcode) & 0xff00U ) >> 8) : __swap16md(tp->th_opcode))), tp->th_u.tu_stuff ) | |||
752 | sock_ntop((struct sockaddr *)&r->addrs.dst),logger->info("%s:%d -> %s:%d \"%s %s\"", sock_ntop((struct sockaddr *)&r->addrs.src), (__uint16_t)(__builtin_constant_p (((struct sockaddr_in *)&r->addrs.src)->sin_port) ? (__uint16_t)(((__uint16_t)(((struct sockaddr_in *)&r-> addrs.src)->sin_port) & 0xffU) << 8 | ((__uint16_t )(((struct sockaddr_in *)&r->addrs.src)->sin_port) & 0xff00U) >> 8) : __swap16md(((struct sockaddr_in *)& r->addrs.src)->sin_port)), sock_ntop((struct sockaddr * )&r->addrs.dst), (__uint16_t)(__builtin_constant_p(((struct sockaddr_in *)&r->addrs.dst)->sin_port) ? (__uint16_t )(((__uint16_t)(((struct sockaddr_in *)&r->addrs.dst)-> sin_port) & 0xffU) << 8 | ((__uint16_t)(((struct sockaddr_in *)&r->addrs.dst)->sin_port) & 0xff00U) >> 8) : __swap16md(((struct sockaddr_in *)&r->addrs.dst) ->sin_port)), opcode((__uint16_t)(__builtin_constant_p(tp-> th_opcode) ? (__uint16_t)(((__uint16_t)(tp->th_opcode) & 0xffU) << 8 | ((__uint16_t)(tp->th_opcode) & 0xff00U ) >> 8) : __swap16md(tp->th_opcode))), tp->th_u.tu_stuff ) | |||
753 | ntohs(((struct sockaddr_in *)&r->addrs.dst)->sin_port),logger->info("%s:%d -> %s:%d \"%s %s\"", sock_ntop((struct sockaddr *)&r->addrs.src), (__uint16_t)(__builtin_constant_p (((struct sockaddr_in *)&r->addrs.src)->sin_port) ? (__uint16_t)(((__uint16_t)(((struct sockaddr_in *)&r-> addrs.src)->sin_port) & 0xffU) << 8 | ((__uint16_t )(((struct sockaddr_in *)&r->addrs.src)->sin_port) & 0xff00U) >> 8) : __swap16md(((struct sockaddr_in *)& r->addrs.src)->sin_port)), sock_ntop((struct sockaddr * )&r->addrs.dst), (__uint16_t)(__builtin_constant_p(((struct sockaddr_in *)&r->addrs.dst)->sin_port) ? (__uint16_t )(((__uint16_t)(((struct sockaddr_in *)&r->addrs.dst)-> sin_port) & 0xffU) << 8 | ((__uint16_t)(((struct sockaddr_in *)&r->addrs.dst)->sin_port) & 0xff00U) >> 8) : __swap16md(((struct sockaddr_in *)&r->addrs.dst) ->sin_port)), opcode((__uint16_t)(__builtin_constant_p(tp-> th_opcode) ? (__uint16_t)(((__uint16_t)(tp->th_opcode) & 0xffU) << 8 | ((__uint16_t)(tp->th_opcode) & 0xff00U ) >> 8) : __swap16md(tp->th_opcode))), tp->th_u.tu_stuff ) | |||
754 | opcode(ntohs(tp->th_opcode)), tp->th_stuff)logger->info("%s:%d -> %s:%d \"%s %s\"", sock_ntop((struct sockaddr *)&r->addrs.src), (__uint16_t)(__builtin_constant_p (((struct sockaddr_in *)&r->addrs.src)->sin_port) ? (__uint16_t)(((__uint16_t)(((struct sockaddr_in *)&r-> addrs.src)->sin_port) & 0xffU) << 8 | ((__uint16_t )(((struct sockaddr_in *)&r->addrs.src)->sin_port) & 0xff00U) >> 8) : __swap16md(((struct sockaddr_in *)& r->addrs.src)->sin_port)), sock_ntop((struct sockaddr * )&r->addrs.dst), (__uint16_t)(__builtin_constant_p(((struct sockaddr_in *)&r->addrs.dst)->sin_port) ? (__uint16_t )(((__uint16_t)(((struct sockaddr_in *)&r->addrs.dst)-> sin_port) & 0xffU) << 8 | ((__uint16_t)(((struct sockaddr_in *)&r->addrs.dst)->sin_port) & 0xff00U) >> 8) : __swap16md(((struct sockaddr_in *)&r->addrs.dst) ->sin_port)), opcode((__uint16_t)(__builtin_constant_p(tp-> th_opcode) ? (__uint16_t)(((__uint16_t)(tp->th_opcode) & 0xffU) << 8 | ((__uint16_t)(tp->th_opcode) & 0xff00U ) >> 8) : __swap16md(tp->th_opcode))), tp->th_u.tu_stuff ); | |||
755 | /* XXX tp->th_stuff could be garbage */ | |||
756 | } | |||
757 | ||||
758 | TAILQ_INSERT_TAIL(&child->fdrequests, r, entry)do { (r)->entry.tqe_next = ((void *)0); (r)->entry.tqe_prev = (&child->fdrequests)->tqh_last; *(&child-> fdrequests)->tqh_last = (r); (&child->fdrequests)-> tqh_last = &(r)->entry.tqe_next; } while (0); | |||
759 | evbuffer_add(child->buf, &r->addrs, sizeof(r->addrs)); | |||
760 | event_add(&child->push_ev, NULL((void *)0)); | |||
761 | ||||
762 | return; | |||
763 | ||||
764 | err: | |||
765 | free(r); | |||
766 | } | |||
767 | ||||
768 | void | |||
769 | unprivproc_push(int fd, short events, void *arg) | |||
770 | { | |||
771 | if (evbuffer_write(child->buf, fd) == -1) | |||
772 | lerr(1, "child evbuffer_write")logger->err((1), "child evbuffer_write"); | |||
773 | ||||
774 | if (EVBUFFER_LENGTH(child->buf)(child->buf)->off) | |||
775 | event_add(&child->push_ev, NULL((void *)0)); | |||
776 | } | |||
777 | ||||
778 | void | |||
779 | unprivproc_pop(int fd, short events, void *arg) | |||
780 | { | |||
781 | struct proxy_request *r; | |||
782 | ||||
783 | struct msghdr msg; | |||
784 | union { | |||
785 | struct cmsghdr hdr; | |||
786 | char buf[CMSG_SPACE(sizeof(int))((((unsigned long)(sizeof(struct cmsghdr)) + (sizeof(long) - 1 )) &~(sizeof(long) - 1)) + (((unsigned long)(sizeof(int)) + (sizeof(long) - 1)) &~(sizeof(long) - 1)))]; | |||
787 | } cmsgbuf; | |||
788 | struct cmsghdr *cmsg; | |||
789 | struct iovec iov; | |||
790 | struct src_addr *src_addr; | |||
791 | struct sockaddr_storage saddr; | |||
792 | socklen_t len; | |||
793 | int result; | |||
794 | int s; | |||
795 | ||||
796 | len = sizeof(saddr); | |||
797 | ||||
798 | do { | |||
799 | memset(&msg, 0, sizeof(msg)); | |||
800 | iov.iov_base = &result; | |||
801 | iov.iov_len = sizeof(int); | |||
802 | msg.msg_iov = &iov; | |||
803 | msg.msg_iovlen = 1; | |||
804 | msg.msg_control = &cmsgbuf.buf; | |||
805 | msg.msg_controllen = sizeof(cmsgbuf.buf); | |||
806 | ||||
807 | switch (recvmsg(fd, &msg, 0)) { | |||
808 | case sizeof(int): | |||
809 | break; | |||
810 | ||||
811 | case -1: | |||
812 | switch (errno(*__errno())) { | |||
813 | case EAGAIN35: | |||
814 | case EINTR4: | |||
815 | return; | |||
816 | default: | |||
817 | lerr(1, "child recvmsg")logger->err((1), "child recvmsg"); | |||
818 | } | |||
819 | /* NOTREACHED */ | |||
820 | ||||
821 | case 0: | |||
822 | lerrx(1, "privproc closed connection")logger->errx((1), "privproc closed connection"); | |||
823 | ||||
824 | default: | |||
825 | lerrx(1, "child recvmsg was weird")logger->errx((1), "child recvmsg was weird"); | |||
826 | /* NOTREACHED */ | |||
827 | } | |||
828 | ||||
829 | if (result != 0) { | |||
830 | errno(*__errno()) = result; | |||
831 | lerr(1, "child fdpass fail")logger->err((1), "child fdpass fail"); | |||
832 | } | |||
833 | ||||
834 | cmsg = CMSG_FIRSTHDR(&msg)((&msg)->msg_controllen >= sizeof(struct cmsghdr) ? (struct cmsghdr *)(&msg)->msg_control : (struct cmsghdr *)((void *)0)); | |||
835 | if (cmsg == NULL((void *)0)) | |||
836 | lerrx(1, "%s: no message header", __func__)logger->errx((1), "%s: no message header", __func__); | |||
837 | ||||
838 | if (cmsg->cmsg_type != SCM_RIGHTS0x01) { | |||
839 | lerrx(1, "%s: expected type %d got %d", __func__,logger->errx((1), "%s: expected type %d got %d", __func__, 0x01, cmsg->cmsg_type) | |||
840 | SCM_RIGHTS, cmsg->cmsg_type)logger->errx((1), "%s: expected type %d got %d", __func__, 0x01, cmsg->cmsg_type); | |||
841 | } | |||
842 | ||||
843 | s = (*(int *)CMSG_DATA(cmsg)((unsigned char *)(cmsg) + (((unsigned long)(sizeof(struct cmsghdr )) + (sizeof(long) - 1)) &~(sizeof(long) - 1)))); | |||
844 | ||||
845 | r = TAILQ_FIRST(&child->fdrequests)((&child->fdrequests)->tqh_first); | |||
846 | if (r == NULL((void *)0)) | |||
847 | lerrx(1, "got fd without a pending request")logger->errx((1), "got fd without a pending request"); | |||
848 | ||||
849 | TAILQ_REMOVE(&child->fdrequests, r, entry)do { if (((r)->entry.tqe_next) != ((void *)0)) (r)->entry .tqe_next->entry.tqe_prev = (r)->entry.tqe_prev; else ( &child->fdrequests)->tqh_last = (r)->entry.tqe_prev ; *(r)->entry.tqe_prev = (r)->entry.tqe_next; ; ; } while (0); | |||
850 | ||||
851 | /* get ready to add rules */ | |||
852 | if (prepare_commit(r->id) == -1) | |||
853 | lerr(1, "%s: prepare_commit", __func__)logger->err((1), "%s: prepare_commit", __func__); | |||
854 | ||||
855 | TAILQ_FOREACH(src_addr, &src_addrs, entry)for((src_addr) = ((&src_addrs)->tqh_first); (src_addr) != ((void *)0); (src_addr) = ((src_addr)->entry.tqe_next) ) | |||
856 | if (src_addr->addr.ss_family == r->addrs.dst.ss_family) | |||
857 | break; | |||
858 | if (src_addr == NULL((void *)0)) { | |||
859 | if (add_filter(r->id, PF_IN, (struct sockaddr *) | |||
860 | &r->addrs.dst, (struct sockaddr *)&r->addrs.src, | |||
861 | ntohs(((struct sockaddr_in *)&r->addrs.src)(__uint16_t)(__builtin_constant_p(((struct sockaddr_in *)& r->addrs.src) ->sin_port) ? (__uint16_t)(((__uint16_t)( ((struct sockaddr_in *)&r->addrs.src) ->sin_port) & 0xffU) << 8 | ((__uint16_t)(((struct sockaddr_in *)& r->addrs.src) ->sin_port) & 0xff00U) >> 8) : __swap16md (((struct sockaddr_in *)&r->addrs.src) ->sin_port)) | |||
862 | ->sin_port)(__uint16_t)(__builtin_constant_p(((struct sockaddr_in *)& r->addrs.src) ->sin_port) ? (__uint16_t)(((__uint16_t)( ((struct sockaddr_in *)&r->addrs.src) ->sin_port) & 0xffU) << 8 | ((__uint16_t)(((struct sockaddr_in *)& r->addrs.src) ->sin_port) & 0xff00U) >> 8) : __swap16md (((struct sockaddr_in *)&r->addrs.src) ->sin_port)), IPPROTO_UDP17) == -1) | |||
863 | lerr(1, "%s: couldn't add pass in", __func__)logger->err((1), "%s: couldn't add pass in", __func__); | |||
864 | } else { | |||
865 | if (getsockname(s, (struct sockaddr*)&saddr, &len) == -1) | |||
866 | lerr(1, "%s: getsockname", __func__)logger->err((1), "%s: getsockname", __func__); | |||
867 | if (add_rdr(r->id, (struct sockaddr *)&r->addrs.dst, | |||
868 | (struct sockaddr*)&saddr, | |||
869 | ntohs(((struct sockaddr_in *)&saddr)->sin_port)(__uint16_t)(__builtin_constant_p(((struct sockaddr_in *)& saddr)->sin_port) ? (__uint16_t)(((__uint16_t)(((struct sockaddr_in *)&saddr)->sin_port) & 0xffU) << 8 | ((__uint16_t )(((struct sockaddr_in *)&saddr)->sin_port) & 0xff00U ) >> 8) : __swap16md(((struct sockaddr_in *)&saddr) ->sin_port)), | |||
870 | (struct sockaddr *)&r->addrs.src, | |||
871 | ntohs(((struct sockaddr_in *)&r->addrs.src)->(__uint16_t)(__builtin_constant_p(((struct sockaddr_in *)& r->addrs.src)-> sin_port) ? (__uint16_t)(((__uint16_t)( ((struct sockaddr_in *)&r->addrs.src)-> sin_port) & 0xffU) << 8 | ((__uint16_t)(((struct sockaddr_in *)& r->addrs.src)-> sin_port) & 0xff00U) >> 8) : __swap16md (((struct sockaddr_in *)&r->addrs.src)-> sin_port)) | |||
872 | sin_port)(__uint16_t)(__builtin_constant_p(((struct sockaddr_in *)& r->addrs.src)-> sin_port) ? (__uint16_t)(((__uint16_t)( ((struct sockaddr_in *)&r->addrs.src)-> sin_port) & 0xffU) << 8 | ((__uint16_t)(((struct sockaddr_in *)& r->addrs.src)-> sin_port) & 0xff00U) >> 8) : __swap16md (((struct sockaddr_in *)&r->addrs.src)-> sin_port)), IPPROTO_UDP17 ) == -1) | |||
873 | lerr(1, "%s: couldn't add rdr rule", __func__)logger->err((1), "%s: couldn't add rdr rule", __func__); | |||
874 | } | |||
875 | ||||
876 | if (add_filter(r->id, PF_OUT, (struct sockaddr *)&r->addrs.dst, | |||
877 | (struct sockaddr *)&r->addrs.src, | |||
878 | ntohs(((struct sockaddr_in *)&r->addrs.src)->sin_port)(__uint16_t)(__builtin_constant_p(((struct sockaddr_in *)& r->addrs.src)->sin_port) ? (__uint16_t)(((__uint16_t)(( (struct sockaddr_in *)&r->addrs.src)->sin_port) & 0xffU) << 8 | ((__uint16_t)(((struct sockaddr_in *)& r->addrs.src)->sin_port) & 0xff00U) >> 8) : __swap16md (((struct sockaddr_in *)&r->addrs.src)->sin_port)), | |||
879 | IPPROTO_UDP17) == -1) | |||
880 | lerr(1, "%s: couldn't add pass out", __func__)logger->err((1), "%s: couldn't add pass out", __func__); | |||
881 | ||||
882 | if (do_commit() == -1) | |||
883 | lerr(1, "%s: couldn't commit rules", __func__)logger->err((1), "%s: couldn't commit rules", __func__); | |||
884 | ||||
885 | /* forward the initial tftp request and start the insanity */ | |||
886 | if (sendto(s, r->buf, r->buflen, 0, | |||
887 | (struct sockaddr *)&r->addrs.dst, | |||
888 | r->addrs.dst.ss_len) == -1) | |||
889 | lerr(1, "%s: unable to send", __func__)logger->err((1), "%s: unable to send", __func__); | |||
890 | ||||
891 | close(s); | |||
892 | ||||
893 | evtimer_set(&r->ev, unprivproc_timeout, r)event_set(&r->ev, -1, 0, unprivproc_timeout, r); | |||
894 | evtimer_add(&r->ev, &transwait)event_add(&r->ev, &transwait); | |||
895 | ||||
896 | TAILQ_INSERT_TAIL(&child->tmrequests, r, entry)do { (r)->entry.tqe_next = ((void *)0); (r)->entry.tqe_prev = (&child->tmrequests)->tqh_last; *(&child-> tmrequests)->tqh_last = (r); (&child->tmrequests)-> tqh_last = &(r)->entry.tqe_next; } while (0); | |||
897 | } while (!TAILQ_EMPTY(&child->fdrequests)(((&child->fdrequests)->tqh_first) == ((void *)0))); | |||
898 | } | |||
899 | ||||
900 | void | |||
901 | unprivproc_timeout(int fd, short events, void *arg) | |||
902 | { | |||
903 | struct proxy_request *r = arg; | |||
904 | ||||
905 | TAILQ_REMOVE(&child->tmrequests, r, entry)do { if (((r)->entry.tqe_next) != ((void *)0)) (r)->entry .tqe_next->entry.tqe_prev = (r)->entry.tqe_prev; else ( &child->tmrequests)->tqh_last = (r)->entry.tqe_prev ; *(r)->entry.tqe_prev = (r)->entry.tqe_next; ; ; } while (0); | |||
906 | ||||
907 | /* delete our rdr rule and clean up */ | |||
908 | prepare_commit(r->id); | |||
909 | do_commit(); | |||
910 | ||||
911 | free(r); | |||
912 | } | |||
913 | ||||
914 | ||||
915 | const char * | |||
916 | opcode(int code) | |||
917 | { | |||
918 | static char str[6]; | |||
919 | ||||
920 | switch (code) { | |||
921 | case 1: | |||
922 | (void)snprintf(str, sizeof(str), "RRQ"); | |||
923 | break; | |||
924 | case 2: | |||
925 | (void)snprintf(str, sizeof(str), "WRQ"); | |||
926 | break; | |||
927 | default: | |||
928 | (void)snprintf(str, sizeof(str), "(%d)", code); | |||
929 | break; | |||
930 | } | |||
931 | ||||
932 | return (str); | |||
933 | } | |||
934 | ||||
935 | const char * | |||
936 | sock_ntop(struct sockaddr *sa) | |||
937 | { | |||
938 | static int n = 0; | |||
939 | ||||
940 | /* Cycle to next buffer. */ | |||
941 | n = (n + 1) % NTOP_BUFS4; | |||
942 | ntop_buf[n][0] = '\0'; | |||
943 | ||||
944 | if (sa->sa_family == AF_INET2) { | |||
945 | struct sockaddr_in *sin = (struct sockaddr_in *)sa; | |||
946 | ||||
947 | return (inet_ntop(AF_INET2, &sin->sin_addr, ntop_buf[n], | |||
948 | sizeof ntop_buf[0])); | |||
949 | } | |||
950 | ||||
951 | if (sa->sa_family == AF_INET624) { | |||
952 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; | |||
953 | ||||
954 | return (inet_ntop(AF_INET624, &sin6->sin6_addr, ntop_buf[n], | |||
955 | sizeof ntop_buf[0])); | |||
956 | } | |||
957 | ||||
958 | return (NULL((void *)0)); | |||
959 | } | |||
960 | ||||
961 | void | |||
962 | syslog_vstrerror(int e, int priority, const char *fmt, va_list ap) | |||
963 | { | |||
964 | char *s; | |||
965 | ||||
966 | if (vasprintf(&s, fmt, ap) == -1) { | |||
967 | syslog(LOG_EMERG0, "unable to alloc in syslog_vstrerror"); | |||
968 | exit(1); | |||
969 | } | |||
970 | ||||
971 | syslog(priority, "%s: %s", s, strerror(e)); | |||
972 | ||||
973 | free(s); | |||
974 | } | |||
975 | ||||
976 | void | |||
977 | syslog_err(int ecode, const char *fmt, ...) | |||
978 | { | |||
979 | va_list ap; | |||
980 | ||||
981 | va_start(ap, fmt)__builtin_va_start(ap, fmt); | |||
982 | syslog_vstrerror(errno(*__errno()), LOG_CRIT2, fmt, ap); | |||
983 | va_end(ap)__builtin_va_end(ap); | |||
984 | ||||
985 | exit(ecode); | |||
986 | } | |||
987 | ||||
988 | void | |||
989 | syslog_errx(int ecode, const char *fmt, ...) | |||
990 | { | |||
991 | va_list ap; | |||
992 | ||||
993 | va_start(ap, fmt)__builtin_va_start(ap, fmt); | |||
994 | vsyslog(LOG_CRIT2, fmt, ap); | |||
995 | va_end(ap)__builtin_va_end(ap); | |||
996 | ||||
997 | exit(ecode); | |||
998 | } | |||
999 | ||||
1000 | void | |||
1001 | syslog_warn(const char *fmt, ...) | |||
1002 | { | |||
1003 | va_list ap; | |||
1004 | ||||
1005 | va_start(ap, fmt)__builtin_va_start(ap, fmt); | |||
1006 | syslog_vstrerror(errno(*__errno()), LOG_ERR3, fmt, ap); | |||
1007 | va_end(ap)__builtin_va_end(ap); | |||
1008 | } | |||
1009 | ||||
1010 | void | |||
1011 | syslog_warnx(const char *fmt, ...) | |||
1012 | { | |||
1013 | va_list ap; | |||
1014 | ||||
1015 | va_start(ap, fmt)__builtin_va_start(ap, fmt); | |||
1016 | vsyslog(LOG_ERR3, fmt, ap); | |||
1017 | va_end(ap)__builtin_va_end(ap); | |||
1018 | } | |||
1019 | ||||
1020 | void | |||
1021 | syslog_info(const char *fmt, ...) | |||
1022 | { | |||
1023 | va_list ap; | |||
1024 | ||||
1025 | va_start(ap, fmt)__builtin_va_start(ap, fmt); | |||
1026 | vsyslog(LOG_INFO6, fmt, ap); | |||
1027 | va_end(ap)__builtin_va_end(ap); | |||
1028 | } | |||
1029 | ||||
1030 | void | |||
1031 | syslog_debug(const char *fmt, ...) | |||
1032 | { | |||
1033 | va_list ap; | |||
1034 | ||||
1035 | if (!debug) | |||
1036 | return; | |||
1037 | ||||
1038 | va_start(ap, fmt)__builtin_va_start(ap, fmt); | |||
1039 | vsyslog(LOG_DEBUG7, fmt, ap); | |||
1040 | va_end(ap)__builtin_va_end(ap); | |||
1041 | } |