Back to index

courier  0.68.2
rfc1035qa.c
Go to the documentation of this file.
00001 /*
00002 ** Copyright 1998 - 2011 Double Precision, Inc.
00003 ** See COPYING for distribution information.
00004 */
00005 
00006 #include      "rfc1035.h"
00007 #include      <errno.h>
00008 #include      <string.h>
00009 #include      <stdlib.h>
00010 #include      <arpa/inet.h>
00011 
00012 /* Convenient function to do forward IP lookup */
00013 
00014 #if    RFC1035_IPV6
00015 
00016 static int rfc1035_a_ipv4(struct rfc1035_res *res,
00017        const char *name, struct in_addr **iaptr, unsigned *iasize)
00018 #else
00019 int rfc1035_a(struct rfc1035_res *res,
00020        const char *name, RFC1035_ADDR **iaptr, unsigned *iasize)
00021 #endif
00022 {
00023 struct rfc1035_reply *reply;
00024 int    n, o;
00025 char   namebuf[RFC1035_MAXNAMESIZE+1];
00026 
00027        namebuf[0]=0;
00028        strncat(namebuf, name, RFC1035_MAXNAMESIZE);
00029 
00030        *iasize=0;
00031        if (rfc1035_resolve_cname(res, namebuf,
00032               RFC1035_TYPE_A, RFC1035_CLASS_IN, &reply, 0) < 0 ||
00033               reply == 0 ||
00034               (n=rfc1035_replysearch_an( res, reply, namebuf, RFC1035_TYPE_A,
00035                      RFC1035_CLASS_IN, 0)) < 0)
00036        {
00037               if (reply && reply->rcode != RFC1035_RCODE_NXDOMAIN &&
00038                      reply->rcode != RFC1035_RCODE_NOERROR)
00039               {
00040                      errno=EAGAIN;
00041                      rfc1035_replyfree(reply);
00042                      return (1);   /* soft error */
00043               }
00044 
00045               if (reply) rfc1035_replyfree(reply);
00046               errno=ENOENT;
00047               return (-1); /* hard error */
00048        }
00049 
00050        for (o=n; o >= 0; o=rfc1035_replysearch_an(res, reply, namebuf,
00051                      RFC1035_TYPE_A, RFC1035_CLASS_IN, o+1))
00052               ++*iasize;
00053 
00054        if ( *iasize == 0 )
00055        {
00056               errno=EAGAIN;
00057               rfc1035_replyfree(reply);
00058               return (-1);
00059        }
00060 
00061        if ( (*iaptr=(struct in_addr *)malloc(sizeof(**iaptr)* *iasize)) == 0)
00062        {
00063               rfc1035_replyfree(reply);
00064               return (-1);
00065        }
00066 
00067        for (*iasize=0; n >= 0; n=rfc1035_replysearch_an(res, reply, namebuf,
00068                      RFC1035_TYPE_A, RFC1035_CLASS_IN, n+1))
00069        {
00070               (*iaptr)[*iasize]= reply->allrrs[n]->rr.inaddr;
00071               ++*iasize;
00072        }
00073 
00074        rfc1035_replyfree(reply);
00075        return (0);
00076 }
00077 
00078 #if    RFC1035_IPV6
00079 
00080 /*
00081 **     The IPv6 version issues two queries - for both A and AAAA records,
00082 **     then maps any A record to IPv6.
00083 **
00084 **     If we get back both an AAAA for the IPv4-mapped address, and the
00085 **     A record itself, ignore the dupe.
00086 */
00087 
00088 static int we_have_that_ipv4(struct in6_addr in6,
00089        const struct  in_addr       *ia4ptr,
00090        unsigned      ia4len)
00091 {
00092 char   buf[INET6_ADDRSTRLEN];
00093 const char *p;
00094 struct in_addr in4;
00095 unsigned i;
00096 
00097        if (!IN6_IS_ADDR_V4MAPPED((&in6))) return (0);   /* Not an IPv4 addy */
00098 
00099        if (inet_ntop(AF_INET6, &in6, buf, sizeof(buf)) == 0)
00100               return (0);   /* WTF??? */
00101 
00102        if ((p=strrchr(buf, ':')) != 0)
00103               ++p;
00104        else
00105               p=buf;
00106 
00107        rfc1035_aton_ipv4(p, &in4);
00108 
00109        for (i=0; i<ia4len; i++)
00110               if (ia4ptr[i].s_addr == in4.s_addr)       return (1);
00111        return (0);
00112 }
00113 
00114 int rfc1035_a(struct rfc1035_res *res,
00115        const char *name, struct in6_addr **iaptr, unsigned *iasize)
00116 {
00117 struct rfc1035_reply *reply;
00118 int    n, o;
00119 char   namebuf[RFC1035_MAXNAMESIZE+1];
00120 int    enotfound=0;
00121 
00122 struct in_addr       *ia4ptr;
00123 unsigned      ia4len;
00124 unsigned k;
00125 
00126        n=rfc1035_a_ipv4(res, name, &ia4ptr, &ia4len);
00127 
00128        if (n > 0) return (n);
00129        if (n < 0)
00130        {
00131               if (errno != ENOENT) return (n);
00132               ia4len=0;
00133               ia4ptr=0;
00134               enotfound=1;
00135        }
00136 
00137        namebuf[0]=0;
00138        strncat(namebuf, name, RFC1035_MAXNAMESIZE);
00139 
00140        *iasize=ia4len;
00141        reply=0;
00142 
00143        /*
00144        ** Resist the temptation to stick in "ia4len > 0 &&", below.  Why?
00145        ** A) We get a connection from an IPv6 address.
00146        ** B) Spam check: the IP address must resolve backwards and forwards.
00147        ** C) There are IPv4 records for the same hostname as well.
00148        ** D) This sux.
00149        */
00150 
00151        if (rfc1035_resolve_cname(res, namebuf,
00152               RFC1035_TYPE_AAAA, RFC1035_CLASS_IN, &reply, 0) < 0 ||
00153               reply == 0 ||
00154               (n=rfc1035_replysearch_an( res, reply, namebuf,
00155                                       RFC1035_TYPE_AAAA,
00156                                       RFC1035_CLASS_IN, 0)) < 0)
00157        {
00158               if (reply && reply->rcode != RFC1035_RCODE_NXDOMAIN &&
00159                      reply->rcode != RFC1035_RCODE_NOERROR &&
00160                      *iasize == 0)
00161                      /* Unfortunately this is necessary.  Some swervers
00162                      ** return a TEMPFAIL for AAAA queries.
00163                      */
00164               {
00165                      errno=EAGAIN;
00166                      rfc1035_replyfree(reply);
00167                      if (ia4len)
00168                             free(ia4ptr);
00169                      return (1);   /* soft error */
00170               }
00171 
00172               if (reply) rfc1035_replyfree(reply);
00173               if (enotfound)
00174                      return (-1);
00175               enotfound=1;
00176               reply=0;
00177               n= -1;
00178        }
00179        else
00180        {
00181               for (o=n; o >= 0; o=rfc1035_replysearch_an(res, reply, namebuf,
00182                             RFC1035_TYPE_AAAA, RFC1035_CLASS_IN, o+1))
00183               {
00184                      if (we_have_that_ipv4(reply->allrrs[n]->rr.in6addr,
00185                             ia4ptr, ia4len))
00186                             continue;
00187 
00188                      ++*iasize;
00189               }
00190        }
00191 
00192        if ( *iasize == 0 && enotfound)
00193        {
00194               if (ia4len)
00195                      free(ia4ptr);
00196               errno=ENOENT;
00197               return (-1);
00198        }
00199 
00200        if ( *iasize == 0 )
00201        {
00202               errno=EAGAIN;
00203               rfc1035_replyfree(reply);
00204               return (-1);
00205        }
00206 
00207        if ( (*iaptr=(struct in6_addr *)malloc(sizeof(**iaptr)* *iasize)) == 0)
00208        {
00209               rfc1035_replyfree(reply);
00210               return (-1);
00211        }
00212 
00213        for (*iasize=0; n >= 0; n=rfc1035_replysearch_an(res, reply, namebuf,
00214                      RFC1035_TYPE_AAAA, RFC1035_CLASS_IN, n+1))
00215        {
00216               if (we_have_that_ipv4(reply->allrrs[n]->rr.in6addr,
00217                      ia4ptr, ia4len))
00218                      continue;
00219               (*iaptr)[*iasize]= reply->allrrs[n]->rr.in6addr;
00220               ++*iasize;
00221        }
00222 
00223        for (k=0; k<ia4len; k++)
00224        {
00225        char   buf[INET6_ADDRSTRLEN];
00226 
00227               strcpy(buf, "::ffff:");
00228               rfc1035_ntoa_ipv4( &ia4ptr[k], buf+sizeof("::ffff:")-1);
00229               if (inet_pton( AF_INET6, buf, (*iaptr)+ *iasize) <= 0)
00230                      memset( (*iaptr)+ *iasize, 0, sizeof(*iaptr));
00231               ++*iasize;
00232        }
00233        if (ia4len)
00234               free (ia4ptr);
00235        rfc1035_replyfree(reply);
00236        return (0);
00237 }
00238 #endif