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.
9 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
13 #include <sys/param.h>
14 #include <sys/socket.h>
15 #include <linux/sockios.h>
18 #include <sys/signal.h>
19 #include <sys/ioctl.h>
21 #include <linux/if_packet.h>
22 #include <linux/if_ether.h>
23 #include <net/if_arp.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
37 static void usage(void) __attribute__((noreturn));
43 struct in_addr src, dst;
45 int dad, unsolicited, advert;
53 struct sockaddr_ll me;
54 struct sockaddr_ll he;
56 struct timeval start, last;
59 int received, brd_recv, req_recv;
61 #define MS_TDIFF(tv1,tv2) ( ((tv1).tv_sec-(tv2).tv_sec)*1000 + \
62 ((tv1).tv_usec-(tv2).tv_usec)/1000 )
67 "Usage: arping [-fqbDUAV] [-c count] [-w timeout] [-I device] [-s source] destination\n"
68 " -f : quit on first reply\n"
70 " -b : keep broadcasting, don't go unicast\n"
71 " -D : duplicate address detection mode\n"
72 " -U : Unsolicited ARP mode, update your neighbours\n"
73 " -A : ARP answer mode, update your neighbours\n"
74 " -V : print version and exit\n"
75 " -c count : how many packets to send\n"
76 " -w timeout : how long to wait for a reply\n"
77 " -I device : which ethernet device to use (eth0)\n"
78 " -s source : source ip address\n"
79 " destination : ask for what ip address\n"
84 void set_signal(int signo, void (*handler)(void))
88 memset(&sa, 0, sizeof(sa));
89 sa.sa_handler = (void (*)(int))handler;
90 sa.sa_flags = SA_RESTART;
91 sigaction(signo, &sa, NULL);
94 int send_pack(int s, struct in_addr src, struct in_addr dst,
95 struct sockaddr_ll *ME, struct sockaddr_ll *HE)
99 unsigned char buf[256];
100 struct arphdr *ah = (struct arphdr*)buf;
101 unsigned char *p = (unsigned char *)(ah+1);
103 ah->ar_hrd = htons(ME->sll_hatype);
104 if (ah->ar_hrd == htons(ARPHRD_FDDI))
105 ah->ar_hrd = htons(ARPHRD_ETHER);
106 ah->ar_pro = htons(ETH_P_IP);
107 ah->ar_hln = ME->sll_halen;
109 ah->ar_op = advert ? htons(ARPOP_REPLY) : htons(ARPOP_REQUEST);
111 memcpy(p, &ME->sll_addr, ah->ar_hln);
118 memcpy(p, &ME->sll_addr, ah->ar_hln);
120 memcpy(p, &HE->sll_addr, ah->ar_hln);
126 gettimeofday(&now, NULL);
127 err = sendto(s, buf, p-buf, 0, (struct sockaddr*)HE, sizeof(*HE));
140 printf("Sent %d probes (%d broadcast(s))\n", sent, brd_sent);
141 printf("Received %d response(s)", received);
142 if (brd_recv || req_recv) {
145 printf("%d request(s)", req_recv);
147 printf("%s%d broadcast(s)",
148 req_recv ? ", " : "",
166 gettimeofday(&tv, NULL);
171 if (count-- == 0 || (timeout && MS_TDIFF(tv,start) > timeout*1000 + 500))
174 if (last.tv_sec==0 || MS_TDIFF(tv,last) > 500) {
175 send_pack(s, src, dst, &me, &he);
176 if (count == 0 && unsolicited)
182 void print_hex(unsigned char *p, int len)
185 for (i=0; i<len; i++) {
186 printf("%02X", p[i]);
192 int recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM)
195 struct arphdr *ah = (struct arphdr*)buf;
196 unsigned char *p = (unsigned char *)(ah+1);
197 struct in_addr src_ip, dst_ip;
199 gettimeofday(&tv, NULL);
201 /* Filter out wild packets */
202 if (FROM->sll_pkttype != PACKET_HOST &&
203 FROM->sll_pkttype != PACKET_BROADCAST &&
204 FROM->sll_pkttype != PACKET_MULTICAST)
207 /* Only these types are recognised */
208 if (ah->ar_op != htons(ARPOP_REQUEST) &&
209 ah->ar_op != htons(ARPOP_REPLY))
212 /* ARPHRD check and this darned FDDI hack here :-( */
213 if (ah->ar_hrd != htons(FROM->sll_hatype) &&
214 (FROM->sll_hatype != ARPHRD_FDDI || ah->ar_hrd != htons(ARPHRD_ETHER)))
217 /* Protocol must be IP. */
218 if (ah->ar_pro != htons(ETH_P_IP))
222 if (ah->ar_hln != me.sll_halen)
224 if (len < sizeof(*ah) + 2*(4 + ah->ar_hln))
226 memcpy(&src_ip, p+ah->ar_hln, 4);
227 memcpy(&dst_ip, p+ah->ar_hln+4+ah->ar_hln, 4);
229 if (src_ip.s_addr != dst.s_addr)
231 if (src.s_addr != dst_ip.s_addr)
233 if (memcmp(p+ah->ar_hln+4, &me.sll_addr, ah->ar_hln))
237 src_ip = 0 (or some src)
239 dst_ip = tested address
242 We fail, if receive request/reply with:
243 src_ip = tested_address
245 if src_ip in request was not zero, check
246 also that it matches to dst_ip, otherwise
247 dst_ip/dst_hw do not matter.
249 if (src_ip.s_addr != dst.s_addr)
251 if (memcmp(p, &me.sll_addr, me.sll_halen) == 0)
253 if (src.s_addr && src.s_addr != dst_ip.s_addr)
258 printf("%s ", FROM->sll_pkttype==PACKET_HOST ? "Unicast" : "Broadcast");
259 printf("%s from ", ah->ar_op == htons(ARPOP_REPLY) ? "reply" : "request");
260 printf("%s [", inet_ntoa(src_ip));
261 print_hex(p, ah->ar_hln);
263 if (dst_ip.s_addr != src.s_addr) {
264 printf("for %s ", inet_ntoa(dst_ip));
267 if (memcmp(p+ah->ar_hln+4, me.sll_addr, ah->ar_hln)) {
271 print_hex(p+ah->ar_hln+4, ah->ar_hln);
275 long usecs = (tv.tv_sec-last.tv_sec) * 1000000 +
276 tv.tv_usec-last.tv_usec;
277 long msecs = (usecs+500)/1000;
278 usecs -= msecs*1000 - 500;
279 printf(" %ld.%03ldms\n", msecs, usecs);
281 printf(" UNSOLICITED?\n");
286 if (FROM->sll_pkttype != PACKET_HOST)
288 if (ah->ar_op == htons(ARPOP_REQUEST))
292 if(!broadcast_only) {
293 memcpy(he.sll_addr, p, me.sll_halen);
300 main(int argc, char **argv)
304 uid_t uid = getuid();
306 s = socket(PF_PACKET, SOCK_DGRAM, 0);
307 socket_errno = errno;
310 perror("arping: setuid");
314 while ((ch = getopt(argc, argv, "h?bfDUAqc:w:s:I:V")) != EOF) {
334 count = atoi(optarg);
337 timeout = atoi(optarg);
349 printf("arping utility, iputils-ss%s\n", SNAPSHOT);
365 if (device == NULL) {
366 fprintf(stderr, "arping: device (option -I) is required\n");
371 errno = socket_errno;
372 perror("arping: socket");
378 memset(&ifr, 0, sizeof(ifr));
379 strncpy(ifr.ifr_name, device, IFNAMSIZ-1);
380 if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
381 fprintf(stderr, "arping: unknown iface %s\n", device);
384 ifindex = ifr.ifr_ifindex;
386 if (ioctl(s, SIOCGIFFLAGS, (char*)&ifr)) {
387 perror("ioctl(SIOCGIFFLAGS)");
390 if (!(ifr.ifr_flags&IFF_UP)) {
392 printf("Interface \"%s\" is down\n", device);
395 if (ifr.ifr_flags&(IFF_NOARP|IFF_LOOPBACK)) {
397 printf("Interface \"%s\" is not ARPable\n", device);
402 if (inet_aton(target, &dst) != 1) {
404 hp = gethostbyname2(target, AF_INET);
406 fprintf(stderr, "arping: unknown host %s\n", target);
409 memcpy(&dst, hp->h_addr, 4);
412 if (source && inet_aton(source, &src) != 1) {
413 fprintf(stderr, "arping: invalid source %s\n", source);
417 if (!dad && unsolicited && src.s_addr == 0)
420 if (!dad || src.s_addr) {
421 struct sockaddr_in saddr;
422 int probe_fd = socket(AF_INET, SOCK_DGRAM, 0);
429 if (setsockopt(probe_fd, SOL_SOCKET, SO_BINDTODEVICE, device, strlen(device)+1) == -1)
430 perror("WARNING: interface is ignored");
432 memset(&saddr, 0, sizeof(saddr));
433 saddr.sin_family = AF_INET;
435 saddr.sin_addr = src;
436 if (bind(probe_fd, (struct sockaddr*)&saddr, sizeof(saddr)) == -1) {
442 socklen_t alen = sizeof(saddr);
444 saddr.sin_port = htons(1025);
445 saddr.sin_addr = dst;
447 if (setsockopt(probe_fd, SOL_SOCKET, SO_DONTROUTE, (char*)&on, sizeof(on)) == -1)
448 perror("WARNING: setsockopt(SO_DONTROUTE)");
449 if (connect(probe_fd, (struct sockaddr*)&saddr, sizeof(saddr)) == -1) {
453 if (getsockname(probe_fd, (struct sockaddr*)&saddr, &alen) == -1) {
454 perror("getsockname");
457 src = saddr.sin_addr;
462 me.sll_family = AF_PACKET;
463 me.sll_ifindex = ifindex;
464 me.sll_protocol = htons(ETH_P_ARP);
465 if (bind(s, (struct sockaddr*)&me, sizeof(me)) == -1) {
471 socklen_t alen = sizeof(me);
472 if (getsockname(s, (struct sockaddr*)&me, &alen) == -1) {
473 perror("getsockname");
477 if (me.sll_halen == 0) {
479 printf("Interface \"%s\" is not ARPable (no ll address)\n", device);
484 memset(he.sll_addr, -1, he.sll_halen);
487 printf("ARPING %s ", inet_ntoa(dst));
488 printf("from %s %s\n", inet_ntoa(src), device ? : "");
491 if (!src.s_addr && !dad) {
492 fprintf(stderr, "arping: no source address in not-DAD mode\n");
496 set_signal(SIGINT, finish);
497 set_signal(SIGALRM, catcher);
502 sigset_t sset, osset;
503 unsigned char packet[4096];
504 struct sockaddr_ll from;
505 socklen_t alen = sizeof(from);
508 if ((cc = recvfrom(s, packet, sizeof(packet), 0,
509 (struct sockaddr *)&from, &alen)) < 0) {
510 perror("arping: recvfrom");
514 sigaddset(&sset, SIGALRM);
515 sigaddset(&sset, SIGINT);
516 sigprocmask(SIG_BLOCK, &sset, &osset);
517 recv_pack(packet, cc, &from);
518 sigprocmask(SIG_SETMASK, &osset, NULL);