blob: 9f41d7d54dbc8a02c50d3c8276c5acb5654b5900 [file] [log] [blame]
Jeremy Kerr42dc98c2016-02-25 10:23:14 +08001/******************************************************************************
2* Copyright 2016 Foxconn
3*
4* Licensed under the Apache License, Version 2.0 (the "License");
5* you may not use this file except in compliance with the License.
6* You may obtain a copy of the License at
7*
8* http://www.apache.org/licenses/LICENSE-2.0
9*
10* Unless required by applicable law or agreed to in writing, software
11* distributed under the License is distributed on an "AS IS" BASIS,
12* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13* See the License for the specific language governing permissions and
14* limitations under the License.
15******************************************************************************/
Jeremy Kerr982b7bc2016-02-25 10:54:39 +080016
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20#include <errno.h>
21#include <time.h>
22#include <unistd.h>
Jeremy Kerrd7865332016-02-25 14:52:50 +080023#include <err.h>
Jeremy Kerr982b7bc2016-02-25 10:54:39 +080024
25#include <sys/ioctl.h>
26#include <sys/socket.h>
27
28#include <netinet/in.h>
Jeremy Kerr760d6ac2016-02-25 14:45:33 +080029#include <arpa/inet.h>
Jeremy Kerr982b7bc2016-02-25 10:54:39 +080030
31#include <linux/if_packet.h>
32#include <linux/if_ether.h>
33#include <linux/if_arp.h>
34
Jeremy Kerr760d6ac2016-02-25 14:45:33 +080035struct arp_packet {
Jeremy Kerr42dc98c2016-02-25 10:23:14 +080036 struct ethhdr eh;
37 struct arphdr arp;
Jeremy Kerr760d6ac2016-02-25 14:45:33 +080038 uint8_t src_mac[ETH_ALEN];
39 struct in_addr src_ip;
40 uint8_t dest_mac[ETH_ALEN];
41 struct in_addr dest_ip;
42} __attribute__((packed));
Jeremy Kerr42dc98c2016-02-25 10:23:14 +080043
Jeremy Kerr7b3bcf72016-02-25 14:29:55 +080044static int send_arp_packet(int fd,
Jeremy Kerr5514f7b2016-02-25 12:41:44 +080045 int ifindex,
Jeremy Kerr5514f7b2016-02-25 12:41:44 +080046 unsigned char *src_mac,
Jeremy Kerr760d6ac2016-02-25 14:45:33 +080047 struct in_addr *src_ip,
48 unsigned char *dest_mac,
49 struct in_addr *dest_ip)
Jeremy Kerr42dc98c2016-02-25 10:23:14 +080050{
Jeremy Kerr42dc98c2016-02-25 10:23:14 +080051 struct sockaddr_ll socket_address;
Jeremy Kerr5bb869d2016-02-25 18:47:08 +080052 struct arp_packet arp;
Jeremy Kerrd7865332016-02-25 14:52:50 +080053 int rc;
Jeremy Kerrc10bedb2016-02-25 14:26:38 +080054
Jeremy Kerr5bb869d2016-02-25 18:47:08 +080055 memset(&arp, 0, sizeof(arp));
56
Jeremy Kerrc10bedb2016-02-25 14:26:38 +080057 /* Prepare our link-layer address: raw packet interface,
58 * using the ifindex interface, receiving ARP packets
59 */
Jeremy Kerr5514f7b2016-02-25 12:41:44 +080060 socket_address.sll_family = PF_PACKET;
Jeremy Kerr42dc98c2016-02-25 10:23:14 +080061 socket_address.sll_protocol = htons(ETH_P_ARP);
Jeremy Kerr5514f7b2016-02-25 12:41:44 +080062 socket_address.sll_ifindex = ifindex;
Jeremy Kerr5514f7b2016-02-25 12:41:44 +080063 socket_address.sll_hatype = ARPHRD_ETHER;
Jeremy Kerr5514f7b2016-02-25 12:41:44 +080064 socket_address.sll_pkttype = PACKET_OTHERHOST;
Jeremy Kerr5514f7b2016-02-25 12:41:44 +080065 socket_address.sll_halen = ETH_ALEN;
Jeremy Kerr42dc98c2016-02-25 10:23:14 +080066 memcpy(socket_address.sll_addr, dest_mac, ETH_ALEN);
Jeremy Kerrc10bedb2016-02-25 14:26:38 +080067
68 /* set the frame header */
Jeremy Kerr5bb869d2016-02-25 18:47:08 +080069 memcpy(arp.eh.h_dest, (void *)dest_mac, ETH_ALEN);
70 memcpy(arp.eh.h_source, (void *)src_mac, ETH_ALEN);
71 arp.eh.h_proto = htons(ETH_P_ARP);
Jeremy Kerrc10bedb2016-02-25 14:26:38 +080072
73 /* Fill InARP request data for ethernet + ipv4 */
Jeremy Kerr5bb869d2016-02-25 18:47:08 +080074 arp.arp.ar_hrd = htons(ARPHRD_ETHER);
75 arp.arp.ar_pro = htons(ETH_P_ARP);
76 arp.arp.ar_hln = ETH_ALEN;
77 arp.arp.ar_pln = 4;
78 arp.arp.ar_op = htons(ARPOP_InREPLY);
Jeremy Kerrc10bedb2016-02-25 14:26:38 +080079
80 /* fill arp ethernet mac & ipv4 info */
Jeremy Kerr5bb869d2016-02-25 18:47:08 +080081 memcpy(&arp.src_mac, src_mac, sizeof(arp.src_mac));
82 memcpy(&arp.src_ip, src_ip, sizeof(arp.src_ip));
83 memcpy(&arp.dest_mac, dest_mac, sizeof(arp.dest_mac));
84 memcpy(&arp.dest_ip, dest_ip, sizeof(arp.dest_ip));
Jeremy Kerrc10bedb2016-02-25 14:26:38 +080085
86 /* send the packet */
Jeremy Kerr5bb869d2016-02-25 18:47:08 +080087 rc = sendto(fd, &arp, sizeof(arp), 0,
Jeremy Kerr5514f7b2016-02-25 12:41:44 +080088 (struct sockaddr *)&socket_address,
89 sizeof(socket_address));
Jeremy Kerrd7865332016-02-25 14:52:50 +080090 if (rc < 0)
91 warn("failure sending ARP response");
92
93 return rc;
Jeremy Kerr42dc98c2016-02-25 10:23:14 +080094}
Jeremy Kerr5514f7b2016-02-25 12:41:44 +080095
Jeremy Kerr7b3bcf72016-02-25 14:29:55 +080096static void show_mac_addr(const char *name, unsigned char *mac_addr)
Jeremy Kerr42dc98c2016-02-25 10:23:14 +080097{
98 int i;
99 printf("%s MAC address: ", name);
Jeremy Kerr5514f7b2016-02-25 12:41:44 +0800100 for (i = 0; i < 6; i++) {
101 printf("%.2X%c", (unsigned char)mac_addr[i],
102 (i == 5) ? '\n' : ':');
103 }
Jeremy Kerr42dc98c2016-02-25 10:23:14 +0800104 return;
105}
Jeremy Kerr5514f7b2016-02-25 12:41:44 +0800106
Jeremy Kerre54e4832016-02-25 17:23:10 +0800107static int get_local_ipaddr(int fd, const char *ifname, struct in_addr *addr)
108{
109 struct sockaddr_in *sa;
110 struct ifreq ifreq;
111 int rc;
112
113 memset(&ifreq, 0, sizeof(ifreq));
114 strcpy(ifreq.ifr_name, ifname);
115
116 rc = ioctl(fd, SIOCGIFADDR, &ifreq);
117 if (rc) {
118 warn("Error querying local address for %s", ifname);
119 return -1;
120 }
121
122 if (ifreq.ifr_addr.sa_family != AF_INET) {
123 warnx("Unknown address family %d in address response",
124 ifreq.ifr_addr.sa_family);
125 return -1;
126 }
127
128 sa = (struct sockaddr_in *)&ifreq.ifr_addr;
129 memcpy(addr, &sa->sin_addr, sizeof(*addr));
130 return 0;
131}
132
Jeremy Kerr86489a12016-02-25 19:14:09 +0800133static int get_local_hwaddr(int fd, const char *ifname, uint8_t *addr)
134{
135 struct ifreq ifreq;
136 int rc;
137
138 memset(&ifreq, 0, sizeof(ifreq));
139 strcpy(ifreq.ifr_name, ifname);
140
141 rc = ioctl(fd, SIOCGIFHWADDR, &ifreq);
142 if (rc) {
143 warn("Error querying local MAC address");
144 return -1;
145 }
146
147 memcpy(addr, ifreq.ifr_hwaddr.sa_data, ETH_ALEN);
148 return 0;
149}
150
Jeremy Kerr115522d2016-02-25 10:24:14 +0800151static void usage(const char *progname)
152{
153 fprintf(stderr, "Usage: %s <interface>\n", progname);
154}
155
156int main(int argc, char **argv)
Jeremy Kerr42dc98c2016-02-25 10:23:14 +0800157{
Jeremy Kerr5514f7b2016-02-25 12:41:44 +0800158 static struct ifreq ifreq_buffer;
Jeremy Kerr3f8a28e2016-02-25 18:56:01 +0800159 struct arp_packet inarp_req;
Jeremy Kerr115522d2016-02-25 10:24:14 +0800160 const char *ifname;
Jeremy Kerr3f8a28e2016-02-25 18:56:01 +0800161 ssize_t len;
Jeremy Kerr760d6ac2016-02-25 14:45:33 +0800162 int fd, ret;
Jeremy Kerr115522d2016-02-25 10:24:14 +0800163
164 if (argc < 2) {
165 usage(argv[0]);
166 return EXIT_FAILURE;
167 }
168
169 ifname = argv[1];
170
Jeremy Kerrd7865332016-02-25 14:52:50 +0800171 if (strlen(ifname) > IFNAMSIZ)
172 errx(EXIT_FAILURE, "Interface name '%s' is invalid", ifname);
Jeremy Kerr5514f7b2016-02-25 12:41:44 +0800173
Jeremy Kerr42dc98c2016-02-25 10:23:14 +0800174 static unsigned char src_mac[6];
Jeremy Kerre54e4832016-02-25 17:23:10 +0800175 static struct in_addr local_ip;
Jeremy Kerr42dc98c2016-02-25 10:23:14 +0800176 int ifindex;
Jeremy Kerr42dc98c2016-02-25 10:23:14 +0800177
Jeremy Kerrc304ce72016-02-25 18:37:14 +0800178 fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ARP));
Jeremy Kerrd7865332016-02-25 14:52:50 +0800179 if (fd < 0)
180 err(EXIT_FAILURE, "Error opening ARP socket");
Jeremy Kerrc10bedb2016-02-25 14:26:38 +0800181
Jeremy Kerr86489a12016-02-25 19:14:09 +0800182 ret = get_local_hwaddr(fd, ifname, src_mac);
183 if (ret)
184 exit(EXIT_FAILURE);
Jeremy Kerrd7865332016-02-25 14:52:50 +0800185
Jeremy Kerr115522d2016-02-25 10:24:14 +0800186 show_mac_addr(ifname, src_mac);
Jeremy Kerrc10bedb2016-02-25 14:26:38 +0800187
188 /* find the ifindex of the interface we're using */
Jeremy Kerr42dc98c2016-02-25 10:23:14 +0800189 memset(&ifreq_buffer, 0x00, sizeof(ifreq_buffer));
Jeremy Kerr115522d2016-02-25 10:24:14 +0800190 strcpy(ifreq_buffer.ifr_name, ifname);
Jeremy Kerr42dc98c2016-02-25 10:23:14 +0800191 ret = ioctl(fd, SIOCGIFINDEX, &ifreq_buffer);
Jeremy Kerrd7865332016-02-25 14:52:50 +0800192 if (ret < 0)
193 err(EXIT_FAILURE, "Error querying interface %s", ifname);
194
Jeremy Kerr42dc98c2016-02-25 10:23:14 +0800195 ifindex = ifreq_buffer.ifr_ifindex;
196
Jeremy Kerr42dc98c2016-02-25 10:23:14 +0800197 while (1) {
Jeremy Kerr3f8a28e2016-02-25 18:56:01 +0800198 len = recvfrom(fd, &inarp_req, sizeof(inarp_req), 0,
199 NULL, NULL);
200 if (len <= 0) {
Jeremy Kerr77cafea2016-02-25 17:15:28 +0800201 if (errno == EINTR)
202 continue;
203 err(EXIT_FAILURE, "Error recieving ARP packet");
Jeremy Kerr42dc98c2016-02-25 10:23:14 +0800204 }
Jeremy Kerr77cafea2016-02-25 17:15:28 +0800205
Jeremy Kerr3f8a28e2016-02-25 18:56:01 +0800206 /* Is this packet large enough for an inarp? */
207 if ((size_t)len < sizeof(inarp_req))
208 continue;
209
210 /* ... is it an inarp request? */
211 if (ntohs(inarp_req.arp.ar_op) != ARPOP_InREQUEST)
Jeremy Kerr77cafea2016-02-25 17:15:28 +0800212 continue;
213
214 /* ... for us? */
Jeremy Kerr3f8a28e2016-02-25 18:56:01 +0800215 if (memcmp(src_mac, inarp_req.eh.h_dest, ETH_ALEN))
Jeremy Kerr77cafea2016-02-25 17:15:28 +0800216 continue;
217
218 printf("src mac =%02x:%02x:%02x:%02x:%02x:%02x\n",
Jeremy Kerr3f8a28e2016-02-25 18:56:01 +0800219 inarp_req.src_mac[0],
220 inarp_req.src_mac[1],
221 inarp_req.src_mac[2],
222 inarp_req.src_mac[3],
223 inarp_req.src_mac[4],
224 inarp_req.src_mac[5]);
Jeremy Kerr77cafea2016-02-25 17:15:28 +0800225
Jeremy Kerr3f8a28e2016-02-25 18:56:01 +0800226 printf("src ip = %s\n", inet_ntoa(inarp_req.src_ip));
Jeremy Kerr77cafea2016-02-25 17:15:28 +0800227
Jeremy Kerre54e4832016-02-25 17:23:10 +0800228 ret = get_local_ipaddr(fd, ifname, &local_ip);
229 /* if we don't have a local IP address to send, just drop the
230 * request */
231 if (ret)
232 continue;
233
Jeremy Kerr5bb869d2016-02-25 18:47:08 +0800234 send_arp_packet(fd, ifindex,
Jeremy Kerr3f8a28e2016-02-25 18:56:01 +0800235 inarp_req.dest_mac,
Jeremy Kerre54e4832016-02-25 17:23:10 +0800236 &local_ip,
Jeremy Kerr3f8a28e2016-02-25 18:56:01 +0800237 inarp_req.src_mac,
238 &inarp_req.src_ip);
Jeremy Kerr42dc98c2016-02-25 10:23:14 +0800239 }
240 close(fd);
241 return 0;
242}