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>
35 #include <sysfs/libsysfs.h>
39 static void usage(void) __attribute__((noreturn));
45 struct in_addr src, dst;
47 int dad, unsolicited, advert;
55 struct sockaddr_storage me;
56 struct sockaddr_storage he;
58 struct timeval start, last;
61 int received, brd_recv, req_recv;
63 #define MS_TDIFF(tv1,tv2) ( ((tv1).tv_sec-(tv2).tv_sec)*1000 + \
64 ((tv1).tv_usec-(tv2).tv_usec)/1000 )
66 #define OFFSET_OF(name,ele) ((size_t)(((name *)0)->ele))
68 static inline socklen_t sll_len(size_t halen)
70 socklen_t len = OFFSET_OF(struct sockaddr_ll, sll_addr) + halen;
71 if (len < sizeof(struct sockaddr_ll))
72 len = sizeof(struct sockaddr_ll);
76 #define SLL_LEN(hln) sll_len(hln)
81 "Usage: arping [-fqbDUAV] [-c count] [-w timeout] [-I device] [-s source] destination\n"
82 " -f : quit on first reply\n"
84 " -b : keep broadcasting, don't go unicast\n"
85 " -D : duplicate address detection mode\n"
86 " -U : Unsolicited ARP mode, update your neighbours\n"
87 " -A : ARP answer mode, update your neighbours\n"
88 " -V : print version and exit\n"
89 " -c count : how many packets to send\n"
90 " -w timeout : how long to wait for a reply\n"
91 " -I device : which ethernet device to use (eth0)\n"
92 " -s source : source ip address\n"
93 " destination : ask for what ip address\n"
98 void set_signal(int signo, void (*handler)(void))
102 memset(&sa, 0, sizeof(sa));
103 sa.sa_handler = (void (*)(int))handler;
104 sa.sa_flags = SA_RESTART;
105 sigaction(signo, &sa, NULL);
108 int send_pack(int s, struct in_addr src, struct in_addr dst,
109 struct sockaddr_ll *ME, struct sockaddr_ll *HE)
113 unsigned char buf[256];
114 struct arphdr *ah = (struct arphdr*)buf;
115 unsigned char *p = (unsigned char *)(ah+1);
117 ah->ar_hrd = htons(ME->sll_hatype);
118 if (ah->ar_hrd == htons(ARPHRD_FDDI))
119 ah->ar_hrd = htons(ARPHRD_ETHER);
120 ah->ar_pro = htons(ETH_P_IP);
121 ah->ar_hln = ME->sll_halen;
123 ah->ar_op = advert ? htons(ARPOP_REPLY) : htons(ARPOP_REQUEST);
125 memcpy(p, &ME->sll_addr, ah->ar_hln);
132 memcpy(p, &ME->sll_addr, ah->ar_hln);
134 memcpy(p, &HE->sll_addr, ah->ar_hln);
140 gettimeofday(&now, NULL);
141 err = sendto(s, buf, p-buf, 0, (struct sockaddr*)HE, SLL_LEN(ah->ar_hln));
154 printf("Sent %d probes (%d broadcast(s))\n", sent, brd_sent);
155 printf("Received %d response(s)", received);
156 if (brd_recv || req_recv) {
159 printf("%d request(s)", req_recv);
161 printf("%s%d broadcast(s)",
162 req_recv ? ", " : "",
180 gettimeofday(&tv, NULL);
185 if (count-- == 0 || (timeout && MS_TDIFF(tv,start) > timeout*1000 + 500))
188 if (last.tv_sec==0 || MS_TDIFF(tv,last) > 500) {
189 send_pack(s, src, dst,
190 (struct sockaddr_ll *)&me, (struct sockaddr_ll *)&he);
191 if (count == 0 && unsolicited)
197 void print_hex(unsigned char *p, int len)
200 for (i=0; i<len; i++) {
201 printf("%02X", p[i]);
207 int recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM)
210 struct arphdr *ah = (struct arphdr*)buf;
211 unsigned char *p = (unsigned char *)(ah+1);
212 struct in_addr src_ip, dst_ip;
214 gettimeofday(&tv, NULL);
216 /* Filter out wild packets */
217 if (FROM->sll_pkttype != PACKET_HOST &&
218 FROM->sll_pkttype != PACKET_BROADCAST &&
219 FROM->sll_pkttype != PACKET_MULTICAST)
222 /* Only these types are recognised */
223 if (ah->ar_op != htons(ARPOP_REQUEST) &&
224 ah->ar_op != htons(ARPOP_REPLY))
227 /* ARPHRD check and this darned FDDI hack here :-( */
228 if (ah->ar_hrd != htons(FROM->sll_hatype) &&
229 (FROM->sll_hatype != ARPHRD_FDDI || ah->ar_hrd != htons(ARPHRD_ETHER)))
232 /* Protocol must be IP. */
233 if (ah->ar_pro != htons(ETH_P_IP))
237 if (ah->ar_hln != ((struct sockaddr_ll *)&me)->sll_halen)
239 if (len < sizeof(*ah) + 2*(4 + ah->ar_hln))
241 memcpy(&src_ip, p+ah->ar_hln, 4);
242 memcpy(&dst_ip, p+ah->ar_hln+4+ah->ar_hln, 4);
244 if (src_ip.s_addr != dst.s_addr)
246 if (src.s_addr != dst_ip.s_addr)
248 if (memcmp(p+ah->ar_hln+4, ((struct sockaddr_ll *)&me)->sll_addr, ah->ar_hln))
252 src_ip = 0 (or some src)
254 dst_ip = tested address
257 We fail, if receive request/reply with:
258 src_ip = tested_address
260 if src_ip in request was not zero, check
261 also that it matches to dst_ip, otherwise
262 dst_ip/dst_hw do not matter.
264 if (src_ip.s_addr != dst.s_addr)
266 if (memcmp(p, ((struct sockaddr_ll *)&me)->sll_addr, ((struct sockaddr_ll *)&me)->sll_halen) == 0)
268 if (src.s_addr && src.s_addr != dst_ip.s_addr)
273 printf("%s ", FROM->sll_pkttype==PACKET_HOST ? "Unicast" : "Broadcast");
274 printf("%s from ", ah->ar_op == htons(ARPOP_REPLY) ? "reply" : "request");
275 printf("%s [", inet_ntoa(src_ip));
276 print_hex(p, ah->ar_hln);
278 if (dst_ip.s_addr != src.s_addr) {
279 printf("for %s ", inet_ntoa(dst_ip));
282 if (memcmp(p+ah->ar_hln+4, ((struct sockaddr_ll *)&me)->sll_addr, ah->ar_hln)) {
286 print_hex(p+ah->ar_hln+4, ah->ar_hln);
290 long usecs = (tv.tv_sec-last.tv_sec) * 1000000 +
291 tv.tv_usec-last.tv_usec;
292 long msecs = (usecs+500)/1000;
293 usecs -= msecs*1000 - 500;
294 printf(" %ld.%03ldms\n", msecs, usecs);
296 printf(" UNSOLICITED?\n");
301 if (FROM->sll_pkttype != PACKET_HOST)
303 if (ah->ar_op == htons(ARPOP_REQUEST))
307 if(!broadcast_only) {
308 memcpy(((struct sockaddr_ll *)&he)->sll_addr, p, ((struct sockaddr_ll *)&me)->sll_halen);
314 void set_device_broadcast(char *device, unsigned char *ba, size_t balen)
316 struct sysfs_class_device *dev;
317 struct sysfs_attribute *brdcast;
321 dev = sysfs_open_class_device("net", device);
323 perror("sysfs_open_class_device(net)");
327 brdcast = sysfs_get_classdev_attr(dev, "broadcast");
329 perror("sysfs_get_classdev_attr(broadcast)");
333 if (sysfs_read_attribute(brdcast)) {
334 perror("sysfs_read_attribute");
338 for (p = ba, ch = 0; p < ba + balen; p++, ch += 3)
339 *p = strtoul(brdcast->value + ch, NULL, 16);
345 main(int argc, char **argv)
349 uid_t uid = getuid();
351 s = socket(PF_PACKET, SOCK_DGRAM, 0);
352 socket_errno = errno;
355 perror("arping: setuid");
359 while ((ch = getopt(argc, argv, "h?bfDUAqc:w:s:I:V")) != EOF) {
379 count = atoi(optarg);
382 timeout = atoi(optarg);
394 printf("arping utility, iputils-ss%s\n", SNAPSHOT);
410 if (device == NULL) {
411 fprintf(stderr, "arping: device (option -I) is required\n");
416 errno = socket_errno;
417 perror("arping: socket");
423 memset(&ifr, 0, sizeof(ifr));
424 strncpy(ifr.ifr_name, device, IFNAMSIZ-1);
425 if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
426 fprintf(stderr, "arping: unknown iface %s\n", device);
429 ifindex = ifr.ifr_ifindex;
431 if (ioctl(s, SIOCGIFFLAGS, (char*)&ifr)) {
432 perror("ioctl(SIOCGIFFLAGS)");
435 if (!(ifr.ifr_flags&IFF_UP)) {
437 printf("Interface \"%s\" is down\n", device);
440 if (ifr.ifr_flags&(IFF_NOARP|IFF_LOOPBACK)) {
442 printf("Interface \"%s\" is not ARPable\n", device);
447 if (inet_aton(target, &dst) != 1) {
449 hp = gethostbyname2(target, AF_INET);
451 fprintf(stderr, "arping: unknown host %s\n", target);
454 memcpy(&dst, hp->h_addr, 4);
457 if (source && inet_aton(source, &src) != 1) {
458 fprintf(stderr, "arping: invalid source %s\n", source);
462 if (!dad && unsolicited && src.s_addr == 0)
465 if (!dad || src.s_addr) {
466 struct sockaddr_in saddr;
467 int probe_fd = socket(AF_INET, SOCK_DGRAM, 0);
474 if (setsockopt(probe_fd, SOL_SOCKET, SO_BINDTODEVICE, device, strlen(device)+1) == -1)
475 perror("WARNING: interface is ignored");
477 memset(&saddr, 0, sizeof(saddr));
478 saddr.sin_family = AF_INET;
480 saddr.sin_addr = src;
481 if (bind(probe_fd, (struct sockaddr*)&saddr, sizeof(saddr)) == -1) {
487 socklen_t alen = sizeof(saddr);
489 saddr.sin_port = htons(1025);
490 saddr.sin_addr = dst;
492 if (setsockopt(probe_fd, SOL_SOCKET, SO_DONTROUTE, (char*)&on, sizeof(on)) == -1)
493 perror("WARNING: setsockopt(SO_DONTROUTE)");
494 if (connect(probe_fd, (struct sockaddr*)&saddr, sizeof(saddr)) == -1) {
498 if (getsockname(probe_fd, (struct sockaddr*)&saddr, &alen) == -1) {
499 perror("getsockname");
502 src = saddr.sin_addr;
507 ((struct sockaddr_ll *)&me)->sll_family = AF_PACKET;
508 ((struct sockaddr_ll *)&me)->sll_ifindex = ifindex;
509 ((struct sockaddr_ll *)&me)->sll_protocol = htons(ETH_P_ARP);
510 if (bind(s, (struct sockaddr*)&me, sizeof(me)) == -1) {
516 socklen_t alen = sizeof(me);
517 if (getsockname(s, (struct sockaddr*)&me, &alen) == -1) {
518 perror("getsockname");
522 if (((struct sockaddr_ll *)&me)->sll_halen == 0) {
524 printf("Interface \"%s\" is not ARPable (no ll address)\n", device);
531 set_device_broadcast(device, ((struct sockaddr_ll *)&he)->sll_addr,
532 ((struct sockaddr_ll *)&he)->sll_halen);
534 memset(((struct sockaddr_ll *)&he)->sll_addr, -1, ((struct sockaddr_ll *)&he)->sll_halen);
538 printf("ARPING %s ", inet_ntoa(dst));
539 printf("from %s %s\n", inet_ntoa(src), device ? : "");
542 if (!src.s_addr && !dad) {
543 fprintf(stderr, "arping: no source address in not-DAD mode\n");
547 set_signal(SIGINT, finish);
548 set_signal(SIGALRM, catcher);
553 sigset_t sset, osset;
554 unsigned char packet[4096];
555 struct sockaddr_storage from;
556 socklen_t alen = sizeof(from);
559 if ((cc = recvfrom(s, packet, sizeof(packet), 0,
560 (struct sockaddr *)&from, &alen)) < 0) {
561 perror("arping: recvfrom");
566 sigaddset(&sset, SIGALRM);
567 sigaddset(&sset, SIGINT);
568 sigprocmask(SIG_BLOCK, &sset, &osset);
569 recv_pack(packet, cc, (struct sockaddr_ll *)&from);
570 sigprocmask(SIG_SETMASK, &osset, NULL);