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>
11 #include <netinet/ether.h>
12 #include <netpacket/packet.h>
16 /* We don't expect to see 1000+ seconds delay, unsigned is enough */
17 #define MONOTONIC_US() ((unsigned)monotonic_us())
32 struct sockaddr_ll me
;
33 struct sockaddr_ll he
;
47 #define G (*(struct globals*)&bb_common_bufsiz1)
52 #define sock_fd (G.sock_fd )
53 #define count (G.count )
54 #define last (G.last )
55 #define timeout_us (G.timeout_us)
56 #define start (G.start )
57 #define sent (G.sent )
58 #define brd_sent (G.brd_sent )
59 #define received (G.received )
60 #define brd_recv (G.brd_recv )
61 #define req_recv (G.req_recv )
62 #define INIT_G() do { \
66 // If GNUisms are not available...
67 //static void *mempcpy(void *_dst, const void *_src, int n)
69 // memcpy(_dst, _src, n);
70 // return (char*)_dst + n;
73 static int send_pack(struct in_addr
*src_addr
,
74 struct in_addr
*dst_addr
, struct sockaddr_ll
*ME
,
75 struct sockaddr_ll
*HE
)
78 unsigned char buf
[256];
79 struct arphdr
*ah
= (struct arphdr
*) buf
;
80 unsigned char *p
= (unsigned char *) (ah
+ 1);
82 ah
->ar_hrd
= htons(ARPHRD_ETHER
);
83 ah
->ar_pro
= htons(ETH_P_IP
);
84 ah
->ar_hln
= ME
->sll_halen
;
86 ah
->ar_op
= option_mask32
& ADVERT
? htons(ARPOP_REPLY
) : htons(ARPOP_REQUEST
);
88 p
= mempcpy(p
, &ME
->sll_addr
, ah
->ar_hln
);
89 p
= mempcpy(p
, src_addr
, 4);
91 if (option_mask32
& ADVERT
)
92 p
= mempcpy(p
, &ME
->sll_addr
, ah
->ar_hln
);
94 p
= mempcpy(p
, &HE
->sll_addr
, ah
->ar_hln
);
96 p
= mempcpy(p
, dst_addr
, 4);
98 err
= sendto(sock_fd
, buf
, p
- buf
, 0, (struct sockaddr
*) HE
, sizeof(*HE
));
100 last
= MONOTONIC_US();
102 if (!(option_mask32
& UNICASTING
))
108 static void finish(void) NORETURN
;
109 static void finish(void)
111 if (!(option_mask32
& QUIET
)) {
112 printf("Sent %u probe(s) (%u broadcast(s))\n"
114 " (%u request(s), %u broadcast(s))\n",
116 received
, (received
== 1) ? "ies" : "y",
119 if (option_mask32
& DAD
)
121 if (option_mask32
& UNSOLICITED
)
126 static void catcher(void)
130 now
= MONOTONIC_US();
134 if (count
== 0 || (timeout_us
&& (now
- start
) > timeout_us
))
137 /* count < 0 means "infinite count" */
141 if (last
== 0 || (now
- last
) > 500000) {
142 send_pack(&src
, &dst
, &me
, &he
);
143 if (count
== 0 && (option_mask32
& UNSOLICITED
))
149 static bool recv_pack(unsigned char *buf
, int len
, struct sockaddr_ll
*FROM
)
151 struct arphdr
*ah
= (struct arphdr
*) buf
;
152 unsigned char *p
= (unsigned char *) (ah
+ 1);
153 struct in_addr src_ip
, dst_ip
;
154 /* moves below assume in_addr is 4 bytes big, ensure that */
155 struct BUG_in_addr_must_be_4
{
156 char BUG_in_addr_must_be_4
[
157 sizeof(struct in_addr
) == 4 ? 1 : -1
159 char BUG_s_addr_must_be_4
[
160 sizeof(src_ip
.s_addr
) == 4 ? 1 : -1
164 /* Filter out wild packets */
165 if (FROM
->sll_pkttype
!= PACKET_HOST
166 && FROM
->sll_pkttype
!= PACKET_BROADCAST
167 && FROM
->sll_pkttype
!= PACKET_MULTICAST
)
170 /* Only these types are recognized */
171 if (ah
->ar_op
!= htons(ARPOP_REQUEST
) && ah
->ar_op
!= htons(ARPOP_REPLY
))
174 /* ARPHRD check and this darned FDDI hack here :-( */
175 if (ah
->ar_hrd
!= htons(FROM
->sll_hatype
)
176 && (FROM
->sll_hatype
!= ARPHRD_FDDI
|| ah
->ar_hrd
!= htons(ARPHRD_ETHER
)))
179 /* Protocol must be IP. */
180 if (ah
->ar_pro
!= htons(ETH_P_IP
)
182 || (ah
->ar_hln
!= me
.sll_halen
)
183 || (len
< (int)(sizeof(*ah
) + 2 * (4 + ah
->ar_hln
))))
186 move_from_unaligned32(src_ip
.s_addr
, p
+ ah
->ar_hln
);
187 move_from_unaligned32(dst_ip
.s_addr
, p
+ ah
->ar_hln
+ 4 + ah
->ar_hln
);
189 if (dst
.s_addr
!= src_ip
.s_addr
)
191 if (!(option_mask32
& DAD
)) {
192 if ((src
.s_addr
!= dst_ip
.s_addr
)
193 || (memcmp(p
+ ah
->ar_hln
+ 4, &me
.sll_addr
, ah
->ar_hln
)))
197 src_ip = 0 (or some src)
199 dst_ip = tested address
202 We fail, if receive request/reply with:
203 src_ip = tested_address
205 if src_ip in request was not zero, check
206 also that it matches to dst_ip, otherwise
207 dst_ip/dst_hw do not matter.
209 if ((memcmp(p
, &me
.sll_addr
, me
.sll_halen
) == 0)
210 || (src
.s_addr
&& src
.s_addr
!= dst_ip
.s_addr
))
213 if (!(option_mask32
& QUIET
)) {
216 printf("%scast re%s from %s [%s]",
217 FROM
->sll_pkttype
== PACKET_HOST
? "Uni" : "Broad",
218 ah
->ar_op
== htons(ARPOP_REPLY
) ? "ply" : "quest",
220 ether_ntoa((struct ether_addr
*) p
));
221 if (dst_ip
.s_addr
!= src
.s_addr
) {
222 printf("for %s ", inet_ntoa(dst_ip
));
225 if (memcmp(p
+ ah
->ar_hln
+ 4, me
.sll_addr
, ah
->ar_hln
)) {
229 ether_ntoa((struct ether_addr
*) p
+ ah
->ar_hln
+ 4));
233 unsigned diff
= MONOTONIC_US() - last
;
234 printf(" %u.%03ums\n", diff
/ 1000, diff
% 1000);
236 printf(" UNSOLICITED?\n");
241 if (FROM
->sll_pkttype
!= PACKET_HOST
)
243 if (ah
->ar_op
== htons(ARPOP_REQUEST
))
245 if (option_mask32
& QUIT_ON_REPLY
)
247 if (!(option_mask32
& BCAST_ONLY
)) {
248 memcpy(he
.sll_addr
, p
, me
.sll_halen
);
249 option_mask32
|= UNICASTING
;
254 int arping_main(int argc
, char **argv
) MAIN_EXTERNALLY_VISIBLE
;
255 int arping_main(int argc UNUSED_PARAM
, char **argv
)
257 const char *device
= "eth0";
260 unsigned char *packet
;
265 sock_fd
= xsocket(AF_PACKET
, SOCK_DGRAM
, 0);
267 // Drop suid root privileges
268 // Need to remove SUID_NEVER from applets.h for this to work
271 err_str
= xasprintf("interface %s %%s", device
);
276 /* Dad also sets quit_on_reply.
277 * Advert also sets unsolicited.
279 opt_complementary
= "=1:Df:AU:c+";
280 opt
= getopt32(argv
, "DUAqfbc:w:I:s:",
281 &count
, &str_timeout
, &device
, &source
);
282 if (opt
& 0x80) /* -w: timeout */
283 timeout_us
= xatou_range(str_timeout
, 0, INT_MAX
/2000000) * 1000000 + 500000;
284 //if (opt & 0x200) /* -s: source */
285 option_mask32
&= 0x3f; /* set respective flags */
288 target
= argv
[optind
];
290 xfunc_error_retval
= 2;
295 memset(&ifr
, 0, sizeof(ifr
));
296 strncpy_IFNAMSIZ(ifr
.ifr_name
, device
);
297 /* We use ifr.ifr_name in error msg so that problem
298 * with truncated name will be visible */
299 ioctl_or_perror_and_die(sock_fd
, SIOCGIFINDEX
, &ifr
, err_str
, "not found");
300 me
.sll_ifindex
= ifr
.ifr_ifindex
;
302 xioctl(sock_fd
, SIOCGIFFLAGS
, (char *) &ifr
);
304 if (!(ifr
.ifr_flags
& IFF_UP
)) {
305 bb_error_msg_and_die(err_str
, "is down");
307 if (ifr
.ifr_flags
& (IFF_NOARP
| IFF_LOOPBACK
)) {
308 bb_error_msg(err_str
, "is not ARPable");
309 return (option_mask32
& DAD
? 0 : 2);
313 /* if (!inet_aton(target, &dst)) - not needed */ {
314 len_and_sockaddr
*lsa
;
315 lsa
= xhost_and_af2sockaddr(target
, 0, AF_INET
);
316 dst
= lsa
->u
.sin
.sin_addr
;
317 if (ENABLE_FEATURE_CLEAN_UP
)
321 if (source
&& !inet_aton(source
, &src
)) {
322 bb_error_msg_and_die("invalid source address %s", source
);
325 if ((option_mask32
& (DAD
|UNSOLICITED
)) == UNSOLICITED
&& src
.s_addr
== 0)
328 if (!(option_mask32
& DAD
) || src
.s_addr
) {
329 struct sockaddr_in saddr
;
330 int probe_fd
= xsocket(AF_INET
, SOCK_DGRAM
, 0);
332 setsockopt_bindtodevice(probe_fd
, device
);
333 memset(&saddr
, 0, sizeof(saddr
));
334 saddr
.sin_family
= AF_INET
;
336 /* Check that this is indeed our IP */
337 saddr
.sin_addr
= src
;
338 xbind(probe_fd
, (struct sockaddr
*) &saddr
, sizeof(saddr
));
339 } else { /* !(option_mask32 & DAD) case */
340 /* Find IP address on this iface */
341 socklen_t alen
= sizeof(saddr
);
343 saddr
.sin_port
= htons(1025);
344 saddr
.sin_addr
= dst
;
346 if (setsockopt(probe_fd
, SOL_SOCKET
, SO_DONTROUTE
, &const_int_1
, sizeof(const_int_1
)) == -1)
347 bb_perror_msg("setsockopt(SO_DONTROUTE)");
348 xconnect(probe_fd
, (struct sockaddr
*) &saddr
, sizeof(saddr
));
349 getsockname(probe_fd
, (struct sockaddr
*) &saddr
, &alen
);
351 //if (getsockname(probe_fd, (struct sockaddr *) &saddr, &alen) == -1)
352 // bb_perror_msg_and_die("getsockname");
353 if (saddr
.sin_family
!= AF_INET
)
354 bb_error_msg_and_die("no IP address configured");
355 src
= saddr
.sin_addr
;
360 me
.sll_family
= AF_PACKET
;
361 //me.sll_ifindex = ifindex; - done before
362 me
.sll_protocol
= htons(ETH_P_ARP
);
363 xbind(sock_fd
, (struct sockaddr
*) &me
, sizeof(me
));
366 socklen_t alen
= sizeof(me
);
367 getsockname(sock_fd
, (struct sockaddr
*) &me
, &alen
);
369 //if (getsockname(sock_fd, (struct sockaddr *) &me, &alen) == -1)
370 // bb_perror_msg_and_die("getsockname");
372 if (me
.sll_halen
== 0) {
373 bb_error_msg(err_str
, "is not ARPable (no ll address)");
374 return (option_mask32
& DAD
? 0 : 2);
377 memset(he
.sll_addr
, -1, he
.sll_halen
);
379 if (!(option_mask32
& QUIET
)) {
380 /* inet_ntoa uses static storage, can't use in same printf */
381 printf("ARPING to %s", inet_ntoa(dst
));
382 printf(" from %s via %s\n", inet_ntoa(src
), device
);
385 signal_SA_RESTART_empty_mask(SIGINT
, (void (*)(int))finish
);
386 signal_SA_RESTART_empty_mask(SIGALRM
, (void (*)(int))catcher
);
390 packet
= xmalloc(4096);
392 sigset_t sset
, osset
;
393 struct sockaddr_ll from
;
394 socklen_t alen
= sizeof(from
);
397 cc
= recvfrom(sock_fd
, packet
, 4096, 0, (struct sockaddr
*) &from
, &alen
);
399 bb_perror_msg("recvfrom");
403 sigaddset(&sset
, SIGALRM
);
404 sigaddset(&sset
, SIGINT
);
405 sigprocmask(SIG_BLOCK
, &sset
, &osset
);
406 recv_pack(packet
, cc
, &from
);
407 sigprocmask(SIG_SETMASK
, &osset
, NULL
);