diff --git a/bin/named/client.c b/bin/named/client.c index 6a971ddc5f..7061ce05f7 100644 --- a/bin/named/client.c +++ b/bin/named/client.c @@ -599,6 +599,7 @@ ns_client_send(ns_client_t *client) { isc_region_t r; isc_socket_t *socket; isc_sockaddr_t *address; + struct in6_pktinfo *pktinfo; unsigned int bufsize = 512; REQUIRE(NS_CLIENT_VALID(client)); @@ -683,8 +684,12 @@ ns_client_send(ns_client_t *client) { isc_buffer_used(&buffer, &r); } CTRACE("sendto"); + if ((client->attributes & NS_CLIENTATTR_PKTINFO) != 0) + pktinfo = &client->pktinfo; + else + pktinfo = NULL; result = isc_socket_sendto(socket, &r, client->task, client_senddone, - client, address, NULL); + client, address, pktinfo); if (result == ISC_R_SUCCESS) { client->nsends++; return; @@ -812,17 +817,25 @@ client_request(isc_task_t *task, isc_event_t *event) { RWLOCK(&ns_g_server->conflock, isc_rwlocktype_read); dns_zonemgr_lockconf(ns_g_server->zonemgr, isc_rwlocktype_read); - + if (event->type == DNS_EVENT_DISPATCH) { - INSIST(! TCP_CLIENT(client)); + INSIST(!TCP_CLIENT(client)); devent = (dns_dispatchevent_t *)event; REQUIRE(client->dispentry != NULL); client->dispevent = devent; buffer = &devent->buffer; result = devent->result; client->peeraddr = devent->addr; + if ((devent->attributes & DNS_DISPATCHATTR_PKTINFO) != 0) { + client->attributes |= NS_CLIENTATTR_PKTINFO; + client->pktinfo = devent->pktinfo; + printf("client: interface %u\n", + client->pktinfo.ipi6_ifindex); + } else { + client->attributes &= ~NS_CLIENTATTR_PKTINFO; + } } else { - INSIST(TCP_CLIENT(client)); + INSIST(TCP_CLIENT(client)); REQUIRE(event->type == DNS_EVENT_TCPMSG); REQUIRE(event->sender == &client->tcpmsg); buffer = &client->tcpmsg.buffer; diff --git a/bin/named/include/named/client.h b/bin/named/include/named/client.h index 45004cad99..b2637cf443 100644 --- a/bin/named/include/named/client.h +++ b/bin/named/include/named/client.h @@ -118,6 +118,7 @@ struct ns_client { isc_quota_t *recursionquota; ns_interface_t *interface; isc_sockaddr_t peeraddr; + struct in6_pktinfo pktinfo; ISC_LINK(ns_client_t) link; client_list_t *list; /* The list 'link' is part of, or NULL if not on any list. */ @@ -129,6 +130,7 @@ struct ns_client { #define NS_CLIENTATTR_TCP 0x01 #define NS_CLIENTATTR_RA 0x02 /* Client gets recusive service */ +#define NS_CLIENTATTR_PKTINFO 0x04 /* pktinfo is valid */ /*** *** Functions diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c index 82842dc102..87b0cb7842 100644 --- a/lib/dns/dispatch.c +++ b/lib/dns/dispatch.c @@ -394,6 +394,7 @@ udp_recv(isc_task_t *task, isc_event_t *ev_in) isc_boolean_t killit; isc_boolean_t queue_request; isc_boolean_t queue_response; + unsigned int attributes; (void)task; /* shut up compiler */ @@ -520,12 +521,20 @@ udp_recv(isc_task_t *task, isc_event_t *ev_in) rev->result = DNS_R_SUCCESS; rev->id = id; rev->addr = ev->address; + attributes = 0; + if ((ev->attributes & ISC_SOCKEVENTATTR_PKTINFO) != 0) { + rev->pktinfo = ev->pktinfo; + attributes |= DNS_DISPATCHATTR_PKTINFO; + } else { + attributes &= ~DNS_DISPATCHATTR_PKTINFO; + } if (queue_request) { ISC_LIST_APPEND(disp->rq_events, rev, link); } else if (queue_response) { ISC_LIST_APPEND(resp->items, rev, link); } else { - ISC_EVENT_INIT(rev, sizeof(*rev), 0, NULL, DNS_EVENT_DISPATCH, + ISC_EVENT_INIT(rev, sizeof(*rev), attributes, NULL, + DNS_EVENT_DISPATCH, resp->action, resp->arg, resp, NULL, NULL); XDEBUG(("Sent event %p buffer %p len %d to task %p, resp %p\n", rev, rev->buffer.base, rev->buffer.length, diff --git a/lib/dns/include/dns/dispatch.h b/lib/dns/include/dns/dispatch.h index a775737235..5355ee0064 100644 --- a/lib/dns/include/dns/dispatch.h +++ b/lib/dns/include/dns/dispatch.h @@ -84,9 +84,15 @@ struct dns_dispatchevent { isc_result_t result; /* result code */ isc_int32_t id; /* message id */ isc_sockaddr_t addr; /* address recv'd from */ + struct in6_pktinfo pktinfo; /* reply info for v6 */ isc_buffer_t buffer; /* data buffer */ }; +/* + * event attributes + */ +#define DNS_DISPATCHATTR_PKTINFO 0x00100000U + /* * Functions to: * diff --git a/lib/isc/include/isc/socket.h b/lib/isc/include/isc/socket.h index ce0178216f..d68d5cb16d 100644 --- a/lib/isc/include/isc/socket.h +++ b/lib/isc/include/isc/socket.h @@ -128,12 +128,12 @@ struct isc_socket_connev { * _TIMESTAMP: The timestamp member is valid. * _PKTINFO: The pktinfo member is valid. */ -#define ISC_SOCKEVENTATTR_ATTACHED 0x8000000U /* internal */ -#define ISC_SOCKEVENTATTR_FATALERROR 0x4000000U /* sock is dead */ -#define ISC_SOCKEVENTATTR_TRUNC 0x0080000U /* public */ -#define ISC_SOCKEVENTATTR_CTRUNC 0x0040000U /* public */ -#define ISC_SOCKEVENTATTR_TIMESTAMP 0x0020000U /* public */ -#define ISC_SOCKEVENTATTR_PKTINFO 0x0010000U /* public */ +#define ISC_SOCKEVENTATTR_ATTACHED 0x80000000U /* internal */ +#define ISC_SOCKEVENTATTR_FATALERROR 0x40000000U /* sock is dead */ +#define ISC_SOCKEVENTATTR_TRUNC 0x00800000U /* public */ +#define ISC_SOCKEVENTATTR_CTRUNC 0x00400000U /* public */ +#define ISC_SOCKEVENTATTR_TIMESTAMP 0x00200000U /* public */ +#define ISC_SOCKEVENTATTR_PKTINFO 0x00100000U /* public */ #define ISC_SOCKEVENT_ANYEVENT (0) #define ISC_SOCKEVENT_RECVDONE (ISC_EVENTCLASS_SOCKET + 1) diff --git a/lib/isc/unix/socket.c b/lib/isc/unix/socket.c index bb799ef32a..f0346e3d80 100644 --- a/lib/isc/unix/socket.c +++ b/lib/isc/unix/socket.c @@ -368,7 +368,8 @@ process_cmsg(isc_socket_t *sock, struct msghdr *msg, isc_socketevent_t *dev) if (cmsgp->cmsg_level == IPPROTO_IPV6 && cmsgp->cmsg_type == IPV6_PKTINFO) { pktinfop = (struct in6_pktinfo *)CMSG_DATA(cmsgp); - dev->pktinfo = *pktinfop; + memcpy(&dev->pktinfo, pktinfop, + sizeof(struct in6_pktinfo)); dev->attributes |= ISC_SOCKEVENTATTR_PKTINFO; goto next; } @@ -496,7 +497,7 @@ build_msghdr_send(isc_socket_t *sock, isc_socketevent_t *dev, cmsgp->cmsg_type = IPV6_PKTINFO; cmsgp->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); pktinfop = (struct in6_pktinfo *)CMSG_DATA(cmsgp); - *pktinfop = dev->pktinfo; + memcpy(pktinfop, &dev->pktinfo, sizeof(struct in6_pktinfo)); } #endif /* USE_CMSG */ #else /* ISC_NET_BSD44MSGHDR */