diff options
Diffstat (limited to 'networking/arping.c')
-rw-r--r-- | networking/arping.c | 69 |
1 files changed, 33 insertions, 36 deletions
diff --git a/networking/arping.c b/networking/arping.c index 771c3bccd..6383f9a88 100644 --- a/networking/arping.c +++ b/networking/arping.c | |||
@@ -33,7 +33,7 @@ struct globals { | |||
33 | struct in_addr dst; | 33 | struct in_addr dst; |
34 | struct sockaddr_ll me; | 34 | struct sockaddr_ll me; |
35 | struct sockaddr_ll he; | 35 | struct sockaddr_ll he; |
36 | int sock; | 36 | int sock_fd; |
37 | 37 | ||
38 | int count; // = -1; | 38 | int count; // = -1; |
39 | unsigned last; | 39 | unsigned last; |
@@ -51,7 +51,7 @@ struct globals { | |||
51 | #define dst (G.dst ) | 51 | #define dst (G.dst ) |
52 | #define me (G.me ) | 52 | #define me (G.me ) |
53 | #define he (G.he ) | 53 | #define he (G.he ) |
54 | #define sock (G.sock ) | 54 | #define sock_fd (G.sock_fd ) |
55 | #define count (G.count ) | 55 | #define count (G.count ) |
56 | #define last (G.last ) | 56 | #define last (G.last ) |
57 | #define timeout_us (G.timeout_us) | 57 | #define timeout_us (G.timeout_us) |
@@ -71,7 +71,6 @@ static int send_pack(struct in_addr *src_addr, | |||
71 | struct sockaddr_ll *HE) | 71 | struct sockaddr_ll *HE) |
72 | { | 72 | { |
73 | int err; | 73 | int err; |
74 | unsigned now; | ||
75 | unsigned char buf[256]; | 74 | unsigned char buf[256]; |
76 | struct arphdr *ah = (struct arphdr *) buf; | 75 | struct arphdr *ah = (struct arphdr *) buf; |
77 | unsigned char *p = (unsigned char *) (ah + 1); | 76 | unsigned char *p = (unsigned char *) (ah + 1); |
@@ -98,10 +97,9 @@ static int send_pack(struct in_addr *src_addr, | |||
98 | memcpy(p, dst_addr, 4); | 97 | memcpy(p, dst_addr, 4); |
99 | p += 4; | 98 | p += 4; |
100 | 99 | ||
101 | now = MONOTONIC_US(); | 100 | err = sendto(sock_fd, buf, p - buf, 0, (struct sockaddr *) HE, sizeof(*HE)); |
102 | err = sendto(sock, buf, p - buf, 0, (struct sockaddr *) HE, sizeof(*HE)); | ||
103 | if (err == p - buf) { | 101 | if (err == p - buf) { |
104 | last = now; | 102 | last = MONOTONIC_US(); |
105 | sent++; | 103 | sent++; |
106 | if (!(option_mask32 & UNICASTING)) | 104 | if (!(option_mask32 & UNICASTING)) |
107 | brd_sent++; | 105 | brd_sent++; |
@@ -135,7 +133,7 @@ static void catcher(void) | |||
135 | if (start == 0) | 133 | if (start == 0) |
136 | start = now; | 134 | start = now; |
137 | 135 | ||
138 | if (count == 0 || (timeout_us && (now - start) > (timeout_us + 500000))) | 136 | if (count == 0 || (timeout_us && (now - start) > timeout_us)) |
139 | finish(); | 137 | finish(); |
140 | 138 | ||
141 | /* count < 0 means "infinite count" */ | 139 | /* count < 0 means "infinite count" */ |
@@ -183,7 +181,7 @@ static int recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM) | |||
183 | memcpy(&src_ip, p + ah->ar_hln, 4); | 181 | memcpy(&src_ip, p + ah->ar_hln, 4); |
184 | memcpy(&dst_ip, p + ah->ar_hln + 4 + ah->ar_hln, 4); | 182 | memcpy(&dst_ip, p + ah->ar_hln + 4 + ah->ar_hln, 4); |
185 | if (!(option_mask32 & DAD)) { | 183 | if (!(option_mask32 & DAD)) { |
186 | if (src_ip.s_addr != dst.s_addr) | 184 | if (dst.s_addr != src_ip.s_addr) |
187 | return 0; | 185 | return 0; |
188 | if (src.s_addr != dst_ip.s_addr) | 186 | if (src.s_addr != dst_ip.s_addr) |
189 | return 0; | 187 | return 0; |
@@ -230,7 +228,8 @@ static int recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM) | |||
230 | } | 228 | } |
231 | 229 | ||
232 | if (last) { | 230 | if (last) { |
233 | printf(" %u.%03ums\n", last / 1000, last % 1000); | 231 | unsigned diff = MONOTONIC_US() - last; |
232 | printf(" %u.%03ums\n", diff / 1000, diff % 1000); | ||
234 | } else { | 233 | } else { |
235 | printf(" UNSOLICITED?\n"); | 234 | printf(" UNSOLICITED?\n"); |
236 | } | 235 | } |
@@ -254,17 +253,17 @@ int arping_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | |||
254 | int arping_main(int argc, char **argv) | 253 | int arping_main(int argc, char **argv) |
255 | { | 254 | { |
256 | const char *device = "eth0"; | 255 | const char *device = "eth0"; |
257 | int ifindex; | ||
258 | char *source = NULL; | 256 | char *source = NULL; |
259 | char *target; | 257 | char *target; |
260 | unsigned char *packet; | 258 | unsigned char *packet; |
261 | 259 | ||
262 | INIT_G(); | 260 | INIT_G(); |
263 | 261 | ||
264 | sock = xsocket(PF_PACKET, SOCK_DGRAM, 0); | 262 | sock_fd = xsocket(AF_PACKET, SOCK_DGRAM, 0); |
265 | 263 | ||
266 | // Drop suid root privileges | 264 | // Drop suid root privileges |
267 | xsetuid(getuid()); | 265 | // Need to remove SUID_NEVER from applets.h for this to work |
266 | //xsetuid(getuid()); | ||
268 | 267 | ||
269 | { | 268 | { |
270 | unsigned opt; | 269 | unsigned opt; |
@@ -279,7 +278,7 @@ int arping_main(int argc, char **argv) | |||
279 | if (opt & 0x40) /* -c: count */ | 278 | if (opt & 0x40) /* -c: count */ |
280 | count = xatoi_u(str_count); | 279 | count = xatoi_u(str_count); |
281 | if (opt & 0x80) /* -w: timeout */ | 280 | if (opt & 0x80) /* -w: timeout */ |
282 | timeout_us = xatou_range(str_timeout, 0, INT_MAX/2000000) * 1000000; | 281 | timeout_us = xatou_range(str_timeout, 0, INT_MAX/2000000) * 1000000 + 500000; |
283 | //if (opt & 0x200) /* -s: source */ | 282 | //if (opt & 0x200) /* -s: source */ |
284 | option_mask32 &= 0x3f; /* set respective flags */ | 283 | option_mask32 &= 0x3f; /* set respective flags */ |
285 | } | 284 | } |
@@ -295,10 +294,10 @@ int arping_main(int argc, char **argv) | |||
295 | strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name) - 1); | 294 | strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name) - 1); |
296 | /* We use ifr.ifr_name in error msg so that problem | 295 | /* We use ifr.ifr_name in error msg so that problem |
297 | * with truncated name will be visible */ | 296 | * with truncated name will be visible */ |
298 | ioctl_or_perror_and_die(sock, SIOCGIFINDEX, &ifr, "interface %s not found", ifr.ifr_name); | 297 | ioctl_or_perror_and_die(sock_fd, SIOCGIFINDEX, &ifr, "interface %s not found", ifr.ifr_name); |
299 | ifindex = ifr.ifr_ifindex; | 298 | me.sll_ifindex = ifr.ifr_ifindex; |
300 | 299 | ||
301 | xioctl(sock, SIOCGIFFLAGS, (char *) &ifr); | 300 | xioctl(sock_fd, SIOCGIFFLAGS, (char *) &ifr); |
302 | 301 | ||
303 | if (!(ifr.ifr_flags & IFF_UP)) { | 302 | if (!(ifr.ifr_flags & IFF_UP)) { |
304 | bb_error_msg_and_die("interface %s is down", device); | 303 | bb_error_msg_and_die("interface %s is down", device); |
@@ -309,7 +308,7 @@ int arping_main(int argc, char **argv) | |||
309 | } | 308 | } |
310 | } | 309 | } |
311 | 310 | ||
312 | if (!inet_aton(target, &dst)) { | 311 | /* if (!inet_aton(target, &dst)) - not needed */ { |
313 | len_and_sockaddr *lsa; | 312 | len_and_sockaddr *lsa; |
314 | lsa = xhost_and_af2sockaddr(target, 0, AF_INET); | 313 | lsa = xhost_and_af2sockaddr(target, 0, AF_INET); |
315 | memcpy(&dst, &lsa->sin.sin_addr.s_addr, 4); | 314 | memcpy(&dst, &lsa->sin.sin_addr.s_addr, 4); |
@@ -321,23 +320,23 @@ int arping_main(int argc, char **argv) | |||
321 | bb_error_msg_and_die("invalid source address %s", source); | 320 | bb_error_msg_and_die("invalid source address %s", source); |
322 | } | 321 | } |
323 | 322 | ||
324 | if (!(option_mask32 & DAD) && (option_mask32 & UNSOLICITED) && src.s_addr == 0) | 323 | if ((option_mask32 & (DAD|UNSOLICITED)) == UNSOLICITED && src.s_addr == 0) |
325 | src = dst; | 324 | src = dst; |
326 | 325 | ||
327 | if (!(option_mask32 & DAD) || src.s_addr) { | 326 | if (!(option_mask32 & DAD) || src.s_addr) { |
328 | struct sockaddr_in saddr; | 327 | struct sockaddr_in saddr; |
329 | int probe_fd = xsocket(AF_INET, SOCK_DGRAM, 0); | 328 | int probe_fd = xsocket(AF_INET, SOCK_DGRAM, 0); |
330 | 329 | ||
331 | if (device) { | 330 | if (setsockopt(probe_fd, SOL_SOCKET, SO_BINDTODEVICE, device, strlen(device) + 1) == -1) |
332 | if (setsockopt(probe_fd, SOL_SOCKET, SO_BINDTODEVICE, device, strlen(device) + 1) == -1) | 331 | bb_perror_msg("cannot bind to device %s", device); |
333 | bb_perror_msg("cannot bind to device %s", device); | ||
334 | } | ||
335 | memset(&saddr, 0, sizeof(saddr)); | 332 | memset(&saddr, 0, sizeof(saddr)); |
336 | saddr.sin_family = AF_INET; | 333 | saddr.sin_family = AF_INET; |
337 | if (src.s_addr) { | 334 | if (src.s_addr) { |
335 | /* Check that this is indeed our IP */ | ||
338 | saddr.sin_addr = src; | 336 | saddr.sin_addr = src; |
339 | xbind(probe_fd, (struct sockaddr *) &saddr, sizeof(saddr)); | 337 | xbind(probe_fd, (struct sockaddr *) &saddr, sizeof(saddr)); |
340 | } else if (!(option_mask32 & DAD)) { | 338 | } else { /* !(option_mask32 & DAD) case */ |
339 | /* Find IP address on this iface */ | ||
341 | socklen_t alen = sizeof(saddr); | 340 | socklen_t alen = sizeof(saddr); |
342 | 341 | ||
343 | saddr.sin_port = htons(1025); | 342 | saddr.sin_port = htons(1025); |
@@ -347,23 +346,25 @@ int arping_main(int argc, char **argv) | |||
347 | bb_perror_msg("setsockopt(SO_DONTROUTE)"); | 346 | bb_perror_msg("setsockopt(SO_DONTROUTE)"); |
348 | xconnect(probe_fd, (struct sockaddr *) &saddr, sizeof(saddr)); | 347 | xconnect(probe_fd, (struct sockaddr *) &saddr, sizeof(saddr)); |
349 | if (getsockname(probe_fd, (struct sockaddr *) &saddr, &alen) == -1) { | 348 | if (getsockname(probe_fd, (struct sockaddr *) &saddr, &alen) == -1) { |
350 | bb_error_msg_and_die("getsockname"); | 349 | bb_perror_msg_and_die("getsockname"); |
351 | } | 350 | } |
351 | if (saddr.sin_family != AF_INET) | ||
352 | bb_error_msg_and_die("no IP address configured"); | ||
352 | src = saddr.sin_addr; | 353 | src = saddr.sin_addr; |
353 | } | 354 | } |
354 | close(probe_fd); | 355 | close(probe_fd); |
355 | } | 356 | } |
356 | 357 | ||
357 | me.sll_family = AF_PACKET; | 358 | me.sll_family = AF_PACKET; |
358 | me.sll_ifindex = ifindex; | 359 | //me.sll_ifindex = ifindex; - done before |
359 | me.sll_protocol = htons(ETH_P_ARP); | 360 | me.sll_protocol = htons(ETH_P_ARP); |
360 | xbind(sock, (struct sockaddr *) &me, sizeof(me)); | 361 | xbind(sock_fd, (struct sockaddr *) &me, sizeof(me)); |
361 | 362 | ||
362 | { | 363 | { |
363 | socklen_t alen = sizeof(me); | 364 | socklen_t alen = sizeof(me); |
364 | 365 | ||
365 | if (getsockname(sock, (struct sockaddr *) &me, &alen) == -1) { | 366 | if (getsockname(sock_fd, (struct sockaddr *) &me, &alen) == -1) { |
366 | bb_error_msg_and_die("getsockname"); | 367 | bb_perror_msg_and_die("getsockname"); |
367 | } | 368 | } |
368 | } | 369 | } |
369 | if (me.sll_halen == 0) { | 370 | if (me.sll_halen == 0) { |
@@ -373,14 +374,10 @@ int arping_main(int argc, char **argv) | |||
373 | he = me; | 374 | he = me; |
374 | memset(he.sll_addr, -1, he.sll_halen); | 375 | memset(he.sll_addr, -1, he.sll_halen); |
375 | 376 | ||
376 | if (!src.s_addr && !(option_mask32 & DAD)) { | ||
377 | bb_error_msg_and_die("no src address in the non-DAD mode"); | ||
378 | } | ||
379 | |||
380 | if (!(option_mask32 & QUIET)) { | 377 | if (!(option_mask32 & QUIET)) { |
381 | printf("ARPING to %s from %s via %s\n", | 378 | /* inet_ntoa uses static storage, can't use in same printf */ |
382 | inet_ntoa(dst), inet_ntoa(src), | 379 | printf("ARPING to %s", inet_ntoa(dst)); |
383 | device ? device : "unknown"); | 380 | printf(" from %s via %s\n", inet_ntoa(src), device); |
384 | } | 381 | } |
385 | 382 | ||
386 | { | 383 | { |
@@ -405,7 +402,7 @@ int arping_main(int argc, char **argv) | |||
405 | socklen_t alen = sizeof(from); | 402 | socklen_t alen = sizeof(from); |
406 | int cc; | 403 | int cc; |
407 | 404 | ||
408 | cc = recvfrom(sock, packet, 4096, 0, (struct sockaddr *) &from, &alen); | 405 | cc = recvfrom(sock_fd, packet, 4096, 0, (struct sockaddr *) &from, &alen); |
409 | if (cc < 0) { | 406 | if (cc < 0) { |
410 | bb_perror_msg("recvfrom"); | 407 | bb_perror_msg("recvfrom"); |
411 | continue; | 408 | continue; |