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 #ifdef _WIN32 00017 00018 #include "spf_sys_config.h" 00019 00020 #ifdef HAVE_ERRNO_H 00021 #include <errno.h> 00022 #endif 00023 00024 #ifdef STDC_HEADERS 00025 # include <stdio.h> /* stdin / stdout */ 00026 # include <stdlib.h> /* malloc / free */ 00027 #endif 00028 00029 #ifdef HAVE_STRING_H 00030 # include <string.h> /* strstr / strdup */ 00031 #else 00032 # ifdef HAVE_STRINGS_H 00033 # include <strings.h> /* strstr / strdup */ 00034 # endif 00035 #endif 00036 00037 #include "spf.h" 00038 #include "spf_dns.h" 00039 #include "spf_internal.h" 00040 #include "spf_dns_internal.h" 00041 #include "spf_dns_windns.h" 00042 #pragma comment(lib, "dnsapi.lib") 00043 #include <windns.h> 00044 00045 00046 typedef struct 00047 { 00048 int debug; 00049 SPF_dns_rr_t spfrr; 00050 } SPF_dns_windns_config_t; 00051 00052 00053 #define SPF_h_errno WSAGetLastError() 00054 00055 00056 static inline SPF_dns_windns_config_t *SPF_voidp2spfhook( void *hook ) 00057 { return (SPF_dns_windns_config_t *)hook; } 00058 static inline void *SPF_spfhook2voidp( SPF_dns_windns_config_t *spfhook ) 00059 { return (void *)spfhook; } 00060 00061 00062 LPSTR SPF_dns_create_error_message_windns(DWORD last_error) 00063 { 00064 LPSTR error_message; 00065 00066 if (!FormatMessageA( 00067 (FORMAT_MESSAGE_ALLOCATE_BUFFER | 00068 FORMAT_MESSAGE_FROM_SYSTEM | 00069 FORMAT_MESSAGE_IGNORE_INSERTS), 00070 NULL, 00071 last_error, 00072 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language 00073 (LPSTR) &error_message, 00074 0, 00075 NULL)) 00076 { 00077 return NULL; 00078 } 00079 00080 return error_message; 00081 } 00082 00083 00084 void SPF_dns_destroy_error_message_windns(LPSTR error_message) 00085 { 00086 LocalFree( error_message ); 00087 } 00088 00089 00090 size_t SPF_dns_txt_get_length_windns(DWORD count, PSTR strings[]) 00091 { 00092 size_t length; 00093 DWORD i; 00094 00095 length = 0; 00096 00097 for( i = 0; i < count; i++ ) 00098 { 00099 length = length + strlen(strings[i]); 00100 } 00101 00102 return length; 00103 } 00104 00105 00106 char *SPF_dns_txt_concat_windns(char *buffer, DWORD count, PSTR strings[]) 00107 { 00108 DWORD i; 00109 00110 buffer[0] = 0; 00111 00112 for( i = 0; i < count; i++ ) 00113 { 00114 if ( strcat( buffer, strings[i] ) == NULL ) 00115 return NULL; 00116 } 00117 00118 return buffer; 00119 } 00120 00121 00122 static SPF_dns_rr_t *SPF_dns_lookup_windns( SPF_dns_config_t spfdcid, const char *domain, ns_type rr_type, int should_cache ) 00123 { 00124 SPF_dns_iconfig_t *spfdic = SPF_dcid2spfdic( spfdcid ); 00125 SPF_dns_windns_config_t *spfhook = SPF_voidp2spfhook( spfdic->hook ); 00126 SPF_dns_rr_t *spfrr; 00127 00128 int cnt; 00129 00130 PDNS_RECORDA pDnsRecord; 00131 00132 DNS_STATUS status; 00133 LPSTR error_message; 00134 00135 char ip4_buf[ INET_ADDRSTRLEN ]; 00136 char ip6_buf[ INET6_ADDRSTRLEN ]; 00137 00138 int rdlen; 00139 00140 DNS_A_DATA *pA_data; 00141 DNS_AAAA_DATA *pAAAA_data; 00142 DNS_MX_DATAA *pMX_data; 00143 DNS_TXT_DATAA *pTXT_data; 00144 DNS_PTR_DATAA *pPTR_data; 00145 00146 size_t txt_data_len; 00147 char *txt_concat; 00148 00149 00150 /* 00151 * initialize stuff 00152 */ 00153 spfrr = &spfhook->spfrr; 00154 SPF_dns_reset_rr( spfrr ); 00155 spfrr->herrno = NO_RECOVERY; 00156 spfrr->rr_type = rr_type; 00157 if ( domain && domain[0] != '\0' ) 00158 { 00159 char *new_domain; 00160 size_t new_len = strlen( domain ) + 1; 00161 00162 if ( spfrr->domain_buf_len < new_len ) 00163 { 00164 new_domain = realloc( spfrr->domain, new_len ); 00165 if ( new_domain == NULL ) 00166 return spfrr; 00167 00168 spfrr->domain = new_domain; 00169 spfrr->domain_buf_len = new_len; 00170 } 00171 strcpy( spfrr->domain, domain ); 00172 } 00173 else if ( spfrr->domain ) 00174 spfrr->domain[0] = '\0'; 00175 00176 cnt = 0; 00177 00178 if ( spfhook->debug ) 00179 SPF_debugf( "WinDNS looking for: %s %s (%d)", 00180 domain, 00181 ( 00182 (rr_type == ns_t_a) ? "A" : 00183 (rr_type == ns_t_aaaa) ? "AAAA" : 00184 (rr_type == ns_t_mx) ? "MX" : 00185 (rr_type == ns_t_txt) ? "TXT" : 00186 (rr_type == ns_t_ptr) ? "PTR" : 00187 (rr_type == ns_t_any) ? "ANY" : 00188 "??" 00189 ), 00190 rr_type ); 00191 00192 00193 /* 00194 * try resolving the name 00195 */ 00196 status = DnsQuery_A( domain, rr_type, 00197 (DNS_QUERY_STANDARD + DNS_QUERY_TREAT_AS_FQDN), 00198 NULL, &pDnsRecord, NULL ); 00199 00200 if ( status != DNS_RCODE_NOERROR ) 00201 { 00202 if ( spfhook->debug ) 00203 { 00204 error_message = SPF_dns_create_error_message_windns(SPF_h_errno); 00205 00206 SPF_debugf( "query failed: err = %d %s (%d)", 00207 status, error_message, SPF_h_errno ); 00208 00209 SPF_dns_destroy_error_message_windns(error_message); 00210 } 00211 00212 if ( 00213 ( SPF_h_errno == HOST_NOT_FOUND ) && 00214 ( spfdic->layer_below ) 00215 ) 00216 return SPF_dcid2spfdic( spfdic->layer_below )->lookup( spfdic->layer_below, domain, rr_type, should_cache ); 00217 00218 spfrr->herrno = SPF_h_errno; 00219 return spfrr; 00220 } 00221 else 00222 spfrr->herrno = NETDB_SUCCESS; 00223 00224 while (pDnsRecord) 00225 { 00226 rdlen = pDnsRecord->wDataLength; 00227 00228 if ( spfhook->debug > 1 ) 00229 SPF_debugf( "name: %s type: %d ttl: %d rdlen: %d", 00230 pDnsRecord->pName, pDnsRecord->wType, 00231 pDnsRecord->dwTtl, rdlen ); 00232 00233 if ( rdlen <= 0 ) 00234 { 00235 pDnsRecord = pDnsRecord->pNext; 00236 continue; 00237 } 00238 00239 /* No sense in doing this twice */ 00240 if (pDnsRecord->wType == ns_t_txt) 00241 { 00242 pTXT_data = &pDnsRecord->Data.TXT; 00243 00244 txt_data_len = 00245 SPF_dns_txt_get_length_windns( 00246 pTXT_data->dwStringCount, 00247 pTXT_data->pStringArray 00248 ); 00249 } 00250 00251 if ( spfhook->debug > 1 ) 00252 { 00253 switch( pDnsRecord->wType ) 00254 { 00255 case ns_t_a: 00256 00257 pA_data = &pDnsRecord->Data.A; 00258 00259 SPF_debugf( "A: %s", 00260 inet_ntop( AF_INET, &pA_data->IpAddress, 00261 ip4_buf, sizeof( ip4_buf ) )); 00262 break; 00263 00264 case ns_t_aaaa: 00265 00266 pAAAA_data = &pDnsRecord->Data.AAAA; 00267 00268 SPF_debugf( "AAAA: %s", 00269 inet_ntop( AF_INET6, &pAAAA_data->Ip6Address, 00270 ip6_buf, sizeof( ip6_buf ) )); 00271 break; 00272 00273 case ns_t_ns: 00274 00275 SPF_debugf( "NS: %s", pDnsRecord->Data.NS.pNameHost ); 00276 break; 00277 00278 case ns_t_cname: 00279 00280 SPF_debugf( "CNAME: %s", pDnsRecord->Data.CNAME.pNameHost ); 00281 break; 00282 00283 case ns_t_mx: 00284 00285 pMX_data = &pDnsRecord->Data.MX; 00286 00287 SPF_debugf( "MX: %d %s", 00288 pMX_data->wPreference, pMX_data->pNameExchange ); 00289 break; 00290 00291 case ns_t_txt: 00292 00293 txt_concat = malloc(txt_data_len + 1); 00294 00295 if ( txt_concat == NULL ) 00296 SPF_debugf( "TXT: (%d) - no memory for concatination", 00297 txt_data_len ); 00298 else 00299 { 00300 if ( SPF_dns_txt_concat_windns( 00301 txt_concat, 00302 pTXT_data->dwStringCount, 00303 pTXT_data->pStringArray 00304 ) == NULL ) 00305 SPF_debugf( "TXT: (%d) - error in concatination", 00306 txt_data_len ); 00307 else 00308 { 00309 SPF_debugf( "TXT: (%d) \"%s\"", 00310 txt_data_len, txt_concat ); 00311 } 00312 free( txt_concat ); 00313 } 00314 break; 00315 00316 case ns_t_ptr: 00317 00318 pPTR_data = &pDnsRecord->Data.PTR; 00319 00320 SPF_debugf( "PTR: %s", pPTR_data->pNameHost ); 00321 break; 00322 00323 default: 00324 SPF_debugf( "not parsed: type: %d", pDnsRecord->wType ); 00325 break; 00326 } 00327 } 00328 00329 if ( 00330 ( pDnsRecord->Flags.S.Section != DNSREC_ANSWER ) && 00331 ( spfhook->debug > 1 ) 00332 ) 00333 { 00334 pDnsRecord = pDnsRecord->pNext; 00335 continue; 00336 } 00337 00338 00339 if ( 00340 ( pDnsRecord->wType != spfrr->rr_type ) && 00341 ( pDnsRecord->wType != ns_t_cname ) 00342 ) 00343 { 00344 SPF_debugf( "unexpected rr type: %d expected: %d", 00345 pDnsRecord->wType, rr_type ); 00346 pDnsRecord = pDnsRecord->pNext; 00347 continue; 00348 } 00349 00350 switch( pDnsRecord->wType ) 00351 { 00352 case ns_t_a: 00353 00354 pA_data = &pDnsRecord->Data.A; 00355 00356 if ( SPF_dns_rr_buf_malloc( 00357 spfrr, cnt, sizeof( pA_data->IpAddress ) 00358 ) != SPF_E_SUCCESS ) 00359 return spfrr; 00360 00361 memmove( &spfrr->rr[cnt]->a, &pA_data->IpAddress, 00362 sizeof( pA_data->IpAddress ) ); 00363 00364 cnt++; 00365 break; 00366 00367 case ns_t_aaaa: 00368 00369 pAAAA_data = &pDnsRecord->Data.AAAA; 00370 00371 if ( SPF_dns_rr_buf_malloc( 00372 spfrr, cnt, sizeof( pAAAA_data->Ip6Address ) 00373 ) != SPF_E_SUCCESS ) 00374 return spfrr; 00375 00376 memmove( &spfrr->rr[cnt]->aaaa, &pAAAA_data->Ip6Address, 00377 sizeof( pAAAA_data->Ip6Address ) ); 00378 00379 cnt++; 00380 break; 00381 00382 case ns_t_ns: 00383 break; 00384 00385 case ns_t_cname: 00386 /* FIXME: are CNAMEs always sent with the real RR? */ 00387 break; 00388 00389 case ns_t_mx: 00390 00391 pMX_data = &pDnsRecord->Data.MX; 00392 00393 if ( SPF_dns_rr_buf_malloc( 00394 spfrr, cnt, strlen( pMX_data->pNameExchange ) + 1 00395 ) != SPF_E_SUCCESS ) 00396 return spfrr; 00397 00398 strcpy( spfrr->rr[cnt]->mx, pMX_data->pNameExchange ); 00399 00400 cnt++; 00401 break; 00402 00403 case ns_t_txt: 00404 00405 if ( SPF_dns_rr_buf_malloc( 00406 spfrr, cnt, txt_data_len + 1 00407 ) != SPF_E_SUCCESS ) 00408 return spfrr; 00409 00410 if ( SPF_dns_txt_concat_windns( 00411 spfrr->rr[cnt]->txt, 00412 pTXT_data->dwStringCount, 00413 pTXT_data->pStringArray 00414 ) == NULL ) 00415 return spfrr; 00416 00417 cnt++; 00418 break; 00419 00420 case ns_t_ptr: 00421 00422 pPTR_data = &pDnsRecord->Data.PTR; 00423 00424 if ( SPF_dns_rr_buf_malloc( 00425 spfrr, cnt, strlen( pPTR_data->pNameHost ) + 1 00426 ) != SPF_E_SUCCESS ) 00427 return spfrr; 00428 00429 strcpy( spfrr->rr[cnt]->ptr, pPTR_data->pNameHost ); 00430 00431 cnt++; 00432 break; 00433 00434 default: 00435 break; 00436 } 00437 00438 spfrr->num_rr = cnt; 00439 00440 pDnsRecord = pDnsRecord->pNext; 00441 } 00442 00443 if ( spfrr->num_rr == 0 ) 00444 spfhook->spfrr.herrno = NO_DATA; 00445 00446 return spfrr; 00447 } 00448 00449 00450 SPF_dns_config_t SPF_dns_create_config_windns( SPF_dns_config_t layer_below, int debug ) 00451 { 00452 SPF_dns_iconfig_t *spfdic; 00453 SPF_dns_windns_config_t *spfhook; 00454 00455 00456 spfdic = malloc( sizeof( *spfdic ) ); 00457 if ( spfdic == NULL ) 00458 return NULL; 00459 00460 spfdic->hook = calloc( 1, sizeof( SPF_dns_windns_config_t ) ); 00461 if ( spfdic->hook == NULL ) 00462 { 00463 free( spfdic ); 00464 return NULL; 00465 } 00466 00467 spfdic->destroy = SPF_dns_destroy_config_windns; 00468 spfdic->lookup = SPF_dns_lookup_windns; 00469 spfdic->get_spf = NULL; 00470 spfdic->get_exp = NULL; 00471 spfdic->add_cache = NULL; 00472 spfdic->layer_below = layer_below; 00473 spfdic->name = "windns"; 00474 00475 spfhook = SPF_voidp2spfhook( spfdic->hook ); 00476 00477 spfhook->debug = debug; 00478 SPF_dns_reset_rr( &spfhook->spfrr ); 00479 spfhook->spfrr.source = SPF_spfdic2dcid( spfdic ); 00480 00481 return SPF_spfdic2dcid( spfdic ); 00482 } 00483 00484 void SPF_dns_reset_config_windns( SPF_dns_config_t spfdcid ) 00485 { 00486 SPF_dns_iconfig_t *spfdic = SPF_dcid2spfdic( spfdcid ); 00487 00488 00489 if ( spfdcid == NULL ) 00490 SPF_error( "spfdcid is NULL" ); 00491 00492 00493 SPF_dns_reset_rr( &(SPF_voidp2spfhook( spfdic->hook )->spfrr) ); 00494 } 00495 00496 void SPF_dns_destroy_config_windns( SPF_dns_config_t spfdcid ) 00497 { 00498 SPF_dns_iconfig_t *spfdic = SPF_dcid2spfdic( spfdcid ); 00499 00500 if ( spfdcid == NULL ) 00501 SPF_error( "spfdcid is NULL" ); 00502 00503 if ( spfdic->hook ) 00504 { 00505 SPF_dns_windns_config_t *spfhook = SPF_voidp2spfhook( spfdic->hook ); 00506 00507 SPF_dns_destroy_rr_var( &spfhook->spfrr ); 00508 00509 free( spfdic->hook ); 00510 } 00511 00512 if ( spfdic ) 00513 free( spfdic ); 00514 } 00515 00516 #endif