1 /* vi: set sw=4 ts=4: */
3 * arping.c - Ping hosts by ARP requests/replies
5 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
7 * Author: Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
8 * Busybox port: Nick Fedchik <nick@fedchik.org.ua>
11 #include <arpa/inet.h>
13 #include <netinet/ether.h>
14 #include <netpacket/packet.h>
18 /* We don't expect to see 1000+ seconds delay, unsigned is enough */
19 #define MONOTONIC_US() ((unsigned)monotonic_us())
34 struct sockaddr_ll me
;
35 struct sockaddr_ll he
;
49 #define G (*(struct globals*)&bb_common_bufsiz1)
54 #define sock_fd (G.sock_fd )
55 #define count (G.count )
56 #define last (G.last )
57 #define timeout_us (G.timeout_us)
58 #define start (G.start )
59 #define sent (G.sent )
60 #define brd_sent (G.brd_sent )
61 #define received (G.received )
62 #define brd_recv (G.brd_recv )
63 #define req_recv (G.req_recv )
64 #define INIT_G() do { \
68 // If GNUisms are not available...
69 //static void *mempcpy(void *_dst, const void *_src, int n)
71 // memcpy(_dst, _src, n);
72 // return (char*)_dst + n;
75 static int send_pack(struct in_addr
*src_addr
,
76 struct in_addr
*dst_addr
, struct sockaddr_ll
*ME
,
77 struct sockaddr_ll
*HE
)
80 unsigned char buf
[256];
81 struct arphdr
*ah
= (struct arphdr
*) buf
;
82 unsigned char *p
= (unsigned char *) (ah
+ 1);
84 ah
->ar_hrd
= htons(ARPHRD_ETHER
);
85 ah
->ar_pro
= htons(ETH_P_IP
);
86 ah
->ar_hln
= ME
->sll_halen
;
88 ah
->ar_op
= option_mask32
& ADVERT
? htons(ARPOP_REPLY
) : htons(ARPOP_REQUEST
);
90 p
= mempcpy(p
, &ME
->sll_addr
, ah
->ar_hln
);
91 p
= mempcpy(p
, src_addr
, 4);
93 if (option_mask32
& ADVERT
)
94 p
= mempcpy(p
, &ME
->sll_addr
, ah
->ar_hln
);
96 p
= mempcpy(p
, &HE
->sll_addr
, ah
->ar_hln
);
98 p
= mempcpy(p
, dst_addr
, 4);
100 err
= sendto(sock_fd
, buf
, p
- buf
, 0, (struct sockaddr
*) HE
, sizeof(*HE
));
101 if (err
== p
- buf
) {
102 last
= MONOTONIC_US();
104 if (!(option_mask32
& UNICASTING
))
110 static void finish(void) NORETURN
;
111 static void finish(void)
113 if (!(option_mask32
& QUIET
)) {
114 printf("Sent %u probe(s) (%u broadcast(s))\n"
116 " (%u request(s), %u broadcast(s))\n",
118 received
, (received
== 1) ? "ies" : "y",
121 if (option_mask32
& DAD
)
123 if (option_mask32
& UNSOLICITED
)
128 static void catcher(void)
132 now
= MONOTONIC_US();
136 if (count
== 0 || (timeout_us
&& (now
- start
) > timeout_us
))
139 /* count < 0 means "infinite count" */
143 if (last
== 0 || (now
- last
) > 500000) {
144 send_pack(&src
, &dst
, &me
, &he
);
145 if (count
== 0 && (option_mask32
& UNSOLICITED
))
151 static bool recv_pack(unsigned char *buf
, int len
, struct sockaddr_ll
*FROM
)
153 struct arphdr
*ah
= (struct arphdr
*) buf
;
154 unsigned char *p
= (unsigned char *) (ah
+ 1);
155 struct in_addr src_ip
, dst_ip
;
156 /* moves below assume in_addr is 4 bytes big, ensure that */
157 struct BUG_in_addr_must_be_4
{
158 char BUG_in_addr_must_be_4
[
159 sizeof(struct in_addr
) == 4 ? 1 : -1
161 char BUG_s_addr_must_be_4
[
162 sizeof(src_ip
.s_addr
) == 4 ? 1 : -1
166 /* Filter out wild packets */
167 if (FROM
->sll_pkttype
!= PACKET_HOST
168 && FROM
->sll_pkttype
!= PACKET_BROADCAST
169 && FROM
->sll_pkttype
!= PACKET_MULTICAST
)
172 /* Only these types are recognised */
173 if (ah
->ar_op
!= htons(ARPOP_REQUEST
) && ah
->ar_op
!= htons(ARPOP_REPLY
))
176 /* ARPHRD check and this darned FDDI hack here :-( */
177 if (ah
->ar_hrd
!= htons(FROM
->sll_hatype
)
178 && (FROM
->sll_hatype
!= ARPHRD_FDDI
|| ah
->ar_hrd
!= htons(ARPHRD_ETHER
)))
181 /* Protocol must be IP. */
182 if (ah
->ar_pro
!= htons(ETH_P_IP
)
184 || (ah
->ar_hln
!= me
.sll_halen
)
185 || (len
< (int)(sizeof(*ah
) + 2 * (4 + ah
->ar_hln
))))
188 move_from_unaligned32(src_ip
.s_addr
, p
+ ah
->ar_hln
);
189 move_from_unaligned32(dst_ip
.s_addr
, p
+ ah
->ar_hln
+ 4 + ah
->ar_hln
);
191 if (dst
.s_addr
!= src_ip
.s_addr
)
193 if (!(option_mask32
& DAD
)) {
194 if ((src
.s_addr
!= dst_ip
.s_addr
)
195 || (memcmp(p
+ ah
->ar_hln
+ 4, &me
.sll_addr
, ah
->ar_hln
)))
199 src_ip = 0 (or some src)
201 dst_ip = tested address
204 We fail, if receive request/reply with:
205 src_ip = tested_address
207 if src_ip in request was not zero, check
208 also that it matches to dst_ip, otherwise
209 dst_ip/dst_hw do not matter.
211 if ((memcmp(p
, &me
.sll_addr
, me
.sll_halen
) == 0)
212 || (src
.s_addr
&& src
.s_addr
!= dst_ip
.s_addr
))
215 if (!(option_mask32
& QUIET
)) {
218 printf("%scast re%s from %s [%s]",
219 FROM
->sll_pkttype
== PACKET_HOST
? "Uni" : "Broad",
220 ah
->ar_op
== htons(ARPOP_REPLY
) ? "ply" : "quest",
222 ether_ntoa((struct ether_addr
*) p
));
223 if (dst_ip
.s_addr
!= src
.s_addr
) {
224 printf("for %s ", inet_ntoa(dst_ip
));
227 if (memcmp(p
+ ah
->ar_hln
+ 4, me
.sll_addr
, ah
->ar_hln
)) {
231 ether_ntoa((struct ether_addr
*) p
+ ah
->ar_hln
+ 4));
235 unsigned diff
= MONOTONIC_US() - last
;
236 printf(" %u.%03ums\n", diff
/ 1000, diff
% 1000);
238 printf(" UNSOLICITED?\n");
243 if (FROM
->sll_pkttype
!= PACKET_HOST
)
245 if (ah
->ar_op
== htons(ARPOP_REQUEST
))
247 if (option_mask32
& QUIT_ON_REPLY
)
249 if (!(option_mask32
& BCAST_ONLY
)) {
250 memcpy(he
.sll_addr
, p
, me
.sll_halen
);
251 option_mask32
|= UNICASTING
;
256 int arping_main(int argc
, char **argv
) MAIN_EXTERNALLY_VISIBLE
;
257 int arping_main(int argc UNUSED_PARAM
, char **argv
)
259 const char *device
= "eth0";
262 unsigned char *packet
;
267 sock_fd
= xsocket(AF_PACKET
, SOCK_DGRAM
, 0);
269 // Drop suid root privileges
270 // Need to remove SUID_NEVER from applets.h for this to work
273 err_str
= xasprintf("interface %s %%s", device
);
278 /* Dad also sets quit_on_reply.
279 * Advert also sets unsolicited.
281 opt_complementary
= "=1:Df:AU:c+";
282 opt
= getopt32(argv
, "DUAqfbc:w:I:s:",
283 &count
, &str_timeout
, &device
, &source
);
284 if (opt
& 0x80) /* -w: timeout */
285 timeout_us
= xatou_range(str_timeout
, 0, INT_MAX
/2000000) * 1000000 + 500000;
286 //if (opt & 0x200) /* -s: source */
287 option_mask32
&= 0x3f; /* set respective flags */
290 target
= argv
[optind
];
292 xfunc_error_retval
= 2;
297 memset(&ifr
, 0, sizeof(ifr
));
298 strncpy_IFNAMSIZ(ifr
.ifr_name
, device
);
299 /* We use ifr.ifr_name in error msg so that problem
300 * with truncated name will be visible */
301 ioctl_or_perror_and_die(sock_fd
, SIOCGIFINDEX
, &ifr
, err_str
, "not found");
302 me
.sll_ifindex
= ifr
.ifr_ifindex
;
304 xioctl(sock_fd
, SIOCGIFFLAGS
, (char *) &ifr
);
306 if (!(ifr
.ifr_flags
& IFF_UP
)) {
307 bb_error_msg_and_die(err_str
, "is down");
309 if (ifr
.ifr_flags
& (IFF_NOARP
| IFF_LOOPBACK
)) {
310 bb_error_msg(err_str
, "is not ARPable");
311 return (option_mask32
& DAD
? 0 : 2);
315 /* if (!inet_aton(target, &dst)) - not needed */ {
316 len_and_sockaddr
*lsa
;
317 lsa
= xhost_and_af2sockaddr(target
, 0, AF_INET
);
318 dst
= lsa
->u
.sin
.sin_addr
;
319 if (ENABLE_FEATURE_CLEAN_UP
)
323 if (source
&& !inet_aton(source
, &src
)) {
324 bb_error_msg_and_die("invalid source address %s", source
);
327 if ((option_mask32
& (DAD
|UNSOLICITED
)) == UNSOLICITED
&& src
.s_addr
== 0)
330 if (!(option_mask32
& DAD
) || src
.s_addr
) {
331 struct sockaddr_in saddr
;
332 int probe_fd
= xsocket(AF_INET
, SOCK_DGRAM
, 0);
334 setsockopt_bindtodevice(probe_fd
, device
);
335 memset(&saddr
, 0, sizeof(saddr
));
336 saddr
.sin_family
= AF_INET
;
338 /* Check that this is indeed our IP */
339 saddr
.sin_addr
= src
;
340 xbind(probe_fd
, (struct sockaddr
*) &saddr
, sizeof(saddr
));
341 } else { /* !(option_mask32 & DAD) case */
342 /* Find IP address on this iface */
343 socklen_t alen
= sizeof(saddr
);
345 saddr
.sin_port
= htons(1025);
346 saddr
.sin_addr
= dst
;
348 if (setsockopt(probe_fd
, SOL_SOCKET
, SO_DONTROUTE
, &const_int_1
, sizeof(const_int_1
)) == -1)
349 bb_perror_msg("setsockopt(SO_DONTROUTE)");
350 xconnect(probe_fd
, (struct sockaddr
*) &saddr
, sizeof(saddr
));
351 if (getsockname(probe_fd
, (struct sockaddr
*) &saddr
, &alen
) == -1) {
352 bb_perror_msg_and_die("getsockname");
354 if (saddr
.sin_family
!= AF_INET
)
355 bb_error_msg_and_die("no IP address configured");
356 src
= saddr
.sin_addr
;
361 me
.sll_family
= AF_PACKET
;
362 //me.sll_ifindex = ifindex; - done before
363 me
.sll_protocol
= htons(ETH_P_ARP
);
364 xbind(sock_fd
, (struct sockaddr
*) &me
, sizeof(me
));
367 socklen_t alen
= sizeof(me
);
369 if (getsockname(sock_fd
, (struct sockaddr
*) &me
, &alen
) == -1) {
370 bb_perror_msg_and_die("getsockname");
373 if (me
.sll_halen
== 0) {
374 bb_error_msg(err_str
, "is not ARPable (no ll address)");
375 return (option_mask32
& DAD
? 0 : 2);
378 memset(he
.sll_addr
, -1, he
.sll_halen
);
380 if (!(option_mask32
& QUIET
)) {
381 /* inet_ntoa uses static storage, can't use in same printf */
382 printf("ARPING to %s", inet_ntoa(dst
));
383 printf(" from %s via %s\n", inet_ntoa(src
), device
);
386 signal_SA_RESTART_empty_mask(SIGINT
, (void (*)(int))finish
);
387 signal_SA_RESTART_empty_mask(SIGALRM
, (void (*)(int))catcher
);
391 packet
= xmalloc(4096);
393 sigset_t sset
, osset
;
394 struct sockaddr_ll from
;
395 socklen_t alen
= sizeof(from
);
398 cc
= recvfrom(sock_fd
, packet
, 4096, 0, (struct sockaddr
*) &from
, &alen
);
400 bb_perror_msg("recvfrom");
404 sigaddset(&sset
, SIGALRM
);
405 sigaddset(&sset
, SIGINT
);
406 sigprocmask(SIG_BLOCK
, &sset
, &osset
);
407 recv_pack(packet
, cc
, &from
);
408 sigprocmask(SIG_SETMASK
, &osset
, NULL
);