Annotation of embedaddon/dhcdrop/src/dhcdrop.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2009 by Chebotarev Roman <roma@ultranet.ru>
3: *
4: * This program is free software; you can redistribute it and/or modify
5: * it under the terms of the GNU General Public License as published by
6: * the Free Software Foundation; either version 2 of the License.
7: *
8: * This program is distributed in the hope that it will be useful,
9: * but WITHOUT ANY WARRANTY; without even the implied warranty of
10: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11: * GNU General Public License for more details.
12: *
13: * You should have received a copy of the GNU General Public License
14: * along with this program; if not, write to the Free Software
15: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16: */
17:
18: #include "common_includes.h"
19: #include "net.h"
20: #include "dhcp.h"
21: #include "dhcdrop_types.h"
22: #include "net_functions.h"
23: #include "dhcp_functions.h"
24: #include "dhcdrop.h"
25:
26: const char usage_message[] = "Usage:\n"
27: "dhcpdrop [-h] [-D] [-t] [-y] [-r] [-b] [-a] [-A] [-f] [-R] [-q]\n"
28: "\t[-m <count>] [-c <count>] [-n <hostname>] [-N <clientname>]\n"
29: "\t[-p <port>] [-P <port>] [-w <secs>] [-T <timeout>]\n"
30: "\t[-M <max-hosts-scan>] [-l <MAC-address>] [-L <network>]\n"
31: "\t[-S <network/mask>] [-F <from-IP>] [-s <server-IP>]\n"
32: "\t[-C <"CHILDREN_TYPE" count (2 - 32)>] [<initial MAC address>]\n"
33: "\t-i <interface-name|interface-index>\n";
34:
35: const char keys[] = "\t-h - print this help message\n"
36: "\t-D - list of available network interfaces.\n"
37: "\t Format - index:name.\n"
38: "\t-t - test mode. Send DHCPDISCOVER and wait DHCPOFFER.\n"
39: "\t Exit with code 200 if DHCPOFFER is received.\n"
40: "\t Otherwise - exit with code 0.\n"
41: "\t-y - answer 'yes' to all questions.\n"
42: "\t-r - disable ethernet address randomize.\n"
43: "\t-b - use flag 'broadcast' in DHCP message\n"
44: "\t (default: don't use flag broadcast).\n"
45: "\t-a - always wait server('s) response\n"
46: "\t on default DHCP client port (68)\n"
47: "\t-A - always wait server('s) response\n"
48: "\t from default DHCP server port (67)\n"
49: "\t-f - flood mode. Generate DHCPDISCOVER flood.\n"
50: "\t-R - send DHCPRELEASE from source MAC address specified\n"
51: "\t by <initial MAC address> and IP address specified\n"
52: "\t by option -F to server specified by option -s.\n"
53: "\t-q - quiet mode.\n"
54: "\t-m count - maximum number of attempts\n"
55: "\t to receive answer from DHCP server.\n"
56: "\t-c count - maximum number of receiving addresses\n"
57: "\t from DHCP server (default: 255).\n"
58: "\t-n hostname - value of DHCP-option 'HostName'\n"
59: "\t (default: 'DHCP-dropper').\n"
60: "\t-N clientname - value of DHCP-option 'Vendor-Class'\n"
61: "\t (default: 'DHCP-dropper').\n"
62: "\t-p port - set client port value.\n"
63: "\t-P port - set server port value.\n"
64: "\t-w seconds - set timeout after which the process will be\n"
65: "\t restarted when using agressive mode (see option -L)\n"
66: "\t (default: 60 secs).\n"
67: "\t-T timeout - set timeout (of) waiting server response\n"
68: "\t in seconds (default: 3).\n"
69: "\t-M max-hosts-scan - maximum number of hosts scanned if\n"
70: "\t agressive mode (is used) (option -L).\n"
71: "\t-l MAC-address - ethernet address of DHCP server\n"
72: "\t which need(s) to (be) ignore(d). May be several servers.\n"
73: "\t Need option '-l' for each server.\n"
74: "\t-L network - specify legal network(s) on interfase. May be\n"
75: "\t several networks. If this parameter is set, dhcdrop\n"
76: "\t uses agressive mode: it scans address range assigned\n"
77: "\t by DHCP server for searching hosts with incorrect addresses,\n"
78: "\t sends DHCPRELEASE to server from every found host after\n"
79: "\t this it restarts process of receiving addreses.\n"
80: "\t-S network/mask - ARP-scan for network 'network' with network\n"
81: "\t mask 'mask' (CIDR notation). Source IP address for scanning\n"
82: "\t specified by option -F. If source IP is not set - using random\n"
83: "\t IP address from network address range.\n"
84: "\t-F from-IP - source IP for scanning network or sending\n"
85: "\t DHCPRELEASE (see option -S and -R).\n"
86: "\t-s server-IP - specify DHCP server IP address.\n"
87: "\t Used with option -R.\n"
88: "\t-C count - "
89: #ifdef _WIN32
90: "child thread"
91: #else
92: "children"
93: #endif
94: " number\n"
95: "\t (default: 0, minimal value: 2, maximum: 32).\n"
96: "\t Compatible only with flag '-f'.\n"
97: #ifdef _WIN32
98: "\t WARNING: not effectively under OS Windows.\n"
99: #endif
100: "\t-i interface - defines network interface, can be name or\n"
101: "\t index (cannot be 'any'). For listing available\n"
102: "\t interfaces use option -D.\n";
103:
104: const char ret_codes[] = "Program can exit with codes:\n"
105: "\t0 - Exit success. Illegal DHCP server not found.\n"
106: "\t10 - invalid user ID. You must be root for running programm.\n"
107: "\t20 - failed to set signal handler.\n"
108: "\t30 - configuration error. See usage.\n"
109: "\t40 - memory allocation error. Insufficient memory?\n"
110: "\t50 - error opening ethernet device.\n"
111: "\t51 - error listing devices.\n"
112: "\t60 - pcap filter overflow.\n"
113: "\t70 - pcap compile error.\n"
114: "\t80 - pcap set filter error.\n"
115: "\t90 - error sending packet.\n"
116: "\t100 - error getting packet.\n"
117: "\t110 - set non blocked mode error.\n"
118: "\t120 - invalid device.\n"
119: "\t200 - illegal DHCP server was found.\n";
120:
121: const char leases_warning[] = "\nWARNING: Failed to take away all the IP addresses assigned by DHCP server.\n"
122: "Perhaps DHCP server checks availability of IP addresses by sending ARP-request\n"
123: "before assigning them. Try to restart dhcpdrop later. If it doesn't help\n"
124: "try to disconnect problem hosts temporarily, then send manually DHCPRELEASE\n"
125: "from address of this hosts (use option -R) and restart dhcdrop.\n";
126:
127: const uint8_t broadcast_ether[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
128:
129: int main (int argc, char **argv)
130: {
131: struct config_params config; /* Parametrs from command line */
132:
133: srand(time(0));
134: atexit(cleanup);
135: set_timer_handler(timeout);
136: set_console_handler(int_sign);
137:
138: configure(argc, argv, &config);
139:
140: int ret = exec_action(&config);
141:
142: if(!config.quiet_mode && !config.test_mode)
143: printf("Finished.\n");
144:
145: return ret;
146: }
147:
148: int exec_action(const struct config_params * config)
149: {
150: int ret;
151:
152: #ifndef _WIN32
153: if(geteuid())
154: {
155: printf("Your EUID shoud be 0 (root) to run this program.\n"
156: "Currently your EUID is %u. Aborting.\n", geteuid());
157: return ERR_EUID;
158: }
159: #endif
160:
161: if(config->discover)
162: interfaces_discover(0);
163:
164: if(!config->test_mode && !config->quiet_mode)
165: printf("Using interface: '%s'\n", config->if_name);
166:
167: if(config->flood)
168: {
169: printf("Sending DHCPDISCOVER flood. Press Ctrl+C to abort...\n");
170: send_flood(config);
171: return EXIT_SUCCESS;
172: }
173:
174: /* Opening network device */
175: pcap_t * pcap_socket = get_device(config);
176:
177: if(config->scanned_network)
178: {
179: scan_subnet(pcap_socket, config->from_ip, config->source_mac, config->scanned_network, config->scan_netmask);
180: pcap_close(pcap_socket);
181: return EXIT_SUCCESS;
182: }
183:
184: if(config->send_dhcprelease)
185: {
186: printf("Send DHCPRELEASE from %s ", config->str_source_mac);
187: printf("client IP %s ", iptos(config->from_ip));
188: printf("to DHCP server %s\n", iptos(config->server_ip));
189: ret = send_dhcp_release(pcap_socket, config, config->source_mac,
190: config->server_ip, config->from_ip, rand());
191: pcap_close(pcap_socket);
192: return ret;
193: }
194:
195: struct dhcp_packet server_response;
196: uint16_t response_length;
197:
198: /* Searching DHCP server in the network */
199: struct dhcp_packet_net_header net_header;
200: ret = get_dhcp_server(config, pcap_socket, &net_header,
201: &server_response, &response_length);
202: if(!ret)
203: {
204: pcap_close(pcap_socket);
205: return EXIT_SUCCESS; /* Illegal DHCP server not found */
206: }
207:
208: if(ret != ILLEGAL_SERV_FOUND)
209: return ret; /* Error occured */
210:
211: if(config->test_mode) /* If test-mode - exit without dropping */
212: {
213: pcap_close(pcap_socket);
214: return ILLEGAL_SERV_FOUND;
215: }
216:
217: char str_srv_etheraddr[MAX_STR_MAC_LEN + 1];
218: bzero(str_srv_etheraddr, sizeof(str_srv_etheraddr));
219: etheraddr_bin_to_str(net_header.eth_head.ether_shost, str_srv_etheraddr);
220: /* Drop server with ethernet address in 'str_srv_etheraddr' */
221: int dropped = drop_dhcp_server(config, pcap_socket, str_srv_etheraddr);
222: if(config->quiet_mode)
223: printf("%d adresses received from DHCP server.\n", dropped);
224:
225: if(legal_nets_list(get_count, 0)) /* If set - use agressive mode */
226: {
227: if(!agressive_clean_leases(pcap_socket, config, &net_header,
228: &server_response, response_length))
229: {
230: if(hosts_list(get_count, 0, 0) > 1)
231: {
232: /* Ask user: "Restart dropping? [y/n]" */
233: char yN[2] = "n"; /* Default - don't restart */
234: (config->yes)? yN[0] = 'y' : (printf("Restart dropping? [y/n] "), scanf("%s", yN));
235: if((yN[0] == 'y') || (yN[0] == 'Y'))
236: {
237: printf("Restart dropping DHCP server after %d seconds timeout...\n", config->wait_before_restart);
238: sleep(config->wait_before_restart);
239: dropped = drop_dhcp_server(config, pcap_socket, str_srv_etheraddr);
240: if(config->quiet_mode)
241: printf("%d adresses received.\n", dropped);
242: if((dropped < (hosts_list(get_count, 0, NULL) - 1 + 1)) && /* -1 - itself DHCP server,
243: + 1 - start address */
244: !config->quiet_mode)
245: printf("%s\n", leases_warning);
246: }
247: }
248: }
249: }
250:
251: pcap_close(pcap_socket);
252:
253: return ILLEGAL_SERV_FOUND;
254: }
255:
256: void configure(const int argc, char **argv, struct config_params * params)
257: {
258: bzero(params, sizeof(struct config_params));
259: params->rand_mac_always = 1; /* Default - randomize source ethernet address */
260: params->max_attempts = MAX_ATTEMPTS; /* If == 0 - exit */
261: params->server_port = DEF_SERVER_PORT;
262: params->client_port = DEF_CLIENT_PORT;
263: params->max_hosts_scan = MAX_HOSTS_SCAN;
264: params->wait_before_restart = WAIT_BEFORE_RERUN;
265:
266: if(argc < 2)
267: usage(0);
268:
269: int i;
270: int ret;
271:
272: for(i = 1; i < argc; ++i)
273: {
274: /* t y r f b h m i c n N C l p P a A T D L M w S F R s*/
275: if(argv[i][0] == '-')
276: {
277: /*Parsing options without params*/
278: if(strlen(argv[i]) > 2)
279: usage(0);
280: switch(argv[i][1])
281: {
282: case 't':
283: params->test_mode = 1;
284: continue;
285: case 'y':
286: params->yes = 1;
287: continue;
288: case 'r':
289: params->rand_mac_always = 0;
290: continue;
291: case 'f':
292: params->flood = 1;
293: continue;
294: case 'b':
295: params->broadcast = 1;
296: continue;
297: case 'a':
298: params->always_wait_to_68 = 1;
299: continue;
300: case 'A':
301: params->always_wait_from_67 = 1;
302: continue;
303: case 'R':
304: params->send_dhcprelease = 1;
305: continue;
306: case 'q':
307: params->quiet_mode = 1;
308: continue;
309: case 'D':
310: params->discover = 1;
311: return;
312: case 'h':
313: usage(1);
314: break;
315: }
316: if(i + 1 >= argc)
317: usage(0);
318: if(argv[i + 1][0] == '-')
319: usage(0);
320:
321: /*Parsing options with params*/
322: switch(argv[i][1])
323: {
324: case 'm':
325: params->max_attempts = atoi(argv[i + 1]);
326: if(params->max_attempts < 1)
327: usage(0);
328: break;
329: case 'i':
330: params->if_name = argv[i + 1];
331: if(atoi(params->if_name) > 0)
332: {
333: params->if_name = interfaces_discover(atoi(params->if_name));
334: if(!params->if_name)
335: {
336: printf("Can't find device by index: '%s', use option '-D' for interface discover. Exit.\n",
337: argv[i + 1]);
338: exit(ERR_LISTING_DEV);
339: }
340: }
341: break;
342: case 'c':
343: params->max_address_count = atoi(argv[i + 1]);
344: if(params->max_address_count < 1)
345: usage(0);
346: break;
347: case 'n':
348: if(strlen(argv[i + 1]) > (sizeof(params->client_hostname) - 1))
349: {
350: printf("Client hostname too long.\n");
351: usage(0);
352: }
353: memcpy(params->client_hostname, argv[i + 1], strlen(argv[i + 1]));
354: break;
355: case 'N':
356: if(strlen(argv[i + 1]) > (sizeof(params->dhcp_client) - 1))
357: {
358: printf("DHCP client name too long.\n");
359: usage(0);
360: }
361: memcpy(params->dhcp_client, argv[i + 1], strlen(argv[i + 1]));
362: break;
363: case 'C':
364: params->children_count = atoi(argv[i + 1]);
365: if(params->children_count < 2 ||
366: params->children_count > MAX_CHILDREN)
367: usage(0);
368: break;
369: case 'p':
370: params->client_port = atoi(argv[i + 1]);
371: if(params->client_port < 1 || params->client_port > MAX_PORT_VALUE)
372: {
373: printf("Invalid DHCP client port value: '%s'\n", argv[i + 1]);
374: usage(0);
375: }
376: break;
377: case 'P':
378: params->server_port = atoi(argv[i + 1]);
379: if(params->server_port < 1 || params->server_port > MAX_PORT_VALUE)
380: {
381: printf("Invalid DHCP server port value: '%s'\n", argv[i + 1]);
382: usage(0);
383: }
384: break;
385: case 'l':
386: if(strlen(argv[i + 1]) > 17)
387: {
388: printf("Legal-server ethernet address too long.\n");
389: usage(0);
390: }
391: if(!ignor_servers_list(add, argv[i + 1]))
392: {
393: printf("Invalid legal-server ethernet address: '%s'\n", argv[i + 1]);
394: usage(0);
395: }
396: break;
397: case 'T':
398: params->timeout = atoi(argv[i + 1]);
399: if(params->timeout < 1)
400: {
401: printf("Invalid timeout value: '%s'\n", argv[i + 1]);
402: usage(0);
403: }
404: break;
405: case 'L':
406: {
407: if(strlen(argv[i + 1]) > MAX_IP4_ALEN) /* 3 = / + \d + d\. Sample: "/24" */
408: {
409: printf("Invalid legal network IP address: '%s'\n", argv[i + 1]);
410: usage(0);
411: }
412:
413: uint32_t net;
414: if( ( net = inet_addr(argv[i + 1])) == INADDR_NONE)
415: {
416: printf("Invalid legal network IP address: '%s'\n", argv[i + 1]);
417: usage(0);
418: }
419:
420: legal_nets_list(add, &net);
421:
422: break;
423: }
424: case 'M':
425: params->max_hosts_scan = atoi(argv[i + 1]);
426: if(params->max_hosts_scan < 4)
427: {
428: printf("Invalid maximum hosts scan value: %s. Minimum - 4.\n", argv[i + 1]);
429: usage(0);
430: }
431: break;
432: case 'w':
433: params->wait_before_restart = atoi(argv[i + 1]);
434: if(params->wait_before_restart < 1)
435: {
436: printf("Invalid 'wait before rerun' value: %s\n", argv[i + 1]);
437: usage(0);
438: }
439: break;
440: case 'S':
441: {
442: char network[MAX_IP4_ALEN + 3 + 1]; /* 3 - CIDR mask (/24 e.g.) 1 - \0 */
443: bzero(network, sizeof(network));
444:
445: if(strlen(argv[i + 1]) > (sizeof(network) - 1))
446: {
447: printf("Invalid network for scanning: %s - too long.\n", argv[i + 1]);
448: usage(0);
449: }
450:
451: strncpy(network, argv[i + 1], strlen(argv[i + 1]));
452:
453: char * mask = strrchr(network, '/');
454: if(!mask)
455: {
456: printf("Invalid network for scanning: %s - netmask not specified.\n", network);
457: usage(0);
458: }
459:
460: *mask = '\0'; /* Split network and netmask strings */
461: ++mask;
462:
463: if( (params->scanned_network = inet_addr(network)) == INADDR_NONE)
464: {
465: printf("Invalid network IP address for scanning: %s\n", network);
466: usage(0);
467: }
468:
469: params->scan_netmask = atoi(mask);
470: if( (params->scan_netmask < 0) || (params->scan_netmask > 30))
471: {
472: printf("Invalid netmask length: %s. Minimum - 0, maximum - 30.\n", mask);
473: usage(0);
474: }
475:
476: int bit_pos;
477: uint32_t netmask = 0;
478: for(bit_pos = 0; bit_pos < (32 - params->scan_netmask) ; ++bit_pos)
479: netmask |= 1 << bit_pos;
480: params->scan_netmask = htonl(~netmask);
481:
482: break;
483: }
484: case 'F':
485: {
486: if( (params->from_ip = inet_addr(argv[i + 1])) == INADDR_NONE)
487: {
488: printf("Invalid source IP address: %s\n", argv[i + 1]);
489: usage(0);
490: }
491: break;
492: }
493: case 's':
494: {
495: if( (params->server_ip = inet_addr(argv[i + 1])) == INADDR_NONE)
496: {
497: printf("Invalid server IP address: %s\n", argv[i + 1]);
498: usage(0);
499: }
500: break;
501: }
502: default:
503: usage(0);
504: break;
505: }
506: ++i;
507: }
508: else
509: {
510: if(strlen(argv[i]) > (sizeof(params->str_source_mac) - 1) )
511: {
512: printf("Length source MAC address too long. Exit.\n");
513: usage(0);
514: }
515: if(strlen(params->str_source_mac))
516: usage(0); /*Ethernet address already set*/
517: replace_semicolons(argv[i]);
518: strncat(params->str_source_mac, argv[i], MAX_STR_MAC_LEN);
519: }
520: }
521:
522: if(params->flood && params->test_mode)
523: {
524: printf("Error: option '-f' (flood) not compatible with option '-t' (test mode).\n");
525: usage(0);
526: }
527:
528: if(params->children_count && ! params->flood)
529: {
530: printf("Error: option '-C' (children count) compatible only with option '-f' (flood).\n");
531: usage(0);
532: }
533:
534: if(params->max_address_count > 255 && !params->rand_mac_always && !params->flood)
535: {
536: printf("Error: Option 'max address count' can't be greatest then 255 if you use option -r\n");
537: usage(0);
538: }
539:
540: if(!params->if_name)
541: usage(0);
542:
543: if(!strcmp("any", params->if_name))
544: {
545: printf("Can't drop DHCP server on 'any' device! Exit.\n");
546: exit(ERR_CONFIG);
547: }
548:
549: if( params->send_dhcprelease && (!params->server_ip ||
550: !params->from_ip || !strlen(params->str_source_mac)) )
551: {
552: printf("You must specify server IP address (use option -s), client IP address (use option -F)\n"
553: "\tand MAC address for sending DHCPRELEASE.\n");
554: usage(0);
555: }
556:
557: /* If not set initial MAC - set random value */
558: if(!strlen(params->str_source_mac))
559: rand_ether_addr(params->str_source_mac);
560: ret = etheraddr_str_to_bin(params->str_source_mac, params->source_mac);
561: if(!ret)
562: {
563: printf("Invalid parametrs in etheraddr_str_to_bin(). Aborting programm!");
564: abort();
565: }
566: if(ret < 0)
567: {
568: printf("Invalid source MAC address: '%s'\n", params->str_source_mac);
569: usage(0);
570: }
571:
572: if(! *params->client_hostname)
573: strncat(params->client_hostname, DEF_HOSTNAME, sizeof(params->client_hostname) - 1);
574: if(! *params->dhcp_client)
575: strncat(params->dhcp_client, DEF_DHCPCLIENT, sizeof(params->dhcp_client) - 1);
576: if( !params->max_address_count && !params->flood)
577: params->max_address_count = MAX_ADDR_COUNT;
578: if( !params->timeout)
579: params->timeout = DEF_TIMEOUT;
580: return;
581: }
582:
583: /*
584: If num == 0 - show all available interfaces and exit from programm.
585: Else - return name of interface by number 'num'
586: */
587: char * interfaces_discover(const int num)
588: {
589: if(!num)
590: printf("Available interfaces:\n");
591:
592: char errbuf[PCAP_ERRBUF_SIZE];
593: pcap_if_t *dev_list_start = 0, * dev_ptr = 0;
594: char * if_name = 0;
595: int32_t ret = pcap_findalldevs(&dev_list_start, errbuf);
596:
597: if(ret == -1)
598: {
599: printf("Error: %s\n", errbuf);
600: exit(ERR_LISTING_DEV);
601: }
602:
603: if(!dev_list_start)
604: {
605: printf("Error.\n");
606: exit(ERR_LISTING_DEV);
607: }
608:
609: int i = 1;
610: for(dev_ptr = dev_list_start; dev_ptr; dev_ptr = dev_ptr->next)
611: {
612: if(num)
613: {
614: if(!strcmp("any", dev_ptr->name))
615: continue;
616: if((i == num))
617: {
618: if_name = (char *) calloc(strlen(dev_ptr->name) + 1, sizeof(char));
619: if(!if_name)
620: {
621: printf("Can't allocate memory for interface '%s'. Quit.\n", dev_ptr->name);
622: exit(ERR_MEMORY);
623: }
624: strncpy(if_name, dev_ptr->name, strlen(dev_ptr->name));
625: pcap_freealldevs(dev_list_start);
626: return if_name;
627:
628: }
629: ++i;
630: }
631: else
632: {
633: if(strcmp("any", dev_ptr->name))
634: {
635: printf("%d:", i++);
636: ifprint(dev_ptr);
637: }
638: }
639: }
640:
641: pcap_freealldevs(dev_list_start);
642:
643: if(num) /* Suitable device not found */
644: return 0;
645:
646: exit(ERR_CONFIG);
647: }
648:
649: void send_flood(const struct config_params * params)
650: {
651: int i;
652: int ret_code;
653: struct flood_params par;
654: par.config = params;
655: #ifdef _WIN32
656: HANDLE threads[MAX_THREADS_COUNT]; /* Array of threads for DHCP senders */
657: DWORD th_id[MAX_THREADS_COUNT]; /* Array of threads identifiers */
658: par.flood_threads = threads;
659: par.threads_ids = th_id;
660: #endif
661:
662: if(params->children_count < 2)
663: {
664: if( (ret_code = start_flood((void*) &par) ) )
665: exit(ret_code);
666: return;
667: }
668: #ifdef _WIN32
669: printf("WARNING: multithread flood not effectively under OS Windows!\n");
670: #endif
671: printf("Create %d "CHILDREN_TYPE" for flood.\n", params->children_count);
672: for( i = 0; i < params->children_count; ++i)
673: new_child(&par, i);
674: printf("Waiting for all "CHILDREN_TYPE".\n");
675: wait_children(&par);
676: return;
677: }
678:
679: int get_dhcp_server(const struct config_params * config, /* Configuration parametrs. Can't be NULL */
680: pcap_t * pcap_socket, /* Pointer to pcap device. Can't be NULL */
681: struct dhcp_packet_net_header * net_header, /* Can't be NULL */
682: struct dhcp_packet * server_response, /* Function store DHCP response server here, */
683: /* can't be NULL */
684: uint16_t * response_length)
685: {
686: if(!pcap_socket || !server_response)
687: return ERR_ABNORMAL;
688:
689: char filter[PCAP_FILTER_LEN + 1]; /* filter for pcap_setfilter */
690: char str_ether_addr[MAX_STR_MAC_LEN + 1];
691:
692: bzero(filter, sizeof(filter));
693:
694: /* Create and set DHCP filter */
695: int ret;
696: if( (ret = make_serverdiscover_filter(filter, sizeof(filter) - 1, config, config->str_source_mac)) )
697: {
698: printf("Can't create DHCP filter.\n");
699: exit(ret);
700: }
701: /*printf("Filter: %s\n", filter);*/
702: if( (ret = set_pcap_filter(pcap_socket, filter)) )
703: {
704: printf("Can't set DHCP filter.\n");
705: exit(ret);
706: }
707:
708: int packet_len;
709:
710: int i;
711: uint32_t xid = rand();
712: for(i = 0; i < config->max_attempts; ++ i)
713: {
714: /* Sending DHCPDISCOVER */
715: if( (ret = send_dhcp_discover(pcap_socket, config, 0, xid)) )
716: return ret;
717: /* and waiting DHCPOFFER */
718: ret = get_dhcp_response(pcap_socket, config->timeout, DHCPOFFER, xid,
719: net_header, server_response, &packet_len);
720: if(!ret) /* DHCP server responded */
721: {
722: struct in_addr ip;
723: /* Trying to decode DHCP response */
724: if((ret = get_dhcp_option(server_response, packet_len,
725: DHO_DHCP_SERVER_IDENTIFIER, (void*)&ip.s_addr, sizeof(ip.s_addr))) < 1)
726: {
727: printf("Can't get DHCP server ID option!\n");
728: continue;
729: }
730:
731: if(ret < 0)
732: continue; /* Possible DoS */
733:
734: if(config->test_mode)
735: {
736: printf("DHCP SRV: %s ", inet_ntoa(ip));
737: ip.s_addr = net_header->ip_header.saddr;
738: printf("(IP-hdr: %s) SRV ether: ", inet_ntoa(ip));
739: print_ether(net_header->eth_head.ether_shost);
740: printf(", YIP: %s\n", inet_ntoa(server_response->yiaddr));
741: }
742: else
743: {
744: /* Convert server ethernet address to string */
745: bzero(str_ether_addr, sizeof(str_ether_addr));
746: etheraddr_bin_to_str(net_header->eth_head.ether_shost, str_ether_addr);
747: /* Print DHCP-info from packet */
748: printf("Got response from server %s ", inet_ntoa(ip));
749: ip.s_addr = net_header->ip_header.saddr;
750: printf("(IP-header %s), server ethernet address: ", inet_ntoa(ip));
751: print_ether(net_header->eth_head.ether_shost);
752: printf(", ");
753: uint32_t lease_time;
754: if(get_dhcp_option(server_response, packet_len, DHO_DHCP_LEASE_TIME,
755: (void*)&lease_time, sizeof(lease_time)) > 0)
756: printf("lease time: %.2gh (%us)\n", (float)ntohl(lease_time)/3600, ntohl(lease_time));
757:
758: decode_dhcp(server_response, packet_len);
759:
760: /* Ask user: "Drop him? [y/n]" */
761: char yN[2] = "n"; /* Default - don't drop */
762: (config->yes)? yN[0] = 'y' : (printf("Drop him? [y/n] "), scanf("%s", yN));
763: if((yN[0] != 'y') && (yN[0] != 'Y')) /* Don't drop this server */
764: {
765: /*Add DHCP server ethernet address in ignored list*/
766: ignor_servers_list(add, str_ether_addr);
767:
768: /* Reinit PCAP filter */
769: if( (ret = make_serverdiscover_filter(filter, sizeof(filter) - 1,
770: config, config->str_source_mac)) )
771: {
772: printf("Can't create DHCP filter.\n");
773: exit(ret);
774: }
775: /*printf("Filter: %s\n", filter);*/
776: if( (ret = set_pcap_filter(pcap_socket, filter)) )
777: {
778: printf("Can't set DHCP filter.\n");
779: exit(ret);
780: }
781:
782: /* Reinit DHCP server search loop */
783: i = -1;
784: if(!config->quiet_mode)
785: printf("Searching next server...\n");
786: continue;
787: }
788: *response_length = packet_len;
789: }
790: break;
791: }
792:
793: if(ret > 0)
794: exit(ret); /* Fatal error occured */
795:
796: if(!config->quiet_mode)
797: printf("Wait DHCPOFFER timeout. Resending DHCPDISCOVER.\n");
798: }
799:
800: if(ret < 0) /* DHCPDISCOVER timeout. Illegal server not found. */
801: return 0;
802:
803: return ILLEGAL_SERV_FOUND;
804: }
805:
806: int drop_dhcp_server(const struct config_params * config, pcap_t * pcap_socket,
807: const char * srv_etheraddr)
808: {
809: char filter[PCAP_FILTER_LEN + 1]; /* filter for pcap_setfilter */
810: uint8_t bin_src_etheraddr[ETH_ALEN];
811: char str_src_etheraddr[MAX_STR_MAC_LEN + 1];
812: struct dhcp_packet_net_header net_header;
813: struct dhcp_packet dhcp_resp;
814:
815: bzero(str_src_etheraddr, sizeof(str_src_etheraddr));
816:
817: strncat(str_src_etheraddr, config->str_source_mac, sizeof(str_src_etheraddr) - 1);
818: etheraddr_str_to_bin(str_src_etheraddr, bin_src_etheraddr);
819:
820: int ret;
821: int i;
822: int j;
823: int packet_len;
824: uint32_t xid;
825: int grab_ip_count = 0;
826:
827: /* Send DHCPDISCOVER(s) and wait response from DHCP server */
828: for(i = config->max_attempts; i > 0;)
829: {
830: bzero(filter, sizeof(filter));
831: /* Create and set filter for DHCP transaction */
832: if( (ret = make_serverdrop_filter(filter, sizeof(filter) - 1, config,
833: str_src_etheraddr, srv_etheraddr)) )
834: {
835: printf("Can't create pcap filter for dropping DHCP server! Exit.\n");
836: exit(ret);
837: }
838:
839: if( (ret = set_pcap_filter(pcap_socket, filter)) )
840: {
841: printf("Can't set DHCP filter.\n");
842: exit(ret);
843: }
844:
845: xid = rand();
846: /* Sending DHCPDISCOVER */
847: if( (ret = send_dhcp_discover(pcap_socket, config, bin_src_etheraddr, xid)) )
848: exit(ret);
849:
850: /* and waiting DHCPOFFER */
851: ret = get_dhcp_response(pcap_socket, config->timeout, DHCPOFFER, xid,
852: &net_header, &dhcp_resp, &packet_len);
853:
854: if(!ret) /* DHCP server responded */
855: {
856: uint32_t server_id;
857: if((ret = get_dhcp_option(&dhcp_resp, packet_len,
858: DHO_DHCP_SERVER_IDENTIFIER, (void*)&server_id, sizeof(server_id))) < 1)
859: {
860: printf("Can't get DHCP server ID option!\n");
861: continue;
862: }
863: if(ret < 0)
864: continue; /* Possible DoS */
865:
866: /* Trying to receive offered IP address */
867: for(j = 0; j < config->max_attempts; ++j)
868: {
869: /* Sendig DHCPREQUEST */
870: if( (ret = send_dhcp_request(pcap_socket, config, bin_src_etheraddr,
871: server_id, dhcp_resp.yiaddr.s_addr, xid)) )
872: exit(ret);
873:
874: /* and waiting DHCPACK */
875: ret = get_dhcp_response(pcap_socket, config->timeout, DHCPACK, xid,
876: &net_header, &dhcp_resp, &packet_len);
877: if(!ret) /* DHCP server responded */
878: {
879: ++grab_ip_count;
880: if(!config->quiet_mode)
881: {
882: printf("%d. ", grab_ip_count);
883: decode_dhcp(&dhcp_resp, packet_len);
884: }
885:
886: bzero(str_src_etheraddr, sizeof(str_src_etheraddr));
887:
888: if(config->rand_mac_always)
889: {
890: rand_ether_addr(str_src_etheraddr);
891: etheraddr_str_to_bin(str_src_etheraddr, bin_src_etheraddr);
892: }
893: else
894: {
895: ++bin_src_etheraddr[ETH_ALEN - 1];
896: etheraddr_bin_to_str(bin_src_etheraddr, str_src_etheraddr);
897: }
898:
899: i = config->max_attempts;
900: goto get_next_ip;
901: }
902:
903: if(ret > 0)
904: exit(ret); /* Fatal error occured */
905:
906: if(!config->quiet_mode)
907: printf("Wait DHCPACK timeout. Resending DHCPREQUEST.\n");
908: }
909: }
910:
911: if(ret > 0)
912: exit(ret); /* Fatal error occured */
913:
914: if(!config->quiet_mode)
915: printf("Wait DHCPOFFER timeout. Resending DHCPDISCOVER.\n");
916: --i;
917:
918: get_next_ip:;
919: if(grab_ip_count >= config->max_address_count)
920: break;
921: }
922: return grab_ip_count;
923: }
924:
925: int agressive_clean_leases(pcap_t * pcap_socket,
926: const struct config_params * config, struct dhcp_packet_net_header * srv_net_header,
927: const struct dhcp_packet * srv_resp, uint16_t resp_len)
928: {
929: if(!config->quiet_mode)
930: printf("Trying to use agressive mode.\n");
931:
932: uint32_t server_netmask;
933:
934: if(get_dhcp_option(srv_resp, resp_len, DHO_SUBNET_MASK, &server_netmask, sizeof(server_netmask)) < 1)
935: {
936: printf("Can't get netmask from DHCP packet.\n");
937: return -1;
938: }
939:
940: int lnets_count = legal_nets_list(get_count, 0);
941: uint32_t lnet, i;
942: for(i = 0; i < lnets_count; ++i)
943: {
944: lnet = legal_nets_list(by_index, &i);
945: if((srv_resp->yiaddr.s_addr & server_netmask) ==
946: (lnet & server_netmask))
947: {
948: printf("Can't use argessive mode because the network assigned "
949: "by DHCP server and the legal network are the same: %s/%d & ",
950: iptos(srv_resp->yiaddr.s_addr & server_netmask), to_cidr(server_netmask));
951: printf("%s/%d\n", iptos(lnet & server_netmask), to_cidr(server_netmask));
952: return -1;
953: }
954: }
955:
956:
957: /* Searching hosts in illegal network */
958:
959: uint32_t start_ip = ntohl(srv_resp->yiaddr.s_addr & server_netmask);
960:
961: if(!start_ip)
962: {
963: printf("Invalid IP address in DHCP server response: %s\n", inet_ntoa(srv_resp->yiaddr));
964: return -1;
965: }
966:
967: uint32_t end_ip = start_ip + (~ntohl(server_netmask));
968:
969: /* Check IP address range length */
970: if((end_ip - start_ip) > config->max_hosts_scan)
971: {
972: printf("Too long IP address scan range: %d. Maximum allowed scans: %d. "
973: "Use option -M for change this value.\n",
974: end_ip - start_ip, config->max_hosts_scan);
975: return -1;
976: }
977:
978: if(!config->quiet_mode)
979: {
980: printf("Starting ARP scanning network in range: %s - ", iptos(htonl(start_ip)));
981: printf("%s...\n", iptos(htonl(end_ip)));
982: }
983:
984: int ret = arp_scan(pcap_socket, start_ip, end_ip,
985: srv_resp->yiaddr.s_addr, srv_resp->chaddr);
986:
987: if(ret)
988: exit(ret);
989:
990: /* Now we have list of hosts with IP adresses assigned by illegal DHCP server */
991: int hosts_count = hosts_list(get_count, 0, NULL);
992: if(hosts_count < 2) /* Hosts with invalid IP addresses not found. 1 - itself DHCP server */
993: {
994: if(!config->quiet_mode)
995: printf("Hosts with invalid IP addresses not found.\n");
996: return 0;
997: }
998:
999: char ether_addr[MAX_STR_MAC_LEN + 1];
1000: bzero(ether_addr, sizeof(ether_addr));
1001: uint8_t bin_ethaddr[ETH_ALEN];
1002: uint32_t ip;
1003:
1004: printf("Illegal DHCP server perhaps assigned IP adresses to the following hosts:\n");
1005: for(i = 0; i < hosts_count; ++i)
1006: {
1007: ip = hosts_list(by_index, i, bin_ethaddr);
1008: etheraddr_bin_to_str(bin_ethaddr, ether_addr);
1009: printf("%d. Received ARP-reply from: %s (%s)%s", i + 1, ether_addr, iptos(ip),
1010: ((ip == srv_net_header->ip_header.saddr) &&
1011: !memcmp(srv_net_header->eth_head.ether_shost, bin_ethaddr, ETH_ALEN)
1012: )? " - itself DHCP server.\n" : "\n");
1013: }
1014:
1015: printf("Sending DHCPRELEASE for invalid clients:\n");
1016: for(i = 0; i < hosts_count; ++i)
1017: {
1018: ip = hosts_list(by_index, i, bin_ethaddr);
1019: if((ip == srv_net_header->ip_header.saddr) &&
1020: !memcmp(srv_net_header->eth_head.ether_shost, bin_ethaddr, ETH_ALEN))
1021: continue;
1022: etheraddr_bin_to_str(bin_ethaddr, ether_addr);
1023: printf("Send DHCPRELEASE for host %s (%s).\n", ether_addr, iptos(ip));
1024: if( (ret = send_dhcp_release(pcap_socket, config, bin_ethaddr,
1025: srv_net_header->ip_header.saddr, ip, rand())) )
1026: exit(ret);
1027: sleep(2);
1028: }
1029:
1030: return 0;
1031: }
1032:
1033: void scan_subnet(pcap_t * pcap_socket, uint32_t from_ip, const uint8_t * from_eth,
1034: const uint32_t network, const uint32_t netmask)
1035: {
1036: uint32_t start_ip = ntohl(network & netmask);
1037: uint32_t end_ip = start_ip + (~ntohl(netmask));
1038:
1039: printf("Starting ARP-scanning for subnet %s/%d.\n", iptos(htonl(start_ip & ntohl(netmask))),
1040: to_cidr(netmask));
1041:
1042: printf("IP address range %s - ", iptos(htonl(start_ip)));
1043: printf("%s.\n", iptos(htonl(end_ip)));
1044:
1045: if(!from_ip)
1046: {
1047: from_ip = htonl(start_ip + ((uint32_t) rand() % (end_ip - start_ip)));
1048: printf("WARNING: Source IP is not set (use option -F).\n"
1049: "Using random value for source IP address: %s\n", iptos(from_ip));
1050: }
1051:
1052: int ret = arp_scan(pcap_socket, start_ip, end_ip, from_ip, from_eth);
1053:
1054: /* Now we have list of hosts with IP adresses assigned by illegal DHCP server */
1055: int hosts_count = hosts_list(get_count, 0, NULL);
1056: char ether_addr[MAX_STR_MAC_LEN + 1];
1057: bzero(ether_addr, sizeof(ether_addr));
1058: uint8_t bin_ethaddr[ETH_ALEN];
1059: uint32_t ip;
1060: int i;
1061:
1062: for(i = 0; i < hosts_count; ++i)
1063: {
1064: ip = hosts_list(by_index, i, bin_ethaddr);
1065: etheraddr_bin_to_str(bin_ethaddr, ether_addr);
1066: printf("%d. Received ARP-reply from: %s (%s).\n", i + 1, ether_addr, iptos(ip));
1067: }
1068:
1069: if(ret)
1070: exit(ret);
1071: }
1072:
1073: int arp_scan(pcap_t * pcap_socket, const uint32_t start_range, const uint32_t end_range,
1074: uint32_t from_ip, const uint8_t * from_ether)
1075: {
1076: int ret;
1077:
1078: /* Set PCAP filter for receiving ARP packets for host 'from_ether'*/
1079: char str_from_ether[MAX_STR_MAC_LEN + 1];
1080: static char filter[PCAP_FILTER_LEN + 1];
1081:
1082: bzero(filter, sizeof(filter));
1083: bzero(str_from_ether, sizeof(str_from_ether));
1084:
1085: etheraddr_bin_to_str(from_ether, str_from_ether);
1086:
1087: if( (ret = make_arp_filter(filter, sizeof(filter) - 1, str_from_ether)) )
1088: {
1089: printf("Can't create ARP filter. Error code: %d.\n", ret);
1090: return ret;
1091: }
1092:
1093: if( (ret = set_pcap_filter(pcap_socket, filter)) )
1094: {
1095: printf("Can't set ARP filter.\n");
1096: return ret;
1097: }
1098:
1099: hosts_list(flush, 0, 0);
1100:
1101: /* Scanning network */
1102: int l;
1103: for(l = 0; l < 2; ++l)
1104: {
1105: uint32_t ip;
1106: for(ip = start_range; ip <= end_range; ++ip)
1107: {
1108: if( (ret = send_arpreq(pcap_socket, htonl(ip), from_ip, from_ether)) )
1109: {
1110: printf("Sending ARP packet error! Code: %d.\n", ret);
1111: return ret;
1112: }
1113:
1114: usleep(60);
1115:
1116: if( (ret = get_arpresps(pcap_socket, 0)) )
1117: {
1118: printf("Get ARP packet error! Code: %d.\n", ret);
1119: return ret;
1120: }
1121: }
1122: }
1123: /* Waiting for slow hosts */
1124: if( (ret = get_arpresps(pcap_socket, 2)) )
1125: {
1126: printf("Get ARP packet error! Code: %d.\n", ret);
1127: return ret;
1128: }
1129:
1130: return 0;
1131: }
1132:
1133: int get_arpresps(pcap_t * pcap_socket, int timeout)
1134: {
1135: uint8_t ether_packet[DHCP_MTU_MAX];
1136: struct arp_packet_net_header * arp_header;
1137:
1138: time_t timeout_time;
1139: int one_packet_timeout = timeout ? 1 : 0;
1140: if(timeout)
1141: timeout_time = time(0) + timeout;
1142:
1143: int ret;
1144: while(1)
1145: {
1146: if( (ret = get_packet(pcap_socket, ether_packet, one_packet_timeout)) < 0)
1147: return ERR_GETPACKET;
1148:
1149: if(ret)
1150: {
1151: arp_header = (struct arp_packet_net_header *) ether_packet;
1152: if(arp_header->arp_head.arp_oper == ARP_OP_RESP)
1153: {
1154: struct arp_data * arp_d = (struct arp_data *)
1155: (ether_packet + sizeof(struct arp_packet_net_header));
1156: hosts_list(add, arp_d->from_ip, arp_d->from_ether);
1157: }
1158: }
1159:
1160: if(!timeout)
1161: break;
1162:
1163: if(time(0) == timeout_time)
1164: break;
1165: }
1166:
1167: return 0;
1168: }
1169:
1170: int send_arpreq(pcap_t * pcap_socket, const uint32_t to_ip,
1171: const uint32_t from_ip, const uint8_t * from_ether)
1172: {
1173: static struct arp_data arp_d;
1174:
1175: memcpy(arp_d.from_ether, from_ether, ETH_ALEN);
1176: arp_d.from_ip = from_ip;
1177:
1178: memcpy(arp_d.to_ether, broadcast_ether, ETH_ALEN);
1179: arp_d.to_ip = to_ip;
1180:
1181: if(!send_packet(pcap_socket, arp_packet, (uint8_t *) &arp_d, sizeof(arp_d), 0, from_ether, 0))
1182: {
1183: pcap_close(pcap_socket);
1184: return ERR_SENDPACKET;
1185: }
1186: return 0;
1187: }
1188:
1189: #ifdef _WIN32
1190: BOOL WINAPI int_sign(DWORD signal)
1191: #else
1192: int int_sign(int32_t signal)
1193: #endif
1194: {
1195: if(signal == INTERRUPT_SIGNAL)
1196: {
1197: printf("Interrupted. Quit.\n");
1198: exit(EXIT_SUCCESS);
1199: }
1200: return 0;
1201: }
1202:
1203: #ifdef _WIN32
1204: unsigned __stdcall start_flood( void* arg )
1205: #else
1206: int start_flood( void* arg )
1207: #endif
1208: {
1209: flood_params_ptr par_ptr = (flood_params_ptr) arg;
1210: int j = 0, i;
1211: int ret;
1212:
1213: uint8_t src_ether[ETH_ALEN];
1214:
1215: int packets_count = par_ptr->config->max_address_count + ((par_ptr->config->max_address_count)? 0 : 1 );
1216:
1217: memcpy(src_ether, par_ptr->config->source_mac, sizeof(src_ether));
1218:
1219: pcap_t * pcap_socket = get_device(par_ptr->config);
1220:
1221: while( j < packets_count )
1222: { /* Sending DHCDISCOVER */
1223: if( (ret = send_dhcp_discover(pcap_socket, par_ptr->config, src_ether, 0)) )
1224: return ret;
1225:
1226: usleep(CAP_TIMEOUT);
1227:
1228: if(par_ptr->config->rand_mac_always) /* Randomize source ethernet address for next DHCPDISCOVER */
1229: {
1230: src_ether[0] = 0;
1231: for(i = 1; i < 6; ++i)
1232: src_ether[i] = rand();
1233: }
1234: if(par_ptr->config->max_address_count)
1235: ++j;
1236: }
1237: pcap_close(pcap_socket);
1238: return 0;
1239: }
1240:
1241:
1242: void new_child(const struct flood_params * p, const int child_num)
1243: {
1244: #ifdef _WIN32
1245: printf("Create thread #%d.\n", child_num + 1);
1246: p->flood_threads[child_num] = (HANDLE)_beginthreadex(NULL, 0, start_flood, (void*) p, 0,
1247: (uint32_t *) &p->threads_ids[child_num]);
1248:
1249: #else
1250: int pid;
1251: pid = fork();
1252: if(pid)
1253: printf("Create child #%d with pid %d.\n", child_num + 1, pid);
1254: else
1255: { /* Generate flood from child processes */
1256: exit(start_flood((void*) p));
1257: }
1258:
1259: #endif
1260: }
1261:
1262: void wait_children(const struct flood_params * p)
1263: {
1264: #ifdef _WIN32
1265: WaitForMultipleObjects(p->config->children_count, (HANDLE*) p->flood_threads, 1, INFINITE);
1266: #else
1267: int32_t pid;
1268: while( (pid = wait(0)) != -1)
1269: printf("Child with pid %d finished.\n", pid);
1270: #endif
1271: return;
1272: }
1273:
1274: int send_dhcp_discover(pcap_t * pcap_socket, const struct config_params * config,
1275: uint8_t * src_ether, const uint32_t xid)
1276: {
1277: /* Create DHCPDISCOVER */
1278: struct dhcp_packet dhcp_req;
1279:
1280: int dhcp_opt_len = make_dhcp_req(&dhcp_req, DHCPDISCOVER, src_ether ? src_ether : config->source_mac,
1281: 0, 0, xid, config);
1282: int snd_data_len = sizeof(struct dhcp_packet) - DHCP_OPTION_LEN + dhcp_opt_len;
1283: if(snd_data_len < BOOTP_MIN_LEN)
1284: snd_data_len = BOOTP_MIN_LEN;
1285:
1286: /* Send DHCPDISCOVER to DHCP server */
1287: if(!send_packet(pcap_socket, dhcp_packet, (uint8_t*) &dhcp_req,
1288: snd_data_len, config, src_ether ? src_ether : config->source_mac, 0))
1289: {
1290: printf("Can't send packet: %s\n", pcap_geterr(pcap_socket));
1291: pcap_close(pcap_socket);
1292: return ERR_SENDPACKET;
1293: }
1294:
1295: return 0;
1296: }
1297:
1298: int make_serverdiscover_filter(char * out_filter, const int max_filter_len,
1299: const struct config_params * config, const char * src_etheraddr)
1300: {
1301: if(!out_filter || !config)
1302: return ERR_ABNORMAL;
1303:
1304: /* Adding in pcap-filter all ignored servers */
1305: struct ignored_mac_node * ign_ptr = ignor_servers_list(get_top, 0);
1306:
1307: snprintf(out_filter, max_filter_len + 1,
1308: STR_SERVERDISCOVER_FILTER, src_etheraddr,
1309: (config->always_wait_from_67)? DEF_SERVER_PORT : config->server_port,
1310: (config->always_wait_to_68)? DEF_CLIENT_PORT : config->client_port
1311: );
1312:
1313: while(ign_ptr)
1314: {
1315: if(strlen(" and not ether src host ") +
1316: strlen(ign_ptr->mac_addr) +
1317: strlen(out_filter) > max_filter_len)
1318: {
1319: printf("Error! Filter owerflow.\n");
1320: return ERR_FILTER_OWERFLOW;
1321: }
1322:
1323: strncat(out_filter, " and not ether src host ", max_filter_len - strlen(out_filter));
1324: strncat(out_filter, ign_ptr->mac_addr, max_filter_len - strlen(out_filter));
1325: ign_ptr = ign_ptr->next;
1326: }
1327:
1328: return 0;
1329: }
1330:
1331: int make_arp_filter(char * out_filter, const int max_filter_len, const char * src_etheraddr)
1332: {
1333: if(!out_filter)
1334: return ERR_ABNORMAL;
1335:
1336: static const char arp_filter[] = "arp and ether dst ";
1337:
1338: if((strlen(arp_filter) + strlen(src_etheraddr)) > max_filter_len)
1339: return -1;
1340:
1341: strncpy(out_filter, arp_filter, max_filter_len);
1342: strncat(out_filter, src_etheraddr, max_filter_len - strlen(out_filter));
1343:
1344: return 0;
1345: }
1346:
1347: int make_serverdrop_filter(char * out_filter, const int max_filter_len,
1348: const struct config_params * config,
1349: const char * src_etheraddr, const char * server_ethaddr)
1350: {
1351: if(!out_filter || !config || !src_etheraddr || !server_ethaddr)
1352: return ERR_ABNORMAL;
1353:
1354: snprintf(out_filter, max_filter_len + 1, STR_SERVERDROP_FILTER, src_etheraddr,
1355: (config->always_wait_from_67)? DEF_SERVER_PORT : config->server_port,
1356: (config->always_wait_to_68)? DEF_CLIENT_PORT : config->client_port,
1357: server_ethaddr);
1358:
1359: return 0;
1360: }
1361:
1362:
1363: int set_pcap_filter(pcap_t * pcap_socket, char * filter_expression)
1364: {
1365: struct bpf_program fp;
1366: if(pcap_compile(pcap_socket, &fp, filter_expression, 1, 0) == -1)
1367: {
1368: printf("pcap_compile error: %s\nFilter expression is: '%s'\n",
1369: pcap_geterr(pcap_socket), filter_expression);
1370: pcap_close(pcap_socket);
1371: return ERR_PCAP_COMPILE;
1372: }
1373:
1374: if(pcap_setfilter(pcap_socket, &fp) == -1)
1375: {
1376: perror("pcap_setfilter");
1377: pcap_close(pcap_socket);
1378: return ERR_PCAP_SETFILTER;
1379: }
1380:
1381: pcap_freecode(&fp);
1382:
1383: return 0;
1384: }
1385:
1386: int send_dhcp_request(pcap_t * pcap_socket, const struct config_params * config,
1387: uint8_t * src_ether, /* Pseudo-client source ethernet address. Can't be NULL */
1388: const uint32_t server_ip_address, /* DHCP server IP address. Can't be NULL */
1389: const uint32_t req_ip_addr, /* Required client IP address. Can't be NULL */
1390: const int32_t xid
1391: )
1392: {
1393: if(!pcap_socket || !config || !src_ether || !server_ip_address || !req_ip_addr)
1394: return ERR_ABNORMAL;
1395:
1396: /* Create DHCPREQUEST */
1397: struct dhcp_packet dhcp_req;
1398:
1399: int dhcp_opt_len = make_dhcp_req(&dhcp_req, DHCPREQUEST, src_ether,
1400: server_ip_address, req_ip_addr, xid, config);
1401:
1402: int snd_data_len = sizeof(struct dhcp_packet) - DHCP_OPTION_LEN + dhcp_opt_len;
1403: if(snd_data_len < BOOTP_MIN_LEN)
1404: snd_data_len = BOOTP_MIN_LEN;
1405:
1406: /* Send DHCPREQUEST to DHCP server */
1407: if(!send_packet(pcap_socket, dhcp_packet, (uint8_t*) &dhcp_req,
1408: snd_data_len, config, src_ether ? src_ether : config->source_mac, 0))
1409: {
1410: printf("Can't send packet: %s\n", pcap_geterr(pcap_socket));
1411: pcap_close(pcap_socket);
1412: return ERR_SENDPACKET;
1413: }
1414:
1415: return 0;
1416: }
1417:
1418: int send_dhcp_release(pcap_t * pcap_socket, const struct config_params * config,
1419: const uint8_t * src_ether, /* Pseudo-client source ethernet address. Can't be NULL */
1420: const uint32_t server_ip_address, /* DHCP server IP address. Can't be NULL */
1421: const uint32_t cl_ip_addr, /* Released client IP address. Can't be NULL */
1422: const int32_t xid
1423: )
1424: {
1425: if(!pcap_socket || !config || !src_ether || !server_ip_address || !cl_ip_addr)
1426: return ERR_ABNORMAL;
1427:
1428: /* Create DHCPREQUEST */
1429: struct dhcp_packet dhcp_req;
1430:
1431: int dhcp_opt_len = make_dhcp_req(&dhcp_req, DHCPRELEASE, src_ether,
1432: server_ip_address, cl_ip_addr, xid, config);
1433:
1434: int snd_data_len = sizeof(struct dhcp_packet) - DHCP_OPTION_LEN + dhcp_opt_len;
1435: if(snd_data_len < BOOTP_MIN_LEN)
1436: snd_data_len = BOOTP_MIN_LEN;
1437:
1438: /* Send DHCPREQUEST to DHCP server */
1439: if(!send_packet(pcap_socket, dhcp_packet, (uint8_t*) &dhcp_req,
1440: snd_data_len, config, src_ether ? src_ether : config->source_mac, server_ip_address))
1441: {
1442: printf("Can't send packet: %s\n", pcap_geterr(pcap_socket));
1443: pcap_close(pcap_socket);
1444: return ERR_SENDPACKET;
1445: }
1446:
1447: return 0;
1448: }
1449:
1450: int get_dhcp_response(pcap_t * pcap_socket, const int timeout, const uint8_t resp_type,
1451: const uint32_t xid, struct dhcp_packet_net_header * net_header,
1452: struct dhcp_packet * response, int * dhcp_data_len)
1453: {
1454: uint8_t ether_packet[DHCP_MTU_MAX];
1455: struct dhcp_packet_net_header * dhcp_net_header;
1456: struct dhcp_packet *dhcp_resp;
1457: uint8_t dhcp_msg_type;
1458:
1459: const int max_errors = 10;
1460: int errors = 0;
1461:
1462: while(1)
1463: {
1464: if(errors == max_errors)
1465: break;
1466:
1467: int ret = get_packet(pcap_socket, ether_packet, timeout);
1468:
1469: if(ret < 0)
1470: return ERR_GETPACKET;
1471:
1472: if(!ret)
1473: return -1; /* Timeout - server not respond */
1474:
1475: /* Analysing packet */
1476: dhcp_net_header = (struct dhcp_packet_net_header *) ether_packet;
1477: dhcp_resp = (struct dhcp_packet *) (ether_packet + sizeof(struct dhcp_packet_net_header));
1478:
1479: *dhcp_data_len = ntohs(dhcp_net_header->udp_header.len)
1480: - sizeof(struct udphdr); /* UDP data length equal DHCP-packet length */
1481:
1482: if(*dhcp_data_len > DHCP_MAX_LEN)
1483: {
1484: printf("UDP data len too long (%u bytes)! Attempting DoS?\n", *dhcp_data_len);
1485: ++errors;
1486: continue;
1487: }
1488:
1489: if(
1490: (dhcp_resp->op != BOOTREPLY) ||
1491: (get_dhcp_option(dhcp_resp, *dhcp_data_len, DHO_DHCP_MESSAGE_TYPE,
1492: (void*)&dhcp_msg_type, sizeof(dhcp_msg_type)) < 1) ||
1493: (dhcp_msg_type != resp_type) ||
1494: (dhcp_resp->xid != xid)
1495: )
1496: {
1497: ++errors;
1498: continue;
1499: }
1500:
1501: memcpy(net_header, ether_packet, sizeof(struct dhcp_packet_net_header));
1502: memcpy(response, dhcp_resp, *dhcp_data_len);
1503: return 0;
1504: }
1505:
1506: return -1;
1507: }
1508:
1509:
1510: struct ignored_mac_node * ignor_servers_list(enum list_operations operation, char * ether_addr)
1511: {
1512: if(ether_addr)
1513: {
1514: replace_semicolons(ether_addr);
1515: int hex;
1516: if(sscanf(ether_addr, "%x:%x:%x:%x:%x:%x",
1517: &hex, &hex, &hex, &hex, &hex, &hex) < 6) /* Invalid format! */
1518: return 0;
1519: }
1520:
1521: static struct ignored_mac_node * ignored_list_top = 0;
1522:
1523: switch(operation)
1524: {
1525: case add:
1526: {
1527: if(!ether_addr || (strlen(ether_addr) < MIN_STR_MAC_LEN))
1528: return 0;
1529:
1530: struct ignored_mac_node * new_node =
1531: (struct ignored_mac_node *) malloc(sizeof(struct ignored_mac_node));
1532:
1533: if(! new_node)
1534: {
1535: printf("Can't allocate memory for legal DHCP server ethernet address! Exit.");
1536: exit(ERR_MEMORY);
1537: }
1538:
1539: bzero(new_node, sizeof(struct ignored_mac_node));
1540: strncpy(new_node->mac_addr, ether_addr, sizeof(new_node->mac_addr) - 1);
1541: new_node->next = ignored_list_top;
1542: ignored_list_top = new_node;
1543: return ignored_list_top;
1544: }
1545: break;
1546: case rem:
1547: {
1548: struct ignored_mac_node * node_ptr = ignored_list_top;
1549: while(node_ptr)
1550: {
1551: if(!strncmp(node_ptr->mac_addr, ether_addr, sizeof(node_ptr->mac_addr) - 1))
1552: {
1553: struct ignored_mac_node * removed = node_ptr;
1554: node_ptr = node_ptr->next;
1555: free(removed);
1556: return ignored_list_top;
1557: }
1558: else
1559: node_ptr = node_ptr->next;
1560: }
1561: }
1562: break;
1563: case get_top:
1564: return ignored_list_top;
1565: case search:
1566: {
1567: struct ignored_mac_node * node_ptr = ignored_list_top;
1568: while(node_ptr)
1569: if(!strncmp(node_ptr->mac_addr, ether_addr, sizeof(node_ptr->mac_addr) - 1))
1570: return ignored_list_top;
1571: else
1572: node_ptr = node_ptr->next;
1573: }
1574: break;
1575: case flush:
1576: {
1577: struct ignored_mac_node * next_node;
1578: while(ignored_list_top)
1579: {
1580: next_node = ignored_list_top->next;
1581: free(ignored_list_top);
1582: ignored_list_top = next_node;
1583: }
1584: return ignored_list_top;
1585: }
1586: break;
1587: default:
1588: break;
1589: }
1590: return 0;
1591: }
1592:
1593: uint32_t legal_nets_list(enum list_operations operation, const uint32_t * value)
1594: {
1595: static uint32_t * legal_nets = 0;
1596: static int count = 0;
1597: static int capacity = 0;
1598:
1599: switch(operation)
1600: {
1601: case get_count:
1602: return count;
1603: case add:
1604: if(!capacity)
1605: {
1606: capacity = 4;
1607: if( !(legal_nets = (uint32_t *) malloc(sizeof(uint32_t) * capacity)) )
1608: {
1609: printf("Can't allocate memory for legal networks! Exit.\n");
1610: exit(ERR_MEMORY);
1611: }
1612: }
1613:
1614: if(count == capacity)
1615: {
1616: capacity *= 2;
1617: if( !(legal_nets = (uint32_t*) realloc(legal_nets, capacity)))
1618: {
1619: printf("Can't reallocate memory for legal networks! Exit.\n");
1620: exit(ERR_MEMORY);
1621: }
1622: }
1623:
1624: legal_nets[count] = *value;
1625: ++count;
1626: break;
1627: case by_index:
1628: return legal_nets[*value];
1629: case flush:
1630: count = 0;
1631: capacity = 0;
1632: if(legal_nets)
1633: free(legal_nets);
1634: break;
1635: default:
1636: printf("Unknown operation on legal nets.\n");
1637: break;
1638: }
1639: return count;
1640: }
1641:
1642: int hosts_list(enum list_operations operation, uint32_t ip_addr, uint8_t * ether_addr)
1643: {
1644: struct invalid_host
1645: {
1646: uint8_t ether_addr[ETH_ALEN];
1647: uint32_t ip_addr;
1648: };
1649:
1650: static struct invalid_host * hosts_list = 0;
1651: static int count = 0;
1652: static int capacity = 0;
1653:
1654: switch(operation)
1655: {
1656: case get_count:
1657: return count;
1658: case add:
1659: {
1660: int i;
1661: for(i = 0; i < count; ++i)
1662: if(!memcmp(hosts_list[i].ether_addr, ether_addr, sizeof(hosts_list[i].ether_addr)) &&
1663: (hosts_list[i].ip_addr == ip_addr)) /* Dupe */
1664: return 0;
1665:
1666: if(!capacity)
1667: {
1668: capacity = 4;
1669: if(! (hosts_list = (struct invalid_host* ) malloc(sizeof(struct invalid_host) * capacity)) )
1670: {
1671: printf("Can't allocate memory for invalid hosts list! Exit.\n");
1672: exit(ERR_MEMORY);
1673: }
1674: }
1675:
1676: if(count == capacity)
1677: {
1678: capacity *= 2;
1679: if( !(hosts_list = (struct invalid_host *) realloc(hosts_list, sizeof(struct invalid_host) * capacity)))
1680: {
1681: printf("Can't reallocate memory for invalid hosts list! Exit.\n");
1682: exit(ERR_MEMORY);
1683: }
1684: }
1685:
1686: memcpy(hosts_list[count].ether_addr, ether_addr, sizeof(hosts_list[count].ether_addr));
1687: hosts_list[count].ip_addr = ip_addr;
1688: ++count;
1689: }
1690: break;
1691: case by_index:
1692: if( (ip_addr < 0) || (ip_addr > (count - 1)) )
1693: return -1;
1694:
1695: memcpy(ether_addr, hosts_list[ip_addr].ether_addr, sizeof(hosts_list[ip_addr].ether_addr));
1696: return hosts_list[ip_addr].ip_addr;
1697: case flush:
1698: capacity = 0;
1699: count = 0;
1700: if(hosts_list)
1701: free(hosts_list);
1702: break;
1703: default:
1704: printf("Unknown operations on invalid hostst list.\n");
1705: break;
1706: }
1707:
1708: return 0;
1709: }
1710:
1711: void cleanup(void)
1712: {
1713: ignor_servers_list(flush, 0);
1714: legal_nets_list(flush, 0);
1715: hosts_list(flush, 0, 0);
1716: }
1717:
1718:
1719: int decode_dhcp(const struct dhcp_packet * packet, const uint16_t packet_len)
1720: {
1721: uint8_t dhcp_msg_type;
1722: switch(packet->op)
1723: {
1724: case BOOTREQUEST: printf("Got BOOTREQUEST("); break;
1725: case BOOTREPLY: printf("Got BOOTREPLY ("); break;
1726: default: printf("Unknown message type: %u\n", packet->op); return 0;
1727: }
1728: if(get_dhcp_option(packet, packet_len, DHO_DHCP_MESSAGE_TYPE,
1729: (void*)&dhcp_msg_type, sizeof(dhcp_msg_type)) < 1)
1730: {
1731: printf("Error: Can't get DHCP message type.\n");
1732: return 0;
1733: }
1734:
1735: switch(dhcp_msg_type)
1736: {
1737: case DHCPDISCOVER: printf("DHCPDISCOVER) "); break;
1738: case DHCPOFFER: printf("DHCPOFFER) "); break;
1739: case DHCPREQUEST: printf("DHCPREQUEST) "); break;
1740: case DHCPDECLINE: printf("DHCPDECLINE) "); break;
1741: case DHCPACK: printf("DHCPACK) "); break;
1742: case DHCPNAK: printf("DHCPNAK) "); break;
1743: case DHCPRELEASE: printf("DHCPRELEASE) "); break;
1744: case DHCPINFORM: printf("DHCPINFORM) "); break;
1745: default: printf("Unknown DHCP message type: %u)\n", dhcp_msg_type);
1746: }
1747:
1748: if(packet->flags && htons(BOOTP_BROADCAST))
1749: printf("flags: BROADCAST ");
1750: printf("for client ether: ");
1751: print_ether(packet->chaddr);
1752:
1753: uint32_t netmask = 0;
1754: printf(" You IP: %s", inet_ntoa(packet->yiaddr));
1755: if(get_dhcp_option(packet, packet_len, DHO_SUBNET_MASK, (void*)&netmask, sizeof(netmask)) < 1)
1756: printf("\n");
1757: else
1758: printf("/%d\n", to_cidr(netmask));
1759:
1760: return dhcp_msg_type;
1761: }
1762:
1763: void usage(const char help)
1764: {
1765: (help)? printf("%s\n%s\n%s", usage_message, keys, ret_codes) : printf("%s", usage_message);
1766: printf("\n%s\n", COPYRIGHT HOMEPAGE);
1767: if(!help)
1768: printf("Use option -h for help. Exit.\n");
1769: exit(ERR_CONFIG);
1770: }
1771:
1772: /* Convert network mask to CIDR notation */
1773: uint32_t to_cidr(uint32_t mask)
1774: {
1775: mask = ntohl(mask);
1776: int i;
1777: for(i = 0; i < 33; ++i)
1778: if(mask & (1 << i))
1779: break;
1780: return (i == 33)? 0 : 32 - i;
1781: }
1782:
1783: /* Convert a numeric IP address to a string */
1784: char *iptos(const uint32_t in)
1785: {
1786: static char output[IPTOSBUFFERS][3*4 + 3 + 1];
1787: static short which;
1788: uint8_t *p;
1789:
1790: p = (uint8_t *)∈
1791: which = (which + 1 == IPTOSBUFFERS ? 0 : which + 1);
1792: snprintf(output[which], sizeof(output), "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
1793: return output[which];
1794: }
1795:
1796: void ifprint(const pcap_if_t *dev)
1797: {
1798: pcap_addr_t *pcap_addr;
1799: /* Name */
1800: printf("%s", dev->name);
1801: /* Description */
1802: if (dev->description)
1803: printf("\n descr: %s", dev->description);
1804: /* IP addresses */
1805: for(pcap_addr = dev->addresses; pcap_addr; pcap_addr = pcap_addr->next)
1806: {
1807: if(!pcap_addr->addr)
1808: continue;
1809: switch(pcap_addr->addr->sa_family)
1810: {
1811: case AF_INET:
1812: if (pcap_addr->addr)
1813: printf("\n iaddr: %s", iptos(((struct sockaddr_in *)pcap_addr->addr)->sin_addr.s_addr));
1814: if (pcap_addr->netmask)
1815: printf("/%d ", to_cidr(((struct sockaddr_in *)pcap_addr->netmask)->sin_addr.s_addr));
1816: if (pcap_addr->broadaddr)
1817: printf(" bcast: %s",iptos(((struct sockaddr_in *)pcap_addr->broadaddr)->sin_addr.s_addr));
1818: if (pcap_addr->dstaddr)
1819: printf(" dst addr: %s",iptos(((struct sockaddr_in *)pcap_addr->dstaddr)->sin_addr.s_addr));
1820: break;
1821: case AF_INET6:
1822: break;
1823:
1824: default:
1825: break;
1826: }
1827: }
1828: printf("\n");
1829: }
1830:
1831: inline int etheraddr_bin_to_str(const uint8_t * bin_addr, char * str_addr)
1832: {
1833: if(!bin_addr || !str_addr)
1834: return 0;
1835: snprintf(str_addr, MAX_STR_MAC_LEN + 1, "%02x:%02x:%02x:%02x:%02x:%02x",
1836: bin_addr[0], bin_addr[1], bin_addr[2], bin_addr[3], bin_addr[4], bin_addr[5]);
1837: return 1;
1838: }
1839:
1840: int etheraddr_str_to_bin(const char * str_addr, uint8_t * bin_addr)
1841: {
1842: if(!str_addr || !bin_addr)
1843: return 0;
1844:
1845: static char ether_addr[MAX_STR_MAC_LEN + 1]; /* Non-const buffer for strtok */
1846: bzero(ether_addr, sizeof(ether_addr));
1847: strncpy(ether_addr, str_addr, sizeof(ether_addr) - 1);
1848:
1849: int i = 0;
1850: int byte;
1851: char * bytePtr = strtok(ether_addr, ":-");
1852: while(bytePtr)
1853: {
1854: if(i > 5)
1855: return -1; /* Ethernet address consist from 6 bytes! */
1856:
1857: if(strlen(bytePtr) > 2)
1858: return -1; /* Too long digit */
1859:
1860: if(sscanf(bytePtr, "%02x", &byte) < 1)
1861: return -1; /* Invalid HEX digit */
1862:
1863: bin_addr[i++] = (uint8_t) byte;
1864: bytePtr = strtok(NULL, ":-");
1865: }
1866: if(i < 6)
1867: return -1; ; /* Ethernet address consist from 6 bytes! */
1868: return 1;
1869: }
1870:
1871: inline void replace_semicolons(char * str_ether)
1872: {
1873: char * p = str_ether;
1874: while(*p)
1875: {
1876: if(*p == '-')
1877: *p = ':';
1878: ++p;
1879: }
1880: }
1881:
1882: inline void print_ether(const uint8_t * ether_addr)
1883: {
1884: int i;
1885: for(i = 0; i < ETH_ALEN; ++i)
1886: printf((i == (ETH_ALEN - 1) ) ? "%02X" :"%02X:", ether_addr[i]);
1887: }
1888:
1889: inline void rand_ether_addr(char * str_mac_addr) /* Minimal size of str_mac_addr must be STR_MAC_LEN (18) */
1890: {
1891: /* Fill first byte */
1892: strncat(str_mac_addr, "00:", 3);
1893: char * p = str_mac_addr + strlen(str_mac_addr);
1894: int i;
1895: for(i = 0; i < 5; ++i, p +=3) /* Randomize next 5 bytes */
1896: snprintf(p, 4, (i < 4)? ("%02X:") : "%02X", (int)(rand() & 0xFF));
1897: return;
1898: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>