一个简易的proxy程序的开发过程(2)

    技术2022-05-11  39

    简易Proxy程序(源代码)

    上次贴出了一篇<<一个简易的proxy程序的开发过程(1)>>和<<一个简易的UDP Proxy程序>>之后,有不少网友来信询问下文何时出现。我却一直忙于工作,忘记了将下文贴上来,非常抱歉。现在在这里把源代码贴出来。我 申明这个源代码基于GNU GPL,目的在于希望大家能够有时间去更加完善它。你也可以按照你自己的希望去改变它。不过,如果你做了任何大的改动,请通知我< ariesram@may10.ca>.

    TODO:

    1、使程序能够监听多个端口,并且连接多个远程服务。

    2、使程序能够从配置文件中读取设定监听端口和所要连接的远程服务地址以及端口以满足多种服务并存

    的需要。

    sp.c

    /*******************************************************************************

    This program is free software; you can redistribute it and/or modify

    it under the terms of the GNU General Public License as published by

    the Free Software Foundation; either version 2 of the License, or

    (at your option) any later version.

    This program 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 General Public License for more details.

    You should have received a copy of the GNU General Public License

    along with this program; if not, write to the Free Software

    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

    *******************************************************************************/

    /*******************************************************************************

    Program: sp.c

    Description: a smart proxy

    Author: Alan Chen (ariesram@may10.ca)

    Date: July 18, 2001

    *******************************************************************************/

    #include <stdio.h>

    #include <string.h>

    #include <sys/types.h>

    #include <sys/socket.h>

    #include <sys/time.h>

    #include <sys/wait.h>

    #include <unistd.h>

    #include <netinet/in.h>

    #define ERRLOG "./sp.log"

    int do_proxy(int infd, char* addr, int port);

    int max(int i, int j);

    void waitchild(int);

    void version();

    void usage();

    void daemonize();

    void p_error(const char * err_msg);

    int main(int argc, char** argv) {

    struct sockaddr_in servaddr, clientaddr;

    int listenfd, connfd;

    int clientlen;

    pid_t chpid;

    int service_port = 0, remote_port = 0;

    char remote_addr[17];

    const char optstring[] = "s:r:p:vh";

    int opt;

    extern char *optarg;

    extern int optind, opterr, optopt;

    extern FILE *stderr;

    memset(remote_addr, 0, 17);

    if( argc == 2 ) {

    while( (opt = getopt(argc, argv, optstring)) != -1 ) {

    if( opt == 'v' ) {

    version();

    exit(0);

    }

    else if ( opt == 'h' ) {

    usage();

    exit(0);

    }

    else {

    printf("type sp -h for help message

    ");

    usage();

    exit(0);

    }

    }

    }

    else {

    while( (opt = getopt(argc, argv, optstring)) != -1 ) {

    switch(opt) {

    case 's':

    service_port = atoi(optarg);

    break;

    case 'r':

    memcpy(remote_addr, optarg, strlen(optarg));

    remote_addr[strlen(remote_addr)] = '';

    break;

    case 'p':

    remote_port = atoi(optarg);

    break;

    default:

    usage();

    exit(0);

    }

    }

    }

    if( service_port == 0' 'remote_port == 0' 'remote_addr[0] == '') {

    usage();

    exit(0);

    }

    daemonize();

    bzero(&servaddr, sizeof(servaddr));

    servaddr.sin_family = AF_INET;

    servaddr.sin_port = htons(service_port);

    servaddr.sin_addr.s_addr = INADDR_ANY;

    listenfd = socket(AF_INET, SOCK_STREAM, 0);

    if(listenfd < 0) {

    p_error("socket error");

    exit(-1);

    }

    if( bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0 ) {

    p_error("bind error");

    exit(-1);

    }

    if( listen(listenfd, 5) < 0 ) {

    p_error("listen error");

    exit(-1);

    }

    signal(SIGCHLD, waitchild);

    for(;;) {

    connfd = accept( listenfd, (struct sockaddr *)&clientaddr,

    &clientlen );

    if( connfd < 0 ) {

    p_error("accept error");

    exit(-1);

    }

    if( (chpid = fork()) == -1 ) {

    p_error("fork error");

    exit(-1);

    }

    if( chpid == 0 ) {

    close(listenfd);

    do_proxy(connfd, remote_addr, remote_port);

    exit(0);

    }

    if( chpid > 0 ) {

    close(connfd);

    }

    }

    exit(0);

    }

    int do_proxy(int infd, char *addr, int port) {

    struct sockaddr_in rout;

    int outfd;

    int maxfd;

    int count = 65535;

    int n;

    fd_set set;

    char buf[count];

    bzero(&rout, sizeof(rout));

    rout.sin_family = AF_INET;

    rout.sin_port = htons(port);

    rout.sin_addr.s_addr = inet_addr(addr);

    if( (outfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {

    p_error("socket error");

    exit(-1);

    }

    if( connect(outfd, (struct sockaddr *)&rout, sizeof(rout)) < 0 ) {

    p_error("connect error");

    exit(-1);

    }

    while(1) {

    FD_ZERO(&set);

    FD_SET(infd, &set);

    FD_SET(outfd, &set);

    maxfd = max(outfd, infd);

    if( select(maxfd + 1, &set, NULL, NULL, NULL) < 0 ) {

    perror("select error:");

    exit(-1);

    }

    if( FD_ISSET(infd, &set) ) {

    n = read(infd, (void *)buf, count);

    if( n <= 0)

    break;

    if( write(outfd, (const void *)buf, n) != n ) {

    p_error("write error");

    continue;

    }

    }

    if( FD_ISSET(outfd, &set) ) {

    n = read(outfd, (void *)buf, count);

    if( n <= 0)

    break;

    if( write(infd, (const void *)buf, n) != n ) {

    p_error("write error");

    continue;

    }

    }

    }

    close(infd);

    close(outfd);

    }

    int max(int i, int j) {

    return i>j?i:j;

    }

    void waitchild(int signo) {

    int status;

    pid_t childpid;

    if( (childpid = waitpid(-1, &status, WNOHANG)) < 0 ) {

    p_error("wait error");

    exit(1);

    }

    return;

    }

    void version() {

    printf("GNU SP 1.0

    Copyright 2001 Aryes Software Studio, Inc.

    SP is free software, covered by the GNU General Public License, and you are

    welcome to change it and/or distribute copies of it under certain conditions.

    ");

    }

    void usage() {

    printf("This is the GNU smart proxy daemon. Usage:

    sp -s service_port -r remote_address -p remote_port

    sp -v

    sp -h

    option:

    -s specify service port of sp

    -r specify remote address which sp will connect

    -p specify remote port while sp will connect to

    -v display version message

    -h display this help message

    Report bugs to <ariesram@may10.ca>.

    ");

    }

    void daemonize() {

    int i;

    #ifndef _DEBUG

    signal(SIGINT, SIG_IGN);

    #endif

    signal(SIGHUP, SIG_IGN);

    signal(SIGABRT, SIG_IGN);

    signal(SIGSTOP, SIG_IGN);

    signal(SIGCHLD, SIG_IGN);

    #ifndef _DEBUG

    if (fork() != 0)

    exit(0);

    setsid();

    for (i = 256; i >= 0; i --)

    #endif

    #ifdef _DEBUG

    for (i = 256; i >= 3; i --)

    #endif

    close(i);

    }

    void p_error(const char * err_msg)

    {

    FILE * fp;

    #ifdef _DEBUG

    printf("%s

    ", err_msg);

    #endif

    fp = fopen(ERRLOG, "a");

    if (fp == NULL)

    return;

    fprintf(fp, "%s

    ", err_msg);

    fclose(fp);

    }

     

    最新回复(0)