ixfr-from-differences yes;
check-integrity no;
allow-query-on { 10.53.0.2; };
- blackhole { 10.53.0.8; };
};
key one {
@10.53.0.2 -b 10.53.0.3 > dig.out.${t}
grep "status: NOERROR" dig.out.${t} > /dev/null 2>&1 || { echo_i "test $t failed" ; status=1; }
-echo_i "testing blackhole ACL processing"
-t=`expr $t + 1`
-ret=0
-$DIG -p ${PORT} +tcp soa example. \
- @10.53.0.2 -b 10.53.0.3 > dig.out.1.${t}
-grep "status: NOERROR" dig.out.1.${t} > /dev/null 2>&1 || ret=1
-$DIG -p ${PORT} +tcp soa example. \
- @10.53.0.2 -b 10.53.0.8 > dig.out.2.${t}
-grep "status: NOERROR" dig.out.2.${t} > /dev/null 2>&1 && ret=1
-grep "communications error" dig.out.2.${t} > /dev/null 2>&1 || ret=1
-$DIG -p ${PORT} soa example. \
- @10.53.0.2 -b 10.53.0.3 > dig.out.3.${t}
-grep "status: NOERROR" dig.out.3.${t} > /dev/null 2>&1 || ret=1
-$DIG -p ${PORT} soa example. \
- @10.53.0.2 -b 10.53.0.8 > dig.out.4.${t}
-grep "status: NOERROR" dig.out.4.${t} > /dev/null 2>&1 && ret=1
-grep "connection timed out" dig.out.4.${t} > /dev/null 2>&1 || ret=1
-[ $ret -eq 0 ] || echo_i "failed"
-status=`expr $status + $ret`
-
# AXFR tests against ns3
echo_i "testing allow-transfer ACLs against ns3 (no existing zones)"
NMEV_SHUTDOWN
} isc_nm_eventtype;
-typedef void (*isc_nm_recv_cb_t)(isc_nmhandle_t *handle, isc_region_t *region,
- void *cbarg);
-/*%<
- * Callback function to be used when receiving a packet.
- *
- * 'handle' the handle that can be used to send back the answer.
- * 'region' contains the received data. It will be freed after
- * return by caller.
- * 'cbarg' the callback argument passed to isc_nm_listenudp(),
- * isc_nm_listentcpdns(), or isc_nm_read().
- */
-
-typedef isc_result_t (*isc_nm_accept_cb_t)(isc_nmhandle_t *handle,
- isc_result_t result, void *cbarg);
-/*%<
- * Callback function to be used when accepting a connection. (This differs
- * from isc_nm_cb_t below in that it returns a result code.)
- *
- * 'handle' the handle that can be used to send back the answer.
- * 'eresult' the result of the event.
- * 'cbarg' the callback argument passed to isc_nm_listentcp() or
- * isc_nm_listentcpdns().
- */
-
-typedef void (*isc_nm_cb_t)(isc_nmhandle_t *handle, isc_result_t result,
- void *cbarg);
-/*%<
- * Callback function for other network completion events (send, connect).
- *
- * 'handle' the handle on which the event took place.
- * 'eresult' the result of the event.
- * 'cbarg' the callback argument passed to isc_nm_send(),
- * isc_nm_tcp_connect(), or isc_nm_listentcp()
- */
-
-typedef void (*isc_nm_opaquecb_t)(void *arg);
-/*%<
- * Opaque callback function, used for isc_nmhandle 'reset' and 'free'
- * callbacks.
- */
-
isc_nm_t *
isc_nm_start(isc_mem_t *mctx, uint32_t workers);
/*%<
void *
isc_nmhandle_getextra(isc_nmhandle_t *handle);
+typedef void (*isc_nm_opaquecb_t)(void *arg);
+
bool
isc_nmhandle_is_stream(isc_nmhandle_t *handle);
* Return a pointer to the netmgr object for the given handle.
*/
+typedef void (*isc_nm_recv_cb_t)(isc_nmhandle_t *handle, isc_region_t *region,
+ void *cbarg);
+/*%<
+ * Callback function to be used when receiving a packet.
+ *
+ * 'handle' the handle that can be used to send back the answer.
+ * 'region' contains the received data. It will be freed after
+ * return by caller.
+ * 'cbarg' the callback argument passed to isc_nm_listenudp(),
+ * isc_nm_listentcpdns(), or isc_nm_read().
+ */
+
+typedef void (*isc_nm_cb_t)(isc_nmhandle_t *handle, isc_result_t result,
+ void *cbarg);
+/*%<
+ * Callback function for other network completion events (send, connect,
+ * accept).
+ *
+ * 'handle' the handle on which the event took place.
+ * 'result' the result of the event.
+ * 'cbarg' the callback argument passed to isc_nm_send(),
+ * isc_nm_tcp_connect(), or isc_nm_listentcp()
+ */
+
isc_result_t
isc_nm_listenudp(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_recv_cb_t cb,
void *cbarg, size_t extrasize, isc_nmsocket_t **sockp);
*/
isc_result_t
-isc_nm_listentcp(isc_nm_t *mgr, isc_nmiface_t *iface,
- isc_nm_accept_cb_t accept_cb, void *accept_cbarg,
- size_t extrahandlesize, int backlog, isc_quota_t *quota,
- isc_nmsocket_t **sockp);
+isc_nm_listentcp(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_cb_t cb,
+ void *cbarg, size_t extrahandlesize, int backlog,
+ isc_quota_t *quota, isc_nmsocket_t **sockp);
/*%<
* Start listening for raw messages over the TCP interface 'iface', using
* net manager 'mgr'.
* On success, 'sockp' will be updated to contain a new listening TCP
* socket.
*
- * When connection is accepted on the socket, 'accept_cb' will be called with
- * 'accept_cbarg' as its argument. The callback is expected to start a read.
+ * When a message is received on the socket, 'cb' will be called with 'cbarg'
+ * as its argument.
*
* When handles are allocated for the socket, 'extrasize' additional bytes
* will be allocated along with the handle for an associated object.
isc_result_t
isc_nm_listentcpdns(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_recv_cb_t cb,
- void *cbarg, isc_nm_accept_cb_t accept_cb,
- void *accept_cbarg, size_t extrahandlesize, int backlog,
- isc_quota_t *quota, isc_nmsocket_t **sockp);
+ void *cbarg, isc_nm_cb_t accept_cb, void *accept_cbarg,
+ size_t extrahandlesize, int backlog, isc_quota_t *quota,
+ isc_nmsocket_t **sockp);
/*%<
* Start listening for DNS messages over the TCP interface 'iface', using
* net manager 'mgr'.
* When a complete DNS message is received on the socket, 'cb' will be
* called with 'cbarg' as its argument.
*
- * When a new TCPDNS connection is accepted, 'accept_cb' will be called
+ * When a new TCP connection is accepted, 'accept_cb' will be called
* with 'accept_cbarg' as its argument.
*
* When handles are allocated for the socket, 'extrasize' additional bytes
netievent_tcpaccept,
netievent_tcpstop,
netievent_tcpclose,
-
netievent_tcpdnsclose,
- netievent_tcpdnssend,
netievent_closecb,
netievent_shutdown,
*/
typedef union {
isc_nm_recv_cb_t recv;
- isc_nm_accept_cb_t accept;
+ isc_nm_cb_t accept;
} isc__nm_readcb_t;
typedef union {
typedef union {
isc_nm_recv_cb_t recv;
- isc_nm_accept_cb_t accept;
+ isc_nm_cb_t accept;
isc_nm_cb_t send;
isc_nm_cb_t connect;
} isc__nm_cb_t;
typedef isc__netievent__socket_req_t isc__netievent_tcpconnect_t;
typedef isc__netievent__socket_req_t isc__netievent_tcplisten_t;
typedef isc__netievent__socket_req_t isc__netievent_tcpsend_t;
-typedef isc__netievent__socket_req_t isc__netievent_tcpdnssend_t;
typedef struct isc__netievent__socket_streaminfo_quota {
isc__netievent_type type;
* way to use an isc__networker_t from another thread.)
*/
+void
+isc__nm_alloc_cb(uv_handle_t *handle, size_t size, uv_buf_t *buf);
+/*%<
+ * Allocator for recv operations.
+ *
+ * Note that as currently implemented, this doesn't actually
+ * allocate anything, it just assigns the the isc__networker's UDP
+ * receive buffer to a socket, and marks it as "in use".
+ */
+
void
isc__nm_free_uvbuf(isc_nmsocket_t *sock, const uv_buf_t *buf);
/*%<
void
isc__nm_async_tcpdnsclose(isc__networker_t *worker, isc__netievent_t *ev0);
-void
-isc__nm_async_tcpdnssend(isc__networker_t *worker, isc__netievent_t *ev0);
-
#define isc__nm_uverr2result(x) \
isc___nm_uverr2result(x, true, __FILE__, __LINE__)
isc_result_t
/*%<
* Decrement socket-related statistics counters.
*/
-
-isc_result_t
-isc__nm_socket_freebind(const uv_handle_t *handle);
-/*%<
- * Set the IP_FREEBIND (or equivalent) socket option on the uv_handle
- */
case netievent_tcpsend:
isc__nm_async_tcpsend(worker, ievent);
break;
- case netievent_tcpdnssend:
- isc__nm_async_tcpdnssend(worker, ievent);
- break;
case netievent_tcpstop:
isc__nm_async_tcpstop(worker, ievent);
break;
if (active_handles == 0 || sock->tcphandle != NULL) {
destroy = true;
}
+ UNLOCK(&sock->lock);
if (destroy) {
- atomic_store(&sock->destroying, true);
- UNLOCK(&sock->lock);
nmsocket_cleanup(sock, true);
- } else {
- UNLOCK(&sock->lock);
}
}
sock->magic = NMSOCK_MAGIC;
}
+void
+isc__nm_alloc_cb(uv_handle_t *handle, size_t size, uv_buf_t *buf) {
+ isc_nmsocket_t *sock = uv_handle_get_data(handle);
+ isc__networker_t *worker = NULL;
+
+ REQUIRE(VALID_NMSOCK(sock));
+ REQUIRE(isc__nm_in_netthread());
+ REQUIRE(size <= ISC_NETMGR_RECVBUF_SIZE);
+
+ worker = &sock->mgr->workers[sock->tid];
+ INSIST(!worker->recvbuf_inuse);
+
+ buf->base = worker->recvbuf;
+ worker->recvbuf_inuse = true;
+ buf->len = ISC_NETMGR_RECVBUF_SIZE;
+}
+
void
isc__nm_free_uvbuf(isc_nmsocket_t *sock, const uv_buf_t *buf) {
isc__networker_t *worker = NULL;
worker = &sock->mgr->workers[sock->tid];
REQUIRE(worker->recvbuf_inuse);
- if (sock->type == isc_nm_udpsocket && buf->base > worker->recvbuf &&
+ if (buf->base > worker->recvbuf &&
buf->base <= worker->recvbuf + ISC_NETMGR_RECVBUF_SIZE)
{
/* Can happen in case of out-of-order recvmmsg in libuv1.36 */
isc_stats_decrement(mgr->stats, counterid);
}
}
-
-#define setsockopt_on(socket, level, name) \
- setsockopt(socket, level, name, &(int){ 1 }, sizeof(int))
-
-isc_result_t
-isc__nm_socket_freebind(const uv_handle_t *handle) {
- /*
- * Set the IP_FREEBIND (or equivalent option) on the uv_handle.
- */
- isc_result_t result = ISC_R_SUCCESS;
- uv_os_fd_t fd;
- if (uv_fileno(handle, &fd) != 0) {
- return (ISC_R_FAILURE);
- }
-#ifdef IP_FREEBIND
- if (setsockopt_on(fd, IPPROTO_IP, IP_FREEBIND) == -1) {
- return (ISC_R_FAILURE);
- }
-#elif defined(IP_BINDANY) || defined(IPV6_BINDANY)
- struct sockaddr_in sockfd;
-
- if (getsockname(fd, (struct sockaddr *)&sockfd,
- &(socklen_t){ sizeof(sockfd) }) == -1)
- {
- return (ISC_R_FAILURE);
- }
-#if defined(IP_BINDANY)
- if (sockfd.sin_family == AF_INET) {
- if (setsockopt_on(fd, IPPROTO_IP, IP_BINDANY) == -1) {
- return (ISC_R_FAILURE);
- }
- }
-#endif
-#if defined(IPV6_BINDANY)
- if (sockfd.sin_family == AF_INET6) {
- if (setsockopt_on(fd, IPPROTO_IPV6, IPV6_BINDANY) == -1) {
- return (ISC_R_FAILURE);
- }
- }
-#endif
-#elif defined(SO_BINDANY)
- if (setsockopt_on(fd, SOL_SOCKET, SO_BINDANY) == -1) {
- return (ISC_R_FAILURE);
- }
-#else
- UNUSED(handle);
- UNUSED(fd);
- result = ISC_R_NOTIMPLEMENTED;
-#endif
- return (result);
-}
}
isc_result_t
-isc_nm_listentcp(isc_nm_t *mgr, isc_nmiface_t *iface,
- isc_nm_accept_cb_t accept_cb, void *accept_cbarg,
- size_t extrahandlesize, int backlog, isc_quota_t *quota,
- isc_nmsocket_t **sockp) {
+isc_nm_listentcp(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_cb_t cb,
+ void *cbarg, size_t extrahandlesize, int backlog,
+ isc_quota_t *quota, isc_nmsocket_t **sockp) {
isc_nmsocket_t *nsock = NULL;
isc__netievent_tcplisten_t *ievent = NULL;
nsock = isc_mem_get(mgr->mctx, sizeof(*nsock));
isc__nmsocket_init(nsock, mgr, isc_nm_tcplistener, iface);
- nsock->accept_cb.accept = accept_cb;
- nsock->accept_cbarg = accept_cbarg;
+ nsock->rcb.accept = cb;
+ nsock->rcbarg = cbarg;
nsock->extrahandlesize = extrahandlesize;
nsock->backlog = backlog;
nsock->result = ISC_R_SUCCESS;
r = uv_tcp_bind(&sock->uv_handle.tcp, &sock->iface->addr.type.sa,
flags);
- if (r == UV_EADDRNOTAVAIL &&
- isc__nm_socket_freebind(&sock->uv_handle.handle) == ISC_R_SUCCESS)
- {
- /*
- * Retry binding with IP_FREEBIND (or equivalent option) if the
- * address is not available. This helps with IPv6 tentative
- * addresses which are reported by the route socket, although
- * named is not yet able to properly bind to them.
- */
- r = uv_tcp_bind(&sock->uv_handle.tcp,
- &sock->iface->addr.type.sa, flags);
- }
-
if (r != 0) {
isc__nm_incstats(sock->mgr, sock->statsindex[STATID_BINDFAIL]);
uv_close(&sock->uv_handle.handle, tcp_close_cb);
handle = isc__nmhandle_get(csock, NULL, &local);
- INSIST(ssock->accept_cb.accept != NULL);
+ INSIST(ssock->rcb.accept != NULL);
csock->read_timeout = ssock->mgr->init;
- ssock->accept_cb.accept(handle, ISC_R_SUCCESS, ssock->accept_cbarg);
+ ssock->rcb.accept(handle, ISC_R_SUCCESS, ssock->rcbarg);
isc_nmsocket_detach(&csock);
return;
return (ISC_R_SUCCESS);
}
-/*%<
- * Allocator for TCP read operations. Limited to size 2^16.
- *
- * Note this doesn't actually allocate anything, it just assigns the
- * worker's receive buffer to a socket, and marks it as "in use".
- */
-static void
-tcp_alloc_cb(uv_handle_t *handle, size_t size, uv_buf_t *buf) {
- isc_nmsocket_t *sock = uv_handle_get_data(handle);
- isc__networker_t *worker = NULL;
-
- REQUIRE(VALID_NMSOCK(sock));
- REQUIRE(sock->type == isc_nm_tcpsocket);
- REQUIRE(isc__nm_in_netthread());
- REQUIRE(size <= 65536);
-
- worker = &sock->mgr->workers[sock->tid];
- INSIST(!worker->recvbuf_inuse);
-
- buf->base = worker->recvbuf;
- buf->len = size;
- worker->recvbuf_inuse = true;
-}
-
void
isc__nm_async_tcp_startread(isc__networker_t *worker, isc__netievent_t *ev0) {
isc__netievent_startread_t *ievent = (isc__netievent_startread_t *)ev0;
0);
}
- r = uv_read_start(&sock->uv_handle.stream, tcp_alloc_cb, read_cb);
+ r = uv_read_start(&sock->uv_handle.stream, isc__nm_alloc_cb, read_cb);
if (r != 0) {
isc__nm_incstats(sock->mgr, sock->statsindex[STATID_RECVFAIL]);
}
/*
* Accept callback for TCP-DNS connection.
*/
-static isc_result_t
+static void
dnslisten_acceptcb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
isc_nmsocket_t *dnslistensock = (isc_nmsocket_t *)cbarg;
isc_nmsocket_t *dnssock = NULL;
REQUIRE(VALID_NMSOCK(dnslistensock));
REQUIRE(dnslistensock->type == isc_nm_tcpdnslistener);
+ /* If accept() was unnsuccessful we can't do anything */
if (result != ISC_R_SUCCESS) {
- return (result);
+ return;
}
if (dnslistensock->accept_cb.accept != NULL) {
- result = dnslistensock->accept_cb.accept(
- handle, ISC_R_SUCCESS, dnslistensock->accept_cbarg);
- if (result != ISC_R_SUCCESS) {
- return (result);
- }
+ dnslistensock->accept_cb.accept(handle, ISC_R_SUCCESS,
+ dnslistensock->accept_cbarg);
}
/* We need to create a 'wrapper' dnssocket for this connection */
dnssock->read_timeout, 0);
isc_nm_read(handle, dnslisten_readcb, dnssock);
-
- return (ISC_R_SUCCESS);
}
/*
*/
isc_result_t
isc_nm_listentcpdns(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_recv_cb_t cb,
- void *cbarg, isc_nm_accept_cb_t accept_cb,
- void *accept_cbarg, size_t extrahandlesize, int backlog,
- isc_quota_t *quota, isc_nmsocket_t **sockp) {
+ void *cbarg, isc_nm_cb_t accept_cb, void *accept_cbarg,
+ size_t extrahandlesize, int backlog, isc_quota_t *quota,
+ isc_nmsocket_t **sockp) {
/* A 'wrapper' socket object with outer set to true TCP socket */
isc_nmsocket_t *dnslistensock = isc_mem_get(mgr->mctx,
sizeof(*dnslistensock));
atomic_store(&handle->sock->outer->keepalive, true);
}
+typedef struct tcpsend {
+ isc_mem_t *mctx;
+ isc_nmhandle_t *handle;
+ isc_region_t region;
+ isc_nmhandle_t *orighandle;
+ isc_nm_cb_t cb;
+ void *cbarg;
+} tcpsend_t;
+
static void
resume_processing(void *arg) {
isc_nmsocket_t *sock = (isc_nmsocket_t *)arg;
static void
tcpdnssend_cb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
- isc__nm_uvreq_t *req = (isc__nm_uvreq_t *)cbarg;
+ tcpsend_t *ts = (tcpsend_t *)cbarg;
UNUSED(handle);
- req->cb.send(req->handle, result, req->cbarg);
- isc_mem_put(req->sock->mgr->mctx, req->uvbuf.base, req->uvbuf.len);
- isc__nm_uvreq_put(&req, req->handle->sock);
-}
-
-void
-isc__nm_async_tcpdnssend(isc__networker_t *worker, isc__netievent_t *ev0) {
- isc_result_t result;
- isc__netievent_tcpdnssend_t *ievent =
- (isc__netievent_tcpdnssend_t *)ev0;
- isc__nm_uvreq_t *req = ievent->req;
- isc_nmsocket_t *sock = ievent->sock;
-
- REQUIRE(worker->id == sock->tid);
-
- result = ISC_R_NOTCONNECTED;
- if (atomic_load(&sock->active)) {
- isc_region_t r;
-
- r.base = (unsigned char *)req->uvbuf.base;
- r.length = req->uvbuf.len;
- result = isc__nm_tcp_send(sock->outer->tcphandle, &r,
- tcpdnssend_cb, req);
- }
+ ts->cb(ts->orighandle, result, ts->cbarg);
+ isc_mem_put(ts->mctx, ts->region.base, ts->region.length);
- if (result != ISC_R_SUCCESS) {
- req->cb.send(req->handle, result, req->cbarg);
- isc_mem_put(sock->mgr->mctx, req->uvbuf.base, req->uvbuf.len);
- isc__nm_uvreq_put(&req, sock);
- }
+ isc_nmhandle_unref(ts->orighandle);
+ isc_mem_putanddetach(&ts->mctx, ts, sizeof(*ts));
}
/*
isc_result_t
isc__nm_tcpdns_send(isc_nmhandle_t *handle, isc_region_t *region,
isc_nm_cb_t cb, void *cbarg) {
- isc__nm_uvreq_t *uvreq = NULL;
+ tcpsend_t *t = NULL;
REQUIRE(VALID_NMHANDLE(handle));
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock->type == isc_nm_tcpdnssocket);
- uvreq = isc__nm_uvreq_get(sock->mgr, sock);
- uvreq->handle = handle;
- isc_nmhandle_ref(uvreq->handle);
- uvreq->cb.send = cb;
- uvreq->cbarg = cbarg;
-
- uvreq->uvbuf.base = isc_mem_get(sock->mgr->mctx, region->length + 2);
- uvreq->uvbuf.len = region->length + 2;
- *(uint16_t *)uvreq->uvbuf.base = htons(region->length);
- memmove(uvreq->uvbuf.base + 2, region->base, region->length);
+ if (sock->outer == NULL) {
+ /* The socket is closed */
+ return (ISC_R_NOTCONNECTED);
+ }
- if (sock->tid == isc_nm_tid()) {
- isc_region_t r;
+ t = isc_mem_get(sock->mgr->mctx, sizeof(*t));
+ *t = (tcpsend_t){
+ .cb = cb,
+ .cbarg = cbarg,
+ .handle = handle->sock->outer->tcphandle,
+ };
- r.base = (unsigned char *)uvreq->uvbuf.base;
- r.length = uvreq->uvbuf.len;
+ isc_mem_attach(sock->mgr->mctx, &t->mctx);
+ t->orighandle = handle;
+ isc_nmhandle_ref(t->orighandle);
- return (isc__nm_tcp_send(sock->outer->tcphandle, &r,
- tcpdnssend_cb, uvreq));
- } else {
- isc__netievent_tcpdnssend_t *ievent = NULL;
+ t->region = (isc_region_t){ .base = isc_mem_get(t->mctx,
+ region->length + 2),
+ .length = region->length + 2 };
- ievent = isc__nm_get_ievent(sock->mgr, netievent_tcpdnssend);
- ievent->req = uvreq;
- ievent->sock = sock;
+ *(uint16_t *)t->region.base = htons(region->length);
+ memmove(t->region.base + 2, region->base, region->length);
- isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
- (isc__netievent_t *)ievent);
-
- return (ISC_R_SUCCESS);
- }
-
- return (ISC_R_UNEXPECTED);
+ return (isc_nm_send(t->handle, &t->region, tcpdnssend_cb, t));
}
static void
tcpdns_close_direct(isc_nmsocket_t *sock) {
REQUIRE(sock->tid == isc_nm_tid());
/* We don't need atomics here, it's all in single network thread */
-
if (sock->timer_initialized) {
/*
* We need to fire the timer callback to clean it up,
return (ISC_R_SUCCESS);
}
-/*%<
- * Allocator for UDP recv operations. Limited to size 20 * (2^16 + 2),
- * which allows enough space for recvmmsg() to get multiple messages at
- * a time.
- *
- * Note this doesn't actually allocate anything, it just assigns the
- * worker's receive buffer to a socket, and marks it as "in use".
- */
-static void
-udp_alloc_cb(uv_handle_t *handle, size_t size, uv_buf_t *buf) {
- isc_nmsocket_t *sock = uv_handle_get_data(handle);
- isc__networker_t *worker = NULL;
-
- REQUIRE(VALID_NMSOCK(sock));
- REQUIRE(sock->type == isc_nm_udpsocket);
- REQUIRE(isc__nm_in_netthread());
- REQUIRE(size <= ISC_NETMGR_RECVBUF_SIZE);
-
- worker = &sock->mgr->workers[sock->tid];
- INSIST(!worker->recvbuf_inuse);
-
- buf->base = worker->recvbuf;
- buf->len = ISC_NETMGR_RECVBUF_SIZE;
- worker->recvbuf_inuse = true;
-}
-
/*
* handle 'udplisten' async call - start listening on a socket.
*/
r = uv_udp_bind(&sock->uv_handle.udp,
&sock->parent->iface->addr.type.sa, uv_bind_flags);
- if (r == UV_EADDRNOTAVAIL &&
- isc__nm_socket_freebind(&sock->uv_handle.handle) == ISC_R_SUCCESS)
- {
- /*
- * Retry binding with IP_FREEBIND (or equivalent option) if the
- * address is not available. This helps with IPv6 tentative
- * addresses which are reported by the route socket, although
- * named is not yet able to properly bind to them.
- */
- r = uv_udp_bind(&sock->uv_handle.udp,
- &sock->parent->iface->addr.type.sa,
- uv_bind_flags);
- }
-
if (r < 0) {
isc__nm_incstats(sock->mgr, sock->statsindex[STATID_BINDFAIL]);
}
uv_send_buffer_size(&sock->uv_handle.handle,
&(int){ ISC_SEND_BUFFER_SIZE });
#endif
- uv_udp_recv_start(&sock->uv_handle.udp, udp_alloc_cb, udp_recv_cb);
+ uv_udp_recv_start(&sock->uv_handle.udp, isc__nm_alloc_cb, udp_recv_cb);
}
static void
stoplistening(isc_nmsocket_t *sock) {
REQUIRE(sock->type == isc_nm_udplistener);
+ /*
+ * Socket is already closing; there's nothing to do.
+ */
+ if (!isc__nmsocket_active(sock)) {
+ return;
+ }
+
+ /*
+ * Mark it inactive now so that all sends will be ignored
+ * and we won't try to stop listening again.
+ */
+ atomic_store(&sock->active, false);
+
for (int i = 0; i < sock->nchildren; i++) {
isc__netievent_udpstop_t *event = NULL;
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock->type == isc_nm_udplistener);
- /*
- * Socket is already closing; there's nothing to do.
- */
- if (!isc__nmsocket_active(sock)) {
- return;
- }
- /*
- * Mark it inactive now so that all sends will be ignored
- * and we won't try to stop listening again.
- */
- atomic_store(&sock->active, false);
-
/*
* If the manager is interlocked, re-enqueue this as an asynchronous
* event. Otherwise, go ahead and stop listening right away.
#endif
/*
- * Three reasons to return now without processing:
- * - If addr == NULL that's the end of stream - we can
- * free the buffer and bail.
- * - If we're simulating a firewall blocking UDP packets
- * bigger than 'maxudp' bytes for testing purposes.
- * - If the socket is no longer active.
+ * If addr == NULL that's the end of stream - we can
+ * free the buffer and bail.
*/
- maxudp = atomic_load(&sock->mgr->maxudp);
- if ((addr == NULL) || (maxudp != 0 && (uint32_t)nrecv > maxudp) ||
- (!isc__nmsocket_active(sock)))
- {
+ if (addr == NULL) {
if (free_buf) {
isc__nm_free_uvbuf(sock, buf);
}
return;
}
+ /*
+ * Simulate a firewall blocking UDP packets bigger than
+ * 'maxudp' bytes.
+ */
+ maxudp = atomic_load(&sock->mgr->maxudp);
+ if (maxudp != 0 && (uint32_t)nrecv > maxudp) {
+ return;
+ }
+
result = isc_sockaddr_fromsockaddr(&sockaddr, addr);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
nmhandle = isc__nmhandle_get(sock, &sockaddr, NULL);
uint32_t maxudp = atomic_load(&sock->mgr->maxudp);
/*
- * We're simulating a firewall blocking UDP packets bigger than
+ * Simulate a firewall blocking UDP packets bigger than
* 'maxudp' bytes, for testing purposes.
*
* The client would ordinarily have unreferenced the handle
REQUIRE(sock->tid == isc_nm_tid());
REQUIRE(sock->type == isc_nm_udpsocket);
- if (!isc__nmsocket_active(sock)) {
- return (ISC_R_CANCELED);
- }
isc_nmhandle_ref(req->handle);
rv = uv_udp_send(&req->uv_req.udp_send, &sock->uv_handle.udp,
&req->uvbuf, 1, &peer->type.sa, udp_send_cb);
void
ns__client_request(isc_nmhandle_t *handle, isc_region_t *region, void *arg) {
ns_client_t *client;
+ bool newclient = false;
ns_clientmgr_t *mgr;
ns_interface_t *ifp;
isc_result_t result;
}
#endif /* if NS_CLIENT_DROPPORT */
- env = ns_interfacemgr_getaclenv(client->manager->interface->mgr);
- if (client->sctx->blackholeacl != NULL &&
- (dns_acl_match(&netaddr, NULL, client->sctx->blackholeacl, env,
- &match, NULL) == ISC_R_SUCCESS) &&
- match > 0)
- {
- ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
- NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(10),
- "dropped request: blackholed peer");
- isc_task_unpause(client->task);
- return;
- }
-
ns_client_log(client, NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_CLIENT,
ISC_LOG_DEBUG(3), "%s request",
TCP_CLIENT(client) ? "TCP" : "UDP");
+ /*
+ * Check the blackhole ACL for UDP only, since TCP is done in
+ * client_newconn.
+ */
+ env = ns_interfacemgr_getaclenv(client->manager->interface->mgr);
+ if (newclient) {
+ if (client->sctx->blackholeacl != NULL &&
+ (dns_acl_match(&netaddr, NULL, client->sctx->blackholeacl,
+ env, &match, NULL) == ISC_R_SUCCESS) &&
+ match > 0)
+ {
+ ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
+ NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(10),
+ "blackholed UDP datagram");
+ isc_task_unpause(client->task);
+ return;
+ }
+ }
+
result = dns_message_peekheader(buffer, &id, &flags);
if (result != ISC_R_SUCCESS) {
/*
isc_task_unpause(client->task);
}
-isc_result_t
+void
ns__client_tcpconn(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
- ns_interface_t *ifp = (ns_interface_t *)arg;
- dns_aclenv_t *env = ns_interfacemgr_getaclenv(ifp->mgr);
- ns_server_t *sctx = ns_interfacemgr_getserver(ifp->mgr);
+ ns_server_t *sctx = (ns_server_t *)arg;
unsigned int tcpquota;
- isc_sockaddr_t peeraddr;
- isc_netaddr_t netaddr;
- int match;
+ UNUSED(handle);
UNUSED(result);
- if (handle != NULL) {
- peeraddr = isc_nmhandle_peeraddr(handle);
- isc_netaddr_fromsockaddr(&netaddr, &peeraddr);
-
- if (sctx->blackholeacl != NULL &&
- (dns_acl_match(&netaddr, NULL, sctx->blackholeacl, env,
- &match, NULL) == ISC_R_SUCCESS) &&
- match > 0)
- {
- return (ISC_R_CONNREFUSED);
- }
- }
-
tcpquota = isc_quota_getused(&sctx->tcpquota);
ns_stats_update_if_greater(sctx->nsstats, ns_statscounter_tcphighwater,
tcpquota);
-
- return (ISC_R_SUCCESS);
}
static void
* (Not intended for use outside this module and associated tests.)
*/
-isc_result_t
+void
ns__client_tcpconn(isc_nmhandle_t *handle, isc_result_t result, void *arg);
/*%<
bool
ns_interfacemgr_listeningon(ns_interfacemgr_t *mgr, const isc_sockaddr_t *addr);
-ns_server_t *
-ns_interfacemgr_getserver(ns_interfacemgr_t *mgr);
-/*%<
- * Returns the ns_server object associated with the interface manager.
- */
-
ns_interface_t *
ns__interfacemgr_getif(ns_interfacemgr_t *mgr);
ns_interface_t *
result = isc_nm_listentcpdns(
ifp->mgr->nm, (isc_nmiface_t *)&ifp->addr, ns__client_request,
- ifp, ns__client_tcpconn, ifp, sizeof(ns_client_t),
+ ifp, ns__client_tcpconn, ifp->mgr->sctx, sizeof(ns_client_t),
ifp->mgr->backlog, &ifp->mgr->sctx->tcpquota,
&ifp->tcplistensocket);
if (result != ISC_R_SUCCESS) {
* this is necessary because we are adding to the TCP quota just
* by listening.
*/
- result = ns__client_tcpconn(NULL, ISC_R_SUCCESS, ifp);
- if (result != ISC_R_SUCCESS) {
- isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
- "connecting TCP socket: %s",
- isc_result_totext(result));
- }
+ ns__client_tcpconn(NULL, ISC_R_SUCCESS, ifp->mgr->sctx);
#if 0
#ifndef ISC_ALLOW_MAPPED
return (result);
}
-ns_server_t *
-ns_interfacemgr_getserver(ns_interfacemgr_t *mgr) {
- REQUIRE(NS_INTERFACEMGR_VALID(mgr));
-
- return (mgr->sctx);
-}
-
ns_interface_t *
ns__interfacemgr_getif(ns_interfacemgr_t *mgr) {
ns_interface_t *head;
ns_interfacemgr_detach
ns_interfacemgr_dumprecursing
ns_interfacemgr_getaclenv
-ns_interfacemgr_getserver
ns_interfacemgr_islistening
ns_interfacemgr_listeningon
ns_interfacemgr_scan