📄 rawsocket.cc
字号:
// -*- mode: c++; c-basic-offset: 2 -*-/* * rawsocket.{cc,hh} -- transports raw IP packets via safe raw sockets (user-level) * * Mark Huang <mlhuang@cs.princeton.edu> * * Copyright (c) 2004-2005 The Trustees of Princeton University (Trustees). * * 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 "rawsocket.hh"#include <click/error.hh>#include <click/confparse.hh>#include <click/glue.hh>#include <click/router.hh>#include <click/standard/scheduleinfo.hh>#include <click/packet_anno.hh>#include <click/packet.hh>#include <unistd.h>#include <sys/socket.h>#include <arpa/inet.h>#include <fcntl.h>#ifndef __sun#include <sys/ioctl.h>#else#include <sys/ioccom.h>#endif#ifdef HAVE_PROPER#include <proper/prop.h>#endif#include "fakepcap.hh"CLICK_DECLSRawSocket::RawSocket() : _task(this), _timer(this), _fd(-1), _port(0), _proper(false), _snaplen(2048), _headroom(Packet::default_headroom), _rq(0), _wq(0){}RawSocket::~RawSocket(){}intRawSocket::configure(Vector<String> &conf, ErrorHandler *errh){ CpVaParseCmd parsecmd = cpUnsignedShort; if (conf.size() && conf[0].upper() == "TCP") parsecmd = cpTCPPort; else if (conf.size() && conf[0].upper() == "UDP") parsecmd = cpUDPPort; String socktype; if (cp_va_kparse(conf, this, errh, "TYPE", cpkP+cpkM, cpString, &socktype, "PORT", cpkP, parsecmd, &_port, "SNAPLEN", 0, cpUnsigned, &_snaplen, "HEADROOM", 0, cpUnsigned, &_headroom, "PROPER", 0, cpBool, &_proper, cpEnd) < 0) return -1; socktype = socktype.upper(); if (socktype == "TCP") _protocol = IPPROTO_TCP; else if (socktype == "UDP") _protocol = IPPROTO_UDP; else if (socktype == "GRE") _protocol = IPPROTO_GRE; else if (socktype == "ICMP") _protocol = IPPROTO_ICMP; else return errh->error("unknown socket type `%s'", socktype.c_str()); return 0;}intRawSocket::initialize_socket_error(ErrorHandler *errh, const char *syscall){ int e = errno; // preserve errno if (_fd >= 0) { close(_fd); _fd = -1; } return errh->error("%s: %s", syscall, strerror(e));}intRawSocket::initialize(ErrorHandler *errh){ struct sockaddr_in sin; // open socket, set options, bind to address _fd = socket(PF_INET, SOCK_RAW, _protocol); if (_fd < 0) return initialize_socket_error(errh, "socket"); if (_port) { memset(&sin, 0, sizeof(sin)); sin.sin_family = PF_INET; sin.sin_port = htons(_port); sin.sin_addr = inet_makeaddr(0, 0); // bind to port#ifdef HAVE_PROPER int ret = -1; if (_proper) { ret = prop_bind_socket(_fd, (struct sockaddr *)&sin, sizeof(sin)); if (ret < 0) errh->warning("prop_bind_socket: %s", strerror(errno)); } if (ret < 0)#endif if (bind(_fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) return initialize_socket_error(errh, "bind"); } // nonblocking I/O and close-on-exec for the socket fcntl(_fd, F_SETFL, O_NONBLOCK); fcntl(_fd, F_SETFD, FD_CLOEXEC); // include IP header int one = 1; if (setsockopt(_fd, 0, IP_HDRINCL, &one, sizeof(one)) < 0) return initialize_socket_error(errh, "IP_HDRINCL"); if (noutputs()) add_select(_fd, SELECT_READ); if (ninputs()) { ScheduleInfo::join_scheduler(this, &_task, errh); _signal = Notifier::upstream_empty_signal(this, 0, &_task); add_select(_fd, SELECT_WRITE); _timer.initialize(this); } return 0;}voidRawSocket::cleanup(CleanupStage){ if (_rq) _rq->kill(); if (_wq) _wq->kill(); if (_fd >= 0) { close(_fd); remove_select(_fd, SELECT_READ | SELECT_WRITE); _fd = -1; }}voidRawSocket::selected(int fd){ ErrorHandler *errh = ErrorHandler::default_handler(); int len; if (noutputs()) { // read data from socket if (!_rq) _rq = Packet::make(_headroom, (const unsigned char *)0, _snaplen, 0); if (_rq) { len = recv(_fd, _rq->data(), _rq->length(), MSG_TRUNC); if (len > 0) { if (len > _snaplen) { assert(_rq->length() == (uint32_t)_snaplen); SET_EXTRA_LENGTH_ANNO(_rq, len - _snaplen); } else _rq->take(_snaplen - len); // set timestamp (void) ioctl(fd, SIOCGSTAMP, &_rq->timestamp_anno()); // set IP annotations if (fake_pcap_force_ip(_rq, FAKE_DLT_RAW)) output(0).push(_rq); else _rq->kill(); _rq = 0; } else { if (len == 0 || errno != EAGAIN) { if (errno != EAGAIN) errh->error("recv: %s", strerror(errno)); } } } } if (ninputs()) { // write data to socket Packet *p; if (_wq) { p = _wq; _wq = 0; } else { p = input(0).pull(); } if (p) { // cast to int so very large plen is interpreted as negative if ((int)p->length() < (int)sizeof(click_ip)) { errh->error("runt IP packet (%d bytes)", p->length()); p->kill(); } else { const click_ip *ip = (const click_ip *) p->data(); struct sockaddr_in sin; // set up destination memset(&sin, 0, sizeof(sin)); sin.sin_family = PF_INET; sin.sin_addr = ip->ip_dst; while (p->length()) { // send packet len = sendto(_fd, p->data(), p->length(), 0, (const struct sockaddr*)&sin, sizeof(sin)); if (len < 0) { if (errno == ENOBUFS || errno == EAGAIN) { // socket queue full, try again later _wq = p; remove_select(_fd, SELECT_WRITE); _events &= ~SELECT_WRITE; _backoff = (!_backoff) ? 1 : _backoff*2; _timer.schedule_after(Timestamp::make_usec(_backoff)); return; } else if (errno == EINTR) { // interrupted by signal, try again immediately continue; } else { // unexpected error: drop packet errh->error("sendto: %s", strerror(errno)); break; } } else { p->pull(len); } } _backoff = 0; p->kill(); } } // nothing to write, wait for upstream signal if (!p && !_signal && (_events & SELECT_WRITE)) { remove_select(_fd, SELECT_WRITE); _events &= ~SELECT_WRITE; } }}voidRawSocket::run_timer(Timer *){ if ((_wq || _signal) && !(_events & SELECT_WRITE) && _fd >= 0) { add_select(_fd, SELECT_WRITE); _events |= SELECT_WRITE; selected(_fd); }}boolRawSocket::run_task(Task *){ if (!_wq && !(_events & SELECT_WRITE) && _fd >= 0) { add_select(_fd, SELECT_WRITE); _events |= SELECT_WRITE; selected(_fd); return true; } else return false;}voidRawSocket::add_handlers(){ add_task_handlers(&_task);}CLICK_ENDDECLSELEMENT_REQUIRES(userlevel linux)EXPORT_ELEMENT(RawSocket)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -