收藏的一个linux下proxy实现的源码


收藏的一个linux下proxy实现的源码

/****************************************************************************
program: proxyd
module: proxyd.c
summary: provides proxy tcp service for a host on an isolated network.

programmer: Carl Harris (ceharris@vt.edu)
date: 22 Feb 94

description:
This code implements a daemon process which listens for tcp connec-
tions on a specified port number. When a connection is established,
a child is forked to handle the new client. The child then estab-
lishes a tcp connection to a port on the isolated host. The child
then falls into a loop in which it writes data to the isolated host
for the client and vice-versa. Once a child has been forked, the
parent resumes listening for additional connections.

The name of the isolated host and the port to serve as proxy for,
as well as the port number the server listen on are specified as
command line arguments.
****************************************************************************/

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <sys/resource.h>
#include <sys/wait.h>

#define TCP_PROTO "tcp"

int proxy_port; /* port to listen for proxy connections on */
struct sockaddr_in hostaddr; /* host addr assembled from gethostbyname() */

extern int errno; /* defined by libc.a */
/*extern char *sys_errlist[];  defined by libc.a */


void parse_args (int argc, char **argv);
void daemonize (int servfd);
void do_proxy (int usersockfd);
void reap_status (void);
void errorout (char *msg);

 

/****************************************************************************
function: main
description: Main level driver. After daemonizing the process, a socket
is opened to listen for connections on the proxy port,
connections are accepted and children are spawned to handle
each new connection.
arguments:
argc,argv you know what those are.

return value: none.
calls: parse_args, do_proxy.
globals: reads proxy_port.
****************************************************************************/

main (argc,argv)
int argc;
char **argv;
{
 int clilen;
 int childpid;
 int sockfd, newsockfd;
 struct sockaddr_in servaddr, cliaddr;

 parse_args(argc,argv);

 /* prepare an address struct to listen for connections */
 bzero((char *) &servaddr, sizeof(servaddr));
 servaddr.sin_family = AF_INET;
 servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
 servaddr.sin_port = proxy_port;

 /* get a socket... */
 if ((sockfd = socket(AF_INET,SOCK_STREAM,0)) < 0) {
  fputs("failed to create server socket",stderr);
  exit(1);
 }

 /* ...and bind our address and port to it */
 if (bind(sockfd,(struct sockaddr *) (&servaddr),sizeof(servaddr)) < 0) { 
  fputs("faild to bind server socket to specified port",stderr);
  exit(1);
 }

 /* get ready to accept with at most 5 clients waiting to connect */
 listen(sockfd,5);

 /* turn ourselves into a daemon */
 daemonize(sockfd);

 /* fall into a loop to accept new connections and spawn children */
 while (1) {
 
  /* accept the next connection */
  clilen = sizeof(struct sockaddr_in);
  newsockfd = accept(sockfd, (struct sockaddr *) (&cliaddr), &clilen);  
  if (newsockfd < 0 && errno == EINTR)
  continue; /* a signal might interrupt our accept() call */
  else if (newsockfd < 0)
  /* something quite amiss -- kill the server */
  errorout("failed to accept connection");
  
  /* fork a child to handle this connection */
  if ((childpid = fork()) == 0) {
   close(sockfd);
   do_proxy(newsockfd);
   exit(0);
  }
  
  /* if fork() failed, the connection is silently dropped -- oops! */
  
  close(newsockfd);
 }
}

/****************************************************************************
function: parse_args
description: parse the command line args.
arguments:
argc,argv you know what these are.

return value: none.
calls: none.
globals: writes proxy_port, writes hostaddr.
****************************************************************************/

