blob: 10db859d39ce1799710751eca83c1985c8517a47 [file] [log] [blame]
Jeremy Kerr42dc98c2016-02-25 10:23:14 +08001/******************************************************************************
2* Copyright 2016 Foxconn
Jeremy Kerr55ed2942016-02-25 19:37:14 +08003* Copyright 2016 IBM Corporation
Jeremy Kerr42dc98c2016-02-25 10:23:14 +08004*
5* Licensed under the Apache License, Version 2.0 (the "License");
6* you may not use this file except in compliance with the License.
7* You may obtain a copy of the License at
8*
9* http://www.apache.org/licenses/LICENSE-2.0
10*
11* Unless required by applicable law or agreed to in writing, software
12* distributed under the License is distributed on an "AS IS" BASIS,
13* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14* See the License for the specific language governing permissions and
15* limitations under the License.
16******************************************************************************/
Jeremy Kerr982b7bc2016-02-25 10:54:39 +080017
18#include <stdio.h>
19#include <stdlib.h>
20#include <string.h>
21#include <errno.h>
22#include <time.h>
23#include <unistd.h>
Jeremy Kerrd7865332016-02-25 14:52:50 +080024#include <err.h>
Jeremy Kerr982b7bc2016-02-25 10:54:39 +080025
26#include <sys/ioctl.h>
27#include <sys/socket.h>
28
29#include <netinet/in.h>
Jeremy Kerr760d6ac2016-02-25 14:45:33 +080030#include <arpa/inet.h>
Jeremy Kerr982b7bc2016-02-25 10:54:39 +080031
32#include <linux/if_packet.h>
33#include <linux/if_ether.h>
34#include <linux/if_arp.h>
35
Jeremy Kerr760d6ac2016-02-25 14:45:33 +080036struct arp_packet {
Jeremy Kerr42dc98c2016-02-25 10:23:14 +080037 struct ethhdr eh;
38 struct arphdr arp;
Jeremy Kerr760d6ac2016-02-25 14:45:33 +080039 uint8_t src_mac[ETH_ALEN];
40 struct in_addr src_ip;
41 uint8_t dest_mac[ETH_ALEN];
42 struct in_addr dest_ip;
43} __attribute__((packed));
Jeremy Kerr42dc98c2016-02-25 10:23:14 +080044
Jeremy Kerr7b3bcf72016-02-25 14:29:55 +080045static int send_arp_packet(int fd,
Jeremy Kerr5514f7b2016-02-25 12:41:44 +080046 int ifindex,
Jeremy Kerr5514f7b2016-02-25 12:41:44 +080047 unsigned char *src_mac,
Jeremy Kerr760d6ac2016-02-25 14:45:33 +080048 struct in_addr *src_ip,
49 unsigned char *dest_mac,
50 struct in_addr *dest_ip)
Jeremy Kerr42dc98c2016-02-25 10:23:14 +080051{
Jeremy Kerr42dc98c2016-02-25 10:23:14 +080052 struct sockaddr_ll socket_address;
Jeremy Kerr5bb869d2016-02-25 18:47:08 +080053 struct arp_packet arp;
Jeremy Kerrd7865332016-02-25 14:52:50 +080054 int rc;
Jeremy Kerrc10bedb2016-02-25 14:26:38 +080055
Jeremy Kerr5bb869d2016-02-25 18:47:08 +080056 memset(&arp, 0, sizeof(arp));
57
Jeremy Kerrc10bedb2016-02-25 14:26:38 +080058 /* Prepare our link-layer address: raw packet interface,
59 * using the ifindex interface, receiving ARP packets
60 */
Jeremy Kerr5514f7b2016-02-25 12:41:44 +080061 socket_address.sll_family = PF_PACKET;
Jeremy Kerr42dc98c2016-02-25 10:23:14 +080062 socket_address.sll_protocol = htons(ETH_P_ARP);
Jeremy Kerr5514f7b2016-02-25 12:41:44 +080063 socket_address.sll_ifindex = ifindex;
Jeremy Kerr5514f7b2016-02-25 12:41:44 +080064 socket_address.sll_hatype = ARPHRD_ETHER;
Jeremy Kerr5514f7b2016-02-25 12:41:44 +080065 socket_address.sll_pkttype = PACKET_OTHERHOST;
Jeremy Kerr5514f7b2016-02-25 12:41:44 +080066 socket_address.sll_halen = ETH_ALEN;
Jeremy Kerr42dc98c2016-02-25 10:23:14 +080067 memcpy(socket_address.sll_addr, dest_mac, ETH_ALEN);
Jeremy Kerrc10bedb2016-02-25 14:26:38 +080068
69 /* set the frame header */
Jeremy Kerr103a9582016-02-25 19:38:52 +080070 memcpy(arp.eh.h_dest, dest_mac, ETH_ALEN);
71 memcpy(arp.eh.h_source, src_mac, ETH_ALEN);
Jeremy Kerr5bb869d2016-02-25 18:47:08 +080072 arp.eh.h_proto = htons(ETH_P_ARP);
Jeremy Kerrc10bedb2016-02-25 14:26:38 +080073
74 /* Fill InARP request data for ethernet + ipv4 */
Jeremy Kerr5bb869d2016-02-25 18:47:08 +080075 arp.arp.ar_hrd = htons(ARPHRD_ETHER);
76 arp.arp.ar_pro = htons(ETH_P_ARP);
77 arp.arp.ar_hln = ETH_ALEN;
78 arp.arp.ar_pln = 4;
79 arp.arp.ar_op = htons(ARPOP_InREPLY);
Jeremy Kerrc10bedb2016-02-25 14:26:38 +080080
81 /* fill arp ethernet mac & ipv4 info */
Jeremy Kerr5bb869d2016-02-25 18:47:08 +080082 memcpy(&arp.src_mac, src_mac, sizeof(arp.src_mac));
83 memcpy(&arp.src_ip, src_ip, sizeof(arp.src_ip));
84 memcpy(&arp.dest_mac, dest_mac, sizeof(arp.dest_mac));
85 memcpy(&arp.dest_ip, dest_ip, sizeof(arp.dest_ip));
Jeremy Kerrc10bedb2016-02-25 14:26:38 +080086
87 /* send the packet */
Jeremy Kerr5bb869d2016-02-25 18:47:08 +080088 rc = sendto(fd, &arp, sizeof(arp), 0,
Jeremy Kerr5514f7b2016-02-25 12:41:44 +080089 (struct sockaddr *)&socket_address,
90 sizeof(socket_address));
Jeremy Kerrd7865332016-02-25 14:52:50 +080091 if (rc < 0)
92 warn("failure sending ARP response");
93
94 return rc;
Jeremy Kerr42dc98c2016-02-25 10:23:14 +080095}
Jeremy Kerr5514f7b2016-02-25 12:41:44 +080096
Jeremy Kerr7b3bcf72016-02-25 14:29:55 +080097static void show_mac_addr(const char *name, unsigned char *mac_addr)
Jeremy Kerr42dc98c2016-02-25 10:23:14 +080098{
99 int i;
100 printf("%s MAC address: ", name);
Jeremy Kerr5514f7b2016-02-25 12:41:44 +0800101 for (i = 0; i < 6; i++) {
102 printf("%.2X%c", (unsigned char)mac_addr[i],
103 (i == 5) ? '\n' : ':');
104 }
Jeremy Kerr42dc98c2016-02-25 10:23:14 +0800105 return;
106}
Jeremy Kerr5514f7b2016-02-25 12:41:44 +0800107
Jeremy Kerrf3b373f2016-02-25 19:24:59 +0800108static int do_ifreq(int fd, unsigned long type,
109 const char *ifname, struct ifreq *ifreq)
110{
111 memset(ifreq, 0, sizeof(*ifreq));
112 strcpy(ifreq->ifr_name, ifname);
113
114 return ioctl(fd, type, ifreq);
115}
116
Jeremy Kerre54e4832016-02-25 17:23:10 +0800117static int get_local_ipaddr(int fd, const char *ifname, struct in_addr *addr)
118{
119 struct sockaddr_in *sa;
120 struct ifreq ifreq;
121 int rc;
122
Jeremy Kerrf3b373f2016-02-25 19:24:59 +0800123 rc = do_ifreq(fd, SIOCGIFADDR, ifname, &ifreq);
Jeremy Kerre54e4832016-02-25 17:23:10 +0800124 if (rc) {
Jeremy Kerr1b127c52016-02-25 19:29:02 +0800125 warn("Error querying local IP address for %s", ifname);
Jeremy Kerre54e4832016-02-25 17:23:10 +0800126 return -1;
127 }
128
129 if (ifreq.ifr_addr.sa_family != AF_INET) {
130 warnx("Unknown address family %d in address response",
131 ifreq.ifr_addr.sa_family);
132 return -1;
133 }
134
135 sa = (struct sockaddr_in *)&ifreq.ifr_addr;
136 memcpy(addr, &sa->sin_addr, sizeof(*addr));
137 return 0;
138}
139
Jeremy Kerr86489a12016-02-25 19:14:09 +0800140static int get_local_hwaddr(int fd, const char *ifname, uint8_t *addr)
141{
142 struct ifreq ifreq;
143 int rc;
144
Jeremy Kerrf3b373f2016-02-25 19:24:59 +0800145 rc = do_ifreq(fd, SIOCGIFHWADDR, ifname, &ifreq);
Jeremy Kerr86489a12016-02-25 19:14:09 +0800146 if (rc) {
Jeremy Kerr1b127c52016-02-25 19:29:02 +0800147 warn("Error querying local MAC address for %s", ifname);
Jeremy Kerr86489a12016-02-25 19:14:09 +0800148 return -1;
149 }
150
151 memcpy(addr, ifreq.ifr_hwaddr.sa_data, ETH_ALEN);
152 return 0;
153}
154
Jeremy Kerrd8343782016-02-25 19:17:19 +0800155static int get_ifindex(int fd, const char *ifname, int *ifindex)
156{
157 struct ifreq ifreq;
158 int rc;
159
Jeremy Kerrf3b373f2016-02-25 19:24:59 +0800160 rc = do_ifreq(fd, SIOCGIFINDEX, ifname, &ifreq);
Jeremy Kerrd8343782016-02-25 19:17:19 +0800161 if (rc < 0) {
162 warn("Error querying interface %s", ifname);
163 return -1;
164 }
165
166 *ifindex = ifreq.ifr_ifindex;
167 return 0;
168}
169
Jeremy Kerr115522d2016-02-25 10:24:14 +0800170static void usage(const char *progname)
171{
172 fprintf(stderr, "Usage: %s <interface>\n", progname);
173}
174
175int main(int argc, char **argv)
Jeremy Kerr42dc98c2016-02-25 10:23:14 +0800176{
Jeremy Kerr14209b02016-02-25 19:34:37 +0800177 static unsigned char local_mac[6];
178 static struct in_addr local_ip;
Jeremy Kerr3f8a28e2016-02-25 18:56:01 +0800179 struct arp_packet inarp_req;
Jeremy Kerr14209b02016-02-25 19:34:37 +0800180 int fd, ret, ifindex;
Jeremy Kerr115522d2016-02-25 10:24:14 +0800181 const char *ifname;
Jeremy Kerr3f8a28e2016-02-25 18:56:01 +0800182 ssize_t len;
Jeremy Kerr115522d2016-02-25 10:24:14 +0800183
184 if (argc < 2) {
185 usage(argv[0]);
186 return EXIT_FAILURE;
187 }
188
189 ifname = argv[1];
190
Jeremy Kerrd7865332016-02-25 14:52:50 +0800191 if (strlen(ifname) > IFNAMSIZ)
192 errx(EXIT_FAILURE, "Interface name '%s' is invalid", ifname);
Jeremy Kerr5514f7b2016-02-25 12:41:44 +0800193
Jeremy Kerr42dc98c2016-02-25 10:23:14 +0800194
Jeremy Kerrc304ce72016-02-25 18:37:14 +0800195 fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ARP));
Jeremy Kerrd7865332016-02-25 14:52:50 +0800196 if (fd < 0)
197 err(EXIT_FAILURE, "Error opening ARP socket");
Jeremy Kerrc10bedb2016-02-25 14:26:38 +0800198
Jeremy Kerr1b127c52016-02-25 19:29:02 +0800199 ret = get_ifindex(fd, ifname, &ifindex);
Jeremy Kerr86489a12016-02-25 19:14:09 +0800200 if (ret)
201 exit(EXIT_FAILURE);
Jeremy Kerrd7865332016-02-25 14:52:50 +0800202
Jeremy Kerr14209b02016-02-25 19:34:37 +0800203 ret = get_local_hwaddr(fd, ifname, local_mac);
Jeremy Kerrd8343782016-02-25 19:17:19 +0800204 if (ret)
205 exit(EXIT_FAILURE);
206
Jeremy Kerr14209b02016-02-25 19:34:37 +0800207 show_mac_addr(ifname, local_mac);
Jeremy Kerrc10bedb2016-02-25 14:26:38 +0800208
Jeremy Kerr42dc98c2016-02-25 10:23:14 +0800209 while (1) {
Jeremy Kerr3f8a28e2016-02-25 18:56:01 +0800210 len = recvfrom(fd, &inarp_req, sizeof(inarp_req), 0,
211 NULL, NULL);
212 if (len <= 0) {
Jeremy Kerr77cafea2016-02-25 17:15:28 +0800213 if (errno == EINTR)
214 continue;
215 err(EXIT_FAILURE, "Error recieving ARP packet");
Jeremy Kerr42dc98c2016-02-25 10:23:14 +0800216 }
Jeremy Kerr77cafea2016-02-25 17:15:28 +0800217
Jeremy Kerr3f8a28e2016-02-25 18:56:01 +0800218 /* Is this packet large enough for an inarp? */
219 if ((size_t)len < sizeof(inarp_req))
220 continue;
221
222 /* ... is it an inarp request? */
223 if (ntohs(inarp_req.arp.ar_op) != ARPOP_InREQUEST)
Jeremy Kerr77cafea2016-02-25 17:15:28 +0800224 continue;
225
226 /* ... for us? */
Jeremy Kerr14209b02016-02-25 19:34:37 +0800227 if (memcmp(local_mac, inarp_req.eh.h_dest, ETH_ALEN))
Jeremy Kerr77cafea2016-02-25 17:15:28 +0800228 continue;
229
Jeremy Kerr492de5d2016-02-25 19:35:44 +0800230 printf("src mac: %02x:%02x:%02x:%02x:%02x:%02x\n",
Jeremy Kerr3f8a28e2016-02-25 18:56:01 +0800231 inarp_req.src_mac[0],
232 inarp_req.src_mac[1],
233 inarp_req.src_mac[2],
234 inarp_req.src_mac[3],
235 inarp_req.src_mac[4],
236 inarp_req.src_mac[5]);
Jeremy Kerr77cafea2016-02-25 17:15:28 +0800237
Jeremy Kerr492de5d2016-02-25 19:35:44 +0800238 printf("src ip: %s\n", inet_ntoa(inarp_req.src_ip));
Jeremy Kerr77cafea2016-02-25 17:15:28 +0800239
Jeremy Kerre54e4832016-02-25 17:23:10 +0800240 ret = get_local_ipaddr(fd, ifname, &local_ip);
241 /* if we don't have a local IP address to send, just drop the
242 * request */
243 if (ret)
244 continue;
245
Jeremy Kerr492de5d2016-02-25 19:35:44 +0800246 printf("local ip: %s\n", inet_ntoa(local_ip));
247
Jeremy Kerr5bb869d2016-02-25 18:47:08 +0800248 send_arp_packet(fd, ifindex,
Jeremy Kerr3f8a28e2016-02-25 18:56:01 +0800249 inarp_req.dest_mac,
Jeremy Kerre54e4832016-02-25 17:23:10 +0800250 &local_ip,
Jeremy Kerr3f8a28e2016-02-25 18:56:01 +0800251 inarp_req.src_mac,
252 &inarp_req.src_ip);
Jeremy Kerr42dc98c2016-02-25 10:23:14 +0800253 }
254 close(fd);
255 return 0;
256}