This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |
Other format: | [Raw text] |
Ping! On Tue, Apr 22, 2014 at 03:16:00PM +0530, Siddhesh Poyarekar wrote: > Ping! > > On Tue, Apr 15, 2014 at 09:59:02PM +0530, Siddhesh Poyarekar wrote: > > AF_UNSPEC results in sending two queries in parallel, one for the A > > record and the other for the AAAA record. If one of these is a > > referral, then the query fails, which is wrong. It should return at > > least the one successful response. > > > > The fix has two parts. The first part makes the referral fall back to > > the SERVFAIL path, which results in using the successful response. > > There is a bug in that path however, due to which the second part is > > necessary. The bug here is that if the first response is a failure > > and the second succeeds, __libc_res_nsearch does not detect that and > > assumes a failure. The case where the first response is a success and > > the second fails, works correctly. > > > > This condition is produced by buggy routers, so here's a crude > > interposable library that can simulate such a condition. The library > > overrides the recvfrom syscall and modifies the header of the packet > > received to reproduce this scenario. It has two key variables: > > mod_packet and first_error. > > > > The mod_packet variable when set to 0, results in odd packets being > > modified to be a referral. When set to 1, even packets are modified > > to be a referral. > > > > The first_error causes the first response to be a failure so that a > > domain-appended search is performed to test the second part of the > > __libc_nsearch fix. > > > > The driver for this fix is a simple getaddrinfo program that does an > > AF_UNSPEC query. I have omitted this since it should be easy to > > implement. > > > > I have tested this on x86_64. > > > > The interceptor library source: > > > > /* Override recvfrom and modify the header of the first DNS response to make it > > a referral and reproduce bz #845218. We have to resort to this ugly hack > > because we cannot make bind return the buggy response of a referral for the > > AAAA record and an authoritative response for the A record. */ > > #define _GNU_SOURCE > > #include <sys/types.h> > > #include <sys/socket.h> > > #include <netinet/in.h> > > #include <arpa/inet.h> > > #include <stdio.h> > > #include <stdbool.h> > > #include <endian.h> > > #include <dlfcn.h> > > #include <stdlib.h> > > > > /* Lifted from resolv/arpa/nameser_compat.h. */ > > typedef struct { > > unsigned id :16; /*%< query identification number */ > > #if BYTE_ORDER == BIG_ENDIAN > > /* fields in third byte */ > > unsigned qr: 1; /*%< response flag */ > > unsigned opcode: 4; /*%< purpose of message */ > > unsigned aa: 1; /*%< authoritive answer */ > > unsigned tc: 1; /*%< truncated message */ > > unsigned rd: 1; /*%< recursion desired */ > > /* fields > > * in > > * fourth > > * byte > > * */ > > unsigned ra: 1; /*%< recursion available */ > > unsigned unused :1; /*%< unused bits (MBZ as of 4.9.3a3) */ > > unsigned ad: 1; /*%< authentic data from named */ > > unsigned cd: 1; /*%< checking disabled by resolver */ > > unsigned rcode :4; /*%< response code */ > > #endif > > #if BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN > > /* fields > > * in > > * third > > * byte > > * */ > > unsigned rd :1; /*%< recursion desired */ > > unsigned tc :1; /*%< truncated message */ > > unsigned aa :1; /*%< authoritive answer */ > > unsigned opcode :4; /*%< purpose of message */ > > unsigned qr :1; /*%< response flag */ > > /* fields > > * in > > * fourth > > * byte > > * */ > > unsigned rcode :4; /*%< response code */ > > unsigned cd: 1; /*%< checking disabled by resolver */ > > unsigned ad: 1; /*%< authentic data from named */ > > unsigned unused :1; /*%< unused bits (MBZ as of 4.9.3a3) */ > > unsigned ra :1; /*%< recursion available */ > > #endif > > /* remaining > > * bytes > > * */ > > unsigned qdcount :16; /*%< number of question entries */ > > unsigned ancount :16; /*%< number of answer entries */ > > unsigned nscount :16; /*%< number of authority entries */ > > unsigned arcount :16; /*%< number of resource entries */ > > } HEADER; > > > > static int done = 0; > > > > /* Packets to modify. 0 for the odd packets and 1 for even packets. */ > > static const int mod_packet = 0; > > > > /* Set to true if the first request should result in an error, resulting in a > > search query. */ > > static bool first_error = true; > > > > static ssize_t (*real_recvfrom) (int sockfd, void *buf, size_t len, int flags, > > struct sockaddr *src_addr, socklen_t *addrlen); > > > > void > > __attribute__ ((constructor)) > > init (void) > > { > > real_recvfrom = dlsym (RTLD_NEXT, "recvfrom"); > > > > if (real_recvfrom == NULL) > > { > > printf ("Failed to get reference to recvfrom: %s\n", dlerror ()); > > printf ("Cannot simulate test\n"); > > abort (); > > } > > } > > > > /* Modify the second packet that we receive to set the header in a manner as to > > reproduce BZ #845218. */ > > static void > > mod_buf (HEADER *h, int port) > > { > > if (done % 2 == mod_packet || (first_error && done == 1)) > > { > > printf ("(Modifying header)"); > > > > if (first_error && done == 1) > > h->rcode = 3; > > else > > h->rcode = 0; /* NOERROR == 0. */ > > h->ancount = 0; > > h->aa = 0; > > h->ra = 0; > > h->arcount = 0; > > } > > done++; > > } > > > > ssize_t > > recvfrom (int sockfd, void *buf, size_t len, int flags, > > struct sockaddr *src_addr, socklen_t *addrlen) > > { > > ssize_t ret = real_recvfrom (sockfd, buf, len, flags, src_addr, addrlen); > > int port = htons (((struct sockaddr_in *) src_addr)->sin_port); > > struct in_addr addr = ((struct sockaddr_in *) src_addr)->sin_addr; > > const char *host = inet_ntoa (addr); > > printf ("\n*** From %s:%d: ", host, port); > > > > mod_buf (buf, port); > > > > printf ("returned %zd\n", ret); > > return ret; > > } > > > > > > [BZ #14308] > > * resolv/res_query.c (__libc_res_nsearch): Return if at least > > one response is valid. > > * resolv/res_send.c (send_dg): Check for validity of other > > response if the current response is a referral. > > > > --- > > resolv/res_query.c | 7 +++++-- > > resolv/res_send.c | 2 +- > > 2 files changed, 6 insertions(+), 3 deletions(-) > > > > diff --git a/resolv/res_query.c b/resolv/res_query.c > > index a9db837..4e6612c 100644 > > --- a/resolv/res_query.c > > +++ b/resolv/res_query.c > > @@ -382,7 +382,9 @@ __libc_res_nsearch(res_state statp, > > answer, anslen, answerp, > > answerp2, nanswerp2, resplen2, > > answerp2_malloced); > > - if (ret > 0 || trailing_dot) > > + if (ret > 0 || trailing_dot > > + /* If the second response is valid then we use that. */ > > + || (ret == 0 && answerp2 != NULL && resplen2 > 0)) > > return (ret); > > saved_herrno = h_errno; > > tried_as_is++; > > @@ -422,7 +424,8 @@ __libc_res_nsearch(res_state statp, > > answer, anslen, answerp, > > answerp2, nanswerp2, > > resplen2, answerp2_malloced); > > - if (ret > 0) > > + if (ret > 0 || (ret == 0 && answerp2 != NULL > > + && resplen2 > 0)) > > return (ret); > > > > if (answerp && *answerp != answer) { > > diff --git a/resolv/res_send.c b/resolv/res_send.c > > index 60743df..3273d55 100644 > > --- a/resolv/res_send.c > > +++ b/resolv/res_send.c > > @@ -1351,6 +1351,7 @@ send_dg(res_state statp, > > (*thisresplenp > *thisanssizp) > > ? *thisanssizp : *thisresplenp); > > > > + next_ns: > > if (recvresp1 || (buf2 != NULL && recvresp2)) { > > *resplen2 = 0; > > return resplen; > > @@ -1368,7 +1369,6 @@ send_dg(res_state statp, > > goto wait; > > } > > > > - next_ns: > > __res_iclose(statp, false); > > /* don't retry if called from dig */ > > if (!statp->pfcode) > > -- > > 1.8.3.1 > > > >
Attachment:
pgpMqD4Vdr1q5.pgp
Description: PGP signature
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |