...
 
Commits (3)
5473. [bug] Due to IPv6 addresses landing in tentative (unbindable)
state first BIND9 wasn't handling adding new IPv6
addresses correctly. [GL #2038]
5472. [func] The statistics channel has been updated to use the 5472. [func] The statistics channel has been updated to use the
new network manager. [GL #2022] new network manager. [GL #2022]
......
...@@ -49,6 +49,21 @@ ...@@ -49,6 +49,21 @@
#define ISC_NETMGR_RECVBUF_SIZE (65536) #define ISC_NETMGR_RECVBUF_SIZE (65536)
#endif #endif
/*
* setsockopt() option that lets us bind to a non-existing interface,
* useful for not fully initialized (tentative) IPv6 interfaces which
* are up, but not yet bindable.
*/
#undef FREEBIND_OPT
#if defined(IP_FREEBIND)
#define FREEBIND_OPT IP_FREEBIND
#elif defined(IP_BINDANY)
#define FREEBIND_OPT IP_BINDANY
#elif defined(SO_BINDANY)
#define FREEBIND_OPT SO_BINDANY
#endif
/* /*
* Single network event loop worker. * Single network event loop worker.
*/ */
......
...@@ -1166,6 +1166,10 @@ nmhandle_deactivate(isc_nmsocket_t *sock, isc_nmhandle_t *handle) { ...@@ -1166,6 +1166,10 @@ nmhandle_deactivate(isc_nmsocket_t *sock, isc_nmhandle_t *handle) {
*/ */
LOCK(&sock->lock); LOCK(&sock->lock);
if (sock->tcphandle == handle) {
sock->tcphandle = NULL;
}
INSIST(sock->ah_handles[handle->ah_pos] == handle); INSIST(sock->ah_handles[handle->ah_pos] == handle);
INSIST(sock->ah_size > handle->ah_pos); INSIST(sock->ah_size > handle->ah_pos);
INSIST(atomic_load(&sock->ah) > 0); INSIST(atomic_load(&sock->ah) > 0);
......
...@@ -340,6 +340,23 @@ isc__nm_async_tcplisten(isc__networker_t *worker, isc__netievent_t *ev0) { ...@@ -340,6 +340,23 @@ isc__nm_async_tcplisten(isc__networker_t *worker, isc__netievent_t *ev0) {
r = uv_tcp_bind(&sock->uv_handle.tcp, &sock->iface->addr.type.sa, r = uv_tcp_bind(&sock->uv_handle.tcp, &sock->iface->addr.type.sa,
flags); flags);
#ifdef FREEBIND_OPT
if (r == UV_EADDRNOTAVAIL) {
/*
* Retry binding with IP_FREEBIND (or equivalent option) if
* the address is not available. Helps with IPv6 tentative
* addresses which are reported by the route socket but we're
* not yet able to properly bind to them.
*/
uv_os_fd_t fd;
if (uv_fileno(&sock->uv_handle.handle, &fd) == 0) {
(void)setsockopt(fd, IPPROTO_IP, FREEBIND_OPT,
&(int){ 1 }, sizeof(int));
}
r = uv_tcp_bind(&sock->uv_handle.tcp,
&sock->iface->addr.type.sa, flags);
}
#endif
if (r != 0) { if (r != 0) {
isc__nm_incstats(sock->mgr, sock->statsindex[STATID_BINDFAIL]); isc__nm_incstats(sock->mgr, sock->statsindex[STATID_BINDFAIL]);
uv_close(&sock->uv_handle.handle, tcp_close_cb); uv_close(&sock->uv_handle.handle, tcp_close_cb);
...@@ -590,7 +607,7 @@ readtimeout_cb(uv_timer_t *handle) { ...@@ -590,7 +607,7 @@ readtimeout_cb(uv_timer_t *handle) {
if (sock->quota) { if (sock->quota) {
isc_quota_detach(&sock->quota); isc_quota_detach(&sock->quota);
} }
if (sock->rcb.recv != NULL) { if (sock->rcb.recv != NULL && sock->tcphandle != NULL) {
sock->rcb.recv(sock->tcphandle, ISC_R_TIMEDOUT, NULL, sock->rcb.recv(sock->tcphandle, ISC_R_TIMEDOUT, NULL,
sock->rcbarg); sock->rcbarg);
isc__nmsocket_clearcb(sock); isc__nmsocket_clearcb(sock);
...@@ -728,7 +745,7 @@ read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) { ...@@ -728,7 +745,7 @@ read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) {
isc_region_t region = { .base = (unsigned char *)buf->base, isc_region_t region = { .base = (unsigned char *)buf->base,
.length = nread }; .length = nread };
if (sock->rcb.recv != NULL) { if (sock->rcb.recv != NULL && sock->tcphandle != NULL) {
sock->rcb.recv(sock->tcphandle, ISC_R_SUCCESS, &region, sock->rcb.recv(sock->tcphandle, ISC_R_SUCCESS, &region,
sock->rcbarg); sock->rcbarg);
} }
...@@ -753,7 +770,7 @@ read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) { ...@@ -753,7 +770,7 @@ read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) {
* This might happen if the inner socket is closing. It means that * This might happen if the inner socket is closing. It means that
* it's detached, so the socket will be closed. * it's detached, so the socket will be closed.
*/ */
if (sock->rcb.recv != NULL) { if (sock->rcb.recv != NULL && sock->tcphandle != NULL) {
isc__nm_incstats(sock->mgr, sock->statsindex[STATID_RECVFAIL]); isc__nm_incstats(sock->mgr, sock->statsindex[STATID_RECVFAIL]);
sock->rcb.recv(sock->tcphandle, ISC_R_EOF, NULL, sock->rcbarg); sock->rcb.recv(sock->tcphandle, ISC_R_EOF, NULL, sock->rcbarg);
isc__nmsocket_clearcb(sock); isc__nmsocket_clearcb(sock);
......
...@@ -168,6 +168,25 @@ isc__nm_async_udplisten(isc__networker_t *worker, isc__netievent_t *ev0) { ...@@ -168,6 +168,25 @@ isc__nm_async_udplisten(isc__networker_t *worker, isc__netievent_t *ev0) {
r = uv_udp_bind(&sock->uv_handle.udp, r = uv_udp_bind(&sock->uv_handle.udp,
&sock->parent->iface->addr.type.sa, uv_bind_flags); &sock->parent->iface->addr.type.sa, uv_bind_flags);
#ifdef FREEBIND_OPT
if (r == UV_EADDRNOTAVAIL) {
/*
* Retry binding with IP_FREEBIND (or equivalent option) if
* the address is not available. Helps with IPv6 tentative
* addresses which are reported by the route socket but we're
* not yet able to properly bind to them.
*/
uv_os_fd_t fd;
if (uv_fileno(&sock->uv_handle.handle, &fd) == 0) {
(void)setsockopt(fd, IPPROTO_IP, FREEBIND_OPT,
&(int){ 1 }, sizeof(int));
}
r = uv_udp_bind(&sock->uv_handle.udp,
&sock->parent->iface->addr.type.sa,
uv_bind_flags);
}
#endif
if (r < 0) { if (r < 0) {
isc__nm_incstats(sock->mgr, sock->statsindex[STATID_BINDFAIL]); isc__nm_incstats(sock->mgr, sock->statsindex[STATID_BINDFAIL]);
} }
......