void parse_args (argc,argv)
int argc;
char **argv;
{
 int i;
 struct hostent *hostp;
 struct servent *servp;
 unsigned long inaddr;
 struct {
  char proxy_port [16];
  char isolated_host [64];
  char service_name [32];
 } pargs;


 if (argc < 4) {
  printf("usage: %s ",argv[0]);
  exit(1);
 }

 strcpy(pargs.proxy_port,argv[1]);
 strcpy(pargs.isolated_host,argv[2]);
 strcpy(pargs.service_name,argv[3]);

 for (i = 0; i < strlen(pargs.proxy_port); i++)
 if (!isdigit(*(pargs.proxy_port + i))) break;

 if (i == strlen(pargs.proxy_port))
  proxy_port = htons(atoi(pargs.proxy_port));
 else {
  printf("%s: invalid proxy port",pargs.proxy_port);
  exit(0);
 }

 bzero(&hostaddr,sizeof(hostaddr));
 hostaddr.sin_family = AF_INET;
 if ((inaddr = inet_addr(pargs.isolated_host)) != INADDR_NONE)
  bcopy(&inaddr,&hostaddr.sin_addr,sizeof(inaddr));
 else if ((hostp = gethostbyname(pargs.isolated_host)) != NULL)
  bcopy(hostp->h_addr,&hostaddr.sin_addr,hostp->h_length);
 else {
  printf("%s: unknown host",pargs.isolated_host);
  exit(1);
 }

 if ((servp = getservbyname(pargs.service_name,TCP_PROTO)) != NULL)
  hostaddr.sin_port = servp->s_port;
 else if (atoi(pargs.service_name) > 0)
  hostaddr.sin_port = htons(atoi(pargs.service_name));
 else {
  printf("%s: invalid/unknown service name or port number",pargs.service_name);
  exit(1);
 }
}

/****************************************************************************
function: daemonize
description: detach the server process from the current context,
creating a pristine, predictable environment in which it
will execute.
arguments:
servfd file descriptor in use by server.

return value: none.
calls: none.
globals: none.
****************************************************************************/

void daemonize (servfd)
int servfd;
{
 int childpid, fd, fdtablesize;

 /* ignore terminal I/O, stop signals */
 signal(SIGTTOU,SIG_IGN);
 signal(SIGTTIN,SIG_IGN);
 signal(SIGTSTP,SIG_IGN);

 /* fork to put us in the background (whether or not the user
 specified '&' on the command line */

 if ((childpid = fork()) < 0) {
  fputs("failed to fork first child",stderr);
  exit(1);
 }
 else if (childpid > 0)
  exit(0); /* terminate parent, continue in child */

 /* dissociate from process group */
 if (setpgrp(0,getpid()) < 0) {
  fputs("failed to become process group leader",stderr);
  exit(1);
 }

 /* lose controlling terminal */
 if ((fd = open("/dev/tty",O_RDWR)) >= 0) {
  ioctl(fd,TIOCNOTTY,NULL);
  close(fd);
 }

 /* close any open file descriptors */
 for (fd = 0, fdtablesize = getdtablesize(); fd < fdtablesize; fd++)
 if (fd != servfd) close(fd);

 /* set working directory to / to allow filesystems to be unmounted */
 chdir("/");

 /* clear the inherited umask */
 umask(0);

 /* setup zombie prevention */
 signal(SIGCLD,reap_status);

}

/****************************************************************************
function: do_proxy
description: does the actual work of virtually connecting a client to
the telnet service on the isolated host.
arguments:
usersockfd socket to which the client is connected.

return value: none.
calls: none.
globals: reads hostaddr.
****************************************************************************/

