C代理 - 绑定无法分配请求的地址

时间:2014-01-09 23:32:43

标签: c bind

我在c中遇到了代理服务器的问题。 用法:laddr lport rhost rport

输入:./proxy localhost 8333 localhost 8080

我收到错误:bind localhost 8333 can't assign requested address.

代码:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <netdb.h>
#include <string.h>
#include <signal.h>
#include <assert.h>
#include <syslog.h>


    #include <sys/types.h>
    #include <sys/select.h>
    #include <sys/file.h>
    #include <sys/ioctl.h>
    #include <sys/param.h>
    #include <sys/socket.h>
    #include <sys/stat.h>
    #include <sys/time.h>
    #include <sys/wait.h>

    #include <netinet/in.h>

    #include <arpa/ftp.h>
    #include <arpa/inet.h>
    #include <arpa/telnet.h>

    #define BUF_SIZE 4096

    extern int sys_nerr, errno;

    char client_hostname[64];

    void
    cleanup(int sig)
    {
        syslog(LOG_INFO, "Cleaning up...");
        exit(0);
    }

    void
    sigreap(int sig)
    {
        int status;
        pid_t p;
        while ((p = waitpid(-1, &status, WNOHANG)) > 0) {
        syslog(LOG_INFO, "sigreap: pid=%d, status=%d\n", (int) p, status);
        }
        /* doh! */
        signal(SIGCHLD, sigreap);
    }

    void
    set_nonblock(int fd)
    {
        int fl;
        int x;
        x = fcntl(fd, F_GETFL, &fl);
        if (x < 0) {
        syslog(LOG_ERR, "fcntl F_GETFL: FD %d: %s", fd, strerror(errno));
        exit(1);
        }
        fl |= O_NONBLOCK;
        x = fcntl(fd, F_SETFL, &fl);
        if (x < 0) {
        syslog(LOG_ERR, "fcntl F_SETFL: FD %d: %s", fd, strerror(errno));
        exit(1);
        }
    }


    int
    create_server_sock(char *addr, int port)
    {
        int addrlen, s, on = 1, x;
        static struct sockaddr_in client_addr;

        s = socket(AF_INET, SOCK_STREAM, 0);
        if (s < 0)
        perror("socket"), exit(1);

        addrlen = sizeof(client_addr);
        memset(&client_addr, '\0', addrlen);
        client_addr.sin_family = AF_INET;
        client_addr.sin_addr.s_addr = inet_addr(addr);
        client_addr.sin_port = htons(port);
        setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, 4);
        x = bind(s, (struct sockaddr *) &client_addr, addrlen);
        if (x < 0)
        perror("bind"), exit(1);

        x = listen(s, 5);
        if (x < 0)
        perror("listen"), exit(1);

        return s;
    }

    int
    open_remote_host(char *host, int port)
    {
        struct sockaddr_in rem_addr;
        int len, s, x;
        struct hostent *H;
        int on = 1;

        H = gethostbyname(host);
        if (!H)
        return (-2);

        len = sizeof(rem_addr);

        s = socket(AF_INET, SOCK_STREAM, 0);
        if (s < 0)
        return s;

        setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, 4);

        len = sizeof(rem_addr);
        memset(&rem_addr, '\0', len);
        rem_addr.sin_family = AF_INET;
        memcpy(&rem_addr.sin_addr, H->h_addr, H->h_length);
        rem_addr.sin_port = htons(port);
        x = connect(s, (struct sockaddr *) &rem_addr, len);
        if (x < 0) {
        close(s);
        return x;
        }
        set_nonblock(s);
        return s;
    }

    int
    get_hinfo_from_sockaddr(struct sockaddr_in addr, int len, char *fqdn)
    {
        struct hostent *hostinfo;

        hostinfo = gethostbyaddr((char *) &addr.sin_addr.s_addr, len, AF_INET);
        if (!hostinfo) {
        sprintf(fqdn, "%s", inet_ntoa(addr.sin_addr));
        return 0;
        }
        if (hostinfo && fqdn)
        sprintf(fqdn, "%s [%s]", hostinfo->h_name, inet_ntoa(addr.sin_addr));
        return 0;
    }


    int
    wait_for_connection(int s)
    {
        static int newsock, len;
        static struct sockaddr_in peer;

        len = sizeof(struct sockaddr);
        newsock = accept(s, (struct sockaddr *) &peer, &len);
        /* dump_sockaddr (peer, len); */
        if (newsock < 0) {
        if (errno != EINTR)
            perror("accept");
        }
        get_hinfo_from_sockaddr(peer, len, client_hostname);
        set_nonblock(newsock);
        return (newsock);
    }

    int
    mywrite(int fd, char *buf, int *len)
    {
        int x = write(fd, buf, *len);
        if (x < 0)
            return x;
        if (x == 0)
            return x;
        if (x != *len)
            memmove(buf, buf+x, (*len)-x);
        *len -= x;
        return x;
    }

    void
    service_client(int cfd, int sfd)
    {
        int maxfd;
        char *sbuf;
        char *cbuf;
        int x, n;
        int cbo = 0;
        int sbo = 0;
        fd_set R;

        sbuf = malloc(BUF_SIZE);
        cbuf = malloc(BUF_SIZE);
        maxfd = cfd > sfd ? cfd : sfd;
        maxfd++;

        while (1) {
        struct timeval to;
        if (cbo) {
            if (mywrite(sfd, cbuf, &cbo) < 0 && errno != EWOULDBLOCK) {
                syslog(LOG_ERR, "write %d: %s", sfd, strerror(errno));
                    exit(1);
            }
        }
        if (sbo) {
            if (mywrite(cfd, sbuf, &sbo) < 0 && errno != EWOULDBLOCK) {
                syslog(LOG_ERR, "write %d: %s", cfd, strerror(errno));
                    exit(1);
            }
        }
        FD_ZERO(&R);
        if (cbo < BUF_SIZE)
            FD_SET(cfd, &R);
        if (sbo < BUF_SIZE)
            FD_SET(sfd, &R);
        to.tv_sec = 0;
        to.tv_usec = 1000;
        x = select(maxfd+1, &R, 0, 0, &to);
        if (x > 0) {
            if (FD_ISSET(cfd, &R)) {
            n = read(cfd, cbuf+cbo, BUF_SIZE-cbo);
            syslog(LOG_INFO, "read %d bytes from CLIENT (%d)", n, cfd);
            if (n > 0) {
                cbo += n;
            } else {
                close(cfd);
                close(sfd);
                _exit(0);
            }
            }
            if (FD_ISSET(sfd, &R)) {
            n = read(sfd, sbuf+sbo, BUF_SIZE-sbo);
            syslog(LOG_INFO, "read %d bytes from SERVER (%d)\n", n, sfd);
            if (n > 0) {
                sbo += n;
            } else {
                close(sfd);
                close(cfd);
                _exit(0);
            }
            }
        } else if (x < 0 && errno != EINTR) {
            close(sfd);
            close(cfd);
            _exit(0);
        }
        }
    }


    int
    main(int argc, char *argv[])
    {
        char *localaddr = strdup(argv[1]);
        int localport = atoi(argv[2]);
        char *remoteaddr = strdup(argv[3]);
        int remoteport = atoi(argv[4]);
        int client, server;
        int master_sock;

        if (5 != argc) {
        fprintf(stderr, "usage: %s laddr lport rhost rport\n", argv[0]);
        exit(1);
        }
        assert(localaddr);
        assert(localport > 0);
        assert(remoteaddr);
        assert(remoteport > 0);

        openlog(argv[0], LOG_PID, LOG_LOCAL4);

        signal(SIGINT, cleanup);
        signal(SIGCHLD, sigreap);

        master_sock = create_server_sock(localaddr, localport);
        for (;;) {
        if ((client = wait_for_connection(master_sock)) < 0)
            continue;
        if ((server = open_remote_host(remoteaddr, remoteport)) < 0)
            continue;
        if (!fork()) {
            syslog(LOG_NOTICE, "connection from %s fd=%d\n", client_hostname, client);
            syslog(LOG_INFO, "connected to %s:%d fd=%d\n", remoteaddr, remoteport, server);
            service_client(client, server);
        }
        close(client);
        close(server);
        }

    }

如何更正代码以使其有效?

1 个答案:

答案 0 :(得分:0)

来自man inet(3):

  

inet_addr()函数转换来自的Internet主机地址cp   以网络字节顺序将IPv4数字和点符号表示为二进制数据。   如果输入无效,则返回INADDR_NONE(通常为-1)。

问题在函数create_server_sock()中,您执行client_addr.sin_addr.s_addr = inet_addr("localhost");。很明显,“localhost”不是数字和点符号。您应该使用gethostbyname,就像使用remoteaddrgetaddrinfo

一样