blob: fd0e1b27684f05aba1118bbe97a5d9214c6121cc [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
Samuel Thibault77216c32022-10-16 02:04:59 +020011//config: select PLATFORM_LINUX
Denys Vlasenko47367e12016-11-23 09:05:14 +010012//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020013//config: Ping hosts by ARP packets.
Denys Vlasenko47367e12016-11-23 09:05:14 +010014
15//applet:IF_ARPING(APPLET(arping, BB_DIR_USR_SBIN, BB_SUID_DROP))
16
17//kbuild:lib-$(CONFIG_ARPING) += arping.o
Glenn L McGrath9e598412003-01-09 10:06:01 +000018
Pere Orga5bc8c002011-04-11 03:29:49 +020019//usage:#define arping_trivial_usage
20//usage: "[-fqbDUA] [-c CNT] [-w TIMEOUT] [-I IFACE] [-s SRC_IP] DST_IP"
21//usage:#define arping_full_usage "\n\n"
22//usage: "Send ARP requests/replies\n"
Pere Orga5bc8c002011-04-11 03:29:49 +020023//usage: "\n -f Quit on first ARP reply"
24//usage: "\n -q Quiet"
25//usage: "\n -b Keep broadcasting, don't go unicast"
Denys Vlasenkofb527692015-08-16 19:56:16 +020026//usage: "\n -D Exit with 1 if DST_IP replies"
Pere Orga5bc8c002011-04-11 03:29:49 +020027//usage: "\n -U Unsolicited ARP mode, update your neighbors"
28//usage: "\n -A ARP answer mode, update your neighbors"
29//usage: "\n -c N Stop after sending N ARP requests"
Denys Vlasenkofb527692015-08-16 19:56:16 +020030//usage: "\n -w TIMEOUT Seconds to wait for ARP reply"
Denys Vlasenkob5257a62018-02-11 21:16:24 +010031//NB: in iputils-s20160308, iface is mandatory, no default
Pere Orga5bc8c002011-04-11 03:29:49 +020032//usage: "\n -I IFACE Interface to use (default eth0)"
33//usage: "\n -s SRC_IP Sender IP address"
34//usage: "\n DST_IP Target IP address"
35
Glenn L McGrath9e598412003-01-09 10:06:01 +000036#include <arpa/inet.h>
37#include <net/if.h>
38#include <netinet/ether.h>
39#include <netpacket/packet.h>
40
Denis Vlasenkob6adbf12007-05-26 19:00:18 +000041#include "libbb.h"
Denys Vlasenkoe6a2f4c2016-04-21 16:26:30 +020042#include "common_bufsiz.h"
Glenn L McGrath9e598412003-01-09 10:06:01 +000043
Denis Vlasenko459be352007-06-17 19:09:05 +000044/* We don't expect to see 1000+ seconds delay, unsigned is enough */
45#define MONOTONIC_US() ((unsigned)monotonic_us())
46
Denis Vlasenko459be352007-06-17 19:09:05 +000047enum {
Denys Vlasenkof5d50fb2018-02-11 13:27:54 +010048 UNSOLICITED = 1 << 0,
49 DAD = 1 << 1,
50 ADVERT = 1 << 2,
51 QUIET = 1 << 3,
52 QUIT_ON_REPLY = 1 << 4,
53 BCAST_ONLY = 1 << 5,
54 UNICASTING = 1 << 6,
55 TIMEOUT = 1 << 7,
Rob Landley8ea52052006-03-30 21:50:57 +000056};
Denys Vlasenkof5d50fb2018-02-11 13:27:54 +010057#define GETOPT32(str_timeout, device, source) \
58 getopt32(argv, "^" \
59 "UDAqfbc:+w:I:s:" \
Denys Vlasenkob5257a62018-02-11 21:16:24 +010060 /* DAD also sets quit_on_reply, */ \
61 /* advert also sets unsolicited: */ \
Denys Vlasenkof5d50fb2018-02-11 13:27:54 +010062 "\0" "=1:Df:AU", \
63 &count, &str_timeout, &device, &source \
64 );
Rob Landley8ea52052006-03-30 21:50:57 +000065
Denis Vlasenkofff9b692007-11-23 09:15:26 +000066struct globals {
67 struct in_addr src;
68 struct in_addr dst;
69 struct sockaddr_ll me;
70 struct sockaddr_ll he;
Denis Vlasenkofff9b692007-11-23 09:15:26 +000071
72 int count; // = -1;
73 unsigned last;
74 unsigned timeout_us;
75 unsigned start;
76
77 unsigned sent;
78 unsigned brd_sent;
79 unsigned received;
80 unsigned brd_recv;
81 unsigned req_recv;
Denys Vlasenkod3162772018-02-11 14:35:05 +010082
Denys Vlasenkob5257a62018-02-11 21:16:24 +010083 /* should be in main(), but are here to reduce stack use: */
Denys Vlasenkod3162772018-02-11 14:35:05 +010084 struct ifreq ifr;
Denys Vlasenkob5257a62018-02-11 21:16:24 +010085 struct sockaddr_in probe_saddr;
Denys Vlasenkod3162772018-02-11 14:35:05 +010086 sigset_t sset;
87 unsigned char packet[4096];
Denys Vlasenko98a4c7c2010-02-04 15:00:15 +010088} FIX_ALIASING;
Denis Vlasenkofff9b692007-11-23 09:15:26 +000089#define src (G.src )
90#define dst (G.dst )
91#define me (G.me )
92#define he (G.he )
Denis Vlasenkofff9b692007-11-23 09:15:26 +000093#define count (G.count )
94#define last (G.last )
95#define timeout_us (G.timeout_us)
96#define start (G.start )
97#define sent (G.sent )
98#define brd_sent (G.brd_sent )
99#define received (G.received )
100#define brd_recv (G.brd_recv )
101#define req_recv (G.req_recv )
Denys Vlasenkod3162772018-02-11 14:35:05 +0100102//#define G (*(struct globals*)bb_common_bufsiz1)
103#define G (*ptr_to_globals)
Denis Vlasenko7049ff82008-06-25 09:53:17 +0000104#define INIT_G() do { \
Denys Vlasenkod3162772018-02-11 14:35:05 +0100105 /*setup_common_bufsiz();*/ \
106 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
Denis Vlasenko7049ff82008-06-25 09:53:17 +0000107 count = -1; \
108} while (0)
Glenn L McGrath9e598412003-01-09 10:06:01 +0000109
Denys Vlasenkob5257a62018-02-11 21:16:24 +0100110#define sock_fd 3
111
Denis Vlasenkobd7bb292007-06-17 23:40:26 +0000112static int send_pack(struct in_addr *src_addr,
Denys Vlasenkof5d50fb2018-02-11 13:27:54 +0100113 struct in_addr *dst_addr,
114 struct sockaddr_ll *ME,
Denis Vlasenko1dc1b372006-12-23 02:48:44 +0000115 struct sockaddr_ll *HE)
Glenn L McGrath9e598412003-01-09 10:06:01 +0000116{
117 int err;
Denis Vlasenko459be352007-06-17 19:09:05 +0000118 unsigned char buf[256];
Glenn L McGrath9e598412003-01-09 10:06:01 +0000119 struct arphdr *ah = (struct arphdr *) buf;
Denys Vlasenkof5d50fb2018-02-11 13:27:54 +0100120 unsigned char *p;
Glenn L McGrath9e598412003-01-09 10:06:01 +0000121
Glenn L McGrath9e598412003-01-09 10:06:01 +0000122 ah->ar_hrd = htons(ARPHRD_ETHER);
123 ah->ar_pro = htons(ETH_P_IP);
124 ah->ar_hln = ME->sll_halen;
125 ah->ar_pln = 4;
Denis Vlasenkobd7bb292007-06-17 23:40:26 +0000126 ah->ar_op = option_mask32 & ADVERT ? htons(ARPOP_REPLY) : htons(ARPOP_REQUEST);
Glenn L McGrath9e598412003-01-09 10:06:01 +0000127
Denys Vlasenkof5d50fb2018-02-11 13:27:54 +0100128 p = (unsigned char *) (ah + 1);
Denis Vlasenkoa6b3a1f2008-04-25 08:13:36 +0000129 p = mempcpy(p, &ME->sll_addr, ah->ar_hln);
130 p = mempcpy(p, src_addr, 4);
Glenn L McGrath9e598412003-01-09 10:06:01 +0000131
Denis Vlasenkobd7bb292007-06-17 23:40:26 +0000132 if (option_mask32 & ADVERT)
Denis Vlasenkoa6b3a1f2008-04-25 08:13:36 +0000133 p = mempcpy(p, &ME->sll_addr, ah->ar_hln);
Glenn L McGrath9e598412003-01-09 10:06:01 +0000134 else
Denis Vlasenkoa6b3a1f2008-04-25 08:13:36 +0000135 p = mempcpy(p, &HE->sll_addr, ah->ar_hln);
Glenn L McGrath9e598412003-01-09 10:06:01 +0000136
Denis Vlasenkoa6b3a1f2008-04-25 08:13:36 +0000137 p = mempcpy(p, dst_addr, 4);
Glenn L McGrath9e598412003-01-09 10:06:01 +0000138
Denis Vlasenkoa09300a2007-11-25 12:40:56 +0000139 err = sendto(sock_fd, buf, p - buf, 0, (struct sockaddr *) HE, sizeof(*HE));
Glenn L McGrath9e598412003-01-09 10:06:01 +0000140 if (err == p - buf) {
Denis Vlasenkoa09300a2007-11-25 12:40:56 +0000141 last = MONOTONIC_US();
Glenn L McGrath9e598412003-01-09 10:06:01 +0000142 sent++;
Denis Vlasenkobd7bb292007-06-17 23:40:26 +0000143 if (!(option_mask32 & UNICASTING))
Glenn L McGrath9e598412003-01-09 10:06:01 +0000144 brd_sent++;
145 }
146 return err;
147}
148
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000149static void finish(void) NORETURN;
Eric Andersen14f5c8d2005-04-16 19:39:00 +0000150static void finish(void)
Glenn L McGrath9e598412003-01-09 10:06:01 +0000151{
Denis Vlasenkobd7bb292007-06-17 23:40:26 +0000152 if (!(option_mask32 & QUIET)) {
153 printf("Sent %u probe(s) (%u broadcast(s))\n"
Denys Vlasenkoa3ec3bd2018-02-11 13:37:07 +0100154 "Received %u response(s)"
Denis Vlasenkobd7bb292007-06-17 23:40:26 +0000155 " (%u request(s), %u broadcast(s))\n",
Bernhard Reutner-Fischerebd13552006-04-03 12:29:12 +0000156 sent, brd_sent,
Denys Vlasenkoa3ec3bd2018-02-11 13:37:07 +0100157 received,
Denis Vlasenko1dc1b372006-12-23 02:48:44 +0000158 req_recv, brd_recv);
Glenn L McGrath9e598412003-01-09 10:06:01 +0000159 }
Denis Vlasenkobd7bb292007-06-17 23:40:26 +0000160 if (option_mask32 & DAD)
Glenn L McGrath9e598412003-01-09 10:06:01 +0000161 exit(!!received);
Denis Vlasenkobd7bb292007-06-17 23:40:26 +0000162 if (option_mask32 & UNSOLICITED)
Denys Vlasenkodb5546c2022-01-05 22:16:06 +0100163 exit_SUCCESS();
Glenn L McGrath9e598412003-01-09 10:06:01 +0000164 exit(!received);
165}
166
Eric Andersen14f5c8d2005-04-16 19:39:00 +0000167static void catcher(void)
Glenn L McGrath9e598412003-01-09 10:06:01 +0000168{
Denis Vlasenko459be352007-06-17 19:09:05 +0000169 unsigned now;
Glenn L McGrath9e598412003-01-09 10:06:01 +0000170
Denis Vlasenko459be352007-06-17 19:09:05 +0000171 now = MONOTONIC_US();
172 if (start == 0)
173 start = now;
Glenn L McGrath9e598412003-01-09 10:06:01 +0000174
Denis Vlasenkoa09300a2007-11-25 12:40:56 +0000175 if (count == 0 || (timeout_us && (now - start) > timeout_us))
Glenn L McGrath9e598412003-01-09 10:06:01 +0000176 finish();
177
Denis Vlasenkofff9b692007-11-23 09:15:26 +0000178 /* count < 0 means "infinite count" */
179 if (count > 0)
180 count--;
Denis Vlasenko459be352007-06-17 19:09:05 +0000181
182 if (last == 0 || (now - last) > 500000) {
Denis Vlasenkobd7bb292007-06-17 23:40:26 +0000183 send_pack(&src, &dst, &me, &he);
184 if (count == 0 && (option_mask32 & UNSOLICITED))
Glenn L McGrath9e598412003-01-09 10:06:01 +0000185 finish();
186 }
187 alarm(1);
188}
189
Denys Vlasenkofb527692015-08-16 19:56:16 +0200190static void recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM)
Glenn L McGrath9e598412003-01-09 10:06:01 +0000191{
Glenn L McGrath9e598412003-01-09 10:06:01 +0000192 struct arphdr *ah = (struct arphdr *) buf;
193 unsigned char *p = (unsigned char *) (ah + 1);
194 struct in_addr src_ip, dst_ip;
Denys Vlasenkod3162772018-02-11 14:35:05 +0100195
Denis Vlasenkoefb545b2008-12-08 22:56:18 +0000196 /* moves below assume in_addr is 4 bytes big, ensure that */
Denys Vlasenkod3162772018-02-11 14:35:05 +0100197 BUILD_BUG_ON(sizeof(struct in_addr) != 4);
198 BUILD_BUG_ON(sizeof(src_ip.s_addr) != 4);
Glenn L McGrath9e598412003-01-09 10:06:01 +0000199
Glenn L McGrath9e598412003-01-09 10:06:01 +0000200 /* Filter out wild packets */
Denis Vlasenko1dc1b372006-12-23 02:48:44 +0000201 if (FROM->sll_pkttype != PACKET_HOST
202 && FROM->sll_pkttype != PACKET_BROADCAST
203 && FROM->sll_pkttype != PACKET_MULTICAST)
Denys Vlasenkofb527692015-08-16 19:56:16 +0200204 return;
Glenn L McGrath9e598412003-01-09 10:06:01 +0000205
Denys Vlasenkob22bbff2009-07-04 16:50:43 +0200206 /* Only these types are recognized */
Glenn L McGrath9e598412003-01-09 10:06:01 +0000207 if (ah->ar_op != htons(ARPOP_REQUEST) && ah->ar_op != htons(ARPOP_REPLY))
Denys Vlasenkofb527692015-08-16 19:56:16 +0200208 return;
Glenn L McGrath9e598412003-01-09 10:06:01 +0000209
210 /* ARPHRD check and this darned FDDI hack here :-( */
Denis Vlasenko1dc1b372006-12-23 02:48:44 +0000211 if (ah->ar_hrd != htons(FROM->sll_hatype)
212 && (FROM->sll_hatype != ARPHRD_FDDI || ah->ar_hrd != htons(ARPHRD_ETHER)))
Denys Vlasenkofb527692015-08-16 19:56:16 +0200213 return;
Glenn L McGrath9e598412003-01-09 10:06:01 +0000214
215 /* Protocol must be IP. */
Bernhard Reutner-Fischerf536b992008-02-11 13:26:54 +0000216 if (ah->ar_pro != htons(ETH_P_IP)
Denis Vlasenkoefb545b2008-12-08 22:56:18 +0000217 || (ah->ar_pln != 4)
218 || (ah->ar_hln != me.sll_halen)
Denys Vlasenkod3162772018-02-11 14:35:05 +0100219 || (len < (int)(sizeof(*ah) + 2 * (4 + ah->ar_hln)))
220 ) {
Denys Vlasenkofb527692015-08-16 19:56:16 +0200221 return;
Denys Vlasenkod3162772018-02-11 14:35:05 +0100222 }
Bernhard Reutner-Fischerf536b992008-02-11 13:26:54 +0000223
Denis Vlasenkoefb545b2008-12-08 22:56:18 +0000224 move_from_unaligned32(src_ip.s_addr, p + ah->ar_hln);
225 move_from_unaligned32(dst_ip.s_addr, p + ah->ar_hln + 4 + ah->ar_hln);
Bernhard Reutner-Fischerf536b992008-02-11 13:26:54 +0000226
227 if (dst.s_addr != src_ip.s_addr)
Denys Vlasenkofb527692015-08-16 19:56:16 +0200228 return;
Denis Vlasenkobd7bb292007-06-17 23:40:26 +0000229 if (!(option_mask32 & DAD)) {
Bernhard Reutner-Fischerf536b992008-02-11 13:26:54 +0000230 if ((src.s_addr != dst_ip.s_addr)
Denys Vlasenkofb527692015-08-16 19:56:16 +0200231 || (memcmp(p + ah->ar_hln + 4, &me.sll_addr, ah->ar_hln)))
232 return;
Glenn L McGrath9e598412003-01-09 10:06:01 +0000233 } else {
234 /* DAD packet was:
235 src_ip = 0 (or some src)
236 src_hw = ME
237 dst_ip = tested address
238 dst_hw = <unspec>
239
240 We fail, if receive request/reply with:
241 src_ip = tested_address
242 src_hw != ME
243 if src_ip in request was not zero, check
244 also that it matches to dst_ip, otherwise
245 dst_ip/dst_hw do not matter.
246 */
Bernhard Reutner-Fischerf536b992008-02-11 13:26:54 +0000247 if ((memcmp(p, &me.sll_addr, me.sll_halen) == 0)
Denis Vlasenkoefb545b2008-12-08 22:56:18 +0000248 || (src.s_addr && src.s_addr != dst_ip.s_addr))
Denys Vlasenkofb527692015-08-16 19:56:16 +0200249 return;
Glenn L McGrath9e598412003-01-09 10:06:01 +0000250 }
Denis Vlasenkobd7bb292007-06-17 23:40:26 +0000251 if (!(option_mask32 & QUIET)) {
Glenn L McGrath9e598412003-01-09 10:06:01 +0000252 int s_printed = 0;
253
Denys Vlasenkoa3ec3bd2018-02-11 13:37:07 +0100254//TODO: arping from iputils-s20160308 print upprcase hex in MAC, follow them?
Denys Vlasenko852e8dd2016-05-26 21:35:46 +0200255 printf("%scast re%s from %s [%02x:%02x:%02x:%02x:%02x:%02x]",
Denis Vlasenko1dc1b372006-12-23 02:48:44 +0000256 FROM->sll_pkttype == PACKET_HOST ? "Uni" : "Broad",
257 ah->ar_op == htons(ARPOP_REPLY) ? "ply" : "quest",
Bernhard Reutner-Fischerebd13552006-04-03 12:29:12 +0000258 inet_ntoa(src_ip),
Denys Vlasenko852e8dd2016-05-26 21:35:46 +0200259 p[0], p[1], p[2], p[3], p[4], p[5]
260 );
Glenn L McGrath9e598412003-01-09 10:06:01 +0000261 if (dst_ip.s_addr != src.s_addr) {
Denys Vlasenkoa3ec3bd2018-02-11 13:37:07 +0100262 printf("for %s", inet_ntoa(dst_ip));
Glenn L McGrath9e598412003-01-09 10:06:01 +0000263 s_printed = 1;
264 }
265 if (memcmp(p + ah->ar_hln + 4, me.sll_addr, ah->ar_hln)) {
Denys Vlasenko852e8dd2016-05-26 21:35:46 +0200266 unsigned char *pp = p + ah->ar_hln + 4;
Glenn L McGrath9e598412003-01-09 10:06:01 +0000267 if (!s_printed)
Denys Vlasenkoa3ec3bd2018-02-11 13:37:07 +0100268 printf(" for");
269 printf(" [%02x:%02x:%02x:%02x:%02x:%02x]",
Denys Vlasenko852e8dd2016-05-26 21:35:46 +0200270 pp[0], pp[1], pp[2], pp[3], pp[4], pp[5]
271 );
Glenn L McGrath9e598412003-01-09 10:06:01 +0000272 }
Rob Landley8ea52052006-03-30 21:50:57 +0000273
Denis Vlasenko459be352007-06-17 19:09:05 +0000274 if (last) {
Denis Vlasenkoa09300a2007-11-25 12:40:56 +0000275 unsigned diff = MONOTONIC_US() - last;
276 printf(" %u.%03ums\n", diff / 1000, diff % 1000);
Glenn L McGrath9e598412003-01-09 10:06:01 +0000277 } else {
Denys Vlasenkod60752f2015-10-07 22:42:45 +0200278 puts(" UNSOLICITED?");
Glenn L McGrath9e598412003-01-09 10:06:01 +0000279 }
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100280 fflush_all();
Glenn L McGrath9e598412003-01-09 10:06:01 +0000281 }
282 received++;
283 if (FROM->sll_pkttype != PACKET_HOST)
284 brd_recv++;
285 if (ah->ar_op == htons(ARPOP_REQUEST))
286 req_recv++;
Denis Vlasenkobd7bb292007-06-17 23:40:26 +0000287 if (option_mask32 & QUIT_ON_REPLY)
Glenn L McGrath9e598412003-01-09 10:06:01 +0000288 finish();
Denis Vlasenkobd7bb292007-06-17 23:40:26 +0000289 if (!(option_mask32 & BCAST_ONLY)) {
Glenn L McGrath9e598412003-01-09 10:06:01 +0000290 memcpy(he.sll_addr, p, me.sll_halen);
Denis Vlasenkobd7bb292007-06-17 23:40:26 +0000291 option_mask32 |= UNICASTING;
Glenn L McGrath9e598412003-01-09 10:06:01 +0000292 }
Glenn L McGrath9e598412003-01-09 10:06:01 +0000293}
294
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +0000295int arping_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000296int arping_main(int argc UNUSED_PARAM, char **argv)
Glenn L McGrath9e598412003-01-09 10:06:01 +0000297{
Denis Vlasenkob6aae0f2007-01-29 22:51:25 +0000298 const char *device = "eth0";
Glenn L McGrath9e598412003-01-09 10:06:01 +0000299 char *source = NULL;
300 char *target;
Bernhard Reutner-Fischerf536b992008-02-11 13:26:54 +0000301 char *err_str;
Glenn L McGrath9e598412003-01-09 10:06:01 +0000302
Denis Vlasenkofff9b692007-11-23 09:15:26 +0000303 INIT_G();
304
Denys Vlasenkob5257a62018-02-11 21:16:24 +0100305 xmove_fd(xsocket(AF_PACKET, SOCK_DGRAM, 0), sock_fd);
Glenn L McGrath9e598412003-01-09 10:06:01 +0000306
Denys Vlasenkofbecca12017-08-06 14:03:27 +0200307 // If you ever change BB_SUID_DROP to BB_SUID_REQUIRE,
308 // drop suid root privileges here:
Denis Vlasenkoa09300a2007-11-25 12:40:56 +0000309 //xsetuid(getuid());
Glenn L McGrath9e598412003-01-09 10:06:01 +0000310
Bernhard Reutner-Fischer13766942006-03-31 18:02:46 +0000311 {
Denis Vlasenko67b23e62006-10-03 21:00:06 +0000312 unsigned opt;
Denis Vlasenko1d426652008-03-17 09:09:09 +0000313 char *str_timeout;
Bernhard Reutner-Fischera0f75e22006-04-03 11:52:01 +0000314
Denys Vlasenkof5d50fb2018-02-11 13:27:54 +0100315 opt = GETOPT32(str_timeout, device, source);
316 if (opt & TIMEOUT)
Denis Vlasenkoa09300a2007-11-25 12:40:56 +0000317 timeout_us = xatou_range(str_timeout, 0, INT_MAX/2000000) * 1000000 + 500000;
Glenn L McGrath9e598412003-01-09 10:06:01 +0000318 }
Glenn L McGrath9e598412003-01-09 10:06:01 +0000319
Denis Vlasenko459be352007-06-17 19:09:05 +0000320 target = argv[optind];
Alexander Korolkov748fb602015-03-12 13:05:33 +0100321 err_str = xasprintf("interface %s %%s", device);
Denis Vlasenko40920822006-10-03 20:28:06 +0000322 xfunc_error_retval = 2;
Glenn L McGrath9e598412003-01-09 10:06:01 +0000323
Denys Vlasenkod3162772018-02-11 14:35:05 +0100324 /*memset(&G.ifr, 0, sizeof(G.ifr)); - zeroed by INIT_G */
325 strncpy_IFNAMSIZ(G.ifr.ifr_name, device);
326 ioctl_or_perror_and_die(sock_fd, SIOCGIFINDEX, &G.ifr, err_str, "not found");
327 me.sll_ifindex = G.ifr.ifr_ifindex;
Glenn L McGrath9e598412003-01-09 10:06:01 +0000328
Denys Vlasenkod3162772018-02-11 14:35:05 +0100329 xioctl(sock_fd, SIOCGIFFLAGS, (char *) &G.ifr);
Glenn L McGrath9e598412003-01-09 10:06:01 +0000330
Denys Vlasenkod3162772018-02-11 14:35:05 +0100331 if (!(G.ifr.ifr_flags & IFF_UP)) {
332 bb_error_msg_and_die(err_str, "is down");
333 }
334 if (G.ifr.ifr_flags & (IFF_NOARP | IFF_LOOPBACK)) {
335 bb_error_msg(err_str, "is not ARPable");
336 BUILD_BUG_ON(DAD != 2);
337 /* exit 0 if DAD, else exit 2 */
338 return (~option_mask32 & DAD);
Glenn L McGrath9e598412003-01-09 10:06:01 +0000339 }
340
Denis Vlasenkoa09300a2007-11-25 12:40:56 +0000341 /* if (!inet_aton(target, &dst)) - not needed */ {
Denis Vlasenko90ec4dc2007-01-25 19:44:38 +0000342 len_and_sockaddr *lsa;
Denis Vlasenko42823d52007-02-04 02:39:08 +0000343 lsa = xhost_and_af2sockaddr(target, 0, AF_INET);
Denis Vlasenkoefb545b2008-12-08 22:56:18 +0000344 dst = lsa->u.sin.sin_addr;
Denis Vlasenko90ec4dc2007-01-25 19:44:38 +0000345 if (ENABLE_FEATURE_CLEAN_UP)
346 free(lsa);
Glenn L McGrath9e598412003-01-09 10:06:01 +0000347 }
348
Glenn L McGratha837e2d2003-02-09 07:01:33 +0000349 if (source && !inet_aton(source, &src)) {
Rob Landley8ea52052006-03-30 21:50:57 +0000350 bb_error_msg_and_die("invalid source address %s", source);
Glenn L McGrath9e598412003-01-09 10:06:01 +0000351 }
352
Denis Vlasenkoa09300a2007-11-25 12:40:56 +0000353 if ((option_mask32 & (DAD|UNSOLICITED)) == UNSOLICITED && src.s_addr == 0)
Glenn L McGrath9e598412003-01-09 10:06:01 +0000354 src = dst;
355
Denis Vlasenkobd7bb292007-06-17 23:40:26 +0000356 if (!(option_mask32 & DAD) || src.s_addr) {
Denys Vlasenkob5257a62018-02-11 21:16:24 +0100357 /*struct sockaddr_in probe_saddr;*/
Denis Vlasenko27af5a02006-09-03 12:21:59 +0000358 int probe_fd = xsocket(AF_INET, SOCK_DGRAM, 0);
Glenn L McGrath9e598412003-01-09 10:06:01 +0000359
Denis Vlasenkoe5373852008-12-10 11:12:16 +0000360 setsockopt_bindtodevice(probe_fd, device);
Denys Vlasenkob5257a62018-02-11 21:16:24 +0100361
362 /*memset(&G.probe_saddr, 0, sizeof(G.probe_saddr)); - zeroed by INIT_G */
363 G.probe_saddr.sin_family = AF_INET;
Glenn L McGrath9e598412003-01-09 10:06:01 +0000364 if (src.s_addr) {
Denis Vlasenkoa09300a2007-11-25 12:40:56 +0000365 /* Check that this is indeed our IP */
Denys Vlasenkob5257a62018-02-11 21:16:24 +0100366 G.probe_saddr.sin_addr = src;
367 xbind(probe_fd, (struct sockaddr *) &G.probe_saddr, sizeof(G.probe_saddr));
Denis Vlasenkoa09300a2007-11-25 12:40:56 +0000368 } else { /* !(option_mask32 & DAD) case */
369 /* Find IP address on this iface */
Denys Vlasenkob5257a62018-02-11 21:16:24 +0100370 G.probe_saddr.sin_port = htons(1025);
371 G.probe_saddr.sin_addr = dst;
Glenn L McGrath9e598412003-01-09 10:06:01 +0000372
Denys Vlasenkoc52cbea2015-08-24 19:48:03 +0200373 if (setsockopt_SOL_SOCKET_1(probe_fd, SO_DONTROUTE) != 0)
Denys Vlasenko2db782b2015-08-24 19:08:14 +0200374 bb_perror_msg("setsockopt(%s)", "SO_DONTROUTE");
Denys Vlasenkob5257a62018-02-11 21:16:24 +0100375 xconnect(probe_fd, (struct sockaddr *) &G.probe_saddr, sizeof(G.probe_saddr));
376 bb_getsockname(probe_fd, (struct sockaddr *) &G.probe_saddr, sizeof(G.probe_saddr));
377 if (G.probe_saddr.sin_family != AF_INET)
James Byrne69374872019-07-02 11:35:03 +0200378 bb_simple_error_msg_and_die("no IP address configured");
Denys Vlasenkob5257a62018-02-11 21:16:24 +0100379 src = G.probe_saddr.sin_addr;
Glenn L McGrath9e598412003-01-09 10:06:01 +0000380 }
381 close(probe_fd);
Denis Vlasenko1dc1b372006-12-23 02:48:44 +0000382 }
Glenn L McGrath9e598412003-01-09 10:06:01 +0000383
384 me.sll_family = AF_PACKET;
Denis Vlasenkoa09300a2007-11-25 12:40:56 +0000385 //me.sll_ifindex = ifindex; - done before
Glenn L McGrath9e598412003-01-09 10:06:01 +0000386 me.sll_protocol = htons(ETH_P_ARP);
Denis Vlasenkoa09300a2007-11-25 12:40:56 +0000387 xbind(sock_fd, (struct sockaddr *) &me, sizeof(me));
Glenn L McGrath9e598412003-01-09 10:06:01 +0000388
Denys Vlasenkoba3b9db2018-02-11 14:55:46 +0100389 bb_getsockname(sock_fd, (struct sockaddr *) &me, sizeof(me));
390 //never happens:
391 //if (getsockname(sock_fd, (struct sockaddr *) &me, &alen) == -1)
392 // bb_perror_msg_and_die("getsockname");
Glenn L McGrath9e598412003-01-09 10:06:01 +0000393 if (me.sll_halen == 0) {
Bernhard Reutner-Fischerf536b992008-02-11 13:26:54 +0000394 bb_error_msg(err_str, "is not ARPable (no ll address)");
Denys Vlasenkof5d50fb2018-02-11 13:27:54 +0100395 BUILD_BUG_ON(DAD != 2);
396 /* exit 0 if DAD, else exit 2 */
397 return (~option_mask32 & DAD);
Glenn L McGrath9e598412003-01-09 10:06:01 +0000398 }
399 he = me;
400 memset(he.sll_addr, -1, he.sll_halen);
401
Denis Vlasenkobd7bb292007-06-17 23:40:26 +0000402 if (!(option_mask32 & QUIET)) {
Denis Vlasenkoa09300a2007-11-25 12:40:56 +0000403 /* inet_ntoa uses static storage, can't use in same printf */
Denys Vlasenkoa3ec3bd2018-02-11 13:37:07 +0100404 printf("ARPING %s", inet_ntoa(dst));
405 printf(" from %s %s\n", inet_ntoa(src), device);
Glenn L McGratha837e2d2003-02-09 07:01:33 +0000406 }
Glenn L McGrath9e598412003-01-09 10:06:01 +0000407
Denys Vlasenkod3162772018-02-11 14:35:05 +0100408 /*sigemptyset(&G.sset); - zeroed by INIT_G */
409 sigaddset(&G.sset, SIGALRM);
410 sigaddset(&G.sset, SIGINT);
Denis Vlasenko8e2cfec2008-03-12 23:19:35 +0000411 signal_SA_RESTART_empty_mask(SIGINT, (void (*)(int))finish);
412 signal_SA_RESTART_empty_mask(SIGALRM, (void (*)(int))catcher);
Glenn L McGrath9e598412003-01-09 10:06:01 +0000413
Denys Vlasenkoe015d062018-02-11 13:48:52 +0100414 /* Send the first packet, arm ALRM */
Glenn L McGrath9e598412003-01-09 10:06:01 +0000415 catcher();
416
417 while (1) {
Glenn L McGrath9e598412003-01-09 10:06:01 +0000418 struct sockaddr_ll from;
Eric Andersen0cb6f352006-01-30 22:30:41 +0000419 socklen_t alen = sizeof(from);
Glenn L McGrath9e598412003-01-09 10:06:01 +0000420 int cc;
421
Denys Vlasenkoe015d062018-02-11 13:48:52 +0100422 /* Unblock SIGALRM so that the previously called alarm()
423 * can prevent recvfrom from blocking forever in case the
424 * inherited procmask is blocking SIGALRM.
425 */
Denys Vlasenkod3162772018-02-11 14:35:05 +0100426 sigprocmask(SIG_UNBLOCK, &G.sset, NULL);
Denys Vlasenkoe015d062018-02-11 13:48:52 +0100427
Denys Vlasenkod3162772018-02-11 14:35:05 +0100428 cc = recvfrom(sock_fd, G.packet, sizeof(G.packet), 0, (struct sockaddr *) &from, &alen);
Denys Vlasenkoe015d062018-02-11 13:48:52 +0100429
430 /* Don't allow SIGALRMs while we process the reply */
Denys Vlasenkod3162772018-02-11 14:35:05 +0100431 sigprocmask(SIG_BLOCK, &G.sset, NULL);
Denis Vlasenko1dc1b372006-12-23 02:48:44 +0000432 if (cc < 0) {
James Byrne69374872019-07-02 11:35:03 +0200433 bb_simple_perror_msg("recvfrom");
Glenn L McGrath9e598412003-01-09 10:06:01 +0000434 continue;
435 }
Denys Vlasenkod3162772018-02-11 14:35:05 +0100436 recv_pack(G.packet, cc, &from);
Glenn L McGrath9e598412003-01-09 10:06:01 +0000437 }
438}