1 /* arping - send ARP REQUEST to a neighbour host.
2 *
3 * Copyright 2013 Sandeep Sharma <sandeep.jack2756@gmail.com>
4 * Copyright 2013 Kyungwan Han <asura321@gmail.com>
5 *
6 * No Standard.
7
8 USE_ARPING(NEWTOY(arping, "<1>1s:I:w#<0c#<0AUDbqf[+AU][+Df]", TOYFLAG_USR|TOYFLAG_SBIN))
9
10 config ARPING
11 bool "arping"
12 default n
13 help
14 usage: arping [-fqbDUA] [-c CNT] [-w TIMEOUT] [-I IFACE] [-s SRC_IP] DST_IP
15
16 Send ARP requests/replies
17
18 -f Quit on first ARP reply
19 -q Quiet
20 -b Keep broadcasting, don't go unicast
21 -D Duplicated address detection mode
22 -U Unsolicited ARP mode, update your neighbors
23 -A ARP answer mode, update your neighbors
24 -c N Stop after sending N ARP requests
25 -w TIMEOUT Time to wait for ARP reply, seconds
26 -I IFACE Interface to use (default eth0)
27 -s SRC_IP Sender IP address
28 DST_IP Target IP address
29 */
30 #define FOR_arping
31 #include "toys.h"
32 #include <netinet/ether.h>
33 #include <netpacket/packet.h>
34
35 GLOBALS(
36 long count;
37 unsigned long time_out;
38 char *iface;
39 char *src_ip;
40
41 int sockfd;
42 unsigned long start, end;
43 unsigned sent_at, sent_nr, rcvd_nr, brd_sent, rcvd_req, brd_rcv,
44 unicast_flag;
45 )
46
47 struct sockaddr_ll src_pk, dst_pk;
48 struct in_addr src_addr, dest_addr;
49 extern void *mempcpy(void *dest, const void *src, size_t n);
50
51 // Gets information of INTERFACE and updates IFINDEX, MAC and IP.
get_interface(char * interface,int * ifindex,uint32_t * oip,uint8_t * mac)52 static void get_interface(char *interface, int *ifindex, uint32_t *oip,
53 uint8_t *mac)
54 {
55 struct ifreq req;
56 struct sockaddr_in *ip;
57 int fd = xsocket(AF_INET, SOCK_RAW, IPPROTO_RAW);
58
59 req.ifr_addr.sa_family = AF_INET;
60 xstrncpy(req.ifr_name, interface, IFNAMSIZ);
61 req.ifr_name[IFNAMSIZ-1] = '\0';
62
63 xioctl(fd, SIOCGIFFLAGS, &req);
64 if (!(req.ifr_flags & IFF_UP)) return;
65
66 if (oip) {
67 xioctl(fd, SIOCGIFADDR, &req);
68 ip = (struct sockaddr_in*) &req.ifr_addr;
69 *oip = ntohl(ip->sin_addr.s_addr);
70 }
71 if (ifindex) {
72 xioctl(fd, SIOCGIFINDEX, &req);
73 *ifindex = req.ifr_ifindex;
74 }
75 if (mac) {
76 xioctl(fd, SIOCGIFHWADDR, &req);
77 memcpy(mac, req.ifr_hwaddr.sa_data, 6);
78 }
79 xclose(fd);
80 }
81
82 // SIGINT handler, Print Number of Packets send or receive details.
done(int sig)83 static void done(int sig)
84 {
85 if (!(toys.optflags & FLAG_q)) {
86 xprintf("Sent %u probe(s) (%u broadcast(s))\n", TT.sent_nr, TT.brd_sent);
87 xprintf("Received %u repl%s (%u request(s), %u broadcast(s))\n",
88 TT.rcvd_nr, TT.rcvd_nr == 1 ? "y":"ies", TT.rcvd_req, TT.brd_rcv);
89 }
90 if (toys.optflags & FLAG_D) exit(!!TT.rcvd_nr);
91 //In -U mode, No reply is expected.
92 if (toys.optflags & FLAG_U) exit(EXIT_SUCCESS);
93 exit(!TT.rcvd_nr);
94 }
95
96 // Create and Send Packet
send_packet()97 static void send_packet()
98 {
99 int ret;
100 unsigned char sbuf[256] = {0,};
101 struct arphdr *arp_h = (struct arphdr *) sbuf;
102 unsigned char *ptr = (unsigned char *)(arp_h + 1);
103
104 arp_h->ar_hrd = htons(ARPHRD_ETHER);
105 arp_h->ar_pro = htons(ETH_P_IP);
106 arp_h->ar_hln = src_pk.sll_halen;
107 arp_h->ar_pln = 4;
108 arp_h->ar_op = (toys.optflags & FLAG_A) ? htons(ARPOP_REPLY)
109 : htons(ARPOP_REQUEST);
110
111 ptr = mempcpy(ptr, &src_pk.sll_addr, src_pk.sll_halen);
112 ptr = mempcpy(ptr, &src_addr, 4);
113 ptr = mempcpy(ptr,
114 (toys.optflags & FLAG_A) ? &src_pk.sll_addr : &dst_pk.sll_addr,
115 src_pk.sll_halen);
116 ptr = mempcpy(ptr, &dest_addr, 4);
117
118 ret = sendto(TT.sockfd, sbuf, ptr - sbuf, 0,
119 (struct sockaddr *)&dst_pk, sizeof(dst_pk));
120 if (ret == ptr - sbuf) {
121 struct timeval tval;
122
123 gettimeofday(&tval, NULL);
124 TT.sent_at = tval.tv_sec * 1000000ULL + tval.tv_usec;
125 TT.sent_nr++;
126 if (!TT.unicast_flag) TT.brd_sent++;
127 }
128 }
129
130 // Receive Packet and filter with valid checks.
recv_from(struct sockaddr_ll * from,int * recv_len)131 static void recv_from(struct sockaddr_ll *from, int *recv_len)
132 {
133 struct in_addr s_ip, d_ip;
134 struct arphdr *arp_hdr = (struct arphdr *)toybuf;
135 unsigned char *p = (unsigned char *)(arp_hdr + 1);
136
137 if (arp_hdr->ar_op != htons(ARPOP_REQUEST) &&
138 arp_hdr->ar_op != htons(ARPOP_REPLY)) return;
139
140 if (from->sll_pkttype != PACKET_HOST && from->sll_pkttype != PACKET_BROADCAST
141 && from->sll_pkttype != PACKET_MULTICAST) return;
142
143 if (arp_hdr->ar_pro != htons(ETH_P_IP) || (arp_hdr->ar_pln != 4)
144 || (arp_hdr->ar_hln != src_pk.sll_halen)
145 || (*recv_len < (int)(sizeof(*arp_hdr) + 2 * (4 + arp_hdr->ar_hln))))
146 return;
147
148 memcpy(&s_ip.s_addr, p + arp_hdr->ar_hln, 4);
149 memcpy(&d_ip.s_addr, p + arp_hdr->ar_hln + 4 + arp_hdr->ar_hln, 4);
150
151 if (dest_addr.s_addr != s_ip.s_addr) return;
152 if (toys.optflags & FLAG_D) {
153 if (src_addr.s_addr && src_addr.s_addr != d_ip.s_addr) return;
154 if (!memcmp(p, &src_pk.sll_addr, src_pk.sll_halen)) return;
155 } else if (src_addr.s_addr != d_ip.s_addr ) return;
156
157 if (!(toys.optflags & FLAG_q)) {
158 printf("%scast re%s from %s [%s]",
159 from->sll_pkttype == PACKET_HOST ? "Uni" : "Broad",
160 arp_hdr->ar_op == htons(ARPOP_REPLY) ? "ply" : "quest",
161 inet_ntoa(s_ip), ether_ntoa((struct ether_addr *) p));
162 if (TT.sent_at) {
163 unsigned delta;
164 struct timeval tval;
165
166 gettimeofday(&tval, NULL);
167 delta = (tval.tv_sec * 1000000ULL + (tval.tv_usec)) - TT.sent_at;
168 xprintf(" %u.%03ums\n", delta / 1000, delta % 1000);
169 }
170 }
171 TT.rcvd_nr++;
172 if (from->sll_pkttype != PACKET_HOST) TT.brd_rcv++;
173 if (arp_hdr->ar_op == htons(ARPOP_REQUEST)) TT.rcvd_req++;
174 if (toys.optflags & FLAG_f) done(0);
175 if (!(toys.optflags & FLAG_b)) {
176 memcpy(dst_pk.sll_addr, p, src_pk.sll_halen);
177 TT.unicast_flag = 1;
178 }
179 }
180
181 // Alarm signal Handle, send packets in one second interval.
send_signal(int sig)182 static void send_signal(int sig)
183 {
184 struct timeval start;
185
186 gettimeofday(&start, NULL);
187 if (!TT.start)
188 TT.end = TT.start = start.tv_sec * 1000 + start.tv_usec / 1000;
189 else TT.end = start.tv_sec*1000 + start.tv_usec / 1000;
190 if (toys.optflags & FLAG_c) {
191 if (!TT.count) done(0);
192 TT.count--;
193 }
194 if ((toys.optflags & FLAG_w) && ((TT.end - TT.start) >
195 ((TT.time_out)*1000))) done(0);
196 send_packet();
197 alarm(1);
198 }
199
arping_main(void)200 void arping_main(void)
201 {
202 struct ifreq ifr;
203 struct sockaddr_ll from;
204 socklen_t len;
205 int if_index, recv_len;
206
207 if (!(toys.optflags & FLAG_I)) TT.iface = "eth0";
208 TT.sockfd = xsocket(AF_PACKET, SOCK_DGRAM, 0);
209
210 memset(&ifr, 0, sizeof(ifr));
211 xstrncpy(ifr.ifr_name, TT.iface, IFNAMSIZ);
212 get_interface(TT.iface, &if_index, NULL, NULL);
213 src_pk.sll_ifindex = if_index;
214
215 xioctl(TT.sockfd, SIOCGIFFLAGS, (char*)&ifr);
216 if (!(ifr.ifr_flags & IFF_UP) && !(toys.optflags & FLAG_q))
217 error_exit("Interface \"%s\" is down", TT.iface);
218 if ((ifr.ifr_flags & (IFF_NOARP | IFF_LOOPBACK))
219 && !(toys.optflags & FLAG_q)) {
220 xprintf("Interface \"%s\" is not ARPable\n", TT.iface);
221 toys.exitval = (toys.optflags & FLAG_D) ? 0 : 2;
222 return;
223 }
224 if (!inet_aton(*toys.optargs, &dest_addr)) {
225 struct hostent *hp = gethostbyname2(*toys.optargs, AF_INET);
226
227 if (!hp) perror_exit("bad address '%s'", *toys.optargs);
228 memcpy(&dest_addr, hp->h_addr, 4);
229 }
230 if ((toys.optflags & FLAG_s) && !(inet_aton(TT.src_ip, &src_addr)))
231 perror_exit("invalid source address '%s'",TT.src_ip);
232 if (!(toys.optflags & FLAG_D) && (toys.optflags & FLAG_U)
233 && !src_addr.s_addr) src_addr = dest_addr;
234 if (!(toys.optflags & FLAG_D) || src_addr.s_addr) {
235 struct sockaddr_in saddr;
236 int p_fd = xsocket(AF_INET, SOCK_DGRAM, 0);
237
238 if (setsockopt(p_fd, SOL_SOCKET, SO_BINDTODEVICE, TT.iface,
239 strlen(TT.iface))) perror_exit("setsockopt");
240
241 memset(&saddr, 0, sizeof(saddr));
242 saddr.sin_family = AF_INET;
243 if (src_addr.s_addr) {
244 saddr.sin_addr = src_addr;
245 xbind(p_fd, (struct sockaddr*)&saddr, sizeof(saddr));
246 } else {
247 uint32_t oip;
248
249 saddr.sin_port = htons(1025);
250 saddr.sin_addr = dest_addr;
251 xconnect(p_fd, (struct sockaddr *) &saddr, sizeof(saddr));
252 get_interface(TT.iface, NULL, &oip, NULL);
253 src_addr.s_addr = htonl(oip);
254 }
255 xclose(p_fd);
256 }
257
258 src_pk.sll_family = AF_PACKET;
259 src_pk.sll_protocol = htons(ETH_P_ARP);
260 xbind(TT.sockfd, (struct sockaddr *)&src_pk, sizeof(src_pk));
261
262 socklen_t alen = sizeof(src_pk);
263 getsockname(TT.sockfd, (struct sockaddr *)&src_pk, &alen);
264 if (!src_pk.sll_halen) {
265 perror_msg("src is not arpable");
266 toys.exitval = (toys.optflags & FLAG_D) ? 0 : 2;
267 return;
268 }
269 if (!(toys.optflags & FLAG_q)) {
270 xprintf("ARPING to %s", inet_ntoa(dest_addr));
271 xprintf(" from %s via %s\n", inet_ntoa(src_addr), TT.iface);
272 }
273
274 dst_pk = src_pk;
275 //First packet always broadcasts.
276 memset(dst_pk.sll_addr, -1, dst_pk.sll_halen);
277 signal(SIGINT, done);
278 signal(SIGALRM, send_signal);
279
280 send_signal(0); // Send first Broadcast message.
281 while (1) {
282 len = sizeof(from);
283 recv_len = recvfrom(TT.sockfd, toybuf, 4096, 0,
284 (struct sockaddr *)&from, &len);
285 if (recv_len < 0) continue;
286 recv_from(&from, &recv_len);
287 }
288 }
289