arping: change a few message strings to be closer to iputils arping
[oweals/busybox.git] / networking / arping.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * Licensed under GPLv2 or later, see file LICENSE in this source tree.
4  *
5  * Author: Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
6  * Busybox port: Nick Fedchik <nick@fedchik.org.ua>
7  */
8 //config:config ARPING
9 //config:       bool "arping (9.3 kb)"
10 //config:       default y
11 //config:       select PLATFORM_LINUX
12 //config:       help
13 //config:       Ping hosts by ARP packets.
14
15 //applet:IF_ARPING(APPLET(arping, BB_DIR_USR_SBIN, BB_SUID_DROP))
16
17 //kbuild:lib-$(CONFIG_ARPING) += arping.o
18
19 //usage:#define arping_trivial_usage
20 //usage:       "[-fqbDUA] [-c CNT] [-w TIMEOUT] [-I IFACE] [-s SRC_IP] DST_IP"
21 //usage:#define arping_full_usage "\n\n"
22 //usage:       "Send ARP requests/replies\n"
23 //usage:     "\n        -f              Quit on first ARP reply"
24 //usage:     "\n        -q              Quiet"
25 //usage:     "\n        -b              Keep broadcasting, don't go unicast"
26 //usage:     "\n        -D              Exit with 1 if DST_IP replies"
27 //usage:     "\n        -U              Unsolicited ARP mode, update your neighbors"
28 //usage:     "\n        -A              ARP answer mode, update your neighbors"
29 //usage:     "\n        -c N            Stop after sending N ARP requests"
30 //usage:     "\n        -w TIMEOUT      Seconds to wait for ARP reply"
31 //usage:     "\n        -I IFACE        Interface to use (default eth0)"
32 //usage:     "\n        -s SRC_IP       Sender IP address"
33 //usage:     "\n        DST_IP          Target IP address"
34
35 #include <arpa/inet.h>
36 #include <net/if.h>
37 #include <netinet/ether.h>
38 #include <netpacket/packet.h>
39
40 #include "libbb.h"
41 #include "common_bufsiz.h"
42
43 /* We don't expect to see 1000+ seconds delay, unsigned is enough */
44 #define MONOTONIC_US() ((unsigned)monotonic_us())
45
46 enum {
47         UNSOLICITED   = 1 << 0,
48         DAD           = 1 << 1,
49         ADVERT        = 1 << 2,
50         QUIET         = 1 << 3,
51         QUIT_ON_REPLY = 1 << 4,
52         BCAST_ONLY    = 1 << 5,
53         UNICASTING    = 1 << 6,
54         TIMEOUT       = 1 << 7,
55 };
56 #define GETOPT32(str_timeout, device, source) \
57         getopt32(argv, "^" \
58                 "UDAqfbc:+w:I:s:" \
59                 /* Dad also sets quit_on_reply, */ \
60                 /* Advert also sets unsolicited: */ \
61                 "\0" "=1:Df:AU", \
62                 &count, &str_timeout, &device, &source \
63         );
64
65 struct globals {
66         struct in_addr src;
67         struct in_addr dst;
68         struct sockaddr_ll me;
69         struct sockaddr_ll he;
70         int sock_fd;
71
72         int count; // = -1;
73         unsigned last;
74         unsigned timeout_us;
75         unsigned start;
76
77         unsigned sent;
78         unsigned brd_sent;
79         unsigned received;
80         unsigned brd_recv;
81         unsigned req_recv;
82 } FIX_ALIASING;
83 #define G (*(struct globals*)bb_common_bufsiz1)
84 #define src        (G.src       )
85 #define dst        (G.dst       )
86 #define me         (G.me        )
87 #define he         (G.he        )
88 #define sock_fd    (G.sock_fd   )
89 #define count      (G.count     )
90 #define last       (G.last      )
91 #define timeout_us (G.timeout_us)
92 #define start      (G.start     )
93 #define sent       (G.sent      )
94 #define brd_sent   (G.brd_sent  )
95 #define received   (G.received  )
96 #define brd_recv   (G.brd_recv  )
97 #define req_recv   (G.req_recv  )
98 #define INIT_G() do { \
99         setup_common_bufsiz(); \
100         count = -1; \
101 } while (0)
102
103 static int send_pack(struct in_addr *src_addr,
104                         struct in_addr *dst_addr,
105                         struct sockaddr_ll *ME,
106                         struct sockaddr_ll *HE)
107 {
108         int err;
109         unsigned char buf[256];
110         struct arphdr *ah = (struct arphdr *) buf;
111         unsigned char *p;
112
113         ah->ar_hrd = htons(ARPHRD_ETHER);
114         ah->ar_pro = htons(ETH_P_IP);
115         ah->ar_hln = ME->sll_halen;
116         ah->ar_pln = 4;
117         ah->ar_op = option_mask32 & ADVERT ? htons(ARPOP_REPLY) : htons(ARPOP_REQUEST);
118
119         p = (unsigned char *) (ah + 1);
120         p = mempcpy(p, &ME->sll_addr, ah->ar_hln);
121         p = mempcpy(p, src_addr, 4);
122
123         if (option_mask32 & ADVERT)
124                 p = mempcpy(p, &ME->sll_addr, ah->ar_hln);
125         else
126                 p = mempcpy(p, &HE->sll_addr, ah->ar_hln);
127
128         p = mempcpy(p, dst_addr, 4);
129
130         err = sendto(sock_fd, buf, p - buf, 0, (struct sockaddr *) HE, sizeof(*HE));
131         if (err == p - buf) {
132                 last = MONOTONIC_US();
133                 sent++;
134                 if (!(option_mask32 & UNICASTING))
135                         brd_sent++;
136         }
137         return err;
138 }
139
140 static void finish(void) NORETURN;
141 static void finish(void)
142 {
143         if (!(option_mask32 & QUIET)) {
144                 printf("Sent %u probe(s) (%u broadcast(s))\n"
145                         "Received %u response(s)"
146                         " (%u request(s), %u broadcast(s))\n",
147                         sent, brd_sent,
148                         received,
149                         req_recv, brd_recv);
150         }
151         if (option_mask32 & DAD)
152                 exit(!!received);
153         if (option_mask32 & UNSOLICITED)
154                 exit(EXIT_SUCCESS);
155         exit(!received);
156 }
157
158 static void catcher(void)
159 {
160         unsigned now;
161
162         now = MONOTONIC_US();
163         if (start == 0)
164                 start = now;
165
166         if (count == 0 || (timeout_us && (now - start) > timeout_us))
167                 finish();
168
169         /* count < 0 means "infinite count" */
170         if (count > 0)
171                 count--;
172
173         if (last == 0 || (now - last) > 500000) {
174                 send_pack(&src, &dst, &me, &he);
175                 if (count == 0 && (option_mask32 & UNSOLICITED))
176                         finish();
177         }
178         alarm(1);
179 }
180
181 static void recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM)
182 {
183         struct arphdr *ah = (struct arphdr *) buf;
184         unsigned char *p = (unsigned char *) (ah + 1);
185         struct in_addr src_ip, dst_ip;
186         /* moves below assume in_addr is 4 bytes big, ensure that */
187         struct BUG_in_addr_must_be_4 {
188                 char BUG_in_addr_must_be_4[
189                         sizeof(struct in_addr) == 4 ? 1 : -1
190                 ];
191                 char BUG_s_addr_must_be_4[
192                         sizeof(src_ip.s_addr) == 4 ? 1 : -1
193                 ];
194         };
195
196         /* Filter out wild packets */
197         if (FROM->sll_pkttype != PACKET_HOST
198          && FROM->sll_pkttype != PACKET_BROADCAST
199          && FROM->sll_pkttype != PACKET_MULTICAST)
200                 return;
201
202         /* Only these types are recognized */
203         if (ah->ar_op != htons(ARPOP_REQUEST) && ah->ar_op != htons(ARPOP_REPLY))
204                 return;
205
206         /* ARPHRD check and this darned FDDI hack here :-( */
207         if (ah->ar_hrd != htons(FROM->sll_hatype)
208          && (FROM->sll_hatype != ARPHRD_FDDI || ah->ar_hrd != htons(ARPHRD_ETHER)))
209                 return;
210
211         /* Protocol must be IP. */
212         if (ah->ar_pro != htons(ETH_P_IP)
213          || (ah->ar_pln != 4)
214          || (ah->ar_hln != me.sll_halen)
215          || (len < (int)(sizeof(*ah) + 2 * (4 + ah->ar_hln))))
216                 return;
217
218         move_from_unaligned32(src_ip.s_addr, p + ah->ar_hln);
219         move_from_unaligned32(dst_ip.s_addr, p + ah->ar_hln + 4 + ah->ar_hln);
220
221         if (dst.s_addr != src_ip.s_addr)
222                 return;
223         if (!(option_mask32 & DAD)) {
224                 if ((src.s_addr != dst_ip.s_addr)
225                  || (memcmp(p + ah->ar_hln + 4, &me.sll_addr, ah->ar_hln)))
226                         return;
227         } else {
228                 /* DAD packet was:
229                    src_ip = 0 (or some src)
230                    src_hw = ME
231                    dst_ip = tested address
232                    dst_hw = <unspec>
233
234                    We fail, if receive request/reply with:
235                    src_ip = tested_address
236                    src_hw != ME
237                    if src_ip in request was not zero, check
238                    also that it matches to dst_ip, otherwise
239                    dst_ip/dst_hw do not matter.
240                  */
241                 if ((memcmp(p, &me.sll_addr, me.sll_halen) == 0)
242                  || (src.s_addr && src.s_addr != dst_ip.s_addr))
243                         return;
244         }
245         if (!(option_mask32 & QUIET)) {
246                 int s_printed = 0;
247
248 //TODO: arping from iputils-s20160308 print upprcase hex in MAC, follow them?
249                 printf("%scast re%s from %s [%02x:%02x:%02x:%02x:%02x:%02x]",
250                         FROM->sll_pkttype == PACKET_HOST ? "Uni" : "Broad",
251                         ah->ar_op == htons(ARPOP_REPLY) ? "ply" : "quest",
252                         inet_ntoa(src_ip),
253                         p[0], p[1], p[2], p[3], p[4], p[5]
254                 );
255                 if (dst_ip.s_addr != src.s_addr) {
256                         printf("for %s", inet_ntoa(dst_ip));
257                         s_printed = 1;
258                 }
259                 if (memcmp(p + ah->ar_hln + 4, me.sll_addr, ah->ar_hln)) {
260                         unsigned char *pp = p + ah->ar_hln + 4;
261                         if (!s_printed)
262                                 printf(" for");
263                         printf(" [%02x:%02x:%02x:%02x:%02x:%02x]",
264                                 pp[0], pp[1], pp[2], pp[3], pp[4], pp[5]
265                         );
266                 }
267
268                 if (last) {
269                         unsigned diff = MONOTONIC_US() - last;
270                         printf(" %u.%03ums\n", diff / 1000, diff % 1000);
271                 } else {
272                         puts(" UNSOLICITED?");
273                 }
274                 fflush_all();
275         }
276         received++;
277         if (FROM->sll_pkttype != PACKET_HOST)
278                 brd_recv++;
279         if (ah->ar_op == htons(ARPOP_REQUEST))
280                 req_recv++;
281         if (option_mask32 & QUIT_ON_REPLY)
282                 finish();
283         if (!(option_mask32 & BCAST_ONLY)) {
284                 memcpy(he.sll_addr, p, me.sll_halen);
285                 option_mask32 |= UNICASTING;
286         }
287 }
288
289 int arping_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
290 int arping_main(int argc UNUSED_PARAM, char **argv)
291 {
292         const char *device = "eth0";
293         char *source = NULL;
294         char *target;
295         unsigned char *packet;
296         char *err_str;
297
298         INIT_G();
299
300         sock_fd = xsocket(AF_PACKET, SOCK_DGRAM, 0);
301
302         // If you ever change BB_SUID_DROP to BB_SUID_REQUIRE,
303         // drop suid root privileges here:
304         //xsetuid(getuid());
305
306         {
307                 unsigned opt;
308                 char *str_timeout;
309
310                 opt = GETOPT32(str_timeout, device, source);
311                 if (opt & TIMEOUT)
312                         timeout_us = xatou_range(str_timeout, 0, INT_MAX/2000000) * 1000000 + 500000;
313         }
314
315         target = argv[optind];
316         err_str = xasprintf("interface %s %%s", device);
317         xfunc_error_retval = 2;
318
319         {
320                 struct ifreq ifr;
321
322                 memset(&ifr, 0, sizeof(ifr));
323                 strncpy_IFNAMSIZ(ifr.ifr_name, device);
324                 /* We use ifr.ifr_name in error msg so that problem
325                  * with truncated name will be visible */
326                 ioctl_or_perror_and_die(sock_fd, SIOCGIFINDEX, &ifr, err_str, "not found");
327                 me.sll_ifindex = ifr.ifr_ifindex;
328
329                 xioctl(sock_fd, SIOCGIFFLAGS, (char *) &ifr);
330
331                 if (!(ifr.ifr_flags & IFF_UP)) {
332                         bb_error_msg_and_die(err_str, "is down");
333                 }
334                 if (ifr.ifr_flags & (IFF_NOARP | IFF_LOOPBACK)) {
335                         bb_error_msg(err_str, "is not ARPable");
336                         BUILD_BUG_ON(DAD != 2);
337                         /* exit 0 if DAD, else exit 2 */
338                         return (~option_mask32 & DAD);
339                 }
340         }
341
342         /* if (!inet_aton(target, &dst)) - not needed */ {
343                 len_and_sockaddr *lsa;
344                 lsa = xhost_and_af2sockaddr(target, 0, AF_INET);
345                 dst = lsa->u.sin.sin_addr;
346                 if (ENABLE_FEATURE_CLEAN_UP)
347                         free(lsa);
348         }
349
350         if (source && !inet_aton(source, &src)) {
351                 bb_error_msg_and_die("invalid source address %s", source);
352         }
353
354         if ((option_mask32 & (DAD|UNSOLICITED)) == UNSOLICITED && src.s_addr == 0)
355                 src = dst;
356
357         if (!(option_mask32 & DAD) || src.s_addr) {
358                 struct sockaddr_in saddr;
359                 int probe_fd = xsocket(AF_INET, SOCK_DGRAM, 0);
360
361                 setsockopt_bindtodevice(probe_fd, device);
362                 memset(&saddr, 0, sizeof(saddr));
363                 saddr.sin_family = AF_INET;
364                 if (src.s_addr) {
365                         /* Check that this is indeed our IP */
366                         saddr.sin_addr = src;
367                         xbind(probe_fd, (struct sockaddr *) &saddr, sizeof(saddr));
368                 } else { /* !(option_mask32 & DAD) case */
369                         /* Find IP address on this iface */
370                         socklen_t alen = sizeof(saddr);
371
372                         saddr.sin_port = htons(1025);
373                         saddr.sin_addr = dst;
374
375                         if (setsockopt_SOL_SOCKET_1(probe_fd, SO_DONTROUTE) != 0)
376                                 bb_perror_msg("setsockopt(%s)", "SO_DONTROUTE");
377                         xconnect(probe_fd, (struct sockaddr *) &saddr, sizeof(saddr));
378                         getsockname(probe_fd, (struct sockaddr *) &saddr, &alen);
379                         //never happens:
380                         //if (getsockname(probe_fd, (struct sockaddr *) &saddr, &alen) == -1)
381                         //      bb_perror_msg_and_die("getsockname");
382                         if (saddr.sin_family != AF_INET)
383                                 bb_error_msg_and_die("no IP address configured");
384                         src = saddr.sin_addr;
385                 }
386                 close(probe_fd);
387         }
388
389         me.sll_family = AF_PACKET;
390         //me.sll_ifindex = ifindex; - done before
391         me.sll_protocol = htons(ETH_P_ARP);
392         xbind(sock_fd, (struct sockaddr *) &me, sizeof(me));
393
394         {
395                 socklen_t alen = sizeof(me);
396                 getsockname(sock_fd, (struct sockaddr *) &me, &alen);
397                 //never happens:
398                 //if (getsockname(sock_fd, (struct sockaddr *) &me, &alen) == -1)
399                 //      bb_perror_msg_and_die("getsockname");
400         }
401         if (me.sll_halen == 0) {
402                 bb_error_msg(err_str, "is not ARPable (no ll address)");
403                 BUILD_BUG_ON(DAD != 2);
404                 /* exit 0 if DAD, else exit 2 */
405                 return (~option_mask32 & DAD);
406         }
407         he = me;
408         memset(he.sll_addr, -1, he.sll_halen);
409
410         if (!(option_mask32 & QUIET)) {
411                 /* inet_ntoa uses static storage, can't use in same printf */
412                 printf("ARPING %s", inet_ntoa(dst));
413                 printf(" from %s %s\n", inet_ntoa(src), device);
414         }
415
416         signal_SA_RESTART_empty_mask(SIGINT,  (void (*)(int))finish);
417         signal_SA_RESTART_empty_mask(SIGALRM, (void (*)(int))catcher);
418
419         catcher();
420
421         packet = xmalloc(4096);
422         while (1) {
423                 sigset_t sset, osset;
424                 struct sockaddr_ll from;
425                 socklen_t alen = sizeof(from);
426                 int cc;
427
428                 cc = recvfrom(sock_fd, packet, 4096, 0, (struct sockaddr *) &from, &alen);
429                 if (cc < 0) {
430                         bb_perror_msg("recvfrom");
431                         continue;
432                 }
433                 sigemptyset(&sset);
434                 sigaddset(&sset, SIGALRM);
435                 sigaddset(&sset, SIGINT);
436                 sigprocmask(SIG_BLOCK, &sset, &osset);
437                 recv_pack(packet, cc, &from);
438                 sigprocmask(SIG_SETMASK, &osset, NULL);
439         }
440 }