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 <err.h> 19 #include <errno.h> 20 #include <stdio.h> 21 #include <stdlib.h> 22 #include <string.h> 23 #include <time.h> 24 #include <unistd.h> 25 26 #include <sys/ioctl.h> 27 #include <sys/socket.h> 28 29 #include <arpa/inet.h> 30 #include <netinet/in.h> 31 32 #include <linux/if_arp.h> 33 #include <linux/if_ether.h> 34 #include <linux/if_packet.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 const unsigned char *src_mac, 48 const struct in_addr *src_ip, 49 const unsigned char *dest_mac, 50 const struct in_addr *dest_ip) 51 { 52 struct sockaddr_ll addr; 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 addr.sll_family = PF_PACKET; 62 addr.sll_protocol = htons(ETH_P_ARP); 63 addr.sll_ifindex = ifindex; 64 addr.sll_hatype = ARPHRD_ETHER; 65 addr.sll_pkttype = PACKET_OTHERHOST; 66 addr.sll_halen = ETH_ALEN; 67 memcpy(addr.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 *)&addr, sizeof(addr)); 90 if (rc < 0) 91 warn("failure sending ARP response"); 92 93 return rc; 94 } 95 96 static void show_mac_addr(const char *name, const unsigned char *mac_addr) 97 { 98 int i; 99 printf("%s MAC address: ", name); 100 for (i = 0; i < 6; i++) { 101 printf("%.2X%c", (unsigned char)mac_addr[i], 102 (i == 5) ? '\n' : ':'); 103 } 104 return; 105 } 106 107 static int do_ifreq(int fd, unsigned long type, 108 const char *ifname, struct ifreq *ifreq) 109 { 110 memset(ifreq, 0, sizeof(*ifreq)); 111 strcpy(ifreq->ifr_name, ifname); 112 113 return ioctl(fd, type, ifreq); 114 } 115 116 static int get_local_ipaddr(int fd, const char *ifname, struct in_addr *addr) 117 { 118 struct sockaddr_in *sa; 119 struct ifreq ifreq; 120 int rc; 121 122 rc = do_ifreq(fd, SIOCGIFADDR, ifname, &ifreq); 123 if (rc) { 124 warn("Error querying local IP address for %s", ifname); 125 return -1; 126 } 127 128 if (ifreq.ifr_addr.sa_family != AF_INET) { 129 warnx("Unknown address family %d in address response", 130 ifreq.ifr_addr.sa_family); 131 return -1; 132 } 133 134 sa = (struct sockaddr_in *)&ifreq.ifr_addr; 135 memcpy(addr, &sa->sin_addr, sizeof(*addr)); 136 return 0; 137 } 138 139 static int get_local_hwaddr(int fd, const char *ifname, uint8_t *addr) 140 { 141 struct ifreq ifreq; 142 int rc; 143 144 rc = do_ifreq(fd, SIOCGIFHWADDR, ifname, &ifreq); 145 if (rc) { 146 warn("Error querying local MAC address for %s", ifname); 147 return -1; 148 } 149 150 memcpy(addr, ifreq.ifr_hwaddr.sa_data, ETH_ALEN); 151 return 0; 152 } 153 154 static int get_ifindex(int fd, const char *ifname, int *ifindex) 155 { 156 struct ifreq ifreq; 157 int rc; 158 159 rc = do_ifreq(fd, SIOCGIFINDEX, ifname, &ifreq); 160 if (rc < 0) { 161 warn("Error querying interface %s", ifname); 162 return -1; 163 } 164 165 *ifindex = ifreq.ifr_ifindex; 166 return 0; 167 } 168 169 static void usage(const char *progname) 170 { 171 fprintf(stderr, "Usage: %s <interface>\n", progname); 172 } 173 174 int main(int argc, char **argv) 175 { 176 static unsigned char local_mac[6]; 177 static struct in_addr local_ip; 178 struct arp_packet inarp_req; 179 int fd, ret, ifindex; 180 const char *ifname; 181 ssize_t len; 182 183 if (argc < 2) { 184 usage(argv[0]); 185 return EXIT_FAILURE; 186 } 187 188 ifname = argv[1]; 189 190 if (strlen(ifname) > IFNAMSIZ) 191 errx(EXIT_FAILURE, "Interface name '%s' is invalid", ifname); 192 193 194 fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ARP)); 195 if (fd < 0) 196 err(EXIT_FAILURE, "Error opening ARP socket"); 197 198 ret = get_ifindex(fd, ifname, &ifindex); 199 if (ret) 200 exit(EXIT_FAILURE); 201 202 ret = get_local_hwaddr(fd, ifname, local_mac); 203 if (ret) 204 exit(EXIT_FAILURE); 205 206 show_mac_addr(ifname, local_mac); 207 208 while (1) { 209 len = recvfrom(fd, &inarp_req, sizeof(inarp_req), 0, 210 NULL, NULL); 211 if (len <= 0) { 212 if (errno == EINTR) 213 continue; 214 err(EXIT_FAILURE, "Error recieving ARP packet"); 215 } 216 217 /* Is this packet large enough for an inarp? */ 218 if ((size_t)len < sizeof(inarp_req)) 219 continue; 220 221 /* ... is it an inarp request? */ 222 if (ntohs(inarp_req.arp.ar_op) != ARPOP_InREQUEST) 223 continue; 224 225 /* ... for us? */ 226 if (memcmp(local_mac, inarp_req.eh.h_dest, ETH_ALEN)) 227 continue; 228 229 printf("src mac: %02x:%02x:%02x:%02x:%02x:%02x\n", 230 inarp_req.src_mac[0], 231 inarp_req.src_mac[1], 232 inarp_req.src_mac[2], 233 inarp_req.src_mac[3], 234 inarp_req.src_mac[4], 235 inarp_req.src_mac[5]); 236 237 printf("src ip: %s\n", inet_ntoa(inarp_req.src_ip)); 238 239 ret = get_local_ipaddr(fd, ifname, &local_ip); 240 /* if we don't have a local IP address to send, just drop the 241 * request */ 242 if (ret) 243 continue; 244 245 printf("local ip: %s\n", inet_ntoa(local_ip)); 246 247 send_arp_packet(fd, ifindex, 248 inarp_req.dest_mac, 249 &local_ip, 250 inarp_req.src_mac, 251 &inarp_req.src_ip); 252 } 253 close(fd); 254 return 0; 255 } 256