1 /* vi: set sw=4 ts=4: */
3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
5 * Author: Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
6 * Busybox port: Nick Fedchik <nick@fedchik.org.ua>
9 //usage:#define arping_trivial_usage
10 //usage: "[-fqbDUA] [-c CNT] [-w TIMEOUT] [-I IFACE] [-s SRC_IP] DST_IP"
11 //usage:#define arping_full_usage "\n\n"
12 //usage: "Send ARP requests/replies\n"
13 //usage: "\n -f Quit on first ARP reply"
14 //usage: "\n -q Quiet"
15 //usage: "\n -b Keep broadcasting, don't go unicast"
16 //usage: "\n -D Exit with 1 if DST_IP replies"
17 //usage: "\n -U Unsolicited ARP mode, update your neighbors"
18 //usage: "\n -A ARP answer mode, update your neighbors"
19 //usage: "\n -c N Stop after sending N ARP requests"
20 //usage: "\n -w TIMEOUT Seconds to wait for ARP reply"
21 //usage: "\n -I IFACE Interface to use (default eth0)"
22 //usage: "\n -s SRC_IP Sender IP address"
23 //usage: "\n DST_IP Target IP address"
25 #include <arpa/inet.h>
27 #include <netinet/ether.h>
28 #include <netpacket/packet.h>
31 #include "common_bufsiz.h"
33 /* We don't expect to see 1000+ seconds delay, unsigned is enough */
34 #define MONOTONIC_US() ((unsigned)monotonic_us())
49 struct sockaddr_ll me
;
50 struct sockaddr_ll he
;
64 #define G (*(struct globals*)bb_common_bufsiz1)
69 #define sock_fd (G.sock_fd )
70 #define count (G.count )
71 #define last (G.last )
72 #define timeout_us (G.timeout_us)
73 #define start (G.start )
74 #define sent (G.sent )
75 #define brd_sent (G.brd_sent )
76 #define received (G.received )
77 #define brd_recv (G.brd_recv )
78 #define req_recv (G.req_recv )
79 #define INIT_G() do { \
80 setup_common_bufsiz(); \
84 // If GNUisms are not available...
85 //static void *mempcpy(void *_dst, const void *_src, int n)
87 // memcpy(_dst, _src, n);
88 // return (char*)_dst + n;
91 static int send_pack(struct in_addr
*src_addr
,
92 struct in_addr
*dst_addr
, struct sockaddr_ll
*ME
,
93 struct sockaddr_ll
*HE
)
96 unsigned char buf
[256];
97 struct arphdr
*ah
= (struct arphdr
*) buf
;
98 unsigned char *p
= (unsigned char *) (ah
+ 1);
100 ah
->ar_hrd
= htons(ARPHRD_ETHER
);
101 ah
->ar_pro
= htons(ETH_P_IP
);
102 ah
->ar_hln
= ME
->sll_halen
;
104 ah
->ar_op
= option_mask32
& ADVERT
? htons(ARPOP_REPLY
) : htons(ARPOP_REQUEST
);
106 p
= mempcpy(p
, &ME
->sll_addr
, ah
->ar_hln
);
107 p
= mempcpy(p
, src_addr
, 4);
109 if (option_mask32
& ADVERT
)
110 p
= mempcpy(p
, &ME
->sll_addr
, ah
->ar_hln
);
112 p
= mempcpy(p
, &HE
->sll_addr
, ah
->ar_hln
);
114 p
= mempcpy(p
, dst_addr
, 4);
116 err
= sendto(sock_fd
, buf
, p
- buf
, 0, (struct sockaddr
*) HE
, sizeof(*HE
));
117 if (err
== p
- buf
) {
118 last
= MONOTONIC_US();
120 if (!(option_mask32
& UNICASTING
))
126 static void finish(void) NORETURN
;
127 static void finish(void)
129 if (!(option_mask32
& QUIET
)) {
130 printf("Sent %u probe(s) (%u broadcast(s))\n"
132 " (%u request(s), %u broadcast(s))\n",
134 received
, (received
== 1) ? "ies" : "y",
137 if (option_mask32
& DAD
)
139 if (option_mask32
& UNSOLICITED
)
144 static void catcher(void)
148 now
= MONOTONIC_US();
152 if (count
== 0 || (timeout_us
&& (now
- start
) > timeout_us
))
155 /* count < 0 means "infinite count" */
159 if (last
== 0 || (now
- last
) > 500000) {
160 send_pack(&src
, &dst
, &me
, &he
);
161 if (count
== 0 && (option_mask32
& UNSOLICITED
))
167 static void recv_pack(unsigned char *buf
, int len
, struct sockaddr_ll
*FROM
)
169 struct arphdr
*ah
= (struct arphdr
*) buf
;
170 unsigned char *p
= (unsigned char *) (ah
+ 1);
171 struct in_addr src_ip
, dst_ip
;
172 /* moves below assume in_addr is 4 bytes big, ensure that */
173 struct BUG_in_addr_must_be_4
{
174 char BUG_in_addr_must_be_4
[
175 sizeof(struct in_addr
) == 4 ? 1 : -1
177 char BUG_s_addr_must_be_4
[
178 sizeof(src_ip
.s_addr
) == 4 ? 1 : -1
182 /* Filter out wild packets */
183 if (FROM
->sll_pkttype
!= PACKET_HOST
184 && FROM
->sll_pkttype
!= PACKET_BROADCAST
185 && FROM
->sll_pkttype
!= PACKET_MULTICAST
)
188 /* Only these types are recognized */
189 if (ah
->ar_op
!= htons(ARPOP_REQUEST
) && ah
->ar_op
!= htons(ARPOP_REPLY
))
192 /* ARPHRD check and this darned FDDI hack here :-( */
193 if (ah
->ar_hrd
!= htons(FROM
->sll_hatype
)
194 && (FROM
->sll_hatype
!= ARPHRD_FDDI
|| ah
->ar_hrd
!= htons(ARPHRD_ETHER
)))
197 /* Protocol must be IP. */
198 if (ah
->ar_pro
!= htons(ETH_P_IP
)
200 || (ah
->ar_hln
!= me
.sll_halen
)
201 || (len
< (int)(sizeof(*ah
) + 2 * (4 + ah
->ar_hln
))))
204 move_from_unaligned32(src_ip
.s_addr
, p
+ ah
->ar_hln
);
205 move_from_unaligned32(dst_ip
.s_addr
, p
+ ah
->ar_hln
+ 4 + ah
->ar_hln
);
207 if (dst
.s_addr
!= src_ip
.s_addr
)
209 if (!(option_mask32
& DAD
)) {
210 if ((src
.s_addr
!= dst_ip
.s_addr
)
211 || (memcmp(p
+ ah
->ar_hln
+ 4, &me
.sll_addr
, ah
->ar_hln
)))
215 src_ip = 0 (or some src)
217 dst_ip = tested address
220 We fail, if receive request/reply with:
221 src_ip = tested_address
223 if src_ip in request was not zero, check
224 also that it matches to dst_ip, otherwise
225 dst_ip/dst_hw do not matter.
227 if ((memcmp(p
, &me
.sll_addr
, me
.sll_halen
) == 0)
228 || (src
.s_addr
&& src
.s_addr
!= dst_ip
.s_addr
))
231 if (!(option_mask32
& QUIET
)) {
234 printf("%scast re%s from %s [%02x:%02x:%02x:%02x:%02x:%02x]",
235 FROM
->sll_pkttype
== PACKET_HOST
? "Uni" : "Broad",
236 ah
->ar_op
== htons(ARPOP_REPLY
) ? "ply" : "quest",
238 p
[0], p
[1], p
[2], p
[3], p
[4], p
[5]
240 if (dst_ip
.s_addr
!= src
.s_addr
) {
241 printf("for %s ", inet_ntoa(dst_ip
));
244 if (memcmp(p
+ ah
->ar_hln
+ 4, me
.sll_addr
, ah
->ar_hln
)) {
245 unsigned char *pp
= p
+ ah
->ar_hln
+ 4;
248 printf("[%02x:%02x:%02x:%02x:%02x:%02x]",
249 pp
[0], pp
[1], pp
[2], pp
[3], pp
[4], pp
[5]
254 unsigned diff
= MONOTONIC_US() - last
;
255 printf(" %u.%03ums\n", diff
/ 1000, diff
% 1000);
257 puts(" UNSOLICITED?");
262 if (FROM
->sll_pkttype
!= PACKET_HOST
)
264 if (ah
->ar_op
== htons(ARPOP_REQUEST
))
266 if (option_mask32
& QUIT_ON_REPLY
)
268 if (!(option_mask32
& BCAST_ONLY
)) {
269 memcpy(he
.sll_addr
, p
, me
.sll_halen
);
270 option_mask32
|= UNICASTING
;
274 int arping_main(int argc
, char **argv
) MAIN_EXTERNALLY_VISIBLE
;
275 int arping_main(int argc UNUSED_PARAM
, char **argv
)
277 const char *device
= "eth0";
280 unsigned char *packet
;
285 sock_fd
= xsocket(AF_PACKET
, SOCK_DGRAM
, 0);
287 // Drop suid root privileges
288 // Need to remove SUID_NEVER from applets.h for this to work
295 /* Dad also sets quit_on_reply.
296 * Advert also sets unsolicited.
298 opt_complementary
= "=1:Df:AU:c+";
299 opt
= getopt32(argv
, "DUAqfbc:w:I:s:",
300 &count
, &str_timeout
, &device
, &source
);
301 if (opt
& 0x80) /* -w: timeout */
302 timeout_us
= xatou_range(str_timeout
, 0, INT_MAX
/2000000) * 1000000 + 500000;
303 //if (opt & 0x200) /* -s: source */
304 option_mask32
&= 0x3f; /* set respective flags */
307 target
= argv
[optind
];
308 err_str
= xasprintf("interface %s %%s", device
);
309 xfunc_error_retval
= 2;
314 memset(&ifr
, 0, sizeof(ifr
));
315 strncpy_IFNAMSIZ(ifr
.ifr_name
, device
);
316 /* We use ifr.ifr_name in error msg so that problem
317 * with truncated name will be visible */
318 ioctl_or_perror_and_die(sock_fd
, SIOCGIFINDEX
, &ifr
, err_str
, "not found");
319 me
.sll_ifindex
= ifr
.ifr_ifindex
;
321 xioctl(sock_fd
, SIOCGIFFLAGS
, (char *) &ifr
);
323 if (!(ifr
.ifr_flags
& IFF_UP
)) {
324 bb_error_msg_and_die(err_str
, "is down");
326 if (ifr
.ifr_flags
& (IFF_NOARP
| IFF_LOOPBACK
)) {
327 bb_error_msg(err_str
, "is not ARPable");
328 return (option_mask32
& DAD
? 0 : 2);
332 /* if (!inet_aton(target, &dst)) - not needed */ {
333 len_and_sockaddr
*lsa
;
334 lsa
= xhost_and_af2sockaddr(target
, 0, AF_INET
);
335 dst
= lsa
->u
.sin
.sin_addr
;
336 if (ENABLE_FEATURE_CLEAN_UP
)
340 if (source
&& !inet_aton(source
, &src
)) {
341 bb_error_msg_and_die("invalid source address %s", source
);
344 if ((option_mask32
& (DAD
|UNSOLICITED
)) == UNSOLICITED
&& src
.s_addr
== 0)
347 if (!(option_mask32
& DAD
) || src
.s_addr
) {
348 struct sockaddr_in saddr
;
349 int probe_fd
= xsocket(AF_INET
, SOCK_DGRAM
, 0);
351 setsockopt_bindtodevice(probe_fd
, device
);
352 memset(&saddr
, 0, sizeof(saddr
));
353 saddr
.sin_family
= AF_INET
;
355 /* Check that this is indeed our IP */
356 saddr
.sin_addr
= src
;
357 xbind(probe_fd
, (struct sockaddr
*) &saddr
, sizeof(saddr
));
358 } else { /* !(option_mask32 & DAD) case */
359 /* Find IP address on this iface */
360 socklen_t alen
= sizeof(saddr
);
362 saddr
.sin_port
= htons(1025);
363 saddr
.sin_addr
= dst
;
365 if (setsockopt_SOL_SOCKET_1(probe_fd
, SO_DONTROUTE
) != 0)
366 bb_perror_msg("setsockopt(%s)", "SO_DONTROUTE");
367 xconnect(probe_fd
, (struct sockaddr
*) &saddr
, sizeof(saddr
));
368 getsockname(probe_fd
, (struct sockaddr
*) &saddr
, &alen
);
370 //if (getsockname(probe_fd, (struct sockaddr *) &saddr, &alen) == -1)
371 // bb_perror_msg_and_die("getsockname");
372 if (saddr
.sin_family
!= AF_INET
)
373 bb_error_msg_and_die("no IP address configured");
374 src
= saddr
.sin_addr
;
379 me
.sll_family
= AF_PACKET
;
380 //me.sll_ifindex = ifindex; - done before
381 me
.sll_protocol
= htons(ETH_P_ARP
);
382 xbind(sock_fd
, (struct sockaddr
*) &me
, sizeof(me
));
385 socklen_t alen
= sizeof(me
);
386 getsockname(sock_fd
, (struct sockaddr
*) &me
, &alen
);
388 //if (getsockname(sock_fd, (struct sockaddr *) &me, &alen) == -1)
389 // bb_perror_msg_and_die("getsockname");
391 if (me
.sll_halen
== 0) {
392 bb_error_msg(err_str
, "is not ARPable (no ll address)");
393 return (option_mask32
& DAD
? 0 : 2);
396 memset(he
.sll_addr
, -1, he
.sll_halen
);
398 if (!(option_mask32
& QUIET
)) {
399 /* inet_ntoa uses static storage, can't use in same printf */
400 printf("ARPING to %s", inet_ntoa(dst
));
401 printf(" from %s via %s\n", inet_ntoa(src
), device
);
404 signal_SA_RESTART_empty_mask(SIGINT
, (void (*)(int))finish
);
405 signal_SA_RESTART_empty_mask(SIGALRM
, (void (*)(int))catcher
);
409 packet
= xmalloc(4096);
411 sigset_t sset
, osset
;
412 struct sockaddr_ll from
;
413 socklen_t alen
= sizeof(from
);
416 cc
= recvfrom(sock_fd
, packet
, 4096, 0, (struct sockaddr
*) &from
, &alen
);
418 bb_perror_msg("recvfrom");
422 sigaddset(&sset
, SIGALRM
);
423 sigaddset(&sset
, SIGINT
);
424 sigprocmask(SIG_BLOCK
, &sset
, &osset
);
425 recv_pack(packet
, cc
, &from
);
426 sigprocmask(SIG_SETMASK
, &osset
, NULL
);