void do_proxy (usersockfd)
int usersockfd;
{
 int isosockfd;
 fd_set rdfdset;
 int connstat;
 int iolen;
 char buf [2048];

 /* open a socket to connect to the isolated host */
 if ((isosockfd = socket(AF_INET,SOCK_STREAM,0)) < 0)
  errorout("failed to create socket to host");

 /* attempt a connection */
 connstat = connect(isosockfd,(struct sockaddr *) &hostaddr,sizeof(hostaddr));
 switch (connstat) {
  case 0:
   break;
  case ETIMEDOUT:
  case ECONNREFUSED:
  case ENETUNREACH:
   strcpy(buf,sys_errlist[errno]);
  strcat(buf,"");
  write(usersockfd,buf,strlen(buf));
  close(usersockfd);
  exit(1); /* die peacefully if we can't establish a connection */
  break;
 default:
  errorout("failed to connect to host");
 }


 /* now we're connected, serve fall into the data echo loop */
 while (1) {
 /* Select for readability on either of our two sockets */
  FD_ZERO(&rdfdset);
  FD_SET(usersockfd,&rdfdset);
  FD_SET(isosockfd,&rdfdset);
  if (select(FD_SETSIZE,&rdfdset,NULL,NULL,NULL) < 0)
   errorout("select failed");

  /* is the client sending data? */
  if (FD_ISSET(usersockfd,&rdfdset)) {
   if ((iolen = read(usersockfd,buf,sizeof(buf))) <= 0)
   break; /* zero length means the client disconnected */

   write(isosockfd,buf,iolen); /* copy to host -- blocking semantics */
  }

  /* is the host sending data? */
  if (FD_ISSET(isosockfd,&rdfdset)) {
   if ((iolen = read(isosockfd,buf,sizeof(buf))) <= 0)
   break; /* zero length means the host disconnected */

   write(usersockfd,buf,iolen); /* copy to client -- blocking semantics */
  }
 }

 /* we're done with the sockets */
 close(isosockfd);
 close(usersockfd);
}

/****************************************************************************
function: errorout
description: displays an error message on the console and kills the
current process.
arguments:
msg message to be displayed.

return value: none -- does not return.
calls: none.
globals: none.
****************************************************************************/

void errorout (msg)
char *msg;
{
 FILE *console;

 console = fopen("/dev/console","a");
 fprintf(console,"proxyd: %s",msg);
 fclose(console);
 exit(1);
}

/****************************************************************************
function: reap_status
description: handle a SIGCLD signal by reaping the exit status of the
perished child, and discarding it.
arguments: none.
return value: none.
calls: none.
globals: none.
****************************************************************************/

void reap_status ()
{
 int pid;
 union wait status;

 while ((pid = wait3(&status,WNOHANG,NULL)) > 0); /* loop while there are more dead children */
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
首先声明,这段源代码不是我编写的,让我们感谢这位名叫Carl Harris的大虾,是他编写了这段代码并将其散播到网上供大家学习讨论。这段代码虽然只是描述了最简单的proxy操作,但它的确是经典,它不仅清晰地描述了客户机/服务器系统的概念,而且几乎包括了Linux网络编程的方方面面,非常适合Linux网络编程的初学者学习。   这段Proxy程序的用法是这样的,我们可以使用这个proxy登录其它主机的服务端口。假如编译后生成了名为Proxy的可执行文件,那么命令及其参数的描述为:    ./Proxy   其中参数proxy_port是指由我们指定的代理服务器端口。参数remote_host是指我们希望连接的远程主机的主机名,IP地址也同样有效。这个主机名在网络上应该是唯一的,如果您不确定的话,可以在远程主机上使用uname -n命令查看一下。参数service_port是远程主机可提供的服务名,也可直接键入服务对应的端口号。这个命令的相应操作是将代理服务器的proxy_port端口绑定到remote_host的service_port端口。然后我们就可以通过代理服务器的proxy_port端口访问remote_host了。例如一台计算机,网络主机名是legends,IP地址为10.10.8.221,如果在我的计算机上执行:    [root@lee /root]#./proxy 8000 legends telnet   那么我们就可以通过下面这条命令访问legends的telnet端口。 ----------------------------------------------------------------- [root@lee /root]#telnet legends 8000 Trying 10.10.8.221... Connected to legends(10.10.8.221). Escape character is '^]' Red Hat Linux release 6.2(Zoot) Kernel 2.2.14-5.0 on an i686 Login: -----------------------------------------------------------------

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值