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

📄 tun.c

📁 NGN-3G核心部件SGSN的代码实现
💻 C
📖 第 1 页 / 共 2 页
字号:
  if (dstaddr) { /* Set the destination address */
    this->dstaddr.s_addr = dstaddr->s_addr;
    ((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_addr.s_addr = 
      dstaddr->s_addr;
    if (ioctl(fd, SIOCSIFDSTADDR, (caddr_t) &ifr) < 0) {
      sys_err(LOG_ERR, __FILE__, __LINE__, errno,
	      "ioctl(SIOCSIFDSTADDR) failed");
      close(fd);
      return -1; 
    }
  }

  if (netmask) { /* Set the netmask */
    this->netmask.s_addr = netmask->s_addr;
#if defined(__linux__)
    ((struct sockaddr_in *) &ifr.ifr_netmask)->sin_addr.s_addr = 
      netmask->s_addr;

#elif defined(__FreeBSD__) || defined (__APPLE__)
    ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = 
      netmask->s_addr;

#elif defined(__sun__)
    ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = 
      netmask->s_addr;
#else
#error  "Unknown platform!"
#endif

    if (ioctl(fd, SIOCSIFNETMASK, (void *) &ifr) < 0) {
      sys_err(LOG_ERR, __FILE__, __LINE__, errno,
	      "ioctl(SIOCSIFNETMASK) failed");
      close(fd);
      return -1;
    }
  }
  
  close(fd);
  this->addrs++;
  
  /* On linux the route to the interface is set automatically
     on FreeBSD we have to do this manually */

  /* TODO: How does it work on Solaris? */

  tun_sifflags(this, IFF_UP | IFF_RUNNING);

#if defined(__FreeBSD__) || defined (__APPLE__)
  tun_addroute(this, dstaddr, addr, netmask);
  this->routes = 1;
#endif

  return 0;
}

int tun_route(struct tun_t *this,
	      struct in_addr *dst,
	      struct in_addr *gateway,
	      struct in_addr *mask,
	      int delete)
{


  /* TODO: Learn how to set routing table on sun  */

#if defined(__linux__)

  struct rtentry r;
  int fd;

  memset (&r, '\0', sizeof (r));
  r.rt_flags = RTF_UP | RTF_GATEWAY; /* RTF_HOST not set */

  /* Create a channel to the NET kernel. */
  if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
    sys_err(LOG_ERR, __FILE__, __LINE__, errno,
	    "socket() failed");
    return -1;
  }

  r.rt_dst.sa_family     = AF_INET;
  r.rt_gateway.sa_family = AF_INET;
  r.rt_genmask.sa_family = AF_INET;
  ((struct sockaddr_in *) &r.rt_dst)->sin_addr.s_addr = dst->s_addr;
  ((struct sockaddr_in *) &r.rt_gateway)->sin_addr.s_addr = gateway->s_addr;
  ((struct sockaddr_in *) &r.rt_genmask)->sin_addr.s_addr = mask->s_addr;
  
  if (delete) {
    if (ioctl(fd, SIOCDELRT, (void *) &r) < 0) {
      sys_err(LOG_ERR, __FILE__, __LINE__, errno,
	      "ioctl(SIOCDELRT) failed");
      close(fd);
      return -1;
    }
  }
  else {
    if (ioctl(fd, SIOCADDRT, (void *) &r) < 0) {
      sys_err(LOG_ERR, __FILE__, __LINE__, errno,
	      "ioctl(SIOCADDRT) failed");
      close(fd);
      return -1;
    }
  }
  close(fd);
  return 0;
  
#elif defined(__FreeBSD__) || defined (__APPLE__)

struct {
  struct rt_msghdr rt;
  struct sockaddr_in dst;
  struct sockaddr_in gate;
  struct sockaddr_in mask;
} req;

 int fd;
 struct rt_msghdr *rtm;
 
 if((fd = socket(AF_ROUTE, SOCK_RAW, 0)) == -1) {
   sys_err(LOG_ERR, __FILE__, __LINE__, errno,
	   "socket() failed");
   return -1;
 }
 
 memset(&req, 0x00, sizeof(req));
 
 rtm  = &req.rt;
 
 rtm->rtm_msglen = sizeof(req);
 rtm->rtm_version = RTM_VERSION;
 if (delete) {
   rtm->rtm_type = RTM_DELETE;
 }
 else {
   rtm->rtm_type = RTM_ADD;
 }
 rtm->rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;  /* TODO */
 rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
 rtm->rtm_pid = getpid();      
 rtm->rtm_seq = 0044;                                 /* TODO */
 
 req.dst.sin_family       = AF_INET;
 req.dst.sin_len          = sizeof(req.dst);
 req.mask.sin_family      = AF_INET;
 req.mask.sin_len         = sizeof(req.mask);
 req.gate.sin_family      = AF_INET;
 req.gate.sin_len         = sizeof(req.gate);

 req.dst.sin_addr.s_addr  = dst->s_addr;
 req.mask.sin_addr.s_addr = mask->s_addr;
 req.gate.sin_addr.s_addr = gateway->s_addr;
 
 if(write(fd, rtm, rtm->rtm_msglen) < 0) {
   sys_err(LOG_ERR, __FILE__, __LINE__, errno,
	   "write() failed");
   close(fd);
   return -1;
 }
 close(fd);
 return 0;

#elif defined(__sun__)
 sys_err(LOG_WARNING, __FILE__, __LINE__, errno,
	 "Could not set up routing on Solaris. Please add route manually.");
 return 0;
 
#else
#error  "Unknown platform!"
#endif

}

