1/* vi: set sw=4 ts=4: */ 2/* 3 * arping.c - Ping hosts by ARP requests/replies 4 * 5 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. 6 * 7 * Author: Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> 8 * Busybox port: Nick Fedchik <nick@fedchik.org.ua> 9 */ 10 11#include <arpa/inet.h> 12#include <net/if.h> 13#include <netinet/ether.h> 14#include <netpacket/packet.h> 15 16#include "libbb.h" 17 18/* We don't expect to see 1000+ seconds delay, unsigned is enough */ 19#define MONOTONIC_US() ((unsigned)monotonic_us()) 20 21static struct in_addr src; 22static struct in_addr dst; 23static struct sockaddr_ll me; 24static struct sockaddr_ll he; 25static unsigned last; 26 27enum { 28 DAD = 1, 29 UNSOLICITED = 2, 30 ADVERT = 4, 31 QUIET = 8, 32 QUIT_ON_REPLY = 16, 33 BCAST_ONLY = 32, 34 UNICASTING = 64 35}; 36 37static int sock; 38static unsigned count = UINT_MAX; 39static unsigned timeout_us; 40static unsigned sent; 41static unsigned brd_sent; 42static unsigned received; 43static unsigned brd_recv; 44static unsigned req_recv; 45 46static int send_pack(struct in_addr *src_addr, 47 struct in_addr *dst_addr, struct sockaddr_ll *ME, 48 struct sockaddr_ll *HE) 49{ 50 int err; 51 unsigned now; 52 unsigned char buf[256]; 53 struct arphdr *ah = (struct arphdr *) buf; 54 unsigned char *p = (unsigned char *) (ah + 1); 55 56 ah->ar_hrd = htons(ME->sll_hatype); 57 ah->ar_hrd = htons(ARPHRD_ETHER); 58 ah->ar_pro = htons(ETH_P_IP); 59 ah->ar_hln = ME->sll_halen; 60 ah->ar_pln = 4; 61 ah->ar_op = option_mask32 & ADVERT ? htons(ARPOP_REPLY) : htons(ARPOP_REQUEST); 62 63 memcpy(p, &ME->sll_addr, ah->ar_hln); 64 p += ME->sll_halen; 65 66 memcpy(p, src_addr, 4); 67 p += 4; 68 69 if (option_mask32 & ADVERT) 70 memcpy(p, &ME->sll_addr, ah->ar_hln); 71 else 72 memcpy(p, &HE->sll_addr, ah->ar_hln); 73 p += ah->ar_hln; 74 75 memcpy(p, dst_addr, 4); 76 p += 4; 77 78 now = MONOTONIC_US(); 79 err = sendto(sock, buf, p - buf, 0, (struct sockaddr *) HE, sizeof(*HE)); 80 if (err == p - buf) { 81 last = now; 82 sent++; 83 if (!(option_mask32 & UNICASTING)) 84 brd_sent++; 85 } 86 return err; 87} 88 89static void finish(void) ATTRIBUTE_NORETURN; 90static void finish(void) 91{ 92 if (!(option_mask32 & QUIET)) { 93 printf("Sent %u probe(s) (%u broadcast(s))\n" 94 "Received %u repl%s" 95 " (%u request(s), %u broadcast(s))\n", 96 sent, brd_sent, 97 received, (received == 1) ? "ies" : "y", 98 req_recv, brd_recv); 99 } 100 if (option_mask32 & DAD) 101 exit(!!received); 102 if (option_mask32 & UNSOLICITED) 103 exit(0); 104 exit(!received); 105} 106 107static void catcher(void) 108{ 109 static unsigned start; 110 111 unsigned now; 112 113 now = MONOTONIC_US(); 114 if (start == 0) 115 start = now; 116 117 if (count == 0 || (timeout_us && (now - start) > (timeout_us + 500000))) 118 finish(); 119 120 count--; 121 122 if (last == 0 || (now - last) > 500000) { 123 send_pack(&src, &dst, &me, &he); 124 if (count == 0 && (option_mask32 & UNSOLICITED)) 125 finish(); 126 } 127 alarm(1); 128} 129 130static int recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM) 131{ 132 struct arphdr *ah = (struct arphdr *) buf; 133 unsigned char *p = (unsigned char *) (ah + 1); 134 struct in_addr src_ip, dst_ip; 135 136 /* Filter out wild packets */ 137 if (FROM->sll_pkttype != PACKET_HOST 138 && FROM->sll_pkttype != PACKET_BROADCAST 139 && FROM->sll_pkttype != PACKET_MULTICAST) 140 return 0; 141 142 /* Only these types are recognised */ 143 if (ah->ar_op != htons(ARPOP_REQUEST) && ah->ar_op != htons(ARPOP_REPLY)) 144 return 0; 145 146 /* ARPHRD check and this darned FDDI hack here :-( */ 147 if (ah->ar_hrd != htons(FROM->sll_hatype) 148 && (FROM->sll_hatype != ARPHRD_FDDI || ah->ar_hrd != htons(ARPHRD_ETHER))) 149 return 0; 150 151 /* Protocol must be IP. */ 152 if (ah->ar_pro != htons(ETH_P_IP)) 153 return 0; 154 if (ah->ar_pln != 4) 155 return 0; 156 if (ah->ar_hln != me.sll_halen) 157 return 0; 158 if (len < sizeof(*ah) + 2 * (4 + ah->ar_hln)) 159 return 0; 160 memcpy(&src_ip, p + ah->ar_hln, 4); 161 memcpy(&dst_ip, p + ah->ar_hln + 4 + ah->ar_hln, 4); 162 if (!(option_mask32 & DAD)) { 163 if (src_ip.s_addr != dst.s_addr) 164 return 0; 165 if (src.s_addr != dst_ip.s_addr) 166 return 0; 167 if (memcmp(p + ah->ar_hln + 4, &me.sll_addr, ah->ar_hln)) 168 return 0; 169 } else { 170 /* DAD packet was: 171 src_ip = 0 (or some src) 172 src_hw = ME 173 dst_ip = tested address 174 dst_hw = <unspec> 175 176 We fail, if receive request/reply with: 177 src_ip = tested_address 178 src_hw != ME 179 if src_ip in request was not zero, check 180 also that it matches to dst_ip, otherwise 181 dst_ip/dst_hw do not matter. 182 */ 183 if (src_ip.s_addr != dst.s_addr) 184 return 0; 185 if (memcmp(p, &me.sll_addr, me.sll_halen) == 0) 186 return 0; 187 if (src.s_addr && src.s_addr != dst_ip.s_addr) 188 return 0; 189 } 190 if (!(option_mask32 & QUIET)) { 191 int s_printed = 0; 192 193 printf("%scast re%s from %s [%s]", 194 FROM->sll_pkttype == PACKET_HOST ? "Uni" : "Broad", 195 ah->ar_op == htons(ARPOP_REPLY) ? "ply" : "quest", 196 inet_ntoa(src_ip), 197 ether_ntoa((struct ether_addr *) p)); 198 if (dst_ip.s_addr != src.s_addr) { 199 printf("for %s ", inet_ntoa(dst_ip)); 200 s_printed = 1; 201 } 202 if (memcmp(p + ah->ar_hln + 4, me.sll_addr, ah->ar_hln)) { 203 if (!s_printed) 204 printf("for "); 205 printf("[%s]", 206 ether_ntoa((struct ether_addr *) p + ah->ar_hln + 4)); 207 } 208 209 if (last) { 210 printf(" %u.%03ums\n", last / 1000, last % 1000); 211 } else { 212 printf(" UNSOLICITED?\n"); 213 } 214 fflush(stdout); 215 } 216 received++; 217 if (FROM->sll_pkttype != PACKET_HOST) 218 brd_recv++; 219 if (ah->ar_op == htons(ARPOP_REQUEST)) 220 req_recv++; 221 if (option_mask32 & QUIT_ON_REPLY) 222 finish(); 223 if (!(option_mask32 & BCAST_ONLY)) { 224 memcpy(he.sll_addr, p, me.sll_halen); 225 option_mask32 |= UNICASTING; 226 } 227 return 1; 228} 229 230int arping_main(int argc, char **argv); 231int arping_main(int argc, char **argv) 232{ 233 const char *device = "eth0"; 234 int ifindex; 235 char *source = NULL; 236 char *target; 237 unsigned char *packet; 238 239 sock = xsocket(PF_PACKET, SOCK_DGRAM, 0); 240 241 // Drop suid root privileges 242 xsetuid(getuid()); 243 244 { 245 unsigned opt; 246 char *str_count, *str_timeout; 247 248 /* Dad also sets quit_on_reply. 249 * Advert also sets unsolicited. 250 */ 251 opt_complementary = "=1:Df:AU"; 252 opt = getopt32(argv, "DUAqfbc:w:I:s:", 253 &str_count, &str_timeout, &device, &source); 254 if (opt & 0x40) /* -c: count */ 255 count = xatou(str_count); 256 if (opt & 0x80) /* -w: timeout */ 257 timeout_us = xatou_range(str_timeout, 0, INT_MAX/2000000) * 1000000; 258 //if (opt & 0x100) /* -I: interface */ 259 if (strlen(device) >= IF_NAMESIZE) { 260 bb_error_msg_and_die("interface name '%s' is too long", 261 device); 262 } 263 //if (opt & 0x200) /* -s: source */ 264 option_mask32 &= 0x3f; /* set respective flags */ 265 } 266 267 target = argv[optind]; 268 269 xfunc_error_retval = 2; 270 271 { 272 struct ifreq ifr; 273 274 memset(&ifr, 0, sizeof(ifr)); 275 strncpy(ifr.ifr_name, device, IFNAMSIZ - 1); 276 ioctl_or_perror_and_die(sock, SIOCGIFINDEX, &ifr, "interface %s not found", device); 277 ifindex = ifr.ifr_ifindex; 278 279 xioctl(sock, SIOCGIFFLAGS, (char *) &ifr); 280 281 if (!(ifr.ifr_flags & IFF_UP)) { 282 bb_error_msg_and_die("interface %s is down", device); 283 } 284 if (ifr.ifr_flags & (IFF_NOARP | IFF_LOOPBACK)) { 285 bb_error_msg("interface %s is not ARPable", device); 286 return (option_mask32 & DAD ? 0 : 2); 287 } 288 } 289 290 if (!inet_aton(target, &dst)) { 291 len_and_sockaddr *lsa; 292 lsa = xhost_and_af2sockaddr(target, 0, AF_INET); 293 memcpy(&dst, &lsa->sin.sin_addr.s_addr, 4); 294 if (ENABLE_FEATURE_CLEAN_UP) 295 free(lsa); 296 } 297 298 if (source && !inet_aton(source, &src)) { 299 bb_error_msg_and_die("invalid source address %s", source); 300 } 301 302 if (!(option_mask32 & DAD) && (option_mask32 & UNSOLICITED) && src.s_addr == 0) 303 src = dst; 304 305 if (!(option_mask32 & DAD) || src.s_addr) { 306 struct sockaddr_in saddr; 307 int probe_fd = xsocket(AF_INET, SOCK_DGRAM, 0); 308 309 if (device) { 310 if (setsockopt(probe_fd, SOL_SOCKET, SO_BINDTODEVICE, device, strlen(device) + 1) == -1) 311 bb_error_msg("warning: interface %s is ignored", device); 312 } 313 memset(&saddr, 0, sizeof(saddr)); 314 saddr.sin_family = AF_INET; 315 if (src.s_addr) { 316 saddr.sin_addr = src; 317 xbind(probe_fd, (struct sockaddr *) &saddr, sizeof(saddr)); 318 } else if (!(option_mask32 & DAD)) { 319 socklen_t alen = sizeof(saddr); 320 321 saddr.sin_port = htons(1025); 322 saddr.sin_addr = dst; 323 324 if (setsockopt(probe_fd, SOL_SOCKET, SO_DONTROUTE, &const_int_1, sizeof(const_int_1)) == -1) 325 bb_perror_msg("warning: setsockopt(SO_DONTROUTE)"); 326 xconnect(probe_fd, (struct sockaddr *) &saddr, sizeof(saddr)); 327 if (getsockname(probe_fd, (struct sockaddr *) &saddr, &alen) == -1) { 328 bb_error_msg_and_die("getsockname"); 329 } 330 src = saddr.sin_addr; 331 } 332 close(probe_fd); 333 } 334 335 me.sll_family = AF_PACKET; 336 me.sll_ifindex = ifindex; 337 me.sll_protocol = htons(ETH_P_ARP); 338 xbind(sock, (struct sockaddr *) &me, sizeof(me)); 339 340 { 341 socklen_t alen = sizeof(me); 342 343 if (getsockname(sock, (struct sockaddr *) &me, &alen) == -1) { 344 bb_error_msg_and_die("getsockname"); 345 } 346 } 347 if (me.sll_halen == 0) { 348 bb_error_msg("interface \"%s\" is not ARPable (no ll address)", device); 349 return (option_mask32 & DAD ? 0 : 2); 350 } 351 he = me; 352 memset(he.sll_addr, -1, he.sll_halen); 353 354 if (!(option_mask32 & QUIET)) { 355 printf("ARPING to %s from %s via %s\n", 356 inet_ntoa(dst), inet_ntoa(src), 357 device ? device : "unknown"); 358 } 359 360 if (!src.s_addr && !(option_mask32 & DAD)) { 361 bb_error_msg_and_die("no src address in the non-DAD mode"); 362 } 363 364 { 365 struct sigaction sa; 366 367 memset(&sa, 0, sizeof(sa)); 368 sa.sa_flags = SA_RESTART; 369 370 sa.sa_handler = (void (*)(int)) finish; 371 sigaction(SIGINT, &sa, NULL); 372 373 sa.sa_handler = (void (*)(int)) catcher; 374 sigaction(SIGALRM, &sa, NULL); 375 } 376 377 catcher(); 378 379 packet = xmalloc(4096); 380 while (1) { 381 sigset_t sset, osset; 382 struct sockaddr_ll from; 383 socklen_t alen = sizeof(from); 384 int cc; 385 386 cc = recvfrom(sock, packet, 4096, 0, (struct sockaddr *) &from, &alen); 387 if (cc < 0) { 388 bb_perror_msg("recvfrom"); 389 continue; 390 } 391 sigemptyset(&sset); 392 sigaddset(&sset, SIGALRM); 393 sigaddset(&sset, SIGINT); 394 sigprocmask(SIG_BLOCK, &sset, &osset); 395 recv_pack(packet, cc, &from); 396 sigprocmask(SIG_SETMASK, &osset, NULL); 397 } 398} 399