6f6b59cfba73be911be31bd9b4459ed1464d61a5
[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
9 #include <arpa/inet.h>
10 #include <net/if.h>
11 #include <netinet/ether.h>
12 #include <netpacket/packet.h>
13
14 #include "libbb.h"
15
16 /* We don't expect to see 1000+ seconds delay, unsigned is enough */
17 #define MONOTONIC_US() ((unsigned)monotonic_us())
18
19 enum {
20         DAD = 1,
21         UNSOLICITED = 2,
22         ADVERT = 4,
23         QUIET = 8,
24         QUIT_ON_REPLY = 16,
25         BCAST_ONLY = 32,
26         UNICASTING = 64
27 };
28
29 struct globals {
30         struct in_addr src;
31         struct in_addr dst;
32         struct sockaddr_ll me;
33         struct sockaddr_ll he;
34         int sock_fd;
35
36         int count; // = -1;
37         unsigned last;
38         unsigned timeout_us;
39         unsigned start;
40
41         unsigned sent;
42         unsigned brd_sent;
43         unsigned received;
44         unsigned brd_recv;
45         unsigned req_recv;
46 } FIX_ALIASING;
47 #define G (*(struct globals*)&bb_common_bufsiz1)
48 #define src        (G.src       )
49 #define dst        (G.dst       )
50 #define me         (G.me        )
51 #define he         (G.he        )
52 #define sock_fd    (G.sock_fd   )
53 #define count      (G.count     )
54 #define last       (G.last      )
55 #define timeout_us (G.timeout_us)
56 #define start      (G.start     )
57 #define sent       (G.sent      )
58 #define brd_sent   (G.brd_sent  )
59 #define received   (G.received  )
60 #define brd_recv   (G.brd_recv  )
61 #define req_recv   (G.req_recv  )
62 #define INIT_G() do { \
63         count = -1; \
64 } while (0)
65
66 // If GNUisms are not available...
67 //static void *mempcpy(void *_dst, const void *_src, int n)
68 //{
69 //      memcpy(_dst, _src, n);
70 //      return (char*)_dst + n;
71 //}
72
73 static int send_pack(struct in_addr *src_addr,
74                         struct in_addr *dst_addr, struct sockaddr_ll *ME,
75                         struct sockaddr_ll *HE)
76 {
77         int err;
78         unsigned char buf[256];
79         struct arphdr *ah = (struct arphdr *) buf;
80         unsigned char *p = (unsigned char *) (ah + 1);
81
82         ah->ar_hrd = htons(ARPHRD_ETHER);
83         ah->ar_pro = htons(ETH_P_IP);
84         ah->ar_hln = ME->sll_halen;
85         ah->ar_pln = 4;
86         ah->ar_op = option_mask32 & ADVERT ? htons(ARPOP_REPLY) : htons(ARPOP_REQUEST);
87
88         p = mempcpy(p, &ME->sll_addr, ah->ar_hln);
89         p = mempcpy(p, src_addr, 4);
90
91         if (option_mask32 & ADVERT)
92                 p = mempcpy(p, &ME->sll_addr, ah->ar_hln);
93         else
94                 p = mempcpy(p, &HE->sll_addr, ah->ar_hln);
95
96         p = mempcpy(p, dst_addr, 4);
97
98         err = sendto(sock_fd, buf, p - buf, 0, (struct sockaddr *) HE, sizeof(*HE));
99         if (err == p - buf) {
100                 last = MONOTONIC_US();
101                 sent++;
102                 if (!(option_mask32 & UNICASTING))
103                         brd_sent++;
104         }
105         return err;
106 }
107
108 static void finish(void) NORETURN;
109 static void finish(void)
110 {
111         if (!(option_mask32 & QUIET)) {
112                 printf("Sent %u probe(s) (%u broadcast(s))\n"
113                         "Received %u repl%s"
114                         " (%u request(s), %u broadcast(s))\n",
115                         sent, brd_sent,
116                         received, (received == 1) ? "ies" : "y",
117                         req_recv, brd_recv);
118         }
119         if (option_mask32 & DAD)
120                 exit(!!received);
121         if (option_mask32 & UNSOLICITED)
122                 exit(EXIT_SUCCESS);
123         exit(!received);
124 }
125
126 static void catcher(void)
127 {
128         unsigned now;
129
130         now = MONOTONIC_US();
131         if (start == 0)
132                 start = now;
133
134         if (count == 0 || (timeout_us && (now - start) > timeout_us))
135                 finish();
136
137         /* count < 0 means "infinite count" */
138         if (count > 0)
139                 count--;
140
141         if (last == 0 || (now - last) > 500000) {
142                 send_pack(&src, &dst, &me, &he);
143                 if (count == 0 && (option_mask32 & UNSOLICITED))
144                         finish();
145         }
146         alarm(1);
147 }
148
149 static bool recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM)
150 {
151         struct arphdr *ah = (struct arphdr *) buf;
152         unsigned char *p = (unsigned char *) (ah + 1);
153         struct in_addr src_ip, dst_ip;
154         /* moves below assume in_addr is 4 bytes big, ensure that */
155         struct BUG_in_addr_must_be_4 {
156                 char BUG_in_addr_must_be_4[
157                         sizeof(struct in_addr) == 4 ? 1 : -1
158                 ];
159                 char BUG_s_addr_must_be_4[
160                         sizeof(src_ip.s_addr) == 4 ? 1 : -1
161                 ];
162         };
163
164         /* Filter out wild packets */
165         if (FROM->sll_pkttype != PACKET_HOST
166          && FROM->sll_pkttype != PACKET_BROADCAST
167          && FROM->sll_pkttype != PACKET_MULTICAST)
168                 return false;
169
170         /* Only these types are recognized */
171         if (ah->ar_op != htons(ARPOP_REQUEST) && ah->ar_op != htons(ARPOP_REPLY))
172                 return false;
173
174         /* ARPHRD check and this darned FDDI hack here :-( */
175         if (ah->ar_hrd != htons(FROM->sll_hatype)
176          && (FROM->sll_hatype != ARPHRD_FDDI || ah->ar_hrd != htons(ARPHRD_ETHER)))
177                 return false;
178
179         /* Protocol must be IP. */
180         if (ah->ar_pro != htons(ETH_P_IP)
181          || (ah->ar_pln != 4)
182          || (ah->ar_hln != me.sll_halen)
183          || (len < (int)(sizeof(*ah) + 2 * (4 + ah->ar_hln))))
184                 return false;
185
186         move_from_unaligned32(src_ip.s_addr, p + ah->ar_hln);
187         move_from_unaligned32(dst_ip.s_addr, p + ah->ar_hln + 4 + ah->ar_hln);
188
189         if (dst.s_addr != src_ip.s_addr)
190                 return false;
191         if (!(option_mask32 & DAD)) {
192                 if ((src.s_addr != dst_ip.s_addr)
193                         || (memcmp(p + ah->ar_hln + 4, &me.sll_addr, ah->ar_hln)))
194                         return false;
195         } else {
196                 /* DAD packet was:
197                    src_ip = 0 (or some src)
198                    src_hw = ME
199                    dst_ip = tested address
200                    dst_hw = <unspec>
201
202                    We fail, if receive request/reply with:
203                    src_ip = tested_address
204                    src_hw != ME
205                    if src_ip in request was not zero, check
206                    also that it matches to dst_ip, otherwise
207                    dst_ip/dst_hw do not matter.
208                  */
209                 if ((memcmp(p, &me.sll_addr, me.sll_halen) == 0)
210                  || (src.s_addr && src.s_addr != dst_ip.s_addr))
211                         return false;
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                         unsigned diff = MONOTONIC_US() - last;
234                         printf(" %u.%03ums\n", diff / 1000, diff % 1000);
235                 } else {
236                         printf(" UNSOLICITED?\n");
237                 }
238                 fflush_all();
239         }
240         received++;
241         if (FROM->sll_pkttype != PACKET_HOST)
242                 brd_recv++;
243         if (ah->ar_op == htons(ARPOP_REQUEST))
244                 req_recv++;
245         if (option_mask32 & QUIT_ON_REPLY)
246                 finish();
247         if (!(option_mask32 & BCAST_ONLY)) {
248                 memcpy(he.sll_addr, p, me.sll_halen);
249                 option_mask32 |= UNICASTING;
250         }
251         return true;
252 }
253
254 int arping_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
255 int arping_main(int argc UNUSED_PARAM, char **argv)
256 {
257         const char *device = "eth0";
258         char *source = NULL;
259         char *target;
260         unsigned char *packet;
261         char *err_str;
262
263         INIT_G();
264
265         sock_fd = xsocket(AF_PACKET, SOCK_DGRAM, 0);
266
267         // Drop suid root privileges
268         // Need to remove SUID_NEVER from applets.h for this to work
269         //xsetuid(getuid());
270
271         err_str = xasprintf("interface %s %%s", device);
272         {
273                 unsigned opt;
274                 char *str_timeout;
275
276                 /* Dad also sets quit_on_reply.
277                  * Advert also sets unsolicited.
278                  */
279                 opt_complementary = "=1:Df:AU:c+";
280                 opt = getopt32(argv, "DUAqfbc:w:I:s:",
281                                 &count, &str_timeout, &device, &source);
282                 if (opt & 0x80) /* -w: timeout */
283                         timeout_us = xatou_range(str_timeout, 0, INT_MAX/2000000) * 1000000 + 500000;
284                 //if (opt & 0x200) /* -s: source */
285                 option_mask32 &= 0x3f; /* set respective flags */
286         }
287
288         target = argv[optind];
289
290         xfunc_error_retval = 2;
291
292         {
293                 struct ifreq ifr;
294
295                 memset(&ifr, 0, sizeof(ifr));
296                 strncpy_IFNAMSIZ(ifr.ifr_name, device);
297                 /* We use ifr.ifr_name in error msg so that problem
298                  * with truncated name will be visible */
299                 ioctl_or_perror_and_die(sock_fd, SIOCGIFINDEX, &ifr, err_str, "not found");
300                 me.sll_ifindex = ifr.ifr_ifindex;
301
302                 xioctl(sock_fd, SIOCGIFFLAGS, (char *) &ifr);
303
304                 if (!(ifr.ifr_flags & IFF_UP)) {
305                         bb_error_msg_and_die(err_str, "is down");
306                 }
307                 if (ifr.ifr_flags & (IFF_NOARP | IFF_LOOPBACK)) {
308                         bb_error_msg(err_str, "is not ARPable");
309                         return (option_mask32 & DAD ? 0 : 2);
310                 }
311         }
312
313         /* if (!inet_aton(target, &dst)) - not needed */ {
314                 len_and_sockaddr *lsa;
315                 lsa = xhost_and_af2sockaddr(target, 0, AF_INET);
316                 dst = lsa->u.sin.sin_addr;
317                 if (ENABLE_FEATURE_CLEAN_UP)
318                         free(lsa);
319         }
320
321         if (source && !inet_aton(source, &src)) {
322                 bb_error_msg_and_die("invalid source address %s", source);
323         }
324
325         if ((option_mask32 & (DAD|UNSOLICITED)) == UNSOLICITED && src.s_addr == 0)
326                 src = dst;
327
328         if (!(option_mask32 & DAD) || src.s_addr) {
329                 struct sockaddr_in saddr;
330                 int probe_fd = xsocket(AF_INET, SOCK_DGRAM, 0);
331
332                 setsockopt_bindtodevice(probe_fd, device);
333                 memset(&saddr, 0, sizeof(saddr));
334                 saddr.sin_family = AF_INET;
335                 if (src.s_addr) {
336                         /* Check that this is indeed our IP */
337                         saddr.sin_addr = src;
338                         xbind(probe_fd, (struct sockaddr *) &saddr, sizeof(saddr));
339                 } else { /* !(option_mask32 & DAD) case */
340                         /* Find IP address on this iface */
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                         getsockname(probe_fd, (struct sockaddr *) &saddr, &alen);
350                         //never happens:
351                         //if (getsockname(probe_fd, (struct sockaddr *) &saddr, &alen) == -1)
352                         //      bb_perror_msg_and_die("getsockname");
353                         if (saddr.sin_family != AF_INET)
354                                 bb_error_msg_and_die("no IP address configured");
355                         src = saddr.sin_addr;
356                 }
357                 close(probe_fd);
358         }
359
360         me.sll_family = AF_PACKET;
361         //me.sll_ifindex = ifindex; - done before
362         me.sll_protocol = htons(ETH_P_ARP);
363         xbind(sock_fd, (struct sockaddr *) &me, sizeof(me));
364
365         {
366                 socklen_t alen = sizeof(me);
367                 getsockname(sock_fd, (struct sockaddr *) &me, &alen);
368                 //never happens:
369                 //if (getsockname(sock_fd, (struct sockaddr *) &me, &alen) == -1)
370                 //      bb_perror_msg_and_die("getsockname");
371         }
372         if (me.sll_halen == 0) {
373                 bb_error_msg(err_str, "is not ARPable (no ll address)");
374                 return (option_mask32 & DAD ? 0 : 2);
375         }
376         he = me;
377         memset(he.sll_addr, -1, he.sll_halen);
378
379         if (!(option_mask32 & QUIET)) {
380                 /* inet_ntoa uses static storage, can't use in same printf */
381                 printf("ARPING to %s", inet_ntoa(dst));
382                 printf(" from %s via %s\n", inet_ntoa(src), device);
383         }
384
385         signal_SA_RESTART_empty_mask(SIGINT,  (void (*)(int))finish);
386         signal_SA_RESTART_empty_mask(SIGALRM, (void (*)(int))catcher);
387
388         catcher();
389
390         packet = xmalloc(4096);
391         while (1) {
392                 sigset_t sset, osset;
393                 struct sockaddr_ll from;
394                 socklen_t alen = sizeof(from);
395                 int cc;
396
397                 cc = recvfrom(sock_fd, packet, 4096, 0, (struct sockaddr *) &from, &alen);
398                 if (cc < 0) {
399                         bb_perror_msg("recvfrom");
400                         continue;
401                 }
402                 sigemptyset(&sset);
403                 sigaddset(&sset, SIGALRM);
404                 sigaddset(&sset, SIGINT);
405                 sigprocmask(SIG_BLOCK, &sset, &osset);
406                 recv_pack(packet, cc, &from);
407                 sigprocmask(SIG_SETMASK, &osset, NULL);
408         }
409 }