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

📄 tunnel.c

📁 穿越防火墙技术代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/*tunnel.cCopyright (C) 1999, 2000 Lars Brinkhoff.  See COPYING for terms and conditions.See tunnel.h for some documentation about the programming interface.*/#include <time.h>#include <stdio.h>#include <netdb_.h>#include <fcntl.h>#include <stdlib.h>#include <sys/poll_.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/tcp.h>#include "http.h"#include "tunnel.h"#include "common.h"/* #define IO_COUNT_HTTP_HEADER *//* #define USE_SHUTDOWN */#define READ_TRAIL_TIMEOUT (1 * 1000) /* milliseconds */#define ACCEPT_TIMEOUT 10 /* seconds */#define min(a, b) ((a) < (b) ? (a) : (b))#define TUNNEL_IN 1#define TUNNEL_OUT 2#if SIZEOF_CHAR == 1typedef unsigned char Request;#else#error "FIXME: Can't handle SIZEOF_CHAR != 1"#endif#if SIZEOF_SHORT == 2typedef unsigned short Length;#else#error "FIXME: Can't handle SIZEOF_SHORT != 2"#endifenum tunnel_request{  TUNNEL_SIMPLE = 0x40,  TUNNEL_OPEN = 0x01,  TUNNEL_DATA = 0x02,  TUNNEL_PADDING = 0x03,  TUNNEL_ERROR = 0x04,  TUNNEL_PAD1 = TUNNEL_SIMPLE | 0x05,  TUNNEL_CLOSE = TUNNEL_SIMPLE | 0x06,  TUNNEL_DISCONNECT = TUNNEL_SIMPLE | 0x07};static inline const char *REQ_TO_STRING (Request request){  switch (request)    {    case TUNNEL_OPEN:		return "TUNNEL_OPEN";    case TUNNEL_DATA:		return "TUNNEL_DATA";    case TUNNEL_PADDING:	return "TUNNEL_PADDING";    case TUNNEL_ERROR:		return "TUNNEL_ERROR";    case TUNNEL_PAD1:		return "TUNNEL_PAD1";    case TUNNEL_CLOSE:		return "TUNNEL_CLOSE";    case TUNNEL_DISCONNECT:	return "TUNNEL_DISCONNECT";    default:			return "(unknown)";    }}struct tunnel{  int in_fd, out_fd;  int server_socket;  Http_destination dest;  struct sockaddr_in address;  size_t bytes;  size_t content_length;  char buf[65536];  char *buf_ptr;  size_t buf_len;  int padding_only;  size_t in_total_raw;  size_t in_total_data;  size_t out_total_raw;  size_t out_total_data;  time_t out_connect_time;  int strict_content_length;  int keep_alive;  int max_connection_age;};static const size_t sizeof_header = sizeof (Request) + sizeof (Length);static inline inttunnel_is_disconnected (Tunnel *tunnel){  return tunnel->out_fd == -1;}static inline inttunnel_is_connected (Tunnel *tunnel){  return !tunnel_is_disconnected (tunnel);}static inline inttunnel_is_server (Tunnel *tunnel){  return tunnel->dest.host_name == NULL;}static inline inttunnel_is_client (Tunnel *tunnel){  return !tunnel_is_server (tunnel);}#if 1static intget_proto_number (const char *name){  struct protoent *p;  int number;  p = getprotobyname (name);  if (p == NULL)    number = -1;  else    number = p->p_proto;  endprotoent ();  return number;}#endifstatic inttunnel_in_setsockopts (int fd){#ifdef SO_RCVLOWAT  int tcp = get_proto_number ("tcp");  if (tcp != -1)    {      int i, n;      i = 1;      if (setsockopt (fd,		      tcp,		      SO_RCVLOWAT,		      (void *)&i,		      sizeof i) == -1)	{	  log_debug ("tunnel_in_setsockopts: non-fatal SO_RCVLOWAT error: %s",		     strerror (errno));	}      n = sizeof i;      getsockopt (fd,		  tcp,		  SO_RCVLOWAT,		  (void *)&i,		  &n);      log_debug ("tunnel_out_setsockopts: SO_RCVLOWAT: %d", i);    }#endif /* SO_RCVLOWAT */  return 0;}static inttunnel_out_setsockopts (int fd){#ifdef SO_SNDLOWAT  {    int tcp = get_proto_number ("tcp");    int i, n;     if (tcp != -1)      {	i = 1;	if (setsockopt (fd,			tcp,			SO_SNDLOWAT,			(void *)&i,			sizeof i) == -1)	  {	    log_debug ("tunnel_out_setsockopts: "		       "non-fatal SO_SNDLOWAT error: %s",		       strerror (errno));	  }	n = sizeof i;	getsockopt (fd,		    tcp,		    SO_SNDLOWAT,		    (void *)&i,		    &n);	log_debug ("tunnel_out_setsockopts: non-fatal SO_SNDLOWAT: %d", i);      }  }#endif /* SO_SNDLOWAT */#ifdef SO_LINGER  {    struct linger l;    int n;    l.l_onoff = 1;    l.l_linger = 20 * 100; /* linger for 20 seconds */    if (setsockopt (fd,		    SOL_SOCKET,		    SO_LINGER,		    (void *)&l,		    sizeof l) == -1)      {	log_debug ("tunnel_out_setsockopts: non-fatal SO_LINGER error: %s",		   strerror (errno));      }    n = sizeof l;    getsockopt (fd,		SOL_SOCKET,		SO_LINGER,		(void *)&l,		&n);    log_debug ("tunnel_out_setsockopts: SO_LINGER: onoff=%d linger=%d",	       l.l_onoff, l.l_linger);  }#endif /* SO_LINGER */#ifdef TCP_NODELAY  {    int tcp = get_proto_number ("tcp");    int i, n;     if (tcp != -1)      {	i = 1;	if (setsockopt (fd,			tcp,			TCP_NODELAY,			(void *)&i,			sizeof i) == -1)	  {	    log_debug ("tunnel_out_setsockopts: "		       "non-fatal TCP_NODELAY error: %s",		       strerror (errno));	  }	n = sizeof i;	getsockopt (fd,		    tcp,		    TCP_NODELAY,		    (void *)&i,		    &n);	log_debug ("tunnel_out_setsockopts: non-fatal TCP_NODELAY: %d", i);      }  }#else#ifdef SO_SNDBUF  {    int i, n;    i = 0;    if (setsockopt (fd,		    SOL_SOCKET,		    SO_SNDBUF,		    (void *)&i,		    sizeof i) == -1)      {	log_debug ("tunnel_out_setsockopts: non-fatal SO_SNDBUF error: %s",		   strerror (errno));      }    n = sizeof i;    getsockopt (fd,		SOL_SOCKET,		SO_SNDBUF,		(void *)&i,		&n);    log_debug ("tunnel_out_setsockopts: SO_SNDBUF: %d", i);  }#endif /* SO_SNDBUF */#endif /* TCP_NODELAY */#ifdef SO_KEEPALIVE  {    int i, n;    i = 1;    if (setsockopt (fd,		    SOL_SOCKET,		    SO_KEEPALIVE,		    (void *)&i,		    sizeof i) == -1)      {	log_debug ("tunnel_out_setsockopts: non-fatal SO_KEEPALIVE error: %s",		   strerror (errno));      }    n = sizeof i;    getsockopt (fd,		SOL_SOCKET,		SO_KEEPALIVE,		(void *)&i,		&n);    log_debug ("tunnel_out_setsockopts: SO_KEEPALIVE: %d", i);  }#endif /* SO_KEEPALIVE */  return 0;}static voidtunnel_out_disconnect (Tunnel *tunnel){  if (tunnel_is_disconnected (tunnel))    return;#ifdef DEBUG_MODE  if (tunnel_is_client (tunnel) &&      tunnel->bytes != tunnel->content_length + 1)    log_error ("tunnel_out_disconnect: warning: "	       "bytes=%d != content_length=%d",	       tunnel->bytes, tunnel->content_length + 1);#endif  close (tunnel->out_fd);  tunnel->out_fd = -1;  tunnel->bytes = 0;  tunnel->buf_ptr = tunnel->buf;  tunnel->buf_len = 0;  log_debug ("tunnel_out_disconnect: output disconnected");}static voidtunnel_in_disconnect (Tunnel *tunnel){  if (tunnel->in_fd == -1)    return;  close (tunnel->in_fd);  tunnel->in_fd = -1;  log_debug ("tunnel_in_disconnect: input disconnected");}static inttunnel_out_connect (Tunnel *tunnel){  ssize_t n;  if (tunnel_is_connected (tunnel))    {      log_debug ("tunnel_out_connect: already connected");      tunnel_out_disconnect (tunnel);    }  tunnel->out_fd = do_connect (&tunnel->address);  if (tunnel->out_fd == -1)    {      log_error ("tunnel_out_connect: do_connect(%d.%d.%d.%d) error: %s",		  tunnel->address.sin_addr.s_addr >> 24,		 (tunnel->address.sin_addr.s_addr >> 16) & 0xff,		 (tunnel->address.sin_addr.s_addr >>  8) & 0xff,		  tunnel->address.sin_addr.s_addr        & 0xff,		 strerror (errno));      return -1;    }  tunnel_out_setsockopts (tunnel->out_fd);#ifdef USE_SHUTDOWN  shutdown (tunnel->out_fd, 0);#endif  /* + 1 to allow for TUNNEL_DISCONNECT */  n = http_post (tunnel->out_fd,		 &tunnel->dest,		 tunnel->content_length + 1);  if (n == -1)    return -1;#ifdef IO_COUNT_HTTP_HEADER  tunnel->out_total_raw += n;  log_annoying ("tunnel_out_connect: out_total_raw = %u",		tunnel->out_total_raw);#endif  tunnel->bytes = 0;  tunnel->buf_ptr = tunnel->buf;  tunnel->buf_len = 0;  tunnel->padding_only = TRUE;  time (&tunnel->out_connect_time);  log_debug ("tunnel_out_connect: output connected");  return 0;}static inttunnel_in_connect (Tunnel *tunnel){  Http_response *response;  ssize_t n;  log_verbose ("tunnel_in_connect()");  if (tunnel->in_fd != -1)    {      log_error ("tunnel_in_connect: already connected");      return -1;    }  tunnel->in_fd = do_connect (&tunnel->address);  if (tunnel->in_fd == -1)    {      log_error ("tunnel_in_connect: do_connect() error: %s",		 strerror (errno));      return -1;    }  tunnel_in_setsockopts (tunnel->in_fd);  if (http_get (tunnel->in_fd, &tunnel->dest) == -1)    return -1;#ifdef USE_SHUTDOWN  if (shutdown (tunnel->in_fd, 1) == -1)    {      log_error ("tunnel_in_connect: shutdown() error: %s",		 strerror (errno));      return -1;    }#endif  n = http_parse_response (tunnel->in_fd, &response);  if (n <= 0)    {      if (n == 0)	log_error ("tunnel_in_connect: no response; peer "		   "closed connection");      else	log_error ("tunnel_in_connect: no response; error: %s",		   strerror (errno));    }  else if (response->major_version != 1 ||	   (response->minor_version != 1 &&	    response->minor_version != 0))    {      log_error ("tunnel_in_connect: unknown HTTP version: %d.%d",		 response->major_version, response->minor_version);      n = -1;    }  else if (response->status_code != 200)    {      log_error ("tunnel_in_connect: HTTP error %d", response->status_code);      errno = http_error_to_errno (-response->status_code);      n = -1;    }  http_destroy_response (response);  if (n > 0)    {#ifdef IO_COUNT_HTTP_HEADER      tunnel->in_total_raw += n;      log_annoying ("tunnel_in_connect: in_total_raw = %u",		    tunnel->in_total_raw);#endif    }  else    {      return n;    }  log_debug ("tunnel_in_connect: input connected");  return 1;}static inline ssize_t

⌨️ 快捷键说明

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