Home | History | Annotate | Download | only in pending
      1 /* arping - send ARP REQUEST to a neighbour host.
      2  *
      3  * Copyright 2013 Sandeep Sharma <sandeep.jack2756 (at) gmail.com>
      4  * Copyright 2013 Kyungwan Han <asura321 (at) gmail.com>
      5  *
      6  * No Standard.
      7 
      8 USE_ARPING(NEWTOY(arping, "<1>1s:I:w#<0c#<0AUDbqf[+AU][+Df]", TOYFLAG_USR|TOYFLAG_SBIN))
      9 
     10 config ARPING
     11   bool "arping"
     12   default n
     13   help
     14     usage: arping [-fqbDUA] [-c CNT] [-w TIMEOUT] [-I IFACE] [-s SRC_IP] DST_IP
     15 
     16     Send ARP requests/replies
     17 
     18     -f         Quit on first ARP reply
     19     -q         Quiet
     20     -b         Keep broadcasting, don't go unicast
     21     -D         Duplicated address detection mode
     22     -U         Unsolicited ARP mode, update your neighbors
     23     -A         ARP answer mode, update your neighbors
     24     -c N       Stop after sending N ARP requests
     25     -w TIMEOUT Time to wait for ARP reply, seconds
     26     -I IFACE   Interface to use (default eth0)
     27     -s SRC_IP  Sender IP address
     28     DST_IP     Target IP address
     29 */
     30 #define FOR_arping
     31 #include "toys.h"
     32 #include <netinet/ether.h>
     33 #include <netpacket/packet.h>
     34 
     35 GLOBALS(
     36     long count;
     37     unsigned long time_out;
     38     char *iface;
     39     char *src_ip;
     40 
     41     int sockfd;
     42     unsigned start;
     43     unsigned end;
     44     unsigned sent_at;
     45     unsigned sent_nr;
     46     unsigned rcvd_nr;
     47     unsigned brd_sent;
     48     unsigned rcvd_req;
     49     unsigned brd_rcv;
     50     unsigned unicast_flag;
     51 )
     52 
     53 struct sockaddr_ll src_pk, dst_pk;
     54 struct in_addr src_addr, dest_addr;
     55 extern void *mempcpy(void *dest, const void *src, size_t n);
     56 
     57 // Gets information of INTERFACE and updates IFINDEX, MAC and IP.
     58 static void get_interface(char *interface, int *ifindex, uint32_t *oip,
     59     uint8_t *mac)
     60 {
     61   struct ifreq req;
     62   struct sockaddr_in *ip;
     63   int fd = xsocket(AF_INET, SOCK_RAW, IPPROTO_RAW);
     64 
     65   req.ifr_addr.sa_family = AF_INET;
     66   xstrncpy(req.ifr_name, interface, IFNAMSIZ);
     67   req.ifr_name[IFNAMSIZ-1] = '\0';
     68 
     69   xioctl(fd, SIOCGIFFLAGS, &req);
     70   if (!(req.ifr_flags & IFF_UP)) return;
     71 
     72   if (oip) {
     73     xioctl(fd, SIOCGIFADDR, &req);
     74     ip = (struct sockaddr_in*) &req.ifr_addr;
     75     *oip = ntohl(ip->sin_addr.s_addr);
     76   }
     77   if (ifindex) {
     78     xioctl(fd, SIOCGIFINDEX, &req);
     79     *ifindex = req.ifr_ifindex;
     80   }
     81   if (mac) {
     82     xioctl(fd, SIOCGIFHWADDR, &req);
     83     memcpy(mac, req.ifr_hwaddr.sa_data, 6);
     84   }
     85   xclose(fd);
     86 }
     87 
     88 // SIGINT handler, Print Number of Packets send or receive details.
     89 static void done(int sig)
     90 {
     91   if (!(toys.optflags & FLAG_q)) {
     92     xprintf("Sent %u probe(s) (%u broadcast(s))\n", TT.sent_nr, TT.brd_sent);
     93     xprintf("Received %u repl%s (%u request(s), %u broadcast(s))\n",
     94         TT.rcvd_nr, TT.rcvd_nr == 1 ? "y":"ies", TT.rcvd_req, TT.brd_rcv);
     95   }
     96   if (toys.optflags & FLAG_D) exit(!!TT.rcvd_nr);
     97   //In -U mode, No reply is expected.
     98   if (toys.optflags & FLAG_U) exit(EXIT_SUCCESS);
     99   exit(!TT.rcvd_nr);
    100 }
    101 
    102 // Create and Send Packet
    103 static void send_packet()
    104 {
    105   int ret;
    106   unsigned char sbuf[256] = {0,};
    107   struct arphdr *arp_h = (struct arphdr *) sbuf;
    108   unsigned char *ptr = (unsigned char *)(arp_h + 1);
    109 
    110   arp_h->ar_hrd = htons(ARPHRD_ETHER);
    111   arp_h->ar_pro = htons(ETH_P_IP);
    112   arp_h->ar_hln = src_pk.sll_halen;
    113   arp_h->ar_pln = 4;
    114   arp_h->ar_op = (toys.optflags & FLAG_A) ? htons(ARPOP_REPLY)
    115     : htons(ARPOP_REQUEST);
    116 
    117   ptr = mempcpy(ptr, &src_pk.sll_addr, src_pk.sll_halen);
    118   ptr = mempcpy(ptr, &src_addr, 4);
    119   ptr = mempcpy(ptr,
    120                 (toys.optflags & FLAG_A) ? &src_pk.sll_addr : &dst_pk.sll_addr,
    121                 src_pk.sll_halen);
    122   ptr = mempcpy(ptr, &dest_addr, 4);
    123 
    124   ret = sendto(TT.sockfd, sbuf, ptr - sbuf, 0,
    125       (struct sockaddr *)&dst_pk, sizeof(dst_pk));
    126   if (ret == ptr - sbuf) {
    127     struct timeval tval;
    128 
    129     gettimeofday(&tval, NULL);
    130     TT.sent_at = tval.tv_sec * 1000000ULL + tval.tv_usec;
    131     TT.sent_nr++;
    132     if (!TT.unicast_flag) TT.brd_sent++;
    133   }
    134 }
    135 
    136 // Receive Packet and filter with valid checks.
    137 static void recv_from(struct sockaddr_ll *from, int *recv_len)
    138 {
    139   struct in_addr s_ip, d_ip;
    140   struct arphdr *arp_hdr = (struct arphdr *)toybuf;
    141   unsigned char *p = (unsigned char *)(arp_hdr + 1);
    142 
    143   if (arp_hdr->ar_op != htons(ARPOP_REQUEST) &&
    144       arp_hdr->ar_op != htons(ARPOP_REPLY)) return;
    145 
    146   if (from->sll_pkttype != PACKET_HOST && from->sll_pkttype != PACKET_BROADCAST
    147       && from->sll_pkttype != PACKET_MULTICAST) return;
    148 
    149   if (arp_hdr->ar_pro != htons(ETH_P_IP) || (arp_hdr->ar_pln != 4)
    150       || (arp_hdr->ar_hln != src_pk.sll_halen)
    151       || (*recv_len < (int)(sizeof(*arp_hdr) + 2 * (4 + arp_hdr->ar_hln))))
    152     return;
    153 
    154   memcpy(&s_ip.s_addr, p + arp_hdr->ar_hln, 4);
    155   memcpy(&d_ip.s_addr, p + arp_hdr->ar_hln + 4 + arp_hdr->ar_hln, 4);
    156 
    157   if (dest_addr.s_addr != s_ip.s_addr) return;
    158   if (toys.optflags & FLAG_D) {
    159     if (src_addr.s_addr && src_addr.s_addr != d_ip.s_addr) return;
    160     if (!memcmp(p, &src_pk.sll_addr, src_pk.sll_halen)) return;
    161   } else if (src_addr.s_addr != d_ip.s_addr ) return;
    162 
    163   if (!(toys.optflags & FLAG_q)) {
    164     printf("%scast re%s from %s [%s]",
    165         from->sll_pkttype == PACKET_HOST ? "Uni" : "Broad",
    166         arp_hdr->ar_op == htons(ARPOP_REPLY) ? "ply" : "quest",
    167         inet_ntoa(s_ip), ether_ntoa((struct ether_addr *) p));
    168     if (TT.sent_at) {
    169       unsigned delta;
    170       struct timeval tval;
    171 
    172       gettimeofday(&tval, NULL);
    173       delta = (tval.tv_sec * 1000000ULL + (tval.tv_usec)) - TT.sent_at;
    174       xprintf(" %u.%03ums\n", delta / 1000, delta % 1000);
    175       xflush();
    176     }
    177   }
    178   TT.rcvd_nr++;
    179   if (from->sll_pkttype != PACKET_HOST) TT.brd_rcv++;
    180   if (arp_hdr->ar_op == htons(ARPOP_REQUEST)) TT.rcvd_req++;
    181   if (toys.optflags & FLAG_f) done(0);
    182   if (!(toys.optflags & FLAG_b)) {
    183     memcpy(dst_pk.sll_addr, p, src_pk.sll_halen);
    184     TT.unicast_flag = 1;
    185   }
    186 }
    187 
    188 // Alarm signal Handle, send packets in one second interval.
    189 static void send_signal(int sig)
    190 {
    191   struct timeval start;
    192 
    193   gettimeofday(&start, NULL);
    194   if (!TT.start)
    195     TT.end = TT.start = start.tv_sec * 1000 + start.tv_usec / 1000;
    196   else TT.end = start.tv_sec*1000 + start.tv_usec / 1000;
    197   if (toys.optflags & FLAG_c) {
    198     if (!TT.count) done(0);
    199     TT.count--;
    200   }
    201   if ((toys.optflags & FLAG_w) && ((TT.end - TT.start) >
    202         ((TT.time_out)*1000))) done(0);
    203   send_packet();
    204   alarm(1);
    205 }
    206 
    207 void arping_main(void)
    208 {
    209   struct ifreq ifr;
    210   struct sockaddr_ll from;
    211   socklen_t len;
    212   int if_index, recv_len;
    213 
    214   if (!(toys.optflags & FLAG_I)) TT.iface = "eth0";
    215   TT.sockfd = xsocket(AF_PACKET, SOCK_DGRAM, 0);
    216 
    217   memset(&ifr, 0, sizeof(ifr));
    218   xstrncpy(ifr.ifr_name, TT.iface, IFNAMSIZ);
    219   get_interface(TT.iface, &if_index, NULL, NULL);
    220   src_pk.sll_ifindex = if_index;
    221 
    222   xioctl(TT.sockfd, SIOCGIFFLAGS, (char*)&ifr);
    223   if (!(ifr.ifr_flags & IFF_UP) && !(toys.optflags & FLAG_q))
    224     error_exit("Interface \"%s\" is down", TT.iface);
    225   if ((ifr.ifr_flags & (IFF_NOARP | IFF_LOOPBACK))
    226       && !(toys.optflags & FLAG_q)) {
    227     xprintf("Interface \"%s\" is not ARPable\n", TT.iface);
    228     toys.exitval = (toys.optflags & FLAG_D) ? 0 : 2;
    229     return;
    230   }
    231   if (!inet_aton(*toys.optargs, &dest_addr)) {
    232     struct hostent *hp = gethostbyname2(*toys.optargs, AF_INET);
    233 
    234     if (!hp) perror_exit("bad address '%s'", *toys.optargs);
    235     memcpy(&dest_addr, hp->h_addr, 4);
    236   }
    237   if ((toys.optflags & FLAG_s) && !(inet_aton(TT.src_ip, &src_addr)))
    238     perror_exit("invalid source address '%s'",TT.src_ip);
    239   if (!(toys.optflags & FLAG_D) && (toys.optflags & FLAG_U)
    240       && !src_addr.s_addr) src_addr = dest_addr;
    241   if (!(toys.optflags & FLAG_D) || src_addr.s_addr) {
    242     struct sockaddr_in saddr;
    243     int p_fd = xsocket(AF_INET, SOCK_DGRAM, 0);
    244 
    245     if (setsockopt(p_fd, SOL_SOCKET, SO_BINDTODEVICE, TT.iface,
    246           strlen(TT.iface))) perror_exit("setsockopt");
    247 
    248     memset(&saddr, 0, sizeof(saddr));
    249     saddr.sin_family = AF_INET;
    250     if (src_addr.s_addr) {
    251       saddr.sin_addr = src_addr;
    252       if (bind(p_fd, (struct sockaddr*)&saddr, sizeof(saddr)))
    253         perror_exit("bind");
    254     } else {
    255       uint32_t oip;
    256 
    257       saddr.sin_port = htons(1025);
    258       saddr.sin_addr = dest_addr;
    259       if (connect(p_fd, (struct sockaddr *) &saddr, sizeof(saddr)))
    260         perror_exit("cannot connect to remote host");
    261       get_interface(TT.iface, NULL, &oip, NULL);
    262       src_addr.s_addr = htonl(oip);
    263     }
    264     xclose(p_fd);
    265   }
    266 
    267   src_pk.sll_family = AF_PACKET;
    268   src_pk.sll_protocol = htons(ETH_P_ARP);
    269   if (bind(TT.sockfd, (struct sockaddr *)&src_pk, sizeof(src_pk)))
    270     perror_exit("bind");
    271 
    272   socklen_t alen = sizeof(src_pk);
    273   getsockname(TT.sockfd, (struct sockaddr *)&src_pk, &alen);
    274   if (!src_pk.sll_halen) {
    275     perror_msg("src is not arpable");
    276     toys.exitval = (toys.optflags & FLAG_D) ? 0 : 2;
    277     return;
    278   }
    279   if (!(toys.optflags & FLAG_q)) {
    280     xprintf("ARPING to %s", inet_ntoa(dest_addr));
    281     xprintf(" from %s via %s\n", inet_ntoa(src_addr), TT.iface);
    282   }
    283 
    284   dst_pk = src_pk;
    285   //First packet always broadcasts.
    286   memset(dst_pk.sll_addr, -1, dst_pk.sll_halen);
    287   signal(SIGINT, done);
    288   signal(SIGALRM, send_signal);
    289 
    290   send_signal(0); // Send first Broadcast message.
    291   while (1) {
    292     len = sizeof(from);
    293     recv_len = recvfrom(TT.sockfd, toybuf, 4096, 0,
    294         (struct sockaddr *)&from, &len);
    295     if (recv_len < 0) continue;
    296     recv_from(&from, &recv_len);
    297   }
    298 }
    299