blob: 86f0221ed96ee9fe24725f2508ab94430b917c67 [file] [log] [blame]
Bernhard Reutner-Fischerdac7ff12006-04-12 17:55:51 +00001/* vi: set sw=4 ts=4: */
Glenn L McGrath9e598412003-01-09 10:06:01 +00002/*
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +02003 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
Glenn L McGrath9e598412003-01-09 10:06:01 +00004 *
Denys Vlasenko11872ca2010-10-30 02:24:48 +02005 * Author: Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
Glenn L McGrath9e598412003-01-09 10:06:01 +00006 * Busybox port: Nick Fedchik <nick@fedchik.org.ua>
7 */
Denys Vlasenko47367e12016-11-23 09:05:14 +01008//config:config ARPING
Denys Vlasenkob097a842018-12-28 03:20:17 +01009//config: bool "arping (9 kb)"
Denys Vlasenko47367e12016-11-23 09:05:14 +010010//config: default y
Denys Vlasenko47367e12016-11-23 09:05:14 +010011//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020012//config: Ping hosts by ARP packets.
Denys Vlasenko47367e12016-11-23 09:05:14 +010013
14//applet:IF_ARPING(APPLET(arping, BB_DIR_USR_SBIN, BB_SUID_DROP))
15
16//kbuild:lib-$(CONFIG_ARPING) += arping.o
Glenn L McGrath9e598412003-01-09 10:06:01 +000017
Pere Orga5bc8c002011-04-11 03:29:49 +020018//usage:#define arping_trivial_usage
19//usage: "[-fqbDUA] [-c CNT] [-w TIMEOUT] [-I IFACE] [-s SRC_IP] DST_IP"
20//usage:#define arping_full_usage "\n\n"
21//usage: "Send ARP requests/replies\n"
Pere Orga5bc8c002011-04-11 03:29:49 +020022//usage: "\n -f Quit on first ARP reply"
23//usage: "\n -q Quiet"
24//usage: "\n -b Keep broadcasting, don't go unicast"
Denys Vlasenkofb527692015-08-16 19:56:16 +020025//usage: "\n -D Exit with 1 if DST_IP replies"
Pere Orga5bc8c002011-04-11 03:29:49 +020026//usage: "\n -U Unsolicited ARP mode, update your neighbors"
27//usage: "\n -A ARP answer mode, update your neighbors"
28//usage: "\n -c N Stop after sending N ARP requests"
Denys Vlasenkofb527692015-08-16 19:56:16 +020029//usage: "\n -w TIMEOUT Seconds to wait for ARP reply"
Denys Vlasenkob5257a62018-02-11 21:16:24 +010030//NB: in iputils-s20160308, iface is mandatory, no default
Pere Orga5bc8c002011-04-11 03:29:49 +020031//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
Glenn L McGrath9e598412003-01-09 10:06:01 +000035#include <arpa/inet.h>
36#include <net/if.h>
37#include <netinet/ether.h>
38#include <netpacket/packet.h>
39
Denis Vlasenkob6adbf12007-05-26 19:00:18 +000040#include "libbb.h"
Denys Vlasenkoe6a2f4c2016-04-21 16:26:30 +020041#include "common_bufsiz.h"
Glenn L McGrath9e598412003-01-09 10:06:01 +000042
Denis Vlasenko459be352007-06-17 19:09:05 +000043/* We don't expect to see 1000+ seconds delay, unsigned is enough */
44#define MONOTONIC_US() ((unsigned)monotonic_us())
45
Denis Vlasenko459be352007-06-17 19:09:05 +000046enum {
Denys Vlasenkof5d50fb2018-02-11 13:27:54 +010047 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,
Rob Landley8ea52052006-03-30 21:50:57 +000055};
Denys Vlasenkof5d50fb2018-02-11 13:27:54 +010056#define GETOPT32(str_timeout, device, source) \
57 getopt32(argv, "^" \
58 "UDAqfbc:+w:I:s:" \
Denys Vlasenkob5257a62018-02-11 21:16:24 +010059 /* DAD also sets quit_on_reply, */ \
60 /* advert also sets unsolicited: */ \
Denys Vlasenkof5d50fb2018-02-11 13:27:54 +010061 "\0" "=1:Df:AU", \
62 &count, &str_timeout, &device, &source \
63 );
Rob Landley8ea52052006-03-30 21:50:57 +000064
Denis Vlasenkofff9b692007-11-23 09:15:26 +000065struct globals {
66 struct in_addr src;
67 struct in_addr dst;
68 struct sockaddr_ll me;
69 struct sockaddr_ll he;
Denis Vlasenkofff9b692007-11-23 09:15:26 +000070
71 int count; // = -1;
72 unsigned last;
73 unsigned timeout_us;
74 unsigned start;
75
76 unsigned sent;
77 unsigned brd_sent;
78 unsigned received;
79 unsigned brd_recv;
80 unsigned req_recv;
Denys Vlasenkod3162772018-02-11 14:35:05 +010081
Denys Vlasenkob5257a62018-02-11 21:16:24 +010082 /* should be in main(), but are here to reduce stack use: */
Denys Vlasenkod3162772018-02-11 14:35:05 +010083 struct ifreq ifr;
Denys Vlasenkob5257a62018-02-11 21:16:24 +010084 struct sockaddr_in probe_saddr;
Denys Vlasenkod3162772018-02-11 14:35:05 +010085 sigset_t sset;
86 unsigned char packet[4096];
Denys Vlasenko98a4c7c2010-02-04 15:00:15 +010087} FIX_ALIASING;
Denis Vlasenkofff9b692007-11-23 09:15:26 +000088#define src (G.src )
89#define dst (G.dst )
90#define me (G.me )
91#define he (G.he )
Denis Vlasenkofff9b692007-11-23 09:15:26 +000092#define count (G.count )
93#define last (G.last )
94#define timeout_us (G.timeout_us)
95#define start (G.start )
96#define sent (G.sent )
97#define brd_sent (G.brd_sent )
98#define received (G.received )
99#define brd_recv (G.brd_recv )
100#define req_recv (G.req_recv )
Denys Vlasenkod3162772018-02-11 14:35:05 +0100101//#define G (*(struct globals*)bb_common_bufsiz1)
102#define G (*ptr_to_globals)
Denis Vlasenko7049ff82008-06-25 09:53:17 +0000103#define INIT_G() do { \
Denys Vlasenkod3162772018-02-11 14:35:05 +0100104 /*setup_common_bufsiz();*/ \
105 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
Denis Vlasenko7049ff82008-06-25 09:53:17 +0000106 count = -1; \
107} while (0)
Glenn L McGrath9e598412003-01-09 10:06:01 +0000108
Denys Vlasenkob5257a62018-02-11 21:16:24 +0100109#define sock_fd 3
110
Denis Vlasenkobd7bb292007-06-17 23:40:26 +0000111static int send_pack(struct in_addr *src_addr,
Denys Vlasenkof5d50fb2018-02-11 13:27:54 +0100112 struct in_addr *dst_addr,
113 struct sockaddr_ll *ME,
Denis Vlasenko1dc1b372006-12-23 02:48:44 +0000114 struct sockaddr_ll *HE)
Glenn L McGrath9e598412003-01-09 10:06:01 +0000115{
116 int err;
Denis Vlasenko459be352007-06-17 19:09:05 +0000117 unsigned char buf[256];
Glenn L McGrath9e598412003-01-09 10:06:01 +0000118 struct arphdr *ah = (struct arphdr *) buf;
Denys Vlasenkof5d50fb2018-02-11 13:27:54 +0100119 unsigned char *p;
Glenn L McGrath9e598412003-01-09 10:06:01 +0000120
Glenn L McGrath9e598412003-01-09 10:06:01 +0000121 ah->ar_hrd = htons(ARPHRD_ETHER);
122 ah->ar_pro = htons(ETH_P_IP);
123 ah->ar_hln = ME->sll_halen;
124 ah->ar_pln = 4;
Denis Vlasenkobd7bb292007-06-17 23:40:26 +0000125 ah->ar_op = option_mask32 & ADVERT ? htons(ARPOP_REPLY) : htons(ARPOP_REQUEST);
Glenn L McGrath9e598412003-01-09 10:06:01 +0000126
Denys Vlasenkof5d50fb2018-02-11 13:27:54 +0100127 p = (unsigned char *) (ah + 1);
Denis Vlasenkoa6b3a1f2008-04-25 08:13:36 +0000128 p = mempcpy(p, &ME->sll_addr, ah->ar_hln);
129 p = mempcpy(p, src_addr, 4);
Glenn L McGrath9e598412003-01-09 10:06:01 +0000130
Denis Vlasenkobd7bb292007-06-17 23:40:26 +0000131 if (option_mask32 & ADVERT)
Denis Vlasenkoa6b3a1f2008-04-25 08:13:36 +0000132 p = mempcpy(p, &ME->sll_addr, ah->ar_hln);
Glenn L McGrath9e598412003-01-09 10:06:01 +0000133 else
Denis Vlasenkoa6b3a1f2008-04-25 08:13:36 +0000134 p = mempcpy(p, &HE->sll_addr, ah->ar_hln);
Glenn L McGrath9e598412003-01-09 10:06:01 +0000135
Denis Vlasenkoa6b3a1f2008-04-25 08:13:36 +0000136 p = mempcpy(p, dst_addr, 4);
Glenn L McGrath9e598412003-01-09 10:06:01 +0000137
Denis Vlasenkoa09300a2007-11-25 12:40:56 +0000138 err = sendto(sock_fd, buf, p - buf, 0, (struct sockaddr *) HE, sizeof(*HE));
Glenn L McGrath9e598412003-01-09 10:06:01 +0000139 if (err == p - buf) {
Denis Vlasenkoa09300a2007-11-25 12:40:56 +0000140 last = MONOTONIC_US();
Glenn L McGrath9e598412003-01-09 10:06:01 +0000141 sent++;
Denis Vlasenkobd7bb292007-06-17 23:40:26 +0000142 if (!(option_mask32 & UNICASTING))
Glenn L McGrath9e598412003-01-09 10:06:01 +0000143 brd_sent++;
144 }
145 return err;
146}
147
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000148static void finish(void) NORETURN;
Eric Andersen14f5c8d2005-04-16 19:39:00 +0000149static void finish(void)
Glenn L McGrath9e598412003-01-09 10:06:01 +0000150{
Denis Vlasenkobd7bb292007-06-17 23:40:26 +0000151 if (!(option_mask32 & QUIET)) {
152 printf("Sent %u probe(s) (%u broadcast(s))\n"
Denys Vlasenkoa3ec3bd2018-02-11 13:37:07 +0100153 "Received %u response(s)"
Denis Vlasenkobd7bb292007-06-17 23:40:26 +0000154 " (%u request(s), %u broadcast(s))\n",
Bernhard Reutner-Fischerebd13552006-04-03 12:29:12 +0000155 sent, brd_sent,
Denys Vlasenkoa3ec3bd2018-02-11 13:37:07 +0100156 received,
Denis Vlasenko1dc1b372006-12-23 02:48:44 +0000157 req_recv, brd_recv);
Glenn L McGrath9e598412003-01-09 10:06:01 +0000158 }
Denis Vlasenkobd7bb292007-06-17 23:40:26 +0000159 if (option_mask32 & DAD)
Glenn L McGrath9e598412003-01-09 10:06:01 +0000160 exit(!!received);
Denis Vlasenkobd7bb292007-06-17 23:40:26 +0000161 if (option_mask32 & UNSOLICITED)
Denys Vlasenkodb5546c2022-01-05 22:16:06 +0100162 exit_SUCCESS();
Glenn L McGrath9e598412003-01-09 10:06:01 +0000163 exit(!received);
164}
165
Eric Andersen14f5c8d2005-04-16 19:39:00 +0000166static void catcher(void)
Glenn L McGrath9e598412003-01-09 10:06:01 +0000167{
Denis Vlasenko459be352007-06-17 19:09:05 +0000168 unsigned now;
Glenn L McGrath9e598412003-01-09 10:06:01 +0000169
Denis Vlasenko459be352007-06-17 19:09:05 +0000170 now = MONOTONIC_US();
171 if (start == 0)
172 start = now;
Glenn L McGrath9e598412003-01-09 10:06:01 +0000173
Denis Vlasenkoa09300a2007-11-25 12:40:56 +0000174 if (count == 0 || (timeout_us && (now - start) > timeout_us))
Glenn L McGrath9e598412003-01-09 10:06:01 +0000175 finish();
176
Denis Vlasenkofff9b692007-11-23 09:15:26 +0000177 /* count < 0 means "infinite count" */
178 if (count > 0)
179 count--;
Denis Vlasenko459be352007-06-17 19:09:05 +0000180
181 if (last == 0 || (now - last) > 500000) {
Denis Vlasenkobd7bb292007-06-17 23:40:26 +0000182 send_pack(&src, &dst, &me, &he);
183 if (count == 0 && (option_mask32 & UNSOLICITED))
Glenn L McGrath9e598412003-01-09 10:06:01 +0000184 finish();
185 }
186 alarm(1);
187}
188
Denys Vlasenkofb527692015-08-16 19:56:16 +0200189static void recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM)
Glenn L McGrath9e598412003-01-09 10:06:01 +0000190{
Glenn L McGrath9e598412003-01-09 10:06:01 +0000191 struct arphdr *ah = (struct arphdr *) buf;
192 unsigned char *p = (unsigned char *) (ah + 1);
193 struct in_addr src_ip, dst_ip;
Denys Vlasenkod3162772018-02-11 14:35:05 +0100194
Denis Vlasenkoefb545b2008-12-08 22:56:18 +0000195 /* moves below assume in_addr is 4 bytes big, ensure that */
Denys Vlasenkod3162772018-02-11 14:35:05 +0100196 BUILD_BUG_ON(sizeof(struct in_addr) != 4);
197 BUILD_BUG_ON(sizeof(src_ip.s_addr) != 4);
Glenn L McGrath9e598412003-01-09 10:06:01 +0000198
Glenn L McGrath9e598412003-01-09 10:06:01 +0000199 /* Filter out wild packets */
Denis Vlasenko1dc1b372006-12-23 02:48:44 +0000200 if (FROM->sll_pkttype != PACKET_HOST
201 && FROM->sll_pkttype != PACKET_BROADCAST
202 && FROM->sll_pkttype != PACKET_MULTICAST)
Denys Vlasenkofb527692015-08-16 19:56:16 +0200203 return;
Glenn L McGrath9e598412003-01-09 10:06:01 +0000204
Denys Vlasenkob22bbff2009-07-04 16:50:43 +0200205 /* Only these types are recognized */
Glenn L McGrath9e598412003-01-09 10:06:01 +0000206 if (ah->ar_op != htons(ARPOP_REQUEST) && ah->ar_op != htons(ARPOP_REPLY))
Denys Vlasenkofb527692015-08-16 19:56:16 +0200207 return;
Glenn L McGrath9e598412003-01-09 10:06:01 +0000208
209 /* ARPHRD check and this darned FDDI hack here :-( */
Denis Vlasenko1dc1b372006-12-23 02:48:44 +0000210 if (ah->ar_hrd != htons(FROM->sll_hatype)
211 && (FROM->sll_hatype != ARPHRD_FDDI || ah->ar_hrd != htons(ARPHRD_ETHER)))
Denys Vlasenkofb527692015-08-16 19:56:16 +0200212 return;
Glenn L McGrath9e598412003-01-09 10:06:01 +0000213
214 /* Protocol must be IP. */
Bernhard Reutner-Fischerf536b992008-02-11 13:26:54 +0000215 if (ah->ar_pro != htons(ETH_P_IP)
Denis Vlasenkoefb545b2008-12-08 22:56:18 +0000216 || (ah->ar_pln != 4)
217 || (ah->ar_hln != me.sll_halen)
Denys Vlasenkod3162772018-02-11 14:35:05 +0100218 || (len < (int)(sizeof(*ah) + 2 * (4 + ah->ar_hln)))
219 ) {
Denys Vlasenkofb527692015-08-16 19:56:16 +0200220 return;
Denys Vlasenkod3162772018-02-11 14:35:05 +0100221 }
Bernhard Reutner-Fischerf536b992008-02-11 13:26:54 +0000222
Denis Vlasenkoefb545b2008-12-08 22:56:18 +0000223 move_from_unaligned32(src_ip.s_addr, p + ah->ar_hln);
224 move_from_unaligned32(dst_ip.s_addr, p + ah->ar_hln + 4 + ah->ar_hln);
Bernhard Reutner-Fischerf536b992008-02-11 13:26:54 +0000225
226 if (dst.s_addr != src_ip.s_addr)
Denys Vlasenkofb527692015-08-16 19:56:16 +0200227 return;
Denis Vlasenkobd7bb292007-06-17 23:40:26 +0000228 if (!(option_mask32 & DAD)) {
Bernhard Reutner-Fischerf536b992008-02-11 13:26:54 +0000229 if ((src.s_addr != dst_ip.s_addr)
Denys Vlasenkofb527692015-08-16 19:56:16 +0200230 || (memcmp(p + ah->ar_hln + 4, &me.sll_addr, ah->ar_hln)))
231 return;
Glenn L McGrath9e598412003-01-09 10:06:01 +0000232 } else {
233 /* DAD packet was:
234 src_ip = 0 (or some src)
235 src_hw = ME
236 dst_ip = tested address
237 dst_hw = <unspec>
238
239 We fail, if receive request/reply with:
240 src_ip = tested_address
241 src_hw != ME
242 if src_ip in request was not zero, check
243 also that it matches to dst_ip, otherwise
244 dst_ip/dst_hw do not matter.
245 */
Bernhard Reutner-Fischerf536b992008-02-11 13:26:54 +0000246 if ((memcmp(p, &me.sll_addr, me.sll_halen) == 0)
Denis Vlasenkoefb545b2008-12-08 22:56:18 +0000247 || (src.s_addr && src.s_addr != dst_ip.s_addr))
Denys Vlasenkofb527692015-08-16 19:56:16 +0200248 return;
Glenn L McGrath9e598412003-01-09 10:06:01 +0000249 }
Denis Vlasenkobd7bb292007-06-17 23:40:26 +0000250 if (!(option_mask32 & QUIET)) {
Glenn L McGrath9e598412003-01-09 10:06:01 +0000251 int s_printed = 0;
252
Denys Vlasenkoa3ec3bd2018-02-11 13:37:07 +0100253//TODO: arping from iputils-s20160308 print upprcase hex in MAC, follow them?
Denys Vlasenko852e8dd2016-05-26 21:35:46 +0200254 printf("%scast re%s from %s [%02x:%02x:%02x:%02x:%02x:%02x]",
Denis Vlasenko1dc1b372006-12-23 02:48:44 +0000255 FROM->sll_pkttype == PACKET_HOST ? "Uni" : "Broad",
256 ah->ar_op == htons(ARPOP_REPLY) ? "ply" : "quest",
Bernhard Reutner-Fischerebd13552006-04-03 12:29:12 +0000257 inet_ntoa(src_ip),
Denys Vlasenko852e8dd2016-05-26 21:35:46 +0200258 p[0], p[1], p[2], p[3], p[4], p[5]
259 );
Glenn L McGrath9e598412003-01-09 10:06:01 +0000260 if (dst_ip.s_addr != src.s_addr) {
Denys Vlasenkoa3ec3bd2018-02-11 13:37:07 +0100261 printf("for %s", inet_ntoa(dst_ip));
Glenn L McGrath9e598412003-01-09 10:06:01 +0000262 s_printed = 1;
263 }
264 if (memcmp(p + ah->ar_hln + 4, me.sll_addr, ah->ar_hln)) {
Denys Vlasenko852e8dd2016-05-26 21:35:46 +0200265 unsigned char *pp = p + ah->ar_hln + 4;
Glenn L McGrath9e598412003-01-09 10:06:01 +0000266 if (!s_printed)
Denys Vlasenkoa3ec3bd2018-02-11 13:37:07 +0100267 printf(" for");
268 printf(" [%02x:%02x:%02x:%02x:%02x:%02x]",
Denys Vlasenko852e8dd2016-05-26 21:35:46 +0200269 pp[0], pp[1], pp[2], pp[3], pp[4], pp[5]
270 );
Glenn L McGrath9e598412003-01-09 10:06:01 +0000271 }
Rob Landley8ea52052006-03-30 21:50:57 +0000272
Denis Vlasenko459be352007-06-17 19:09:05 +0000273 if (last) {
Denis Vlasenkoa09300a2007-11-25 12:40:56 +0000274 unsigned diff = MONOTONIC_US() - last;
275 printf(" %u.%03ums\n", diff / 1000, diff % 1000);
Glenn L McGrath9e598412003-01-09 10:06:01 +0000276 } else {
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200277 puts(" UNSOLICITED?");
Glenn L McGrath9e598412003-01-09 10:06:01 +0000278 }
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100279 fflush_all();
Glenn L McGrath9e598412003-01-09 10:06:01 +0000280 }
281 received++;
282 if (FROM->sll_pkttype != PACKET_HOST)
283 brd_recv++;
284 if (ah->ar_op == htons(ARPOP_REQUEST))
285 req_recv++;
Denis Vlasenkobd7bb292007-06-17 23:40:26 +0000286 if (option_mask32 & QUIT_ON_REPLY)
Glenn L McGrath9e598412003-01-09 10:06:01 +0000287 finish();
Denis Vlasenkobd7bb292007-06-17 23:40:26 +0000288 if (!(option_mask32 & BCAST_ONLY)) {
Glenn L McGrath9e598412003-01-09 10:06:01 +0000289 memcpy(he.sll_addr, p, me.sll_halen);
Denis Vlasenkobd7bb292007-06-17 23:40:26 +0000290 option_mask32 |= UNICASTING;
Glenn L McGrath9e598412003-01-09 10:06:01 +0000291 }
Glenn L McGrath9e598412003-01-09 10:06:01 +0000292}
293
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +0000294int arping_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000295int arping_main(int argc UNUSED_PARAM, char **argv)
Glenn L McGrath9e598412003-01-09 10:06:01 +0000296{
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +0000297 const char *device = "eth0";
Glenn L McGrath9e598412003-01-09 10:06:01 +0000298 char *source = NULL;
299 char *target;
Bernhard Reutner-Fischerf536b992008-02-11 13:26:54 +0000300 char *err_str;
Glenn L McGrath9e598412003-01-09 10:06:01 +0000301
Denis Vlasenkofff9b692007-11-23 09:15:26 +0000302 INIT_G();
303
Denys Vlasenkob5257a62018-02-11 21:16:24 +0100304 xmove_fd(xsocket(AF_PACKET, SOCK_DGRAM, 0), sock_fd);
Glenn L McGrath9e598412003-01-09 10:06:01 +0000305
Denys Vlasenkofbecca12017-08-06 14:03:27 +0200306 // If you ever change BB_SUID_DROP to BB_SUID_REQUIRE,
307 // drop suid root privileges here:
Denis Vlasenkoa09300a2007-11-25 12:40:56 +0000308 //xsetuid(getuid());
Glenn L McGrath9e598412003-01-09 10:06:01 +0000309
Bernhard Reutner-Fischer13766942006-03-31 18:02:46 +0000310 {
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000311 unsigned opt;
Denis Vlasenko1d426652008-03-17 09:09:09 +0000312 char *str_timeout;
Bernhard Reutner-Fischera0f75e22006-04-03 11:52:01 +0000313
Denys Vlasenkof5d50fb2018-02-11 13:27:54 +0100314 opt = GETOPT32(str_timeout, device, source);
315 if (opt & TIMEOUT)
Denis Vlasenkoa09300a2007-11-25 12:40:56 +0000316 timeout_us = xatou_range(str_timeout, 0, INT_MAX/2000000) * 1000000 + 500000;
Glenn L McGrath9e598412003-01-09 10:06:01 +0000317 }
Glenn L McGrath9e598412003-01-09 10:06:01 +0000318
Denis Vlasenko459be352007-06-17 19:09:05 +0000319 target = argv[optind];
Alexander Korolkov748fb602015-03-12 13:05:33 +0100320 err_str = xasprintf("interface %s %%s", device);
Denis Vlasenko40920822006-10-03 20:28:06 +0000321 xfunc_error_retval = 2;
Glenn L McGrath9e598412003-01-09 10:06:01 +0000322
Denys Vlasenkod3162772018-02-11 14:35:05 +0100323 /*memset(&G.ifr, 0, sizeof(G.ifr)); - zeroed by INIT_G */
324 strncpy_IFNAMSIZ(G.ifr.ifr_name, device);
325 ioctl_or_perror_and_die(sock_fd, SIOCGIFINDEX, &G.ifr, err_str, "not found");
326 me.sll_ifindex = G.ifr.ifr_ifindex;
Glenn L McGrath9e598412003-01-09 10:06:01 +0000327
Denys Vlasenkod3162772018-02-11 14:35:05 +0100328 xioctl(sock_fd, SIOCGIFFLAGS, (char *) &G.ifr);
Glenn L McGrath9e598412003-01-09 10:06:01 +0000329
Denys Vlasenkod3162772018-02-11 14:35:05 +0100330 if (!(G.ifr.ifr_flags & IFF_UP)) {
331 bb_error_msg_and_die(err_str, "is down");
332 }
333 if (G.ifr.ifr_flags & (IFF_NOARP | IFF_LOOPBACK)) {
334 bb_error_msg(err_str, "is not ARPable");
335 BUILD_BUG_ON(DAD != 2);
336 /* exit 0 if DAD, else exit 2 */
337 return (~option_mask32 & DAD);
Glenn L McGrath9e598412003-01-09 10:06:01 +0000338 }
339
Denis Vlasenkoa09300a2007-11-25 12:40:56 +0000340 /* if (!inet_aton(target, &dst)) - not needed */ {
Denis Vlasenko90ec4dc2007-01-25 19:44:38 +0000341 len_and_sockaddr *lsa;
Denis Vlasenko42823d52007-02-04 02:39:08 +0000342 lsa = xhost_and_af2sockaddr(target, 0, AF_INET);
Denis Vlasenkoefb545b2008-12-08 22:56:18 +0000343 dst = lsa->u.sin.sin_addr;
Denis Vlasenko90ec4dc2007-01-25 19:44:38 +0000344 if (ENABLE_FEATURE_CLEAN_UP)
345 free(lsa);
Glenn L McGrath9e598412003-01-09 10:06:01 +0000346 }
347
Glenn L McGratha837e2d2003-02-09 07:01:33 +0000348 if (source && !inet_aton(source, &src)) {
Rob Landley8ea52052006-03-30 21:50:57 +0000349 bb_error_msg_and_die("invalid source address %s", source);
Glenn L McGrath9e598412003-01-09 10:06:01 +0000350 }
351
Denis Vlasenkoa09300a2007-11-25 12:40:56 +0000352 if ((option_mask32 & (DAD|UNSOLICITED)) == UNSOLICITED && src.s_addr == 0)
Glenn L McGrath9e598412003-01-09 10:06:01 +0000353 src = dst;
354
Denis Vlasenkobd7bb292007-06-17 23:40:26 +0000355 if (!(option_mask32 & DAD) || src.s_addr) {
Denys Vlasenkob5257a62018-02-11 21:16:24 +0100356 /*struct sockaddr_in probe_saddr;*/
Denis Vlasenko27af5a02006-09-03 12:21:59 +0000357 int probe_fd = xsocket(AF_INET, SOCK_DGRAM, 0);
Glenn L McGrath9e598412003-01-09 10:06:01 +0000358
Denis Vlasenkoe5373852008-12-10 11:12:16 +0000359 setsockopt_bindtodevice(probe_fd, device);
Denys Vlasenkob5257a62018-02-11 21:16:24 +0100360
361 /*memset(&G.probe_saddr, 0, sizeof(G.probe_saddr)); - zeroed by INIT_G */
362 G.probe_saddr.sin_family = AF_INET;
Glenn L McGrath9e598412003-01-09 10:06:01 +0000363 if (src.s_addr) {
Denis Vlasenkoa09300a2007-11-25 12:40:56 +0000364 /* Check that this is indeed our IP */
Denys Vlasenkob5257a62018-02-11 21:16:24 +0100365 G.probe_saddr.sin_addr = src;
366 xbind(probe_fd, (struct sockaddr *) &G.probe_saddr, sizeof(G.probe_saddr));
Denis Vlasenkoa09300a2007-11-25 12:40:56 +0000367 } else { /* !(option_mask32 & DAD) case */
368 /* Find IP address on this iface */
Denys Vlasenkob5257a62018-02-11 21:16:24 +0100369 G.probe_saddr.sin_port = htons(1025);
370 G.probe_saddr.sin_addr = dst;
Glenn L McGrath9e598412003-01-09 10:06:01 +0000371
Denys Vlasenkoc52cbea2015-08-24 19:48:03 +0200372 if (setsockopt_SOL_SOCKET_1(probe_fd, SO_DONTROUTE) != 0)
Denys Vlasenko2db782b2015-08-24 19:08:14 +0200373 bb_perror_msg("setsockopt(%s)", "SO_DONTROUTE");
Denys Vlasenkob5257a62018-02-11 21:16:24 +0100374 xconnect(probe_fd, (struct sockaddr *) &G.probe_saddr, sizeof(G.probe_saddr));
375 bb_getsockname(probe_fd, (struct sockaddr *) &G.probe_saddr, sizeof(G.probe_saddr));
376 if (G.probe_saddr.sin_family != AF_INET)
James Byrne69374872019-07-02 11:35:03 +0200377 bb_simple_error_msg_and_die("no IP address configured");
Denys Vlasenkob5257a62018-02-11 21:16:24 +0100378 src = G.probe_saddr.sin_addr;
Glenn L McGrath9e598412003-01-09 10:06:01 +0000379 }
380 close(probe_fd);
Denis Vlasenko1dc1b372006-12-23 02:48:44 +0000381 }
Glenn L McGrath9e598412003-01-09 10:06:01 +0000382
383 me.sll_family = AF_PACKET;
Denis Vlasenkoa09300a2007-11-25 12:40:56 +0000384 //me.sll_ifindex = ifindex; - done before
Glenn L McGrath9e598412003-01-09 10:06:01 +0000385 me.sll_protocol = htons(ETH_P_ARP);
Denis Vlasenkoa09300a2007-11-25 12:40:56 +0000386 xbind(sock_fd, (struct sockaddr *) &me, sizeof(me));
Glenn L McGrath9e598412003-01-09 10:06:01 +0000387
Denys Vlasenkoba3b9db2018-02-11 14:55:46 +0100388 bb_getsockname(sock_fd, (struct sockaddr *) &me, sizeof(me));
389 //never happens:
390 //if (getsockname(sock_fd, (struct sockaddr *) &me, &alen) == -1)
391 // bb_perror_msg_and_die("getsockname");
Glenn L McGrath9e598412003-01-09 10:06:01 +0000392 if (me.sll_halen == 0) {
Bernhard Reutner-Fischerf536b992008-02-11 13:26:54 +0000393 bb_error_msg(err_str, "is not ARPable (no ll address)");
Denys Vlasenkof5d50fb2018-02-11 13:27:54 +0100394 BUILD_BUG_ON(DAD != 2);
395 /* exit 0 if DAD, else exit 2 */
396 return (~option_mask32 & DAD);
Glenn L McGrath9e598412003-01-09 10:06:01 +0000397 }
398 he = me;
399 memset(he.sll_addr, -1, he.sll_halen);
400
Denis Vlasenkobd7bb292007-06-17 23:40:26 +0000401 if (!(option_mask32 & QUIET)) {
Denis Vlasenkoa09300a2007-11-25 12:40:56 +0000402 /* inet_ntoa uses static storage, can't use in same printf */
Denys Vlasenkoa3ec3bd2018-02-11 13:37:07 +0100403 printf("ARPING %s", inet_ntoa(dst));
404 printf(" from %s %s\n", inet_ntoa(src), device);
Glenn L McGratha837e2d2003-02-09 07:01:33 +0000405 }
Glenn L McGrath9e598412003-01-09 10:06:01 +0000406
Denys Vlasenkod3162772018-02-11 14:35:05 +0100407 /*sigemptyset(&G.sset); - zeroed by INIT_G */
408 sigaddset(&G.sset, SIGALRM);
409 sigaddset(&G.sset, SIGINT);
Denis Vlasenko8e2cfec2008-03-12 23:19:35 +0000410 signal_SA_RESTART_empty_mask(SIGINT, (void (*)(int))finish);
411 signal_SA_RESTART_empty_mask(SIGALRM, (void (*)(int))catcher);
Glenn L McGrath9e598412003-01-09 10:06:01 +0000412
Denys Vlasenkoe015d062018-02-11 13:48:52 +0100413 /* Send the first packet, arm ALRM */
Glenn L McGrath9e598412003-01-09 10:06:01 +0000414 catcher();
415
416 while (1) {
Glenn L McGrath9e598412003-01-09 10:06:01 +0000417 struct sockaddr_ll from;
Eric Andersen0cb6f352006-01-30 22:30:41 +0000418 socklen_t alen = sizeof(from);
Glenn L McGrath9e598412003-01-09 10:06:01 +0000419 int cc;
420
Denys Vlasenkoe015d062018-02-11 13:48:52 +0100421 /* Unblock SIGALRM so that the previously called alarm()
422 * can prevent recvfrom from blocking forever in case the
423 * inherited procmask is blocking SIGALRM.
424 */
Denys Vlasenkod3162772018-02-11 14:35:05 +0100425 sigprocmask(SIG_UNBLOCK, &G.sset, NULL);
Denys Vlasenkoe015d062018-02-11 13:48:52 +0100426
Denys Vlasenkod3162772018-02-11 14:35:05 +0100427 cc = recvfrom(sock_fd, G.packet, sizeof(G.packet), 0, (struct sockaddr *) &from, &alen);
Denys Vlasenkoe015d062018-02-11 13:48:52 +0100428
429 /* Don't allow SIGALRMs while we process the reply */
Denys Vlasenkod3162772018-02-11 14:35:05 +0100430 sigprocmask(SIG_BLOCK, &G.sset, NULL);
Denis Vlasenko1dc1b372006-12-23 02:48:44 +0000431 if (cc < 0) {
James Byrne69374872019-07-02 11:35:03 +0200432 bb_simple_perror_msg("recvfrom");
Glenn L McGrath9e598412003-01-09 10:06:01 +0000433 continue;
434 }
Denys Vlasenkod3162772018-02-11 14:35:05 +0100435 recv_pack(G.packet, cc, &from);
Glenn L McGrath9e598412003-01-09 10:06:01 +0000436 }
437}