int tun_addroute(struct tun_t *this,
		 struct in_addr *dst,
		 struct in_addr *gateway,
		 struct in_addr *mask)
{
  return tun_route(this, dst, gateway, mask, 0);
}

int tun_delroute(struct tun_t *this,
		 struct in_addr *dst,
		 struct in_addr *gateway,
		 struct in_addr *mask)
{
  return tun_route(this, dst, gateway, mask, 1);
}


int tun_new(struct tun_t **tun)
{

#if defined(__linux__)
  struct ifreq ifr;

#elif defined(__FreeBSD__) || defined (__APPLE__)
  char devname[IFNAMSIZ+5]; /* "/dev/" + ifname */
  int devnum;
  struct ifaliasreq areq;
  int fd;

#elif defined(__sun__)
  int if_fd, ppa = -1;
  static int ip_fd = 0;
  int muxid;
  struct ifreq ifr;

#else
#error  "Unknown platform!"
#endif
  
  if (!(*tun = calloc(1, sizeof(struct tun_t)))) {
    sys_err(LOG_ERR, __FILE__, __LINE__, errno, "calloc() failed");
    return EOF;
  }
  
  (*tun)->cb_ind = NULL;
  (*tun)->addrs = 0;
  (*tun)->routes = 0;
  
#if defined(__linux__)
  /* Open the actual tun device */
  if (((*tun)->fd  = open("/dev/net/tun", O_RDWR)) < 0) {
    sys_err(LOG_ERR, __FILE__, __LINE__, errno, "open() failed");
    return -1;
  }
  
  /* Set device flags. For some weird reason this is also the method
     used to obtain the network interface name */
  memset(&ifr, 0, sizeof(ifr));
  ifr.ifr_flags = IFF_TUN | IFF_NO_PI; /* Tun device, no packet info */
  if (ioctl((*tun)->fd, TUNSETIFF, (void *) &ifr) < 0) {
    sys_err(LOG_ERR, __FILE__, __LINE__, errno, "ioctl() failed");
    close((*tun)->fd);
    return -1;
  } 
  
  strncpy((*tun)->devname, ifr.ifr_name, IFNAMSIZ);
  (*tun)->devname[IFNAMSIZ] = 0;
  
  ioctl((*tun)->fd, TUNSETNOCSUM, 1); /* Disable checksums */
  return 0;
  
#elif defined(__FreeBSD__) || defined (__APPLE__)

  /* Find suitable device */
  for (devnum = 0; devnum < 255; devnum++) { /* TODO 255 */ 
    snprintf(devname, sizeof(devname), "/dev/tun%d", devnum);
    devname[sizeof(devname)] = 0;
    if (((*tun)->fd = open(devname, O_RDWR)) >= 0) break;
    if (errno != EBUSY) break;
  } 
  if ((*tun)->fd < 0) {
    sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't find tunnel device");
    return -1;
  }

  snprintf((*tun)->devname, sizeof((*tun)->devname), "tun%d", devnum);
  (*tun)->devname[sizeof((*tun)->devname)] = 0;

  /* The tun device we found might have "old" IP addresses allocated */
  /* We need to delete those. This problem is not present on Linux */

  memset(&areq, 0, sizeof(areq));

  /* Set up interface name */
  strncpy(areq.ifra_name, (*tun)->devname, IFNAMSIZ);
  areq.ifra_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */

  /* Create a channel to the NET kernel. */
  if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
    sys_err(LOG_ERR, __FILE__, __LINE__, errno,
	    "socket() failed");
    return -1;
  }
  
  /* Delete any IP addresses until SIOCDIFADDR fails */
  while (ioctl(fd, SIOCDIFADDR, (void *) &areq) != -1);

  close(fd);
  return 0;

