socks-private.c

来自「GNet是一个简单的网络库。它是目标定向的」· C语言 代码 · 共 468 行

C
468
字号
/* GNet - Networking library * Copyright (C) 2001-2002  Marius Eriksen, David Helder * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA  02111-1307, USA. */#include "gnet-private.h"#include "socks.h"#include "socks-private.h"static int socks_get_version (void);/* **************************************** */static intsocks_get_version (void){  const gchar* verc;  if ((verc = g_getenv("SOCKS_VERSION")))     return atoi(verc);  return GNET_DEFAULT_SOCKS_VERSION;}/* **************************************** */static int socks_negotiate_connect (GTcpSocket *s, const GInetAddr *dst);static int socks4_negotiate_connect (GIOChannel *ioc, const GInetAddr *dst);static int socks5_negotiate_connect (GIOChannel *ioc, const GInetAddr *dst);GTcpSocket* gnet_private_socks_tcp_socket_new (const GInetAddr* addr){  GInetAddr* 		ss_addr = NULL;  GTcpSocket* 		s;  int			rv;  g_return_val_if_fail (addr != NULL, NULL);  /* Get SOCKS server */  ss_addr = gnet_socks_get_server();  if (!ss_addr)    return NULL;    /* Connect to SOCKS server */  s = gnet_tcp_socket_new_direct (ss_addr);  gnet_inetaddr_delete (ss_addr);  if (!s)    return NULL;  /* Negotiate connection */  rv = socks_negotiate_connect (s, addr);  if (rv < 0)    {      gnet_tcp_socket_delete (s);      return NULL;    }  return s;}/* **************************************** */struct async_data{  GInetAddr* addr;  GTcpSocketNewAsyncFunc func;  gpointer data;};static void async_cb (GTcpSocket* socket, GTcpSocketNewAsyncStatus status, gpointer data);GTcpSocketNewAsyncIDgnet_private_socks_tcp_socket_new_async (const GInetAddr* addr, 					 GTcpSocketNewAsyncFunc func,					 gpointer data){  GTcpSocket* 		s;  GInetAddr* 		ss_addr = NULL;  struct async_data*	ad;  g_return_val_if_fail(addr != NULL, NULL);  g_return_val_if_fail(func != NULL, NULL);  /* Get SOCKS server */  ss_addr = gnet_socks_get_server();  if (!ss_addr)    return NULL;  /* Create data */  ad = g_new0(struct async_data, 1);  ad->addr = gnet_inetaddr_clone(addr);  ad->func = func;  ad->data = data;  /* Connect to SOCKS server */  s = gnet_tcp_socket_new_async_direct (ss_addr, async_cb, ad);  gnet_inetaddr_delete (ss_addr);  return s;  /* s might be NULL */}static voidasync_cb (GTcpSocket* socket, GTcpSocketNewAsyncStatus status, gpointer data){  struct async_data* ad = (struct async_data*) data;    if (status == GTCP_SOCKET_NEW_ASYNC_STATUS_OK)    {      int rv;      rv = socks_negotiate_connect (socket, ad->addr);      if (rv < 0)	goto error;      (ad->func)(socket, GTCP_SOCKET_NEW_ASYNC_STATUS_OK, ad->data);      gnet_inetaddr_delete (ad->addr);      g_free (ad);      return;    } error:  (ad->func)(NULL, GTCP_SOCKET_NEW_ASYNC_STATUS_ERROR, ad->data);  gnet_inetaddr_delete (ad->addr);  g_free (ad);}/* **************************************** */static intsocks_negotiate_connect (GTcpSocket *s, const GInetAddr *dst){  GIOChannel *ioc;  int ver, ret;  ioc = gnet_tcp_socket_get_iochannel(s);  ver = socks_get_version();  if (ver == 5)    ret = socks5_negotiate_connect (ioc, dst);  else if (ver == 4)    ret = socks4_negotiate_connect (ioc, dst);  else    ret = -1;  g_io_channel_unref(ioc);  return ret;}static intsocks4_negotiate_connect (GIOChannel *ioc, const GInetAddr *dst){  struct socks4_h s4h;  struct sockaddr_in *sa_in;  int len;  sa_in = (struct sockaddr_in*)&dst->sa;  s4h.vn = 4;  s4h.cd = 1;  s4h.dport = (short)sa_in->sin_port;  s4h.dip = (long)sa_in->sin_addr.s_addr;  s4h.userid = 0;  if (gnet_io_channel_writen(ioc, &s4h, 9, &len) != G_IO_ERROR_NONE)    return -1;  if (gnet_io_channel_readn(ioc, &s4h, 8, &len) != G_IO_ERROR_NONE)    return -1;  if ((s4h.cd != 90) || (s4h.vn != 0))    return -1;  return 0;}static intsocks5_negotiate_connect (GIOChannel *ioc, const GInetAddr *dst){  unsigned char s5r[3];  struct socks5_h s5h;  struct sockaddr_in *sa_in;  int len;  s5r[0] = 5;  s5r[1] = 1;	/* XXX no authentication yet */  s5r[2] = 0;	  if (gnet_io_channel_writen(ioc, s5r, 3, &len) != G_IO_ERROR_NONE)    return -1;  if (gnet_io_channel_readn(ioc, s5r, 2, &len) != G_IO_ERROR_NONE)    return -1;  if ((s5r[0] != 5) || (s5r[1] != 0))    return -1;	  sa_in = (struct sockaddr_in*)&dst->sa;  /* fill in SOCKS5 request */  s5h.vn = 5;  s5h.cd = 1;  s5h.rsv = 0;  s5h.atyp = 1;  s5h.dip = (long)sa_in->sin_addr.s_addr;   s5h.dport = (short)sa_in->sin_port;  if (gnet_io_channel_writen(ioc, (gchar*)&s5h, 10, &len) != G_IO_ERROR_NONE)    return -1;  if (gnet_io_channel_readn(ioc, (gchar*)&s5h, 10, &len) != G_IO_ERROR_NONE)    return -1;  if (s5h.cd != 0)    return -1;  return 0;}/* **************************************** */static int socks5_negotiate_bind (GTcpSocket* socket, int port);static gboolean socks_tcp_socket_server_accept_async_cb (GIOChannel* iochannel, 							 GIOCondition condition, 							 gpointer data);GTcpSocket*gnet_private_socks_tcp_socket_server_new (gint port){  GInetAddr* 		ss_addr = NULL;  GTcpSocket* 		s;  int			rv;  /* We only support SOCKS 5 */  if (socks_get_version () != 5)    return NULL;  /* Get SOCKS server */  ss_addr = gnet_socks_get_server();  if (!ss_addr)    return NULL;  /* Connect to SOCKS server */  s = gnet_tcp_socket_new_direct (ss_addr);  gnet_inetaddr_delete (ss_addr);  if (!s)    return NULL;  /* Negotiate connection */  rv = socks5_negotiate_bind (s, port);  if (rv < 0)    {      gnet_tcp_socket_delete (s);      return NULL;    }  return s;}static intsocks5_negotiate_bind (GTcpSocket* socket, int port){  GIOChannel *ioc;  unsigned char s5r[3];  struct socks5_h s5h;  int len;  ioc = gnet_tcp_socket_get_iochannel(socket);  s5r[0] = 5;  s5r[1] = 1;	/* no authentication */  s5r[2] = 0;	  if (gnet_io_channel_writen(ioc, s5r, 3, &len) != G_IO_ERROR_NONE)    goto error;  if (gnet_io_channel_readn(ioc, s5r, 2, &len) != G_IO_ERROR_NONE)    goto error;  if ((s5r[0] != 5) || (s5r[1] != 0))    goto error;	  /* fill in SOCKS5 request */  s5h.vn = 5;  s5h.cd = 2;  /* bind */  s5h.rsv = 0;  s5h.atyp = 1;  s5h.dip = 0; /* FIX: this works with nylon; i will check on rfc */  s5h.dport = g_htons(port);     if (gnet_io_channel_writen(ioc, (gchar*)&s5h, 10, &len) != G_IO_ERROR_NONE)    goto error;  /* this reply simply confirms */  if (gnet_io_channel_readn(ioc, (gchar*)&s5h, 10, &len) != G_IO_ERROR_NONE)    goto error;  /* make sure we have a connection */  if (s5h.cd != 0)    goto error;  /* Copy the address */  GNET_SOCKADDR_IN(socket->sa).sin_addr.s_addr = s5h.dip;  GNET_SOCKADDR_IN(socket->sa).sin_port = s5h.dport;  return 0; error:  g_io_channel_unref(ioc);  return -1;}/* XXX 0 server SOCKS compliant? */ GTcpSocket*gnet_private_socks_tcp_socket_server_accept (GTcpSocket* socket){  gint server_port;  struct socks5_h s5h;  int len;  GIOChannel* iochannel;  GIOError error;  GTcpSocket* s;  GTcpSocket* new_socket;  g_return_val_if_fail (socket, NULL);  /* Save server port */  server_port = g_ntohs(GNET_SOCKADDR_IN(socket->sa).sin_port);  /* this reply reveals the connecting hosts ip and port */  iochannel = gnet_tcp_socket_get_iochannel(socket);  error = gnet_io_channel_readn(iochannel, (gchar*) &s5h, 10, &len);  g_io_channel_unref (iochannel);  if (error != G_IO_ERROR_NONE)    return NULL;  /* The client socket is the server socket */  s = g_new0(GTcpSocket, 1);  s->sockfd = socket->sockfd;  GNET_SOCKADDR_IN(s->sa).sin_addr.s_addr = s5h.dip;  GNET_SOCKADDR_IN(s->sa).sin_port = s5h.dport;  s->ref_count = 1;  /* Create a new server socket (we just use the sockfd) */  new_socket = gnet_private_socks_tcp_socket_server_new (server_port);  if (new_socket == NULL)    {      g_free (s); /* ok, we copied sockfd */      return NULL;    }    /* Copy the fd over and delete the new socket */  socket->sockfd = new_socket->sockfd;  g_free (new_socket); /* ok, we copied sockfd */  /* Hand over IOChannel */  if (socket->accept_watch)    {      g_source_remove (socket->accept_watch);      socket->accept_watch = 0;    }  s->iochannel = socket->iochannel;  socket->iochannel = NULL;  /* Reset the async watch if necessary */  if (socket->accept_func)    {      GIOChannel* iochannel;      /* This will recreate the IOChannel */      iochannel = gnet_tcp_socket_get_iochannel (socket);      /* Set the watch on the new IO channel */      socket->accept_watch = g_io_add_watch(iochannel, 					    G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, 					    socks_tcp_socket_server_accept_async_cb, socket);      g_io_channel_unref (iochannel);    }  return s;}voidgnet_private_socks_tcp_socket_server_accept_async (GTcpSocket* socket, 						   GTcpSocketAcceptFunc accept_func, 						   gpointer user_data){  GIOChannel* iochannel;  g_return_if_fail (socket);  g_return_if_fail (accept_func);  g_return_if_fail (!socket->accept_func);  /* Save callback */  socket->accept_func = accept_func;  socket->accept_data = user_data;  /* Add read watch */  iochannel = gnet_tcp_socket_get_iochannel (socket);  socket->accept_watch = g_io_add_watch(iochannel, 					G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, 					socks_tcp_socket_server_accept_async_cb, socket);  g_io_channel_unref (iochannel);}static gbooleansocks_tcp_socket_server_accept_async_cb (GIOChannel* iochannel, GIOCondition condition, 					 gpointer data){  GTcpSocket* server = (GTcpSocket*) data;  g_assert (server);  if (condition & G_IO_IN)    {      GTcpSocket* client;      client = gnet_private_socks_tcp_socket_server_accept (server);      if (!client) 	return TRUE;      (server->accept_func)(server, client, server->accept_data);      return FALSE;    }  else /* error */    {      gnet_tcp_socket_ref (server);      (server->accept_func)(server, NULL, server->accept_data);      server->accept_watch = 0;      server->accept_func = NULL;      server->accept_data = NULL;      gnet_tcp_socket_unref (server);      return FALSE;    }  return FALSE;}

⌨️ 快捷键说明

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