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