1*a95f0396Skirill /* $OpenBSD: frontend.c,v 1.90 2024/11/24 11:33:34 kirill Exp $ */ 2018cebfbSflorian 3018cebfbSflorian /* 4018cebfbSflorian * Copyright (c) 2018 Florian Obser <florian@openbsd.org> 5018cebfbSflorian * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> 6018cebfbSflorian * Copyright (c) 2004 Esben Norby <norby@openbsd.org> 7018cebfbSflorian * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 8018cebfbSflorian * 9018cebfbSflorian * Permission to use, copy, modify, and distribute this software for any 10018cebfbSflorian * purpose with or without fee is hereby granted, provided that the above 11018cebfbSflorian * copyright notice and this permission notice appear in all copies. 12018cebfbSflorian * 13018cebfbSflorian * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14018cebfbSflorian * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15018cebfbSflorian * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16018cebfbSflorian * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17018cebfbSflorian * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18018cebfbSflorian * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19018cebfbSflorian * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20018cebfbSflorian */ 21018cebfbSflorian 22018cebfbSflorian #include <sys/types.h> 23018cebfbSflorian #include <sys/queue.h> 24018cebfbSflorian #include <sys/socket.h> 25018cebfbSflorian #include <sys/syslog.h> 262d988276Sflorian #include <sys/tree.h> 27018cebfbSflorian #include <sys/uio.h> 28018cebfbSflorian 295ec49af2Sflorian #include <netinet/in.h> 30018cebfbSflorian #include <net/if.h> 31018cebfbSflorian #include <net/route.h> 32018cebfbSflorian 33018cebfbSflorian #include <errno.h> 34018cebfbSflorian #include <event.h> 355dca88ceSflorian #include <ifaddrs.h> 36018cebfbSflorian #include <imsg.h> 37018cebfbSflorian #include <netdb.h> 38018cebfbSflorian #include <pwd.h> 39018cebfbSflorian #include <signal.h> 405ec49af2Sflorian #include <stdint.h> 41018cebfbSflorian #include <stdio.h> 42018cebfbSflorian #include <stdlib.h> 43018cebfbSflorian #include <string.h> 445ec49af2Sflorian #include <time.h> 45018cebfbSflorian #include <unistd.h> 46018cebfbSflorian 4771f565e7Sflorian #include "libunbound/config.h" 4871f565e7Sflorian #include "libunbound/sldns/pkthdr.h" 4971f565e7Sflorian #include "libunbound/sldns/sbuffer.h" 50d1b04a40Sflorian #include "libunbound/sldns/str2wire.h" 5171f565e7Sflorian #include "libunbound/sldns/wire2str.h" 52a8ba344bSflorian #include "libunbound/util/alloc.h" 53a8ba344bSflorian #include "libunbound/util/net_help.h" 54a8ba344bSflorian #include "libunbound/util/regional.h" 554340e121Sflorian #include "libunbound/util/data/dname.h" 56a8ba344bSflorian #include "libunbound/util/data/msgencode.h" 574340e121Sflorian #include "libunbound/util/data/msgparse.h" 584340e121Sflorian #include "libunbound/util/data/msgreply.h" 5971f565e7Sflorian 6058b5b9b8Sflorian #include "log.h" 61018cebfbSflorian #include "unwind.h" 62018cebfbSflorian #include "frontend.h" 63018cebfbSflorian #include "control.h" 6400b0420eSflorian #include "dns64_synth.h" 65018cebfbSflorian 6669f07918Sbluhm #define MINIMUM(a, b) (((a) < (b)) ? (a) : (b)) 67018cebfbSflorian #define ROUTE_SOCKET_BUF_SIZE 16384 68018cebfbSflorian 698a36e665Sflorian /* 708a36e665Sflorian * size of a resource record with name a two octed pointer to qname 718a36e665Sflorian * 2 octets pointer to qname 728a36e665Sflorian * 2 octets TYPE 738a36e665Sflorian * 2 octets CLASS 748a36e665Sflorian * 4 octets TTL 758a36e665Sflorian * 2 octets RDLENGTH 768a36e665Sflorian */ 778a36e665Sflorian #define COMPRESSED_RR_SIZE 12 78a8ba344bSflorian #define MINIMIZE_ANSWER 1 798a36e665Sflorian 80297af7e1Sflorian #define FD_RESERVE 5 81297af7e1Sflorian #define TCP_TIMEOUT 15 82297af7e1Sflorian #define DEFAULT_TCP_SIZE 512 83297af7e1Sflorian 84018cebfbSflorian struct udp_ev { 85018cebfbSflorian struct event ev; 86018cebfbSflorian uint8_t query[65536]; 87018cebfbSflorian struct msghdr rcvmhdr; 88018cebfbSflorian struct iovec rcviov[1]; 89018cebfbSflorian struct sockaddr_storage from; 90018cebfbSflorian } udp4ev, udp6ev; 91018cebfbSflorian 92297af7e1Sflorian struct tcp_accept_ev { 93297af7e1Sflorian struct event ev; 94297af7e1Sflorian struct event pause; 95297af7e1Sflorian } tcp4ev, tcp6ev; 96297af7e1Sflorian 97018cebfbSflorian struct pending_query { 98018cebfbSflorian TAILQ_ENTRY(pending_query) entry; 99018cebfbSflorian struct sockaddr_storage from; 1004340e121Sflorian struct sldns_buffer *qbuf; 101a8ba344bSflorian struct sldns_buffer *abuf; 102a8ba344bSflorian struct regional *region; 103a8ba344bSflorian struct query_info qinfo; 104a8ba344bSflorian struct edns_data edns; 105297af7e1Sflorian struct event ev; /* for tcp */ 106297af7e1Sflorian struct event resp_ev; /* for tcp */ 107297af7e1Sflorian struct event tmo_ev; /* for tcp */ 108018cebfbSflorian uint64_t imsg_id; 109dbf56da7Sflorian uint16_t id; 110dbf56da7Sflorian uint16_t flags; 111018cebfbSflorian int fd; 112297af7e1Sflorian int tcp; 11300b0420eSflorian int dns64_synthesize; 114018cebfbSflorian }; 115018cebfbSflorian 116018cebfbSflorian TAILQ_HEAD(, pending_query) pending_queries; 117018cebfbSflorian 1182d988276Sflorian struct bl_node { 1192d988276Sflorian RB_ENTRY(bl_node) entry; 1202d988276Sflorian char *domain; 121*a95f0396Skirill int len; 122*a95f0396Skirill int wildcard; 1232d988276Sflorian }; 1242d988276Sflorian 125018cebfbSflorian __dead void frontend_shutdown(void); 126018cebfbSflorian void frontend_sig_handler(int, short, void *); 127018cebfbSflorian void frontend_startup(void); 128018cebfbSflorian void udp_receive(int, short, void *); 129a8ba344bSflorian void handle_query(struct pending_query *); 130a8ba344bSflorian void free_pending_query(struct pending_query *); 131297af7e1Sflorian void tcp_accept(int, short, void *); 132297af7e1Sflorian int accept_reserve(int, struct sockaddr *, socklen_t *); 133297af7e1Sflorian void accept_paused(int, short, void *); 134297af7e1Sflorian void tcp_request(int, short, void *); 135297af7e1Sflorian void tcp_response(int, short, void *); 136297af7e1Sflorian void tcp_timeout(int, short, void *); 137ad50aed9Sflorian int check_query(sldns_buffer*); 138a8ba344bSflorian void noerror_answer(struct pending_query *); 13900b0420eSflorian void synthesize_dns64_answer(struct pending_query *); 14000b0420eSflorian void resend_dns64_query(struct pending_query *); 1418a36e665Sflorian void chaos_answer(struct pending_query *); 142a8ba344bSflorian void error_answer(struct pending_query *, int rcode); 1431e5d1cd0Sflorian void send_answer(struct pending_query *); 144018cebfbSflorian void route_receive(int, short, void *); 145018cebfbSflorian void handle_route_message(struct rt_msghdr *, 146018cebfbSflorian struct sockaddr **); 147018cebfbSflorian void get_rtaddrs(int, struct sockaddr *, 148018cebfbSflorian struct sockaddr **); 149018cebfbSflorian struct pending_query *find_pending_query(uint64_t); 150296cf316Sflorian void parse_trust_anchor(struct trust_anchor_head *, int); 151296cf316Sflorian void send_trust_anchors(struct trust_anchor_head *); 152296cf316Sflorian void write_trust_anchors(struct trust_anchor_head *, int); 1532d988276Sflorian void parse_blocklist(int); 1542d988276Sflorian int bl_cmp(struct bl_node *, struct bl_node *); 1552d988276Sflorian void free_bl(void); 156b5001ac5Sotto int pending_query_cnt(void); 1575dca88ceSflorian void check_available_af(void); 158*a95f0396Skirill void reverse(char *, char *); 159018cebfbSflorian 160bb81f7e1Sflorian struct uw_conf *frontend_conf; 161d81b02e2Sflorian static struct imsgev *iev_main; 162d81b02e2Sflorian static struct imsgev *iev_resolver; 163018cebfbSflorian struct event ev_route; 1647be68703Sflorian int udp4sock = -1, udp6sock = -1; 165297af7e1Sflorian int tcp4sock = -1, tcp6sock = -1; 166d1b04a40Sflorian int ta_fd = -1; 167018cebfbSflorian 168296cf316Sflorian static struct trust_anchor_head trust_anchors, new_trust_anchors; 169296cf316Sflorian 1702d988276Sflorian RB_HEAD(bl_tree, bl_node) bl_head = RB_INITIALIZER(&bl_head); 1712d988276Sflorian RB_PROTOTYPE(bl_tree, bl_node, entry, bl_cmp) 1722d988276Sflorian RB_GENERATE(bl_tree, bl_node, entry, bl_cmp) 1732d988276Sflorian 17400b0420eSflorian struct dns64_prefix *dns64_prefixes; 17500b0420eSflorian int dns64_prefix_count; 17600b0420eSflorian 177018cebfbSflorian void 178018cebfbSflorian frontend_sig_handler(int sig, short event, void *bula) 179018cebfbSflorian { 180018cebfbSflorian /* 181018cebfbSflorian * Normal signal handler rules don't apply because libevent 182018cebfbSflorian * decouples for us. 183018cebfbSflorian */ 184018cebfbSflorian 185018cebfbSflorian switch (sig) { 186018cebfbSflorian case SIGINT: 187018cebfbSflorian case SIGTERM: 188018cebfbSflorian frontend_shutdown(); 189018cebfbSflorian default: 190018cebfbSflorian fatalx("unexpected signal"); 191018cebfbSflorian } 192018cebfbSflorian } 193018cebfbSflorian 194018cebfbSflorian void 195018cebfbSflorian frontend(int debug, int verbose) 196018cebfbSflorian { 197018cebfbSflorian struct event ev_sigint, ev_sigterm; 198018cebfbSflorian struct passwd *pw; 199018cebfbSflorian 200018cebfbSflorian frontend_conf = config_new_empty(); 201018cebfbSflorian 202018cebfbSflorian log_init(debug, LOG_DAEMON); 203018cebfbSflorian log_setverbose(verbose); 204018cebfbSflorian 205018cebfbSflorian if ((pw = getpwnam(UNWIND_USER)) == NULL) 206018cebfbSflorian fatal("getpwnam"); 207018cebfbSflorian 208018cebfbSflorian if (chroot(pw->pw_dir) == -1) 209018cebfbSflorian fatal("chroot"); 210018cebfbSflorian if (chdir("/") == -1) 211018cebfbSflorian fatal("chdir(\"/\")"); 212018cebfbSflorian 213d223f0d9Sflorian setproctitle("%s", "frontend"); 214d223f0d9Sflorian log_procinit("frontend"); 215018cebfbSflorian 216018cebfbSflorian if (setgroups(1, &pw->pw_gid) || 217018cebfbSflorian setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 218018cebfbSflorian setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 219018cebfbSflorian fatal("can't drop privileges"); 220018cebfbSflorian 2215dca88ceSflorian if (pledge("stdio dns unix recvfd", NULL) == -1) 222018cebfbSflorian fatal("pledge"); 223018cebfbSflorian 224018cebfbSflorian event_init(); 225018cebfbSflorian 226018cebfbSflorian /* Setup signal handler. */ 227018cebfbSflorian signal_set(&ev_sigint, SIGINT, frontend_sig_handler, NULL); 228018cebfbSflorian signal_set(&ev_sigterm, SIGTERM, frontend_sig_handler, NULL); 229018cebfbSflorian signal_add(&ev_sigint, NULL); 230018cebfbSflorian signal_add(&ev_sigterm, NULL); 231018cebfbSflorian signal(SIGPIPE, SIG_IGN); 232018cebfbSflorian signal(SIGHUP, SIG_IGN); 233018cebfbSflorian 234018cebfbSflorian /* Setup pipe and event handler to the parent process. */ 2354595f84cSotto if (iev_main != NULL) 2364595f84cSotto fatal("iev_main"); 237018cebfbSflorian if ((iev_main = malloc(sizeof(struct imsgev))) == NULL) 238018cebfbSflorian fatal(NULL); 2390e59d0d1Sclaudio if (imsgbuf_init(&iev_main->ibuf, 3) == -1) 2400e59d0d1Sclaudio fatal(NULL); 2410e59d0d1Sclaudio imsgbuf_allow_fdpass(&iev_main->ibuf); 242018cebfbSflorian iev_main->handler = frontend_dispatch_main; 243018cebfbSflorian iev_main->events = EV_READ; 244018cebfbSflorian event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events, 245018cebfbSflorian iev_main->handler, iev_main); 246018cebfbSflorian event_add(&iev_main->ev, NULL); 247018cebfbSflorian 248018cebfbSflorian udp4ev.rcviov[0].iov_base = (caddr_t)udp4ev.query; 249018cebfbSflorian udp4ev.rcviov[0].iov_len = sizeof(udp4ev.query); 250018cebfbSflorian udp4ev.rcvmhdr.msg_name = (caddr_t)&udp4ev.from; 251018cebfbSflorian udp4ev.rcvmhdr.msg_namelen = sizeof(udp4ev.from); 252018cebfbSflorian udp4ev.rcvmhdr.msg_iov = udp4ev.rcviov; 253018cebfbSflorian udp4ev.rcvmhdr.msg_iovlen = 1; 254018cebfbSflorian 255018cebfbSflorian udp6ev.rcviov[0].iov_base = (caddr_t)udp6ev.query; 256018cebfbSflorian udp6ev.rcviov[0].iov_len = sizeof(udp6ev.query); 257018cebfbSflorian udp6ev.rcvmhdr.msg_name = (caddr_t)&udp6ev.from; 258018cebfbSflorian udp6ev.rcvmhdr.msg_namelen = sizeof(udp6ev.from); 259018cebfbSflorian udp6ev.rcvmhdr.msg_iov = udp6ev.rcviov; 260018cebfbSflorian udp6ev.rcvmhdr.msg_iovlen = 1; 261018cebfbSflorian 262018cebfbSflorian TAILQ_INIT(&pending_queries); 263018cebfbSflorian 264296cf316Sflorian TAILQ_INIT(&trust_anchors); 265296cf316Sflorian TAILQ_INIT(&new_trust_anchors); 266296cf316Sflorian 267abb04357Sflorian add_new_ta(&trust_anchors, KSK2017); 26810427868Sflorian add_new_ta(&trust_anchors, KSK2024); 269abb04357Sflorian 270018cebfbSflorian event_dispatch(); 271018cebfbSflorian 272018cebfbSflorian frontend_shutdown(); 273018cebfbSflorian } 274018cebfbSflorian 275018cebfbSflorian __dead void 276018cebfbSflorian frontend_shutdown(void) 277018cebfbSflorian { 278018cebfbSflorian /* Close pipes. */ 279dd7efffeSclaudio imsgbuf_write(&iev_resolver->ibuf); 2809cbf9e90Sclaudio imsgbuf_clear(&iev_resolver->ibuf); 281018cebfbSflorian close(iev_resolver->ibuf.fd); 282dd7efffeSclaudio imsgbuf_write(&iev_main->ibuf); 2839cbf9e90Sclaudio imsgbuf_clear(&iev_main->ibuf); 284018cebfbSflorian close(iev_main->ibuf.fd); 285018cebfbSflorian 286018cebfbSflorian config_clear(frontend_conf); 287018cebfbSflorian 288018cebfbSflorian free(iev_resolver); 289018cebfbSflorian free(iev_main); 290018cebfbSflorian 291018cebfbSflorian log_info("frontend exiting"); 292018cebfbSflorian exit(0); 293018cebfbSflorian } 294018cebfbSflorian 295018cebfbSflorian int 296018cebfbSflorian frontend_imsg_compose_main(int type, pid_t pid, void *data, uint16_t datalen) 297018cebfbSflorian { 298bb81f7e1Sflorian return (imsg_compose_event(iev_main, type, 0, pid, -1, data, datalen)); 299018cebfbSflorian } 300018cebfbSflorian 301018cebfbSflorian int 302bb81f7e1Sflorian frontend_imsg_compose_resolver(int type, pid_t pid, void *data, 303bb81f7e1Sflorian uint16_t datalen) 304018cebfbSflorian { 305018cebfbSflorian return (imsg_compose_event(iev_resolver, type, 0, pid, -1, data, 306018cebfbSflorian datalen)); 307018cebfbSflorian } 308018cebfbSflorian 309018cebfbSflorian void 310018cebfbSflorian frontend_dispatch_main(int fd, short event, void *bula) 311018cebfbSflorian { 312bb81f7e1Sflorian static struct uw_conf *nconf; 313018cebfbSflorian struct imsg imsg; 314018cebfbSflorian struct imsgev *iev = bula; 315018cebfbSflorian struct imsgbuf *ibuf = &iev->ibuf; 316018cebfbSflorian int n, shut = 0; 317018cebfbSflorian 318018cebfbSflorian if (event & EV_READ) { 319668e5ba9Sclaudio if ((n = imsgbuf_read(ibuf)) == -1) 320dd7efffeSclaudio fatal("imsgbuf_read error"); 321018cebfbSflorian if (n == 0) /* Connection closed. */ 322018cebfbSflorian shut = 1; 323018cebfbSflorian } 324018cebfbSflorian if (event & EV_WRITE) { 325dd7efffeSclaudio if (imsgbuf_write(ibuf) == -1) { 326e3b6409cSclaudio if (errno == EPIPE) /* Connection closed. */ 327018cebfbSflorian shut = 1; 328e3b6409cSclaudio else 329dd7efffeSclaudio fatal("imsgbuf_write"); 330e3b6409cSclaudio } 331018cebfbSflorian } 332018cebfbSflorian 333018cebfbSflorian for (;;) { 334018cebfbSflorian if ((n = imsg_get(ibuf, &imsg)) == -1) 335018cebfbSflorian fatal("%s: imsg_get error", __func__); 336018cebfbSflorian if (n == 0) /* No more messages. */ 337018cebfbSflorian break; 338018cebfbSflorian 339018cebfbSflorian switch (imsg.hdr.type) { 340b2501eadSflorian case IMSG_SOCKET_IPC_RESOLVER: 341018cebfbSflorian /* 342018cebfbSflorian * Setup pipe and event handler to the resolver 343018cebfbSflorian * process. 344018cebfbSflorian */ 345018cebfbSflorian if (iev_resolver) { 3462b821978Sflorian fatalx("%s: received unexpected imsg fd " 347018cebfbSflorian "to frontend", __func__); 348018cebfbSflorian break; 349018cebfbSflorian } 350eeb36cc3Sclaudio if ((fd = imsg_get_fd(&imsg)) == -1) { 3512b821978Sflorian fatalx("%s: expected to receive imsg fd to " 352018cebfbSflorian "frontend but didn't receive any", 353018cebfbSflorian __func__); 354018cebfbSflorian break; 355018cebfbSflorian } 356018cebfbSflorian 3574595f84cSotto if (iev_resolver != NULL) 3584595f84cSotto fatal("iev_resolver"); 359018cebfbSflorian iev_resolver = malloc(sizeof(struct imsgev)); 360018cebfbSflorian if (iev_resolver == NULL) 361018cebfbSflorian fatal(NULL); 362018cebfbSflorian 3630e59d0d1Sclaudio if (imsgbuf_init(&iev_resolver->ibuf, fd) == -1) 3640e59d0d1Sclaudio fatal(NULL); 365018cebfbSflorian iev_resolver->handler = frontend_dispatch_resolver; 366018cebfbSflorian iev_resolver->events = EV_READ; 367018cebfbSflorian 368018cebfbSflorian event_set(&iev_resolver->ev, iev_resolver->ibuf.fd, 369bb81f7e1Sflorian iev_resolver->events, iev_resolver->handler, 370bb81f7e1Sflorian iev_resolver); 371018cebfbSflorian event_add(&iev_resolver->ev, NULL); 372018cebfbSflorian break; 373018cebfbSflorian case IMSG_RECONF_CONF: 3742d988276Sflorian case IMSG_RECONF_BLOCKLIST_FILE: 375018cebfbSflorian case IMSG_RECONF_FORWARDER: 3763570995aSflorian case IMSG_RECONF_DOT_FORWARDER: 377dd16127bSotto case IMSG_RECONF_FORCE: 378679647feSflorian imsg_receive_config(&imsg, &nconf); 3793570995aSflorian break; 380018cebfbSflorian case IMSG_RECONF_END: 381580cede2Sflorian if (nconf == NULL) 382580cede2Sflorian fatalx("%s: IMSG_RECONF_END without " 383580cede2Sflorian "IMSG_RECONF_CONF", __func__); 384018cebfbSflorian merge_config(frontend_conf, nconf); 3852d988276Sflorian if (frontend_conf->blocklist_file == NULL) 3862d988276Sflorian free_bl(); 387018cebfbSflorian nconf = NULL; 388018cebfbSflorian break; 389018cebfbSflorian case IMSG_UDP6SOCK: 3902b821978Sflorian if (udp6sock != -1) 3912b821978Sflorian fatalx("%s: received unexpected udp6sock", 3922b821978Sflorian __func__); 393eeb36cc3Sclaudio if ((udp6sock = imsg_get_fd(&imsg)) == -1) 394018cebfbSflorian fatalx("%s: expected to receive imsg " 395bb81f7e1Sflorian "UDP6 fd but didn't receive any", __func__); 396018cebfbSflorian event_set(&udp6ev.ev, udp6sock, EV_READ | EV_PERSIST, 397018cebfbSflorian udp_receive, &udp6ev); 398d265a5d3Sflorian event_add(&udp6ev.ev, NULL); 399018cebfbSflorian break; 400018cebfbSflorian case IMSG_UDP4SOCK: 4012b821978Sflorian if (udp4sock != -1) 4022b821978Sflorian fatalx("%s: received unexpected udp4sock", 4032b821978Sflorian __func__); 404eeb36cc3Sclaudio if ((udp4sock = imsg_get_fd(&imsg)) == -1) 405018cebfbSflorian fatalx("%s: expected to receive imsg " 406bb81f7e1Sflorian "UDP4 fd but didn't receive any", __func__); 407018cebfbSflorian event_set(&udp4ev.ev, udp4sock, EV_READ | EV_PERSIST, 408018cebfbSflorian udp_receive, &udp4ev); 409d265a5d3Sflorian event_add(&udp4ev.ev, NULL); 410018cebfbSflorian break; 411297af7e1Sflorian case IMSG_TCP4SOCK: 412297af7e1Sflorian if (tcp4sock != -1) 413297af7e1Sflorian fatalx("%s: received unexpected tcp4sock", 414297af7e1Sflorian __func__); 415eeb36cc3Sclaudio if ((tcp4sock = imsg_get_fd(&imsg)) == -1) 416297af7e1Sflorian fatalx("%s: expected to receive imsg " 417297af7e1Sflorian "TCP4 fd but didn't receive any", __func__); 418297af7e1Sflorian event_set(&tcp4ev.ev, tcp4sock, EV_READ | EV_PERSIST, 419297af7e1Sflorian tcp_accept, &tcp4ev); 420297af7e1Sflorian event_add(&tcp4ev.ev, NULL); 421297af7e1Sflorian evtimer_set(&tcp4ev.pause, accept_paused, &tcp4ev); 422297af7e1Sflorian break; 423297af7e1Sflorian case IMSG_TCP6SOCK: 424297af7e1Sflorian if (tcp6sock != -1) 425297af7e1Sflorian fatalx("%s: received unexpected tcp6sock", 426297af7e1Sflorian __func__); 427eeb36cc3Sclaudio if ((tcp6sock = imsg_get_fd(&imsg)) == -1) 428297af7e1Sflorian fatalx("%s: expected to receive imsg " 429297af7e1Sflorian "TCP6 fd but didn't receive any", __func__); 430297af7e1Sflorian event_set(&tcp6ev.ev, tcp6sock, EV_READ | EV_PERSIST, 431297af7e1Sflorian tcp_accept, &tcp6ev); 432297af7e1Sflorian event_add(&tcp6ev.ev, NULL); 433297af7e1Sflorian evtimer_set(&tcp6ev.pause, accept_paused, &tcp6ev); 434297af7e1Sflorian break; 4357be68703Sflorian case IMSG_ROUTESOCK: { 4367be68703Sflorian static int routesock = -1; 4377be68703Sflorian 4382b821978Sflorian if (routesock != -1) 4392b821978Sflorian fatalx("%s: received unexpected routesock", 4402b821978Sflorian __func__); 441eeb36cc3Sclaudio if ((fd = imsg_get_fd(&imsg)) == -1) 442018cebfbSflorian fatalx("%s: expected to receive imsg " 443018cebfbSflorian "routesocket fd but didn't receive any", 444018cebfbSflorian __func__); 445018cebfbSflorian routesock = fd; 446018cebfbSflorian event_set(&ev_route, fd, EV_READ | EV_PERSIST, 447018cebfbSflorian route_receive, NULL); 448018cebfbSflorian break; 4497be68703Sflorian } 450018cebfbSflorian case IMSG_STARTUP: 451018cebfbSflorian frontend_startup(); 452018cebfbSflorian break; 453018cebfbSflorian case IMSG_CONTROLFD: 454eeb36cc3Sclaudio if ((fd = imsg_get_fd(&imsg)) == -1) 455bb81f7e1Sflorian fatalx("%s: expected to receive imsg control " 456bb81f7e1Sflorian "fd but didn't receive any", __func__); 457018cebfbSflorian /* Listen on control socket. */ 4583538560bSflorian control_listen(fd); 459018cebfbSflorian break; 460296cf316Sflorian case IMSG_TAFD: 461eeb36cc3Sclaudio if ((ta_fd = imsg_get_fd(&imsg)) != -1) 462d1b04a40Sflorian parse_trust_anchor(&trust_anchors, ta_fd); 463296cf316Sflorian if (!TAILQ_EMPTY(&trust_anchors)) 464296cf316Sflorian send_trust_anchors(&trust_anchors); 465296cf316Sflorian break; 4662d988276Sflorian case IMSG_BLFD: 467eeb36cc3Sclaudio if ((fd = imsg_get_fd(&imsg)) == -1) 4682d988276Sflorian fatalx("%s: expected to receive imsg block " 4692d988276Sflorian "list fd but didn't receive any", __func__); 4702d988276Sflorian parse_blocklist(fd); 4712d988276Sflorian break; 472018cebfbSflorian default: 473018cebfbSflorian log_debug("%s: error handling imsg %d", __func__, 474018cebfbSflorian imsg.hdr.type); 475018cebfbSflorian break; 476018cebfbSflorian } 477018cebfbSflorian imsg_free(&imsg); 478018cebfbSflorian } 479018cebfbSflorian if (!shut) 480018cebfbSflorian imsg_event_add(iev); 481018cebfbSflorian else { 482018cebfbSflorian /* This pipe is dead. Remove its event handler. */ 483018cebfbSflorian event_del(&iev->ev); 484018cebfbSflorian event_loopexit(NULL); 485018cebfbSflorian } 486018cebfbSflorian } 487018cebfbSflorian 488018cebfbSflorian void 489018cebfbSflorian frontend_dispatch_resolver(int fd, short event, void *bula) 490018cebfbSflorian { 49100b0420eSflorian static struct dns64_prefix *new_dns64_prefixes = NULL; 49200b0420eSflorian static int new_dns64_prefix_count = 0; 49300b0420eSflorian static int new_dns64_prefix_pos = 0; 49415c83d0cSflorian struct pending_query *pq; 495018cebfbSflorian struct imsgev *iev = bula; 496018cebfbSflorian struct imsgbuf *ibuf = &iev->ibuf; 497018cebfbSflorian struct imsg imsg; 498296cf316Sflorian int n, shut = 0, chg; 499018cebfbSflorian 500018cebfbSflorian if (event & EV_READ) { 501668e5ba9Sclaudio if ((n = imsgbuf_read(ibuf)) == -1) 502dd7efffeSclaudio fatal("imsgbuf_read error"); 503018cebfbSflorian if (n == 0) /* Connection closed. */ 504018cebfbSflorian shut = 1; 505018cebfbSflorian } 506018cebfbSflorian if (event & EV_WRITE) { 507dd7efffeSclaudio if (imsgbuf_write(ibuf) == -1) { 508e3b6409cSclaudio if (errno == EPIPE) /* Connection closed. */ 509018cebfbSflorian shut = 1; 510e3b6409cSclaudio else 511dd7efffeSclaudio fatal("imsgbuf_write"); 512e3b6409cSclaudio } 513018cebfbSflorian } 514018cebfbSflorian 515018cebfbSflorian for (;;) { 516018cebfbSflorian if ((n = imsg_get(ibuf, &imsg)) == -1) 517018cebfbSflorian fatal("%s: imsg_get error", __func__); 518018cebfbSflorian if (n == 0) /* No more messages. */ 519018cebfbSflorian break; 520018cebfbSflorian 521018cebfbSflorian switch (imsg.hdr.type) { 5221548e3a9Sflorian case IMSG_ANSWER: { 5231548e3a9Sflorian struct answer_header *answer_header; 5241548e3a9Sflorian int data_len; 5251548e3a9Sflorian uint8_t *data; 5261548e3a9Sflorian 5271548e3a9Sflorian if (IMSG_DATA_SIZE(imsg) < sizeof(*answer_header)) 52815c83d0cSflorian fatalx("%s: IMSG_ANSWER wrong length: " 52915c83d0cSflorian "%lu", __func__, IMSG_DATA_SIZE(imsg)); 5301548e3a9Sflorian answer_header = (struct answer_header *)imsg.data; 5311548e3a9Sflorian data = (uint8_t *)imsg.data + sizeof(*answer_header); 5324753c8fdSflorian if (answer_header->answer_len > UINT16_MAX) 5331548e3a9Sflorian fatalx("%s: IMSG_ANSWER answer too big: %d", 5341548e3a9Sflorian __func__, answer_header->answer_len); 5351548e3a9Sflorian data_len = IMSG_DATA_SIZE(imsg) - 5361548e3a9Sflorian sizeof(*answer_header); 5371548e3a9Sflorian 5381548e3a9Sflorian if ((pq = find_pending_query(answer_header->id)) == 5391e5d1cd0Sflorian NULL) { 5401548e3a9Sflorian log_warnx("%s: cannot find pending query %llu", 5411548e3a9Sflorian __func__, answer_header->id); 54215c83d0cSflorian break; 54315c83d0cSflorian } 54415c83d0cSflorian 5451548e3a9Sflorian if (answer_header->srvfail) { 546a8ba344bSflorian error_answer(pq, LDNS_RCODE_SERVFAIL); 5471e5d1cd0Sflorian send_answer(pq); 54815c83d0cSflorian break; 54915c83d0cSflorian } 5501548e3a9Sflorian 551dbf56da7Sflorian if (answer_header->bogus && !(pq->flags & BIT_CD)) { 552a8ba344bSflorian error_answer(pq, LDNS_RCODE_SERVFAIL); 55315c83d0cSflorian send_answer(pq); 554018cebfbSflorian break; 5551548e3a9Sflorian } 556a8ba344bSflorian 557a8ba344bSflorian if (sldns_buffer_position(pq->abuf) == 0 && 558a8ba344bSflorian !sldns_buffer_set_capacity(pq->abuf, 559a8ba344bSflorian answer_header->answer_len)) { 560a8ba344bSflorian error_answer(pq, LDNS_RCODE_SERVFAIL); 561a8ba344bSflorian send_answer(pq); 562a8ba344bSflorian break; 5631548e3a9Sflorian } 5641548e3a9Sflorian 565a8ba344bSflorian if (sldns_buffer_position(pq->abuf) + data_len > 566a8ba344bSflorian sldns_buffer_capacity(pq->abuf)) 5671548e3a9Sflorian fatalx("%s: IMSG_ANSWER answer too big: %d", 5681548e3a9Sflorian __func__, data_len); 569a8ba344bSflorian sldns_buffer_write(pq->abuf, data, data_len); 5701548e3a9Sflorian 571a8ba344bSflorian if (sldns_buffer_position(pq->abuf) == 572a8ba344bSflorian sldns_buffer_capacity(pq->abuf)) { 573a8ba344bSflorian sldns_buffer_flip(pq->abuf); 57400b0420eSflorian if (pq->dns64_synthesize) { 57500b0420eSflorian synthesize_dns64_answer(pq); 5761548e3a9Sflorian send_answer(pq); 57700b0420eSflorian } else { 57800b0420eSflorian noerror_answer(pq); 57900b0420eSflorian if (pq->dns64_synthesize) 58000b0420eSflorian /* we did not find a answer */ 58100b0420eSflorian resend_dns64_query(pq); 58200b0420eSflorian else 58300b0420eSflorian send_answer(pq); 58400b0420eSflorian } 585a8ba344bSflorian } 5861548e3a9Sflorian break; 5871548e3a9Sflorian } 588018cebfbSflorian case IMSG_CTL_RESOLVER_INFO: 589ecfbee2cSflorian case IMSG_CTL_AUTOCONF_RESOLVER_INFO: 590c071f090Sflorian case IMSG_CTL_MEM_INFO: 591018cebfbSflorian case IMSG_CTL_END: 592018cebfbSflorian control_imsg_relay(&imsg); 593018cebfbSflorian break; 594296cf316Sflorian case IMSG_NEW_TA: 595296cf316Sflorian /* make sure this is a string */ 596a9155f32Sflorian ((char *)imsg.data)[IMSG_DATA_SIZE(imsg) - 1] = '\0'; 597a9155f32Sflorian add_new_ta(&new_trust_anchors, imsg.data); 598296cf316Sflorian break; 599296cf316Sflorian case IMSG_NEW_TAS_ABORT: 600296cf316Sflorian free_tas(&new_trust_anchors); 601296cf316Sflorian break; 602296cf316Sflorian case IMSG_NEW_TAS_DONE: 603296cf316Sflorian chg = merge_tas(&new_trust_anchors, &trust_anchors); 60407b5b07bSflorian if (chg) 605296cf316Sflorian send_trust_anchors(&trust_anchors); 60607b5b07bSflorian 607296cf316Sflorian /* 608296cf316Sflorian * always write trust anchors, the modify date on 609296cf316Sflorian * the file is an indication when we made progress 610296cf316Sflorian */ 611d1b04a40Sflorian if (ta_fd != -1) 612d1b04a40Sflorian write_trust_anchors(&trust_anchors, ta_fd); 613296cf316Sflorian break; 61400b0420eSflorian case IMSG_NEW_DNS64_PREFIXES_START: 61500b0420eSflorian if (IMSG_DATA_SIZE(imsg) != 61600b0420eSflorian sizeof(new_dns64_prefix_count)) 61700b0420eSflorian fatalx("%s: IMSG_NEW_DNS64_PREFIXES_START " 61800b0420eSflorian "wrong length: %lu", __func__, 61900b0420eSflorian IMSG_DATA_SIZE(imsg)); 62000b0420eSflorian memcpy(&new_dns64_prefix_count, imsg.data, 62100b0420eSflorian sizeof(new_dns64_prefix_count)); 62200b0420eSflorian free(new_dns64_prefixes); 62300b0420eSflorian new_dns64_prefixes = NULL; 62400b0420eSflorian if (new_dns64_prefix_count > 0) 62500b0420eSflorian new_dns64_prefixes = 62600b0420eSflorian calloc(new_dns64_prefix_count, 62700b0420eSflorian sizeof(struct dns64_prefix)); 62800b0420eSflorian new_dns64_prefix_pos = 0; 62900b0420eSflorian break; 63000b0420eSflorian case IMSG_NEW_DNS64_PREFIX: { 63100b0420eSflorian if (IMSG_DATA_SIZE(imsg) != sizeof(struct dns64_prefix)) 63200b0420eSflorian fatalx("%s: IMSG_NEW_DNS64_PREFIX wrong " 63300b0420eSflorian "length: %lu", __func__, 63400b0420eSflorian IMSG_DATA_SIZE(imsg)); 63500b0420eSflorian if (new_dns64_prefixes == NULL) 63600b0420eSflorian break; 63700b0420eSflorian if (new_dns64_prefix_pos >= new_dns64_prefix_count) 63800b0420eSflorian fatalx("%s: IMSG_NEW_DNS64_PREFIX: too many " 63900b0420eSflorian "prefixes", __func__); 64000b0420eSflorian memcpy(&new_dns64_prefixes[new_dns64_prefix_pos++], 64100b0420eSflorian imsg.data, sizeof(struct dns64_prefix)); 64200b0420eSflorian break; 64300b0420eSflorian } 64400b0420eSflorian case IMSG_NEW_DNS64_PREFIXES_DONE: 64500b0420eSflorian free(dns64_prefixes); 64600b0420eSflorian dns64_prefixes = new_dns64_prefixes; 64700b0420eSflorian dns64_prefix_count = new_dns64_prefix_count; 64800b0420eSflorian new_dns64_prefixes = NULL; 64900b0420eSflorian break; 650018cebfbSflorian default: 651018cebfbSflorian log_debug("%s: error handling imsg %d", __func__, 652018cebfbSflorian imsg.hdr.type); 653018cebfbSflorian break; 654018cebfbSflorian } 655018cebfbSflorian imsg_free(&imsg); 656018cebfbSflorian } 657018cebfbSflorian if (!shut) 658018cebfbSflorian imsg_event_add(iev); 659018cebfbSflorian else { 660018cebfbSflorian /* This pipe is dead. Remove its event handler. */ 661018cebfbSflorian event_del(&iev->ev); 662018cebfbSflorian event_loopexit(NULL); 663018cebfbSflorian } 664018cebfbSflorian } 665018cebfbSflorian 666018cebfbSflorian void 667018cebfbSflorian frontend_startup(void) 668018cebfbSflorian { 669018cebfbSflorian if (!event_initialized(&ev_route)) 670018cebfbSflorian fatalx("%s: did not receive a route socket from the main " 671018cebfbSflorian "process", __func__); 672018cebfbSflorian 673018cebfbSflorian event_add(&ev_route, NULL); 674018cebfbSflorian 675018cebfbSflorian frontend_imsg_compose_main(IMSG_STARTUP_DONE, 0, NULL, 0); 6765dca88ceSflorian check_available_af(); 677018cebfbSflorian } 678018cebfbSflorian 679018cebfbSflorian void 680a8ba344bSflorian free_pending_query(struct pending_query *pq) 681a8ba344bSflorian { 682a8ba344bSflorian if (!pq) 683a8ba344bSflorian return; 684a8ba344bSflorian 685a8ba344bSflorian TAILQ_REMOVE(&pending_queries, pq, entry); 686a8ba344bSflorian regional_destroy(pq->region); 687a8ba344bSflorian sldns_buffer_free(pq->qbuf); 688a8ba344bSflorian sldns_buffer_free(pq->abuf); 689297af7e1Sflorian if (pq->tcp) { 690297af7e1Sflorian if (event_initialized(&pq->ev)) 691297af7e1Sflorian event_del(&pq->ev); 692297af7e1Sflorian if (event_initialized(&pq->resp_ev)) 693297af7e1Sflorian event_del(&pq->resp_ev); 694297af7e1Sflorian if (event_initialized(&pq->tmo_ev)) 695297af7e1Sflorian event_del(&pq->tmo_ev); 696297af7e1Sflorian if (pq->fd != -1) 697297af7e1Sflorian close(pq->fd); 698297af7e1Sflorian } 699a8ba344bSflorian free(pq); 700a8ba344bSflorian } 701a8ba344bSflorian 702a8ba344bSflorian void 703018cebfbSflorian udp_receive(int fd, short events, void *arg) 704018cebfbSflorian { 705018cebfbSflorian struct udp_ev *udpev = (struct udp_ev *)arg; 706a8ba344bSflorian struct pending_query *pq = NULL; 707a8ba344bSflorian ssize_t len; 708018cebfbSflorian 709df69c215Sderaadt if ((len = recvmsg(fd, &udpev->rcvmhdr, 0)) == -1) { 710018cebfbSflorian log_warn("recvmsg"); 711018cebfbSflorian return; 712018cebfbSflorian } 713018cebfbSflorian 71410dfa598Sflorian if ((pq = calloc(1, sizeof(*pq))) == NULL) { 715018cebfbSflorian log_warn(NULL); 716018cebfbSflorian return; 717018cebfbSflorian } 718018cebfbSflorian 719018cebfbSflorian do { 720018cebfbSflorian arc4random_buf(&pq->imsg_id, sizeof(pq->imsg_id)); 721018cebfbSflorian } while(find_pending_query(pq->imsg_id) != NULL); 722018cebfbSflorian 723a8ba344bSflorian TAILQ_INSERT_TAIL(&pending_queries, pq, entry); 724a8ba344bSflorian 725a8ba344bSflorian pq->from = udpev->from; 726a8ba344bSflorian pq->fd = fd; 727a8ba344bSflorian pq->qbuf = sldns_buffer_new(len); 728a8ba344bSflorian pq->abuf = sldns_buffer_new(len); /* make sure we can send errors */ 729a8ba344bSflorian pq->region = regional_create(); 730a8ba344bSflorian 731dbf56da7Sflorian if (!pq->qbuf || !pq->abuf || !pq->region) { 732a8ba344bSflorian log_warnx("out of memory"); 733a8ba344bSflorian free_pending_query(pq); 734a8ba344bSflorian return; 7354340e121Sflorian } 736a8ba344bSflorian 7374340e121Sflorian sldns_buffer_write(pq->qbuf, udpev->query, len); 7384340e121Sflorian sldns_buffer_flip(pq->qbuf); 739a8ba344bSflorian handle_query(pq); 740a8ba344bSflorian } 741a8ba344bSflorian 742a8ba344bSflorian void 743a8ba344bSflorian handle_query(struct pending_query *pq) 744a8ba344bSflorian { 745a8ba344bSflorian struct query_imsg query_imsg; 746a8ba344bSflorian struct bl_node find; 747*a95f0396Skirill int rcode, matched; 748a8ba344bSflorian char *str; 749a8ba344bSflorian char dname[LDNS_MAX_DOMAINLEN + 1]; 750a8ba344bSflorian char qclass_buf[16]; 751a8ba344bSflorian char qtype_buf[16]; 752018cebfbSflorian 7536282c991Sflorian if (log_getverbose() & OPT_VERBOSE2 && (str = 754a8ba344bSflorian sldns_wire2str_pkt(sldns_buffer_begin(pq->qbuf), 755a8ba344bSflorian sldns_buffer_limit(pq->qbuf))) != NULL) { 7566282c991Sflorian log_debug("from: %s\n%s", ip_port((struct sockaddr *) 757a8ba344bSflorian &pq->from), str); 7584340e121Sflorian free(str); 7594340e121Sflorian } 7604340e121Sflorian 761dbf56da7Sflorian if (sldns_buffer_remaining(pq->qbuf) < LDNS_HEADER_SIZE) { 762dbf56da7Sflorian log_warnx("bad query: too short, dropped"); 763ad50aed9Sflorian goto drop; 764a8ba344bSflorian } 765a8ba344bSflorian 766dbf56da7Sflorian pq->id = sldns_buffer_read_u16_at(pq->qbuf, 0); 767dbf56da7Sflorian pq->flags = sldns_buffer_read_u16_at(pq->qbuf, 2); 768a8ba344bSflorian 769dbf56da7Sflorian if (!query_info_parse(&pq->qinfo, pq->qbuf)) { 770dbf56da7Sflorian log_warnx("query_info_parse failed"); 771a8ba344bSflorian goto drop; 772a8ba344bSflorian } 773a8ba344bSflorian 774a8ba344bSflorian rcode = check_query(pq->qbuf); 775a8ba344bSflorian switch (rcode) { 776a8ba344bSflorian case LDNS_RCODE_NOERROR: 777a8ba344bSflorian break; 778a8ba344bSflorian case -1: 779a8ba344bSflorian goto drop; 780a8ba344bSflorian default: 781a8ba344bSflorian error_answer(pq, rcode); 782ad50aed9Sflorian goto send_answer; 783ad50aed9Sflorian } 784ad50aed9Sflorian 785a1a7ba80Sflorian rcode = parse_edns_from_query_pkt(pq->qbuf, &pq->edns, NULL, NULL, 7867037e34cSflorian NULL, 0, pq->region, NULL); 787a8ba344bSflorian if (rcode != LDNS_RCODE_NOERROR) { 788a8ba344bSflorian error_answer(pq, rcode); 789ad50aed9Sflorian goto send_answer; 790ad50aed9Sflorian } 791ad50aed9Sflorian 792a8ba344bSflorian if (!dname_valid(pq->qinfo.qname, pq->qinfo.qname_len)) { 793a8ba344bSflorian error_answer(pq, LDNS_RCODE_FORMERR); 794ad50aed9Sflorian goto send_answer; 795ad50aed9Sflorian } 796a8ba344bSflorian dname_str(pq->qinfo.qname, dname); 797ad50aed9Sflorian 798a8ba344bSflorian sldns_wire2str_class_buf(pq->qinfo.qclass, qclass_buf, 799a8ba344bSflorian sizeof(qclass_buf)); 800a8ba344bSflorian sldns_wire2str_type_buf(pq->qinfo.qtype, qtype_buf, sizeof(qtype_buf)); 801a8ba344bSflorian log_debug("%s: %s %s %s ?", ip_port((struct sockaddr *)&pq->from), 8024595f84cSotto dname, qclass_buf, qtype_buf); 803ad50aed9Sflorian 804*a95f0396Skirill if (!RB_EMPTY(&bl_head)) { 805*a95f0396Skirill find.len = strlen(dname); 806*a95f0396Skirill find.wildcard = 0; 807*a95f0396Skirill reverse(dname, dname + find.len); 8084340e121Sflorian find.domain = dname; 809*a95f0396Skirill matched = (RB_FIND(bl_tree, &bl_head, &find) != NULL); 810*a95f0396Skirill reverse(dname, dname + find.len); 811*a95f0396Skirill if (matched) { 812ac71ec8eSflorian if (frontend_conf->blocklist_log) 813ac71ec8eSflorian log_info("blocking %s", dname); 814a8ba344bSflorian error_answer(pq, LDNS_RCODE_REFUSED); 815ad50aed9Sflorian goto send_answer; 816ad50aed9Sflorian } 817*a95f0396Skirill } 818ad50aed9Sflorian 819a8ba344bSflorian if (pq->qinfo.qtype == LDNS_RR_TYPE_AXFR || pq->qinfo.qtype == 820ad50aed9Sflorian LDNS_RR_TYPE_IXFR) { 821a8ba344bSflorian error_answer(pq, LDNS_RCODE_REFUSED); 822ad50aed9Sflorian goto send_answer; 823ad50aed9Sflorian } 824ad50aed9Sflorian 825a8ba344bSflorian if(pq->qinfo.qtype == LDNS_RR_TYPE_OPT || 826a8ba344bSflorian pq->qinfo.qtype == LDNS_RR_TYPE_TSIG || 827a8ba344bSflorian pq->qinfo.qtype == LDNS_RR_TYPE_TKEY || 828a8ba344bSflorian pq->qinfo.qtype == LDNS_RR_TYPE_MAILA || 829a8ba344bSflorian pq->qinfo.qtype == LDNS_RR_TYPE_MAILB || 830a8ba344bSflorian (pq->qinfo.qtype >= 128 && pq->qinfo.qtype <= 248)) { 831a8ba344bSflorian error_answer(pq, LDNS_RCODE_FORMERR); 832ad50aed9Sflorian goto send_answer; 833ad50aed9Sflorian } 834ad50aed9Sflorian 835a8ba344bSflorian if (pq->qinfo.qclass == LDNS_RR_CLASS_CH) { 8368a36e665Sflorian if (strcasecmp(dname, "version.server.") == 0 || 8378a36e665Sflorian strcasecmp(dname, "version.bind.") == 0) { 8388a36e665Sflorian chaos_answer(pq); 8398a36e665Sflorian } else 840a8ba344bSflorian error_answer(pq, LDNS_RCODE_REFUSED); 841ad50aed9Sflorian goto send_answer; 8422d988276Sflorian } 8432d988276Sflorian 844e650aea3Sotto if (strlcpy(query_imsg.qname, dname, sizeof(query_imsg.qname)) >= 845e650aea3Sotto sizeof(query_imsg.qname)) { 84671f565e7Sflorian log_warnx("qname too long"); 847a8ba344bSflorian error_answer(pq, LDNS_RCODE_FORMERR); 848ad50aed9Sflorian goto send_answer; 84971f565e7Sflorian } 850e650aea3Sotto query_imsg.id = pq->imsg_id; 851a8ba344bSflorian query_imsg.t = pq->qinfo.qtype; 852a8ba344bSflorian query_imsg.c = pq->qinfo.qclass; 853018cebfbSflorian 854e650aea3Sotto if (frontend_imsg_compose_resolver(IMSG_QUERY, 0, &query_imsg, 855a8ba344bSflorian sizeof(query_imsg)) == -1) { 856a8ba344bSflorian error_answer(pq, LDNS_RCODE_SERVFAIL); 857ad50aed9Sflorian goto send_answer; 858018cebfbSflorian } 859ad50aed9Sflorian return; 860ad50aed9Sflorian 861ad50aed9Sflorian send_answer: 8621e5d1cd0Sflorian send_answer(pq); 863a8ba344bSflorian return; 864a8ba344bSflorian 865ad50aed9Sflorian drop: 866a8ba344bSflorian free_pending_query(pq); 867a8ba344bSflorian } 868a8ba344bSflorian 869a8ba344bSflorian void 870a8ba344bSflorian noerror_answer(struct pending_query *pq) 871a8ba344bSflorian { 872a8ba344bSflorian struct query_info skip, qinfo; 873a8ba344bSflorian struct reply_info *rinfo = NULL; 874a8ba344bSflorian struct alloc_cache alloc; 875a8ba344bSflorian struct edns_data edns; 87600b0420eSflorian struct ub_packed_rrset_key *an_rrset = NULL; 87700b0420eSflorian struct packed_rrset_data *an_rrset_data = NULL; 878a8ba344bSflorian 879a8ba344bSflorian alloc_init(&alloc, NULL, 0); 880a8ba344bSflorian memset(&qinfo, 0, sizeof(qinfo)); 881a8ba344bSflorian /* read past query section, no memory is allocated */ 882a8ba344bSflorian if (!query_info_parse(&skip, pq->abuf)) 883a8ba344bSflorian goto srvfail; 884a8ba344bSflorian 885a8ba344bSflorian if (reply_info_parse(pq->abuf, &alloc, &qinfo, &rinfo, pq->region, 886a8ba344bSflorian &edns) != 0) 887a8ba344bSflorian goto srvfail; 88800b0420eSflorian 88900b0420eSflorian if ((an_rrset = reply_find_answer_rrset(&qinfo, rinfo)) != NULL) 89000b0420eSflorian an_rrset_data = (struct packed_rrset_data*)an_rrset->entry.data; 89100b0420eSflorian 892a8ba344bSflorian /* reply_info_parse() allocates memory */ 893a8ba344bSflorian query_info_clear(&qinfo); 894a8ba344bSflorian 89500b0420eSflorian /* XXX check that there a no AAAA records in answer section? */ 89600b0420eSflorian if ((an_rrset_data == NULL || an_rrset_data->count == 0) && 89700b0420eSflorian !pq->dns64_synthesize && pq->qinfo.qtype == LDNS_RR_TYPE_AAAA && 89800b0420eSflorian pq->qinfo.qclass == LDNS_RR_CLASS_IN && dns64_prefix_count > 0) { 89900b0420eSflorian pq->dns64_synthesize = 1; 90000b0420eSflorian return; 90100b0420eSflorian } 90200b0420eSflorian 903a8ba344bSflorian sldns_buffer_clear(pq->abuf); 904dbf56da7Sflorian if (reply_info_encode(&pq->qinfo, rinfo, htons(pq->id), rinfo->flags, 905297af7e1Sflorian pq->abuf, 0, pq->region, pq->tcp ? UINT16_MAX : pq->edns.udp_size, 906a8ba344bSflorian pq->edns.bits & EDNS_DO, MINIMIZE_ANSWER) == 0) 907a8ba344bSflorian goto srvfail; 908a8ba344bSflorian 909a8ba344bSflorian reply_info_parsedelete(rinfo, &alloc); 910a8ba344bSflorian alloc_clear(&alloc); 911a8ba344bSflorian return; 912a8ba344bSflorian 913a8ba344bSflorian srvfail: 914a8ba344bSflorian reply_info_parsedelete(rinfo, &alloc); 915a8ba344bSflorian alloc_clear(&alloc); 916a8ba344bSflorian error_answer(pq, LDNS_RCODE_SERVFAIL); 917ad50aed9Sflorian } 918ad50aed9Sflorian 9198a36e665Sflorian void 92000b0420eSflorian synthesize_dns64_answer(struct pending_query *pq) 92100b0420eSflorian { 92200b0420eSflorian struct query_info skip, qinfo; 92300b0420eSflorian struct reply_info *rinfo = NULL, *synth_rinfo = NULL; 92400b0420eSflorian struct alloc_cache alloc; 92500b0420eSflorian struct edns_data edns; 92600b0420eSflorian size_t i; 92700b0420eSflorian 92800b0420eSflorian pq->dns64_synthesize = 0; 92900b0420eSflorian 93000b0420eSflorian alloc_init(&alloc, NULL, 0); 93100b0420eSflorian memset(&qinfo, 0, sizeof(qinfo)); 93200b0420eSflorian /* read past query section, no memory is allocated */ 93300b0420eSflorian if (!query_info_parse(&skip, pq->abuf)) 93400b0420eSflorian goto srvfail; 93500b0420eSflorian 93600b0420eSflorian if (reply_info_parse(pq->abuf, &alloc, &qinfo, &rinfo, pq->region, 93700b0420eSflorian &edns) != 0) 93800b0420eSflorian goto srvfail; 93900b0420eSflorian 94000b0420eSflorian /* reply_info_parse() allocates memory */ 94100b0420eSflorian query_info_clear(&qinfo); 94200b0420eSflorian 94300b0420eSflorian synth_rinfo = construct_reply_info_base(pq->region, rinfo->flags, 94400b0420eSflorian rinfo->qdcount, rinfo->ttl, rinfo->prefetch_ttl, 94500b0420eSflorian rinfo->serve_expired_ttl, rinfo->an_numrrsets, 94600b0420eSflorian rinfo->ns_numrrsets, rinfo->ar_numrrsets, rinfo->rrset_count, 9476ced2d15Sflorian rinfo->security, rinfo->reason_bogus); 94800b0420eSflorian 94900b0420eSflorian if (!synth_rinfo) 95000b0420eSflorian goto srvfail; 95100b0420eSflorian 95200b0420eSflorian if(!reply_info_alloc_rrset_keys(synth_rinfo, NULL, pq->region)) 95300b0420eSflorian goto srvfail; 95400b0420eSflorian 95500b0420eSflorian for (i = 0; i < synth_rinfo->rrset_count; i++) { 95600b0420eSflorian struct ub_packed_rrset_key *src_rrset_key, *dst_rrset_key; 95700b0420eSflorian struct packed_rrset_data *src_rrset_data; 95800b0420eSflorian struct packed_rrset_data *dst_rrset_data; 95900b0420eSflorian 96000b0420eSflorian src_rrset_key = rinfo->rrsets[i]; 96100b0420eSflorian src_rrset_data = 96200b0420eSflorian (struct packed_rrset_data *)src_rrset_key->entry.data; 96300b0420eSflorian dst_rrset_key = synth_rinfo->rrsets[i]; 96400b0420eSflorian 96500b0420eSflorian dst_rrset_key->id = src_rrset_key->id; 96600b0420eSflorian dst_rrset_key->rk = src_rrset_key->rk; 96700b0420eSflorian 96800b0420eSflorian if (i < rinfo->an_numrrsets && src_rrset_key->rk.type == 96900b0420eSflorian htons(LDNS_RR_TYPE_A)) { 97000b0420eSflorian dns64_synth_aaaa_data(src_rrset_key, src_rrset_data, 97100b0420eSflorian dst_rrset_key, &dst_rrset_data, pq->region); 97200b0420eSflorian if (dst_rrset_data == NULL) 97300b0420eSflorian goto srvfail; 97400b0420eSflorian } else { 97500b0420eSflorian dst_rrset_key->entry.hash = src_rrset_key->entry.hash; 97600b0420eSflorian dst_rrset_key->rk.dname = regional_alloc_init( 97700b0420eSflorian pq->region, src_rrset_key->rk.dname, 97800b0420eSflorian src_rrset_key->rk.dname_len); 97900b0420eSflorian if (dst_rrset_key->rk.dname == NULL) 98000b0420eSflorian goto srvfail; 98100b0420eSflorian 98200b0420eSflorian dst_rrset_data = regional_alloc_init(pq->region, 98300b0420eSflorian src_rrset_data, 98400b0420eSflorian packed_rrset_sizeof(src_rrset_data)); 98500b0420eSflorian if (dst_rrset_data == NULL) 98600b0420eSflorian goto srvfail; 98700b0420eSflorian } 98800b0420eSflorian 98900b0420eSflorian packed_rrset_ptr_fixup(dst_rrset_data); 99000b0420eSflorian dst_rrset_key->entry.data = dst_rrset_data; 99100b0420eSflorian } 99200b0420eSflorian 99300b0420eSflorian if (!sldns_buffer_set_capacity(pq->abuf, pq->tcp ? UINT16_MAX : 99400b0420eSflorian pq->edns.udp_size)) 99500b0420eSflorian goto srvfail; 99600b0420eSflorian 99700b0420eSflorian sldns_buffer_clear(pq->abuf); 99800b0420eSflorian 999dbf56da7Sflorian if (reply_info_encode(&pq->qinfo, synth_rinfo, htons(pq->id), 100000b0420eSflorian synth_rinfo->flags, pq->abuf, 0, pq->region, 100100b0420eSflorian pq->tcp ? UINT16_MAX : pq->edns.udp_size, 100200b0420eSflorian pq->edns.bits & EDNS_DO, MINIMIZE_ANSWER) == 0) 100300b0420eSflorian goto srvfail; 100400b0420eSflorian 100500b0420eSflorian reply_info_parsedelete(rinfo, &alloc); 100600b0420eSflorian alloc_clear(&alloc); 100700b0420eSflorian return; 100800b0420eSflorian 100900b0420eSflorian srvfail: 101000b0420eSflorian reply_info_parsedelete(rinfo, &alloc); 101100b0420eSflorian alloc_clear(&alloc); 101200b0420eSflorian error_answer(pq, LDNS_RCODE_SERVFAIL); 101300b0420eSflorian } 101400b0420eSflorian 101500b0420eSflorian void 10162de410b6Stb resend_dns64_query(struct pending_query *opq) 10172de410b6Stb { 101800b0420eSflorian struct pending_query *pq; 101900b0420eSflorian struct query_imsg query_imsg; 102000b0420eSflorian int rcode; 102100b0420eSflorian char dname[LDNS_MAX_DOMAINLEN + 1]; 102200b0420eSflorian 102300b0420eSflorian if ((pq = calloc(1, sizeof(*pq))) == NULL) { 102400b0420eSflorian log_warn(NULL); 102500b0420eSflorian return; 102600b0420eSflorian } 102700b0420eSflorian 102800b0420eSflorian do { 102900b0420eSflorian arc4random_buf(&pq->imsg_id, sizeof(pq->imsg_id)); 103000b0420eSflorian } while(find_pending_query(pq->imsg_id) != NULL); 103100b0420eSflorian 103200b0420eSflorian TAILQ_INSERT_TAIL(&pending_queries, pq, entry); 103300b0420eSflorian 103400b0420eSflorian pq->from = opq->from; 103500b0420eSflorian pq->fd = opq->fd; 103600b0420eSflorian opq->fd = -1; 103700b0420eSflorian pq->tcp = opq->tcp; 103800b0420eSflorian pq->qbuf = sldns_buffer_new(sldns_buffer_capacity(opq->qbuf)); 103900b0420eSflorian pq->abuf = sldns_buffer_new(sldns_buffer_capacity(opq->abuf)); 104000b0420eSflorian pq->region = regional_create(); 104100b0420eSflorian 1042dbf56da7Sflorian if (!pq->qbuf || !pq->abuf || !pq->region) { 104300b0420eSflorian log_warnx("out of memory"); 104400b0420eSflorian free_pending_query(pq); 104500b0420eSflorian free_pending_query(opq); 104600b0420eSflorian return; 104700b0420eSflorian } 104800b0420eSflorian 104900b0420eSflorian sldns_buffer_rewind(opq->qbuf); 105000b0420eSflorian sldns_buffer_write(pq->qbuf, sldns_buffer_current(opq->qbuf), 105100b0420eSflorian sldns_buffer_remaining(opq->qbuf)); 105200b0420eSflorian sldns_buffer_flip(pq->qbuf); 105300b0420eSflorian 105400b0420eSflorian if (pq->tcp) { 105500b0420eSflorian struct timeval timeout = {TCP_TIMEOUT, 0}; 105600b0420eSflorian 105700b0420eSflorian event_set(&pq->ev, pq->fd, EV_READ | EV_PERSIST, tcp_request, 105800b0420eSflorian pq); 105900b0420eSflorian event_set(&pq->resp_ev, pq->fd, EV_WRITE | EV_PERSIST, 106000b0420eSflorian tcp_response, pq); 106100b0420eSflorian evtimer_set(&pq->tmo_ev, tcp_timeout, pq); 106200b0420eSflorian evtimer_add(&pq->tmo_ev, &timeout); 106300b0420eSflorian } 106400b0420eSflorian 1065dbf56da7Sflorian if (sldns_buffer_remaining(pq->qbuf) < LDNS_HEADER_SIZE) { 1066dbf56da7Sflorian log_warnx("bad query: too short, dropped"); 1067dbf56da7Sflorian goto drop; 1068dbf56da7Sflorian } 1069dbf56da7Sflorian 1070dbf56da7Sflorian pq->id = sldns_buffer_read_u16_at(pq->qbuf, 0); 1071dbf56da7Sflorian pq->flags = sldns_buffer_read_u16_at(pq->qbuf, 2); 1072dbf56da7Sflorian 107300b0420eSflorian if (!query_info_parse(&pq->qinfo, pq->qbuf)) { 107400b0420eSflorian log_warnx("query_info_parse failed"); 107500b0420eSflorian goto drop; 107600b0420eSflorian } 107700b0420eSflorian 1078a1a7ba80Sflorian rcode = parse_edns_from_query_pkt(pq->qbuf, &pq->edns, NULL, NULL, 10797037e34cSflorian NULL, 0, pq->region, NULL); 108000b0420eSflorian if (rcode != LDNS_RCODE_NOERROR) { 108100b0420eSflorian error_answer(pq, rcode); 108200b0420eSflorian goto send_answer; 108300b0420eSflorian } 108400b0420eSflorian 108500b0420eSflorian dname_str(pq->qinfo.qname, dname); 108600b0420eSflorian strlcpy(query_imsg.qname, dname, sizeof(query_imsg.qname)); 108700b0420eSflorian query_imsg.id = pq->imsg_id; 108800b0420eSflorian query_imsg.t = LDNS_RR_TYPE_A; 108900b0420eSflorian query_imsg.c = pq->qinfo.qclass; 109000b0420eSflorian 109100b0420eSflorian pq->dns64_synthesize = 1; 109200b0420eSflorian 109300b0420eSflorian if (frontend_imsg_compose_resolver(IMSG_QUERY, 0, &query_imsg, 109400b0420eSflorian sizeof(query_imsg)) == -1) { 109500b0420eSflorian error_answer(pq, LDNS_RCODE_SERVFAIL); 109600b0420eSflorian goto send_answer; 109700b0420eSflorian } 109800b0420eSflorian 109900b0420eSflorian free_pending_query(opq); 110000b0420eSflorian return; 110100b0420eSflorian 110200b0420eSflorian send_answer: 110300b0420eSflorian free_pending_query(opq); 110400b0420eSflorian send_answer(pq); 110500b0420eSflorian return; 110600b0420eSflorian 110700b0420eSflorian drop: 110800b0420eSflorian free_pending_query(opq); 110900b0420eSflorian free_pending_query(pq); 111000b0420eSflorian } 111100b0420eSflorian 111200b0420eSflorian void 11138a36e665Sflorian chaos_answer(struct pending_query *pq) 11148a36e665Sflorian { 1115a8ba344bSflorian size_t len; 1116a8ba344bSflorian const char *name = "unwind"; 11178a36e665Sflorian 11188a36e665Sflorian len = strlen(name); 1119a8ba344bSflorian if (!sldns_buffer_set_capacity(pq->abuf, 1120a8ba344bSflorian sldns_buffer_capacity(pq->qbuf) + COMPRESSED_RR_SIZE + 1 + len)) { 1121a8ba344bSflorian error_answer(pq, LDNS_RCODE_SERVFAIL); 11228a36e665Sflorian return; 1123a8ba344bSflorian } 11248a36e665Sflorian 1125a8ba344bSflorian sldns_buffer_copy(pq->abuf, pq->qbuf); 11268a36e665Sflorian 1127a8ba344bSflorian sldns_buffer_clear(pq->abuf); 1128a8ba344bSflorian 1129a8ba344bSflorian sldns_buffer_skip(pq->abuf, sizeof(uint16_t)); /* skip id */ 1130a8ba344bSflorian sldns_buffer_write_u16(pq->abuf, 0); /* clear flags */ 1131a8ba344bSflorian LDNS_QR_SET(sldns_buffer_begin(pq->abuf)); 1132a8ba344bSflorian LDNS_RA_SET(sldns_buffer_begin(pq->abuf)); 11338a36e665Sflorian if (LDNS_RD_WIRE(sldns_buffer_begin(pq->qbuf))) 1134a8ba344bSflorian LDNS_RD_SET(sldns_buffer_begin(pq->abuf)); 11358a36e665Sflorian if (LDNS_CD_WIRE(sldns_buffer_begin(pq->qbuf))) 1136a8ba344bSflorian LDNS_CD_SET(sldns_buffer_begin(pq->abuf)); 1137a8ba344bSflorian LDNS_RCODE_SET(sldns_buffer_begin(pq->abuf), LDNS_RCODE_NOERROR); 1138a8ba344bSflorian sldns_buffer_write_u16(pq->abuf, 1); /* qdcount */ 1139a8ba344bSflorian sldns_buffer_write_u16(pq->abuf, 1); /* ancount */ 1140a8ba344bSflorian sldns_buffer_write_u16(pq->abuf, 0); /* nscount */ 1141a8ba344bSflorian sldns_buffer_write_u16(pq->abuf, 0); /* arcount */ 1142a8ba344bSflorian (void)query_dname_len(pq->abuf); /* skip qname */ 1143a8ba344bSflorian sldns_buffer_skip(pq->abuf, sizeof(uint16_t)); /* skip qtype */ 1144a8ba344bSflorian sldns_buffer_skip(pq->abuf, sizeof(uint16_t)); /* skip qclass */ 11458a36e665Sflorian 1146a8ba344bSflorian sldns_buffer_write_u16(pq->abuf, 0xc00c); /* ptr to query */ 1147a8ba344bSflorian sldns_buffer_write_u16(pq->abuf, LDNS_RR_TYPE_TXT); 1148a8ba344bSflorian sldns_buffer_write_u16(pq->abuf, LDNS_RR_CLASS_CH); 1149a8ba344bSflorian sldns_buffer_write_u32(pq->abuf, 0); /* TTL */ 1150a8ba344bSflorian sldns_buffer_write_u16(pq->abuf, 1 + len); /* RDLENGTH */ 1151a8ba344bSflorian sldns_buffer_write_u8(pq->abuf, len); /* length octed */ 1152a8ba344bSflorian sldns_buffer_write(pq->abuf, name, len); 1153a8ba344bSflorian sldns_buffer_flip(pq->abuf); 1154a8ba344bSflorian } 1155a8ba344bSflorian 1156a8ba344bSflorian void 1157a8ba344bSflorian error_answer(struct pending_query *pq, int rcode) 1158a8ba344bSflorian { 1159a8ba344bSflorian sldns_buffer_clear(pq->abuf); 1160dbf56da7Sflorian error_encode(pq->abuf, rcode, &pq->qinfo, htons(pq->id), pq->flags, 1161dbf56da7Sflorian pq->edns.edns_present ? &pq->edns : NULL); 11628a36e665Sflorian } 11638a36e665Sflorian 1164ad50aed9Sflorian int 1165ad50aed9Sflorian check_query(sldns_buffer* pkt) 1166ad50aed9Sflorian { 1167ad50aed9Sflorian if(sldns_buffer_limit(pkt) < LDNS_HEADER_SIZE) { 1168ad50aed9Sflorian log_warnx("bad query: too short, dropped"); 1169ad50aed9Sflorian return -1; 1170ad50aed9Sflorian } 1171ad50aed9Sflorian if(LDNS_QR_WIRE(sldns_buffer_begin(pkt))) { 1172ad50aed9Sflorian log_warnx("bad query: QR set, dropped"); 1173ad50aed9Sflorian return -1; 1174ad50aed9Sflorian } 1175ad50aed9Sflorian if(LDNS_TC_WIRE(sldns_buffer_begin(pkt))) { 1176ad50aed9Sflorian LDNS_TC_CLR(sldns_buffer_begin(pkt)); 1177ad50aed9Sflorian log_warnx("bad query: TC set"); 1178ad50aed9Sflorian return (LDNS_RCODE_FORMERR); 1179ad50aed9Sflorian } 1180ad50aed9Sflorian if(!(LDNS_RD_WIRE(sldns_buffer_begin(pkt)))) { 1181ad50aed9Sflorian log_warnx("bad query: RD not set"); 1182ad50aed9Sflorian return (LDNS_RCODE_REFUSED); 1183ad50aed9Sflorian } 1184ad50aed9Sflorian if(LDNS_OPCODE_WIRE(sldns_buffer_begin(pkt)) != LDNS_PACKET_QUERY) { 1185ad50aed9Sflorian log_warnx("bad query: unknown opcode %d", 1186ad50aed9Sflorian LDNS_OPCODE_WIRE(sldns_buffer_begin(pkt))); 1187ad50aed9Sflorian return (LDNS_RCODE_NOTIMPL); 1188ad50aed9Sflorian } 1189ad50aed9Sflorian 1190ad50aed9Sflorian if (LDNS_QDCOUNT(sldns_buffer_begin(pkt)) != 1 && 1191ad50aed9Sflorian LDNS_ANCOUNT(sldns_buffer_begin(pkt))!= 0 && 1192ad50aed9Sflorian LDNS_NSCOUNT(sldns_buffer_begin(pkt))!= 0 && 1193ad50aed9Sflorian LDNS_ARCOUNT(sldns_buffer_begin(pkt)) > 1) { 1194ad50aed9Sflorian log_warnx("bad query: qdcount: %d, ancount: %d " 1195ad50aed9Sflorian "nscount: %d, arcount: %d", 1196ad50aed9Sflorian LDNS_QDCOUNT(sldns_buffer_begin(pkt)), 1197ad50aed9Sflorian LDNS_ANCOUNT(sldns_buffer_begin(pkt)), 1198ad50aed9Sflorian LDNS_NSCOUNT(sldns_buffer_begin(pkt)), 1199ad50aed9Sflorian LDNS_ARCOUNT(sldns_buffer_begin(pkt))); 1200ad50aed9Sflorian return (LDNS_RCODE_FORMERR); 1201ad50aed9Sflorian } 12021e80ba60Sflorian return (LDNS_RCODE_NOERROR); 1203018cebfbSflorian } 1204018cebfbSflorian 1205018cebfbSflorian void 12061e5d1cd0Sflorian send_answer(struct pending_query *pq) 1207018cebfbSflorian { 12086282c991Sflorian char *str; 1209018cebfbSflorian 12106282c991Sflorian if (log_getverbose() & OPT_VERBOSE2 && (str = 1211a8ba344bSflorian sldns_wire2str_pkt(sldns_buffer_begin(pq->abuf), 1212a8ba344bSflorian sldns_buffer_limit(pq->abuf))) != NULL) { 1213a8ba344bSflorian log_debug("from: %s\n%s", ip_port((struct sockaddr *) 1214a8ba344bSflorian &pq->from), str); 12156282c991Sflorian free(str); 12166282c991Sflorian } 12176282c991Sflorian 1218297af7e1Sflorian if (!pq->tcp) { 1219a8ba344bSflorian if(sendto(pq->fd, sldns_buffer_current(pq->abuf), 1220a8ba344bSflorian sldns_buffer_remaining(pq->abuf), 0, 1221a8ba344bSflorian (struct sockaddr *)&pq->from, pq->from.ss_len) == -1) 1222018cebfbSflorian log_warn("sendto"); 1223a8ba344bSflorian free_pending_query(pq); 1224297af7e1Sflorian } else { 1225297af7e1Sflorian struct sldns_buffer *tmp; 1226297af7e1Sflorian 1227297af7e1Sflorian tmp = sldns_buffer_new(sldns_buffer_limit(pq->abuf) + 2); 1228297af7e1Sflorian 1229297af7e1Sflorian if (!tmp) { 1230297af7e1Sflorian free_pending_query(pq); 1231297af7e1Sflorian return; 1232297af7e1Sflorian } 1233297af7e1Sflorian 1234297af7e1Sflorian sldns_buffer_write_u16(tmp, sldns_buffer_limit(pq->abuf)); 1235297af7e1Sflorian sldns_buffer_write(tmp, sldns_buffer_current(pq->abuf), 1236297af7e1Sflorian sldns_buffer_remaining(pq->abuf)); 1237297af7e1Sflorian sldns_buffer_flip(tmp); 1238297af7e1Sflorian sldns_buffer_free(pq->abuf); 1239297af7e1Sflorian pq->abuf = tmp; 1240297af7e1Sflorian event_add(&pq->resp_ev, NULL); 1241297af7e1Sflorian } 1242018cebfbSflorian } 1243018cebfbSflorian 1244018cebfbSflorian char* 1245018cebfbSflorian ip_port(struct sockaddr *sa) 1246018cebfbSflorian { 1247018cebfbSflorian static char hbuf[NI_MAXHOST], buf[NI_MAXHOST]; 1248018cebfbSflorian 1249018cebfbSflorian if (getnameinfo(sa, sa->sa_len, hbuf, sizeof(hbuf), NULL, 0, 1250018cebfbSflorian NI_NUMERICHOST) != 0) { 1251018cebfbSflorian snprintf(buf, sizeof(buf), "%s", "(unknown)"); 1252018cebfbSflorian return buf; 1253018cebfbSflorian } 1254018cebfbSflorian 1255018cebfbSflorian if (sa->sa_family == AF_INET6) 12569c8ccd70Sflorian snprintf(buf, sizeof(buf), "[%s]:%d", hbuf, ntohs( 12579c8ccd70Sflorian ((struct sockaddr_in6 *)sa)->sin6_port)); 1258018cebfbSflorian if (sa->sa_family == AF_INET) 12599c8ccd70Sflorian snprintf(buf, sizeof(buf), "[%s]:%d", hbuf, ntohs( 12609c8ccd70Sflorian ((struct sockaddr_in *)sa)->sin_port)); 1261018cebfbSflorian 1262018cebfbSflorian return buf; 1263018cebfbSflorian } 1264018cebfbSflorian 1265018cebfbSflorian struct pending_query* 1266018cebfbSflorian find_pending_query(uint64_t id) 1267018cebfbSflorian { 1268018cebfbSflorian struct pending_query *pq; 1269018cebfbSflorian 1270018cebfbSflorian TAILQ_FOREACH(pq, &pending_queries, entry) 1271018cebfbSflorian if (pq->imsg_id == id) 1272018cebfbSflorian return pq; 1273018cebfbSflorian return NULL; 1274018cebfbSflorian } 1275018cebfbSflorian 1276018cebfbSflorian void 1277018cebfbSflorian route_receive(int fd, short events, void *arg) 1278018cebfbSflorian { 1279018cebfbSflorian static uint8_t *buf; 1280018cebfbSflorian 1281018cebfbSflorian struct rt_msghdr *rtm; 1282018cebfbSflorian struct sockaddr *sa, *rti_info[RTAX_MAX]; 1283018cebfbSflorian ssize_t n; 1284018cebfbSflorian 1285018cebfbSflorian if (buf == NULL) { 1286018cebfbSflorian buf = malloc(ROUTE_SOCKET_BUF_SIZE); 1287018cebfbSflorian if (buf == NULL) 1288018cebfbSflorian fatal("malloc"); 1289018cebfbSflorian } 1290018cebfbSflorian rtm = (struct rt_msghdr *)buf; 1291018cebfbSflorian if ((n = read(fd, buf, ROUTE_SOCKET_BUF_SIZE)) == -1) { 1292018cebfbSflorian if (errno == EAGAIN || errno == EINTR) 1293018cebfbSflorian return; 1294018cebfbSflorian log_warn("dispatch_rtmsg: read error"); 1295018cebfbSflorian return; 1296018cebfbSflorian } 1297018cebfbSflorian 1298018cebfbSflorian if (n == 0) 1299018cebfbSflorian fatal("routing socket closed"); 1300018cebfbSflorian 1301018cebfbSflorian if (n < (ssize_t)sizeof(rtm->rtm_msglen) || n < rtm->rtm_msglen) { 1302018cebfbSflorian log_warnx("partial rtm of %zd in buffer", n); 1303018cebfbSflorian return; 1304018cebfbSflorian } 1305018cebfbSflorian 1306018cebfbSflorian if (rtm->rtm_version != RTM_VERSION) 1307018cebfbSflorian return; 1308018cebfbSflorian 1309018cebfbSflorian sa = (struct sockaddr *)(buf + rtm->rtm_hdrlen); 1310018cebfbSflorian get_rtaddrs(rtm->rtm_addrs, sa, rti_info); 1311018cebfbSflorian 1312018cebfbSflorian handle_route_message(rtm, rti_info); 1313018cebfbSflorian } 1314018cebfbSflorian 1315018cebfbSflorian #define ROUNDUP(a) \ 1316018cebfbSflorian ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 1317018cebfbSflorian 1318018cebfbSflorian void 1319018cebfbSflorian get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) 1320018cebfbSflorian { 1321018cebfbSflorian int i; 1322018cebfbSflorian 1323018cebfbSflorian for (i = 0; i < RTAX_MAX; i++) { 1324018cebfbSflorian if (addrs & (1 << i)) { 1325018cebfbSflorian rti_info[i] = sa; 1326018cebfbSflorian sa = (struct sockaddr *)((char *)(sa) + 1327018cebfbSflorian ROUNDUP(sa->sa_len)); 1328018cebfbSflorian } else 1329018cebfbSflorian rti_info[i] = NULL; 1330018cebfbSflorian } 1331018cebfbSflorian } 1332018cebfbSflorian 1333018cebfbSflorian void 1334018cebfbSflorian handle_route_message(struct rt_msghdr *rtm, struct sockaddr **rti_info) 1335018cebfbSflorian { 133628ba4729Sflorian struct imsg_rdns_proposal rdns_proposal; 133728ba4729Sflorian struct sockaddr_rtdns *rtdns; 133885384332Sflorian struct if_announcemsghdr *ifan; 1339018cebfbSflorian 1340018cebfbSflorian switch (rtm->rtm_type) { 134185384332Sflorian case RTM_IFANNOUNCE: 134285384332Sflorian ifan = (struct if_announcemsghdr *)rtm; 134385384332Sflorian if (ifan->ifan_what == IFAN_ARRIVAL) 134485384332Sflorian break; 134585384332Sflorian rdns_proposal.if_index = ifan->ifan_index; 134685384332Sflorian rdns_proposal.src = 0; 134785384332Sflorian rdns_proposal.rtdns.sr_family = AF_INET; 134885384332Sflorian rdns_proposal.rtdns.sr_len = offsetof(struct sockaddr_rtdns, 134985384332Sflorian sr_dns); 135085384332Sflorian frontend_imsg_compose_resolver(IMSG_REPLACE_DNS, 0, 135185384332Sflorian &rdns_proposal, sizeof(rdns_proposal)); 135285384332Sflorian break; 13537e9ae0c5Sflorian case RTM_IFINFO: 1354dcacc294Sflorian frontend_imsg_compose_resolver(IMSG_NETWORK_CHANGED, 0, NULL, 13557e9ae0c5Sflorian 0); 13567e9ae0c5Sflorian break; 135728ba4729Sflorian case RTM_PROPOSAL: 135828ba4729Sflorian if (!(rtm->rtm_addrs & RTA_DNS)) 135928ba4729Sflorian break; 136028ba4729Sflorian 136128ba4729Sflorian rtdns = (struct sockaddr_rtdns*)rti_info[RTAX_DNS]; 136228ba4729Sflorian rdns_proposal.if_index = rtm->rtm_index; 136312811ba0Sflorian rdns_proposal.src = rtm->rtm_priority; 136428ba4729Sflorian memcpy(&rdns_proposal.rtdns, rtdns, sizeof(rdns_proposal.rtdns)); 1365906bb1caSflorian frontend_imsg_compose_resolver(IMSG_REPLACE_DNS, 0, 136628ba4729Sflorian &rdns_proposal, sizeof(rdns_proposal)); 136728ba4729Sflorian break; 13685dca88ceSflorian case RTM_NEWADDR: 13695dca88ceSflorian case RTM_DELADDR: 13705dca88ceSflorian case RTM_DESYNC: 13715dca88ceSflorian check_available_af(); 13725dca88ceSflorian break; 1373018cebfbSflorian default: 1374018cebfbSflorian break; 1375018cebfbSflorian } 1376018cebfbSflorian } 1377018cebfbSflorian 1378018cebfbSflorian void 1379296cf316Sflorian add_new_ta(struct trust_anchor_head *tah, char *val) 1380296cf316Sflorian { 1381296cf316Sflorian struct trust_anchor *ta, *i; 1382296cf316Sflorian int cmp; 1383296cf316Sflorian 1384296cf316Sflorian if ((ta = malloc(sizeof(*ta))) == NULL) 1385296cf316Sflorian fatal("%s", __func__); 1386296cf316Sflorian if ((ta->ta = strdup(val)) == NULL) 1387296cf316Sflorian fatal("%s", __func__); 1388296cf316Sflorian 1389296cf316Sflorian /* keep the list sorted to prevent churn if the order changes in DNS */ 1390296cf316Sflorian TAILQ_FOREACH(i, tah, entry) { 1391296cf316Sflorian cmp = strcmp(i->ta, ta->ta); 1392296cf316Sflorian if ( cmp == 0) { 1393296cf316Sflorian /* duplicate */ 1394296cf316Sflorian free(ta->ta); 1395296cf316Sflorian free(ta); 1396296cf316Sflorian return; 1397296cf316Sflorian } else if (cmp > 0) { 1398296cf316Sflorian TAILQ_INSERT_BEFORE(i, ta, entry); 1399296cf316Sflorian return; 1400296cf316Sflorian } 1401296cf316Sflorian } 1402296cf316Sflorian TAILQ_INSERT_TAIL(tah, ta, entry); 1403296cf316Sflorian } 1404296cf316Sflorian 1405296cf316Sflorian void 1406296cf316Sflorian free_tas(struct trust_anchor_head *tah) 1407296cf316Sflorian { 1408296cf316Sflorian struct trust_anchor *ta; 1409296cf316Sflorian 1410296cf316Sflorian while ((ta = TAILQ_FIRST(tah))) { 1411296cf316Sflorian TAILQ_REMOVE(tah, ta, entry); 1412296cf316Sflorian free(ta->ta); 1413296cf316Sflorian free(ta); 1414296cf316Sflorian } 1415296cf316Sflorian } 1416296cf316Sflorian 1417296cf316Sflorian int 1418296cf316Sflorian merge_tas(struct trust_anchor_head *newh, struct trust_anchor_head *oldh) 1419296cf316Sflorian { 1420296cf316Sflorian struct trust_anchor *i, *j; 1421296cf316Sflorian int chg = 0; 1422296cf316Sflorian 1423296cf316Sflorian j = TAILQ_FIRST(oldh); 1424296cf316Sflorian 1425296cf316Sflorian TAILQ_FOREACH(i, newh, entry) { 1426296cf316Sflorian if (j == NULL || strcmp(i->ta, j->ta) != 0) { 1427296cf316Sflorian chg = 1; 1428296cf316Sflorian break; 1429296cf316Sflorian } 1430296cf316Sflorian j = TAILQ_NEXT(j, entry); 1431296cf316Sflorian } 1432296cf316Sflorian if (j != NULL) 1433296cf316Sflorian chg = 1; 1434296cf316Sflorian 1435296cf316Sflorian if (chg) { 1436296cf316Sflorian free_tas(oldh); 143794a469e3Sbket TAILQ_CONCAT(oldh, newh, entry); 1438296cf316Sflorian } else { 1439296cf316Sflorian free_tas(newh); 1440296cf316Sflorian } 1441296cf316Sflorian return (chg); 1442296cf316Sflorian } 1443296cf316Sflorian 1444296cf316Sflorian void 1445296cf316Sflorian parse_trust_anchor(struct trust_anchor_head *tah, int fd) 1446296cf316Sflorian { 1447d1b04a40Sflorian size_t len, dname_len; 1448d1b04a40Sflorian ssize_t n, sz; 1449d1b04a40Sflorian uint8_t rr[LDNS_RR_BUF_SIZE]; 1450d1b04a40Sflorian char *str, *p, buf[512], *line; 1451296cf316Sflorian 1452d1b04a40Sflorian sz = 0; 1453d1b04a40Sflorian str = NULL; 1454d1b04a40Sflorian 1455d1b04a40Sflorian while ((n = read(fd, buf, sizeof(buf))) > 0) { 1456d1b04a40Sflorian p = recallocarray(str, sz, sz + n, 1); 1457d1b04a40Sflorian if (p == NULL) { 1458d1b04a40Sflorian log_warn("%s", __func__); 1459d1b04a40Sflorian goto out; 1460d1b04a40Sflorian } 1461d1b04a40Sflorian str = p; 1462d1b04a40Sflorian memcpy(str + sz, buf, n); 1463d1b04a40Sflorian sz += n; 1464296cf316Sflorian } 1465296cf316Sflorian 1466d1b04a40Sflorian if (n == -1) { 1467d1b04a40Sflorian log_warn("%s", __func__); 1468d1b04a40Sflorian goto out; 1469d1b04a40Sflorian } 1470d1b04a40Sflorian 1471d1b04a40Sflorian /* make it a string */ 1472d1b04a40Sflorian p = recallocarray(str, sz, sz + 1, 1); 1473d1b04a40Sflorian if (p == NULL) { 1474d1b04a40Sflorian log_warn("%s", __func__); 1475d1b04a40Sflorian goto out; 1476d1b04a40Sflorian } 1477d1b04a40Sflorian str = p; 1478d1b04a40Sflorian sz++; 1479d1b04a40Sflorian 1480d1b04a40Sflorian len = sizeof(rr); 1481d1b04a40Sflorian 1482f8e69f6bSotto while ((line = strsep(&p, "\n")) != NULL) { 1483d1b04a40Sflorian if (sldns_str2wire_rr_buf(line, rr, &len, &dname_len, 14846cee0ce8Sflorian ROOT_DNSKEY_TTL, NULL, 0, NULL, 0) != 0) 1485296cf316Sflorian continue; 1486d1b04a40Sflorian if (sldns_wirerr_get_type(rr, len, dname_len) == 1487d1b04a40Sflorian LDNS_RR_TYPE_DNSKEY) 1488296cf316Sflorian add_new_ta(tah, line); 1489296cf316Sflorian } 1490d1b04a40Sflorian 1491d1b04a40Sflorian out: 1492d1b04a40Sflorian free(str); 1493d1b04a40Sflorian return; 1494296cf316Sflorian } 1495296cf316Sflorian 1496296cf316Sflorian void 1497296cf316Sflorian send_trust_anchors(struct trust_anchor_head *tah) 1498296cf316Sflorian { 1499296cf316Sflorian struct trust_anchor *ta; 1500296cf316Sflorian 1501296cf316Sflorian TAILQ_FOREACH(ta, tah, entry) 1502296cf316Sflorian frontend_imsg_compose_resolver(IMSG_NEW_TA, 0, ta->ta, 1503296cf316Sflorian strlen(ta->ta) + 1); 1504296cf316Sflorian frontend_imsg_compose_resolver(IMSG_NEW_TAS_DONE, 0, NULL, 0); 1505296cf316Sflorian } 1506296cf316Sflorian 1507296cf316Sflorian void 1508296cf316Sflorian write_trust_anchors(struct trust_anchor_head *tah, int fd) 1509296cf316Sflorian { 1510296cf316Sflorian struct trust_anchor *ta; 1511d1b04a40Sflorian size_t len = 0; 1512d1b04a40Sflorian ssize_t n; 1513d1b04a40Sflorian char *str; 1514296cf316Sflorian 1515d1b04a40Sflorian if (lseek(fd, 0, SEEK_SET) == -1) { 1516296cf316Sflorian log_warn("%s", __func__); 1517d1b04a40Sflorian goto out; 1518296cf316Sflorian } 1519296cf316Sflorian 1520d1b04a40Sflorian TAILQ_FOREACH(ta, tah, entry) { 1521d1b04a40Sflorian if ((n = asprintf(&str, "%s\n", ta->ta)) == -1) { 1522d1b04a40Sflorian log_warn("%s", __func__); 1523d1b04a40Sflorian len = 0; 1524d1b04a40Sflorian goto out; 1525d1b04a40Sflorian } 1526d1b04a40Sflorian len += n; 1527d1b04a40Sflorian if (write(fd, str, n) != n) { 1528d1b04a40Sflorian log_warn("%s", __func__); 1529d1b04a40Sflorian free(str); 1530d1b04a40Sflorian len = 0; 1531d1b04a40Sflorian goto out; 1532d1b04a40Sflorian } 1533d1b04a40Sflorian free(str); 1534d1b04a40Sflorian } 1535d1b04a40Sflorian out: 1536d1b04a40Sflorian ftruncate(fd, len); 1537d1b04a40Sflorian fsync(fd); 1538296cf316Sflorian } 15392d988276Sflorian 15402d988276Sflorian void 15412d988276Sflorian parse_blocklist(int fd) 15422d988276Sflorian { 15432d988276Sflorian FILE *f; 15442d988276Sflorian struct bl_node *bl_node; 15452d988276Sflorian char *line = NULL; 15462d988276Sflorian size_t linesize = 0; 15472d988276Sflorian ssize_t linelen; 15482d988276Sflorian 15492d988276Sflorian if((f = fdopen(fd, "r")) == NULL) { 15502d988276Sflorian log_warn("cannot read block list"); 15512d988276Sflorian close(fd); 15522d988276Sflorian return; 15532d988276Sflorian } 15542d988276Sflorian 15552d988276Sflorian free_bl(); 15562d988276Sflorian 15572d988276Sflorian while ((linelen = getline(&line, &linesize, f)) != -1) { 15582d988276Sflorian if (line[linelen - 1] == '\n') { 15592d988276Sflorian if (linelen >= 2 && line[linelen - 2] != '.') 15602d988276Sflorian line[linelen - 1] = '.'; 15612d988276Sflorian else 1562*a95f0396Skirill line[linelen-- - 1] = '\0'; 15632d988276Sflorian } 15642d988276Sflorian 1565*a95f0396Skirill if (line[0] == '#') 1566*a95f0396Skirill continue; 1567*a95f0396Skirill 15682d988276Sflorian bl_node = malloc(sizeof *bl_node); 15692d988276Sflorian if (bl_node == NULL) 15702d988276Sflorian fatal("%s: malloc", __func__); 15712d988276Sflorian if ((bl_node->domain = strdup(line)) == NULL) 15722d988276Sflorian fatal("%s: strdup", __func__); 1573*a95f0396Skirill reverse(bl_node->domain, bl_node->domain + linelen); 1574*a95f0396Skirill bl_node->len = linelen; 1575*a95f0396Skirill bl_node->wildcard = line[0] == '.'; 1576dbebd753Stb if (RB_INSERT(bl_tree, &bl_head, bl_node) != NULL) { 1577dbebd753Stb log_warnx("duplicate blocked domain \"%s\"", line); 1578dbebd753Stb free(bl_node->domain); 1579dbebd753Stb free(bl_node); 1580dbebd753Stb } 15812d988276Sflorian } 15822d988276Sflorian free(line); 15832d988276Sflorian if (ferror(f)) 15842d988276Sflorian log_warn("getline"); 15852d988276Sflorian fclose(f); 15862d988276Sflorian } 15872d988276Sflorian 15882d988276Sflorian int 15892d988276Sflorian bl_cmp(struct bl_node *e1, struct bl_node *e2) { 1590*a95f0396Skirill if (e1->wildcard == e2->wildcard) 15912d988276Sflorian return (strcasecmp(e1->domain, e2->domain)); 1592*a95f0396Skirill else if (e1->wildcard) 1593*a95f0396Skirill return (strncasecmp(e1->domain, e2->domain, e1->len)); 1594*a95f0396Skirill else /* e2->wildcard */ 1595*a95f0396Skirill return (strncasecmp(e1->domain, e2->domain, e2->len)); 15962d988276Sflorian } 15972d988276Sflorian 15982d988276Sflorian void 15992d988276Sflorian free_bl(void) 16002d988276Sflorian { 16012d988276Sflorian struct bl_node *n, *nxt; 16022d988276Sflorian 16033bcff273Stb RB_FOREACH_SAFE(n, bl_tree, &bl_head, nxt) { 16042d988276Sflorian RB_REMOVE(bl_tree, &bl_head, n); 1605cb873a5fStb free(n->domain); 16062d988276Sflorian free(n); 16072d988276Sflorian } 16082d988276Sflorian } 1609b5001ac5Sotto 1610b5001ac5Sotto int 1611b5001ac5Sotto pending_query_cnt(void) 1612b5001ac5Sotto { 1613b5001ac5Sotto struct pending_query *e; 1614b5001ac5Sotto int cnt = 0; 1615b5001ac5Sotto 1616b5001ac5Sotto TAILQ_FOREACH(e, &pending_queries, entry) 1617b5001ac5Sotto cnt++; 1618b5001ac5Sotto return cnt; 1619b5001ac5Sotto } 1620297af7e1Sflorian 1621297af7e1Sflorian void 1622297af7e1Sflorian accept_paused(int fd, short events, void *arg) 1623297af7e1Sflorian { 1624297af7e1Sflorian struct tcp_accept_ev *tcpev = arg; 1625297af7e1Sflorian event_add(&tcpev->ev, NULL); 1626297af7e1Sflorian } 1627297af7e1Sflorian 1628297af7e1Sflorian int 1629297af7e1Sflorian accept_reserve(int sockfd, struct sockaddr *addr, socklen_t *addrlen) 1630297af7e1Sflorian { 1631297af7e1Sflorian if (getdtablecount() + FD_RESERVE >= getdtablesize()) { 1632297af7e1Sflorian log_debug("%s: inflight fds exceeded", __func__); 1633297af7e1Sflorian errno = EMFILE; 1634297af7e1Sflorian return -1; 1635297af7e1Sflorian } 1636297af7e1Sflorian return accept4(sockfd, addr, addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC); 1637297af7e1Sflorian } 1638297af7e1Sflorian 1639297af7e1Sflorian void 1640297af7e1Sflorian tcp_accept(int fd, short events, void *arg) 1641297af7e1Sflorian { 1642297af7e1Sflorian static struct timeval timeout = {TCP_TIMEOUT, 0}; 1643297af7e1Sflorian static struct timeval backoff = {1, 0}; 1644297af7e1Sflorian struct pending_query *pq; 1645297af7e1Sflorian struct tcp_accept_ev *tcpev; 1646297af7e1Sflorian struct sockaddr_storage ss; 1647297af7e1Sflorian socklen_t len; 1648297af7e1Sflorian int s; 1649297af7e1Sflorian 1650297af7e1Sflorian tcpev = arg; 1651297af7e1Sflorian len = sizeof(ss); 1652297af7e1Sflorian 1653297af7e1Sflorian if ((s = accept_reserve(fd, (struct sockaddr *)&ss, &len)) == -1) { 1654297af7e1Sflorian switch (errno) { 1655297af7e1Sflorian case EINTR: 1656297af7e1Sflorian case EWOULDBLOCK: 1657297af7e1Sflorian case ECONNABORTED: 1658297af7e1Sflorian return; 1659297af7e1Sflorian case EMFILE: 1660297af7e1Sflorian case ENFILE: 1661297af7e1Sflorian event_del(&tcpev->ev); 1662297af7e1Sflorian evtimer_add(&tcpev->pause, &backoff); 1663297af7e1Sflorian return; 1664297af7e1Sflorian default: 1665297af7e1Sflorian fatal("accept"); 1666297af7e1Sflorian } 1667297af7e1Sflorian } 1668297af7e1Sflorian 1669297af7e1Sflorian if ((pq = calloc(1, sizeof(*pq))) == NULL) { 1670297af7e1Sflorian log_warn(NULL); 1671297af7e1Sflorian close(s); 1672297af7e1Sflorian return; 1673297af7e1Sflorian } 1674297af7e1Sflorian 1675297af7e1Sflorian do { 1676297af7e1Sflorian arc4random_buf(&pq->imsg_id, sizeof(pq->imsg_id)); 1677297af7e1Sflorian } while(find_pending_query(pq->imsg_id) != NULL); 1678297af7e1Sflorian 1679297af7e1Sflorian TAILQ_INSERT_TAIL(&pending_queries, pq, entry); 1680297af7e1Sflorian 1681297af7e1Sflorian pq->from = ss; 1682297af7e1Sflorian pq->fd = s; 1683297af7e1Sflorian pq->tcp = 1; 1684297af7e1Sflorian pq->qbuf = sldns_buffer_new(DEFAULT_TCP_SIZE); 1685297af7e1Sflorian pq->region = regional_create(); 1686297af7e1Sflorian 1687dbf56da7Sflorian if (!pq->qbuf || !pq->region) { 1688297af7e1Sflorian free_pending_query(pq); 1689297af7e1Sflorian return; 1690297af7e1Sflorian } 1691297af7e1Sflorian 1692297af7e1Sflorian event_set(&pq->ev, s, EV_READ | EV_PERSIST, tcp_request, pq); 1693297af7e1Sflorian event_add(&pq->ev, NULL); 1694297af7e1Sflorian event_set(&pq->resp_ev, s, EV_WRITE | EV_PERSIST, tcp_response, pq); 1695297af7e1Sflorian 1696297af7e1Sflorian evtimer_set(&pq->tmo_ev, tcp_timeout, pq); 1697297af7e1Sflorian evtimer_add(&pq->tmo_ev, &timeout); 1698297af7e1Sflorian } 1699297af7e1Sflorian 1700297af7e1Sflorian void 1701297af7e1Sflorian tcp_request(int fd, short events, void *arg) 1702297af7e1Sflorian { 1703297af7e1Sflorian struct pending_query *pq; 1704297af7e1Sflorian ssize_t n; 1705297af7e1Sflorian 1706297af7e1Sflorian pq = arg; 1707297af7e1Sflorian 1708297af7e1Sflorian n = read(fd, sldns_buffer_current(pq->qbuf), 1709297af7e1Sflorian sldns_buffer_remaining(pq->qbuf)); 1710297af7e1Sflorian 1711297af7e1Sflorian switch (n) { 1712297af7e1Sflorian case -1: 1713297af7e1Sflorian switch (errno) { 1714297af7e1Sflorian case EINTR: 1715297af7e1Sflorian case EAGAIN: 1716297af7e1Sflorian return; 1717297af7e1Sflorian default: 1718297af7e1Sflorian goto fail; 1719297af7e1Sflorian } 1720297af7e1Sflorian break; 1721297af7e1Sflorian case 0: 1722297af7e1Sflorian log_debug("closed connection"); 1723297af7e1Sflorian goto fail; 1724297af7e1Sflorian default: 1725297af7e1Sflorian break; 1726297af7e1Sflorian } 1727297af7e1Sflorian 1728297af7e1Sflorian sldns_buffer_skip(pq->qbuf, n); 1729297af7e1Sflorian 1730297af7e1Sflorian if (sldns_buffer_position(pq->qbuf) >= 2 && !pq->abuf) { 1731297af7e1Sflorian struct sldns_buffer *tmp; 173269f07918Sbluhm size_t rem; 1733297af7e1Sflorian uint16_t len; 1734297af7e1Sflorian 1735297af7e1Sflorian sldns_buffer_flip(pq->qbuf); 1736297af7e1Sflorian len = sldns_buffer_read_u16(pq->qbuf); 1737297af7e1Sflorian tmp = sldns_buffer_new(len); 1738b9be5719Stb if (tmp == NULL) 1739297af7e1Sflorian goto fail; 1740b9be5719Stb pq->abuf = sldns_buffer_new(len); 1741b9be5719Stb if (pq->abuf == NULL) { 1742b9be5719Stb sldns_buffer_free(tmp); 1743b9be5719Stb goto fail; 1744b9be5719Stb } 1745297af7e1Sflorian 174669f07918Sbluhm rem = sldns_buffer_remaining(pq->qbuf); 1747297af7e1Sflorian sldns_buffer_write(tmp, sldns_buffer_current(pq->qbuf), 174869f07918Sbluhm MINIMUM(len, rem)); 1749297af7e1Sflorian sldns_buffer_free(pq->qbuf); 1750297af7e1Sflorian pq->qbuf = tmp; 1751297af7e1Sflorian } 1752297af7e1Sflorian if (sldns_buffer_remaining(pq->qbuf) == 0) { 1753297af7e1Sflorian sldns_buffer_flip(pq->qbuf); 1754297af7e1Sflorian shutdown(fd, SHUT_RD); 1755297af7e1Sflorian event_del(&pq->ev); 1756297af7e1Sflorian handle_query(pq); 1757297af7e1Sflorian } 1758297af7e1Sflorian return; 1759297af7e1Sflorian fail: 1760297af7e1Sflorian free_pending_query(pq); 1761297af7e1Sflorian } 1762297af7e1Sflorian 1763297af7e1Sflorian void 1764297af7e1Sflorian tcp_response(int fd, short events, void *arg) 1765297af7e1Sflorian { 1766297af7e1Sflorian struct pending_query *pq; 1767297af7e1Sflorian ssize_t n; 1768297af7e1Sflorian 1769297af7e1Sflorian pq = arg; 1770297af7e1Sflorian 1771297af7e1Sflorian n = write(fd, sldns_buffer_current(pq->abuf), 1772297af7e1Sflorian sldns_buffer_remaining(pq->abuf)); 1773297af7e1Sflorian 1774297af7e1Sflorian if (n == -1) { 1775297af7e1Sflorian if (errno == EAGAIN || errno == EINTR) 1776297af7e1Sflorian return; 1777297af7e1Sflorian free_pending_query(pq); 1778cc695705Sjsg return; 1779297af7e1Sflorian } 1780297af7e1Sflorian sldns_buffer_skip(pq->abuf, n); 1781297af7e1Sflorian if (sldns_buffer_remaining(pq->abuf) == 0) 1782297af7e1Sflorian free_pending_query(pq); 1783297af7e1Sflorian } 1784297af7e1Sflorian 1785297af7e1Sflorian void 1786297af7e1Sflorian tcp_timeout(int fd, short events, void *arg) 1787297af7e1Sflorian { 1788297af7e1Sflorian free_pending_query(arg); 1789297af7e1Sflorian } 17905dca88ceSflorian 17915dca88ceSflorian void 1792c16f5ec7Stb check_available_af(void) 17935dca88ceSflorian { 17945dca88ceSflorian static int available_af = HAVE_IPV4 | HAVE_IPV6; 17955dca88ceSflorian static int rtable = -1; 17965dca88ceSflorian struct ifaddrs *ifap, *ifa; 17975dca88ceSflorian struct if_data *ifa_data; 17985dca88ceSflorian struct sockaddr_in *sin4; 17995dca88ceSflorian struct sockaddr_in6 *sin6; 18005dca88ceSflorian int new_available_af = 0, ifa_rtable = -1; 18015dca88ceSflorian 18025dca88ceSflorian if (rtable == -1) 18035dca88ceSflorian rtable = getrtable(); 18045dca88ceSflorian 18055dca88ceSflorian if (getifaddrs(&ifap) != 0) { 18065dca88ceSflorian log_warn("getifaddrs"); 18075dca88ceSflorian return; 18085dca88ceSflorian } 18095dca88ceSflorian 18105dca88ceSflorian for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { 18115dca88ceSflorian if (ifa->ifa_addr == NULL) 18125dca88ceSflorian continue; 18135dca88ceSflorian switch(ifa->ifa_addr->sa_family) { 18145dca88ceSflorian case AF_LINK: 18155dca88ceSflorian /* AF_LINK comes before inet / inet6 on an interface */ 18165dca88ceSflorian ifa_data = (struct if_data *)ifa->ifa_data; 18175dca88ceSflorian ifa_rtable = ifa_data->ifi_rdomain; 18185dca88ceSflorian break; 18195dca88ceSflorian case AF_INET: 18205dca88ceSflorian if (ifa_rtable != rtable) 18215dca88ceSflorian continue; 18225dca88ceSflorian 18235dca88ceSflorian sin4 = (struct sockaddr_in *)ifa->ifa_addr; 18245dca88ceSflorian if ((ntohl(sin4->sin_addr.s_addr) >> 24) == 18255dca88ceSflorian IN_LOOPBACKNET) 18265dca88ceSflorian continue; 18275dca88ceSflorian new_available_af |= HAVE_IPV4; 18285dca88ceSflorian break; 18295dca88ceSflorian case AF_INET6: 18305dca88ceSflorian if (ifa_rtable != rtable) 18315dca88ceSflorian continue; 18325dca88ceSflorian 18335dca88ceSflorian sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; 18345dca88ceSflorian if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr) || 18355dca88ceSflorian IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) || 18365dca88ceSflorian IN6_IS_ADDR_MC_LINKLOCAL(&sin6->sin6_addr) || 18375dca88ceSflorian IN6_IS_ADDR_MC_INTFACELOCAL(&sin6->sin6_addr)) 18385dca88ceSflorian continue; 18395dca88ceSflorian new_available_af |= HAVE_IPV6; 18405dca88ceSflorian break; 18415dca88ceSflorian default: 18425dca88ceSflorian break; 18435dca88ceSflorian } 18445dca88ceSflorian if (new_available_af == (HAVE_IPV4 | HAVE_IPV6)) 18455dca88ceSflorian break; 18465dca88ceSflorian } 18475dca88ceSflorian freeifaddrs(ifap); 18485dca88ceSflorian if (new_available_af != available_af) { 18495dca88ceSflorian available_af = new_available_af; 18505dca88ceSflorian frontend_imsg_compose_resolver(IMSG_CHANGE_AFS, 0, 18515dca88ceSflorian &available_af, sizeof(available_af)); 18525dca88ceSflorian } 18535dca88ceSflorian } 1854*a95f0396Skirill 1855*a95f0396Skirill void 1856*a95f0396Skirill reverse(char *begin, char *end) 1857*a95f0396Skirill { 1858*a95f0396Skirill char t; 1859*a95f0396Skirill 1860*a95f0396Skirill while (begin < --end) { 1861*a95f0396Skirill t = *begin; 1862*a95f0396Skirill *begin = *end; 1863*a95f0396Skirill *end = t; 1864*a95f0396Skirill ++begin; 1865*a95f0396Skirill } 1866*a95f0396Skirill } 1867