libspf2 1.2.10
|
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("%s", " - 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 }