libspf2  1.2.10
spf_dns_windns.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or modify
3  * it under the terms of either:
4  *
5  * a) The GNU Lesser General Public License as published by the Free
6  * Software Foundation; either version 2.1, or (at your option) any
7  * later version,
8  *
9  * OR
10  *
11  * b) The two-clause BSD license.
12  *
13  * These licenses can be found with the distribution in the file LICENSES
14  */
15 
16 #ifdef _WIN32
17 
18 #include "spf_sys_config.h"
19 
20 #ifdef HAVE_ERRNO_H
21 #include <errno.h>
22 #endif
23 
24 #ifdef STDC_HEADERS
25 # include <stdio.h> /* stdin / stdout */
26 # include <stdlib.h> /* malloc / free */
27 #endif
28 
29 #ifdef HAVE_STRING_H
30 # include <string.h> /* strstr / strdup */
31 #else
32 # ifdef HAVE_STRINGS_H
33 # include <strings.h> /* strstr / strdup */
34 # endif
35 #endif
36 
37 #include "spf.h"
38 #include "spf_dns.h"
39 #include "spf_internal.h"
40 #include "spf_dns_internal.h"
41 #include "spf_dns_windns.h"
42 #pragma comment(lib, "dnsapi.lib")
43 #include <windns.h>
44 
45 
46 typedef struct
47 {
48  int debug;
49  SPF_dns_rr_t spfrr;
50 } SPF_dns_windns_config_t;
51 
52 
53 #define SPF_h_errno WSAGetLastError()
54 
55 
56 static inline SPF_dns_windns_config_t *SPF_voidp2spfhook( void *hook )
57  { return (SPF_dns_windns_config_t *)hook; }
58 static inline void *SPF_spfhook2voidp( SPF_dns_windns_config_t *spfhook )
59  { return (void *)spfhook; }
60 
61 
62 LPSTR SPF_dns_create_error_message_windns(DWORD last_error)
63 {
64  LPSTR error_message;
65 
66  if (!FormatMessageA(
67  (FORMAT_MESSAGE_ALLOCATE_BUFFER |
68  FORMAT_MESSAGE_FROM_SYSTEM |
69  FORMAT_MESSAGE_IGNORE_INSERTS),
70  NULL,
71  last_error,
72  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
73  (LPSTR) &error_message,
74  0,
75  NULL))
76  {
77  return NULL;
78  }
79 
80  return error_message;
81 }
82 
83 
84 void SPF_dns_destroy_error_message_windns(LPSTR error_message)
85 {
86  LocalFree( error_message );
87 }
88 
89 
90 size_t SPF_dns_txt_get_length_windns(DWORD count, PSTR strings[])
91 {
92  size_t length;
93  DWORD i;
94 
95  length = 0;
96 
97  for( i = 0; i < count; i++ )
98  {
99  length = length + strlen(strings[i]);
100  }
101 
102  return length;
103 }
104 
105 
106 char *SPF_dns_txt_concat_windns(char *buffer, DWORD count, PSTR strings[])
107 {
108  DWORD i;
109 
110  buffer[0] = 0;
111 
112  for( i = 0; i < count; i++ )
113  {
114  if ( strcat( buffer, strings[i] ) == NULL )
115  return NULL;
116  }
117 
118  return buffer;
119 }
120 
121 
122 static SPF_dns_rr_t *SPF_dns_lookup_windns( SPF_dns_config_t spfdcid, const char *domain, ns_type rr_type, int should_cache )
123 {
124  SPF_dns_iconfig_t *spfdic = SPF_dcid2spfdic( spfdcid );
125  SPF_dns_windns_config_t *spfhook = SPF_voidp2spfhook( spfdic->hook );
126  SPF_dns_rr_t *spfrr;
127 
128  int cnt;
129 
130  PDNS_RECORDA pDnsRecord;
131 
132  DNS_STATUS status;
133  LPSTR error_message;
134 
135  char ip4_buf[ INET_ADDRSTRLEN ];
136  char ip6_buf[ INET6_ADDRSTRLEN ];
137 
138  int rdlen;
139 
140  DNS_A_DATA *pA_data;
141  DNS_AAAA_DATA *pAAAA_data;
142  DNS_MX_DATAA *pMX_data;
143  DNS_TXT_DATAA *pTXT_data;
144  DNS_PTR_DATAA *pPTR_data;
145 
146  size_t txt_data_len;
147  char *txt_concat;
148 
149 
150  /*
151  * initialize stuff
152  */
153  spfrr = &spfhook->spfrr;
154  SPF_dns_reset_rr( spfrr );
155  spfrr->herrno = NO_RECOVERY;
156  spfrr->rr_type = rr_type;
157  if ( domain && domain[0] != '\0' )
158  {
159  char *new_domain;
160  size_t new_len = strlen( domain ) + 1;
161 
162  if ( spfrr->domain_buf_len < new_len )
163  {
164  new_domain = realloc( spfrr->domain, new_len );
165  if ( new_domain == NULL )
166  return spfrr;
167 
168  spfrr->domain = new_domain;
169  spfrr->domain_buf_len = new_len;
170  }
171  strcpy( spfrr->domain, domain );
172  }
173  else if ( spfrr->domain )
174  spfrr->domain[0] = '\0';
175 
176  cnt = 0;
177 
178  if ( spfhook->debug )
179  SPF_debugf( "WinDNS looking for: %s %s (%d)",
180  domain,
181  (
182  (rr_type == ns_t_a) ? "A" :
183  (rr_type == ns_t_aaaa) ? "AAAA" :
184  (rr_type == ns_t_mx) ? "MX" :
185  (rr_type == ns_t_txt) ? "TXT" :
186  (rr_type == ns_t_ptr) ? "PTR" :
187  (rr_type == ns_t_any) ? "ANY" :
188  "??"
189  ),
190  rr_type );
191 
192 
193  /*
194  * try resolving the name
195  */
196  status = DnsQuery_A( domain, rr_type,
197  (DNS_QUERY_STANDARD + DNS_QUERY_TREAT_AS_FQDN),
198  NULL, &pDnsRecord, NULL );
199 
200  if ( status != DNS_RCODE_NOERROR )
201  {
202  if ( spfhook->debug )
203  {
204  error_message = SPF_dns_create_error_message_windns(SPF_h_errno);
205 
206  SPF_debugf( "query failed: err = %d %s (%d)",
207  status, error_message, SPF_h_errno );
208 
209  SPF_dns_destroy_error_message_windns(error_message);
210  }
211 
212  if (
213  ( SPF_h_errno == HOST_NOT_FOUND ) &&
214  ( spfdic->layer_below )
215  )
216  return SPF_dcid2spfdic( spfdic->layer_below )->lookup( spfdic->layer_below, domain, rr_type, should_cache );
217 
218  spfrr->herrno = SPF_h_errno;
219  return spfrr;
220  }
221  else
222  spfrr->herrno = NETDB_SUCCESS;
223 
224  while (pDnsRecord)
225  {
226  rdlen = pDnsRecord->wDataLength;
227 
228  if ( spfhook->debug > 1 )
229  SPF_debugf( "name: %s type: %d ttl: %d rdlen: %d",
230  pDnsRecord->pName, pDnsRecord->wType,
231  pDnsRecord->dwTtl, rdlen );
232 
233  if ( rdlen <= 0 )
234  {
235  pDnsRecord = pDnsRecord->pNext;
236  continue;
237  }
238 
239  /* No sense in doing this twice */
240  if (pDnsRecord->wType == ns_t_txt)
241  {
242  pTXT_data = &pDnsRecord->Data.TXT;
243 
244  txt_data_len =
245  SPF_dns_txt_get_length_windns(
246  pTXT_data->dwStringCount,
247  pTXT_data->pStringArray
248  );
249  }
250 
251  if ( spfhook->debug > 1 )
252  {
253  switch( pDnsRecord->wType )
254  {
255  case ns_t_a:
256 
257  pA_data = &pDnsRecord->Data.A;
258 
259  SPF_debugf( "A: %s",
260  inet_ntop( AF_INET, &pA_data->IpAddress,
261  ip4_buf, sizeof( ip4_buf ) ));
262  break;
263 
264  case ns_t_aaaa:
265 
266  pAAAA_data = &pDnsRecord->Data.AAAA;
267 
268  SPF_debugf( "AAAA: %s",
269  inet_ntop( AF_INET6, &pAAAA_data->Ip6Address,
270  ip6_buf, sizeof( ip6_buf ) ));
271  break;
272 
273  case ns_t_ns:
274 
275  SPF_debugf( "NS: %s", pDnsRecord->Data.NS.pNameHost );
276  break;
277 
278  case ns_t_cname:
279 
280  SPF_debugf( "CNAME: %s", pDnsRecord->Data.CNAME.pNameHost );
281  break;
282 
283  case ns_t_mx:
284 
285  pMX_data = &pDnsRecord->Data.MX;
286 
287  SPF_debugf( "MX: %d %s",
288  pMX_data->wPreference, pMX_data->pNameExchange );
289  break;
290 
291  case ns_t_txt:
292 
293  txt_concat = malloc(txt_data_len + 1);
294 
295  if ( txt_concat == NULL )
296  SPF_debugf( "TXT: (%d) - no memory for concatination",
297  txt_data_len );
298  else
299  {
300  if ( SPF_dns_txt_concat_windns(
301  txt_concat,
302  pTXT_data->dwStringCount,
303  pTXT_data->pStringArray
304  ) == NULL )
305  SPF_debugf( "TXT: (%d) - error in concatination",
306  txt_data_len );
307  else
308  {
309  SPF_debugf( "TXT: (%d) \"%s\"",
310  txt_data_len, txt_concat );
311  }
312  free( txt_concat );
313  }
314  break;
315 
316  case ns_t_ptr:
317 
318  pPTR_data = &pDnsRecord->Data.PTR;
319 
320  SPF_debugf( "PTR: %s", pPTR_data->pNameHost );
321  break;
322 
323  default:
324  SPF_debugf( "not parsed: type: %d", pDnsRecord->wType );
325  break;
326  }
327  }
328 
329  if (
330  ( pDnsRecord->Flags.S.Section != DNSREC_ANSWER ) &&
331  ( spfhook->debug > 1 )
332  )
333  {
334  pDnsRecord = pDnsRecord->pNext;
335  continue;
336  }
337 
338 
339  if (
340  ( pDnsRecord->wType != spfrr->rr_type ) &&
341  ( pDnsRecord->wType != ns_t_cname )
342  )
343  {
344  SPF_debugf( "unexpected rr type: %d expected: %d",
345  pDnsRecord->wType, rr_type );
346  pDnsRecord = pDnsRecord->pNext;
347  continue;
348  }
349 
350  switch( pDnsRecord->wType )
351  {
352  case ns_t_a:
353 
354  pA_data = &pDnsRecord->Data.A;
355 
356  if ( SPF_dns_rr_buf_malloc(
357  spfrr, cnt, sizeof( pA_data->IpAddress )
358  ) != SPF_E_SUCCESS )
359  return spfrr;
360 
361  memmove( &spfrr->rr[cnt]->a, &pA_data->IpAddress,
362  sizeof( pA_data->IpAddress ) );
363 
364  cnt++;
365  break;
366 
367  case ns_t_aaaa:
368 
369  pAAAA_data = &pDnsRecord->Data.AAAA;
370 
371  if ( SPF_dns_rr_buf_malloc(
372  spfrr, cnt, sizeof( pAAAA_data->Ip6Address )
373  ) != SPF_E_SUCCESS )
374  return spfrr;
375 
376  memmove( &spfrr->rr[cnt]->aaaa, &pAAAA_data->Ip6Address,
377  sizeof( pAAAA_data->Ip6Address ) );
378 
379  cnt++;
380  break;
381 
382  case ns_t_ns:
383  break;
384 
385  case ns_t_cname:
386  /* FIXME: are CNAMEs always sent with the real RR? */
387  break;
388 
389  case ns_t_mx:
390 
391  pMX_data = &pDnsRecord->Data.MX;
392 
393  if ( SPF_dns_rr_buf_malloc(
394  spfrr, cnt, strlen( pMX_data->pNameExchange ) + 1
395  ) != SPF_E_SUCCESS )
396  return spfrr;
397 
398  strcpy( spfrr->rr[cnt]->mx, pMX_data->pNameExchange );
399 
400  cnt++;
401  break;
402 
403  case ns_t_txt:
404 
405  if ( SPF_dns_rr_buf_malloc(
406  spfrr, cnt, txt_data_len + 1
407  ) != SPF_E_SUCCESS )
408  return spfrr;
409 
410  if ( SPF_dns_txt_concat_windns(
411  spfrr->rr[cnt]->txt,
412  pTXT_data->dwStringCount,
413  pTXT_data->pStringArray
414  ) == NULL )
415  return spfrr;
416 
417  cnt++;
418  break;
419 
420  case ns_t_ptr:
421 
422  pPTR_data = &pDnsRecord->Data.PTR;
423 
424  if ( SPF_dns_rr_buf_malloc(
425  spfrr, cnt, strlen( pPTR_data->pNameHost ) + 1
426  ) != SPF_E_SUCCESS )
427  return spfrr;
428 
429  strcpy( spfrr->rr[cnt]->ptr, pPTR_data->pNameHost );
430 
431  cnt++;
432  break;
433 
434  default:
435  break;
436  }
437 
438  spfrr->num_rr = cnt;
439 
440  pDnsRecord = pDnsRecord->pNext;
441  }
442 
443  if ( spfrr->num_rr == 0 )
444  spfhook->spfrr.herrno = NO_DATA;
445 
446  return spfrr;
447 }
448 
449 
450 SPF_dns_config_t SPF_dns_create_config_windns( SPF_dns_config_t layer_below, int debug )
451 {
452  SPF_dns_iconfig_t *spfdic;
453  SPF_dns_windns_config_t *spfhook;
454 
455 
456  spfdic = malloc( sizeof( *spfdic ) );
457  if ( spfdic == NULL )
458  return NULL;
459 
460  spfdic->hook = calloc( 1, sizeof( SPF_dns_windns_config_t ) );
461  if ( spfdic->hook == NULL )
462  {
463  free( spfdic );
464  return NULL;
465  }
466 
467  spfdic->destroy = SPF_dns_destroy_config_windns;
468  spfdic->lookup = SPF_dns_lookup_windns;
469  spfdic->get_spf = NULL;
470  spfdic->get_exp = NULL;
471  spfdic->add_cache = NULL;
472  spfdic->layer_below = layer_below;
473  spfdic->name = "windns";
474 
475  spfhook = SPF_voidp2spfhook( spfdic->hook );
476 
477  spfhook->debug = debug;
478  SPF_dns_reset_rr( &spfhook->spfrr );
479  spfhook->spfrr.source = SPF_spfdic2dcid( spfdic );
480 
481  return SPF_spfdic2dcid( spfdic );
482 }
483 
484 void SPF_dns_reset_config_windns( SPF_dns_config_t spfdcid )
485 {
486  SPF_dns_iconfig_t *spfdic = SPF_dcid2spfdic( spfdcid );
487 
488 
489  if ( spfdcid == NULL )
490  SPF_error( "spfdcid is NULL" );
491 
492 
493  SPF_dns_reset_rr( &(SPF_voidp2spfhook( spfdic->hook )->spfrr) );
494 }
495 
496 void SPF_dns_destroy_config_windns( SPF_dns_config_t spfdcid )
497 {
498  SPF_dns_iconfig_t *spfdic = SPF_dcid2spfdic( spfdcid );
499 
500  if ( spfdcid == NULL )
501  SPF_error( "spfdcid is NULL" );
502 
503  if ( spfdic->hook )
504  {
505  SPF_dns_windns_config_t *spfhook = SPF_voidp2spfhook( spfdic->hook );
506 
507  SPF_dns_destroy_rr_var( &spfhook->spfrr );
508 
509  free( spfdic->hook );
510  }
511 
512  if ( spfdic )
513  free( spfdic );
514 }
515 
516 #endif
#define NO_DATA
Definition: spf_dns.h:106
#define NO_RECOVERY
Definition: spf_dns.h:105
#define HOST_NOT_FOUND
Definition: spf_dns.h:103
#define NETDB_SUCCESS
Definition: spf_dns.h:102
void SPF_dns_reset_config_windns(SPF_dns_config_t spfdcid)
SPF_dns_config_t SPF_dns_create_config_windns(SPF_dns_config_t layer_below, int debug)
void SPF_dns_destroy_config_windns(SPF_dns_config_t spfdcid)
#define NULL
Definition: spf_internal.h:28
#define SPF_error(errmsg)
Definition: spf_log.h:40
#define SPF_debugf
Definition: spf_log.h:80
@ SPF_E_SUCCESS
Definition: spf_response.h:120
ns_type
Definition: arpa_nameser.h:300
@ ns_t_ptr
Definition: arpa_nameser.h:313
@ ns_t_mx
Definition: arpa_nameser.h:316
@ ns_t_any
Definition: arpa_nameser.h:350
@ ns_t_ns
Definition: arpa_nameser.h:303
@ ns_t_a
Definition: arpa_nameser.h:302
@ ns_t_txt
Definition: arpa_nameser.h:317
@ ns_t_aaaa
Definition: arpa_nameser.h:329
@ ns_t_cname
Definition: arpa_nameser.h:306
#define SPF_h_errno
#define debug
struct in_addr a
Definition: spf_dns_rr.h:33
struct in6_addr aaaa
Definition: spf_dns_rr.h:37
SPF_dns_rr_data_t ** rr
Definition: spf_dns_rr.h:60
size_t domain_buf_len
Definition: spf_dns_rr.h:54
char * domain
Definition: spf_dns_rr.h:53
ns_type rr_type
Definition: spf_dns_rr.h:56
SPF_dns_stat_t herrno
Definition: spf_dns_rr.h:66