ze-filter  (ze-filter-0.8.0-develop-180218)
ze-dns-parse.c
Go to the documentation of this file.
1 /*
2  *
3  * ze-filter - Mail Server Filter for sendmail
4  *
5  * Copyright (c) 2001-2018 - Jose-Marcio Martins da Cruz
6  *
7  * Auteur : Jose Marcio Martins da Cruz
8  * jose.marcio.mc@gmail.org
9  *
10  * Historique :
11  * Creation : Fri Oct 8 15:44:40 CEST 2004
12  *
13  * This program is free software, but with restricted license :
14  *
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19  *
20  * More details about ze-filter license can be found at ze-filter
21  * web site : http://foss.jose-marcio.org
22  */
23 
24 
25 #include <ze-sys.h>
26 #include <ze-libjc.h>
27 #include <ze-dns-parse.h>
28 
29 
30 /* ****************************************************************************
31  * *
32  * *
33  **************************************************************************** */
34 
35 static int compar_dns_host(const void *, const void *);
36 
37 static int parse_mx_answer(DNS_REPLY_T * r, DNS_HOSTARR_T * mx);
38 static int parse_a_answer(DNS_REPLY_T * r, DNS_HOSTARR_T * a);
39 
40 /* ****************************************************************************
41  * *
42  * *
43  **************************************************************************** */
44 
45 static int dns_retry = 0;
46 static int dns_retrans = 0;
47 static int dns_init_ok = FALSE;
48 
49 static void
50 dns_init()
51 {
52  if (!dns_init_ok)
53  {
54  char *env = NULL;
55 
56  dns_retry = _res.retry;
57  dns_retrans = _res.retrans;
58 
59  if ((env = getenv("DNS_RETRY")) != NULL)
60  {
61  int t;
62 
63  errno = 0;
64  t = strtol(env, NULL, 10);
65  if (errno == 0)
66  dns_retry = t;
67  }
68 
69  if ((env = getenv("DNS_RETRANS")) != NULL)
70  {
71  int t;
72 
73  errno = 0;
74  t = strtol(env, NULL, 10);
75  if (errno == 0)
76  dns_retrans = t;
77  }
78 
79  ZE_MessageInfo(11, "DNS retry : %d, retrans : %d", dns_retry, dns_retrans);
80  dns_init_ok = TRUE;
81  }
82 }
83 
84 /* ****************************************************************************
85  * *
86  * *
87  **************************************************************************** */
88 void
90  DNS_HOSTARR_T *r;
91 {
92  int i;
93 
94  if (r == NULL)
95  return;
96 
97  for (i = 0; i < r->count; i++)
98  {
99  FREE(r->host[i].ip);
100  FREE(r->host[i].name);
101  FREE(r->host[i].txt);
102  }
103  FREE(r->domain);
104  r->count = 0;
105 }
106 
107 
108 /* ****************************************************************************
109  * *
110  * *
111  **************************************************************************** */
112 static int
113 parse_a_answer(r, a)
114  DNS_REPLY_T *r;
115  DNS_HOSTARR_T *a;
116 {
117  RR_RECORD_T *rr;
118 
119  if (r == NULL || a == NULL)
120  return 0;
121 
122  for (rr = r->dns_r_head; rr != NULL; rr = rr->rr_next)
123  {
124  char buf[64];
125 
126  if (a->count >= MAX_HOST)
127  break;
128 
129  if (rr->rr_type == T_NS)
130  break;
131 
132  if (rr->rr_type != T_A)
133  continue;
134 
135  a->host[a->count].name = strdup(a->domain);
136 
137  if (!jinet_ntop(AF_INET, rr->rr_u.rr_a, buf, sizeof (buf)))
138  memset(buf, 0, sizeof (buf));
139 
140  a->host[a->count].ip = strdup(buf);
141 
142  a->count++;
143  }
144 
145  return a->count;
146 }
147 
148 /* ****************************************************************************
149  * *
150  * *
151  **************************************************************************** */
152 int
154  char *domain;
155  DNS_HOSTARR_T *a;
156 {
157  DNS_REPLY_T rt;
158  int res = DNS_NO_ERR;
159 
160  if (domain == NULL || a == NULL)
161  return DNS_LOC_ERR;
162 
163  memset(a, 0, sizeof (*a));
164  a->domain = strdup(domain);
165  memset(&rt, 0, sizeof (rt));
166 
167  dns_init();
168  if ((res = dns_lookup(domain, "A", dns_retrans, dns_retry, &rt)) >= 0)
169  {
170  parse_a_answer(&rt, a);
171  if (a->count > 0)
172  qsort(a->host, a->count, sizeof (DNS_HOST_T), compar_dns_host);
173  dns_free_data(&rt);
174  }
175 
176  if (a->count > 0)
177  return a->count;
178  return res;
179 }
180 
181 /* ****************************************************************************
182  * *
183  * *
184  **************************************************************************** */
185 static int
186 parse_aaaa_answer(r, a)
187  DNS_REPLY_T *r;
188  DNS_HOSTARR_T *a;
189 {
190  RR_RECORD_T *rr;
191 
192  if (r == NULL || a == NULL)
193  return 0;
194 
195  for (rr = r->dns_r_head; rr != NULL; rr = rr->rr_next)
196  {
197  char buf[64];
198 
199  if (a->count >= MAX_HOST)
200  break;
201 
202  if (rr->rr_type == T_NS)
203  break;
204 
205  if (rr->rr_type != T_AAAA)
206  continue;
207 
208  a->host[a->count].name = strdup(a->domain);
209 
210  if (!jinet_ntop(AF_INET6, rr->rr_u.rr_a, buf, sizeof (buf)))
211  memset(buf, 0, sizeof (buf));
212 
213  a->host[a->count].ip = strdup(buf);
214 
215  a->count++;
216  }
217 
218  return a->count;
219 }
220 
221 /* ****************************************************************************
222  * *
223  * *
224  **************************************************************************** */
225 int
226 dns_get_aaaa(domain, a)
227  char *domain;
228  DNS_HOSTARR_T *a;
229 {
230  DNS_REPLY_T rt;
231  int res = DNS_NO_ERR;
232 
233  if (domain == NULL || a == NULL)
234  return DNS_LOC_ERR;
235 
236  memset(a, 0, sizeof (*a));
237  a->domain = strdup(domain);
238  memset(&rt, 0, sizeof (rt));
239 
240  dns_init();
241  if ((res = dns_lookup(domain, "AAAA", dns_retrans, dns_retry, &rt)) >= 0)
242  {
243  parse_aaaa_answer(&rt, a);
244  if (a->count > 0)
245  qsort(a->host, a->count, sizeof (DNS_HOST_T), compar_dns_host);
246  dns_free_data(&rt);
247  }
248 
249  if (a->count > 0)
250  return a->count;
251  return res;
252 }
253 
254 /* ****************************************************************************
255  * *
256  * *
257  **************************************************************************** */
258 static int
259 parse_mx_answer(r, mx)
260  DNS_REPLY_T *r;
261  DNS_HOSTARR_T *mx;
262 {
263  RR_RECORD_T *rr;
264 
265  if (r == NULL || mx == NULL)
266  return 0;
267 
268  for (rr = r->dns_r_head; rr != NULL; rr = rr->rr_next)
269  {
270  RR_RECORD_T *ra;
271 
272  if (mx->count >= MAX_HOST)
273  break;
274 
275  if (rr->rr_type != T_MX)
276  continue;
277 
278  if (rr->rr_u.rr_mx->mx_r_domain == NULL)
279  continue;
280 
281  mx->host[mx->count].name = strdup(rr->rr_u.rr_mx->mx_r_domain);
282  if (mx->host[mx->count].name == NULL)
283  {
284  ZE_LogSysError("malloc error");
285  continue;
286  }
287  mx->host[mx->count].pref = rr->rr_u.rr_mx->mx_r_preference;
288 
289  /* First look at additional section */
290  for (ra = r->dns_r_head; ra != NULL; ra = ra->rr_next)
291  {
292  if (ra->rr_type != T_A)
293  continue;
294 
295  if (ra->rr_domain == NULL)
296  continue;
297 
298  if (strcasecmp(rr->rr_u.rr_mx->mx_r_domain, ra->rr_domain) == 0)
299  {
300  char buf[32];
301 
302  if (mx->host[mx->count].ip != NULL)
303  {
304  if (mx->count >= MAX_HOST - 1)
305  break;
306 
307  if (mx->host[mx->count].name != NULL)
308  mx->host[mx->count + 1].name = strdup(mx->host[mx->count].name);
309  mx->host[mx->count + 1].pref = mx->host[mx->count].pref;
310  mx->count++;
311  }
312 
313  if (!jinet_ntop(AF_INET, ra->rr_u.rr_a, buf, sizeof (buf)))
314  memset(buf, 0, sizeof (buf));
315 
316  mx->host[mx->count].ip = strdup(buf);
317  }
318  }
319 
320  /* Not found - so query it */
321  if (mx->host[mx->count].ip == NULL && mx->host[mx->count].name != NULL)
322  {
323  int i;
324  DNS_HOSTARR_T a;
325 
326  memset(&a, 0, sizeof (a));
327  if (dns_get_a(rr->rr_u.rr_mx->mx_r_domain, &a) > 0)
328  {
329  for (i = 0; i < a.count; i++)
330  {
331  if (mx->host[mx->count].ip != NULL)
332  {
333  if (mx->count >= MAX_HOST - 1)
334  break;
335 
336  if (mx->host[mx->count].name != NULL)
337  mx->host[mx->count + 1].name = strdup(mx->host[mx->count].name);
338  mx->host[mx->count + 1].pref = mx->host[mx->count].pref;
339  mx->count++;
340  }
341  mx->host[mx->count].ip = strdup(a.host[i].ip);
342  }
343  }
344  dns_free_hostarr(&a);
345  }
346  mx->count++;
347  }
348  return mx->count;
349 }
350 
351 
352 /* ****************************************************************************
353  * *
354  * *
355  **************************************************************************** */
356 int
357 dns_get_mx(domain, mx)
358  char *domain;
359  DNS_HOSTARR_T *mx;
360 {
361  DNS_REPLY_T rt;
362  int res = 0;
363  int result = DNS_NO_ERR;
364 
365  if (domain == NULL || mx == NULL)
366  return DNS_LOC_ERR;
367 
368  ZE_MessageInfo(11, "Entering %s : %s", ZE_FUNCTION, domain);
369  memset(mx, 0, sizeof (*mx));
370  mx->domain = strdup(domain);
371 
372  dns_init();
373  if ((res = dns_lookup(domain, "MX", dns_retrans, dns_retry, &rt)) >= 0)
374  {
375  result = parse_mx_answer(&rt, mx);
376  if (mx->count > 1)
377  qsort(mx->host, mx->count, sizeof (DNS_HOST_T), compar_dns_host);
378  dns_free_data(&rt);
379  }
380 
381  ZE_MessageInfo(11, "%-20s : res = %d count = %d\n", domain, res, mx->count);
382  if (mx->count > 0)
383  return mx->count;
384  return res;
385 }
386 
387 
388 /* ****************************************************************************
389  * *
390  * *
391  **************************************************************************** */
392 void
394  DNS_REPLY_T *r;
395  int level;
396 {
397  if (r != NULL)
398  {
399  char prefix[16];
400  RR_RECORD_T *rr;
401 
402  zeStrSet(prefix, ' ', level * 2);
403  for (rr = r->dns_r_head; rr != NULL; rr = rr->rr_next)
404  {
405  char *stype = (char *) dns_type_to_string(rr->rr_type);
406 
407  stype = STRNULL(stype, "???");
408 
409  switch (rr->rr_type)
410  {
411  case T_MX:
412  printf("%s* %-3s %2d %s\n",
413  prefix,
414  stype, rr->rr_u.rr_mx->mx_r_preference,
415  rr->rr_u.rr_mx->mx_r_domain);
416  {
417  DNS_REPLY_T rt;
418  int res;
419 
420  if ((res = dns_lookup(rr->rr_u.rr_mx->mx_r_domain, "A",
421  dns_retrans, dns_retry, &rt)) >= 0)
422  {
423  print_dns_reply(&rt, level + 1);
424  dns_free_data(&rt);
425  }
426  }
427  break;
428  case T_A:
429  {
430  char buf[32];
431 
432  if (!jinet_ntop(AF_INET, rr->rr_u.rr_a, buf, sizeof (buf)))
433  memset(buf, 0, sizeof (buf));
434  printf("%s* %-3s %-16s %s\n", prefix, stype, buf, rr->rr_domain);
435  }
436  break;
437  default:
438  printf("%s* %-3s %s\n", prefix, stype, rr->rr_domain);
439  break;
440  }
441  }
442  }
443 }
444 
445 /* ****************************************************************************
446  * *
447  * *
448  **************************************************************************** */
449 int
451  const void *va;
452  const void *vb;
453 {
454  DNS_HOST_T *a = (DNS_HOST_T *) va;
455  DNS_HOST_T *b = (DNS_HOST_T *) vb;
456  int r = 0;
457 
458  if (a == NULL || b == NULL)
459  return 0;
460 
461  if (a->pref != b->pref)
462  return a->pref - b->pref;
463 
464  if (a->name != NULL && b->name != NULL)
465  r = strcasecmp(a->name, b->name);
466 
467  if (r == 0 && a->ip != NULL && b->ip != NULL)
468  r = strcasecmp(a->ip, b->ip);
469 
470  return r;
471 }
void dns_free_hostarr(DNS_HOSTARR_T *r)
Definition: ze-dns-parse.c:89
char mx_r_domain[1]
Definition: ze-dns.h:80
#define ZE_FUNCTION
Definition: ze-sys.h:471
#define FREE(x)
Definition: macros.h:37
#define STRNULL(x, r)
Definition: macros.h:81
int dns_get_mx(char *domain, DNS_HOSTARR_T *mx)
Definition: ze-dns-parse.c:357
#define FALSE
Definition: macros.h:160
RR_RECORD_T * rr_next
Definition: ze-dns.h:113
int dns_lookup(const char *domain, const char *type_name, time_t retrans, int retry, DNS_REPLY_T *)
#define MAX_HOST
Definition: ze-dns-parse.h:33
union resource_record::@0 rr_u
const char * dns_type_to_string(int)
Definition: ze-dns.c:164
char * zeStrSet(char *, int, int)
Definition: zeStrings.c:330
DNS_HOST_T host[MAX_HOST]
Definition: ze-dns-parse.h:46
MX_RECORD_T * rr_mx
Definition: ze-dns.h:104
#define ZE_MessageInfo(level,...)
Definition: zeSyslog.h:90
#define TRUE
Definition: macros.h:157
void dns_free_data(DNS_REPLY_T *)
Definition: ze-dns.c:190
#define DNS_LOC_ERR
Definition: ze-dns.h:144
#define ZE_LogSysError(...)
Definition: zeSyslog.h:129
struct in_addr * rr_a
Definition: ze-dns.h:107
char * name
Definition: ze-dns-parse.h:39
unsigned int mx_r_preference
Definition: ze-dns.h:79
RR_RECORD_T * dns_r_head
Definition: ze-dns.h:126
int compar_dns_host(void *va, const void *vb) const
Definition: ze-dns-parse.c:450
char * rr_domain
Definition: ze-dns.h:96
int dns_get_a(char *domain, DNS_HOSTARR_T *a)
Definition: ze-dns-parse.c:153
char * ip
Definition: ze-dns-parse.h:38
void print_dns_reply(DNS_REPLY_T *r, int level)
Definition: ze-dns-parse.c:393
int dns_get_aaaa(char *domain, DNS_HOSTARR_T *a)
Definition: ze-dns-parse.c:226
unsigned int rr_type
Definition: ze-dns.h:97
char * jinet_ntop(int, void *, char *, size_t)
Definition: ze-inet.c:34
char domain[]
#define DNS_NO_ERR
Definition: ze-dns.h:140
char * txt
Definition: ze-dns-parse.h:40