📄 proxyarp.c
字号:
/* $Id: proxyarp.c,v 1.24 2001/09/08 16:51:58 jm Exp $ * ARP interface * * Dynamic hierarchial IP tunnel * Copyright (C) 1998-2001, Dynamics group * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. See README and COPYING for * more details. *//* uncomment following define to use arp program instead of own routines *//* #define USE_STUBS */#define DEBUG_FLAG 'O'#ifdef USE_STUBS#ifndef _GNU_SOURCE/* snprintf */#define _GNU_SOURCE#endif#endif#include "config.h"#include <stdlib.h>#include <stdio.h>#include <unistd.h>#include <sys/socket.h>#include <sys/ioctl.h>#include <netinet/in.h>#ifdef DYN_TARGET_LINUX#include <net/if_arp.h>#endif#include <arpa/inet.h>#include <net/if.h>#include <string.h>#include <errno.h>#include <assert.h>#ifdef DYN_TARGET_LINUX#if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1) || __GLIBC__ > 2#include <netinet/if_ether.h>#include <netpacket/packet.h>#else#include <linux/if_ether.h>#include <linux/if_packet.h>#endif#endif#include "debug.h"#include "util.h"#ifdef DYN_TARGET_WINDOWS#include "dyn_ip.h"#endif#include "proxyarp.h"/** * proxyarp_add_item: * @host_addr: the address to be added to the ARP cache * @interface: the interface to which the entry is added * * Add an ARP item into kernel's ARP cache with 'pub' flag (i.e. kernel will * answer the ARP requests on given interface) * * This routine gets the hardware address of the host's own interface and adds * an entry with that hardware address to the given IP address. If the same * address is added twice to same interface, the second addition is ignored * (by kernel) and the call should succeed (without adding duplicate entry). * * Returns: * 0 = success, * -1 = failure */int proxyarp_add_item(struct in_addr host_addr, char const *interface){#ifdef USE_STUBS char command[200]; snprintf(command, sizeof(command), "arp -Ds %s %s pub", inet_ntoa(host_addr), interface); printf("add_proxyarp_item stub - executing[%s]\n", command); if (system(command) != 0) { return -1; } return 0;#else#ifdef DYN_TARGET_LINUX int s, i; struct ifreq ifr; struct arpreq req; struct sockaddr_in *sa; if (interface == NULL) { DEBUG(DEBUG_FLAG, "proxyarp_add_item: interface = NULL\n"); return -1; } i = strlen(interface); if (i >= sizeof(ifr.ifr_name) || i >= sizeof(req.arp_dev)) { DEBUG(DEBUG_FLAG, "proxyarp_add_item: too long interface " "parameter\n"); return -1; } memcpy(ifr.ifr_name, interface, i + 1); s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); if (s < 0) { DEBUG(DEBUG_FLAG, "proxyarp_add_item: socket failed: %s\n", strerror(errno)); return -1; } if (ioctl(s, SIOCGIFHWADDR, &ifr) < 0) { DEBUG(DEBUG_FLAG, "proxyarp_add_item: ioctl SIOGIFHWADDR " "failed: %s\n", strerror(errno)); close(s); return -1; } if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) { DEBUG(DEBUG_FLAG, "proxyarp_add_item: unknown address " "family - correct HW-addr format not known\n" "\t(HW-addr in hex: "); for (i = 0; i < sizeof(ifr.ifr_hwaddr.sa_data); i++) DEBUG(DEBUG_FLAG, "%s%02X", i > 0 ? ":" : "", (unsigned char) ifr.ifr_hwaddr.sa_data[i]); DEBUG(DEBUG_FLAG, ")\n"); } else { DEBUG(DEBUG_FLAG, "proxyarp_add_item: ether - name=%s, " "HW addr=%s\n", ifr.ifr_name, ether_hwtoa((unsigned char *) ifr.ifr_hwaddr.sa_data)); } memset((char *) &req, 0, sizeof(req)); memcpy(req.arp_dev, interface, i + 1); sa = (struct sockaddr_in *) &req.arp_pa; sa->sin_family = AF_INET; memcpy((char *) &sa->sin_addr, (char *) &host_addr, sizeof(struct in_addr)); memcpy((char *) &req.arp_ha, (char *) &ifr.ifr_hwaddr, sizeof(struct sockaddr)); req.arp_flags = ATF_PERM | ATF_COM | ATF_PUBL; if (ioctl(s, SIOCSARP, &req) < 0) { DEBUG(DEBUG_FLAG, "proxyarp_add_item: ioctl SIOCSARP failed: %s\n", strerror(errno)); close(s); return -1; } DEBUG(DEBUG_FLAG, "proxyarp_add_item: added proxyarp for %s to " "device %s\n", inet_ntoa(host_addr), interface); close(s); return 0;#else return -1;#endif /* DYN_TARGET_LINUX */#endif /* USE_STUBS */}#ifdef DYN_TARGET_LINUX#ifndef USE_STUBSstatic int arp_ioctl(struct in_addr host_addr, char const *interface, int command, int flags, struct sockaddr *eth){ int s, len; struct arpreq req; struct sockaddr_in *sa; if (interface == NULL) { DEBUG(DEBUG_FLAG, "arp_ioctl: interface = NULL\n"); return -1; } len = strlen(interface); if (len >= sizeof(req.arp_dev)) { DEBUG(DEBUG_FLAG, "arp_ioctl: too long interface parameter\n"); return -1; } memset((char *) &req, 0, sizeof(req)); sa = (struct sockaddr_in *) &req.arp_pa; sa->sin_family = AF_INET; memcpy((char *) &sa->sin_addr, (char *) &host_addr, sizeof(struct in_addr)); req.arp_flags = flags; memcpy(req.arp_dev, interface, len + 1); if (eth != NULL) memcpy((char *) &req.arp_ha, (char *) eth, sizeof(struct sockaddr)); s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); if (s < 0) { DEBUG(DEBUG_FLAG, "arp_ioctl socket failed: %s\n", strerror(errno)); return -1; } if (ioctl(s, command, &req) < 0) { DEBUG(DEBUG_FLAG, "arp_ioctl(%s, %s): ioctl failed: %s\n", inet_ntoa(host_addr), interface, strerror(errno)); close(s); return -1; } DEBUG(DEBUG_FLAG, "arp_ioctl: %s for addr %s dev %s completed\n", (command == SIOCSARP ? "SIOCSARP" : "SIOCDARP"), inet_ntoa(host_addr), interface); close(s); return 0;}#endif /* USE_STUBS */#endif /* DYN_TARGET_LINUX *//** * proxyarp_del_item: * @host_addr: the address to be removed from the ARP cache * @interface: the interface to which the entry was added * * Remove an ARP item added with proxyarp_add_item from kernel's ARP cache * * Returns: * 0 = success, * -1 = failure */int proxyarp_del_item(struct in_addr host_addr, char const *interface){#ifdef USE_STUBS char command[200]; snprintf(command, sizeof(command), "arp -i %s -d %s", interface, inet_ntoa(host_addr)); printf("arp_del stub - executing[%s]\n", command); if (system(command) != 0) { return -1; } return 0;#else#ifdef DYN_TARGET_LINUX return arp_ioctl(host_addr, interface, SIOCDARP, ATF_PERM | ATF_PUBL, NULL);#else return -1;#endif#endif}/* Note: gratuitous ARP is implemented only for Ethernet; * other types of ARP requests should be implemented if needed */struct arphdr_ether { unsigned char ar_sha[ETH_ALEN]; /* Sender hardware address. */ unsigned char ar_sip[4]; /* Sender IP address. */ unsigned char ar_tha[ETH_ALEN]; /* Target hardware address. */ unsigned char ar_tip[4]; /* Target IP address. */};/** * proxyarp_gratuitous: * @host_addr: the address for which the gratuitous ARP is sent * @interface: the interface to which the package is sent * * Send a gratuitous ARP request to flush other hosts' ARP caches * * Returns: * 0 = success, * -1 = failure */int proxyarp_gratuitous(struct in_addr host_addr, char const *interface){#ifdef DYN_TARGET_LINUX char *buf; struct ethhdr *ehdr; struct arphdr *ahdr; struct arphdr_ether *ahdr_ether; int s, arp_len, i, hwaddr_len, ifindex; struct sockaddr_ll sa; struct ifreq ifr; /* get interface index and own hwaddr */ memset(&ifr, 0, sizeof(ifr)); assert(interface != NULL && strlen(interface) < IFNAMSIZ); dynamics_strlcpy(ifr.ifr_name, interface, IFNAMSIZ); s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) { DEBUG(DEBUG_FLAG, "proxyarp_gratuitous: socket: %s\n", strerror(errno)); return -1; } if (ioctl(s, SIOCGIFINDEX, &ifr) != 0) { DEBUG(DEBUG_FLAG, "proxyarp_gratuitous(%s): ioctl: %s\n", interface, strerror(errno)); close(s); return -1; } ifindex = ifr.ifr_ifindex; if (ioctl(s, SIOCGIFHWADDR, &ifr) != 0) { DEBUG(DEBUG_FLAG, "proxyarp_gratuitous(%s): ioctl: %s\n", interface, strerror(errno)); close(s); return -1; } close(s); /* make the gratuitous ARP packet */ switch (ifr.ifr_hwaddr.sa_family) { case ETH_P_802_3: arp_len = sizeof(struct ethhdr) + sizeof(struct arphdr) + sizeof(struct arphdr_ether); hwaddr_len = ETH_ALEN; break; default: DEBUG(DEBUG_FLAG, "proxyarp_gratuitous: unsupported HW addr family (%i)\n", ifr.ifr_hwaddr.sa_family); return -1; } DEBUG(DEBUG_FLAG, "proxyarp_gratuitous: sending gratuitous ARP - " "IPaddr: %s, HWaddr: ", inet_ntoa(host_addr)); for (i = 0; i < hwaddr_len; i++) DEBUG(DEBUG_FLAG, "%02X%s", (unsigned char)ifr.ifr_hwaddr.sa_data[i], i < hwaddr_len - 1 ? ":" : ""); DEBUG(DEBUG_FLAG, ", family=%i\n", ifr.ifr_hwaddr.sa_family); buf = malloc(arp_len); if (buf == NULL) { DEBUG(DEBUG_FLAG, "proxyarp_gratuitous: not enough memory\n"); return -1; } memset(buf, 0, arp_len); s = socket(PF_PACKET, SOCK_RAW, htons(ifr.ifr_hwaddr.sa_family)); if (s < 0) { DEBUG(DEBUG_FLAG, "proxyarp_gratuitous: socket: %s\n", strerror(errno)); free(buf); return -1; } memset(&sa, 0, sizeof(sa)); sa.sll_family = AF_PACKET; sa.sll_protocol = htons(ifr.ifr_hwaddr.sa_family); sa.sll_ifindex = ifindex; sa.sll_pkttype = PACKET_BROADCAST; if (ifr.ifr_hwaddr.sa_family == ETH_P_802_3) { sa.sll_hatype = htons(ARPHRD_ETHER); sa.sll_halen = hwaddr_len; memset(sa.sll_addr, 0xff, hwaddr_len); ehdr = (struct ethhdr *) buf; memset(ehdr->h_dest, 0xff, ETH_ALEN); /* hardware broadcast */ memcpy(ehdr->h_source, ifr.ifr_hwaddr.sa_data, ETH_ALEN); ehdr->h_proto = htons(ETH_P_ARP); ahdr = (struct arphdr *) ((char *) ehdr + sizeof(struct ethhdr)); ahdr->ar_hrd = htons(ARPHRD_ETHER); ahdr->ar_pro = htons(ETH_P_IP); ahdr->ar_hln = ETH_ALEN; ahdr->ar_pln = 4; /* IPv4 - 4 byte address */ ahdr->ar_op = htons(ARPOP_REQUEST); ahdr_ether = (struct arphdr_ether *) ((char *) ahdr + sizeof(struct arphdr)); memcpy(ahdr_ether->ar_sha, ifr.ifr_hwaddr.sa_data, ETH_ALEN); memcpy(ahdr_ether->ar_sip, &host_addr, 4); memset(ahdr_ether->ar_tha, 0, ETH_ALEN); memcpy(ahdr_ether->ar_tip, &host_addr, 4); } i = 0; if (sendto(s, buf, arp_len, 0, (struct sockaddr *) &sa, sizeof(sa)) < 0) { DEBUG(DEBUG_FLAG, "proxyarp_gratuitous: sendto: %s\n", strerror(errno)); i = -1; } close(s); free(buf); return i;#else return -1;#endif /* DYN_TARGET_LINUX */}/** * arp_add_permanent_item: * @host_addr: * @interface: * @eth: * * * * Returns: */int arp_add_permanent_item(struct in_addr host_addr, char const *interface, struct sockaddr *eth){#ifdef USE_STUBS char command[200]; assert(interface != NULL && eth != NULL); snprintf(command, sizeof(command), "arp -s %s %s -i %s", inet_ntoa(host_addr), ether_hwtoa(eth->sa_data), interface); printf("arp_add_permanent_item stub - executing[%s]\n", command); if (system(command) != 0) { return -1; } return 0;#else#ifdef DYN_TARGET_LINUX return arp_ioctl(host_addr, interface, SIOCSARP, ATF_PERM | ATF_COM, eth);#endif#ifdef DYN_TARGET_WINDOWS MIB_IPNETROW entry; DWORD res; memset(&entry, 0, sizeof(entry)); entry.dwIndex = dyn_ip_get_ifindex(interface); entry.dwPhysAddrLen = 6; memcpy(&entry.bPhysAddr, ð->sa_data, 6); entry.dwAddr = host_addr.s_addr; entry.dwType = 4; res = CreateIpNetEntry(&entry); if (res == NO_ERROR) { DEBUG(DEBUG_FLAG, "Static ARP entry added (%s, %s, iface=%li)" "\n", inet_ntoa(host_addr), ether_hwtoa(eth->sa_data), entry.dwIndex); return 0; } else { DEBUG(DEBUG_FLAG, "Static ARP entry adding failed (res=%li)\n", res); return -1; }#endif /* DYN_TARGET_WINDOWS */#endif /* USE_STUBS */}/** * arp_del_permanent_item: * @host_addr: * @interface: * * * * Returns: */int arp_del_permanent_item(struct in_addr host_addr, char const *interface){#ifdef USE_STUBS char command[200]; snprintf(command, sizeof(command), "arp -i %s -d %s", interface, inet_ntoa(host_addr)); printf("arp_del stub - executing[%s]\n", command); if (system(command) != 0) { return -1; } return 0;#else#ifdef DYN_TARGET_LINUX return arp_ioctl(host_addr, interface, SIOCDARP, ATF_PERM, NULL);#endif#ifdef DYN_TARGET_WINDOWS MIB_IPNETROW entry; DWORD res; memset(&entry, 0, sizeof(entry)); entry.dwIndex = dyn_ip_get_ifindex(interface); entry.dwPhysAddrLen = 6; /* memcpy(&entry.bPhysAddr, ð->sa_data, 6); */ entry.dwAddr = host_addr.s_addr; entry.dwType = 4; res = DeleteIpNetEntry(&entry); if (res == NO_ERROR) { DEBUG(DEBUG_FLAG, "Static ARP entry removed (%s, iface=%li)\n", inet_ntoa(host_addr), entry.dwIndex); return 0; } else { DEBUG(DEBUG_FLAG, "Static ARP entry removing failed (res=%li)" "\n", res); return -1; }#endif /* DYN_TARGET_WINDOWS */#endif}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -