1/* 2 * services/listen_dnsport.c - listen on port 53 for incoming DNS queries. 3 * 4 * Copyright (c) 2007, NLnet Labs. All rights reserved. 5 * 6 * This software is open source. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * Redistributions of source code must retain the above copyright notice, 13 * this list of conditions and the following disclaimer. 14 * 15 * Redistributions in binary form must reproduce the above copyright notice, 16 * this list of conditions and the following disclaimer in the documentation 17 * and/or other materials provided with the distribution. 18 * 19 * Neither the name of the NLNET LABS nor the names of its contributors may 20 * be used to endorse or promote products derived from this software without 21 * specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 25 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE 27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 * POSSIBILITY OF SUCH DAMAGE. 34 */ 35 36/** 37 * \file 38 * 39 * This file has functions to get queries from clients. 40 */ 41#include "config.h" 42#ifdef HAVE_SYS_TYPES_H 43# include <sys/types.h> 44#endif 45#include <sys/time.h> 46#include "services/listen_dnsport.h" 47#include "services/outside_network.h" 48#include "util/netevent.h" 49#include "util/log.h" 50#include "util/config_file.h" 51#include "util/net_help.h" 52 53#ifdef HAVE_NETDB_H 54#include <netdb.h> 55#endif 56#include <fcntl.h> 57 58/** number of queued TCP connections for listen() */ 59#define TCP_BACKLOG 5 60 61/** 62 * Debug print of the getaddrinfo returned address. 63 * @param addr: the address returned. 64 */ 65static void 66verbose_print_addr(struct addrinfo *addr) 67{ 68 if(verbosity >= VERB_ALGO) { 69 char buf[100]; 70 void* sinaddr = &((struct sockaddr_in*)addr->ai_addr)->sin_addr; 71#ifdef INET6 72 if(addr->ai_family == AF_INET6) 73 sinaddr = &((struct sockaddr_in6*)addr->ai_addr)-> 74 sin6_addr; 75#endif /* INET6 */ 76 if(inet_ntop(addr->ai_family, sinaddr, buf, 77 (socklen_t)sizeof(buf)) == 0) { 78 strncpy(buf, "(null)", sizeof(buf)); 79 } 80 buf[sizeof(buf)-1] = 0; 81 verbose(VERB_ALGO, "creating %s%s socket %s %d", 82 addr->ai_socktype==SOCK_DGRAM?"udp": 83 addr->ai_socktype==SOCK_STREAM?"tcp":"otherproto", 84 addr->ai_family==AF_INET?"4": 85 addr->ai_family==AF_INET6?"6": 86 "_otherfam", buf, 87 ntohs(((struct sockaddr_in*)addr->ai_addr)->sin_port)); 88 } 89} 90 91int 92create_udp_sock(int family, int socktype, struct sockaddr* addr, 93 socklen_t addrlen, int v6only, int* inuse, int* noproto, 94 int rcv, int snd) 95{ 96 int s; 97#if defined(IPV6_USE_MIN_MTU) 98 int on=1; 99#endif 100#ifdef IPV6_MTU 101 int mtu = IPV6_MIN_MTU; 102#endif 103#if !defined(SO_RCVBUFFORCE) && !defined(SO_RCVBUF) 104 (void)rcv; 105#endif 106#if !defined(SO_SNDBUFFORCE) && !defined(SO_SNDBUF) 107 (void)snd; 108#endif 109#ifndef IPV6_V6ONLY 110 (void)v6only; 111#endif 112 if((s = socket(family, socktype, 0)) == -1) { 113 *inuse = 0; 114#ifndef USE_WINSOCK 115 if(errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT) { 116 *noproto = 1; 117 return -1; 118 } 119 log_err("can't create socket: %s", strerror(errno)); 120#else 121 if(WSAGetLastError() == WSAEAFNOSUPPORT || 122 WSAGetLastError() == WSAEPROTONOSUPPORT) { 123 *noproto = 1; 124 return -1; 125 } 126 log_err("can't create socket: %s", 127 wsa_strerror(WSAGetLastError())); 128#endif 129 *noproto = 0; 130 return -1; 131 } 132 if(rcv) { 133#ifdef SO_RCVBUF 134 int got; 135 socklen_t slen = (socklen_t)sizeof(got); 136# ifdef SO_RCVBUFFORCE 137 /* Linux specific: try to use root permission to override 138 * system limits on rcvbuf. The limit is stored in 139 * /proc/sys/net/core/rmem_max or sysctl net.core.rmem_max */ 140 if(setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, (void*)&rcv, 141 (socklen_t)sizeof(rcv)) < 0) { 142 if(errno != EPERM) { 143# ifndef USE_WINSOCK 144 log_err("setsockopt(..., SO_RCVBUFFORCE, " 145 "...) failed: %s", strerror(errno)); 146 close(s); 147# else 148 log_err("setsockopt(..., SO_RCVBUFFORCE, " 149 "...) failed: %s", 150 wsa_strerror(WSAGetLastError())); 151 closesocket(s); 152# endif 153 *noproto = 0; 154 *inuse = 0; 155 return -1; 156 } 157# endif /* SO_RCVBUFFORCE */ 158 if(setsockopt(s, SOL_SOCKET, SO_RCVBUF, (void*)&rcv, 159 (socklen_t)sizeof(rcv)) < 0) { 160# ifndef USE_WINSOCK 161 log_err("setsockopt(..., SO_RCVBUF, " 162 "...) failed: %s", strerror(errno)); 163 close(s); 164# else 165 log_err("setsockopt(..., SO_RCVBUF, " 166 "...) failed: %s", 167 wsa_strerror(WSAGetLastError())); 168 closesocket(s); 169# endif 170 *noproto = 0; 171 *inuse = 0; 172 return -1; 173 } 174 /* check if we got the right thing or if system 175 * reduced to some system max. Warn if so */ 176 if(getsockopt(s, SOL_SOCKET, SO_RCVBUF, (void*)&got, 177 &slen) >= 0 && got < rcv/2) { 178 log_warn("so-rcvbuf %u was not granted. " 179 "Got %u. To fix: start with " 180 "root permissions(linux) or sysctl " 181 "bigger net.core.rmem_max(linux) or " 182 "kern.ipc.maxsockbuf(bsd) values.", 183 (unsigned)rcv, (unsigned)got); 184 } 185# ifdef SO_RCVBUFFORCE 186 } 187# endif 188#endif /* SO_RCVBUF */ 189 } 190 /* first do RCVBUF as the receive buffer is more important */ 191 if(snd) { 192#ifdef SO_SNDBUF 193 int got; 194 socklen_t slen = (socklen_t)sizeof(got); 195# ifdef SO_SNDBUFFORCE 196 /* Linux specific: try to use root permission to override 197 * system limits on sndbuf. The limit is stored in 198 * /proc/sys/net/core/wmem_max or sysctl net.core.wmem_max */ 199 if(setsockopt(s, SOL_SOCKET, SO_SNDBUFFORCE, (void*)&snd, 200 (socklen_t)sizeof(snd)) < 0) { 201 if(errno != EPERM) { 202# ifndef USE_WINSOCK 203 log_err("setsockopt(..., SO_SNDBUFFORCE, " 204 "...) failed: %s", strerror(errno)); 205 close(s); 206# else 207 log_err("setsockopt(..., SO_SNDBUFFORCE, " 208 "...) failed: %s", 209 wsa_strerror(WSAGetLastError())); 210 closesocket(s); 211# endif 212 *noproto = 0; 213 *inuse = 0; 214 return -1; 215 } 216# endif /* SO_SNDBUFFORCE */ 217 if(setsockopt(s, SOL_SOCKET, SO_SNDBUF, (void*)&snd, 218 (socklen_t)sizeof(snd)) < 0) { 219# ifndef USE_WINSOCK 220 log_err("setsockopt(..., SO_SNDBUF, " 221 "...) failed: %s", strerror(errno)); 222 close(s); 223# else 224 log_err("setsockopt(..., SO_SNDBUF, " 225 "...) failed: %s", 226 wsa_strerror(WSAGetLastError())); 227 closesocket(s); 228# endif 229 *noproto = 0; 230 *inuse = 0; 231 return -1; 232 } 233 /* check if we got the right thing or if system 234 * reduced to some system max. Warn if so */ 235 if(getsockopt(s, SOL_SOCKET, SO_SNDBUF, (void*)&got, 236 &slen) >= 0 && got < snd/2) { 237 log_warn("so-sndbuf %u was not granted. " 238 "Got %u. To fix: start with " 239 "root permissions(linux) or sysctl " 240 "bigger net.core.wmem_max(linux) or " 241 "kern.ipc.maxsockbuf(bsd) values.", 242 (unsigned)snd, (unsigned)got); 243 } 244# ifdef SO_SNDBUFFORCE 245 } 246# endif 247#endif /* SO_SNDBUF */ 248 } 249 if(family == AF_INET6) { 250# if defined(IPV6_V6ONLY) 251 if(v6only) { 252 int val=(v6only==2)?0:1; 253 if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, 254 (void*)&val, (socklen_t)sizeof(val)) < 0) { 255#ifndef USE_WINSOCK 256 log_err("setsockopt(..., IPV6_V6ONLY" 257 ", ...) failed: %s", strerror(errno)); 258 close(s); 259#else 260 log_err("setsockopt(..., IPV6_V6ONLY" 261 ", ...) failed: %s", 262 wsa_strerror(WSAGetLastError())); 263 closesocket(s); 264#endif 265 *noproto = 0; 266 *inuse = 0; 267 return -1; 268 } 269 } 270# endif 271# if defined(IPV6_USE_MIN_MTU) 272 /* 273 * There is no fragmentation of IPv6 datagrams 274 * during forwarding in the network. Therefore 275 * we do not send UDP datagrams larger than 276 * the minimum IPv6 MTU of 1280 octets. The 277 * EDNS0 message length can be larger if the 278 * network stack supports IPV6_USE_MIN_MTU. 279 */ 280 if (setsockopt(s, IPPROTO_IPV6, IPV6_USE_MIN_MTU, 281 (void*)&on, (socklen_t)sizeof(on)) < 0) { 282# ifndef USE_WINSOCK 283 log_err("setsockopt(..., IPV6_USE_MIN_MTU, " 284 "...) failed: %s", strerror(errno)); 285 close(s); 286# else 287 log_err("setsockopt(..., IPV6_USE_MIN_MTU, " 288 "...) failed: %s", 289 wsa_strerror(WSAGetLastError())); 290 closesocket(s); 291# endif 292 *noproto = 0; 293 *inuse = 0; 294 return -1; 295 } 296# elif defined(IPV6_MTU) 297 /* 298 * On Linux, to send no larger than 1280, the PMTUD is 299 * disabled by default for datagrams anyway, so we set 300 * the MTU to use. 301 */ 302 if (setsockopt(s, IPPROTO_IPV6, IPV6_MTU, 303 (void*)&mtu, (socklen_t)sizeof(mtu)) < 0) { 304# ifndef USE_WINSOCK 305 log_err("setsockopt(..., IPV6_MTU, ...) failed: %s", 306 strerror(errno)); 307 close(s); 308# else 309 log_err("setsockopt(..., IPV6_MTU, ...) failed: %s", 310 wsa_strerror(WSAGetLastError())); 311 closesocket(s); 312# endif 313 *noproto = 0; 314 *inuse = 0; 315 return -1; 316 } 317# endif /* IPv6 MTU */ 318 } else if(family == AF_INET) { 319# if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT) 320 int action = IP_PMTUDISC_DONT; 321 if (setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, 322 &action, (socklen_t)sizeof(action)) < 0) { 323 log_err("setsockopt(..., IP_MTU_DISCOVER, " 324 "IP_PMTUDISC_DONT...) failed: %s", 325 strerror(errno)); 326# ifndef USE_WINSOCK 327 close(s); 328# else 329 closesocket(s); 330# endif 331 return -1; 332 } 333# elif defined(IP_DONTFRAG) 334 int off = 0; 335 if (setsockopt(s, IPPROTO_IP, IP_DONTFRAG, 336 &off, (socklen_t)sizeof(off)) < 0) { 337 log_err("setsockopt(..., IP_DONTFRAG, ...) failed: %s", 338 strerror(errno)); 339# ifndef USE_WINSOCK 340 close(s); 341# else 342 closesocket(s); 343# endif 344 return -1; 345 } 346# endif /* IPv4 MTU */ 347 } 348 if(bind(s, (struct sockaddr*)addr, addrlen) != 0) { 349 *noproto = 0; 350#ifndef USE_WINSOCK 351#ifdef EADDRINUSE 352 *inuse = (errno == EADDRINUSE); 353 /* detect freebsd jail with no ipv6 permission */ 354 if(family==AF_INET6 && errno==EINVAL) 355 *noproto = 1; 356 else if(errno != EADDRINUSE) { 357 log_err("can't bind socket: %s", strerror(errno)); 358 log_addr(0, "failed address", 359 (struct sockaddr_storage*)addr, addrlen); 360 } 361#endif /* EADDRINUSE */ 362 close(s); 363#else /* USE_WINSOCK */ 364 if(WSAGetLastError() != WSAEADDRINUSE && 365 WSAGetLastError() != WSAEADDRNOTAVAIL) { 366 log_err("can't bind socket: %s", 367 wsa_strerror(WSAGetLastError())); 368 log_addr(0, "failed address", 369 (struct sockaddr_storage*)addr, addrlen); 370 } 371 closesocket(s); 372#endif 373 return -1; 374 } 375 if(!fd_set_nonblock(s)) { 376 *noproto = 0; 377 *inuse = 0; 378#ifndef USE_WINSOCK 379 close(s); 380#else 381 closesocket(s); 382#endif 383 return -1; 384 } 385 return s; 386} 387 388int 389create_tcp_accept_sock(struct addrinfo *addr, int v6only, int* noproto) 390{ 391 int s; 392#if defined(SO_REUSEADDR) || defined(IPV6_V6ONLY) 393 int on = 1; 394#endif /* SO_REUSEADDR || IPV6_V6ONLY */ 395 verbose_print_addr(addr); 396 *noproto = 0; 397 if((s = socket(addr->ai_family, addr->ai_socktype, 0)) == -1) { 398#ifndef USE_WINSOCK 399 if(errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT) { 400 *noproto = 1; 401 return -1; 402 } 403 log_err("can't create socket: %s", strerror(errno)); 404#else 405 if(WSAGetLastError() == WSAEAFNOSUPPORT || 406 WSAGetLastError() == WSAEPROTONOSUPPORT) { 407 *noproto = 1; 408 return -1; 409 } 410 log_err("can't create socket: %s", 411 wsa_strerror(WSAGetLastError())); 412#endif 413 return -1; 414 } 415#ifdef SO_REUSEADDR 416 if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void*)&on, 417 (socklen_t)sizeof(on)) < 0) { 418#ifndef USE_WINSOCK 419 log_err("setsockopt(.. SO_REUSEADDR ..) failed: %s", 420 strerror(errno)); 421 close(s); 422#else 423 log_err("setsockopt(.. SO_REUSEADDR ..) failed: %s", 424 wsa_strerror(WSAGetLastError())); 425 closesocket(s); 426#endif 427 return -1; 428 } 429#endif /* SO_REUSEADDR */ 430#if defined(IPV6_V6ONLY) 431 if(addr->ai_family == AF_INET6 && v6only) { 432 if(setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, 433 (void*)&on, (socklen_t)sizeof(on)) < 0) { 434#ifndef USE_WINSOCK 435 log_err("setsockopt(..., IPV6_V6ONLY, ...) failed: %s", 436 strerror(errno)); 437 close(s); 438#else 439 log_err("setsockopt(..., IPV6_V6ONLY, ...) failed: %s", 440 wsa_strerror(WSAGetLastError())); 441 closesocket(s); 442#endif 443 return -1; 444 } 445 } 446#else 447 (void)v6only; 448#endif /* IPV6_V6ONLY */ 449 if(bind(s, addr->ai_addr, addr->ai_addrlen) != 0) { 450#ifndef USE_WINSOCK 451 /* detect freebsd jail with no ipv6 permission */ 452 if(addr->ai_family==AF_INET6 && errno==EINVAL) 453 *noproto = 1; 454 else { 455 log_err("can't bind socket: %s", strerror(errno)); 456 log_addr(0, "failed address", 457 (struct sockaddr_storage*)addr->ai_addr, 458 addr->ai_addrlen); 459 } 460 close(s); 461#else 462 log_err("can't bind socket: %s", 463 wsa_strerror(WSAGetLastError())); 464 log_addr(0, "failed address", 465 (struct sockaddr_storage*)addr->ai_addr, 466 addr->ai_addrlen); 467 closesocket(s); 468#endif 469 return -1; 470 } 471 if(!fd_set_nonblock(s)) { 472#ifndef USE_WINSOCK 473 close(s); 474#else 475 closesocket(s); 476#endif 477 return -1; 478 } 479 if(listen(s, TCP_BACKLOG) == -1) { 480#ifndef USE_WINSOCK 481 log_err("can't listen: %s", strerror(errno)); 482 close(s); 483#else 484 log_err("can't listen: %s", wsa_strerror(WSAGetLastError())); 485 closesocket(s); 486#endif 487 return -1; 488 } 489 return s; 490} 491 492/** 493 * Create socket from getaddrinfo results 494 */ 495static int 496make_sock(int stype, const char* ifname, const char* port, 497 struct addrinfo *hints, int v6only, int* noip6, size_t rcv, size_t snd) 498{ 499 struct addrinfo *res = NULL; 500 int r, s, inuse, noproto; 501 hints->ai_socktype = stype; 502 *noip6 = 0; 503 if((r=getaddrinfo(ifname, port, hints, &res)) != 0 || !res) { 504#ifdef USE_WINSOCK 505 if(r == EAI_NONAME && hints->ai_family == AF_INET6){ 506 *noip6 = 1; /* 'Host not found' for IP6 on winXP */ 507 return -1; 508 } 509#endif 510 log_err("node %s:%s getaddrinfo: %s %s", 511 ifname?ifname:"default", port, gai_strerror(r), 512#ifdef EAI_SYSTEM 513 r==EAI_SYSTEM?(char*)strerror(errno):"" 514#else 515 "" 516#endif 517 ); 518 return -1; 519 } 520 if(stype == SOCK_DGRAM) { 521 verbose_print_addr(res); 522 s = create_udp_sock(res->ai_family, res->ai_socktype, 523 (struct sockaddr*)res->ai_addr, res->ai_addrlen, 524 v6only, &inuse, &noproto, (int)rcv, (int)snd); 525 if(s == -1 && inuse) { 526 log_err("bind: address already in use"); 527 } else if(s == -1 && noproto && hints->ai_family == AF_INET6){ 528 *noip6 = 1; 529 } 530 } else { 531 s = create_tcp_accept_sock(res, v6only, &noproto); 532 if(s == -1 && noproto && hints->ai_family == AF_INET6){ 533 *noip6 = 1; 534 } 535 } 536 freeaddrinfo(res); 537 return s; 538} 539 540/** make socket and first see if ifname contains port override info */ 541static int 542make_sock_port(int stype, const char* ifname, const char* port, 543 struct addrinfo *hints, int v6only, int* noip6, size_t rcv, size_t snd) 544{ 545 char* s = strchr(ifname, '@'); 546 if(s) { 547 /* override port with ifspec@port */ 548 char p[16]; 549 char newif[128]; 550 if((size_t)(s-ifname) >= sizeof(newif)) { 551 log_err("ifname too long: %s", ifname); 552 *noip6 = 0; 553 return -1; 554 } 555 if(strlen(s+1) >= sizeof(p)) { 556 log_err("portnumber too long: %s", ifname); 557 *noip6 = 0; 558 return -1; 559 } 560 strncpy(newif, ifname, sizeof(newif)); 561 newif[s-ifname] = 0; 562 strncpy(p, s+1, sizeof(p)); 563 p[strlen(s+1)]=0; 564 return make_sock(stype, newif, p, hints, v6only, noip6, 565 rcv, snd); 566 } 567 return make_sock(stype, ifname, port, hints, v6only, noip6, rcv, snd); 568} 569 570/** 571 * Add port to open ports list. 572 * @param list: list head. changed. 573 * @param s: fd. 574 * @param ftype: if fd is UDP. 575 * @return false on failure. list in unchanged then. 576 */ 577static int 578port_insert(struct listen_port** list, int s, enum listen_type ftype) 579{ 580 struct listen_port* item = (struct listen_port*)malloc( 581 sizeof(struct listen_port)); 582 if(!item) 583 return 0; 584 item->next = *list; 585 item->fd = s; 586 item->ftype = ftype; 587 *list = item; 588 return 1; 589} 590 591/** set fd to receive source address packet info */ 592static int 593set_recvpktinfo(int s, int family) 594{ 595#if defined(IPV6_RECVPKTINFO) || defined(IPV6_PKTINFO) || (defined(IP_RECVDSTADDR) && defined(IP_SENDSRCADDR)) || defined(IP_PKTINFO) 596 int on = 1; 597#else 598 (void)s; 599#endif 600 if(family == AF_INET6) { 601# ifdef IPV6_RECVPKTINFO 602 if(setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, 603 (void*)&on, (socklen_t)sizeof(on)) < 0) { 604 log_err("setsockopt(..., IPV6_RECVPKTINFO, ...) failed: %s", 605 strerror(errno)); 606 return 0; 607 } 608# elif defined(IPV6_PKTINFO) 609 if(setsockopt(s, IPPROTO_IPV6, IPV6_PKTINFO, 610 (void*)&on, (socklen_t)sizeof(on)) < 0) { 611 log_err("setsockopt(..., IPV6_PKTINFO, ...) failed: %s", 612 strerror(errno)); 613 return 0; 614 } 615# else 616 log_err("no IPV6_RECVPKTINFO and no IPV6_PKTINFO option, please " 617 "disable interface-automatic in config"); 618 return 0; 619# endif /* defined IPV6_RECVPKTINFO */ 620 621 } else if(family == AF_INET) { 622# ifdef IP_PKTINFO 623 if(setsockopt(s, IPPROTO_IP, IP_PKTINFO, 624 (void*)&on, (socklen_t)sizeof(on)) < 0) { 625 log_err("setsockopt(..., IP_PKTINFO, ...) failed: %s", 626 strerror(errno)); 627 return 0; 628 } 629# elif defined(IP_RECVDSTADDR) && defined(IP_SENDSRCADDR) 630 if(setsockopt(s, IPPROTO_IP, IP_RECVDSTADDR, 631 (void*)&on, (socklen_t)sizeof(on)) < 0) { 632 log_err("setsockopt(..., IP_RECVDSTADDR, ...) failed: %s", 633 strerror(errno)); 634 return 0; 635 } 636# else 637 log_err("no IP_SENDSRCADDR or IP_PKTINFO option, please disable " 638 "interface-automatic in config"); 639 return 0; 640# endif /* IP_PKTINFO */ 641 642 } 643 return 1; 644} 645 646/** 647 * Helper for ports_open. Creates one interface (or NULL for default). 648 * @param ifname: The interface ip address. 649 * @param do_auto: use automatic interface detection. 650 * If enabled, then ifname must be the wildcard name. 651 * @param do_udp: if udp should be used. 652 * @param do_tcp: if udp should be used. 653 * @param hints: for getaddrinfo. family and flags have to be set by caller. 654 * @param port: Port number to use (as string). 655 * @param list: list of open ports, appended to, changed to point to list head. 656 * @param rcv: receive buffer size for UDP 657 * @param snd: send buffer size for UDP 658 * @param ssl_port: ssl service port number 659 * @return: returns false on error. 660 */ 661static int 662ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp, 663 struct addrinfo *hints, const char* port, struct listen_port** list, 664 size_t rcv, size_t snd, int ssl_port) 665{ 666 int s, noip6=0; 667 if(!do_udp && !do_tcp) 668 return 0; 669 if(do_auto) { 670 if((s = make_sock_port(SOCK_DGRAM, ifname, port, hints, 1, 671 &noip6, rcv, snd)) == -1) { 672 if(noip6) { 673 log_warn("IPv6 protocol not available"); 674 return 1; 675 } 676 return 0; 677 } 678 /* getting source addr packet info is highly non-portable */ 679 if(!set_recvpktinfo(s, hints->ai_family)) { 680#ifndef USE_WINSOCK 681 close(s); 682#else 683 closesocket(s); 684#endif 685 return 0; 686 } 687 if(!port_insert(list, s, listen_type_udpancil)) { 688#ifndef USE_WINSOCK 689 close(s); 690#else 691 closesocket(s); 692#endif 693 return 0; 694 } 695 } else if(do_udp) { 696 /* regular udp socket */ 697 if((s = make_sock_port(SOCK_DGRAM, ifname, port, hints, 1, 698 &noip6, rcv, snd)) == -1) { 699 if(noip6) { 700 log_warn("IPv6 protocol not available"); 701 return 1; 702 } 703 return 0; 704 } 705 if(!port_insert(list, s, listen_type_udp)) { 706#ifndef USE_WINSOCK 707 close(s); 708#else 709 closesocket(s); 710#endif 711 return 0; 712 } 713 } 714 if(do_tcp) { 715 int is_ssl = ((strchr(ifname, '@') && 716 atoi(strchr(ifname, '@')+1) == ssl_port) || 717 (!strchr(ifname, '@') && atoi(port) == ssl_port)); 718 if((s = make_sock_port(SOCK_STREAM, ifname, port, hints, 1, 719 &noip6, 0, 0)) == -1) { 720 if(noip6) { 721 /*log_warn("IPv6 protocol not available");*/ 722 return 1; 723 } 724 return 0; 725 } 726 if(is_ssl) 727 verbose(VERB_ALGO, "setup TCP for SSL service"); 728 if(!port_insert(list, s, is_ssl?listen_type_ssl: 729 listen_type_tcp)) { 730#ifndef USE_WINSOCK 731 close(s); 732#else 733 closesocket(s); 734#endif 735 return 0; 736 } 737 } 738 return 1; 739} 740 741/** 742 * Add items to commpoint list in front. 743 * @param c: commpoint to add. 744 * @param front: listen struct. 745 * @return: false on failure. 746 */ 747static int 748listen_cp_insert(struct comm_point* c, struct listen_dnsport* front) 749{ 750 struct listen_list* item = (struct listen_list*)malloc( 751 sizeof(struct listen_list)); 752 if(!item) 753 return 0; 754 item->com = c; 755 item->next = front->cps; 756 front->cps = item; 757 return 1; 758} 759 760struct listen_dnsport* 761listen_create(struct comm_base* base, struct listen_port* ports, 762 size_t bufsize, int tcp_accept_count, void* sslctx, 763 comm_point_callback_t* cb, void *cb_arg) 764{ 765 struct listen_dnsport* front = (struct listen_dnsport*) 766 malloc(sizeof(struct listen_dnsport)); 767 if(!front) 768 return NULL; 769 front->cps = NULL; 770 front->udp_buff = ldns_buffer_new(bufsize); 771 if(!front->udp_buff) { 772 free(front); 773 return NULL; 774 } 775 776 /* create comm points as needed */ 777 while(ports) { 778 struct comm_point* cp = NULL; 779 if(ports->ftype == listen_type_udp) 780 cp = comm_point_create_udp(base, ports->fd, 781 front->udp_buff, cb, cb_arg); 782 else if(ports->ftype == listen_type_tcp) 783 cp = comm_point_create_tcp(base, ports->fd, 784 tcp_accept_count, bufsize, cb, cb_arg); 785 else if(ports->ftype == listen_type_ssl) { 786 cp = comm_point_create_tcp(base, ports->fd, 787 tcp_accept_count, bufsize, cb, cb_arg); 788 cp->ssl = sslctx; 789 } else if(ports->ftype == listen_type_udpancil) 790 cp = comm_point_create_udp_ancil(base, ports->fd, 791 front->udp_buff, cb, cb_arg); 792 if(!cp) { 793 log_err("can't create commpoint"); 794 listen_delete(front); 795 return NULL; 796 } 797 cp->do_not_close = 1; 798 if(!listen_cp_insert(cp, front)) { 799 log_err("malloc failed"); 800 comm_point_delete(cp); 801 listen_delete(front); 802 return NULL; 803 } 804 ports = ports->next; 805 } 806 if(!front->cps) { 807 log_err("Could not open sockets to accept queries."); 808 listen_delete(front); 809 return NULL; 810 } 811 812 return front; 813} 814 815void 816listen_list_delete(struct listen_list* list) 817{ 818 struct listen_list *p = list, *pn; 819 while(p) { 820 pn = p->next; 821 comm_point_delete(p->com); 822 free(p); 823 p = pn; 824 } 825} 826 827void 828listen_delete(struct listen_dnsport* front) 829{ 830 if(!front) 831 return; 832 listen_list_delete(front->cps); 833 ldns_buffer_free(front->udp_buff); 834 free(front); 835} 836 837struct listen_port* 838listening_ports_open(struct config_file* cfg) 839{ 840 struct listen_port* list = NULL; 841 struct addrinfo hints; 842 int i, do_ip4, do_ip6; 843 int do_tcp, do_auto; 844 char portbuf[32]; 845 snprintf(portbuf, sizeof(portbuf), "%d", cfg->port); 846 do_ip4 = cfg->do_ip4; 847 do_ip6 = cfg->do_ip6; 848 do_tcp = cfg->do_tcp; 849 do_auto = cfg->if_automatic && cfg->do_udp; 850 if(cfg->incoming_num_tcp == 0) 851 do_tcp = 0; 852 853 /* getaddrinfo */ 854 memset(&hints, 0, sizeof(hints)); 855 hints.ai_flags = AI_PASSIVE; 856 /* no name lookups on our listening ports */ 857 if(cfg->num_ifs > 0) 858 hints.ai_flags |= AI_NUMERICHOST; 859 hints.ai_family = AF_UNSPEC; 860#ifndef INET6 861 do_ip6 = 0; 862#endif 863 if(!do_ip4 && !do_ip6) { 864 return NULL; 865 } 866 /* create ip4 and ip6 ports so that return addresses are nice. */ 867 if(do_auto || cfg->num_ifs == 0) { 868 if(do_ip6) { 869 hints.ai_family = AF_INET6; 870 if(!ports_create_if(do_auto?"::0":"::1", 871 do_auto, cfg->do_udp, do_tcp, 872 &hints, portbuf, &list, 873 cfg->so_rcvbuf, cfg->so_sndbuf, 874 cfg->ssl_port)) { 875 listening_ports_free(list); 876 return NULL; 877 } 878 } 879 if(do_ip4) { 880 hints.ai_family = AF_INET; 881 if(!ports_create_if(do_auto?"0.0.0.0":"127.0.0.1", 882 do_auto, cfg->do_udp, do_tcp, 883 &hints, portbuf, &list, 884 cfg->so_rcvbuf, cfg->so_sndbuf, 885 cfg->ssl_port)) { 886 listening_ports_free(list); 887 return NULL; 888 } 889 } 890 } else for(i = 0; i<cfg->num_ifs; i++) { 891 if(str_is_ip6(cfg->ifs[i])) { 892 if(!do_ip6) 893 continue; 894 hints.ai_family = AF_INET6; 895 if(!ports_create_if(cfg->ifs[i], 0, cfg->do_udp, 896 do_tcp, &hints, portbuf, &list, 897 cfg->so_rcvbuf, cfg->so_sndbuf, 898 cfg->ssl_port)) { 899 listening_ports_free(list); 900 return NULL; 901 } 902 } else { 903 if(!do_ip4) 904 continue; 905 hints.ai_family = AF_INET; 906 if(!ports_create_if(cfg->ifs[i], 0, cfg->do_udp, 907 do_tcp, &hints, portbuf, &list, 908 cfg->so_rcvbuf, cfg->so_sndbuf, 909 cfg->ssl_port)) { 910 listening_ports_free(list); 911 return NULL; 912 } 913 } 914 } 915 return list; 916} 917 918void listening_ports_free(struct listen_port* list) 919{ 920 struct listen_port* nx; 921 while(list) { 922 nx = list->next; 923 if(list->fd != -1) { 924#ifndef USE_WINSOCK 925 close(list->fd); 926#else 927 closesocket(list->fd); 928#endif 929 } 930 free(list); 931 list = nx; 932 } 933} 934 935size_t listen_get_mem(struct listen_dnsport* listen) 936{ 937 size_t s = sizeof(*listen) + sizeof(*listen->base) + 938 sizeof(*listen->udp_buff) + 939 ldns_buffer_capacity(listen->udp_buff); 940 struct listen_list* p; 941 for(p = listen->cps; p; p = p->next) { 942 s += sizeof(*p); 943 s += comm_point_get_mem(p->com); 944 } 945 return s; 946} 947 948void listen_stop_accept(struct listen_dnsport* listen) 949{ 950 /* do not stop the ones that have no tcp_free list 951 * (they have already stopped listening) */ 952 struct listen_list* p; 953 for(p=listen->cps; p; p=p->next) { 954 if(p->com->type == comm_tcp_accept && 955 p->com->tcp_free != NULL) { 956 comm_point_stop_listening(p->com); 957 } 958 } 959} 960 961void listen_start_accept(struct listen_dnsport* listen) 962{ 963 /* do not start the ones that have no tcp_free list, it is no 964 * use to listen to them because they have no free tcp handlers */ 965 struct listen_list* p; 966 for(p=listen->cps; p; p=p->next) { 967 if(p->com->type == comm_tcp_accept && 968 p->com->tcp_free != NULL) { 969 comm_point_start_listening(p->com, -1, -1); 970 } 971 } 972} 973 974