📄 fromhost.cc
字号:
// -*- c-basic-offset: 4 -*-/* * fromhost.{cc,hh} -- receives packets to Linux through the * TUN Universal TUN/TAP module * John Bicket * * Copyright (c) 2004 Massachusetts Institute of Technology * * 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 "fromhost.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>#include <net/if.h>#include <linux/if_tun.h>#ifdef HAVE_PROPER#include <proper/prop.h>#endifCLICK_DECLSFromHost::FromHost() : _fd(-1), _near(0), _mask(0), _macaddr(), _task(this){}FromHost::~FromHost(){}intFromHost::configure(Vector<String> &conf, ErrorHandler *errh){ _headroom = Packet::default_headroom; _headroom += (4 - (_headroom + 2) % 4) % 4; // default 4/2 alignment _mtu_out = DEFAULT_MTU; if (cp_va_kparse(conf, this, errh, "DEVNAME", cpkP+cpkM, cpString, &_dev_name, "DST", cpkP, cpIPPrefix, &_near, &_mask, "ETHER", 0, cpEthernetAddress, &_macaddr, "HEADROOM", 0, cpUnsigned, &_headroom, "MTU", 0, cpInteger, &_mtu_out, cpEnd) < 0) return -1; if (!_dev_name) return errh->error("must specify device name"); if (_headroom > 8192) return errh->error("HEADROOM too large"); return 0;}intFromHost::try_linux_universal(ErrorHandler *errh){ int fd;#ifdef HAVE_PROPER fd = prop_open("/dev/net/tun", O_RDWR); if (fd >= 0) { if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { int e = errno; errh->error("fcntl /dev/net/tun: %s", strerror(e)); close(fd); return -e; } } else errh->warning("prop_open /dev/net/tun: %s", strerror(errno)); if (fd < 0)#endif fd = open("/dev/net/tun", O_RDWR | O_NONBLOCK); if (fd < 0) { int e = errno; errh->error("open /dev/net/tun: %s", strerror(e)); return -e; } struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); /* we want an ethertap-like interface */ ifr.ifr_flags = IFF_TAP; /* * setting ifr_name this allows us to select an aribitrary * interface name. */ strcpy(ifr.ifr_name, _dev_name.c_str()); int err = ioctl(fd, TUNSETIFF, (void *)&ifr); if (err < 0) { errh->warning("Linux universal tun failed for %s: %s", _dev_name.c_str(), strerror(errno)); close(fd); return -errno; } _dev_name = ifr.ifr_name; _fd = fd; return 0;}intFromHost::setup_tun(struct in_addr near, struct in_addr mask, ErrorHandler *errh){ char tmp[512], tmp0[64], tmp1[64]; if (_macaddr) { sprintf(tmp, "/sbin/ifconfig %s hw ether %s", _dev_name.c_str(), _macaddr.unparse_colon().c_str()); if (system(tmp) != 0) { errh->error("%s: %s", tmp, strerror(errno)); } sprintf(tmp, "/sbin/ifconfig %s arp", _dev_name.c_str()); if (system(tmp) != 0) return errh->error("%s: couldn't set arp flags: %s", tmp, strerror(errno)); } if (near.s_addr) { strcpy(tmp0, inet_ntoa(near)); strcpy(tmp1, inet_ntoa(mask)); sprintf(tmp, "/sbin/ifconfig %s %s netmask %s up 2>/dev/null", _dev_name.c_str(), tmp0, tmp1); if (system(tmp) != 0) { return errh->error("%s: `%s' failed\n(Perhaps Ethertap is in a kernel module that you haven't loaded yet?)", _dev_name.c_str(), tmp); } } // calculate maximum packet size needed to receive data from // tun/tap. _mtu_in = _mtu_out + 4; return 0;}voidFromHost::dealloc_tun(){ if (_near) { String cmd = "/sbin/ifconfig " + _dev_name + " down"; if (system(cmd.c_str()) != 0) click_chatter("%s: failed: %s", name().c_str(), cmd.c_str()); }}intFromHost::initialize(ErrorHandler *errh){ if (try_linux_universal(errh) < 0) return -1; if (setup_tun(_near, _mask, errh) < 0) return -1; ScheduleInfo::join_scheduler(this, &_task, errh); _nonfull_signal = Notifier::downstream_full_signal(this, 0, &_task); add_select(_fd, SELECT_READ); return 0;}voidFromHost::cleanup(CleanupStage){ if (_fd >= 0) { close(_fd); remove_select(_fd, SELECT_READ); }}voidFromHost::selected(int fd){ if (fd != _fd) return; WritablePacket *p = Packet::make(_headroom, 0, _mtu_in, 0); if (!p) { click_chatter("out of memory!"); return; } int cc = read(_fd, p->data(), _mtu_in); if (cc > 0) { p->take(_mtu_in - cc); // 2-byte padding followed by an Ethernet type p->pull(4); p->set_mac_header(p->data()); const click_ip *ip = reinterpret_cast<const click_ip *>(p->data() + sizeof(click_ether)); p->set_dst_ip_anno(IPAddress(ip->ip_dst)); p->set_ip_header(ip, ip->ip_hl << 2); p->timestamp_anno().set_now(); output(0).push(p); } else { p->kill(); perror("FromHost read"); } if (!_nonfull_signal) { remove_select(_fd, SELECT_READ); return; }}boolFromHost::run_task(Task *){ if (!_nonfull_signal) return false; add_select(_fd, SELECT_READ); return true;}enum {H_DEV_NAME, H_SIGNAL};StringFromHost::read_param(Element *e, void *thunk){ FromHost *td = (FromHost *)e; switch ((uintptr_t) thunk) { case H_DEV_NAME: return td->dev_name(); case H_SIGNAL: return String(td->_nonfull_signal.active()); default: return ""; }}voidFromHost::add_handlers(){ add_read_handler("dev_name", read_param, (void *) H_DEV_NAME); add_read_handler("signal", read_param, (void *) H_SIGNAL);}CLICK_ENDDECLSELEMENT_REQUIRES(userlevel linux)EXPORT_ELEMENT(FromHost)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -