1 /*
2  * $Id:$
3  */
4 
5 #include "default.h"
6 #include <sys/types.h>
7 #include <stdio.h>
8 #ifdef HAVE_UNISTD_H
9 # include <unistd.h>
10 #endif
11 #include <stdlib.h>
12 #include <stdarg.h>
13 #include <time.h>
14 #include <libnet.h>
15 #include "thcrut.h"
16 #include "dhcp.h"
17 #include "thcrut_libnet.h"
18 #include "network_raw.h"
19 #include "network.h"
20 #include "range.h"
21 #include "dhcp.h"
22 #include "packets.h"
23 #include "thcrut_pcap.h"
24 
25 #define STATE_RESET		(0)
26 #define STATE_DHCPI		(1)
27 #define STATE_DHCPII		(2)
28 #define STATE_DHCPIII		(3)
29 
30 #define DFL_HOSTS_PARALLEL      (10)
31 
32 extern struct _opt opt;
33 static void dhcp_filter(unsigned char *u, struct pcap_pkthdr *p, unsigned char *packet);
34 
35 static struct _lnet lnet;
36 //static struct _bmac bmac;
37 static struct _dhcpset ds;
38 static char dsbuf[1024];
39 static char buf_packet[1024];
40 static char *packet; /* Aligned so that ip-header is on a 4byte boundary */
41 static unsigned char srcmac[ETH_ALEN];
42 
43 /*
44  * Print out the last suboptions (one:value two:value, ..)
45  * We trust the input (no error checking)
46  */
47 static void
dhcp_print_lastsub(struct _dhcpset * ds)48 dhcp_print_lastsub(struct _dhcpset *ds)
49 {
50 	unsigned char len;    /* number of suboptions */
51 	unsigned char *ptr;
52 	unsigned char i=0;
53 	unsigned char value;
54 
55 	if (ds->lastsub == NULL)
56 		return;
57 
58 	len = *(ds->lastsub + 1);
59 	ptr = ds->lastsub + 2;
60 	for (i=0; i < len; i++)
61 	{
62 		value = *ptr++;
63 		fprintf(stderr, "%s(%u) ", dhcp_str(value), value);
64 	}
65 	fprintf(stderr, "\n");
66 }
67 
68 /*
69  * Build and send DHCP request.
70  */
71 static int
do_dhcp(char * packet,unsigned char * smac,long dstip)72 do_dhcp(char *packet, unsigned char *smac, long dstip)
73 {
74 	int len;
75 	int c;
76 	struct ip *ip = (struct ip *)(packet + LIBNET_ETH_H);
77 	struct _bootp *bp = (struct _bootp *)(packet + LIBNET_ETH_H + LIBNET_IP_H + LIBNET_UDP_H);
78 
79 	memcpy(packet + ETH_ALEN, smac, ETH_ALEN);
80 	memcpy(bp->chaddr, smac, ETH_ALEN);
81 
82 	len = LIBNET_ETH_H + LIBNET_IP_H + LIBNET_UDP_H + DHCP_MIN_OPT;
83 	ip->ip_len = htons(len - LIBNET_ETH_H);
84 	ip->ip_dst.s_addr = htonl(dstip);
85 	libnet_do_checksum(packet + LIBNET_ETH_H, IPPROTO_IP, LIBNET_IP_H);
86 	c = libnet_write_link_layer(opt.network, opt.device, packet, len);
87 	if (c != len)
88 		libnet_error(LIBNET_ERR_FATAL, "libnet_write_link_layer: %d bytes\n", c);
89 
90 	return 0;
91 }
92 
93 static void
init_vars(void)94 init_vars(void)
95 {
96 	struct ip *ip;
97 
98 	opt.ip_socket = init_pcap(opt.device, 1, "udp and dst port 68", NULL, NULL, &opt.dlt_len);
99 	opt.network = init_libnet(&opt.device, NULL);
100 	packet = (buf_packet + 2); /* IP header should be aligned */
101 	ip = (struct ip *)(packet + LIBNET_ETH_H);
102 
103 	if (libnet_init_packet(MAX_PAYLOAD_SIZE, &lnet.packet) == -1)
104 		libnet_error(LIBNET_ERR_FATAL, "libnet_init_packet failed\n");
105 
106 	dhcp_gen_packets(packet, LIBNET_UDP_H + DHCP_MIN_OPT, opt.src_ip, dsbuf, &ds);
107 }
108 
109 static void
show_info()110 show_info()
111 {
112 	fprintf(stderr, "Device      : %s\n", opt.device);
113 	//fprintf(stderr, "srcMAC      : %s", val2mac(bmac.start_mac));
114         //fprintf(stderr, "-%s\n", val2mac(bmac.end_mac));
115         //fprintf(stderr, "dstMAC      : %s\n", val2mac(spfdstmac));
116         fprintf(stderr, "srcIP       : %s\n", int_ntoa(opt.src_ip));
117 	fprintf(stderr, "DHCP Opts   : ");
118 	dhcp_print_lastsub(&ds);    /* print last suboptions */
119 }
120 
121 static void
usage(void)122 usage(void)
123 {
124 	fprintf(stderr, ""
125 "usage: dhcp [options] [target IP/Range] ...\n"
126 " 255.255.255.255 is used as default target.\n"
127 " -l <n>              Hosts in parallel (%d)\n"
128 /*" -s <IP>             source IP (%s)\n" */
129 " -v                  vebose\n"
130 " -m <mac>            source mac (random: %s)\n"
131 " -D <val1[,val2]>    DHCP option, 0=List DHCP options\n"
132 "", DFL_HOSTS_PARALLEL, val2mac(srcmac));
133 
134 	exit(0);
135 }
136 
137 static void
init_defaults(void)138 init_defaults(void)
139 {
140 	MAC_gen_pseudo(srcmac);
141 	opt.dst_ip = -1;  /* 255.255.255.255 */
142 	//opt.src_ip = 0;   /* 0.0.0.0 */
143 	init_dhcpset(&ds, dsbuf, DHCP_MIN_OPT);
144 	if (opt.hosts_parallel == 0)
145 		opt.hosts_parallel = DFL_HOSTS_PARALLEL;
146 }
147 
148 static void
do_getopt(int argc,char * argv[])149 do_getopt(int argc, char *argv[])
150 {
151 	char *ptr;
152 	int c;
153 	int dhcp_set = 0;
154 
155 	optind = 1;
156 	while ( (c = getopt(argc, argv, "+vhD:m:")) != -1)
157 	{
158 		switch (c)
159 		{
160 		case 'v':
161 			opt.flags |= FL_OPT_VERBOSE;
162 			break;
163 		case 'D':
164 			dhcp_set = 1;
165 			if (atoi(optarg) == 0)
166 			{
167 				list_dhcp();
168 				exit(0);
169 			}
170 			while ( (ptr = strchr(optarg, ',')) != NULL)
171 			{
172 				*ptr++ = '\0';
173 				dhcp_add_suboption(&ds, atoi(optarg));
174 				optarg = ptr;
175 			}
176 			if (*optarg != 0)  /* someone passed "1," */
177 				dhcp_add_suboption(&ds, atoi(optarg));
178 			break;
179 #if 0
180 		case 's':
181 			opt.src_ip = inet_addr(optarg);
182 			break;
183 #endif
184 		case 'm':
185 			opt.flags |= FL_OPT_SPOOFMAC;
186 			macstr2mac(srcmac, optarg);
187 			break;
188 		default:
189 			usage();
190 		}
191 	}
192 
193 	if (!dhcp_set)
194 		dhcp_set_default(&ds);
195 
196 	opt.argvlist = &argv[optind];
197 	opt.argc = argc - optind;
198 }
199 
200 static void
dis_timeout(struct _state * state)201 dis_timeout(struct _state *state)
202 {
203 	switch (STATE_current(state))
204 	{
205 	case STATE_RESET:
206 		STATE_current(state) = STATE_DHCPI;
207 		do_dhcp(packet, srcmac, STATE_ip(state));
208 		break;
209 	case STATE_DHCPI:
210 		STATE_current(state) = STATE_DHCPII;
211 		do_dhcp(packet, srcmac, STATE_ip(state));
212 		break;
213 	case STATE_DHCPII:
214 		STATE_current(state) = STATE_DHCPIII;
215 		do_dhcp(packet, srcmac, STATE_ip(state));
216 		break;
217 	case STATE_DHCPIII:
218 		STATE_reset(state);
219 		break;
220 	default:
221 		fprintf(stderr, "Unknown state: %d\n", STATE_current(state));
222 		STATE_reset(state);
223 		break;
224 	}
225 }
226 
227 static void
cb_filter(void)228 cb_filter(void)
229 {
230 	if (pcap_dispatch(opt.ip_socket, -1, (pcap_handler) dhcp_filter, NULL) < 0)
231 	{
232 		pcap_perror(opt.ip_socket, "pcap_dispatch");
233 		exit(-1);
234 	}
235 }
236 
237 static void
bootp_print(struct ip * ip,struct _bootp * bp,int len)238 bootp_print(struct ip *ip, struct _bootp *bp, int len)
239 {
240 	char *ptr;
241 	int c;
242 	unsigned char buf[2048];
243 	unsigned char dptype, dplen;
244 
245 	printf("BOOTP reply from %s -> ", int_ntoa(ip->ip_src));
246 	printf("%s\n", int_ntoa(ip->ip_dst));
247 	printf("  Server      : %s\n", int_ntoa(bp->siaddr));
248 	printf("  Client      : %s\n", int_ntoa(bp->yiaddr));
249 	printf("  Relay Agent : %s\n", int_ntoa(bp->giaddr));
250 	printf("  ServerName  : %.*s\n", (int)sizeof bp->sname, bp->sname);
251 	printf("  BootFile    : %.*s\n", (int)sizeof bp->file, bp->file);
252 	printf("  MAC         : %s\n", val2mac(bp->chaddr));
253 
254 	ptr = bp->options;
255 	c = 4;  /* magic cookie */
256 	while (c + 2 < len)
257 	{
258 		if ( (dptype = *(ptr + c++)) == DHCP_END)
259 			break;
260 		if ( (dplen = *(ptr + c)) > len - c)
261 			break;
262 
263 		dhcp_val2str(buf, sizeof buf, dptype, dplen, ptr + c + 1);
264 		printf("  %s\n", buf);
265 		c += *(ptr + c) + 1;
266 	}
267 }
268 
269 static void
dhcp_filter(unsigned char * u,struct pcap_pkthdr * p,unsigned char * packet)270 dhcp_filter(unsigned char *u, struct pcap_pkthdr *p, unsigned char *packet)
271 {
272 	char buf[2048];
273 	struct ip ip;
274 	struct udphdr *udp = (struct udphdr *)buf;
275 	unsigned short options;
276 	size_t len;  /* udp header + data */
277 	struct _bootp *bp = (struct _bootp *)(buf + 8);
278 
279 	/* 312 + 20 + 8 */
280 	if (p->caplen < (opt.dlt_len + 20 + 8))
281 		return;
282 	memcpy(&ip, packet + opt.dlt_len, sizeof ip);
283 	if ( vrfy_ip(&ip, p->caplen - opt.dlt_len, &options) != 0)
284 		return;
285 
286 	len = p->caplen - opt.dlt_len - 20 - options;
287 	if (sizeof buf < len)
288 		len = sizeof buf;
289 	memcpy(buf, packet + opt.dlt_len + 20 + options, len);
290 
291 	if (p->caplen < opt.dlt_len + 20 + options)
292 		return;
293 
294 	if (ip.ip_p != IPPROTO_UDP)
295 		return;
296 
297 	if (vrfy_udp(udp, len) != 0)
298 		return;
299 
300 	if (udp->uh_dport != htons(68))
301 		return;
302 
303 	if (bp->op != BOOTP_REPLY)
304 		return;
305 
306 	if (len > ntohs(udp->uh_ulen))
307 		len = ntohs(udp->uh_ulen);
308 
309 	if (len < sizeof(struct _bootp) + 8)
310 		return;  /* Empty BOOTP message */
311 
312 	bootp_print(&ip, bp, len - 8 - sizeof(struct _bootp));
313 
314 	exit(0); /* exit after first answer we got */
315 }
316 
317 int
dhcp_main(int argc,char * argv[])318 dhcp_main(int argc, char *argv[])
319 {
320 	struct _ipranges ipr;
321 	struct _state state;
322 	int ret;
323 
324 	memset(buf_packet, 0, sizeof buf_packet);
325 
326 	init_defaults();
327 	do_getopt(argc, argv);
328 	init_vars();
329 
330 	/*
331 	 * Use default broadcast if no IP is given.
332 	 */
333 	if (opt.argc == 0)
334 	{
335 		opt.argvlist--;
336 		opt.argvlist[0] = "255.255.255.255";
337 		opt.argc++;
338 	}
339 	IP_init(&ipr, opt.argvlist,  (opt.flags & FL_OPT_SPREADMODE)?IPR_MODE_SPREAD:0);
340 
341 	if (opt.flags & FL_OPT_VERBOSE)
342 		show_info();
343 
344         if (!SQ_init(&opt.sq, opt.hosts_parallel, sizeof(struct _state), pcap_fileno(opt.ip_socket), dis_timeout, cb_filter))
345 	{
346 		fprintf(stderr, "Failed to init states: %s\n", strerror(errno));
347 		exit(-1); /* Out of Memory */
348 	}
349 
350 	/* Set MAC here */
351 	memset(&state, 0, sizeof state);
352 
353 	while (1)
354 	{
355 		IP_next(&ipr);
356 		if (IP_current(&ipr))
357                 {
358                         STATE_ip(&state) = IP_current(&ipr);
359                         ret = STATE_wait(&opt.sq, &state);
360                 } else
361 			ret = STATE_wait(&opt.sq, NULL);
362 
363 		if (ret != 0)
364 			break;
365 	}
366 
367 	return 0;
368 }
369 
370