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

📄 kerneltun.cc

📁 Click is a modular router toolkit. To use it you ll need to know how to compile and install the sof
💻 CC
📖 第 1 页 / 共 2 页
字号:
// -*- c-basic-offset: 4 -*-/* * kerneltun.{cc,hh} -- element accesses network via /dev/tun device * Robert Morris, Douglas S. J. De Couto, Eddie Kohler * * Copyright (c) 1999-2000 Massachusetts Institute of Technology * Copyright (c) 2006 Regents of the University of California * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, subject to the conditions * listed in the Click LICENSE file. These conditions include: you must * preserve this copyright notice, and you cannot mention the copyright * holders in advertising related to the Software without their permission. * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This * notice is a summary of the Click LICENSE file; the license in that file is * legally binding. */#include <click/config.h>#include "kerneltun.hh"#include "fakepcap.hh"#include <click/error.hh>#include <click/bitvector.hh>#include <click/confparse.hh>#include <click/straccum.hh>#include <click/glue.hh>#include <clicknet/ether.h>#include <click/standard/scheduleinfo.hh>#include <unistd.h>#include <fcntl.h>#include <sys/ioctl.h>#include <arpa/inet.h>#if defined(__linux__) && defined(HAVE_LINUX_IF_TUN_H)# define KERNELTUN_LINUX 1#elif defined(HAVE_NET_IF_TUN_H)# define KERNELTUN_NET 1#elif defined(__APPLE__)# define KERNELTUN_OSX 1// assume tun driver installed from http://chrisp.de/en/projects/tunnel.html// this driver doesn't produce or expect packets with an address family prepended#endif#if defined(HAVE_NET_IF_TAP_H)# define KERNELTAP_NET 1#endif#include <net/if.h>#if HAVE_NET_IF_TUN_H# include <net/if_tun.h>#elif HAVE_LINUX_IF_TUN_H# include <linux/if_tun.h>#endif#if HAVE_NET_IF_TAP_H# include <net/if_tap.h>#endif#if defined(__NetBSD__)# include <sys/param.h># include <sys/sysctl.h>#endif#if defined(__FreeBSD__)# include <net/ethernet.h>#endifCLICK_DECLSKernelTun::KernelTun()    : _fd(-1), _tap(false), _task(this), _ignore_q_errs(false),      _printed_write_err(false), _printed_read_err(false){}KernelTun::~KernelTun(){}void *KernelTun::cast(const char *n){    if (strcmp(n, "KernelTun") == 0)	return this;    else	return Element::cast(n);}intKernelTun::configure(Vector<String> &conf, ErrorHandler *errh){    _gw = IPAddress();    _headroom = Packet::default_headroom;    _adjust_headroom = false;    _headroom += (4 - _headroom % 4) % 4; // default 4/0 alignment    _mtu_out = DEFAULT_MTU;    if (cp_va_kparse(conf, this, errh,		     "ADDR", cpkP+cpkM, cpIPPrefix, &_near, &_mask,		     "GATEWAY", cpkP, cpIPAddress, &_gw,		     "TAP", 0, cpBool, &_tap,		     "HEADROOM", cpkC, &_adjust_headroom, cpUnsigned, &_headroom,		     "ETHER", 0, cpEthernetAddress, &_macaddr,		     "IGNORE_QUEUE_OVERFLOWS", 0, cpBool, &_ignore_q_errs,		     "MTU", 0, cpInteger, &_mtu_out,#if KERNELTUN_LINUX		     "DEV_NAME", cpkD, cpString, &_dev_name, // deprecated		     "DEVNAME", 0, cpString, &_dev_name,#endif		    cpEnd) < 0)	return -1;    if (_gw) { // then it was set to non-zero by arg	// check net part matches	unsigned int g = _gw.in_addr().s_addr;	unsigned int m = _mask.in_addr().s_addr;	unsigned int n = _near.in_addr().s_addr;	if ((g & m) != (n & m)) {	    _gw = 0;	    errh->warning("not setting up default route\n(network address and gateway are on different networks)");	}    }    if (_mtu_out < (int) sizeof(click_ip))	return errh->error("MTU must be greater than %d", sizeof(click_ip));    if (_headroom > 8192)	return errh->error("HEADROOM too big");    else	_adjust_headroom = !_adjust_headroom;    return 0;}#if KERNELTUN_LINUXintKernelTun::try_linux_universal(ErrorHandler *errh){    int fd = open("/dev/net/tun", O_RDWR | O_NONBLOCK);    if (fd < 0)	return -errno;    struct ifreq ifr;    memset(&ifr, 0, sizeof(ifr));    ifr.ifr_flags = (_tap ? IFF_TAP : IFF_TUN);    if (_dev_name)	// Setting ifr_name allows us to select an arbitrary interface name.	strncpy(ifr.ifr_name, _dev_name.c_str(), sizeof(ifr.ifr_name));    int err = ioctl(fd, TUNSETIFF, (void *)&ifr);    if (err < 0) {	errh->warning("Linux universal tun failed: %s", strerror(errno));	close(fd);	return -errno;    }    _dev_name = ifr.ifr_name;    _fd = fd;    _type = LINUX_UNIVERSAL;    return 0;}#endifintKernelTun::try_tun(const String &dev_name, ErrorHandler *){    String filename = "/dev/" + dev_name;    int fd = open(filename.c_str(), O_RDWR | O_NONBLOCK);    if (fd < 0)	return -errno;    _dev_name = dev_name;    _fd = fd;    return 0;}/* * Find an available kernel tap, or report error if none are available. * Does not set up the tap. * On success, _dev_name, _type, and _fd are valid. */intKernelTun::alloc_tun(ErrorHandler *errh){#if !KERNELTUN_LINUX && !KERNELTUN_NET && !KERNELTUN_OSX && !KERNELTAP_NET    return errh->error("%s is not yet supported on this system.\n(Please report this message to click@pdos.lcs.mit.edu.)", class_name());#endif    int error, saved_error = 0;    String saved_device, saved_message;    StringAccum tried;#if KERNELTUN_LINUX    if ((error = try_linux_universal(errh)) >= 0)	return error;    else if (!saved_error || error != -ENOENT) {	saved_error = error, saved_device = "net/tun";	if (error == -ENODEV)	    saved_message = "\n(Perhaps you need to enable tun in your kernel or load the `tun' module.)";    }    tried << "/dev/net/tun, ";#endif    String dev_prefix;#ifdef __linux__    _type = LINUX_ETHERTAP;    dev_prefix = "tap";#elif defined(KERNELTUN_OSX)    _type = OSX_TUN;    dev_prefix = "tun";#elif defined(__NetBSD__) && !defined(TUNSIFHEAD)    _type = (_tap ? NETBSD_TAP : NETBSD_TUN);    dev_prefix = (_tap ? "tap" : "tun");#else    _type = (_tap ? BSD_TAP : BSD_TUN);    dev_prefix = (_tap ? "tap" : "tun");#endif#if defined(__NetBSD__) && !defined(TUNSIFHEAD)    if (_type == NETBSD_TAP) {	// In NetBSD, two ways to create a tap:	// 1. open /dev/tap cloning interface.	// 2. do ifconfig tapN create (SIOCIFCREATE), and then open(/dev/tapN).	// We use the cloning interface.	if ((error = try_tun(dev_prefix, errh)) >= 0) {	    struct ifreq ifr;	    memset(&ifr, 0, sizeof(ifr));	    if (ioctl(_fd, TAPGIFNAME, &ifr) != 0)		return errh->error("TAPGIFNAME failed: %s", strerror(errno));	    _dev_name = ifr.ifr_name;	    return error;	} else if (!saved_error || error != -ENOENT)	    saved_error = error, saved_device = dev_prefix, saved_message = String();	tried << "/dev/" << dev_prefix;	goto error_out;    }#endif    for (int i = 0; i < 6; i++) {	if ((error = try_tun(dev_prefix + String(i), errh)) >= 0)	    return error;	else if (!saved_error || error != -ENOENT)	    saved_error = error, saved_device = dev_prefix + String(i), saved_message = String();	tried << "/dev/" << dev_prefix << i << ", ";    }#if defined(__NetBSD__) && !defined(TUNSIFHEAD) error_out:#endif    if (saved_error == -ENOENT) {	tried.pop_back(2);	return errh->error("could not find a tap device\n(checked %s)\nYou may need to load a kernel module to support tap.", tried.c_str());    } else	return errh->error("could not allocate device /dev/%s: %s%s", saved_device.c_str(), strerror(-saved_error), saved_message.c_str());}intKernelTun::updown(IPAddress addr, IPAddress mask, ErrorHandler *errh){    int before = errh->nerrors();    int s = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);    if (s < 0)	return errh->error("socket() failed: %s", strerror(errno));    struct ifreq ifr;    memset(&ifr, 0, sizeof(ifr));    strncpy(ifr.ifr_name, _dev_name.c_str(), sizeof(ifr.ifr_name));#if defined(SIOCSIFADDR) && defined(SIOCSIFNETMASK)    for (int trynum = 0; trynum < 2; trynum++) {	struct sockaddr_in *sin = (struct sockaddr_in *) &ifr.ifr_addr;	sin->sin_family = AF_INET;# if HAVE_SOCKADDR_IN_SIN_LEN	sin->sin_len = sizeof(struct sockaddr_in);# endif	sin->sin_port = 0;	// Try setting the netmask twice.  On FreeBSD, we need to set the mask	// *before* we set the address, or there's nasty behavior where the	// tunnel cannot be assigned a different address.  (Or something like	// that, I forget now.)  But on Linux, you must set the mask *after*	// the address.	sin->sin_addr = mask;	if (ioctl(s, SIOCSIFNETMASK, &ifr) == 0)	    trynum++;	else if (trynum == 1) {	    errh->error("SIOCSIFNETMASK failed: %s", strerror(errno));	    goto out;	}	sin->sin_addr = addr;	if (trynum < 2 && ioctl(s, SIOCSIFADDR, &ifr) != 0) {	    errh->error("SIOCSIFADDR failed: %s", strerror(errno));	    goto out;	}    }#else# error "Lacking SIOCSIFADDR and/or SIOCSIFNETMASK"#endif#if defined(SIOCSIFHWADDR)    if (_macaddr) {	ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;	memcpy(ifr.ifr_hwaddr.sa_data, _macaddr.data(), sizeof(_macaddr));	if (ioctl(s, SIOCSIFHWADDR, &ifr) != 0)	    errh->warning("could not set interface Ethernet address: %s", strerror(errno));    }#elif defined(__NetBSD__)    if (_macaddr && _tap) {	String tap = "net.link.tap." + _dev_name, mac = _macaddr.unparse_colon();	int r = sysctlbyname(tap.c_str(), (void *) 0, (size_t *) 0, (void *) mac.c_str(), mac.length());	if (r < 0)	    errh->warning("could not set interface Ethernet address: %s", strerror(errno));    } else if (_macaddr)	errh->warning("could not set interface Ethernet address: no support for /dev/tun");#elif defined(__FreeBSD__)    if (_macaddr && _tap) {	ifr.ifr_addr.sa_len = ETHER_ADDR_LEN;	ifr.ifr_addr.sa_family = AF_LINK;	memcpy(ifr.ifr_addr.sa_data, _macaddr.data(), ETHER_ADDR_LEN);	if (ioctl(s, SIOCSIFLLADDR, &ifr) != 0)	    errh->warning("could not set interface Ethernet address: %s", strerror(errno));    } else if (_macaddr)	errh->warning("could not set interface Ethernet address: no support for /dev/tun");#else    if (_macaddr)	errh->warning("could not set interface Ethernet address: no support");#endif#if defined(SIOCSIFMTU)    if (_mtu_out != DEFAULT_MTU) {

⌨️ 快捷键说明

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