1 /*
2  * $Id:$
3  *
4  * Pretty interesting which OS answers for arp request for
5  * 127.0.0.1, 0.0.0.0 or gives replies about MAC from other
6  * interfaces (linux for example).
7  */
8 
9 #include "default.h"
10 #include <sys/types.h>
11 #include <stdio.h>
12 #ifdef HAVE_UNISTD_H
13 # include <unistd.h>
14 #endif
15 #include <stdlib.h>
16 #include <stdarg.h>
17 #include <time.h>
18 #include <libnet.h>
19 #include "macvendor.h"
20 #include "thcrut.h"
21 #include "range.h"
22 #include "packets.h"
23 #include "network.h"
24 #include "network_raw.h"
25 #include "thcrut_libnet.h"
26 #include "thcrut_pcap.h"
27 
28 #define STATE_RESET	(0)
29 #define STATE_ARPI	(1)
30 #define STATE_ARPII	(2)
31 #define STATE_ARPIII	(3)
32 
33 #define DFL_HOSTS_PARALLEL	(100)
34 
35 extern struct _opt opt;
36 static void arp_filter(unsigned char *u, struct pcap_pkthdr *p, unsigned char *packet);
37 static void do_arp();
38 
39 static char packet[LIBNET_ETH_H + LIBNET_ARP_H];
40 static char srcmac[ETH_ALEN];
41 
42 static void
init_vars(void)43 init_vars(void)
44 {
45 	char buf[1024];
46 	char *ptr;
47 	struct stat sbuf;
48 	char err_buf[LIBNET_ERRBUF_SIZE];
49 	struct ether_addr *hw;
50 
51 	opt.ip_socket = init_pcap(opt.device, 1, "arp[6:2] = 2", NULL, NULL, &opt.dlt_len);
52 	/*
53 	 * Only listen to replies.
54 	 */
55 	if (!(opt.flags & FL_OPT_SPOOFMAC))
56 	{
57 		hw = libnet_get_hwaddr(opt.network, opt.device, err_buf);
58 		if (!hw)
59 		{
60 			fprintf(stderr, "libnet_get_hwaddr: %s\n", err_buf);
61 			exit(-1);
62 		}
63 		memcpy(srcmac, (char *)hw, ETH_ALEN);
64 	}
65 
66 	arp_gen_packets(packet, opt.src_ip);
67 
68 	/*
69 	 * Try to load mac vendor DB. Ignore if we fail.
70 	 */
71 	if ( (ptr = getenv("THCRUTDIR")))
72 	{
73 		snprintf(buf, sizeof buf, "%s/manuf", ptr);
74 		readvendornames(buf);
75 	} else {
76 		snprintf(buf, sizeof buf, "%s/manuf", THCRUT_DATADIR);
77 		if (readvendornames(buf) != 0)
78 		{
79 			if (readvendornames("./manuf") != 0)
80 				fprintf(stderr, "Load ./manuf: %s\n", strerror(errno));
81 		} else if (stat("./manuf", &sbuf) == 0) {
82 			fprintf(stderr, "WARNING: ./manuf exist. Using config file from "THCRUT_DATADIR" for security reasons.\nset THCRUTDIR=. to overwrite.\n");
83 		}
84 	}
85 }
86 
87 static void
usage(void)88 usage(void)
89 {
90 	fprintf(stderr, ""
91 "usage: arp [options] [IP] ...\n"
92 " -l <n>              Hosts in parallel (%d)\n"
93 " -m <mac>            source MAC (source interface)\n"
94 "", DFL_HOSTS_PARALLEL);
95 
96 	exit(0);
97 }
98 
99 /*
100  * Init libnet here because we want to display the correct IP
101  */
102 static void
init_defaults(void)103 init_defaults(void)
104 {
105 	opt.network = init_libnet(&opt.device, &opt.src_ip);
106 	if (opt.hosts_parallel == 0)
107 		opt.hosts_parallel = DFL_HOSTS_PARALLEL;
108 }
109 
110 static void
do_getopt(int argc,char * argv[])111 do_getopt(int argc, char *argv[])
112 {
113 	int c;
114 
115 	optind = 1;
116 	while ( (c = getopt(argc, argv, "+hl:m:")) != -1)
117 	{
118 		switch (c)
119 		{
120 		case 'l':
121 			opt.hosts_parallel = atoi(optarg);
122 			break;
123 		case 'm':
124 			macstr2mac(srcmac, optarg);
125 			opt.flags |= FL_OPT_SPOOFMAC;
126 			break;
127 		default:
128 			usage();
129 		}
130 	}
131 
132 	opt.argvlist = &argv[optind];
133 	opt.argc = argc - optind;
134 
135 	if (opt.argc <= 0)
136 		usage();
137 }
138 
139 /*
140  * Send arp request
141  */
142 static void
do_arp(char * packet,char * srcmac,long ip)143 do_arp(char *packet, char *srcmac, long ip)
144 {
145 	struct ETH_arp *eth_arp = (struct ETH_arp *)(packet + LIBNET_ETH_H);
146 	int c;
147 
148 	ip = htonl(ip);
149 	memcpy(packet + ETH_ALEN, srcmac, ETH_ALEN);
150 	memcpy(eth_arp->ar_sha, srcmac, ETH_ALEN);
151 	memcpy(eth_arp->ar_tip, &ip, 4);  /* Put the dst ip into the packet */
152 
153 	c = libnet_write_link_layer(opt.network, opt.device, packet, LIBNET_ETH_H + LIBNET_ARP_H);
154 	if (c != LIBNET_ETH_H + LIBNET_ARP_H)
155 	{
156 		libnet_error(LIBNET_ERR_FATAL, "libnet_write_link_layer (%d)", c);
157 		exit(-1);
158 	}
159 }
160 
161 static void
dis_timeout(struct _state * state)162 dis_timeout(struct _state *state)
163 {
164 	switch (STATE_current(state))
165 	{
166 	case STATE_RESET:
167 		STATE_current(state) = STATE_ARPI;
168 		do_arp(packet, srcmac, STATE_ip(state));
169 		break;
170 	case STATE_ARPI:
171 		STATE_current(state) = STATE_ARPII;
172 		do_arp(packet, srcmac, STATE_ip(state));
173 		break;
174 	case STATE_ARPII:
175 		STATE_current(state) = STATE_ARPIII;
176 		do_arp(packet, srcmac, STATE_ip(state));
177 		break;
178 	case STATE_ARPIII:
179 		STATE_reset(state);
180 		break;
181 	default:
182 		fprintf(stderr, "%s:%d Unknown state %d\n", __func__, __LINE__, STATE_current(state));
183 		STATE_reset(state);
184 		break;
185 	}
186 }
187 
188 static void
cb_filter(void)189 cb_filter(void)
190 {
191 	if (pcap_dispatch(opt.ip_socket, -1, (pcap_handler)arp_filter, NULL) < 0)
192 	{
193 		pcap_perror(opt.ip_socket, "pcap_dispatch");
194 		exit(-1);
195 	}
196 }
197 
198 static void
arp_filter(unsigned char * u,struct pcap_pkthdr * p,unsigned char * packet)199 arp_filter(unsigned char *u, struct pcap_pkthdr *p, unsigned char *packet)
200 {
201 	struct ETH_arp *arp = (struct ETH_arp *)(packet + LIBNET_ETH_H);
202 	struct _state *state;
203 	long l;
204 	char *ptr;
205 
206 	if (p->caplen < LIBNET_ETH_H + sizeof *arp)
207 		return;
208 	memcpy(&l, arp->ar_sip, 4);
209 
210 	if (!(state = STATE_by_ip(&opt.sq, ntohl(l))))
211 		return;
212 
213 	ptr = mac2vendor(arp->ar_sha);
214 	/*
215 	 * 16 bytes for IP, 1 byte for space, 17 for mac + 1 space = 35
216 	 * 80 - 35 = 45.
217 	 */
218 	if (!ptr)
219 		printf("%-16s %.45s\n", int_ntoa(l), val2mac(arp->ar_sha));
220 	else
221 		printf("%-16s %s %.45s\n", int_ntoa(l), val2mac(arp->ar_sha), ptr);
222 
223 	STATE_reset(state);
224 }
225 
226 
227 int
arp_main(int argc,char * argv[])228 arp_main(int argc, char *argv[])
229 {
230 	struct _state state;
231 	struct pcap_stat ps;
232 	int ret;
233 
234 	memset(packet, 0, sizeof packet);
235 
236 	init_defaults();
237 	do_getopt(argc, argv);
238 	init_vars();
239 
240 	IP_init(&opt.ipr, opt.argvlist, (opt.flags & FL_OPT_SPREADMODE)?IPR_MODE_SPREAD:0);
241 
242 	if (!SQ_init(&opt.sq, opt.hosts_parallel, sizeof(struct _state), pcap_fileno(opt.ip_socket), dis_timeout, cb_filter))
243 	{
244 		fprintf(stderr, "Failed to init states: %s\n", strerror(errno));
245 		exit(-1);
246 	}
247 
248 	memset(&state, 0, sizeof state);
249 	while (1)
250 	{
251 		IP_next(&opt.ipr);
252 		if (IP_current(&opt.ipr))
253 		{
254 			STATE_ip(&state) = IP_current(&opt.ipr);
255 			ret = STATE_wait(&opt.sq, &state);
256 		} else
257 			ret = STATE_wait(&opt.sq, NULL);
258 
259 		if (ret != 0)
260 			break;
261 	}
262 
263 	if (thcrut_pcap_stats(opt.ip_socket, &ps) == 0)
264 		fprintf(stderr, "%u packets received by filter, %u packets dropped by kernel\n", ps.ps_recv, ps.ps_drop);
265 
266 	return 0;
267 }
268 
269