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