diff --git a/CHANGES b/CHANGES index fd058c7b04..c5480469fe 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,5 @@ +4950. [bug] ISC_SOCKEVENTATTR_TRUNC was not be set. [GL #238] + 4949. [bug] lib/isc/print.c failed to handle floating point output correctly. [GL #261] diff --git a/lib/isc/tests/socket_test.c b/lib/isc/tests/socket_test.c index 8122e1bcc1..c9a1571973 100644 --- a/lib/isc/tests/socket_test.c +++ b/lib/isc/tests/socket_test.c @@ -28,6 +28,7 @@ static isc_boolean_t recv_dscp; static unsigned int recv_dscp_value; +static isc_boolean_t recv_trunc; /* * Helper functions @@ -73,8 +74,10 @@ event_done(isc_task_t *task, isc_event_t *event) { if ((dev->attributes & ISC_SOCKEVENTATTR_DSCP) != 0) { recv_dscp = ISC_TRUE; recv_dscp_value = dev->dscp;; - } else + } else { recv_dscp = ISC_FALSE; + } + recv_trunc = ISC_TF((dev->attributes & ISC_SOCKEVENTATTR_TRUNC) != 0); isc_event_free(&event); } @@ -777,6 +780,131 @@ ATF_TC_BODY(net_probedscp, tc) { #endif } +/* Test UDP truncation detection */ +ATF_TC(udp_trunc); +ATF_TC_HEAD(udp_trunc, tc) { + atf_tc_set_md_var(tc, "descr", "UDP Truncation detection"); +} +ATF_TC_BODY(udp_trunc, tc) { + isc_result_t result; + isc_sockaddr_t addr1, addr2; + struct in_addr in; + isc_socket_t *s1 = NULL, *s2 = NULL; + isc_task_t *task = NULL; + char sendbuf[BUFSIZ*2], recvbuf[BUFSIZ]; + completion_t completion; + isc_region_t r; + isc_socketevent_t *socketevent; + + UNUSED(tc); + + result = isc_test_begin(NULL, ISC_TRUE, 0); + ATF_REQUIRE_EQ(result, ISC_R_SUCCESS); + + in.s_addr = inet_addr("127.0.0.1"); + isc_sockaddr_fromin(&addr1, &in, 0); + isc_sockaddr_fromin(&addr2, &in, 0); + + result = isc_socket_create(socketmgr, PF_INET, isc_sockettype_udp, &s1); + ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s", + isc_result_totext(result)); + result = isc_socket_bind(s1, &addr1, ISC_SOCKET_REUSEADDRESS); + ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s", + isc_result_totext(result)); + result = isc_socket_getsockname(s1, &addr1); + ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s", + isc_result_totext(result)); + ATF_REQUIRE(isc_sockaddr_getport(&addr1) != 0); + + result = isc_socket_create(socketmgr, PF_INET, isc_sockettype_udp, &s2); + ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s", + isc_result_totext(result)); + result = isc_socket_bind(s2, &addr2, ISC_SOCKET_REUSEADDRESS); + ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s", + isc_result_totext(result)); + result = isc_socket_getsockname(s2, &addr2); + ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s", + isc_result_totext(result)); + ATF_REQUIRE(isc_sockaddr_getport(&addr2) != 0); + + result = isc_task_create(taskmgr, 0, &task); + ATF_CHECK_EQ_MSG(result, ISC_R_SUCCESS, "%s", + isc_result_totext(result)); + + /* + * Send a message that will not be truncated. + */ + memset(sendbuf, 0xff, sizeof(sendbuf)); + snprintf(sendbuf, sizeof(sendbuf), "Hello"); + r.base = (void *) sendbuf; + r.length = strlen(sendbuf) + 1; + + completion_init(&completion); + + socketevent = isc_socket_socketevent(mctx, s1, ISC_SOCKEVENT_SENDDONE, + event_done, &completion); + ATF_REQUIRE(socketevent != NULL); + + result = isc_socket_sendto2(s1, &r, task, &addr2, NULL, socketevent, 0); + ATF_REQUIRE_EQ_MSG(result, ISC_R_SUCCESS, "%s", + isc_result_totext(result)); + waitfor(&completion); + ATF_CHECK(completion.done); + ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS); + + r.base = (void *) recvbuf; + r.length = BUFSIZ; + completion_init(&completion); + recv_trunc = ISC_FALSE; + result = isc_socket_recv(s2, &r, 1, task, event_done, &completion); + ATF_CHECK_EQ(result, ISC_R_SUCCESS); + waitfor(&completion); + ATF_CHECK(completion.done); + ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS); + ATF_CHECK_STREQ(recvbuf, "Hello"); + ATF_CHECK_EQ(recv_trunc, ISC_FALSE); + + /* + * Send a message that will be truncated. + */ + memset(sendbuf, 0xff, sizeof(sendbuf)); + snprintf(sendbuf, sizeof(sendbuf), "Hello"); + r.base = (void *) sendbuf; + r.length = sizeof(sendbuf); + + completion_init(&completion); + + socketevent = isc_socket_socketevent(mctx, s1, ISC_SOCKEVENT_SENDDONE, + event_done, &completion); + ATF_REQUIRE(socketevent != NULL); + + result = isc_socket_sendto2(s1, &r, task, &addr2, NULL, socketevent, 0); + ATF_REQUIRE_EQ_MSG(result, ISC_R_SUCCESS, "%s", + isc_result_totext(result)); + waitfor(&completion); + ATF_CHECK(completion.done); + ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS); + + r.base = (void *) recvbuf; + r.length = BUFSIZ; + completion_init(&completion); + recv_trunc = ISC_FALSE; + result = isc_socket_recv(s2, &r, 1, task, event_done, &completion); + ATF_CHECK_EQ(result, ISC_R_SUCCESS); + waitfor(&completion); + ATF_CHECK(completion.done); + ATF_CHECK_EQ(completion.result, ISC_R_SUCCESS); + ATF_CHECK_STREQ(recvbuf, "Hello"); + ATF_CHECK_EQ(recv_trunc, ISC_TRUE); + + isc_task_detach(&task); + + isc_socket_detach(&s1); + isc_socket_detach(&s2); + + isc_test_end(); +} + /* * Main */ @@ -788,6 +916,7 @@ ATF_TP_ADD_TCS(tp) { ATF_TP_ADD_TC(tp, udp_dscp_v4); ATF_TP_ADD_TC(tp, udp_dscp_v6); ATF_TP_ADD_TC(tp, net_probedscp); + ATF_TP_ADD_TC(tp, udp_trunc); return (atf_no_error()); } diff --git a/lib/isc/unix/socket.c b/lib/isc/unix/socket.c index 7fe982d493..03226e24ff 100644 --- a/lib/isc/unix/socket.c +++ b/lib/isc/unix/socket.c @@ -372,7 +372,7 @@ struct isc__socket { active : 1, /* currently active */ pktdscp : 1; /* per packet dscp */ -#ifdef ISC_NET_RECVOVERFLOW +#ifdef ISC_PLATFORM_RECVOVERFLOW unsigned char overflow; /* used for MSG_TRUNC fake */ #endif @@ -464,7 +464,7 @@ static isc__socketmgr_t *socketmgr = NULL; * send() and recv() iovec counts */ #define MAXSCATTERGATHER_SEND (ISC_SOCKET_MAXSCATTERGATHER) -#ifdef ISC_NET_RECVOVERFLOW +#ifdef ISC_PLATFORM_RECVOVERFLOW # define MAXSCATTERGATHER_RECV (ISC_SOCKET_MAXSCATTERGATHER + 1) #else # define MAXSCATTERGATHER_RECV (ISC_SOCKET_MAXSCATTERGATHER) @@ -1700,10 +1700,6 @@ build_msghdr_recv(isc__socket_t *sock, isc_socketevent_t *dev, #else msg->msg_name = (void *)&dev->address.type.sa; msg->msg_namelen = sizeof(dev->address.type); -#endif -#ifdef ISC_NET_RECVOVERFLOW - /* If needed, steal one iovec for overflow detection. */ - maxiov--; #endif } else { /* TCP */ msg->msg_name = NULL; @@ -1755,12 +1751,11 @@ build_msghdr_recv(isc__socket_t *sock, isc_socketevent_t *dev, config: /* - * If needed, set up to receive that one extra byte. Note that - * we know there is at least one iov left, since we stole it - * at the top of this function. + * If needed, set up to receive that one extra byte. */ -#ifdef ISC_NET_RECVOVERFLOW +#ifdef ISC_PLATFORM_RECVOVERFLOW if (sock->type == isc_sockettype_udp) { + INSIST(iovcount < MAXSCATTERGATHER_RECV); iov[iovcount].iov_base = (void *)(&sock->overflow); iov[iovcount].iov_len = 1; iovcount++; @@ -1997,7 +1992,7 @@ doio_recv(isc__socket_t *sock, isc_socketevent_t *dev) { * this indicates an overflow situation. Set the flag in the * dev entry and adjust how much we read by one. */ -#ifdef ISC_NET_RECVOVERFLOW +#ifdef ISC_PLATFORM_RECVOVERFLOW if ((sock->type == isc_sockettype_udp) && ((size_t)cc > read_count)) { dev->attributes |= ISC_SOCKEVENTATTR_TRUNC; cc--;