aboutsummaryrefslogtreecommitdiff
path: root/networking/arping.c
diff options
context:
space:
mode:
Diffstat (limited to 'networking/arping.c')
-rw-r--r--networking/arping.c193
1 files changed, 96 insertions, 97 deletions
diff --git a/networking/arping.c b/networking/arping.c
index f9967d81e..788fded3c 100644
--- a/networking/arping.c
+++ b/networking/arping.c
@@ -11,7 +11,6 @@
11//config: select PLATFORM_LINUX 11//config: select PLATFORM_LINUX
12//config: help 12//config: help
13//config: Ping hosts by ARP packets. 13//config: Ping hosts by ARP packets.
14//config:
15 14
16//applet:IF_ARPING(APPLET(arping, BB_DIR_USR_SBIN, BB_SUID_DROP)) 15//applet:IF_ARPING(APPLET(arping, BB_DIR_USR_SBIN, BB_SUID_DROP))
17 16
@@ -29,6 +28,7 @@
29//usage: "\n -A ARP answer mode, update your neighbors" 28//usage: "\n -A ARP answer mode, update your neighbors"
30//usage: "\n -c N Stop after sending N ARP requests" 29//usage: "\n -c N Stop after sending N ARP requests"
31//usage: "\n -w TIMEOUT Seconds to wait for ARP reply" 30//usage: "\n -w TIMEOUT Seconds to wait for ARP reply"
31//NB: in iputils-s20160308, iface is mandatory, no default
32//usage: "\n -I IFACE Interface to use (default eth0)" 32//usage: "\n -I IFACE Interface to use (default eth0)"
33//usage: "\n -s SRC_IP Sender IP address" 33//usage: "\n -s SRC_IP Sender IP address"
34//usage: "\n DST_IP Target IP address" 34//usage: "\n DST_IP Target IP address"
@@ -45,21 +45,29 @@
45#define MONOTONIC_US() ((unsigned)monotonic_us()) 45#define MONOTONIC_US() ((unsigned)monotonic_us())
46 46
47enum { 47enum {
48 DAD = 1, 48 UNSOLICITED = 1 << 0,
49 UNSOLICITED = 2, 49 DAD = 1 << 1,
50 ADVERT = 4, 50 ADVERT = 1 << 2,
51 QUIET = 8, 51 QUIET = 1 << 3,
52 QUIT_ON_REPLY = 16, 52 QUIT_ON_REPLY = 1 << 4,
53 BCAST_ONLY = 32, 53 BCAST_ONLY = 1 << 5,
54 UNICASTING = 64 54 UNICASTING = 1 << 6,
55 TIMEOUT = 1 << 7,
55}; 56};
57#define GETOPT32(str_timeout, device, source) \
58 getopt32(argv, "^" \
59 "UDAqfbc:+w:I:s:" \
60 /* DAD also sets quit_on_reply, */ \
61 /* advert also sets unsolicited: */ \
62 "\0" "=1:Df:AU", \
63 &count, &str_timeout, &device, &source \
64 );
56 65
57struct globals { 66struct globals {
58 struct in_addr src; 67 struct in_addr src;
59 struct in_addr dst; 68 struct in_addr dst;
60 struct sockaddr_ll me; 69 struct sockaddr_ll me;
61 struct sockaddr_ll he; 70 struct sockaddr_ll he;
62 int sock_fd;
63 71
64 int count; // = -1; 72 int count; // = -1;
65 unsigned last; 73 unsigned last;
@@ -71,13 +79,17 @@ struct globals {
71 unsigned received; 79 unsigned received;
72 unsigned brd_recv; 80 unsigned brd_recv;
73 unsigned req_recv; 81 unsigned req_recv;
82
83 /* should be in main(), but are here to reduce stack use: */
84 struct ifreq ifr;
85 struct sockaddr_in probe_saddr;
86 sigset_t sset;
87 unsigned char packet[4096];
74} FIX_ALIASING; 88} FIX_ALIASING;
75#define G (*(struct globals*)bb_common_bufsiz1)
76#define src (G.src ) 89#define src (G.src )
77#define dst (G.dst ) 90#define dst (G.dst )
78#define me (G.me ) 91#define me (G.me )
79#define he (G.he ) 92#define he (G.he )
80#define sock_fd (G.sock_fd )
81#define count (G.count ) 93#define count (G.count )
82#define last (G.last ) 94#define last (G.last )
83#define timeout_us (G.timeout_us) 95#define timeout_us (G.timeout_us)
@@ -87,26 +99,25 @@ struct globals {
87#define received (G.received ) 99#define received (G.received )
88#define brd_recv (G.brd_recv ) 100#define brd_recv (G.brd_recv )
89#define req_recv (G.req_recv ) 101#define req_recv (G.req_recv )
102//#define G (*(struct globals*)bb_common_bufsiz1)
103#define G (*ptr_to_globals)
90#define INIT_G() do { \ 104#define INIT_G() do { \
91 setup_common_bufsiz(); \ 105 /*setup_common_bufsiz();*/ \
106 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
92 count = -1; \ 107 count = -1; \
93} while (0) 108} while (0)
94 109
95// If GNUisms are not available... 110#define sock_fd 3
96//static void *mempcpy(void *_dst, const void *_src, int n)
97//{
98// memcpy(_dst, _src, n);
99// return (char*)_dst + n;
100//}
101 111
102static int send_pack(struct in_addr *src_addr, 112static int send_pack(struct in_addr *src_addr,
103 struct in_addr *dst_addr, struct sockaddr_ll *ME, 113 struct in_addr *dst_addr,
114 struct sockaddr_ll *ME,
104 struct sockaddr_ll *HE) 115 struct sockaddr_ll *HE)
105{ 116{
106 int err; 117 int err;
107 unsigned char buf[256]; 118 unsigned char buf[256];
108 struct arphdr *ah = (struct arphdr *) buf; 119 struct arphdr *ah = (struct arphdr *) buf;
109 unsigned char *p = (unsigned char *) (ah + 1); 120 unsigned char *p;
110 121
111 ah->ar_hrd = htons(ARPHRD_ETHER); 122 ah->ar_hrd = htons(ARPHRD_ETHER);
112 ah->ar_pro = htons(ETH_P_IP); 123 ah->ar_pro = htons(ETH_P_IP);
@@ -114,6 +125,7 @@ static int send_pack(struct in_addr *src_addr,
114 ah->ar_pln = 4; 125 ah->ar_pln = 4;
115 ah->ar_op = option_mask32 & ADVERT ? htons(ARPOP_REPLY) : htons(ARPOP_REQUEST); 126 ah->ar_op = option_mask32 & ADVERT ? htons(ARPOP_REPLY) : htons(ARPOP_REQUEST);
116 127
128 p = (unsigned char *) (ah + 1);
117 p = mempcpy(p, &ME->sll_addr, ah->ar_hln); 129 p = mempcpy(p, &ME->sll_addr, ah->ar_hln);
118 p = mempcpy(p, src_addr, 4); 130 p = mempcpy(p, src_addr, 4);
119 131
@@ -139,10 +151,10 @@ static void finish(void)
139{ 151{
140 if (!(option_mask32 & QUIET)) { 152 if (!(option_mask32 & QUIET)) {
141 printf("Sent %u probe(s) (%u broadcast(s))\n" 153 printf("Sent %u probe(s) (%u broadcast(s))\n"
142 "Received %u repl%s" 154 "Received %u response(s)"
143 " (%u request(s), %u broadcast(s))\n", 155 " (%u request(s), %u broadcast(s))\n",
144 sent, brd_sent, 156 sent, brd_sent,
145 received, (received == 1) ? "ies" : "y", 157 received,
146 req_recv, brd_recv); 158 req_recv, brd_recv);
147 } 159 }
148 if (option_mask32 & DAD) 160 if (option_mask32 & DAD)
@@ -180,15 +192,10 @@ static void recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM)
180 struct arphdr *ah = (struct arphdr *) buf; 192 struct arphdr *ah = (struct arphdr *) buf;
181 unsigned char *p = (unsigned char *) (ah + 1); 193 unsigned char *p = (unsigned char *) (ah + 1);
182 struct in_addr src_ip, dst_ip; 194 struct in_addr src_ip, dst_ip;
195
183 /* moves below assume in_addr is 4 bytes big, ensure that */ 196 /* moves below assume in_addr is 4 bytes big, ensure that */
184 struct BUG_in_addr_must_be_4 { 197 BUILD_BUG_ON(sizeof(struct in_addr) != 4);
185 char BUG_in_addr_must_be_4[ 198 BUILD_BUG_ON(sizeof(src_ip.s_addr) != 4);
186 sizeof(struct in_addr) == 4 ? 1 : -1
187 ];
188 char BUG_s_addr_must_be_4[
189 sizeof(src_ip.s_addr) == 4 ? 1 : -1
190 ];
191 };
192 199
193 /* Filter out wild packets */ 200 /* Filter out wild packets */
194 if (FROM->sll_pkttype != PACKET_HOST 201 if (FROM->sll_pkttype != PACKET_HOST
@@ -209,8 +216,10 @@ static void recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM)
209 if (ah->ar_pro != htons(ETH_P_IP) 216 if (ah->ar_pro != htons(ETH_P_IP)
210 || (ah->ar_pln != 4) 217 || (ah->ar_pln != 4)
211 || (ah->ar_hln != me.sll_halen) 218 || (ah->ar_hln != me.sll_halen)
212 || (len < (int)(sizeof(*ah) + 2 * (4 + ah->ar_hln)))) 219 || (len < (int)(sizeof(*ah) + 2 * (4 + ah->ar_hln)))
220 ) {
213 return; 221 return;
222 }
214 223
215 move_from_unaligned32(src_ip.s_addr, p + ah->ar_hln); 224 move_from_unaligned32(src_ip.s_addr, p + ah->ar_hln);
216 move_from_unaligned32(dst_ip.s_addr, p + ah->ar_hln + 4 + ah->ar_hln); 225 move_from_unaligned32(dst_ip.s_addr, p + ah->ar_hln + 4 + ah->ar_hln);
@@ -242,6 +251,7 @@ static void recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM)
242 if (!(option_mask32 & QUIET)) { 251 if (!(option_mask32 & QUIET)) {
243 int s_printed = 0; 252 int s_printed = 0;
244 253
254//TODO: arping from iputils-s20160308 print upprcase hex in MAC, follow them?
245 printf("%scast re%s from %s [%02x:%02x:%02x:%02x:%02x:%02x]", 255 printf("%scast re%s from %s [%02x:%02x:%02x:%02x:%02x:%02x]",
246 FROM->sll_pkttype == PACKET_HOST ? "Uni" : "Broad", 256 FROM->sll_pkttype == PACKET_HOST ? "Uni" : "Broad",
247 ah->ar_op == htons(ARPOP_REPLY) ? "ply" : "quest", 257 ah->ar_op == htons(ARPOP_REPLY) ? "ply" : "quest",
@@ -249,14 +259,14 @@ static void recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM)
249 p[0], p[1], p[2], p[3], p[4], p[5] 259 p[0], p[1], p[2], p[3], p[4], p[5]
250 ); 260 );
251 if (dst_ip.s_addr != src.s_addr) { 261 if (dst_ip.s_addr != src.s_addr) {
252 printf("for %s ", inet_ntoa(dst_ip)); 262 printf("for %s", inet_ntoa(dst_ip));
253 s_printed = 1; 263 s_printed = 1;
254 } 264 }
255 if (memcmp(p + ah->ar_hln + 4, me.sll_addr, ah->ar_hln)) { 265 if (memcmp(p + ah->ar_hln + 4, me.sll_addr, ah->ar_hln)) {
256 unsigned char *pp = p + ah->ar_hln + 4; 266 unsigned char *pp = p + ah->ar_hln + 4;
257 if (!s_printed) 267 if (!s_printed)
258 printf("for "); 268 printf(" for");
259 printf("[%02x:%02x:%02x:%02x:%02x:%02x]", 269 printf(" [%02x:%02x:%02x:%02x:%02x:%02x]",
260 pp[0], pp[1], pp[2], pp[3], pp[4], pp[5] 270 pp[0], pp[1], pp[2], pp[3], pp[4], pp[5]
261 ); 271 );
262 } 272 }
@@ -288,12 +298,11 @@ int arping_main(int argc UNUSED_PARAM, char **argv)
288 const char *device = "eth0"; 298 const char *device = "eth0";
289 char *source = NULL; 299 char *source = NULL;
290 char *target; 300 char *target;
291 unsigned char *packet;
292 char *err_str; 301 char *err_str;
293 302
294 INIT_G(); 303 INIT_G();
295 304
296 sock_fd = xsocket(AF_PACKET, SOCK_DGRAM, 0); 305 xmove_fd(xsocket(AF_PACKET, SOCK_DGRAM, 0), sock_fd);
297 306
298 // If you ever change BB_SUID_DROP to BB_SUID_REQUIRE, 307 // If you ever change BB_SUID_DROP to BB_SUID_REQUIRE,
299 // drop suid root privileges here: 308 // drop suid root privileges here:
@@ -303,41 +312,30 @@ int arping_main(int argc UNUSED_PARAM, char **argv)
303 unsigned opt; 312 unsigned opt;
304 char *str_timeout; 313 char *str_timeout;
305 314
306 /* Dad also sets quit_on_reply. 315 opt = GETOPT32(str_timeout, device, source);
307 * Advert also sets unsolicited. 316 if (opt & TIMEOUT)
308 */
309 opt = getopt32(argv, "^" "DUAqfbc:+w:I:s:" "\0" "=1:Df:AU",
310 &count, &str_timeout, &device, &source
311 );
312 if (opt & 0x80) /* -w: timeout */
313 timeout_us = xatou_range(str_timeout, 0, INT_MAX/2000000) * 1000000 + 500000; 317 timeout_us = xatou_range(str_timeout, 0, INT_MAX/2000000) * 1000000 + 500000;
314 //if (opt & 0x200) /* -s: source */
315 option_mask32 &= 0x3f; /* set respective flags */
316 } 318 }
317 319
318 target = argv[optind]; 320 target = argv[optind];
319 err_str = xasprintf("interface %s %%s", device); 321 err_str = xasprintf("interface %s %%s", device);
320 xfunc_error_retval = 2; 322 xfunc_error_retval = 2;
321 323
322 { 324 /*memset(&G.ifr, 0, sizeof(G.ifr)); - zeroed by INIT_G */
323 struct ifreq ifr; 325 strncpy_IFNAMSIZ(G.ifr.ifr_name, device);
324 326 ioctl_or_perror_and_die(sock_fd, SIOCGIFINDEX, &G.ifr, err_str, "not found");
325 memset(&ifr, 0, sizeof(ifr)); 327 me.sll_ifindex = G.ifr.ifr_ifindex;
326 strncpy_IFNAMSIZ(ifr.ifr_name, device);
327 /* We use ifr.ifr_name in error msg so that problem
328 * with truncated name will be visible */
329 ioctl_or_perror_and_die(sock_fd, SIOCGIFINDEX, &ifr, err_str, "not found");
330 me.sll_ifindex = ifr.ifr_ifindex;
331 328
332 xioctl(sock_fd, SIOCGIFFLAGS, (char *) &ifr); 329 xioctl(sock_fd, SIOCGIFFLAGS, (char *) &G.ifr);
333 330
334 if (!(ifr.ifr_flags & IFF_UP)) { 331 if (!(G.ifr.ifr_flags & IFF_UP)) {
335 bb_error_msg_and_die(err_str, "is down"); 332 bb_error_msg_and_die(err_str, "is down");
336 } 333 }
337 if (ifr.ifr_flags & (IFF_NOARP | IFF_LOOPBACK)) { 334 if (G.ifr.ifr_flags & (IFF_NOARP | IFF_LOOPBACK)) {
338 bb_error_msg(err_str, "is not ARPable"); 335 bb_error_msg(err_str, "is not ARPable");
339 return (option_mask32 & DAD ? 0 : 2); 336 BUILD_BUG_ON(DAD != 2);
340 } 337 /* exit 0 if DAD, else exit 2 */
338 return (~option_mask32 & DAD);
341 } 339 }
342 340
343 /* if (!inet_aton(target, &dst)) - not needed */ { 341 /* if (!inet_aton(target, &dst)) - not needed */ {
@@ -356,33 +354,29 @@ int arping_main(int argc UNUSED_PARAM, char **argv)
356 src = dst; 354 src = dst;
357 355
358 if (!(option_mask32 & DAD) || src.s_addr) { 356 if (!(option_mask32 & DAD) || src.s_addr) {
359 struct sockaddr_in saddr; 357 /*struct sockaddr_in probe_saddr;*/
360 int probe_fd = xsocket(AF_INET, SOCK_DGRAM, 0); 358 int probe_fd = xsocket(AF_INET, SOCK_DGRAM, 0);
361 359
362 setsockopt_bindtodevice(probe_fd, device); 360 setsockopt_bindtodevice(probe_fd, device);
363 memset(&saddr, 0, sizeof(saddr)); 361
364 saddr.sin_family = AF_INET; 362 /*memset(&G.probe_saddr, 0, sizeof(G.probe_saddr)); - zeroed by INIT_G */
363 G.probe_saddr.sin_family = AF_INET;
365 if (src.s_addr) { 364 if (src.s_addr) {
366 /* Check that this is indeed our IP */ 365 /* Check that this is indeed our IP */
367 saddr.sin_addr = src; 366 G.probe_saddr.sin_addr = src;
368 xbind(probe_fd, (struct sockaddr *) &saddr, sizeof(saddr)); 367 xbind(probe_fd, (struct sockaddr *) &G.probe_saddr, sizeof(G.probe_saddr));
369 } else { /* !(option_mask32 & DAD) case */ 368 } else { /* !(option_mask32 & DAD) case */
370 /* Find IP address on this iface */ 369 /* Find IP address on this iface */
371 socklen_t alen = sizeof(saddr); 370 G.probe_saddr.sin_port = htons(1025);
372 371 G.probe_saddr.sin_addr = dst;
373 saddr.sin_port = htons(1025);
374 saddr.sin_addr = dst;
375 372
376 if (setsockopt_SOL_SOCKET_1(probe_fd, SO_DONTROUTE) != 0) 373 if (setsockopt_SOL_SOCKET_1(probe_fd, SO_DONTROUTE) != 0)
377 bb_perror_msg("setsockopt(%s)", "SO_DONTROUTE"); 374 bb_perror_msg("setsockopt(%s)", "SO_DONTROUTE");
378 xconnect(probe_fd, (struct sockaddr *) &saddr, sizeof(saddr)); 375 xconnect(probe_fd, (struct sockaddr *) &G.probe_saddr, sizeof(G.probe_saddr));
379 getsockname(probe_fd, (struct sockaddr *) &saddr, &alen); 376 bb_getsockname(probe_fd, (struct sockaddr *) &G.probe_saddr, sizeof(G.probe_saddr));
380 //never happens: 377 if (G.probe_saddr.sin_family != AF_INET)
381 //if (getsockname(probe_fd, (struct sockaddr *) &saddr, &alen) == -1)
382 // bb_perror_msg_and_die("getsockname");
383 if (saddr.sin_family != AF_INET)
384 bb_error_msg_and_die("no IP address configured"); 378 bb_error_msg_and_die("no IP address configured");
385 src = saddr.sin_addr; 379 src = G.probe_saddr.sin_addr;
386 } 380 }
387 close(probe_fd); 381 close(probe_fd);
388 } 382 }
@@ -392,48 +386,53 @@ int arping_main(int argc UNUSED_PARAM, char **argv)
392 me.sll_protocol = htons(ETH_P_ARP); 386 me.sll_protocol = htons(ETH_P_ARP);
393 xbind(sock_fd, (struct sockaddr *) &me, sizeof(me)); 387 xbind(sock_fd, (struct sockaddr *) &me, sizeof(me));
394 388
395 { 389 bb_getsockname(sock_fd, (struct sockaddr *) &me, sizeof(me));
396 socklen_t alen = sizeof(me); 390 //never happens:
397 getsockname(sock_fd, (struct sockaddr *) &me, &alen); 391 //if (getsockname(sock_fd, (struct sockaddr *) &me, &alen) == -1)
398 //never happens: 392 // bb_perror_msg_and_die("getsockname");
399 //if (getsockname(sock_fd, (struct sockaddr *) &me, &alen) == -1)
400 // bb_perror_msg_and_die("getsockname");
401 }
402 if (me.sll_halen == 0) { 393 if (me.sll_halen == 0) {
403 bb_error_msg(err_str, "is not ARPable (no ll address)"); 394 bb_error_msg(err_str, "is not ARPable (no ll address)");
404 return (option_mask32 & DAD ? 0 : 2); 395 BUILD_BUG_ON(DAD != 2);
396 /* exit 0 if DAD, else exit 2 */
397 return (~option_mask32 & DAD);
405 } 398 }
406 he = me; 399 he = me;
407 memset(he.sll_addr, -1, he.sll_halen); 400 memset(he.sll_addr, -1, he.sll_halen);
408 401
409 if (!(option_mask32 & QUIET)) { 402 if (!(option_mask32 & QUIET)) {
410 /* inet_ntoa uses static storage, can't use in same printf */ 403 /* inet_ntoa uses static storage, can't use in same printf */
411 printf("ARPING to %s", inet_ntoa(dst)); 404 printf("ARPING %s", inet_ntoa(dst));
412 printf(" from %s via %s\n", inet_ntoa(src), device); 405 printf(" from %s %s\n", inet_ntoa(src), device);
413 } 406 }
414 407
408 /*sigemptyset(&G.sset); - zeroed by INIT_G */
409 sigaddset(&G.sset, SIGALRM);
410 sigaddset(&G.sset, SIGINT);
415 signal_SA_RESTART_empty_mask(SIGINT, (void (*)(int))finish); 411 signal_SA_RESTART_empty_mask(SIGINT, (void (*)(int))finish);
416 signal_SA_RESTART_empty_mask(SIGALRM, (void (*)(int))catcher); 412 signal_SA_RESTART_empty_mask(SIGALRM, (void (*)(int))catcher);
417 413
414 /* Send the first packet, arm ALRM */
418 catcher(); 415 catcher();
419 416
420 packet = xmalloc(4096);
421 while (1) { 417 while (1) {
422 sigset_t sset, osset;
423 struct sockaddr_ll from; 418 struct sockaddr_ll from;
424 socklen_t alen = sizeof(from); 419 socklen_t alen = sizeof(from);
425 int cc; 420 int cc;
426 421
427 cc = recvfrom(sock_fd, packet, 4096, 0, (struct sockaddr *) &from, &alen); 422 /* 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 */
426 sigprocmask(SIG_UNBLOCK, &G.sset, NULL);
427
428 cc = recvfrom(sock_fd, G.packet, sizeof(G.packet), 0, (struct sockaddr *) &from, &alen);
429
430 /* Don't allow SIGALRMs while we process the reply */
431 sigprocmask(SIG_BLOCK, &G.sset, NULL);
428 if (cc < 0) { 432 if (cc < 0) {
429 bb_perror_msg("recvfrom"); 433 bb_perror_msg("recvfrom");
430 continue; 434 continue;
431 } 435 }
432 sigemptyset(&sset); 436 recv_pack(G.packet, cc, &from);
433 sigaddset(&sset, SIGALRM);
434 sigaddset(&sset, SIGINT);
435 sigprocmask(SIG_BLOCK, &sset, &osset);
436 recv_pack(packet, cc, &from);
437 sigprocmask(SIG_SETMASK, &osset, NULL);
438 } 437 }
439} 438}