blob: f24fb4a66c8dec7a32d1e8dea3b1972ddb62f008 [file] [log] [blame]
Jeremy Kerr42dc98c2016-02-25 10:23:14 +08001/******************************************************************************
Jeremy Kerrf2101cf2016-03-03 14:49:52 +08002 * Copyright 2016 Foxconn
3 * Copyright 2016 IBM Corporation
4 *
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
Jeremy Kerr52e24782016-03-03 14:51:35 +080018#include <err.h>
19#include <errno.h>
Jeremy Kerr982b7bc2016-02-25 10:54:39 +080020#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
Jeremy Kerr982b7bc2016-02-25 10:54:39 +080023#include <time.h>
24#include <unistd.h>
25
26#include <sys/ioctl.h>
27#include <sys/socket.h>
28
Jeremy Kerr760d6ac2016-02-25 14:45:33 +080029#include <arpa/inet.h>
Jeremy Kerr52e24782016-03-03 14:51:35 +080030#include <netinet/in.h>
Jeremy Kerr982b7bc2016-02-25 10:54:39 +080031
Jeremy Kerr982b7bc2016-02-25 10:54:39 +080032#include <linux/if_arp.h>
Jeremy Kerr52e24782016-03-03 14:51:35 +080033#include <linux/if_ether.h>
34#include <linux/if_packet.h>
Jeremy Kerr982b7bc2016-02-25 10:54:39 +080035
Jeremy Kerr71f385b2016-03-03 15:18:39 +080036struct eth_addr {
37 uint8_t eth_addr[ETH_ALEN];
38} __attribute__((packed));
39
Jeremy Kerr760d6ac2016-02-25 14:45:33 +080040struct arp_packet {
Jeremy Kerrf2101cf2016-03-03 14:49:52 +080041 struct ethhdr eh;
42 struct arphdr arp;
Jeremy Kerr71f385b2016-03-03 15:18:39 +080043 struct eth_addr src_mac;
Jeremy Kerr760d6ac2016-02-25 14:45:33 +080044 struct in_addr src_ip;
Jeremy Kerr71f385b2016-03-03 15:18:39 +080045 struct eth_addr dest_mac;
Jeremy Kerr760d6ac2016-02-25 14:45:33 +080046 struct in_addr dest_ip;
47} __attribute__((packed));
Jeremy Kerr42dc98c2016-02-25 10:23:14 +080048
Jeremy Kerre09d30d2016-03-04 11:42:03 +080049struct inarp_ctx {
50 int socket;
51 const char *ifname;
52 int ifindex;
53 struct eth_addr local_mac;
54};
55
Jeremy Kerr7b3bcf72016-02-25 14:29:55 +080056static int send_arp_packet(int fd,
Jeremy Kerrf2101cf2016-03-03 14:49:52 +080057 int ifindex,
Jeremy Kerr71f385b2016-03-03 15:18:39 +080058 const struct eth_addr *src_mac,
Jeremy Kerr88384bc2016-03-03 14:52:50 +080059 const struct in_addr *src_ip,
Jeremy Kerr71f385b2016-03-03 15:18:39 +080060 const struct eth_addr *dest_mac,
Jeremy Kerr88384bc2016-03-03 14:52:50 +080061 const struct in_addr *dest_ip)
Jeremy Kerr42dc98c2016-02-25 10:23:14 +080062{
Jeremy Kerr89dd5142016-02-25 19:40:02 +080063 struct sockaddr_ll addr;
Jeremy Kerr5bb869d2016-02-25 18:47:08 +080064 struct arp_packet arp;
Jeremy Kerrd7865332016-02-25 14:52:50 +080065 int rc;
Jeremy Kerrc10bedb2016-02-25 14:26:38 +080066
Jeremy Kerr5bb869d2016-02-25 18:47:08 +080067 memset(&arp, 0, sizeof(arp));
68
Jeremy Kerrc10bedb2016-02-25 14:26:38 +080069 /* Prepare our link-layer address: raw packet interface,
70 * using the ifindex interface, receiving ARP packets
71 */
Jeremy Kerr89dd5142016-02-25 19:40:02 +080072 addr.sll_family = PF_PACKET;
73 addr.sll_protocol = htons(ETH_P_ARP);
74 addr.sll_ifindex = ifindex;
75 addr.sll_hatype = ARPHRD_ETHER;
76 addr.sll_pkttype = PACKET_OTHERHOST;
77 addr.sll_halen = ETH_ALEN;
78 memcpy(addr.sll_addr, dest_mac, ETH_ALEN);
Jeremy Kerrc10bedb2016-02-25 14:26:38 +080079
80 /* set the frame header */
Jeremy Kerr103a9582016-02-25 19:38:52 +080081 memcpy(arp.eh.h_dest, dest_mac, ETH_ALEN);
82 memcpy(arp.eh.h_source, src_mac, ETH_ALEN);
Jeremy Kerr5bb869d2016-02-25 18:47:08 +080083 arp.eh.h_proto = htons(ETH_P_ARP);
Jeremy Kerrc10bedb2016-02-25 14:26:38 +080084
85 /* Fill InARP request data for ethernet + ipv4 */
Jeremy Kerr5bb869d2016-02-25 18:47:08 +080086 arp.arp.ar_hrd = htons(ARPHRD_ETHER);
87 arp.arp.ar_pro = htons(ETH_P_ARP);
88 arp.arp.ar_hln = ETH_ALEN;
89 arp.arp.ar_pln = 4;
90 arp.arp.ar_op = htons(ARPOP_InREPLY);
Jeremy Kerrc10bedb2016-02-25 14:26:38 +080091
92 /* fill arp ethernet mac & ipv4 info */
Jeremy Kerr5bb869d2016-02-25 18:47:08 +080093 memcpy(&arp.src_mac, src_mac, sizeof(arp.src_mac));
94 memcpy(&arp.src_ip, src_ip, sizeof(arp.src_ip));
95 memcpy(&arp.dest_mac, dest_mac, sizeof(arp.dest_mac));
96 memcpy(&arp.dest_ip, dest_ip, sizeof(arp.dest_ip));
Jeremy Kerrc10bedb2016-02-25 14:26:38 +080097
98 /* send the packet */
Jeremy Kerr5bb869d2016-02-25 18:47:08 +080099 rc = sendto(fd, &arp, sizeof(arp), 0,
Jeremy Kerr89dd5142016-02-25 19:40:02 +0800100 (struct sockaddr *)&addr, sizeof(addr));
Jeremy Kerrd7865332016-02-25 14:52:50 +0800101 if (rc < 0)
102 warn("failure sending ARP response");
103
104 return rc;
Jeremy Kerr42dc98c2016-02-25 10:23:14 +0800105}
Jeremy Kerr5514f7b2016-02-25 12:41:44 +0800106
Jeremy Kerr71f385b2016-03-03 15:18:39 +0800107static const char *eth_mac_to_str(const struct eth_addr *mac_addr)
Jeremy Kerr42dc98c2016-02-25 10:23:14 +0800108{
Jeremy Kerrdf046132016-03-03 15:03:22 +0800109 static char mac_str[ETH_ALEN * (sizeof("00:") - 1)];
Jeremy Kerr71f385b2016-03-03 15:18:39 +0800110 const uint8_t *addr = mac_addr->eth_addr;
Jeremy Kerrdf046132016-03-03 15:03:22 +0800111
112 snprintf(mac_str, sizeof(mac_str),
113 "%02x:%02x:%02x:%02x:%02x:%02x",
Jeremy Kerr71f385b2016-03-03 15:18:39 +0800114 addr[0], addr[1], addr[2],
115 addr[3], addr[4], addr[5]);
Jeremy Kerrdf046132016-03-03 15:03:22 +0800116
117 return mac_str;
Jeremy Kerr42dc98c2016-02-25 10:23:14 +0800118}
Jeremy Kerr5514f7b2016-02-25 12:41:44 +0800119
Jeremy Kerrf3b373f2016-02-25 19:24:59 +0800120static int do_ifreq(int fd, unsigned long type,
121 const char *ifname, struct ifreq *ifreq)
122{
123 memset(ifreq, 0, sizeof(*ifreq));
Jeremy Kerr7275d5c2016-03-03 15:30:10 +0800124 strncpy(ifreq->ifr_name, ifname, sizeof(ifreq->ifr_name));
Jeremy Kerrf3b373f2016-02-25 19:24:59 +0800125
126 return ioctl(fd, type, ifreq);
127}
128
Jeremy Kerre54e4832016-02-25 17:23:10 +0800129static int get_local_ipaddr(int fd, const char *ifname, struct in_addr *addr)
130{
131 struct sockaddr_in *sa;
132 struct ifreq ifreq;
133 int rc;
134
Jeremy Kerrf3b373f2016-02-25 19:24:59 +0800135 rc = do_ifreq(fd, SIOCGIFADDR, ifname, &ifreq);
Jeremy Kerre54e4832016-02-25 17:23:10 +0800136 if (rc) {
Jeremy Kerr1b127c52016-02-25 19:29:02 +0800137 warn("Error querying local IP address for %s", ifname);
Jeremy Kerre54e4832016-02-25 17:23:10 +0800138 return -1;
139 }
140
141 if (ifreq.ifr_addr.sa_family != AF_INET) {
142 warnx("Unknown address family %d in address response",
Jeremy Kerrf2101cf2016-03-03 14:49:52 +0800143 ifreq.ifr_addr.sa_family);
Jeremy Kerre54e4832016-02-25 17:23:10 +0800144 return -1;
145 }
146
147 sa = (struct sockaddr_in *)&ifreq.ifr_addr;
148 memcpy(addr, &sa->sin_addr, sizeof(*addr));
149 return 0;
150}
151
Jeremy Kerr71f385b2016-03-03 15:18:39 +0800152static int get_local_hwaddr(int fd, const char *ifname, struct eth_addr *addr)
Jeremy Kerr86489a12016-02-25 19:14:09 +0800153{
154 struct ifreq ifreq;
155 int rc;
156
Jeremy Kerrf3b373f2016-02-25 19:24:59 +0800157 rc = do_ifreq(fd, SIOCGIFHWADDR, ifname, &ifreq);
Jeremy Kerr86489a12016-02-25 19:14:09 +0800158 if (rc) {
Jeremy Kerr1b127c52016-02-25 19:29:02 +0800159 warn("Error querying local MAC address for %s", ifname);
Jeremy Kerr86489a12016-02-25 19:14:09 +0800160 return -1;
161 }
162
163 memcpy(addr, ifreq.ifr_hwaddr.sa_data, ETH_ALEN);
164 return 0;
165}
166
Jeremy Kerrd8343782016-02-25 19:17:19 +0800167static int get_ifindex(int fd, const char *ifname, int *ifindex)
168{
169 struct ifreq ifreq;
170 int rc;
171
Jeremy Kerrf3b373f2016-02-25 19:24:59 +0800172 rc = do_ifreq(fd, SIOCGIFINDEX, ifname, &ifreq);
Jeremy Kerrd8343782016-02-25 19:17:19 +0800173 if (rc < 0) {
174 warn("Error querying interface %s", ifname);
175 return -1;
176 }
177
178 *ifindex = ifreq.ifr_ifindex;
179 return 0;
180}
181
Jeremy Kerr115522d2016-02-25 10:24:14 +0800182static void usage(const char *progname)
183{
184 fprintf(stderr, "Usage: %s <interface>\n", progname);
185}
186
187int main(int argc, char **argv)
Jeremy Kerr42dc98c2016-02-25 10:23:14 +0800188{
Jeremy Kerr3f8a28e2016-02-25 18:56:01 +0800189 struct arp_packet inarp_req;
Jeremy Kerre09d30d2016-03-04 11:42:03 +0800190 struct in_addr local_ip;
191 struct inarp_ctx inarp;
Jeremy Kerr3f8a28e2016-02-25 18:56:01 +0800192 ssize_t len;
Jeremy Kerre09d30d2016-03-04 11:42:03 +0800193 int ret;
Jeremy Kerr115522d2016-02-25 10:24:14 +0800194
195 if (argc < 2) {
196 usage(argv[0]);
197 return EXIT_FAILURE;
198 }
199
Jeremy Kerre09d30d2016-03-04 11:42:03 +0800200 memset(&inarp, 0, sizeof(inarp));
201 inarp.ifname = argv[1];
Jeremy Kerr115522d2016-02-25 10:24:14 +0800202
Jeremy Kerre09d30d2016-03-04 11:42:03 +0800203 if (strlen(inarp.ifname) > IFNAMSIZ)
204 errx(EXIT_FAILURE, "Interface name '%s' is invalid",
205 inarp.ifname);
Jeremy Kerr5514f7b2016-02-25 12:41:44 +0800206
Jeremy Kerre09d30d2016-03-04 11:42:03 +0800207 inarp.socket = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ARP));
208 if (inarp.socket < 0)
Jeremy Kerrd7865332016-02-25 14:52:50 +0800209 err(EXIT_FAILURE, "Error opening ARP socket");
Jeremy Kerrc10bedb2016-02-25 14:26:38 +0800210
Jeremy Kerre09d30d2016-03-04 11:42:03 +0800211 ret = get_ifindex(inarp.socket, inarp.ifname, &inarp.ifindex);
Jeremy Kerr86489a12016-02-25 19:14:09 +0800212 if (ret)
213 exit(EXIT_FAILURE);
Jeremy Kerrd7865332016-02-25 14:52:50 +0800214
Jeremy Kerre09d30d2016-03-04 11:42:03 +0800215 ret = get_local_hwaddr(inarp.socket, inarp.ifname, &inarp.local_mac);
Jeremy Kerrd8343782016-02-25 19:17:19 +0800216 if (ret)
217 exit(EXIT_FAILURE);
218
Jeremy Kerre09d30d2016-03-04 11:42:03 +0800219 printf("%s MAC address: %s\n", inarp.ifname,
220 eth_mac_to_str(&inarp.local_mac));
Jeremy Kerrc10bedb2016-02-25 14:26:38 +0800221
Jeremy Kerr42dc98c2016-02-25 10:23:14 +0800222 while (1) {
Jeremy Kerre09d30d2016-03-04 11:42:03 +0800223 len = recvfrom(inarp.socket, &inarp_req, sizeof(inarp_req), 0,
Jeremy Kerr3f8a28e2016-02-25 18:56:01 +0800224 NULL, NULL);
225 if (len <= 0) {
Jeremy Kerr77cafea2016-02-25 17:15:28 +0800226 if (errno == EINTR)
227 continue;
228 err(EXIT_FAILURE, "Error recieving ARP packet");
Jeremy Kerr42dc98c2016-02-25 10:23:14 +0800229 }
Jeremy Kerr77cafea2016-02-25 17:15:28 +0800230
Jeremy Kerr3f8a28e2016-02-25 18:56:01 +0800231 /* Is this packet large enough for an inarp? */
232 if ((size_t)len < sizeof(inarp_req))
233 continue;
234
235 /* ... is it an inarp request? */
236 if (ntohs(inarp_req.arp.ar_op) != ARPOP_InREQUEST)
Jeremy Kerr77cafea2016-02-25 17:15:28 +0800237 continue;
238
239 /* ... for us? */
Jeremy Kerre09d30d2016-03-04 11:42:03 +0800240 if (memcmp(&inarp.local_mac, inarp_req.eh.h_dest, ETH_ALEN))
Jeremy Kerr77cafea2016-02-25 17:15:28 +0800241 continue;
242
Jeremy Kerr71f385b2016-03-03 15:18:39 +0800243 printf("src mac: %s\n", eth_mac_to_str(&inarp_req.src_mac));
Jeremy Kerr492de5d2016-02-25 19:35:44 +0800244 printf("src ip: %s\n", inet_ntoa(inarp_req.src_ip));
Jeremy Kerr77cafea2016-02-25 17:15:28 +0800245
Jeremy Kerre09d30d2016-03-04 11:42:03 +0800246 ret = get_local_ipaddr(inarp.socket, inarp.ifname, &local_ip);
Jeremy Kerre54e4832016-02-25 17:23:10 +0800247 /* if we don't have a local IP address to send, just drop the
248 * request */
249 if (ret)
250 continue;
251
Jeremy Kerr492de5d2016-02-25 19:35:44 +0800252 printf("local ip: %s\n", inet_ntoa(local_ip));
253
Jeremy Kerre09d30d2016-03-04 11:42:03 +0800254 send_arp_packet(inarp.socket, inarp.ifindex,
Jeremy Kerr71f385b2016-03-03 15:18:39 +0800255 &inarp_req.dest_mac,
Jeremy Kerrf2101cf2016-03-03 14:49:52 +0800256 &local_ip,
Jeremy Kerr71f385b2016-03-03 15:18:39 +0800257 &inarp_req.src_mac,
Jeremy Kerrf2101cf2016-03-03 14:49:52 +0800258 &inarp_req.src_ip);
Jeremy Kerr42dc98c2016-02-25 10:23:14 +0800259 }
Jeremy Kerre09d30d2016-03-04 11:42:03 +0800260 close(inarp.socket);
Jeremy Kerr42dc98c2016-02-25 10:23:14 +0800261 return 0;
262}