blob: a0bfdaaf647646c6ec30721f11ec099345a925b5 [file] [log] [blame]
Glenn L McGrath9e598412003-01-09 10:06:01 +00001/*
2 * arping.c - Ping hosts by ARP requests/replies
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 *
9 * Author: Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
10 * Busybox port: Nick Fedchik <nick@fedchik.org.ua>
11 */
12
13#include <sys/ioctl.h>
14#include <sys/signal.h>
15#include <sys/time.h>
16
17#include <errno.h>
18#include <stdlib.h>
19#include <string.h>
20#include <unistd.h>
21
22#include <arpa/inet.h>
23#include <net/if.h>
24#include <netinet/ether.h>
25#include <netpacket/packet.h>
26
27#include "busybox.h"
28
29#define APPLET_NAME "arping"
30
31struct in_addr src;
32struct in_addr dst;
33struct sockaddr_ll me;
34struct sockaddr_ll he;
35struct timeval last;
36int dad;
37int unsolicited;
38int advert;
39int quiet;
40int quit_on_reply = 0;
41int count = -1;
42int timeout;
43int unicasting;
44int s;
45int broadcast_only;
46int sent;
47int brd_sent;
48int received;
49int brd_recv;
50int req_recv;
51
52#define MS_TDIFF(tv1,tv2) ( ((tv1).tv_sec-(tv2).tv_sec)*1000 + \
53 ((tv1).tv_usec-(tv2).tv_usec)/1000 )
54#if 0
55static void set_signal(int signo, void (*handler) (void))
56{
57 struct sigaction sa;
58
59 memset(&sa, 0, sizeof(sa));
60 sa.sa_handler = (void (*)(int)) handler;
61 sa.sa_flags = SA_RESTART;
62 sigaction(signo, &sa, NULL);
63}
64#endif
65
66static int send_pack(int sock, struct in_addr *src_addr, struct in_addr *dst_addr,
67 struct sockaddr_ll *ME, struct sockaddr_ll *HE)
68{
69 int err;
70 struct timeval now;
71 unsigned char buf[256];
72 struct arphdr *ah = (struct arphdr *) buf;
73 unsigned char *p = (unsigned char *) (ah + 1);
74
75 ah->ar_hrd = htons(ME->sll_hatype);
76 ah->ar_hrd = htons(ARPHRD_ETHER);
77 ah->ar_pro = htons(ETH_P_IP);
78 ah->ar_hln = ME->sll_halen;
79 ah->ar_pln = 4;
80 ah->ar_op = advert ? htons(ARPOP_REPLY) : htons(ARPOP_REQUEST);
81
82 memcpy(p, &ME->sll_addr, ah->ar_hln);
83 p += ME->sll_halen;
84
85 memcpy(p, src_addr, 4);
86 p += 4;
87
88 if (advert)
89 memcpy(p, &ME->sll_addr, ah->ar_hln);
90 else
91 memcpy(p, &HE->sll_addr, ah->ar_hln);
92 p += ah->ar_hln;
93
94 memcpy(p, dst_addr, 4);
95 p += 4;
96
97 gettimeofday(&now, NULL);
98 err = sendto(sock, buf, p - buf, 0, (struct sockaddr *) HE, sizeof(*HE));
99 if (err == p - buf) {
100 last = now;
101 sent++;
102 if (!unicasting)
103 brd_sent++;
104 }
105 return err;
106}
107
108void finish(void)
109{
110 if (!quiet) {
111 printf("Sent %d probes (%d broadcast(s))\n", sent, brd_sent);
112 printf("Received %d repl%s", received, (received > 1) ? "ies" : "y");
113 if (brd_recv || req_recv) {
114 printf(" (");
115 if (req_recv)
116 printf("%d request(s)", req_recv);
117 if (brd_recv)
118 printf("%s%d broadcast(s)", req_recv ? ", " : "", brd_recv);
119 putchar(')');
120 }
121 putchar('\n');
122 fflush(stdout);
123 }
124 if (dad)
125 exit(!!received);
126 if (unsolicited)
127 exit(0);
128 exit(!received);
129}
130
131void catcher(void)
132{
133 struct timeval tv;
134 struct timeval start;
135
136 gettimeofday(&tv, NULL);
137
138 if (start.tv_sec == 0)
139 start = tv;
140
141 if (count-- == 0
142 || (timeout && MS_TDIFF(tv, start) > timeout * 1000 + 500))
143 finish();
144
145 if (last.tv_sec == 0 || MS_TDIFF(tv, last) > 500) {
146 send_pack(s, &src, &dst, &me, &he);
147 if (count == 0 && unsolicited)
148 finish();
149 }
150 alarm(1);
151}
152
153int recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM)
154{
155 struct timeval tv;
156 struct arphdr *ah = (struct arphdr *) buf;
157 unsigned char *p = (unsigned char *) (ah + 1);
158 struct in_addr src_ip, dst_ip;
159
160 gettimeofday(&tv, NULL);
161
162 /* Filter out wild packets */
163 if (FROM->sll_pkttype != PACKET_HOST &&
164 FROM->sll_pkttype != PACKET_BROADCAST &&
165 FROM->sll_pkttype != PACKET_MULTICAST)
166 return 0;
167
168 /* Only these types are recognised */
169 if (ah->ar_op != htons(ARPOP_REQUEST) && ah->ar_op != htons(ARPOP_REPLY))
170 return 0;
171
172 /* ARPHRD check and this darned FDDI hack here :-( */
173 if (ah->ar_hrd != htons(FROM->sll_hatype) &&
174 (FROM->sll_hatype != ARPHRD_FDDI
175 || ah->ar_hrd != htons(ARPHRD_ETHER)))
176 return 0;
177
178 /* Protocol must be IP. */
179 if (ah->ar_pro != htons(ETH_P_IP))
180 return 0;
181 if (ah->ar_pln != 4)
182 return 0;
183 if (ah->ar_hln != me.sll_halen)
184 return 0;
185 if (len < sizeof(*ah) + 2 * (4 + ah->ar_hln))
186 return 0;
187 memcpy(&src_ip, p + ah->ar_hln, 4);
188 memcpy(&dst_ip, p + ah->ar_hln + 4 + ah->ar_hln, 4);
189 if (!dad) {
190 if (src_ip.s_addr != dst.s_addr)
191 return 0;
192 if (src.s_addr != dst_ip.s_addr)
193 return 0;
194 if (memcmp(p + ah->ar_hln + 4, &me.sll_addr, ah->ar_hln))
195 return 0;
196 } else {
197 /* DAD packet was:
198 src_ip = 0 (or some src)
199 src_hw = ME
200 dst_ip = tested address
201 dst_hw = <unspec>
202
203 We fail, if receive request/reply with:
204 src_ip = tested_address
205 src_hw != ME
206 if src_ip in request was not zero, check
207 also that it matches to dst_ip, otherwise
208 dst_ip/dst_hw do not matter.
209 */
210 if (src_ip.s_addr != dst.s_addr)
211 return 0;
212 if (memcmp(p, &me.sll_addr, me.sll_halen) == 0)
213 return 0;
214 if (src.s_addr && src.s_addr != dst_ip.s_addr)
215 return 0;
216 }
217 if (!quiet) {
218 int s_printed = 0;
219
220 printf("%s ",
221 FROM->sll_pkttype == PACKET_HOST ? "Unicast" : "Broadcast");
222 printf("%s from ",
223 ah->ar_op == htons(ARPOP_REPLY) ? "reply" : "request");
224 printf("%s ", inet_ntoa(src_ip));
225 printf("[%s]", ether_ntoa((struct ether_addr *) p));
226 if (dst_ip.s_addr != src.s_addr) {
227 printf("for %s ", inet_ntoa(dst_ip));
228 s_printed = 1;
229 }
230 if (memcmp(p + ah->ar_hln + 4, me.sll_addr, ah->ar_hln)) {
231 if (!s_printed)
232 printf("for ");
233 printf("[%s]",
234 ether_ntoa((struct ether_addr *) p + ah->ar_hln + 4));
235 }
236 if (last.tv_sec) {
237 long usecs = (tv.tv_sec - last.tv_sec) * 1000000 +
238 tv.tv_usec - last.tv_usec;
239 long msecs = (usecs + 500) / 1000;
240
241 usecs -= msecs * 1000 - 500;
242 printf(" %ld.%03ldms\n", msecs, usecs);
243 } else {
244 printf(" UNSOLICITED?\n");
245 }
246 fflush(stdout);
247 }
248 received++;
249 if (FROM->sll_pkttype != PACKET_HOST)
250 brd_recv++;
251 if (ah->ar_op == htons(ARPOP_REQUEST))
252 req_recv++;
253 if (quit_on_reply)
254 finish();
255 if (!broadcast_only) {
256 memcpy(he.sll_addr, p, me.sll_halen);
257 unicasting = 1;
258 }
259 return 1;
260}
261
262int arping_main(int argc, char **argv)
263{
264 int socket_errno;
265 int ch;
266 uid_t uid = getuid();
267 char *device = "eth0";
268 int ifindex = 0;
269 char *source = NULL;
270 char *target;
271
272 s = socket(PF_PACKET, SOCK_DGRAM, 0);
273 socket_errno = errno;
274
275 setuid(uid);
276
277 while ((ch = getopt(argc, argv, "h?bfDUAqc:w:s:I")) != EOF) {
278 switch (ch) {
279 case 'b':
280 broadcast_only = 1;
281 break;
282 case 'D':
283 dad++;
284 quit_on_reply = 1;
285 break;
286 case 'U':
287 unsolicited++;
288 break;
289 case 'A':
290 advert++;
291 unsolicited++;
292 break;
293 case 'q':
294 quiet++;
295 break;
296 case 'c':
297 count = atoi(optarg);
298 break;
299 case 'w':
300 timeout = atoi(optarg);
301 break;
302 case 'I':
303 device = optarg;
304 break;
305 case 'f':
306 quit_on_reply = 1;
307 break;
308 case 's':
309 source = optarg;
310 break;
311 case 'h':
312 case '?':
313 default:
314 show_usage();
315 }
316 }
317 argc -= optind;
318 argv += optind;
319
320 if (argc != 1)
321 show_usage();
322
323 target = *argv;
324
325 if (device == NULL) {
326 error_msg("-I <interface> is required!");
327 exit(1);
328 }
329
330 if (s < 0) {
331 error_msg("socket");
332 exit(socket_errno);
333 }
334
335 if (1) {
336 struct ifreq ifr;
337
338 memset(&ifr, 0, sizeof(ifr));
339 strncpy(ifr.ifr_name, device, IFNAMSIZ - 1);
340 if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
341 error_msg("unknown interface %s", device);
342 exit(2);
343 }
344 ifindex = ifr.ifr_ifindex;
345
346 if (ioctl(s, SIOCGIFFLAGS, (char *) &ifr)) {
347 error_msg("SIOCGIFFLAGS");
348 exit(2);
349 }
350 if (!(ifr.ifr_flags & IFF_UP)) {
351 error_msg("Interface \"%s\" is down", device);
352 exit(2);
353 }
354 if (ifr.ifr_flags & (IFF_NOARP | IFF_LOOPBACK)) {
355 error_msg("Interface \"%s\" is not ARPable", device);
356 exit(dad ? 0 : 2);
357 }
358 }
359
360 if (inet_aton(target, &dst) != 1) {
361 struct hostent *hp;
362
363 hp = gethostbyname2(target, AF_INET);
364 if (!hp) {
365 error_msg("invalid or unknown target %s", target);
366 exit(2);
367 }
368 memcpy(&dst, hp->h_addr, 4);
369 }
370
371 if (source && inet_aton(source, &src) != 1) {
372 error_msg("invalid source address %s", source);
373 exit(2);
374 }
375
376 if (!dad && unsolicited && src.s_addr == 0)
377 src = dst;
378
379 if (!dad || src.s_addr) {
380 struct sockaddr_in saddr;
381 int probe_fd = socket(AF_INET, SOCK_DGRAM, 0);
382
383 if (probe_fd < 0) {
384 error_msg("socket");
385 exit(2);
386 }
387 if (device) {
388 if (setsockopt
389 (probe_fd, SOL_SOCKET, SO_BINDTODEVICE, device,
390 strlen(device) + 1) == -1)
391 perror("WARNING: interface is ignored");
392 }
393 memset(&saddr, 0, sizeof(saddr));
394 saddr.sin_family = AF_INET;
395 if (src.s_addr) {
396 saddr.sin_addr = src;
397 if (bind(probe_fd, (struct sockaddr *) &saddr, sizeof(saddr)) == -1) {
398 error_msg("bind");
399 exit(2);
400 }
401 } else if (!dad) {
402 int on = 1;
403 int alen = sizeof(saddr);
404
405 saddr.sin_port = htons(1025);
406 saddr.sin_addr = dst;
407
408 if (setsockopt
409 (probe_fd, SOL_SOCKET, SO_DONTROUTE, (char *) &on,
410 sizeof(on)) == -1)
411 perror("WARNING: setsockopt(SO_DONTROUTE)");
412 if (connect(probe_fd, (struct sockaddr *) &saddr, sizeof(saddr))
413 == -1) {
414 error_msg("connect");
415 exit(2);
416 }
417 if (getsockname(probe_fd, (struct sockaddr *) &saddr, &alen) ==
418 -1) {
419 error_msg("getsockname");
420 exit(2);
421 }
422 src = saddr.sin_addr;
423 }
424 close(probe_fd);
425 };
426
427 me.sll_family = AF_PACKET;
428 me.sll_ifindex = ifindex;
429 me.sll_protocol = htons(ETH_P_ARP);
430 if (bind(s, (struct sockaddr *) &me, sizeof(me)) == -1) {
431 error_msg("bind");
432 exit(2);
433 }
434
435 if (1) {
436 int alen = sizeof(me);
437
438 if (getsockname(s, (struct sockaddr *) &me, &alen) == -1) {
439 error_msg("getsockname");
440 exit(2);
441 }
442 }
443 if (me.sll_halen == 0) {
444 error_msg("Interface \"%s\" is not ARPable (no ll address)", device);
445 exit(dad ? 0 : 2);
446 }
447 he = me;
448 memset(he.sll_addr, -1, he.sll_halen);
449
450 if (!quiet)
451 printf("ARPING to %s from %s via %s\n", inet_ntoa(dst),
452 inet_ntoa(src), device ? device : "unknown");
453
454 if (!src.s_addr && !dad) {
455 error_msg("no src address in the non-DAD mode");
456 exit(2);
457 }
458
459 {
460 struct sigaction sa;
461 memset(&sa, 0, sizeof(sa));
462 sa.sa_flags = SA_RESTART;
463
464 sa.sa_handler = (void (*)(int)) finish;
465 sigaction(SIGINT, &sa, NULL);
466
467 sa.sa_handler = (void (*)(int)) catcher;
468 sigaction(SIGALRM, &sa, NULL);
469 }
470
471 catcher();
472
473 while (1) {
474 sigset_t sset, osset;
475 char packet[4096];
476 struct sockaddr_ll from;
477 int alen = sizeof(from);
478 int cc;
479
480 if ((cc = recvfrom(s, packet, sizeof(packet), 0,
481 (struct sockaddr *) &from, &alen)) < 0) {
482 perror("recvfrom");
483 continue;
484 }
485 sigemptyset(&sset);
486 sigaddset(&sset, SIGALRM);
487 sigaddset(&sset, SIGINT);
488 sigprocmask(SIG_BLOCK, &sset, &osset);
489 recv_pack(packet, cc, &from);
490 sigprocmask(SIG_SETMASK, &osset, NULL);
491 }
492}