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

📄 dyn_ip.c

📁 mobile ip 在linux下的一种实现
💻 C
📖 第 1 页 / 共 5 页
字号:
/* $Id: dyn_ip.c,v 1.79 2001/10/04 16:46:37 jm Exp $ * Tunnel and route interface to kernel * * 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. *//* This interface code is heavily based on Alexey Kuznetsov's iproute2 */#define DEBUG_FLAG 'K'#include "config.h"#include "owntypes.h"#ifndef _GNU_SOURCE#define _GNU_SOURCE#endif#include <stdio.h>#include <stdlib.h>#include <string.h>#include <assert.h>#include <net/if.h>#include <netinet/in.h>#include <sys/socket.h>#include <arpa/inet.h>#include <sys/ioctl.h>#include <netinet/ip.h>#include <errno.h>#include <unistd.h>#ifdef DYN_TARGET_LINUX#include <linux/if_tunnel.h>#include <linux/netlink.h>#include <linux/rtnetlink.h>#include <net/if_arp.h>#endif#include <time.h>#include <fcntl.h>#include <sys/uio.h>#include "debug.h"#include "dyn_ip.h"#include "util.h"#ifdef DYN_TARGET_WINDOWS#include "windows_extra.h"#endif#ifndef MSG_TRUNC#define MSG_TRUNC 0x20#endif#ifndef IPPROTO_GRE#define IPPROTO_GRE 47#endif#ifdef DYN_TARGET_LINUXstruct rtnl_handle{	int fd;	struct sockaddr_nl local;	__u32 seq;	__u32 dump;};static struct idxmap *idxmap = NULL;/* generic tunnel ioctl caller for dyn_ip_tunnel_add(), * dyn_ip_tunnel_add_gre(), and dyn_ip_tunnel_del() */static int tunnel_ioctl(int cmd, const char *dev, __u32 remote, __u32 local,			int proto, __u32 key){	struct ifreq ifr;	struct ip_tunnel_parm p;	int s;	assert(dev != NULL && strlen(dev) < IFNAMSIZ);	memset(&p, 0, sizeof(p));	p.iph.version = 4;	p.iph.ihl = 5;	p.iph.frag_off = htons(IP_DF); /* Flag: Don't Fragment */	p.iph.ttl = 64; /* fixed TTL for the outer IP header to make the			 * tunnel transparent for traceroute like applications			 */	dynamics_strlcpy(p.name, dev, IFNAMSIZ);	if (cmd == SIOCADDTUNNEL) {		if (key != 0 && proto == IPPROTO_GRE) {			p.i_key = p.o_key = htonl(key);			p.i_flags |= htons(0x2000); /* GRE_KEY */			p.o_flags |= htons(0x2000); /* GRE_KEY */		}		p.iph.protocol = proto;		p.iph.daddr = remote;		p.iph.saddr = local;		if (proto == IPPROTO_IPIP)			dynamics_strlcpy(ifr.ifr_name, "tunl0", IFNAMSIZ);		else if (proto == IPPROTO_GRE)			dynamics_strlcpy(ifr.ifr_name, "gre0", IFNAMSIZ);	} else if (cmd == SIOCDELTUNNEL) {		dynamics_strlcpy(ifr.ifr_name, dev, IFNAMSIZ);	} else {		DEBUG(DEBUG_FLAG, "tunnel_ioctl: Unknown cmd %i\n", cmd);		return -1;	}	ifr.ifr_ifru.ifru_data = (void*) &p;	s = socket(AF_INET, SOCK_DGRAM, 0);	if (s < 0) {		DEBUG(DEBUG_FLAG, "tunnel_ioctl: socket: %s\n",		      strerror(errno));		return -1;	}	if (ioctl(s, cmd, &ifr) != 0) {		DEBUG(DEBUG_FLAG, "tunnel_ioctl: ioctl: %s\n",		      strerror(errno));		close(s);		return -1;	}	close(s);	return 0;}/** * dyn_ip_tunnel_add: * @dev: the device name of the tunnel to add * @remote: IP address of remote end of tunnel * @local: IP address of local end of tunnel *  * Add an IP Encapsulation within IP (RFC 2003) tunnel named * @dev between @local and @remote. * * Returns: 0 if successful, else -1 */int dyn_ip_tunnel_add(const char *dev, struct in_addr remote, 		      struct in_addr local){	return tunnel_ioctl(SIOCADDTUNNEL, dev, remote.s_addr, local.s_addr,			    IPPROTO_IPIP, 0);}/** * dyn_ip_tunnel_add_gre: * @dev: the device name of the tunnel to add * @remote: IP address of remote end of tunnel * @local: IP address of local end of tunnel * @key: Key field for the GRE header (used to index the tunnels between same * end-points) * * Add a Generic Routing Encapsulation (RFC 1701) tunnel named @dev * between @local and @remote. * * Returns: 0 if successful, else -1 */int dyn_ip_tunnel_add_gre(const char *dev, struct in_addr remote,			  struct in_addr local, int key){	return tunnel_ioctl(SIOCADDTUNNEL, dev, remote.s_addr, local.s_addr,			    IPPROTO_GRE, key);}/** * dyn_ip_tunnel_del: * @dev: the name of the device to delete * * Delete tunnel named @dev. * * Returns: 0 if successful, else -1 */int dyn_ip_tunnel_del(const char *dev){	return tunnel_ioctl(SIOCDELTUNNEL, dev, 0, 0, IPPROTO_IPIP, 0);}/** * dyn_ip_link_set_dev: * @dev: interface to be modified * @flag: flags to be set * @set: 1=set given flags, 0=unset given flags * * Modifies given interface @dev by setting or unsetting interface flags @flag. * * Returns: 0 on success or -1 on failure */static int dyn_ip_link_set_dev(const char *dev, int flag, int set){	struct ifreq ifr;	int s, changed;	assert(dev != NULL);	assert(strlen(dev) < IFNAMSIZ);	dynamics_strlcpy(ifr.ifr_name, dev, IFNAMSIZ);	s = socket(AF_INET, SOCK_DGRAM, 0);	if (s < 0) {		DEBUG(DEBUG_FLAG, "dyn_ip_link_set_dev: socket: %s\n",		      strerror(errno));		return -1;	}	if (ioctl(s, SIOCGIFFLAGS, &ifr) != 0) {		DEBUG(DEBUG_FLAG,		      "dyn_ip_link_set_dev: ioctl SIOCGIFFLAGS: %s\n",		      strerror(errno));		close(s);		return -1;	}	changed = 0;	if (set) {		if ((ifr.ifr_flags & flag) == 0) {			ifr.ifr_flags |= flag;			changed = 1;		}	} else {		if ((ifr.ifr_flags & flag) != 0) {			ifr.ifr_flags &= ~flag;			changed = 1;		}	}	if (changed) {		if (ioctl(s, SIOCSIFFLAGS, &ifr) != 0) {			DEBUG(DEBUG_FLAG,			      "dyn_ip_link_set_dev_up: ioctl SIOCSIFFLAGS: "			      "%s\n", strerror(errno));			close(s);			return -1;		}	}	close(s);	return 0;}/** * dyn_ip_link_set_dev_up: * @dev: network device name * * Set the link on device @dev up. *  * Returns: 0 if successful, else -1 */int dyn_ip_link_set_dev_up(const char *dev){	return dyn_ip_link_set_dev(dev, IFF_UP, 1);}/** * dyn_ip_link_set_dev_down: * @dev: network device name *  * Set the link on device @dev down. *  * Returns: 0 if successful, else -1 */int dyn_ip_link_set_dev_down(const char *dev){	return dyn_ip_link_set_dev(dev, IFF_UP, 0);}/** * rtnl_open: * @rth:  * @subscriptions:  *  *  *  * Returns:  */static int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions){	unsigned int len;	assert(rth != NULL);	rth->fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);	if (rth->fd < 0) {		DEBUG(DEBUG_FLAG,		      "rtnl_open: cannot open netlink socket: %s\n",		      strerror(errno));		return -1;	}	memset(&rth->local, 0, sizeof(rth->local));	rth->local.nl_family = AF_NETLINK;	rth->local.nl_groups = subscriptions;	if (bind(rth->fd, (struct sockaddr *) &rth->local,		 sizeof(rth->local)) < 0) {		DEBUG(DEBUG_FLAG,		      "rtnl_open: cannot bind netlink socket: %s\n",		      strerror(errno));		close(rth->fd);		return -1;	}	len = sizeof(rth->local);	if (getsockname(rth->fd, (struct sockaddr *) &rth->local, &len) < 0) {		DEBUG(DEBUG_FLAG,		      "rtnl_open: cannot getsockname: %s\n", strerror(errno));		close(rth->fd);		return -1;	}	if (len != sizeof(rth->local)) {		DEBUG(DEBUG_FLAG,		      "rtnl_open: wrong address length %i != %i\n",		      len, sizeof(rth->local));		close(rth->fd);		return -1;	}	if (rth->local.nl_family != AF_NETLINK) {		DEBUG(DEBUG_FLAG,		      "rtnl_open: wrong address family %i != %i\n",		      rth->local.nl_family, AF_NETLINK);		close(rth->fd);		return -1;	}	rth->seq = time(NULL);	return 0;}/** * rtnl_talk: * @rth:  * @n:  * @answer:  *  *  *  * Returns:  */static int rtnl_talk(struct rtnl_handle *rth, struct nlmsghdr *n,		     struct nlmsghdr *answer){	int status;	struct nlmsghdr *h;	struct sockaddr_nl nladdr;	struct iovec iov;	char   buf[8192];	struct msghdr msg = {		(void *) &nladdr, sizeof(nladdr),		&iov, 1,		NULL, 0,		0	};	iov.iov_base = (void*) n;	iov.iov_len = n->nlmsg_len;	memset(&nladdr, 0, sizeof(nladdr));	nladdr.nl_family = AF_NETLINK;	nladdr.nl_pid = 0;	nladdr.nl_groups = 0;	n->nlmsg_seq = ++rth->seq;	if (answer == NULL)		n->nlmsg_flags |= NLM_F_ACK;	status = sendmsg(rth->fd, &msg, 0);	if (status < 0) {		DEBUG(DEBUG_FLAG, "rtnl_talk: sendmsg: %s\n", strerror(errno));		return -1;	}	iov.iov_base = buf;	iov.iov_len = sizeof(buf);	do {		status = recvmsg(rth->fd, &msg, 0);		if (status < 0) {			if (errno == EINTR)				continue;			DEBUG(DEBUG_FLAG, "rtnl_talk: OVERRUN: %s\n",					 strerror(errno));			continue;		}		if (status == 0) {			DEBUG(DEBUG_FLAG, "rtnl_talk: EOF on netlink\n");			return -1;		}		if (msg.msg_namelen != sizeof(nladdr)) {			DEBUG(DEBUG_FLAG,			      "rtnl_talk: sender address length == %i != %i\n",			      msg.msg_namelen, sizeof(nladdr));			return -1;		}		for (h = (struct nlmsghdr*) buf; status >= sizeof(*h); ) {			int len = h->nlmsg_len;			pid_t pid = h->nlmsg_pid;			int l = len - sizeof(*h);			unsigned seq = h->nlmsg_seq;			if (l < 0 || len > status) {				if (msg.msg_flags & MSG_TRUNC) {					DEBUG(DEBUG_FLAG,					      "rtnl_talk: "					      "truncated message\n");					return -1;				}				DEBUG(DEBUG_FLAG,				      "rtnl_talk: malformed message: len=%d\n",				      len);				return -1;			}			if (h->nlmsg_pid != pid || h->nlmsg_seq != seq) {				/* junk */				continue;			}			if (h->nlmsg_type == NLMSG_ERROR) {				struct nlmsgerr *err =					(struct nlmsgerr *) NLMSG_DATA(h);				if (l < sizeof(struct nlmsgerr)) {					DEBUG(DEBUG_FLAG,					      "rtnl_talk: ERROR truncated\n");					return -1;				}				errno = -err->error;				if (errno == 0) {					if (answer)						memcpy(answer, h,						       h->nlmsg_len);					return 0;				}				DEBUG(DEBUG_FLAG,				      "rtnl_talk: RTNETLINK error: "				      "%s\n", strerror(errno));				return -1;			}			if (answer) {				memcpy(answer, h, h->nlmsg_len);				return 0;			}			DEBUG(DEBUG_FLAG, "rtnl_talk: unexpected reply\n");			status -= NLMSG_ALIGN(len);			h = (struct nlmsghdr *) 				(((char *) h) + NLMSG_ALIGN(len));		}		if (msg.msg_flags & MSG_TRUNC) {			DEBUG(DEBUG_FLAG, "rtnl_talk: message truncated\n");			continue;		}		if (status) {			DEBUG(DEBUG_FLAG, "rtnl_talk: remnant of size %i\n",			      status);			return -1;		}	} while (1);}/** * addattr32: * @n:  * @maxlen:  * @type:  * @data:  *  *  *  * Returns:  */static int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data){	int len;	struct rtattr *rta;	len = RTA_LENGTH(4);	if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen)		return -1;	rta = (struct rtattr *)(((char *) n) + NLMSG_ALIGN(n->nlmsg_len));	rta->rta_type = type;	rta->rta_len = len;	memcpy(RTA_DATA(rta), &data, 4);	n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;	return 0;}/** * addattr_l: * @n:  * @maxlen:  * @type:  * @data:  * @alen:  *  *  *  * Returns:  */static int addattr_l(struct nlmsghdr *n, int maxlen, int type,		     const void *data, int alen){	int len;	struct rtattr *rta;	len = RTA_LENGTH(alen);	if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen)		return -1;	rta = (struct rtattr *)(((char *) n) + NLMSG_ALIGN(n->nlmsg_len));	rta->rta_type = type;	rta->rta_len = len;	memcpy(RTA_DATA(rta), data, alen);	n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;	return 0;}static int rtnl_wilddump_request(struct rtnl_handle *rth, int family, int type){	struct {		struct nlmsghdr nlh;		struct rtgenmsg g;	} req;	struct sockaddr_nl nladdr;	memset(&nladdr, 0, sizeof(nladdr));	nladdr.nl_family = AF_NETLINK;	req.nlh.nlmsg_len = sizeof(req);	req.nlh.nlmsg_type = type;	req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;	req.nlh.nlmsg_pid = 0;	req.nlh.nlmsg_seq = rth->dump = ++rth->seq;	req.g.rtgen_family = family;	return sendto(rth->fd, (void *) &req, sizeof(req), 0,		      (struct sockaddr *) &nladdr, sizeof(nladdr));}static int rtnl_dump_filter(struct rtnl_handle *rth,			    int (*filter)(struct sockaddr_nl *,					  struct nlmsghdr *n, void *),			    void *arg1){	char buf[8192];	struct sockaddr_nl nladdr;	struct iovec iov = { buf, sizeof(buf) };	do {		int status;		struct nlmsghdr *h;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -