a2c4c22472f598882eefb444d93459a11346e004
[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 static struct in_addr src;
22 static struct in_addr dst;
23 static struct sockaddr_ll me;
24 static struct sockaddr_ll he;
25 static unsigned last;
26
27 enum {
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
37 static int sock;
38 static unsigned count = UINT_MAX;
39 static unsigned timeout_us;
40 static unsigned sent;
41 static unsigned brd_sent;
42 static unsigned received;
43 static unsigned brd_recv;
44 static unsigned req_recv;
45
46 static 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
89 static void finish(void) ATTRIBUTE_NORETURN;
90 static 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
107 static 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
130 static 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
230 int arping_main(int argc, char **argv);
231 int 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 }