1 /****************************************************************************** 2 * 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 ******************************************************************************/ 17 18 #include <stdio.h> 19 #include <stdlib.h> 20 #include <string.h> 21 #include <errno.h> 22 #include <time.h> 23 #include <unistd.h> 24 #include <err.h> 25 26 #include <sys/ioctl.h> 27 #include <sys/socket.h> 28 29 #include <netinet/in.h> 30 #include <arpa/inet.h> 31 32 #include <linux/if_packet.h> 33 #include <linux/if_ether.h> 34 #include <linux/if_arp.h> 35 36 struct arp_packet { 37 struct ethhdr eh; 38 struct arphdr arp; 39 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)); 44 45 static int send_arp_packet(int fd, 46 int ifindex, 47 unsigned char *src_mac, 48 struct in_addr *src_ip, 49 unsigned char *dest_mac, 50 struct in_addr *dest_ip) 51 { 52 struct sockaddr_ll socket_address; 53 struct arp_packet arp; 54 int rc; 55 56 memset(&arp, 0, sizeof(arp)); 57 58 /* Prepare our link-layer address: raw packet interface, 59 * using the ifindex interface, receiving ARP packets 60 */ 61 socket_address.sll_family = PF_PACKET; 62 socket_address.sll_protocol = htons(ETH_P_ARP); 63 socket_address.sll_ifindex = ifindex; 64 socket_address.sll_hatype = ARPHRD_ETHER; 65 socket_address.sll_pkttype = PACKET_OTHERHOST; 66 socket_address.sll_halen = ETH_ALEN; 67 memcpy(socket_address.sll_addr, dest_mac, ETH_ALEN); 68 69 /* set the frame header */ 70 memcpy(arp.eh.h_dest, dest_mac, ETH_ALEN); 71 memcpy(arp.eh.h_source, src_mac, ETH_ALEN); 72 arp.eh.h_proto = htons(ETH_P_ARP); 73 74 /* Fill InARP request data for ethernet + ipv4 */ 75 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); 80 81 /* fill arp ethernet mac & ipv4 info */ 82 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)); 86 87 /* send the packet */ 88 rc = sendto(fd, &arp, sizeof(arp), 0, 89 (struct sockaddr *)&socket_address, 90 sizeof(socket_address)); 91 if (rc < 0) 92 warn("failure sending ARP response"); 93 94 return rc; 95 } 96 97 static void show_mac_addr(const char *name, unsigned char *mac_addr) 98 { 99 int i; 100 printf("%s MAC address: ", name); 101 for (i = 0; i < 6; i++) { 102 printf("%.2X%c", (unsigned char)mac_addr[i], 103 (i == 5) ? '\n' : ':'); 104 } 105 return; 106 } 107 108 static 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 117 static 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 123 rc = do_ifreq(fd, SIOCGIFADDR, ifname, &ifreq); 124 if (rc) { 125 warn("Error querying local IP address for %s", ifname); 126 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 140 static int get_local_hwaddr(int fd, const char *ifname, uint8_t *addr) 141 { 142 struct ifreq ifreq; 143 int rc; 144 145 rc = do_ifreq(fd, SIOCGIFHWADDR, ifname, &ifreq); 146 if (rc) { 147 warn("Error querying local MAC address for %s", ifname); 148 return -1; 149 } 150 151 memcpy(addr, ifreq.ifr_hwaddr.sa_data, ETH_ALEN); 152 return 0; 153 } 154 155 static int get_ifindex(int fd, const char *ifname, int *ifindex) 156 { 157 struct ifreq ifreq; 158 int rc; 159 160 rc = do_ifreq(fd, SIOCGIFINDEX, ifname, &ifreq); 161 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 170 static void usage(const char *progname) 171 { 172 fprintf(stderr, "Usage: %s <interface>\n", progname); 173 } 174 175 int main(int argc, char **argv) 176 { 177 static unsigned char local_mac[6]; 178 static struct in_addr local_ip; 179 struct arp_packet inarp_req; 180 int fd, ret, ifindex; 181 const char *ifname; 182 ssize_t len; 183 184 if (argc < 2) { 185 usage(argv[0]); 186 return EXIT_FAILURE; 187 } 188 189 ifname = argv[1]; 190 191 if (strlen(ifname) > IFNAMSIZ) 192 errx(EXIT_FAILURE, "Interface name '%s' is invalid", ifname); 193 194 195 fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ARP)); 196 if (fd < 0) 197 err(EXIT_FAILURE, "Error opening ARP socket"); 198 199 ret = get_ifindex(fd, ifname, &ifindex); 200 if (ret) 201 exit(EXIT_FAILURE); 202 203 ret = get_local_hwaddr(fd, ifname, local_mac); 204 if (ret) 205 exit(EXIT_FAILURE); 206 207 show_mac_addr(ifname, local_mac); 208 209 while (1) { 210 len = recvfrom(fd, &inarp_req, sizeof(inarp_req), 0, 211 NULL, NULL); 212 if (len <= 0) { 213 if (errno == EINTR) 214 continue; 215 err(EXIT_FAILURE, "Error recieving ARP packet"); 216 } 217 218 /* 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) 224 continue; 225 226 /* ... for us? */ 227 if (memcmp(local_mac, inarp_req.eh.h_dest, ETH_ALEN)) 228 continue; 229 230 printf("src mac: %02x:%02x:%02x:%02x:%02x:%02x\n", 231 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]); 237 238 printf("src ip: %s\n", inet_ntoa(inarp_req.src_ip)); 239 240 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 246 printf("local ip: %s\n", inet_ntoa(local_ip)); 247 248 send_arp_packet(fd, ifindex, 249 inarp_req.dest_mac, 250 &local_ip, 251 inarp_req.src_mac, 252 &inarp_req.src_ip); 253 } 254 close(fd); 255 return 0; 256 } 257