spf_dns.c

Go to the documentation of this file.
00001 /* 
00002  * This program is free software; you can redistribute it and/or modify
00003  * it under the terms of either:
00004  * 
00005  *   a) The GNU Lesser General Public License as published by the Free
00006  *      Software Foundation; either version 2.1, or (at your option) any
00007  *      later version, 
00008  * 
00009  *   OR
00010  * 
00011  *   b) The two-clause BSD license.
00012  *
00013  * These licenses can be found with the distribution in the file LICENSES
00014  */
00015 
00016 
00017 #include "spf_sys_config.h"
00018 
00019 #ifdef STDC_HEADERS
00020 # include <stdio.h>        /* stdin / stdout */
00021 # include <stdlib.h>       /* malloc / free */
00022 #endif
00023 
00024 #ifdef HAVE_STRING_H
00025 # include <string.h>       /* strstr / strdup */
00026 #else
00027 # ifdef HAVE_STRINGS_H
00028 #  include <strings.h>       /* strstr / strdup */
00029 # endif
00030 #endif
00031 
00032 #ifdef HAVE_NETDB_H
00033 #include <netdb.h>
00034 #endif
00035 
00036 
00037 #include "spf.h"
00038 #include "spf_dns.h"
00039 #include "spf_internal.h"
00040 #include "spf_dns_internal.h"
00041 
00042 
00043 /*
00044  * helper functions
00045  */
00046 
00047 static void
00048 SPF_dns_debug_pre(SPF_dns_server_t *spf_dns_server, const char *domain,
00049                                 ns_type rr_type, int should_cache)
00050 {
00051         if (spf_dns_server->debug) {
00052                 SPF_debugf("DNS[%s] lookup: %s %s (%d)",
00053                         spf_dns_server->name, domain,
00054                         SPF_strrrtype(rr_type), rr_type);
00055         }
00056 }
00057 
00058 static void
00059 SPF_dns_debug_post(SPF_dns_server_t *spf_dns_server, SPF_dns_rr_t *spfrr)
00060 {
00061         if (spf_dns_server->debug) {
00062                 char    ip4_buf[ INET_ADDRSTRLEN ];
00063                 char    ip6_buf[ INET6_ADDRSTRLEN ];
00064                 int             i;
00065 
00066                 SPF_debugf("DNS[%s] found record", spf_dns_server->name);
00067                 SPF_debugf("    DOMAIN: %s  TYPE: %s (%d)",
00068                         spfrr->domain,
00069                         SPF_strrrtype(spfrr->rr_type), spfrr->rr_type);
00070                 SPF_debugf("    TTL: %ld  RR found: %d  herrno: %d  source: %s",
00071                         (long)spfrr->ttl, spfrr->num_rr, spfrr->herrno,
00072                         (spfrr->source
00073                                 ? (spfrr->source->name
00074                                         ? spfrr->source->name
00075                                         : "(unnamed source)")
00076                                 : "(null source)"));
00077                 for (i = 0; i < spfrr->num_rr; i++) {
00078                         switch (spfrr->rr_type) {
00079                                 case ns_t_a:
00080                                         SPF_debugf("    - A: %s",
00081                                                         inet_ntop(AF_INET, &(spfrr->rr[i]->a),
00082                                                                 ip4_buf, sizeof(ip4_buf)));
00083                                         break;
00084 
00085                                 case ns_t_ptr:
00086                                         SPF_debugf("    - PTR: %s", spfrr->rr[i]->ptr);
00087                                         break;
00088 
00089                                 case ns_t_mx:
00090                                         SPF_debugf("    - MX: %s", spfrr->rr[i]->mx);
00091                                         break;
00092 
00093                                 case ns_t_txt:
00094                                         SPF_debugf("    - TXT: %s", spfrr->rr[i]->txt);
00095                                         break;
00096 
00097                                 case ns_t_spf:
00098                                         SPF_debugf("    - SPF: %s", spfrr->rr[i]->txt);
00099                                         break;
00100 
00101                                 case ns_t_aaaa:
00102                                         SPF_debugf("    - AAAA: %s",
00103                                                         inet_ntop(AF_INET6, &(spfrr->rr[i]->aaaa),
00104                                                                 ip6_buf, sizeof(ip6_buf)));
00105                                         break;
00106 
00107                                 default:
00108                                         SPF_debugf("    - Unknown RR type");
00109                                         break;
00110                         }
00111                 }
00112         }
00113 }
00114 
00115 void
00116 SPF_dns_free(SPF_dns_server_t *spf_dns_server)
00117 {
00118         SPF_dns_server_t        *layer_below;
00119 
00120         SPF_ASSERT_NOTNULL(spf_dns_server);
00121         // SPF_ASSERT_NOTNULL(spf_dns_server->destroy);
00122         layer_below = spf_dns_server->layer_below;
00123 
00124         /* If this is not set, we assume someone else knows, and will destroy it. */
00125         if (spf_dns_server->destroy) {
00126                 spf_dns_server->destroy(spf_dns_server);
00127                 if (layer_below != NULL)
00128                         SPF_dns_free(layer_below);
00129         }
00130 }
00131 
00132 SPF_dns_rr_t *
00133 SPF_dns_lookup(SPF_dns_server_t *spf_dns_server, const char *domain,
00134                                 ns_type rr_type, int should_cache)
00135 {
00136         SPF_dns_rr_t    *spfrr;
00137         
00138         SPF_ASSERT_NOTNULL(spf_dns_server);
00139         SPF_dns_debug_pre(spf_dns_server, domain, rr_type, should_cache);
00140         SPF_ASSERT_NOTNULL(spf_dns_server->lookup);
00141         spfrr = spf_dns_server->lookup(spf_dns_server,
00142                                         domain, rr_type, should_cache);
00143         if (spfrr == NULL)
00144                 SPF_error( "SPF DNS layer return NULL during a lookup." );
00145         SPF_dns_debug_post(spf_dns_server, spfrr);
00146         return spfrr;
00147 }
00148 
00149 SPF_dns_rr_t *
00150 SPF_dns_rlookup(SPF_dns_server_t *spf_dns_server, struct in_addr ipv4,
00151                                 ns_type rr_type, int should_cache)
00152 {
00153         char                     domain[ sizeof("111.222.333.444.in-addr.arpa") ];
00154         union {
00155                 struct in_addr  ipv4;
00156                 unsigned char   x[4];
00157         } tmp;
00158 
00159         /*
00160          * make sure the scratch buffer is big enough
00161          */
00162         tmp.ipv4 = ipv4;
00163 
00164         snprintf(domain, sizeof(domain), "%d.%d.%d.%d.in-addr.arpa",
00165                  tmp.x[3], tmp.x[2], tmp.x[1], tmp.x[0]);
00166 
00167         return SPF_dns_lookup(spf_dns_server, domain, rr_type,should_cache);
00168 }
00169 
00170 SPF_dns_rr_t *
00171 SPF_dns_rlookup6(SPF_dns_server_t *spf_dns_server,
00172                                 struct in6_addr ipv6, ns_type rr_type, int should_cache)
00173 {
00174         char     domain[ sizeof(struct in6_addr) * 4 + sizeof(".ip6.arpa" ) + 1];  /* nibbles */
00175         char    *p, *p_end;
00176         int              i;
00177 
00178         p = domain;
00179         p_end = p + sizeof( domain );
00180                         
00181         for (i = sizeof(struct in6_addr) - 1; i >= 0; i--) {
00182                 p += snprintf(p, p_end - p, "%.1x.%.1x.",
00183                                         ipv6.s6_addr[i] & 0xf,
00184                                         ipv6.s6_addr[i] >> 4);
00185         }
00186 
00187         /* squash the final '.' */
00188         p += snprintf(p, p_end - p, "ip6.arpa");
00189 
00190         return SPF_dns_lookup(spf_dns_server, domain, rr_type, should_cache);
00191 }
00192 
00193 
00194 
00195 /* XXX FIXME */
00196 /*
00197  * Set the SMTP client domain name
00198  */
00199 
00205 char *
00206 SPF_dns_get_client_dom( SPF_dns_server_t *spf_dns_server,
00207                                 SPF_request_t *sr )
00208 {
00209         char     *client_dom;
00210         SPF_dns_rr_t *rr_ptr;
00211         SPF_dns_rr_t *rr_a;
00212         SPF_dns_rr_t *rr_aaaa;
00213         
00214         int             i, j;
00215         
00216         int             max_ptr;
00217 
00218         SPF_ASSERT_NOTNULL(spf_dns_server);
00219         SPF_ASSERT_NOTNULL(sr);
00220 
00221 
00222 /*
00223  * The "p" macro expands to the validated domain name of the SMTP
00224  * client.  The validation procedure is described in section 5.4.  If
00225  * there are no validated domain names, the word "unknown" is
00226  * substituted.  If multiple validated domain names exist, the first one
00227  * returned in the PTR result is chosen.
00228  *
00229  *
00230  *   sending-host_names := ptr_lookup(sending-host_IP);
00231  *   for each name in (sending-host_names) {
00232  *     IP_addresses := a_lookup(name);
00233  *     if the sending-host_IP is one of the IP_addresses {
00234  *       validated_sending-host_names += name;
00235  *   } }
00236  */
00237 
00238         if ( sr->client_ver == AF_INET ) {
00239                 rr_ptr = SPF_dns_rlookup( spf_dns_server, sr->ipv4, ns_t_ptr, FALSE );
00240                 
00241                 max_ptr = rr_ptr->num_rr;
00242                 /* XXX TODO? Or irrelevant?
00243                 if (max_ptr > sr->max_dns_ptr)
00244                         max_ptr = sr->max_dns_ptr;
00245                 */
00246                 /* XXX do we want to report if this is exceeded and we
00247                  * might've missed a validated name because of that?
00248                  */
00249                 if (max_ptr > SPF_MAX_DNS_PTR)
00250                         max_ptr = SPF_MAX_DNS_PTR;
00251 
00252                 for (i = 0; i < max_ptr; i++) {
00253                         rr_a = SPF_dns_lookup(spf_dns_server, rr_ptr->rr[i]->ptr, ns_t_a, FALSE);
00254 
00255                         for (j = 0; j < rr_a->num_rr; j++) {
00256                                 if (rr_a->rr[j]->a.s_addr == sr->ipv4.s_addr) {
00257                                         client_dom = strdup(rr_ptr->rr[i]->ptr);
00258                                         SPF_dns_rr_free(rr_ptr);
00259                                         SPF_dns_rr_free(rr_a);
00260                                         return client_dom;
00261                                 }
00262                         }
00263                         SPF_dns_rr_free(rr_a);
00264                 }
00265                 SPF_dns_rr_free(rr_ptr);
00266         }
00267                 
00268         else if ( sr->client_ver == AF_INET6 ) {
00269                 rr_ptr = SPF_dns_rlookup6( spf_dns_server, sr->ipv6, ns_t_ptr, FALSE );
00270 
00271                 max_ptr = rr_ptr->num_rr;
00272                 /*
00273                 if ( max_ptr > sr->max_dns_ptr )
00274                         max_ptr = sr->max_dns_ptr;
00275                 */
00276                 /* XXX do we want to report if this is exceeded and we
00277                  * might've missed a validated name because of that?
00278                  */
00279                 if ( max_ptr > SPF_MAX_DNS_PTR )
00280                         max_ptr = SPF_MAX_DNS_PTR;
00281 
00282                 for( i = 0; i < max_ptr; i++ ) {
00283                         rr_aaaa = SPF_dns_lookup( spf_dns_server, rr_ptr->rr[i]->ptr, ns_t_aaaa, FALSE );
00284 
00285                         for( j = 0; j < rr_aaaa->num_rr; j++ ) {
00286                                 if ( memcmp( &rr_aaaa->rr[j]->aaaa, &sr->ipv6,
00287                                                  sizeof( sr->ipv6 ) ) == 0 ) {
00288                                         client_dom = strdup( rr_ptr->rr[i]->ptr );
00289                                         SPF_dns_rr_free( rr_ptr );
00290                                         SPF_dns_rr_free( rr_aaaa );
00291                                         return client_dom;
00292                                 }
00293                         }
00294                         SPF_dns_rr_free( rr_aaaa );
00295                 }
00296                 SPF_dns_rr_free( rr_ptr );
00297         }
00298 
00299         return strdup( "unknown" );
00300 }

Generated on Tue Nov 4 13:27:39 2008 for libspf2 by  doxygen 1.5.4