#elif defined(__sun__)

  if( (ip_fd = open("/dev/udp", O_RDWR, 0)) < 0){
    sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't open /dev/udp");
    return -1;
  }
  
  if( ((*tun)->fd = open("/dev/tun", O_RDWR, 0)) < 0){
    sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't open /dev/tun");
    return -1;
  }
  
  /* Assign a new PPA and get its unit number. */
  if( (ppa = ioctl((*tun)->fd, TUNNEWPPA, -1)) < 0){
    sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't assign new interface");
    return -1;
  }
  
  if( (if_fd = open("/dev/tun", O_RDWR, 0)) < 0){
    sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't open /dev/tun (2)");
    return -1;
  }
  if(ioctl(if_fd, I_PUSH, "ip") < 0){
    sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't push IP module");
    return -1;
  }
  
  /* Assign ppa according to the unit number returned by tun device */
  if(ioctl(if_fd, IF_UNITSEL, (char *)&ppa) < 0){
    sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't set PPA %d", ppa);
    return -1;
  }

  /* Link the two streams */
  if ((muxid = ioctl(ip_fd, I_LINK, if_fd)) < 0) {
    sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't link TUN device to IP");
    return -1;
  }

  close (if_fd);
  
  snprintf((*tun)->devname, sizeof((*tun)->devname), "tun%d", ppa);
  (*tun)->devname[sizeof((*tun)->devname)] = 0;

  memset(&ifr, 0, sizeof(ifr));
  strcpy(ifr.ifr_name, (*tun)->devname);
  ifr.ifr_ip_muxid = muxid;
  
  if (ioctl(ip_fd, SIOCSIFMUXID, &ifr) < 0) {
    ioctl(ip_fd, I_PUNLINK, muxid);
    sys_err(LOG_ERR, __FILE__, __LINE__, errno, "Can't set multiplexor id");
    return -1;
  }
  
  /*  if (fcntl (fd, F_SETFL, O_NONBLOCK) < 0)
      msg (M_ERR, "Set file descriptor to non-blocking failed"); */

  return 0;

#else
#error  "Unknown platform!"
#endif

}

int tun_free(struct tun_t *tun)
{

  if (tun->routes) {
    tun_delroute(tun, &tun->dstaddr, &tun->addr, &tun->netmask);
  }

  if (close(tun->fd)) {
    sys_err(LOG_ERR, __FILE__, __LINE__, errno, "close() failed");
  }

  /* TODO: For solaris we need to unlink streams */

  free(tun);
  return 0;
}


int tun_set_cb_ind(struct tun_t *this, 
  int (*cb_ind) (struct tun_t *tun, void *pack, unsigned len)) {
  this->cb_ind = cb_ind;
  return 0;
}


int tun_decaps(struct tun_t *this)
{

#if defined(__linux__) || defined (__FreeBSD__) || defined (__APPLE__)

  unsigned char buffer[PACKET_MAX];
  int status;
  
  if ((status = read(this->fd, buffer, sizeof(buffer))) <= 0) {
    sys_err(LOG_ERR, __FILE__, __LINE__, errno, "read() failed");
    return -1;
  }
  
  if (this->cb_ind)
    return this->cb_ind(this, buffer, status);

  return 0;

#elif defined (__sun__)

  unsigned char buffer[PACKET_MAX];
  struct strbuf sbuf;
  int f = 0;
  
  sbuf.maxlen = PACKET_MAX;      
  sbuf.buf = buffer;
  if (getmsg(this->fd, NULL, &sbuf, &f) < 0) {
    sys_err(LOG_ERR, __FILE__, __LINE__, errno, "getmsg() failed");
    return -1;
  }

  if (this->cb_ind)
    return this->cb_ind(this, buffer, sbuf.len);

  return 0;
  
#endif

}


int tun_encaps(struct tun_t *tun, void *pack, unsigned len)
{

#if defined(__linux__) || defined (__FreeBSD__) || defined (__APPLE__)

  return write(tun->fd, pack, len);

#elif defined (__sun__)

  struct strbuf sbuf;
  sbuf.len = len;      
  sbuf.buf = pack;
  return putmsg(tun->fd, NULL, &sbuf, 0);

#endif
}

int tun_runscript(struct tun_t *tun, char* script) {
  
  char buf[TUN_SCRIPTSIZE];
  char snet[TUN_ADDRSIZE];
  char smask[TUN_ADDRSIZE];

  strncpy(snet, inet_ntoa(tun->addr), sizeof(snet));
  snet[sizeof(snet)-1] = 0;
  strncpy(smask, inet_ntoa(tun->netmask), sizeof(smask));
  smask[sizeof(smask)-1] = 0;
  
  /* system("ipup /dev/tun0 192.168.0.10 255.255.255.0"); */
  snprintf(buf, sizeof(buf), "%s %s %s %s",
	   script, tun->devname, snet, smask);
  buf[sizeof(buf)-1] = 0;
  system(buf);
  return 0;
}

⌨️ 快捷键说明

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