int create_udp_sock(int family, int socktype, struct sockaddr* addr, socklen_t addrlen, int v6only, int* inuse, int* noproto, int rcv, int snd, int listen, int* reuseport) { int s; #if defined(SO_REUSEADDR) || defined(SO_REUSEPORT) || defined(IPV6_USE_MIN_MTU) int on=1; #endif #ifdef IPV6_MTU int mtu = IPV6_MIN_MTU; #endif #if !defined(SO_RCVBUFFORCE) && !defined(SO_RCVBUF) (void)rcv; #endif #if !defined(SO_SNDBUFFORCE) && !defined(SO_SNDBUF) (void)snd; #endif #ifndef IPV6_V6ONLY (void)v6only; #endif if((s = socket(family, socktype, 0)) == -1) { *inuse = 0; #ifndef USE_WINSOCK if(errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT) { *noproto = 1; return -1; } log_err("can't create socket: %s", strerror(errno)); #else if(WSAGetLastError() == WSAEAFNOSUPPORT || WSAGetLastError() == WSAEPROTONOSUPPORT) { *noproto = 1; return -1; } log_err("can't create socket: %s", wsa_strerror(WSAGetLastError())); #endif *noproto = 0; return -1; } if(listen) { #ifdef SO_REUSEADDR if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void*)&on, (socklen_t)sizeof(on)) < 0) { #ifndef USE_WINSOCK log_err("setsockopt(.. SO_REUSEADDR ..) failed: %s", strerror(errno)); if(errno != ENOSYS) { close(s); *noproto = 0; *inuse = 0; return -1; } #else log_err("setsockopt(.. SO_REUSEADDR ..) failed: %s", wsa_strerror(WSAGetLastError())); closesocket(s); *noproto = 0; *inuse = 0; return -1; #endif } #endif /* SO_REUSEADDR */ #ifdef SO_REUSEPORT /* try to set SO_REUSEPORT so that incoming * queries are distributed evenly among the receiving threads. * Each thread must have its own socket bound to the same port, * with SO_REUSEPORT set on each socket. */ if (reuseport && *reuseport && setsockopt(s, SOL_SOCKET, SO_REUSEPORT, (void*)&on, (socklen_t)sizeof(on)) < 0) { #ifdef ENOPROTOOPT if(errno != ENOPROTOOPT || verbosity >= 3) log_warn("setsockopt(.. SO_REUSEPORT ..) failed: %s", strerror(errno)); #endif /* this option is not essential, we can continue */ *reuseport = 0; } #else (void)reuseport; #endif /* defined(SO_REUSEPORT) */ } if(rcv) { #ifdef SO_RCVBUF int got; socklen_t slen = (socklen_t)sizeof(got); # ifdef SO_RCVBUFFORCE /* Linux specific: try to use root permission to override * system limits on rcvbuf. The limit is stored in * /proc/sys/net/core/rmem_max or sysctl net.core.rmem_max */ if(setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, (void*)&rcv, (socklen_t)sizeof(rcv)) < 0) { if(errno != EPERM) { # ifndef USE_WINSOCK log_err("setsockopt(..., SO_RCVBUFFORCE, " "...) failed: %s", strerror(errno)); close(s); # else log_err("setsockopt(..., SO_RCVBUFFORCE, " "...) failed: %s", wsa_strerror(WSAGetLastError())); closesocket(s); # endif *noproto = 0; *inuse = 0; return -1; } # endif /* SO_RCVBUFFORCE */ if(setsockopt(s, SOL_SOCKET, SO_RCVBUF, (void*)&rcv, (socklen_t)sizeof(rcv)) < 0) { # ifndef USE_WINSOCK log_err("setsockopt(..., SO_RCVBUF, " "...) failed: %s", strerror(errno)); close(s); # else log_err("setsockopt(..., SO_RCVBUF, " "...) failed: %s", wsa_strerror(WSAGetLastError())); closesocket(s); # endif *noproto = 0; *inuse = 0; return -1; } /* check if we got the right thing or if system * reduced to some system max. Warn if so */ if(getsockopt(s, SOL_SOCKET, SO_RCVBUF, (void*)&got, &slen) >= 0 && got < rcv/2) { log_warn("so-rcvbuf %u was not granted. " "Got %u. To fix: start with " "root permissions(linux) or sysctl " "bigger net.core.rmem_max(linux) or " "kern.ipc.maxsockbuf(bsd) values.", (unsigned)rcv, (unsigned)got); } # ifdef SO_RCVBUFFORCE } # endif #endif /* SO_RCVBUF */ } /* first do RCVBUF as the receive buffer is more important */ if(snd) { #ifdef SO_SNDBUF int got; socklen_t slen = (socklen_t)sizeof(got); # ifdef SO_SNDBUFFORCE /* Linux specific: try to use root permission to override * system limits on sndbuf. The limit is stored in * /proc/sys/net/core/wmem_max or sysctl net.core.wmem_max */ if(setsockopt(s, SOL_SOCKET, SO_SNDBUFFORCE, (void*)&snd, (socklen_t)sizeof(snd)) < 0) { if(errno != EPERM) { # ifndef USE_WINSOCK log_err("setsockopt(..., SO_SNDBUFFORCE, " "...) failed: %s", strerror(errno)); close(s); # else log_err("setsockopt(..., SO_SNDBUFFORCE, " "...) failed: %s", wsa_strerror(WSAGetLastError())); closesocket(s); # endif *noproto = 0; *inuse = 0; return -1; } # endif /* SO_SNDBUFFORCE */ if(setsockopt(s, SOL_SOCKET, SO_SNDBUF, (void*)&snd, (socklen_t)sizeof(snd)) < 0) { # ifndef USE_WINSOCK log_err("setsockopt(..., SO_SNDBUF, " "...) failed: %s", strerror(errno)); close(s); # else log_err("setsockopt(..., SO_SNDBUF, " "...) failed: %s", wsa_strerror(WSAGetLastError())); closesocket(s); # endif *noproto = 0; *inuse = 0; return -1; } /* check if we got the right thing or if system * reduced to some system max. Warn if so */ if(getsockopt(s, SOL_SOCKET, SO_SNDBUF, (void*)&got, &slen) >= 0 && got < snd/2) { log_warn("so-sndbuf %u was not granted. " "Got %u. To fix: start with " "root permissions(linux) or sysctl " "bigger net.core.wmem_max(linux) or " "kern.ipc.maxsockbuf(bsd) values.", (unsigned)snd, (unsigned)got); } # ifdef SO_SNDBUFFORCE } # endif #endif /* SO_SNDBUF */ } if(family == AF_INET6) { # if defined(IPV6_V6ONLY) if(v6only) { int val=(v6only==2)?0:1; if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&val, (socklen_t)sizeof(val)) < 0) { #ifndef USE_WINSOCK log_err("setsockopt(..., IPV6_V6ONLY" ", ...) failed: %s", strerror(errno)); close(s); #else log_err("setsockopt(..., IPV6_V6ONLY" ", ...) failed: %s", wsa_strerror(WSAGetLastError())); closesocket(s); #endif *noproto = 0; *inuse = 0; return -1; } } # endif # if defined(IPV6_USE_MIN_MTU) /* * There is no fragmentation of IPv6 datagrams * during forwarding in the network. Therefore * we do not send UDP datagrams larger than * the minimum IPv6 MTU of 1280 octets. The * EDNS0 message length can be larger if the * network stack supports IPV6_USE_MIN_MTU. */ if (setsockopt(s, IPPROTO_IPV6, IPV6_USE_MIN_MTU, (void*)&on, (socklen_t)sizeof(on)) < 0) { # ifndef USE_WINSOCK log_err("setsockopt(..., IPV6_USE_MIN_MTU, " "...) failed: %s", strerror(errno)); close(s); # else log_err("setsockopt(..., IPV6_USE_MIN_MTU, " "...) failed: %s", wsa_strerror(WSAGetLastError())); closesocket(s); # endif *noproto = 0; *inuse = 0; return -1; } # elif defined(IPV6_MTU) /* * On Linux, to send no larger than 1280, the PMTUD is * disabled by default for datagrams anyway, so we set * the MTU to use. */ if (setsockopt(s, IPPROTO_IPV6, IPV6_MTU, (void*)&mtu, (socklen_t)sizeof(mtu)) < 0) { # ifndef USE_WINSOCK log_err("setsockopt(..., IPV6_MTU, ...) failed: %s", strerror(errno)); close(s); # else log_err("setsockopt(..., IPV6_MTU, ...) failed: %s", wsa_strerror(WSAGetLastError())); closesocket(s); # endif *noproto = 0; *inuse = 0; return -1; } # endif /* IPv6 MTU */ } else if(family == AF_INET) { # if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT) /* linux 3.15 has IP_PMTUDISC_OMIT, Hannes Frederic Sowa made it so that * PMTU information is not accepted, but fragmentation is allowed * if and only if the packet size exceeds the outgoing interface MTU * (and also uses the interface mtu to determine the size of the packets). * So there won't be any EMSGSIZE error. Against DNS fragmentation attacks. * FreeBSD already has same semantics without setting the option. */ int omit_set = 0; int action; # if defined(IP_PMTUDISC_OMIT) action = IP_PMTUDISC_OMIT; if (setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, &action, (socklen_t)sizeof(action)) < 0) { if (errno != EINVAL) { log_err("setsockopt(..., IP_MTU_DISCOVER, IP_PMTUDISC_OMIT...) failed: %s", strerror(errno)); # ifndef USE_WINSOCK close(s); # else closesocket(s); # endif *noproto = 0; *inuse = 0; return -1; } } else { omit_set = 1; } # endif if (omit_set == 0) { action = IP_PMTUDISC_DONT; if (setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, &action, (socklen_t)sizeof(action)) < 0) { log_err("setsockopt(..., IP_MTU_DISCOVER, IP_PMTUDISC_DONT...) failed: %s", strerror(errno)); # ifndef USE_WINSOCK close(s); # else closesocket(s); # endif *noproto = 0; *inuse = 0; return -1; } } # elif defined(IP_DONTFRAG) int off = 0; if (setsockopt(s, IPPROTO_IP, IP_DONTFRAG, &off, (socklen_t)sizeof(off)) < 0) { log_err("setsockopt(..., IP_DONTFRAG, ...) failed: %s", strerror(errno)); # ifndef USE_WINSOCK close(s); # else closesocket(s); # endif *noproto = 0; *inuse = 0; return -1; } # endif /* IPv4 MTU */ } if(bind(s, (struct sockaddr*)addr, addrlen) != 0) { *noproto = 0; *inuse = 0; #ifndef USE_WINSOCK #ifdef EADDRINUSE *inuse = (errno == EADDRINUSE); /* detect freebsd jail with no ipv6 permission */ if(family==AF_INET6 && errno==EINVAL) *noproto = 1; else if(errno != EADDRINUSE) { log_err_addr("can't bind socket", strerror(errno), (struct sockaddr_storage*)addr, addrlen); } #endif /* EADDRINUSE */ close(s); #else /* USE_WINSOCK */ if(WSAGetLastError() != WSAEADDRINUSE && WSAGetLastError() != WSAEADDRNOTAVAIL) { log_err_addr("can't bind socket", wsa_strerror(WSAGetLastError()), (struct sockaddr_storage*)addr, addrlen); } closesocket(s); #endif return -1; } if(!fd_set_nonblock(s)) { *noproto = 0; *inuse = 0; #ifndef USE_WINSOCK close(s); #else closesocket(s); #endif return -1; } return s; }
/** contact the server with TCP connect */ static int contact_server(const char* svr, struct config_file* cfg, int statuscmd) { struct sockaddr_storage addr; socklen_t addrlen; int addrfamily = 0; int fd; /* use svr or the first config entry */ if(!svr) { if(cfg->control_ifs) svr = cfg->control_ifs->str; else svr = "127.0.0.1"; /* config 0 addr (everything), means ask localhost */ if(strcmp(svr, "0.0.0.0") == 0) svr = "127.0.0.1"; else if(strcmp(svr, "::0") == 0 || strcmp(svr, "0::0") == 0 || strcmp(svr, "0::") == 0 || strcmp(svr, "::") == 0) svr = "::1"; } if(strchr(svr, '@')) { if(!extstrtoaddr(svr, &addr, &addrlen)) fatal_exit("could not parse IP@port: %s", svr); #ifdef HAVE_SYS_UN_H } else if(svr[0] == '/') { struct sockaddr_un* usock = (struct sockaddr_un *) &addr; usock->sun_family = AF_LOCAL; #ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN usock->sun_len = (socklen_t)sizeof(usock); #endif (void)strlcpy(usock->sun_path, svr, sizeof(usock->sun_path)); addrlen = (socklen_t)sizeof(struct sockaddr_un); addrfamily = AF_LOCAL; #endif } else { if(!ipstrtoaddr(svr, cfg->control_port, &addr, &addrlen)) fatal_exit("could not parse IP: %s", svr); } if(addrfamily == 0) addrfamily = addr_is_ip6(&addr, addrlen)?AF_INET6:AF_INET; fd = socket(addrfamily, SOCK_STREAM, 0); if(fd == -1) { #ifndef USE_WINSOCK fatal_exit("socket: %s", strerror(errno)); #else fatal_exit("socket: %s", wsa_strerror(WSAGetLastError())); #endif } if(connect(fd, (struct sockaddr*)&addr, addrlen) < 0) { #ifndef USE_WINSOCK log_err_addr("connect", strerror(errno), &addr, addrlen); if(errno == ECONNREFUSED && statuscmd) { printf("unbound is stopped\n"); exit(3); } #else log_err_addr("connect", wsa_strerror(WSAGetLastError()), &addr, addrlen); if(WSAGetLastError() == WSAECONNREFUSED && statuscmd) { printf("unbound is stopped\n"); exit(3); } #endif exit(1); } return fd; }
int create_tcp_accept_sock(struct addrinfo *addr, int v6only, int* noproto, int* reuseport) { int s; #if defined(SO_REUSEADDR) || defined(SO_REUSEPORT) || defined(IPV6_V6ONLY) int on = 1; #endif /* SO_REUSEADDR || IPV6_V6ONLY */ verbose_print_addr(addr); *noproto = 0; if((s = socket(addr->ai_family, addr->ai_socktype, 0)) == -1) { #ifndef USE_WINSOCK if(errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT) { *noproto = 1; return -1; } log_err("can't create socket: %s", strerror(errno)); #else if(WSAGetLastError() == WSAEAFNOSUPPORT || WSAGetLastError() == WSAEPROTONOSUPPORT) { *noproto = 1; return -1; } log_err("can't create socket: %s", wsa_strerror(WSAGetLastError())); #endif return -1; } #ifdef SO_REUSEADDR if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void*)&on, (socklen_t)sizeof(on)) < 0) { #ifndef USE_WINSOCK log_err("setsockopt(.. SO_REUSEADDR ..) failed: %s", strerror(errno)); close(s); #else log_err("setsockopt(.. SO_REUSEADDR ..) failed: %s", wsa_strerror(WSAGetLastError())); closesocket(s); #endif return -1; } #endif /* SO_REUSEADDR */ #ifdef SO_REUSEPORT /* try to set SO_REUSEPORT so that incoming * connections are distributed evenly among the receiving threads. * Each thread must have its own socket bound to the same port, * with SO_REUSEPORT set on each socket. */ if (reuseport && *reuseport && setsockopt(s, SOL_SOCKET, SO_REUSEPORT, (void*)&on, (socklen_t)sizeof(on)) < 0) { #ifdef ENOPROTOOPT if(errno != ENOPROTOOPT || verbosity >= 3) log_warn("setsockopt(.. SO_REUSEPORT ..) failed: %s", strerror(errno)); #endif /* this option is not essential, we can continue */ *reuseport = 0; } #else (void)reuseport; #endif /* defined(SO_REUSEPORT) */ #if defined(IPV6_V6ONLY) if(addr->ai_family == AF_INET6 && v6only) { if(setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&on, (socklen_t)sizeof(on)) < 0) { #ifndef USE_WINSOCK log_err("setsockopt(..., IPV6_V6ONLY, ...) failed: %s", strerror(errno)); close(s); #else log_err("setsockopt(..., IPV6_V6ONLY, ...) failed: %s", wsa_strerror(WSAGetLastError())); closesocket(s); #endif return -1; } } #else (void)v6only; #endif /* IPV6_V6ONLY */ if(bind(s, addr->ai_addr, addr->ai_addrlen) != 0) { #ifndef USE_WINSOCK /* detect freebsd jail with no ipv6 permission */ if(addr->ai_family==AF_INET6 && errno==EINVAL) *noproto = 1; else { log_err_addr("can't bind socket", strerror(errno), (struct sockaddr_storage*)addr->ai_addr, addr->ai_addrlen); } close(s); #else log_err_addr("can't bind socket", wsa_strerror(WSAGetLastError()), (struct sockaddr_storage*)addr->ai_addr, addr->ai_addrlen); closesocket(s); #endif return -1; } if(!fd_set_nonblock(s)) { #ifndef USE_WINSOCK close(s); #else closesocket(s); #endif return -1; } if(listen(s, TCP_BACKLOG) == -1) { #ifndef USE_WINSOCK log_err("can't listen: %s", strerror(errno)); close(s); #else log_err("can't listen: %s", wsa_strerror(WSAGetLastError())); closesocket(s); #endif return -1; } return s; }