HTTPS代理永远无法成功连接

时间:2016-03-28 16:39:45

标签: c++ sockets networking proxy http-proxy

我正在尝试做的是一个处理HTTP(S)连接的分叉代理:成功执行GET(没有SSL)请求,并将内容传递给客户端,当涉及到{ {1}}方法事情进展不顺利,因为CONNECT到远程服务器可能不会立即成功:事实上,它已经成功了。

我尝试连接到远程服务器的非阻塞套接字,因此我可以看到connect()是立即进行还是需要一些时间:在第二种情况下,我会调用connect()查看何时远程服务器已准备好向我发送数据:但select()从未连接过。

这是我的代理connect()代码:

main()

现在接下来,我的问题int main(int argc, char *argv[]) { // ClientManager.cpp is described below ClientManager cm; //listening on port given by argv if (cm.startListeningForClient(listening_port)) { while(true) { int new_client_socket = cm.acceptConnectionFromClient(); if (new_client_socket >= 0) { cm.forkAndManageClient(); } else { perror("accept error"); } } } else { perror("Error on start listening"); } return EXIT_SUCCESS; } 有些遗漏,其功能在ClientManager.cpp上面调用:

main()

它管理设置套接字到非阻止模式,并打印ClientManager::ClientManager() { sockfd_client = -1; // socket connected to client new_sockfd_client = -1; // socket accepting connection from client sockfd_server = -1; // socket connected to remote server } // error controls omitted bool ClientManager::startListeningForClient(int port) { struct sockaddr_in serv_addr; bzero((char*)&serv_addr,sizeof(serv_addr)); serv_addr.sin_family=AF_INET; serv_addr.sin_port=htons(port); serv_addr.sin_addr.s_addr=INADDR_ANY; sockfd_client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); bind(sockfd_client,(struct sockaddr*)&serv_addr, sizeof(serv_addr)); listen(sockfd_client, 50); return true; } // error controls omitted int ClientManager::acceptConnectionFromClient(void) { struct sockaddr_in cli_addr; unsigned int clilen; bzero((char*)&cli_addr, sizeof(cli_addr)); clilen = sizeof(cli_addr); new_sockfd_client = accept(sockfd_client, (struct sockaddr*)&cli_addr, &clilen); return new_sockfd_client; } int ClientManager::forkAndManageClient() { // getRequestFromClient: the method below receives requests from // clients and parses the infos I need (i.e. what method, // hostname of remote server to be resolved, its port, ...) getRequestFromClient(); // managing the HTTP(S) request by the child process int pid = fork(); if (pid < 0) { perror("ERROR on fork"); } else if (pid > 0) { // parent process // do nothing } else { // close immediately the client socket used for accepting new connections from the parent process close (sockfd_client); if (!manageRequest()) { perror("Error managing request from client"); } // close the connection from the client close (new_sockfd_client); new_sockfd_client = -1; // the child process will terminate now _exit(EXIT_SUCCESS); } return pid; } // now the problematic method... bool ClientManager::manageRequest(void) { // if this is a CONNECT request if (rm.isCONNECT()) { struct sockaddr_in remote_server; int conn_res; remote_server.sin_family = AF_INET; remote_server.sin_addr.s_addr = rm.getServerAddr(); remote_server.sin_port = rm.getServerPort(); fd_set fdset; struct timeval tv; sockfd_server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // make socket not blocking int flags = fcntl(sockfd_server, F_GETFL, 0); flags = flags | O_NONBLOCK; if (fcntl(sockfd_server, F_SETFL, flags) == -1) { perror("FCNTL:"); } printf("CONNECT set socket to non-blocking mode\n"); conn_res = connect(sockfd_server, (struct sockaddr *)&remote_server, sizeof(struct sockaddr_in)); printf("AFTER CONNECT()\n"); if (conn_res < 0) { if (errno != EINPROGRESS) { printf("CONNECT: connect() failed, quitting\n"); return false; } } printf("CONNECT connection is taking place...\n"); // connected immediately if (conn_res == 0) { printf("CONNECT connected OK!\n"); goto CONNECTED; } FD_ZERO(&fdset); FD_SET(sockfd_server, &fdset); tv.tv_sec = 5; // tried 5, 20, 60 seconds, but it always times out tv.tv_usec = 0; printf("CONNECT attempting select()\n"); if (select(sockfd_server+1, NULL, &fdset, NULL, &tv) == 0) { errno = ETIMEDOUT; close(sockfd_server); sockfd_server = -1; return false; } if (FD_ISSET(sockfd_server, &fdset)) { int so_error; socklen_t len = sizeof so_error; if (getsockopt(sockfd_server, SOL_SOCKET, SO_ERROR, &so_error, &len) < 0) { return false; } } else { printf("sockfd_server not set\n"); } CONNECTED: fcntl(sockfd_server, F_SETFL, flags &~ O_NONBLOCK); // yeah, now I will start to deal the HTTPS flow in both directions return true; } } ,但它始终返回CONNECT connection is taking place...

我为发布数英里的LOC道歉,但这是让我疯狂的原因,在阅读帖子,教程和指南之后,我真的不知道该怎么做。

1 个答案:

答案 0 :(得分:0)

它现在连接到需要HTTPS连接的每个站点! 缺少正确的错误检查和关闭套接字描述符。这是我的代码:

bool ClientManager::manageRequest(void) {

if (rm.isCONNECT()) {
    struct sockaddr_in remote_server, local_bind;
    int conn_res, select_res;

    memset(&remote_server, 0, sizeof(remote_server));
    remote_server.sin_family = AF_INET;
    remote_server.sin_addr.s_addr = rm.getServerAddr();
    remote_server.sin_port = rm.getServerPort();

    memset(&local_bind, 0, sizeof(local_bind));
    local_bind.sin_family = AF_INET;
    local_bind.sin_addr.s_addr = htonl(INADDR_ANY);
    local_bind.sin_port = htons(0);

    fd_set rdset, wrset;
    struct timeval tv;

    sockfd_server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (sockfd_server < 0) {
        perror("socket: ");
    }

    if(!setNonBlocking(sockfd_server))
        perror("fcntl");
    debug_green("CONNECT set socket to non-blocking mode\n");

    bind(sockfd_server, (struct sockaddr*) &local_bind, sizeof(local_bind));

    conn_res = connect(sockfd_server, (struct sockaddr *)&remote_server, sizeof(struct sockaddr_in));
    // The socket is nonblocking and the connection cannot be completed immediately
    // check for EINPROGRESS
    if ((conn_res == -1) && (errno != EINPROGRESS)) {

        FD_ZERO(&rdset);
        FD_SET(sockfd_server, &rdset);
        wrset = rdset;
        tv.tv_sec = 0;
        tv.tv_usec = 0;

        debug_yellow("CONNECT attempting select()\n");
        do {
            select_res = select(sockfd_server+1, &rdset, &wrset, NULL, &tv);
        } while ((select_res == -1) && (errno == EINTR));

        if ((!FD_ISSET(sockfd_server, &rdset)) && ((!FD_ISSET(sockfd_server, &wrset)))) {
            debug_red("SELECT sockfds not responding\n");
            close(sockfd_server);
            sockfd_server = -1;
            return false;
        }

        conn_res = connect(sockfd_server, (struct sockaddr *)&remote_server, sizeof(struct sockaddr_in));
        if (conn_res == -1)  {
            if(errno == EISCONN)
                printf ("connect(): connections already existing, OK\n");
            else  {
                printf("connect() for safety check: connection NOT successfull\n");
                close(sockfd_server);
                sockfd_server = -1;
                return false;
            }
        }
        printf("connection OK\n");
        fflush(stdout);
    } else {
        debug_green("Connection immediately OK\n");
        fflush(stdout);
    }
    if (!setBlocking(sockfd_server)) {
        perror("FCNTL:");
    }
    debug_green("CONNECT set socket back to blocking mode\n");fflush(stdout);   
}

return true;
}

设置阻塞或非阻塞套接字的功能:

bool ClientManager::setNonBlocking(int sockfd) {
    printf("setting non block socket\n"); fflush(stdout);
    int flags;
    if ((flags = fcntl(sockfd, F_GETFL, 0)) < 0)
        return false;
    flags |= O_NONBLOCK;
    if (fcntl(sockfd, F_SETFL, flags) < 0)
        return false;
    return true;
}

bool ClientManager::setBlocking(int sockfd) {
    printf("setting block socket\n"); fflush(stdout);
    int flags;
    if ((flags = fcntl(sockfd, F_GETFL, 0)) < 0)
        return false;
    flags &= (~O_NONBLOCK);
    if (fcntl(sockfd, F_SETFL, flags) < 0)
        return false;
    return true;
}

调试功能:

#define DEFAULTCOLOR    "\033[0m"
#define RED             "\033[22;31m"
#define YELLOW          "\033[1;33m"
#define GREEN           "\033[0;0;32m"

#define debug_red(...) std::cout << RED << __VA_ARGS__ << DEFAULTCOLOR; fflush(stdout);
#define debug_yellow(...) std::cout << YELLOW << __VA_ARGS__ << DEFAULTCOLOR; fflush(stdout);
#define debug_green(...) std::cout << GREEN << __VA_ARGS__ << DEFAULTCOLOR; fflush(stdout);