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

📄 divertsocket.cc

📁 COPE the first practical network coding scheme which is developped on click
💻 CC
字号:
/* * fromdevice.{cc,hh} -- element diverts IP packets into Click using divert sockets * Alexander Yip * * Copyright (c) 2001 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 "divertsocket.hh"#include <click/error.hh>#include <click/confparse.hh>#include <click/glue.hh>#include <unistd.h>#include <fcntl.h># include <net/if.h>#if defined(__FreeBSD__ )# include <sys/ioctl.h># include <sys/socket.h># include <sys/types.h>#elif defined(__linux__)# include <features.h># include <net/if_packet.h># include <netinet/ip.h># include <netinet/in.h># include <netinet/tcp.h># include <netinet/udp.h># include <sys/param.h># include <linux/types.h># include <linux/icmp.h># if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1#  include <netpacket/packet.h>#  include <net/ethernet.h># else#  include <linux/if_packet.h>#  include <linux/if_ether.h># endif#endif#include <clicknet/ip.h>DivertSocket::DivertSocket(){  _fd = -1;}DivertSocket::~DivertSocket() {  uninitialize();}voidDivertSocket::notify_ninputs(int n){  set_ninputs(n);}voidDivertSocket::notify_noutputs(int n){  set_noutputs(n);}int DivertSocket::parse_ports(const String &param, ErrorHandler *errh,			      int32_t *portl, int32_t *porth) {  int dash;  *portl =  *porth = 0;;  dash = param.find_left('-');  if (dash < 0)     dash = param.length();  if (!cp_integer(param.substring(0,dash), portl)){    //errh->error("1 bad port in rule spec");    return -1;  }  if (dash < param.length()) {    if (!cp_integer(param.substring(dash+1), porth)) {      //errh->error("2 bad port in rule spec");      return -1;    }  } else     *porth = *portl;  if (*portl > *porth || *portl < 0 || *porth > 0xFFFF) {    errh->error("port(s) %d-%d out of range in rule spec", portl, porth);    return -1;  }  return 0;}intDivertSocket::configure(const Vector<String> &conf, ErrorHandler *errh){  int confindex = 5;  _have_sport = _have_dport = false;  _setup_fw = true;#ifdef 0  for(int i=0; i < conf.size(); i++){    click_chatter("  %s\n", ((String)conf[i]).cc());  }#endif	  if (conf.size() == 1) {    if (cp_va_parse(conf[0], this, errh, cpUnsigned, "divertport", 		    &_divertport, cpEnd) < 0)      return -1;    _setup_fw = false;    return 0;  }     if (conf.size() < confindex+1) {    errh->error("not enough parameters for DivertSocket");    return -1;  }  if (conf.size() > confindex+4) {    errh->error("too many parameters for DivertSocket");    return -1;  }  /*  click_chatter("Hello 1 this = %x\n", (void *)this);  click_chatter("Hello 2 this = %x\n", (void *)this);  click_chatter("conf[0] = %s\n", conf[0].cc());  */  // parse devicename  if (cp_va_parse(conf[0], this, errh, cpString, "device", &_device, cpEnd) < 0)    return -1;  // parse divert port number  if (cp_va_parse(conf[1], this, errh, cpUnsigned, "divertport", &_divertport, cpEnd) < 0)    return -1;  // parse rule number  if (cp_va_parse(conf[2], this, errh, cpUnsigned, "rulenumber", &_rulenumber, cpEnd) < 0)    return -1;    // parse protocol & src addr/mask  if ((cp_va_parse(conf[3], this, errh, cpByte, "protocol", &_protocol, cpEnd) < 0) ||      (!cp_ip_prefix(conf[4], &_saddr, &_smask, true, this))) {    errh->error("invalid src addr/mask");    return -1;  }   _saddr &= _smask;  if ((_protocol != IP_PROTO_UDP && _protocol != IP_PROTO_TCP) && (conf.size() > 7)) {    errh->error("too many parameters for non TCP/UDP rule");    return -1;  }    // parse src ports  if (_protocol == IP_PROTO_UDP || _protocol == IP_PROTO_TCP) {    if (parse_ports(conf[5], errh, &_sportl, &_sporth) < 0)      _have_sport = false;    else {      _have_sport = true;      confindex++;    }  } else if (parse_ports(conf[5], errh, &_sportl, &_sporth) >= 0) {    errh->error("ports not required for non TCP/UDP rules");    return -1;  }  //printf("1 confindex = %d (%s)\n", confindex, conf[confindex].cc());  // parse dst addr/mask  if (!cp_ip_prefix(conf[confindex], &_daddr, &_dmask, true, this )){    errh->error("invalid dst addr/mask");    return -1;  }  _daddr &= _dmask;  confindex++;    // parse dst ports  if (confindex < conf.size()) {    //printf("2 confindex = %d (%s)\n", confindex, conf[confindex].cc());    if (_protocol == IP_PROTO_UDP || _protocol == IP_PROTO_TCP) {      if (parse_ports(conf[confindex], errh, &_dportl, &_dporth) < 0)	_have_dport = false;      else {	_have_dport = true;	confindex++;      }    } else if (parse_ports(conf[confindex], errh, &_dportl, &_dporth) >= 0) {      errh->error("ports not required for non TCP/UDP rules");      return -1;    }  }  // parse in/out  if (confindex < conf.size() ) {    if (cp_va_parse(conf[confindex], this, errh, cpString, "in/out", &_inout, cpEnd) < 0)      return -1;    if ( (_inout != "") && (_inout != "in") && (_inout != "out") ) {      errh->error("illegal direction specifier: '%s'", _inout.cc());      return -1;    }  }  return 0;}intDivertSocket::setup_firewall(ErrorHandler *errh) {#if defined(__FreeBSD__)  char tmp[512];  char sport[32], dport[32], prot[8];#elif defined(__linux__)  char *fw_policy="DIVERT";  char fw_chain[32];#endif  // Setup firewall to divert sockets#if defined(__FreeBSD__)  if (_protocol == 0)     sprintf(prot, "ip");  else    sprintf(prot, "%d", _protocol);   if (_have_sport) {    if (_sportl == _sporth)      sprintf(sport, "%d", _sportl);    else      sprintf(sport, "%d-%d", _sportl, _sporth);  } else {    sport[0]=0;  }  if (_have_dport) {    if (_dportl == _dporth)      sprintf(dport, "%d", _dportl);    else      sprintf(dport, "%d-%d", _dportl, _dporth);  } else {    dport[0]=0;  }  sprintf(tmp, "/sbin/ipfw add %u divert %u %s from %s:%s %s to %s:%s %s %s via %s",	  _rulenumber, _divertport, 	  prot, _saddr.s().cc(), _smask.s().cc(), sport,	  _daddr.s().cc(), _dmask.s().cc(), dport, _inout.cc(), _device.cc() );  printf("%s\n", tmp);  if (system(tmp) != 0) {    close (_fd);    errh->error("ipfw failed");    return -1;  }#elif defined(__linux__)    /* fill in the rule first */  bzero(&fw, sizeof (struct ip_fw));  fw.fw_proto= _protocol;  fw.fw_redirpt=htons(bindPort.sin_port);  //fw.fw_redirpt=bindPort.sin_port;  if (_have_sport) {    fw.fw_spts[0]=_sportl;    fw.fw_spts[1]=_sporth;  } else {    fw.fw_spts[0]=0;    fw.fw_spts[1]=0xffff;  }  if (_have_dport) {    fw.fw_dpts[0]=_dportl;    fw.fw_dpts[1]=_dporth;  } else {    fw.fw_dpts[0]=0;    fw.fw_dpts[1]=0xffff;  }  fw.fw_src.s_addr = _saddr.in_addr().s_addr;  fw.fw_smsk.s_addr= _smask.in_addr().s_addr;  fw.fw_dst.s_addr = _daddr.in_addr().s_addr;  fw.fw_dmsk.s_addr= _dmask.in_addr().s_addr;  fw.fw_outputsize=0xffff;  strcpy(fw.fw_vianame, _device.cc() );  /* fill in the fwuser structure */  ipfu.ipfw=fw;  memcpy(ipfu.label, fw_policy, strlen(fw_policy));  /* fill in the fwnew structure */  ipfc.fwn_rule=ipfu;  ipfc.fwn_rulenum = _rulenumber;  /* open a socket */  if ((fw_sock=socket(AF_INET, SOCK_RAW, IPPROTO_RAW))==-1) {    errh->error("could not create raw socket for firewall setup");    return -1;  }  if (_inout == "in") {    strcpy(fw_chain, "input");    memcpy(ipfc.fwn_label, fw_chain, strlen(fw_chain));  } else if (_inout == "out") {    strcpy(fw_chain, "output");    memcpy(ipfc.fwn_label, fw_chain, strlen(fw_chain));  } else {    memcpy(&ipfc2, &ipfc, sizeof(ipfc));    strcpy(fw_chain, "input");    memcpy(ipfc.fwn_label, fw_chain, strlen(fw_chain));    strcpy(fw_chain, "output");    memcpy(ipfc2.fwn_label, fw_chain, strlen(fw_chain));    /* write a rule into it */    if (setsockopt(fw_sock, IPPROTO_IP, IP_FW_INSERT, &ipfc2, sizeof(ipfc2))==-1) {      errh->error("could not set output firewall rule: %s", strerror(errno));      return -1;    }  }  /* write a rule into it */  if (setsockopt(fw_sock, IPPROTO_IP, IP_FW_INSERT, &ipfc, sizeof(ipfc))==-1) {    errh->error("could not set firewall rule: %s",strerror(errno));    return -1;  }#else   close(_fd);  errh->error("This platform is not yet supported by DivertSocket");  return -1;  #endif  return 0;}		  intDivertSocket::initialize(ErrorHandler *errh) {  int ret, n;  struct sockaddr_in bindPort; //, sin;#ifdef 0  printf("Device  : \t%s\n", _device.cc());  printf("DIV port: \t%u\n", _divertport);  printf("Rule Num: \t%u\n", _rulenumber);  printf("Protocol: \t%d\n", _protocol);  printf("src/mask: \t%s / %s\n", _saddr.s().cc(), _smask.s().cc());  printf("dst/mask: \t%s / %s\n", _daddr.s().cc(), _dmask.s().cc());  printf("sport   : \t%u - %u\n", _sportl, _sporth);  printf("dport   : \t%u - %u\n", _dportl, _dporth);  printf("in/out  : \t%s\n", _inout.cc());#endif  // Setup divert socket  _fd = socket(AF_INET, SOCK_RAW, IPPROTO_DIVERT);  if (_fd == -1) {    errh->error("DivertSocket(socket): %s", strerror(errno));    return -1;  }  bindPort.sin_family=AF_INET;  bindPort.sin_port=htons(_divertport);  bindPort.sin_addr.s_addr=0;  // set REUSE option  n = 1;  if (setsockopt (_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&n, sizeof (n)) < 0) {    errh->error("could not set REUSEADDR");    close (_fd);    return -1;  }    // bind to port  ret=bind(_fd, (struct sockaddr *)&bindPort, sizeof(struct sockaddr_in));  if (ret != 0) {    close(_fd);    errh->error("DivertSocket(bind): %s", strerror(errno));    return -1;  }  fcntl(_fd, F_SETFL, O_NONBLOCK);  // setup firewall  if (_setup_fw && (ret = setup_firewall(errh) < 0))    return ret;  add_select(_fd, SELECT_READ);  return 0;}  void DivertSocket::uninitialize(){  if (_fd >= 0) {        if (_setup_fw) {#if defined(__FreeBSD__)      char tmp[64];      sprintf(tmp, "/sbin/ipfw delete %u", _rulenumber);      system(tmp);      #elif defined(__linux__)       struct ip_fwdelnum ipfwd;            ipfwd.fwd_rulenum = ipfc.fwn_rulenum;      strcpy(ipfwd.fwd_label, ipfc.fwn_label);                  if (setsockopt(fw_sock, IPPROTO_IP, IP_FW_DELETE_NUM, &ipfwd, sizeof(ipfwd))==-1) {	fprintf(stderr, "could not remove firewall rule");      }            if (_inout == "") {	ipfwd.fwd_rulenum = ipfc2.fwn_rulenum;	strcpy(ipfwd.fwd_label, ipfc2.fwn_label);		if (setsockopt(fw_sock, IPPROTO_IP, IP_FW_DELETE_NUM, &ipfwd, sizeof(ipfwd))==-1) {	  fprintf(stderr, "could not remove output firewall rule");	}      }      close(fw_sock);  #else  #endif    }    //fprintf(stderr, "closing _fd\n");    close (_fd);    remove_select(_fd, SELECT_READ);    _fd = -1;  }}voidDivertSocket::selected(int fd) {  struct sockaddr_in sa;  socklen_t fromlen;    WritablePacket *p;  int len;  if (fd != _fd)     return;  fromlen = sizeof(sa);  p  = Packet::make(2, 0, 2046, 0); // YIPAL bufsize  len = recvfrom(_fd, p->data(), p->length(), 0, (sockaddr *)&sa, &fromlen);  if (len > 0) {    // set the timestamp     p->timestamp_anno() = Timestamp::now();    p->change_headroom_and_length(2, len);		     output(0).push(p);  } else {    p->kill();    if (len <= 0 && errno != EAGAIN)      click_chatter("DivertSocket: recvfrom: %s", strerror(errno));  }}voidDivertSocket::send_packet(Packet *p){  int n;  struct sockaddr_in sa;  sa.sin_len = sizeof(sa);  sa.sin_family = AF_INET;  sa.sin_port = htons(_divertport);  memcpy(&sa.sin_addr.s_addr, p->data() + 16, 4);  //printf("address: 0x%x\n", sa.sin_addr.s_addr);  n = sendto(_fd, p->data(), p->length() , 0, 	     (sockaddr *)&sa, sizeof(sa));  //click_chatter("  %i bytes reinjected.", n);  if (n < 0)    click_chatter("DivertSocket: %s", strerror(errno));  p->kill();}voidDivertSocket::push(int, Packet *p){  assert(p->length() >= 20);  send_packet(p);}ELEMENT_REQUIRES(userlevel)EXPORT_ELEMENT(DivertSocket)

⌨️ 快捷键说明

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