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