10f66f451Sopenharmony_ci/* arping - send ARP REQUEST to a neighbour host. 20f66f451Sopenharmony_ci * 30f66f451Sopenharmony_ci * Copyright 2013 Sandeep Sharma <sandeep.jack2756@gmail.com> 40f66f451Sopenharmony_ci * Copyright 2013 Kyungwan Han <asura321@gmail.com> 50f66f451Sopenharmony_ci * 60f66f451Sopenharmony_ci * No Standard. 70f66f451Sopenharmony_ci 80f66f451Sopenharmony_ciUSE_ARPING(NEWTOY(arping, "<1>1s:I:w#<0c#<0AUDbqf[+AU][+Df]", TOYFLAG_USR|TOYFLAG_SBIN)) 90f66f451Sopenharmony_ci 100f66f451Sopenharmony_ciconfig ARPING 110f66f451Sopenharmony_ci bool "arping" 120f66f451Sopenharmony_ci default n 130f66f451Sopenharmony_ci help 140f66f451Sopenharmony_ci usage: arping [-fqbDUA] [-c CNT] [-w TIMEOUT] [-I IFACE] [-s SRC_IP] DST_IP 150f66f451Sopenharmony_ci 160f66f451Sopenharmony_ci Send ARP requests/replies 170f66f451Sopenharmony_ci 180f66f451Sopenharmony_ci -f Quit on first ARP reply 190f66f451Sopenharmony_ci -q Quiet 200f66f451Sopenharmony_ci -b Keep broadcasting, don't go unicast 210f66f451Sopenharmony_ci -D Duplicated address detection mode 220f66f451Sopenharmony_ci -U Unsolicited ARP mode, update your neighbors 230f66f451Sopenharmony_ci -A ARP answer mode, update your neighbors 240f66f451Sopenharmony_ci -c N Stop after sending N ARP requests 250f66f451Sopenharmony_ci -w TIMEOUT Time to wait for ARP reply, seconds 260f66f451Sopenharmony_ci -I IFACE Interface to use (default eth0) 270f66f451Sopenharmony_ci -s SRC_IP Sender IP address 280f66f451Sopenharmony_ci DST_IP Target IP address 290f66f451Sopenharmony_ci*/ 300f66f451Sopenharmony_ci#define FOR_arping 310f66f451Sopenharmony_ci#include "toys.h" 320f66f451Sopenharmony_ci#include <netinet/ether.h> 330f66f451Sopenharmony_ci#include <netpacket/packet.h> 340f66f451Sopenharmony_ci 350f66f451Sopenharmony_ciGLOBALS( 360f66f451Sopenharmony_ci long count; 370f66f451Sopenharmony_ci unsigned long time_out; 380f66f451Sopenharmony_ci char *iface; 390f66f451Sopenharmony_ci char *src_ip; 400f66f451Sopenharmony_ci 410f66f451Sopenharmony_ci int sockfd; 420f66f451Sopenharmony_ci unsigned long start, end; 430f66f451Sopenharmony_ci unsigned sent_at, sent_nr, rcvd_nr, brd_sent, rcvd_req, brd_rcv, 440f66f451Sopenharmony_ci unicast_flag; 450f66f451Sopenharmony_ci) 460f66f451Sopenharmony_ci 470f66f451Sopenharmony_cistruct sockaddr_ll src_pk, dst_pk; 480f66f451Sopenharmony_cistruct in_addr src_addr, dest_addr; 490f66f451Sopenharmony_ciextern void *mempcpy(void *dest, const void *src, size_t n); 500f66f451Sopenharmony_ci 510f66f451Sopenharmony_ci// Gets information of INTERFACE and updates IFINDEX, MAC and IP. 520f66f451Sopenharmony_cistatic void get_interface(char *interface, int *ifindex, uint32_t *oip, 530f66f451Sopenharmony_ci uint8_t *mac) 540f66f451Sopenharmony_ci{ 550f66f451Sopenharmony_ci struct ifreq req; 560f66f451Sopenharmony_ci struct sockaddr_in *ip; 570f66f451Sopenharmony_ci int fd = xsocket(AF_INET, SOCK_RAW, IPPROTO_RAW); 580f66f451Sopenharmony_ci 590f66f451Sopenharmony_ci req.ifr_addr.sa_family = AF_INET; 600f66f451Sopenharmony_ci xstrncpy(req.ifr_name, interface, IFNAMSIZ); 610f66f451Sopenharmony_ci req.ifr_name[IFNAMSIZ-1] = '\0'; 620f66f451Sopenharmony_ci 630f66f451Sopenharmony_ci xioctl(fd, SIOCGIFFLAGS, &req); 640f66f451Sopenharmony_ci if (!(req.ifr_flags & IFF_UP)) return; 650f66f451Sopenharmony_ci 660f66f451Sopenharmony_ci if (oip) { 670f66f451Sopenharmony_ci xioctl(fd, SIOCGIFADDR, &req); 680f66f451Sopenharmony_ci ip = (struct sockaddr_in*) &req.ifr_addr; 690f66f451Sopenharmony_ci *oip = ntohl(ip->sin_addr.s_addr); 700f66f451Sopenharmony_ci } 710f66f451Sopenharmony_ci if (ifindex) { 720f66f451Sopenharmony_ci xioctl(fd, SIOCGIFINDEX, &req); 730f66f451Sopenharmony_ci *ifindex = req.ifr_ifindex; 740f66f451Sopenharmony_ci } 750f66f451Sopenharmony_ci if (mac) { 760f66f451Sopenharmony_ci xioctl(fd, SIOCGIFHWADDR, &req); 770f66f451Sopenharmony_ci memcpy(mac, req.ifr_hwaddr.sa_data, 6); 780f66f451Sopenharmony_ci } 790f66f451Sopenharmony_ci xclose(fd); 800f66f451Sopenharmony_ci} 810f66f451Sopenharmony_ci 820f66f451Sopenharmony_ci// SIGINT handler, Print Number of Packets send or receive details. 830f66f451Sopenharmony_cistatic void done(int sig) 840f66f451Sopenharmony_ci{ 850f66f451Sopenharmony_ci if (!(toys.optflags & FLAG_q)) { 860f66f451Sopenharmony_ci xprintf("Sent %u probe(s) (%u broadcast(s))\n", TT.sent_nr, TT.brd_sent); 870f66f451Sopenharmony_ci xprintf("Received %u repl%s (%u request(s), %u broadcast(s))\n", 880f66f451Sopenharmony_ci TT.rcvd_nr, TT.rcvd_nr == 1 ? "y":"ies", TT.rcvd_req, TT.brd_rcv); 890f66f451Sopenharmony_ci } 900f66f451Sopenharmony_ci if (toys.optflags & FLAG_D) exit(!!TT.rcvd_nr); 910f66f451Sopenharmony_ci //In -U mode, No reply is expected. 920f66f451Sopenharmony_ci if (toys.optflags & FLAG_U) exit(EXIT_SUCCESS); 930f66f451Sopenharmony_ci exit(!TT.rcvd_nr); 940f66f451Sopenharmony_ci} 950f66f451Sopenharmony_ci 960f66f451Sopenharmony_ci// Create and Send Packet 970f66f451Sopenharmony_cistatic void send_packet() 980f66f451Sopenharmony_ci{ 990f66f451Sopenharmony_ci int ret; 1000f66f451Sopenharmony_ci unsigned char sbuf[256] = {0,}; 1010f66f451Sopenharmony_ci struct arphdr *arp_h = (struct arphdr *) sbuf; 1020f66f451Sopenharmony_ci unsigned char *ptr = (unsigned char *)(arp_h + 1); 1030f66f451Sopenharmony_ci 1040f66f451Sopenharmony_ci arp_h->ar_hrd = htons(ARPHRD_ETHER); 1050f66f451Sopenharmony_ci arp_h->ar_pro = htons(ETH_P_IP); 1060f66f451Sopenharmony_ci arp_h->ar_hln = src_pk.sll_halen; 1070f66f451Sopenharmony_ci arp_h->ar_pln = 4; 1080f66f451Sopenharmony_ci arp_h->ar_op = (toys.optflags & FLAG_A) ? htons(ARPOP_REPLY) 1090f66f451Sopenharmony_ci : htons(ARPOP_REQUEST); 1100f66f451Sopenharmony_ci 1110f66f451Sopenharmony_ci ptr = mempcpy(ptr, &src_pk.sll_addr, src_pk.sll_halen); 1120f66f451Sopenharmony_ci ptr = mempcpy(ptr, &src_addr, 4); 1130f66f451Sopenharmony_ci ptr = mempcpy(ptr, 1140f66f451Sopenharmony_ci (toys.optflags & FLAG_A) ? &src_pk.sll_addr : &dst_pk.sll_addr, 1150f66f451Sopenharmony_ci src_pk.sll_halen); 1160f66f451Sopenharmony_ci ptr = mempcpy(ptr, &dest_addr, 4); 1170f66f451Sopenharmony_ci 1180f66f451Sopenharmony_ci ret = sendto(TT.sockfd, sbuf, ptr - sbuf, 0, 1190f66f451Sopenharmony_ci (struct sockaddr *)&dst_pk, sizeof(dst_pk)); 1200f66f451Sopenharmony_ci if (ret == ptr - sbuf) { 1210f66f451Sopenharmony_ci struct timeval tval; 1220f66f451Sopenharmony_ci 1230f66f451Sopenharmony_ci gettimeofday(&tval, NULL); 1240f66f451Sopenharmony_ci TT.sent_at = tval.tv_sec * 1000000ULL + tval.tv_usec; 1250f66f451Sopenharmony_ci TT.sent_nr++; 1260f66f451Sopenharmony_ci if (!TT.unicast_flag) TT.brd_sent++; 1270f66f451Sopenharmony_ci } 1280f66f451Sopenharmony_ci} 1290f66f451Sopenharmony_ci 1300f66f451Sopenharmony_ci// Receive Packet and filter with valid checks. 1310f66f451Sopenharmony_cistatic void recv_from(struct sockaddr_ll *from, int *recv_len) 1320f66f451Sopenharmony_ci{ 1330f66f451Sopenharmony_ci struct in_addr s_ip, d_ip; 1340f66f451Sopenharmony_ci struct arphdr *arp_hdr = (struct arphdr *)toybuf; 1350f66f451Sopenharmony_ci unsigned char *p = (unsigned char *)(arp_hdr + 1); 1360f66f451Sopenharmony_ci 1370f66f451Sopenharmony_ci if (arp_hdr->ar_op != htons(ARPOP_REQUEST) && 1380f66f451Sopenharmony_ci arp_hdr->ar_op != htons(ARPOP_REPLY)) return; 1390f66f451Sopenharmony_ci 1400f66f451Sopenharmony_ci if (from->sll_pkttype != PACKET_HOST && from->sll_pkttype != PACKET_BROADCAST 1410f66f451Sopenharmony_ci && from->sll_pkttype != PACKET_MULTICAST) return; 1420f66f451Sopenharmony_ci 1430f66f451Sopenharmony_ci if (arp_hdr->ar_pro != htons(ETH_P_IP) || (arp_hdr->ar_pln != 4) 1440f66f451Sopenharmony_ci || (arp_hdr->ar_hln != src_pk.sll_halen) 1450f66f451Sopenharmony_ci || (*recv_len < (int)(sizeof(*arp_hdr) + 2 * (4 + arp_hdr->ar_hln)))) 1460f66f451Sopenharmony_ci return; 1470f66f451Sopenharmony_ci 1480f66f451Sopenharmony_ci memcpy(&s_ip.s_addr, p + arp_hdr->ar_hln, 4); 1490f66f451Sopenharmony_ci memcpy(&d_ip.s_addr, p + arp_hdr->ar_hln + 4 + arp_hdr->ar_hln, 4); 1500f66f451Sopenharmony_ci 1510f66f451Sopenharmony_ci if (dest_addr.s_addr != s_ip.s_addr) return; 1520f66f451Sopenharmony_ci if (toys.optflags & FLAG_D) { 1530f66f451Sopenharmony_ci if (src_addr.s_addr && src_addr.s_addr != d_ip.s_addr) return; 1540f66f451Sopenharmony_ci if (!memcmp(p, &src_pk.sll_addr, src_pk.sll_halen)) return; 1550f66f451Sopenharmony_ci } else if (src_addr.s_addr != d_ip.s_addr ) return; 1560f66f451Sopenharmony_ci 1570f66f451Sopenharmony_ci if (!(toys.optflags & FLAG_q)) { 1580f66f451Sopenharmony_ci printf("%scast re%s from %s [%s]", 1590f66f451Sopenharmony_ci from->sll_pkttype == PACKET_HOST ? "Uni" : "Broad", 1600f66f451Sopenharmony_ci arp_hdr->ar_op == htons(ARPOP_REPLY) ? "ply" : "quest", 1610f66f451Sopenharmony_ci inet_ntoa(s_ip), ether_ntoa((struct ether_addr *) p)); 1620f66f451Sopenharmony_ci if (TT.sent_at) { 1630f66f451Sopenharmony_ci unsigned delta; 1640f66f451Sopenharmony_ci struct timeval tval; 1650f66f451Sopenharmony_ci 1660f66f451Sopenharmony_ci gettimeofday(&tval, NULL); 1670f66f451Sopenharmony_ci delta = (tval.tv_sec * 1000000ULL + (tval.tv_usec)) - TT.sent_at; 1680f66f451Sopenharmony_ci xprintf(" %u.%03ums\n", delta / 1000, delta % 1000); 1690f66f451Sopenharmony_ci } 1700f66f451Sopenharmony_ci } 1710f66f451Sopenharmony_ci TT.rcvd_nr++; 1720f66f451Sopenharmony_ci if (from->sll_pkttype != PACKET_HOST) TT.brd_rcv++; 1730f66f451Sopenharmony_ci if (arp_hdr->ar_op == htons(ARPOP_REQUEST)) TT.rcvd_req++; 1740f66f451Sopenharmony_ci if (toys.optflags & FLAG_f) done(0); 1750f66f451Sopenharmony_ci if (!(toys.optflags & FLAG_b)) { 1760f66f451Sopenharmony_ci memcpy(dst_pk.sll_addr, p, src_pk.sll_halen); 1770f66f451Sopenharmony_ci TT.unicast_flag = 1; 1780f66f451Sopenharmony_ci } 1790f66f451Sopenharmony_ci} 1800f66f451Sopenharmony_ci 1810f66f451Sopenharmony_ci// Alarm signal Handle, send packets in one second interval. 1820f66f451Sopenharmony_cistatic void send_signal(int sig) 1830f66f451Sopenharmony_ci{ 1840f66f451Sopenharmony_ci struct timeval start; 1850f66f451Sopenharmony_ci 1860f66f451Sopenharmony_ci gettimeofday(&start, NULL); 1870f66f451Sopenharmony_ci if (!TT.start) 1880f66f451Sopenharmony_ci TT.end = TT.start = start.tv_sec * 1000 + start.tv_usec / 1000; 1890f66f451Sopenharmony_ci else TT.end = start.tv_sec*1000 + start.tv_usec / 1000; 1900f66f451Sopenharmony_ci if (toys.optflags & FLAG_c) { 1910f66f451Sopenharmony_ci if (!TT.count) done(0); 1920f66f451Sopenharmony_ci TT.count--; 1930f66f451Sopenharmony_ci } 1940f66f451Sopenharmony_ci if ((toys.optflags & FLAG_w) && ((TT.end - TT.start) > 1950f66f451Sopenharmony_ci ((TT.time_out)*1000))) done(0); 1960f66f451Sopenharmony_ci send_packet(); 1970f66f451Sopenharmony_ci alarm(1); 1980f66f451Sopenharmony_ci} 1990f66f451Sopenharmony_ci 2000f66f451Sopenharmony_civoid arping_main(void) 2010f66f451Sopenharmony_ci{ 2020f66f451Sopenharmony_ci struct ifreq ifr; 2030f66f451Sopenharmony_ci struct sockaddr_ll from; 2040f66f451Sopenharmony_ci socklen_t len; 2050f66f451Sopenharmony_ci int if_index, recv_len; 2060f66f451Sopenharmony_ci 2070f66f451Sopenharmony_ci if (!(toys.optflags & FLAG_I)) TT.iface = "eth0"; 2080f66f451Sopenharmony_ci TT.sockfd = xsocket(AF_PACKET, SOCK_DGRAM, 0); 2090f66f451Sopenharmony_ci 2100f66f451Sopenharmony_ci memset(&ifr, 0, sizeof(ifr)); 2110f66f451Sopenharmony_ci xstrncpy(ifr.ifr_name, TT.iface, IFNAMSIZ); 2120f66f451Sopenharmony_ci get_interface(TT.iface, &if_index, NULL, NULL); 2130f66f451Sopenharmony_ci src_pk.sll_ifindex = if_index; 2140f66f451Sopenharmony_ci 2150f66f451Sopenharmony_ci xioctl(TT.sockfd, SIOCGIFFLAGS, (char*)&ifr); 2160f66f451Sopenharmony_ci if (!(ifr.ifr_flags & IFF_UP) && !(toys.optflags & FLAG_q)) 2170f66f451Sopenharmony_ci error_exit("Interface \"%s\" is down", TT.iface); 2180f66f451Sopenharmony_ci if ((ifr.ifr_flags & (IFF_NOARP | IFF_LOOPBACK)) 2190f66f451Sopenharmony_ci && !(toys.optflags & FLAG_q)) { 2200f66f451Sopenharmony_ci xprintf("Interface \"%s\" is not ARPable\n", TT.iface); 2210f66f451Sopenharmony_ci toys.exitval = (toys.optflags & FLAG_D) ? 0 : 2; 2220f66f451Sopenharmony_ci return; 2230f66f451Sopenharmony_ci } 2240f66f451Sopenharmony_ci if (!inet_aton(*toys.optargs, &dest_addr)) { 2250f66f451Sopenharmony_ci struct hostent *hp = gethostbyname2(*toys.optargs, AF_INET); 2260f66f451Sopenharmony_ci 2270f66f451Sopenharmony_ci if (!hp) perror_exit("bad address '%s'", *toys.optargs); 2280f66f451Sopenharmony_ci memcpy(&dest_addr, hp->h_addr, 4); 2290f66f451Sopenharmony_ci } 2300f66f451Sopenharmony_ci if ((toys.optflags & FLAG_s) && !(inet_aton(TT.src_ip, &src_addr))) 2310f66f451Sopenharmony_ci perror_exit("invalid source address '%s'",TT.src_ip); 2320f66f451Sopenharmony_ci if (!(toys.optflags & FLAG_D) && (toys.optflags & FLAG_U) 2330f66f451Sopenharmony_ci && !src_addr.s_addr) src_addr = dest_addr; 2340f66f451Sopenharmony_ci if (!(toys.optflags & FLAG_D) || src_addr.s_addr) { 2350f66f451Sopenharmony_ci struct sockaddr_in saddr; 2360f66f451Sopenharmony_ci int p_fd = xsocket(AF_INET, SOCK_DGRAM, 0); 2370f66f451Sopenharmony_ci 2380f66f451Sopenharmony_ci if (setsockopt(p_fd, SOL_SOCKET, SO_BINDTODEVICE, TT.iface, 2390f66f451Sopenharmony_ci strlen(TT.iface))) perror_exit("setsockopt"); 2400f66f451Sopenharmony_ci 2410f66f451Sopenharmony_ci memset(&saddr, 0, sizeof(saddr)); 2420f66f451Sopenharmony_ci saddr.sin_family = AF_INET; 2430f66f451Sopenharmony_ci if (src_addr.s_addr) { 2440f66f451Sopenharmony_ci saddr.sin_addr = src_addr; 2450f66f451Sopenharmony_ci xbind(p_fd, (struct sockaddr*)&saddr, sizeof(saddr)); 2460f66f451Sopenharmony_ci } else { 2470f66f451Sopenharmony_ci uint32_t oip; 2480f66f451Sopenharmony_ci 2490f66f451Sopenharmony_ci saddr.sin_port = htons(1025); 2500f66f451Sopenharmony_ci saddr.sin_addr = dest_addr; 2510f66f451Sopenharmony_ci xconnect(p_fd, (struct sockaddr *) &saddr, sizeof(saddr)); 2520f66f451Sopenharmony_ci get_interface(TT.iface, NULL, &oip, NULL); 2530f66f451Sopenharmony_ci src_addr.s_addr = htonl(oip); 2540f66f451Sopenharmony_ci } 2550f66f451Sopenharmony_ci xclose(p_fd); 2560f66f451Sopenharmony_ci } 2570f66f451Sopenharmony_ci 2580f66f451Sopenharmony_ci src_pk.sll_family = AF_PACKET; 2590f66f451Sopenharmony_ci src_pk.sll_protocol = htons(ETH_P_ARP); 2600f66f451Sopenharmony_ci xbind(TT.sockfd, (struct sockaddr *)&src_pk, sizeof(src_pk)); 2610f66f451Sopenharmony_ci 2620f66f451Sopenharmony_ci socklen_t alen = sizeof(src_pk); 2630f66f451Sopenharmony_ci getsockname(TT.sockfd, (struct sockaddr *)&src_pk, &alen); 2640f66f451Sopenharmony_ci if (!src_pk.sll_halen) { 2650f66f451Sopenharmony_ci perror_msg("src is not arpable"); 2660f66f451Sopenharmony_ci toys.exitval = (toys.optflags & FLAG_D) ? 0 : 2; 2670f66f451Sopenharmony_ci return; 2680f66f451Sopenharmony_ci } 2690f66f451Sopenharmony_ci if (!(toys.optflags & FLAG_q)) { 2700f66f451Sopenharmony_ci xprintf("ARPING to %s", inet_ntoa(dest_addr)); 2710f66f451Sopenharmony_ci xprintf(" from %s via %s\n", inet_ntoa(src_addr), TT.iface); 2720f66f451Sopenharmony_ci } 2730f66f451Sopenharmony_ci 2740f66f451Sopenharmony_ci dst_pk = src_pk; 2750f66f451Sopenharmony_ci //First packet always broadcasts. 2760f66f451Sopenharmony_ci memset(dst_pk.sll_addr, -1, dst_pk.sll_halen); 2770f66f451Sopenharmony_ci signal(SIGINT, done); 2780f66f451Sopenharmony_ci signal(SIGALRM, send_signal); 2790f66f451Sopenharmony_ci 2800f66f451Sopenharmony_ci send_signal(0); // Send first Broadcast message. 2810f66f451Sopenharmony_ci while (1) { 2820f66f451Sopenharmony_ci len = sizeof(from); 2830f66f451Sopenharmony_ci recv_len = recvfrom(TT.sockfd, toybuf, 4096, 0, 2840f66f451Sopenharmony_ci (struct sockaddr *)&from, &len); 2850f66f451Sopenharmony_ci if (recv_len < 0) continue; 2860f66f451Sopenharmony_ci recv_from(&from, &recv_len); 2870f66f451Sopenharmony_ci } 2880f66f451Sopenharmony_ci} 289