8 |
* Busybox port: Nick Fedchik <nick@fedchik.org.ua> |
* Busybox port: Nick Fedchik <nick@fedchik.org.ua> |
9 |
*/ |
*/ |
10 |
|
|
|
#include <sys/ioctl.h> |
|
|
#include <signal.h> |
|
|
|
|
11 |
#include <arpa/inet.h> |
#include <arpa/inet.h> |
12 |
#include <net/if.h> |
#include <net/if.h> |
13 |
#include <netinet/ether.h> |
#include <netinet/ether.h> |
14 |
#include <netpacket/packet.h> |
#include <netpacket/packet.h> |
15 |
|
|
16 |
#include "busybox.h" |
#include "libbb.h" |
17 |
|
|
18 |
static struct in_addr src; |
/* We don't expect to see 1000+ seconds delay, unsigned is enough */ |
19 |
static struct in_addr dst; |
#define MONOTONIC_US() ((unsigned)monotonic_us()) |
|
static struct sockaddr_ll me; |
|
|
static struct sockaddr_ll he; |
|
|
static struct timeval last; |
|
|
|
|
|
enum cfg_e { |
|
|
dad = 1, |
|
|
unsolicited = 2, |
|
|
advert = 4, |
|
|
quiet = 8, |
|
|
quit_on_reply = 16, |
|
|
broadcast_only = 32, |
|
|
unicasting = 64 |
|
|
}; |
|
|
static int cfg; |
|
20 |
|
|
21 |
static int s; |
enum { |
22 |
static unsigned count = UINT_MAX; |
DAD = 1, |
23 |
static unsigned timeout; |
UNSOLICITED = 2, |
24 |
static int sent; |
ADVERT = 4, |
25 |
static int brd_sent; |
QUIET = 8, |
26 |
static int received; |
QUIT_ON_REPLY = 16, |
27 |
static int brd_recv; |
BCAST_ONLY = 32, |
28 |
static int req_recv; |
UNICASTING = 64 |
29 |
|
}; |
30 |
|
|
31 |
#define MS_TDIFF(tv1,tv2) ( ((tv1).tv_sec-(tv2).tv_sec)*1000 + \ |
struct globals { |
32 |
((tv1).tv_usec-(tv2).tv_usec)/1000 ) |
struct in_addr src; |
33 |
|
struct in_addr dst; |
34 |
|
struct sockaddr_ll me; |
35 |
|
struct sockaddr_ll he; |
36 |
|
int sock_fd; |
37 |
|
|
38 |
|
int count; // = -1; |
39 |
|
unsigned last; |
40 |
|
unsigned timeout_us; |
41 |
|
unsigned start; |
42 |
|
|
43 |
|
unsigned sent; |
44 |
|
unsigned brd_sent; |
45 |
|
unsigned received; |
46 |
|
unsigned brd_recv; |
47 |
|
unsigned req_recv; |
48 |
|
}; |
49 |
|
#define G (*(struct globals*)&bb_common_bufsiz1) |
50 |
|
#define src (G.src ) |
51 |
|
#define dst (G.dst ) |
52 |
|
#define me (G.me ) |
53 |
|
#define he (G.he ) |
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 { \ |
65 |
|
count = -1; \ |
66 |
|
} while (0) |
67 |
|
|
68 |
|
// If GNUisms are not available... |
69 |
|
//static void *mempcpy(void *_dst, const void *_src, int n) |
70 |
|
//{ |
71 |
|
// memcpy(_dst, _src, n); |
72 |
|
// return (char*)_dst + n; |
73 |
|
//} |
74 |
|
|
75 |
static int send_pack(int sock, struct in_addr *src_addr, |
static int send_pack(struct in_addr *src_addr, |
76 |
struct in_addr *dst_addr, struct sockaddr_ll *ME, |
struct in_addr *dst_addr, struct sockaddr_ll *ME, |
77 |
struct sockaddr_ll *HE) |
struct sockaddr_ll *HE) |
78 |
{ |
{ |
79 |
int err; |
int err; |
80 |
struct timeval now; |
unsigned char buf[256]; |
|
RESERVE_CONFIG_UBUFFER(buf, 256); |
|
81 |
struct arphdr *ah = (struct arphdr *) buf; |
struct arphdr *ah = (struct arphdr *) buf; |
82 |
unsigned char *p = (unsigned char *) (ah + 1); |
unsigned char *p = (unsigned char *) (ah + 1); |
83 |
|
|
|
ah->ar_hrd = htons(ME->sll_hatype); |
|
84 |
ah->ar_hrd = htons(ARPHRD_ETHER); |
ah->ar_hrd = htons(ARPHRD_ETHER); |
85 |
ah->ar_pro = htons(ETH_P_IP); |
ah->ar_pro = htons(ETH_P_IP); |
86 |
ah->ar_hln = ME->sll_halen; |
ah->ar_hln = ME->sll_halen; |
87 |
ah->ar_pln = 4; |
ah->ar_pln = 4; |
88 |
ah->ar_op = cfg & advert ? htons(ARPOP_REPLY) : htons(ARPOP_REQUEST); |
ah->ar_op = option_mask32 & ADVERT ? htons(ARPOP_REPLY) : htons(ARPOP_REQUEST); |
89 |
|
|
90 |
memcpy(p, &ME->sll_addr, ah->ar_hln); |
p = mempcpy(p, &ME->sll_addr, ah->ar_hln); |
91 |
p += ME->sll_halen; |
p = mempcpy(p, src_addr, 4); |
92 |
|
|
93 |
memcpy(p, src_addr, 4); |
if (option_mask32 & ADVERT) |
94 |
p += 4; |
p = mempcpy(p, &ME->sll_addr, ah->ar_hln); |
|
|
|
|
if (cfg & advert) |
|
|
memcpy(p, &ME->sll_addr, ah->ar_hln); |
|
95 |
else |
else |
96 |
memcpy(p, &HE->sll_addr, ah->ar_hln); |
p = mempcpy(p, &HE->sll_addr, ah->ar_hln); |
|
p += ah->ar_hln; |
|
97 |
|
|
98 |
memcpy(p, dst_addr, 4); |
p = mempcpy(p, dst_addr, 4); |
|
p += 4; |
|
99 |
|
|
100 |
gettimeofday(&now, NULL); |
err = sendto(sock_fd, buf, p - buf, 0, (struct sockaddr *) HE, sizeof(*HE)); |
|
err = sendto(sock, buf, p - buf, 0, (struct sockaddr *) HE, sizeof(*HE)); |
|
101 |
if (err == p - buf) { |
if (err == p - buf) { |
102 |
last = now; |
last = MONOTONIC_US(); |
103 |
sent++; |
sent++; |
104 |
if (!(cfg & unicasting)) |
if (!(option_mask32 & UNICASTING)) |
105 |
brd_sent++; |
brd_sent++; |
106 |
} |
} |
|
RELEASE_CONFIG_BUFFER(buf); |
|
107 |
return err; |
return err; |
108 |
} |
} |
109 |
|
|
110 |
|
static void finish(void) NORETURN; |
111 |
static void finish(void) |
static void finish(void) |
112 |
{ |
{ |
113 |
if (!(cfg & quiet)) { |
if (!(option_mask32 & QUIET)) { |
114 |
printf("Sent %d probe(s) (%d broadcast(s))\n" |
printf("Sent %u probe(s) (%u broadcast(s))\n" |
115 |
"Received %d repl%s" |
"Received %u repl%s" |
116 |
" (%d request(s), %d broadcast(s))\n", |
" (%u request(s), %u broadcast(s))\n", |
117 |
sent, brd_sent, |
sent, brd_sent, |
118 |
received, (received == 1) ? "ies" : "y", |
received, (received == 1) ? "ies" : "y", |
119 |
req_recv, brd_recv); |
req_recv, brd_recv); |
120 |
} |
} |
121 |
if (cfg & dad) |
if (option_mask32 & DAD) |
122 |
exit(!!received); |
exit(!!received); |
123 |
if (cfg & unsolicited) |
if (option_mask32 & UNSOLICITED) |
124 |
exit(0); |
exit(EXIT_SUCCESS); |
125 |
exit(!received); |
exit(!received); |
126 |
} |
} |
127 |
|
|
128 |
static void catcher(void) |
static void catcher(void) |
129 |
{ |
{ |
130 |
struct timeval tv; |
unsigned now; |
|
static struct timeval start; |
|
|
|
|
|
gettimeofday(&tv, NULL); |
|
131 |
|
|
132 |
if (start.tv_sec == 0) |
now = MONOTONIC_US(); |
133 |
start = tv; |
if (start == 0) |
134 |
|
start = now; |
135 |
|
|
136 |
if (count-- == 0 |
if (count == 0 || (timeout_us && (now - start) > timeout_us)) |
|
|| (timeout && MS_TDIFF(tv, start) > timeout * 1000 + 500)) |
|
137 |
finish(); |
finish(); |
138 |
|
|
139 |
if (last.tv_sec == 0 || MS_TDIFF(tv, last) > 500) { |
/* count < 0 means "infinite count" */ |
140 |
send_pack(s, &src, &dst, &me, &he); |
if (count > 0) |
141 |
if (count == 0 && (cfg & unsolicited)) |
count--; |
142 |
|
|
143 |
|
if (last == 0 || (now - last) > 500000) { |
144 |
|
send_pack(&src, &dst, &me, &he); |
145 |
|
if (count == 0 && (option_mask32 & UNSOLICITED)) |
146 |
finish(); |
finish(); |
147 |
} |
} |
148 |
alarm(1); |
alarm(1); |
149 |
} |
} |
150 |
|
|
151 |
static int recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM) |
static bool recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM) |
152 |
{ |
{ |
153 |
struct arphdr *ah = (struct arphdr *) buf; |
struct arphdr *ah = (struct arphdr *) buf; |
154 |
unsigned char *p = (unsigned char *) (ah + 1); |
unsigned char *p = (unsigned char *) (ah + 1); |
158 |
if (FROM->sll_pkttype != PACKET_HOST |
if (FROM->sll_pkttype != PACKET_HOST |
159 |
&& FROM->sll_pkttype != PACKET_BROADCAST |
&& FROM->sll_pkttype != PACKET_BROADCAST |
160 |
&& FROM->sll_pkttype != PACKET_MULTICAST) |
&& FROM->sll_pkttype != PACKET_MULTICAST) |
161 |
return 0; |
return false; |
162 |
|
|
163 |
/* Only these types are recognised */ |
/* Only these types are recognised */ |
164 |
if (ah->ar_op != htons(ARPOP_REQUEST) && ah->ar_op != htons(ARPOP_REPLY)) |
if (ah->ar_op != htons(ARPOP_REQUEST) && ah->ar_op != htons(ARPOP_REPLY)) |
165 |
return 0; |
return false; |
166 |
|
|
167 |
/* ARPHRD check and this darned FDDI hack here :-( */ |
/* ARPHRD check and this darned FDDI hack here :-( */ |
168 |
if (ah->ar_hrd != htons(FROM->sll_hatype) |
if (ah->ar_hrd != htons(FROM->sll_hatype) |
169 |
&& (FROM->sll_hatype != ARPHRD_FDDI || ah->ar_hrd != htons(ARPHRD_ETHER))) |
&& (FROM->sll_hatype != ARPHRD_FDDI || ah->ar_hrd != htons(ARPHRD_ETHER))) |
170 |
return 0; |
return false; |
171 |
|
|
172 |
/* Protocol must be IP. */ |
/* Protocol must be IP. */ |
173 |
if (ah->ar_pro != htons(ETH_P_IP)) |
if (ah->ar_pro != htons(ETH_P_IP) |
174 |
return 0; |
|| (ah->ar_pln != 4) |
175 |
if (ah->ar_pln != 4) |
|| (ah->ar_hln != me.sll_halen) |
176 |
return 0; |
|| (len < (int)(sizeof(*ah) + 2 * (4 + ah->ar_hln)))) |
177 |
if (ah->ar_hln != me.sll_halen) |
return false; |
178 |
return 0; |
|
|
if (len < sizeof(*ah) + 2 * (4 + ah->ar_hln)) |
|
|
return 0; |
|
179 |
memcpy(&src_ip, p + ah->ar_hln, 4); |
memcpy(&src_ip, p + ah->ar_hln, 4); |
180 |
memcpy(&dst_ip, p + ah->ar_hln + 4 + ah->ar_hln, 4); |
memcpy(&dst_ip, p + ah->ar_hln + 4 + ah->ar_hln, 4); |
181 |
if (!(cfg & dad)) { |
|
182 |
if (src_ip.s_addr != dst.s_addr) |
if (dst.s_addr != src_ip.s_addr) |
183 |
return 0; |
return false; |
184 |
if (src.s_addr != dst_ip.s_addr) |
if (!(option_mask32 & DAD)) { |
185 |
return 0; |
if ((src.s_addr != dst_ip.s_addr) |
186 |
if (memcmp(p + ah->ar_hln + 4, &me.sll_addr, ah->ar_hln)) |
|| (memcmp(p + ah->ar_hln + 4, &me.sll_addr, ah->ar_hln))) |
187 |
return 0; |
return false; |
188 |
} else { |
} else { |
189 |
/* DAD packet was: |
/* DAD packet was: |
190 |
src_ip = 0 (or some src) |
src_ip = 0 (or some src) |
199 |
also that it matches to dst_ip, otherwise |
also that it matches to dst_ip, otherwise |
200 |
dst_ip/dst_hw do not matter. |
dst_ip/dst_hw do not matter. |
201 |
*/ |
*/ |
202 |
if (src_ip.s_addr != dst.s_addr) |
if ((memcmp(p, &me.sll_addr, me.sll_halen) == 0) |
203 |
return 0; |
|| (src.s_addr && src.s_addr != dst_ip.s_addr)) |
204 |
if (memcmp(p, &me.sll_addr, me.sll_halen) == 0) |
return false; |
|
return 0; |
|
|
if (src.s_addr && src.s_addr != dst_ip.s_addr) |
|
|
return 0; |
|
205 |
} |
} |
206 |
if (!(cfg & quiet)) { |
if (!(option_mask32 & QUIET)) { |
207 |
int s_printed = 0; |
int s_printed = 0; |
|
struct timeval tv; |
|
|
|
|
|
gettimeofday(&tv, NULL); |
|
208 |
|
|
209 |
printf("%scast re%s from %s [%s]", |
printf("%scast re%s from %s [%s]", |
210 |
FROM->sll_pkttype == PACKET_HOST ? "Uni" : "Broad", |
FROM->sll_pkttype == PACKET_HOST ? "Uni" : "Broad", |
222 |
ether_ntoa((struct ether_addr *) p + ah->ar_hln + 4)); |
ether_ntoa((struct ether_addr *) p + ah->ar_hln + 4)); |
223 |
} |
} |
224 |
|
|
225 |
if (last.tv_sec) { |
if (last) { |
226 |
long usecs = (tv.tv_sec - last.tv_sec) * 1000000 + |
unsigned diff = MONOTONIC_US() - last; |
227 |
tv.tv_usec - last.tv_usec; |
printf(" %u.%03ums\n", diff / 1000, diff % 1000); |
|
long msecs = (usecs + 500) / 1000; |
|
|
|
|
|
usecs -= msecs * 1000 - 500; |
|
|
printf(" %ld.%03ldms\n", msecs, usecs); |
|
228 |
} else { |
} else { |
229 |
printf(" UNSOLICITED?\n"); |
printf(" UNSOLICITED?\n"); |
230 |
} |
} |
235 |
brd_recv++; |
brd_recv++; |
236 |
if (ah->ar_op == htons(ARPOP_REQUEST)) |
if (ah->ar_op == htons(ARPOP_REQUEST)) |
237 |
req_recv++; |
req_recv++; |
238 |
if (cfg & quit_on_reply) |
if (option_mask32 & QUIT_ON_REPLY) |
239 |
finish(); |
finish(); |
240 |
if (!(cfg & broadcast_only)) { |
if (!(option_mask32 & BCAST_ONLY)) { |
241 |
memcpy(he.sll_addr, p, me.sll_halen); |
memcpy(he.sll_addr, p, me.sll_halen); |
242 |
cfg |= unicasting; |
option_mask32 |= UNICASTING; |
243 |
} |
} |
244 |
return 1; |
return true; |
245 |
} |
} |
246 |
|
|
247 |
int arping_main(int argc, char **argv) |
int arping_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
248 |
|
int arping_main(int argc UNUSED_PARAM, char **argv) |
249 |
{ |
{ |
250 |
char *device = "eth0"; |
const char *device = "eth0"; |
|
int ifindex; |
|
251 |
char *source = NULL; |
char *source = NULL; |
252 |
char *target; |
char *target; |
253 |
|
unsigned char *packet; |
254 |
|
char *err_str; |
255 |
|
|
256 |
s = xsocket(PF_PACKET, SOCK_DGRAM, 0); |
INIT_G(); |
257 |
|
|
258 |
|
sock_fd = xsocket(AF_PACKET, SOCK_DGRAM, 0); |
259 |
|
|
260 |
// Drop suid root privileges |
// Drop suid root privileges |
261 |
xsetuid(getuid()); |
// Need to remove SUID_NEVER from applets.h for this to work |
262 |
|
//xsetuid(getuid()); |
263 |
|
|
264 |
|
err_str = xasprintf("interface %s %%s", device); |
265 |
{ |
{ |
266 |
unsigned opt; |
unsigned opt; |
267 |
char *_count, *_timeout; |
char *str_timeout; |
268 |
|
|
269 |
/* Dad also sets quit_on_reply. |
/* Dad also sets quit_on_reply. |
270 |
* Advert also sets unsolicited. |
* Advert also sets unsolicited. |
271 |
*/ |
*/ |
272 |
opt_complementary = "Df:AU"; |
opt_complementary = "=1:Df:AU:c+"; |
273 |
opt = getopt32(argc, argv, "DUAqfbc:w:i:s:", |
opt = getopt32(argv, "DUAqfbc:w:I:s:", |
274 |
&_count, &_timeout, &device, &source); |
&count, &str_timeout, &device, &source); |
|
cfg |= opt & 0x3f; /* set respective flags */ |
|
|
if (opt & 0x40) /* -c: count */ |
|
|
count = xatou(_count); |
|
275 |
if (opt & 0x80) /* -w: timeout */ |
if (opt & 0x80) /* -w: timeout */ |
276 |
timeout = xatoul_range(_timeout, 0, INT_MAX/2000); |
timeout_us = xatou_range(str_timeout, 0, INT_MAX/2000000) * 1000000 + 500000; |
|
//if (opt & 0x100) /* -i: interface */ |
|
|
if (strlen(device) > IF_NAMESIZE) { |
|
|
bb_error_msg_and_die("interface name '%s' is too long", |
|
|
device); |
|
|
} |
|
277 |
//if (opt & 0x200) /* -s: source */ |
//if (opt & 0x200) /* -s: source */ |
278 |
|
option_mask32 &= 0x3f; /* set respective flags */ |
279 |
} |
} |
|
argc -= optind; |
|
|
argv += optind; |
|
|
|
|
|
if (argc != 1) |
|
|
bb_show_usage(); |
|
280 |
|
|
281 |
target = *argv; |
target = argv[optind]; |
282 |
|
|
283 |
xfunc_error_retval = 2; |
xfunc_error_retval = 2; |
284 |
|
|
286 |
struct ifreq ifr; |
struct ifreq ifr; |
287 |
|
|
288 |
memset(&ifr, 0, sizeof(ifr)); |
memset(&ifr, 0, sizeof(ifr)); |
289 |
strncpy(ifr.ifr_name, device, IFNAMSIZ - 1); |
strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name) - 1); |
290 |
if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) { |
/* We use ifr.ifr_name in error msg so that problem |
291 |
bb_error_msg_and_die("interface %s not found", device); |
* with truncated name will be visible */ |
292 |
} |
ioctl_or_perror_and_die(sock_fd, SIOCGIFINDEX, &ifr, err_str, "not found"); |
293 |
ifindex = ifr.ifr_ifindex; |
me.sll_ifindex = ifr.ifr_ifindex; |
294 |
|
|
295 |
|
xioctl(sock_fd, SIOCGIFFLAGS, (char *) &ifr); |
296 |
|
|
|
if (ioctl(s, SIOCGIFFLAGS, (char *) &ifr)) { |
|
|
bb_error_msg_and_die("SIOCGIFFLAGS"); |
|
|
} |
|
297 |
if (!(ifr.ifr_flags & IFF_UP)) { |
if (!(ifr.ifr_flags & IFF_UP)) { |
298 |
bb_error_msg_and_die("interface %s is down", device); |
bb_error_msg_and_die(err_str, "is down"); |
299 |
} |
} |
300 |
if (ifr.ifr_flags & (IFF_NOARP | IFF_LOOPBACK)) { |
if (ifr.ifr_flags & (IFF_NOARP | IFF_LOOPBACK)) { |
301 |
bb_error_msg("interface %s is not ARPable", device); |
bb_error_msg(err_str, "is not ARPable"); |
302 |
return (cfg & dad ? 0 : 2); |
return (option_mask32 & DAD ? 0 : 2); |
303 |
} |
} |
304 |
} |
} |
305 |
|
|
306 |
if (!inet_aton(target, &dst)) { |
/* if (!inet_aton(target, &dst)) - not needed */ { |
307 |
struct hostent *hp; |
len_and_sockaddr *lsa; |
308 |
|
lsa = xhost_and_af2sockaddr(target, 0, AF_INET); |
309 |
hp = gethostbyname2(target, AF_INET); |
memcpy(&dst, &lsa->u.sin.sin_addr.s_addr, 4); |
310 |
if (!hp) { |
if (ENABLE_FEATURE_CLEAN_UP) |
311 |
bb_error_msg_and_die("invalid or unknown target %s", target); |
free(lsa); |
|
} |
|
|
memcpy(&dst, hp->h_addr, 4); |
|
312 |
} |
} |
313 |
|
|
314 |
if (source && !inet_aton(source, &src)) { |
if (source && !inet_aton(source, &src)) { |
315 |
bb_error_msg_and_die("invalid source address %s", source); |
bb_error_msg_and_die("invalid source address %s", source); |
316 |
} |
} |
317 |
|
|
318 |
if (!(cfg & dad) && (cfg & unsolicited) && src.s_addr == 0) |
if ((option_mask32 & (DAD|UNSOLICITED)) == UNSOLICITED && src.s_addr == 0) |
319 |
src = dst; |
src = dst; |
320 |
|
|
321 |
if (!(cfg & dad) || src.s_addr) { |
if (!(option_mask32 & DAD) || src.s_addr) { |
322 |
struct sockaddr_in saddr; |
struct sockaddr_in saddr; |
323 |
int probe_fd = xsocket(AF_INET, SOCK_DGRAM, 0); |
int probe_fd = xsocket(AF_INET, SOCK_DGRAM, 0); |
324 |
|
|
325 |
if (device) { |
setsockopt_bindtodevice(probe_fd, device); |
|
if (setsockopt(probe_fd, SOL_SOCKET, SO_BINDTODEVICE, device, strlen(device) + 1) == -1) |
|
|
bb_error_msg("warning: interface %s is ignored", device); |
|
|
} |
|
326 |
memset(&saddr, 0, sizeof(saddr)); |
memset(&saddr, 0, sizeof(saddr)); |
327 |
saddr.sin_family = AF_INET; |
saddr.sin_family = AF_INET; |
328 |
if (src.s_addr) { |
if (src.s_addr) { |
329 |
|
/* Check that this is indeed our IP */ |
330 |
saddr.sin_addr = src; |
saddr.sin_addr = src; |
331 |
xbind(probe_fd, (struct sockaddr *) &saddr, sizeof(saddr)); |
xbind(probe_fd, (struct sockaddr *) &saddr, sizeof(saddr)); |
332 |
} else if (!(cfg & dad)) { |
} else { /* !(option_mask32 & DAD) case */ |
333 |
static const int on = 1; |
/* Find IP address on this iface */ |
334 |
socklen_t alen = sizeof(saddr); |
socklen_t alen = sizeof(saddr); |
335 |
|
|
336 |
saddr.sin_port = htons(1025); |
saddr.sin_port = htons(1025); |
337 |
saddr.sin_addr = dst; |
saddr.sin_addr = dst; |
338 |
|
|
339 |
if (setsockopt(probe_fd, SOL_SOCKET, SO_DONTROUTE, (char *) &on, sizeof(on)) == -1) |
if (setsockopt(probe_fd, SOL_SOCKET, SO_DONTROUTE, &const_int_1, sizeof(const_int_1)) == -1) |
340 |
bb_perror_msg("warning: setsockopt(SO_DONTROUTE)"); |
bb_perror_msg("setsockopt(SO_DONTROUTE)"); |
341 |
xconnect(probe_fd, (struct sockaddr *) &saddr, sizeof(saddr)); |
xconnect(probe_fd, (struct sockaddr *) &saddr, sizeof(saddr)); |
342 |
if (getsockname(probe_fd, (struct sockaddr *) &saddr, &alen) == -1) { |
if (getsockname(probe_fd, (struct sockaddr *) &saddr, &alen) == -1) { |
343 |
bb_error_msg_and_die("getsockname"); |
bb_perror_msg_and_die("getsockname"); |
344 |
} |
} |
345 |
|
if (saddr.sin_family != AF_INET) |
346 |
|
bb_error_msg_and_die("no IP address configured"); |
347 |
src = saddr.sin_addr; |
src = saddr.sin_addr; |
348 |
} |
} |
349 |
close(probe_fd); |
close(probe_fd); |
350 |
} |
} |
351 |
|
|
352 |
me.sll_family = AF_PACKET; |
me.sll_family = AF_PACKET; |
353 |
me.sll_ifindex = ifindex; |
//me.sll_ifindex = ifindex; - done before |
354 |
me.sll_protocol = htons(ETH_P_ARP); |
me.sll_protocol = htons(ETH_P_ARP); |
355 |
xbind(s, (struct sockaddr *) &me, sizeof(me)); |
xbind(sock_fd, (struct sockaddr *) &me, sizeof(me)); |
356 |
|
|
357 |
{ |
{ |
358 |
socklen_t alen = sizeof(me); |
socklen_t alen = sizeof(me); |
359 |
|
|
360 |
if (getsockname(s, (struct sockaddr *) &me, &alen) == -1) { |
if (getsockname(sock_fd, (struct sockaddr *) &me, &alen) == -1) { |
361 |
bb_error_msg_and_die("getsockname"); |
bb_perror_msg_and_die("getsockname"); |
362 |
} |
} |
363 |
} |
} |
364 |
if (me.sll_halen == 0) { |
if (me.sll_halen == 0) { |
365 |
bb_error_msg("interface \"%s\" is not ARPable (no ll address)", device); |
bb_error_msg(err_str, "is not ARPable (no ll address)"); |
366 |
return (cfg & dad ? 0 : 2); |
return (option_mask32 & DAD ? 0 : 2); |
367 |
} |
} |
368 |
he = me; |
he = me; |
369 |
memset(he.sll_addr, -1, he.sll_halen); |
memset(he.sll_addr, -1, he.sll_halen); |
370 |
|
|
371 |
if (!(cfg & quiet)) { |
if (!(option_mask32 & QUIET)) { |
372 |
printf("ARPING to %s from %s via %s\n", |
/* inet_ntoa uses static storage, can't use in same printf */ |
373 |
inet_ntoa(dst), inet_ntoa(src), |
printf("ARPING to %s", inet_ntoa(dst)); |
374 |
device ? device : "unknown"); |
printf(" from %s via %s\n", inet_ntoa(src), device); |
375 |
} |
} |
376 |
|
|
377 |
if (!src.s_addr && !(cfg & dad)) { |
signal_SA_RESTART_empty_mask(SIGINT, (void (*)(int))finish); |
378 |
bb_error_msg_and_die("no src address in the non-DAD mode"); |
signal_SA_RESTART_empty_mask(SIGALRM, (void (*)(int))catcher); |
|
} |
|
|
|
|
|
{ |
|
|
struct sigaction sa; |
|
|
|
|
|
memset(&sa, 0, sizeof(sa)); |
|
|
sa.sa_flags = SA_RESTART; |
|
|
|
|
|
sa.sa_handler = (void (*)(int)) finish; |
|
|
sigaction(SIGINT, &sa, NULL); |
|
|
|
|
|
sa.sa_handler = (void (*)(int)) catcher; |
|
|
sigaction(SIGALRM, &sa, NULL); |
|
|
} |
|
379 |
|
|
380 |
catcher(); |
catcher(); |
381 |
|
|
382 |
|
packet = xmalloc(4096); |
383 |
while (1) { |
while (1) { |
384 |
sigset_t sset, osset; |
sigset_t sset, osset; |
|
RESERVE_CONFIG_UBUFFER(packet, 4096); |
|
385 |
struct sockaddr_ll from; |
struct sockaddr_ll from; |
386 |
socklen_t alen = sizeof(from); |
socklen_t alen = sizeof(from); |
387 |
int cc; |
int cc; |
388 |
|
|
389 |
cc = recvfrom(s, packet, 4096, 0, (struct sockaddr *) &from, &alen); |
cc = recvfrom(sock_fd, packet, 4096, 0, (struct sockaddr *) &from, &alen); |
390 |
if (cc < 0) { |
if (cc < 0) { |
391 |
bb_perror_msg("recvfrom"); |
bb_perror_msg("recvfrom"); |
392 |
continue; |
continue; |
397 |
sigprocmask(SIG_BLOCK, &sset, &osset); |
sigprocmask(SIG_BLOCK, &sset, &osset); |
398 |
recv_pack(packet, cc, &from); |
recv_pack(packet, cc, &from); |
399 |
sigprocmask(SIG_SETMASK, &osset, NULL); |
sigprocmask(SIG_SETMASK, &osset, NULL); |
|
RELEASE_CONFIG_BUFFER(packet); |
|
400 |
} |
} |
401 |
} |
} |