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