⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 proxyarp.c

📁 mobile ip 在linux下的一种实现
💻 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, &eth->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, &eth->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 + -