Ejemplo n.º 1
0
int httpUtil::parse_request(const char* source,uint32_t len) {
    if(!source||len==0) {
        return -1;
    }
    clear_request();
    char* pheadEnd=0;
    char* pentity=0;
    pheadEnd=strstr(source,"\r\n\r\n");
    if(pheadEnd==0) {
        return -1;
    }
    uint32_t headlen=pheadEnd+4-source;
    pentity=pheadEnd+4;
    if(headlen==0) {
        return -1;
    }
    char* headbuff=new char[headlen+1];
    if(!headbuff) {
        return -1;
    }
    memset(headbuff,0,headlen+1);
    memcpy(headbuff,source,headlen);
    int getRet=0,PostRet=0;
    getRet=get_header_field(headbuff,_request_firstLine,"GET ");
    PostRet=get_header_field(headbuff,_request_firstLine,"POST ");
    if(getRet==0) {
        _request_method="GET";
    }
    else if(PostRet==0) {
        _request_method="POST";
    }
    get_header_field(headbuff,_request_accept,"Accept: ");
    get_header_field(headbuff,_request_referer,"Referer: ");
    get_header_field(headbuff,_request_acceptEncoding,"Accept-Encoding: ");
    get_header_field(headbuff,_request_userAgent,"User-Agent: ");
    get_header_field(headbuff,_request_host,"Host: ");
    get_header_field(headbuff,_request_cookie,"Cookie: ");
    get_header_field(headbuff,_request_acceptLanguage,"Accept-Language: ");
    get_header_field(headbuff,_request_connection,"Connection: ");
    dissect_request_firstLine();
    uint32_t entitylen=len-headlen;
    if(entitylen==0) {
        _request_payload="";
    }
    else
        _request_payload=pentity;
    delete []headbuff;
    return 0;
}
Ejemplo n.º 2
0
int proxy_thread( struct thread_data *td )
{
    int remote_fd = -1;
    int state;
    int n, client_fd;
	int result = -1;
    uint32 client_ip;
    ssize_t writed;
    int already_authorized = 0;
    // if some http data coming together with request
    char *data = NULL;
    int data_len = 0;

#define BUF_SIZE 1504
#define REQ_SIZE 15004
#define clear_buffer() memset(buffer, 0, BUF_SIZE)
#define clear_request() memset(request, 0, REQ_SIZE);
#define clear_req() memset(&req, 0, sizeof(req));
        
    char buffer[BUF_SIZE];
    char last_host[BUF_SIZE];
    request = malloc(REQ_SIZE);


    struct sockaddr_in remote_addr;
    struct hostent *remote_host;
    struct timeval timeout;

    fd_set rfds;

	FENTER;
	ASSERT(request);

    client_fd = td->client_fd;
    client_ip = td->client_ip;

    /* fetch the http request headers */
    FD_ZERO( &rfds );
    FD_SET( (unsigned int) client_fd, &rfds );

    timeout.tv_sec  = 15;
    timeout.tv_usec =  0;

    if ( select(client_fd + 1, &rfds, NULL, NULL, &timeout ) <= 0) {
		ERR("select() timeout", 0);
		result = 11;
        goto exit;
    }

    char *end_of_req = NULL;
    char *preq = request;
    clear_req();
    clear_request();
    clear_buffer();
    if ( ( n = read(client_fd, buffer, sizeof(buffer)-4) ) <= 0 ) {
        ERR("read() fail", 0);
        result = 12;
        goto exit;
    }
    DBG("-  recv %d bytes", n);
    // append
    memcpy(preq, buffer, n);
    preq += n;

process_request:
    while ( !(end_of_req = strstr(request, "\r\n\r\n")) ) {
        DBG("-  request without %s", ANSI_WHITE"CRLFCRLF"ANSI_RESET);
        clear_buffer();
        if ( ( n = read(client_fd, buffer, sizeof(buffer)-4) ) <= 0 ) {
            ERR("read() fail", 0);
            result = 12;
            goto exit;
        }
        DBG("-  recv %d bytes", n);
        // append
        memcpy(preq, buffer, n);
        preq += n;
    }
    end_of_req += 4; // first byte after CRLFCRLF

    if ( (unsigned int)(end_of_req - request) == strlen(request) ) {
        DBG("no data found in this request", 0);
    } else {
        data_len = preq - end_of_req;
        DBG("%d data bytes found in this request", data_len);
        data = malloc(data_len);
        if (!data) {
            ERR("malloc() %d", data_len);
            goto exit;
        }
        memcpy(data, end_of_req, data_len);
    }

//#define DUMP
#ifdef DUMP
    LOG_HEXDUMP("RECEIVED FROM CLIENT", (unsigned char*)request, preq-request);
#else
    DBG("RECEIVED FROM CLIENT %d bytes", preq-request);
#endif
    if (!parse_request()) {
        WARN("bad request:", request);
        return -1;
    };

    if (!already_authorized) { 
        if (is_proxy_authorized()) {
            already_authorized = 1;
        } else {
            proxy_unauthorized(td);
            goto exit;
        }
    }

    if ( is_syscmd() ) {
        if ( is_sys_authorized() ) {
            process_sys_cmd();
            goto exit;
        } else {
            sys_unauthorized(td);
            goto exit;
        }
    }


    //LOG_HEXDUMP("BEFORE", (unsigned char*)req.headers, BUF_SIZE);
    remove_header("Proxy-Authorization");
    remove_header("Proxy-Connection");
    //LOG_HEXDUMP("AFTER", (unsigned char*)req.headers, BUF_SIZE);

    /* resolve the http server hostname */
    if ( !(req.hostname) || !( remote_host = gethostbyname( req.hostname ) ) ) {
		WARN("-  fail to resolve '%s'", req.hostname);
        result = 19;
		goto exit;
    }

    if ( req.connect ) {
        if( td->connect == 1 && req.port != 443 ) {
            result = 20;
			goto exit;
        }
    }

    /* connect to the remote server, if not already connected */
    if ( 1 || strcmp(req.hostname, last_host) ) {
        shutdown( remote_fd, 2 );
        close( remote_fd );

        remote_fd = socket( AF_INET, SOCK_STREAM, IPPROTO_IP );

        if (remote_fd < 0) {
			WARN("-  socket() fail", 0);
            result = 21;
			goto exit;
        }

        remote_addr.sin_family = AF_INET;
        remote_addr.sin_port = htons( (unsigned short) req.port );

        memcpy( (void *) &remote_addr.sin_addr,
                (void *) remote_host->h_addr,
                remote_host->h_length );

        if ( connect( remote_fd, (struct sockaddr *) &remote_addr, sizeof( remote_addr ) ) < 0 ) {
			WARN("-  connect() to '%s:%d' fail", req.hostname, req.port);
            result = 22;
            goto exit;
        }
        DBG("-  connected to %s:%d", req.url_host, req.port);

        memset( last_host, 0, sizeof( last_host ) );
        strncpy( last_host, req.hostname, sizeof( last_host ) - 1 );
    } else {
        INFO("reuse current connection", 0);
    }

    if ( req.connect ) {
        /* send HTTP/1.0 200 OK */
        snprintf(buffer, sizeof(buffer), "HTTP/1.0 200 OK\r\n\r\n");

        if ( (writed = write(client_fd, buffer, 19)) != 19 ) {
            WARN("write() fail: %d", writed);
            result = 23;
			goto exit;
        }
        req.sent_to_client += writed;
    }
    else
    {
        /* Construct and send modified request */
        size_t server_req_size = strlen(req.method) + strlen(req.url) + strlen(req.http_ver) + strlen(req.headers) + 16;
        char *server_req = malloc(server_req_size);
        if (!server_req) {
            ERR("malloc() fail: %d", server_req_size); 
            result = 235;
            goto exit;
        }
        memset(server_req, 0, server_req_size);
		n = snprintf(server_req, server_req_size - 4, "%s %s %s%s", req.method, req.url, req.http_ver, req.headers);
        if ((writed = write(remote_fd, server_req, n)) != n) {
            WARN("write() fail: %d", writed);
            result = 24;
			goto exit;
        }
        req.sent_to_server += writed;
#ifdef DUMP
		LOG_HEXDUMP("SENDED TO SERVER", (unsigned char*)server_req, n);
#else
        DBG("SENDED TO SERVER %d bytes", n);
#endif
        free(server_req);

        if ( data ) {
            // Some additional data was found in initial request
            if ((writed = write(remote_fd, data, data_len)) != data_len) {
                WARN("write() fail: %d", writed);
                result = 35;
                goto exit;
            }
            req.sent_to_server += writed;
#ifdef DUMP
            LOG_HEXDUMP("SENDED TO SERVER (data)", (unsigned char*)data, data_len);
#else
            DBG("SENDED TO SERVER %d bytes (data)", n);
#endif
            // clear data
            free(data);
            data = NULL;
            data_len = 0;
        }
    }

    /* tunnel the data between the client and the server */

    state = 0;

    while( 1 )
    {
        FD_ZERO( &rfds );
        FD_SET( (unsigned int) client_fd, &rfds );
        FD_SET( (unsigned int) remote_fd, &rfds );
    
        n = ( client_fd > remote_fd ) ? client_fd : remote_fd;

        if ( select( n + 1, &rfds, NULL, NULL, NULL ) < 0 ) {
            ERR("select() fail", 0);
            result = 25;
			goto exit;
        }

        if ( FD_ISSET( remote_fd, &rfds ) ) {
            clear_buffer();
            if ( ( n = read( remote_fd, buffer, BUF_SIZE-1) ) <= 0 ) {
                WARN("read() fail: %d", n);
                result = 26;
				goto exit;
            }
#ifdef DUMP
			LOG_HEXDUMP("RECEIVED FROM SERVER (tunneled)", (unsigned char*)buffer, n);
#else
            DBG("RECEIVED FROM SERVER (tunneled) %d bytes", n);
#endif

            state = 1; /* client finished sending data */

            if ( (writed = write( client_fd, buffer, n )) != n ) {
                WARN("write() fail: %d", writed);
                result = 27;
				goto exit;
            }
            req.sent_to_client += n;
#ifdef DUMP
			LOG_HEXDUMP("SENDED TO CLIENT (tunneled)", (unsigned char*)buffer, n);
#else
            DBG("SENDED TO CLIENT (tunneled) %d bytes", n);
#endif
        }

        if ( FD_ISSET( client_fd, &rfds ) ) {
            clear_buffer();
            if ( (n = read( client_fd, buffer, BUF_SIZE-1)) <= 0 ) {
                WARN("read() fail: %d", n);
                result = 28;
				goto exit;
            }
#ifdef DUMP
			LOG_HEXDUMP("RECEIVED FROM CLIENT (tunneled)", (unsigned char*)buffer, n);
#else
            DBG("RECEIVED FROM CLIENT (tunneled) %d bytes", n);
#endif

            if ( state && !req.connect ) {
                /* new http request */
                INFO("-  process new http request", 0);
                syslog_request();

                LOG_HEXDUMP("request", (unsigned char*)buffer, n);

                memset(&req, 0, sizeof(req));
                int req_len = MIN((size_t)n, REQ_SIZE-1);
                strncpy(request, buffer, req_len);
                preq = request + req_len;
                goto process_request;
            }

            if ((writed = write( remote_fd, buffer, n)) != n ) {
                WARN("write() fail: %d", writed);
                result = 29;
				goto exit;
            }
            req.sent_to_server += n;
#ifdef DUMP
			LOG_HEXDUMP("SENDED TO SERVER (tunneled)", (unsigned char*)buffer, n);
#else
            DBG("SENDED TO SERVER (tunneled) %d bytes", n);
#endif
        }
    }


    /* not reached */
exit:

    shutdown( client_fd, 2 );
    shutdown( remote_fd, 2 );
    close( client_fd );
    close( remote_fd );
    syslog_request();
    closelog();
	if (request) free(request);
	FLEAVEA("exit with %d code sent to client: %d, to server: %d", result, req.sent_to_client, req.sent_to_server);
    return( result );
}