@ -186,48 +186,137 @@ error: {
}
// ====================================================================
// HTTP CONNECT handshake
// HTTP CONNECT / HTTP proxy handshake
// ====================================================================
static void process_http_request ( struct socks_proxy_conn * c ) {
// Ищем "\r\n\r\n" или первую "\r\n" для строки CONNECT
char * end = memmem ( c - > buf , c - > buf_len , " \r \n \r \n " , 4 ) ;
if ( ! end ) { end = memmem ( c - > buf , c - > buf_len , " \r \n " , 2 ) ; if ( ! end ) return ; }
char * line_end = memmem ( c - > buf , c - > buf_len , " \r \n " , 2 ) ;
if ( ! line_end ) return ;
uint16_t line_len = ( uint16_t ) ( ( uint8_t * ) end - c - > buf ) ;
uint16_t line_len = ( uint16_t ) ( ( uint8_t * ) line_ end - c - > buf ) ;
if ( line_len < 8 ) { DEBUG_ERROR ( DEBUG_CATEGORY_SOCKET , " socks_proxy: http request too short " ) ; goto error ; }
// Парсим "CONNECT host:port HTTP/1.1"
char line [ 512 ] ; if ( line_len > sizeof ( line ) - 1 ) line_len = sizeof ( line ) - 1 ;
memcpy ( line , c - > buf , line_len ) ; line [ line_len ] = ' \0 ' ;
char host_port [ 256 ] ;
if ( sscanf ( line , " CONNECT %255s HTTP/ " , host_port ) ! = 1 ) {
DEBUG_ERROR ( DEBUG_CATEGORY_SOCKET , " socks_proxy: bad http connect: %s " , line ) ;
// ===== CONNECT =====
if ( strncmp ( line , " CONNECT " , 8 ) = = 0 ) {
char host_port [ 256 ] ;
if ( sscanf ( line , " CONNECT %255s HTTP/ " , host_port ) ! = 1 ) {
DEBUG_ERROR ( DEBUG_CATEGORY_SOCKET , " socks_proxy: bad http connect: %s " , line ) ;
goto error ;
}
char * colon = strrchr ( host_port , ' : ' ) ;
if ( ! colon ) { DEBUG_ERROR ( DEBUG_CATEGORY_SOCKET , " socks_proxy: no port in %s " , host_port ) ; goto error ; }
* colon = ' \0 ' ; int port = atoi ( colon + 1 ) ;
if ( port < = 0 | | port > 65535 ) { DEBUG_ERROR ( DEBUG_CATEGORY_SOCKET , " socks_proxy: bad port %d " , port ) ; goto error ; }
struct hostent * he = gethostbyname ( host_port ) ;
if ( ! he | | he - > h_addrtype ! = AF_INET ) {
DEBUG_ERROR ( DEBUG_CATEGORY_SOCKET , " socks_proxy: DNS failed for %s " , host_port ) ;
uint8_t resp [ ] = " HTTP/1.1 502 Bad Gateway \r \n \r \n " ;
write_to_client ( c , resp , ( uint16_t ) strlen ( ( char * ) resp ) ) ; tcp_conn_push_close ( c - > tc ) ; return ;
}
memcpy ( c - > dest_ip , he - > h_addr , 4 ) ; c - > dest_port = htons ( ( uint16_t ) port ) ;
DEBUG_INFO ( DEBUG_CATEGORY_SOCKET , " socks_proxy: HTTP CONNECT %s → %d.%d.%d.%d:%d " ,
host_port , c - > dest_ip [ 0 ] , c - > dest_ip [ 1 ] , c - > dest_ip [ 2 ] , c - > dest_ip [ 3 ] , port ) ;
c - > buf_len = 0 ;
c - > state = HTTP_STATE_RELAY ;
uint8_t resp [ ] = " HTTP/1.1 200 Connection Established \r \n \r \n " ;
write_to_client ( c , resp , ( uint16_t ) strlen ( ( char * ) resp ) ) ;
if ( send_connect ( c ) < 0 ) { tcp_conn_push_close ( c - > tc ) ; }
return ;
}
// ===== Не-CONNECT: HTTP-прокси (GET, POST, PUT, HEAD, OPTIONS, ...) =====
char * hdr_end = memmem ( c - > buf , c - > buf_len , " \r \n \r \n " , 4 ) ;
if ( ! hdr_end ) return ;
uint16_t headers_len = ( uint16_t ) ( ( uint8_t * ) hdr_end - c - > buf ) + 4 ;
char method [ 16 ] = { 0 } , url [ 512 ] = { 0 } ;
if ( sscanf ( line , " %15s %511s " , method , url ) < 2 ) {
DEBUG_ERROR ( DEBUG_CATEGORY_SOCKET , " socks_proxy: bad http request line: %s " , line ) ;
goto error ;
}
if ( strncmp ( url , " http:// " , 7 ) ! = 0 ) {
DEBUG_ERROR ( DEBUG_CATEGORY_SOCKET , " socks_proxy: not an absolute http URL: %s " , url ) ;
goto error ;
}
char * colon = strrchr ( host_port , ' : ' ) ;
if ( ! colon ) { DEBUG_ERROR ( DEBUG_CATEGORY_SOCKET , " socks_proxy: no port in %s " , host_port ) ; goto error ; }
* colon = ' \0 ' ; int port = atoi ( colon + 1 ) ;
if ( port < = 0 | | port > 65535 ) { DEBUG_ERROR ( DEBUG_CATEGORY_SOCKET , " socks_proxy: bad port %d " , port ) ; goto error ; }
char host [ 256 ] ;
int port = 80 ;
const char * host_start = url + 7 ;
const char * path_start = strchr ( host_start , ' / ' ) ;
const char * col = NULL ;
for ( const char * p = host_start ; ( path_start ? p < path_start : * p ) ; p + + ) {
if ( * p = = ' : ' ) { col = p ; break ; }
}
struct hostent * he = gethostbyname ( host_port ) ;
if ( col & & ( ! path_start | | col < path_start ) ) {
size_t hlen = ( size_t ) ( col - host_start ) ;
if ( hlen > = sizeof ( host ) ) goto error ;
memcpy ( host , host_start , hlen ) ; host [ hlen ] = ' \0 ' ;
port = atoi ( col + 1 ) ;
if ( port < = 0 | | port > 65535 ) { DEBUG_ERROR ( DEBUG_CATEGORY_SOCKET , " socks_proxy: bad port %d in %s " , port , url ) ; goto error ; }
} else if ( path_start ) {
size_t hlen = ( size_t ) ( path_start - host_start ) ;
if ( hlen > = sizeof ( host ) ) goto error ;
memcpy ( host , host_start , hlen ) ; host [ hlen ] = ' \0 ' ;
} else {
size_t hlen = strlen ( host_start ) ;
if ( hlen > = sizeof ( host ) ) goto error ;
memcpy ( host , host_start , hlen ) ; host [ hlen ] = ' \0 ' ;
}
if ( host [ 0 ] = = ' \0 ' ) { DEBUG_ERROR ( DEBUG_CATEGORY_SOCKET , " socks_proxy: empty host in %s " , url ) ; goto error ; }
if ( ! path_start | | * path_start = = ' \0 ' ) path_start = " / " ;
struct hostent * he = gethostbyname ( host ) ;
if ( ! he | | he - > h_addrtype ! = AF_INET ) {
DEBUG_ERROR ( DEBUG_CATEGORY_SOCKET , " socks_proxy: DNS failed for %s " , host_port ) ;
DEBUG_ERROR ( DEBUG_CATEGORY_SOCKET , " socks_proxy: DNS failed for %s " , host ) ;
uint8_t resp [ ] = " HTTP/1.1 502 Bad Gateway \r \n \r \n " ;
write_to_client ( c , resp , ( uint16_t ) strlen ( ( char * ) resp ) ) ; tcp_conn_push_close ( c - > tc ) ; return ;
}
memcpy ( c - > dest_ip , he - > h_addr , 4 ) ; c - > dest_port = htons ( ( uint16_t ) port ) ;
DEBUG_INFO ( DEBUG_CATEGORY_SOCKET , " socks_proxy: HTTP CONNECT %s → %d.%d.%d.%d:%d " ,
host_port , c - > dest_ip [ 0 ] , c - > dest_ip [ 1 ] , c - > dest_ip [ 2 ] , c - > dest_ip [ 3 ] , port ) ;
c - > buf_len = 0 ;
c - > state = HTTP_STATE_RELAY ; // reply immediately, no waiting
uint8_t resp [ ] = " HTTP/1.1 200 Connection Established \r \n \r \n " ;
write_to_client ( c , resp , ( uint16_t ) strlen ( ( char * ) resp ) ) ;
DEBUG_INFO ( DEBUG_CATEGORY_SOCKET , " socks_proxy: HTTP %s %s:%d%s → %d.%d.%d.%d:%d " ,
method , host , port , path_start ,
c - > dest_ip [ 0 ] , c - > dest_ip [ 1 ] , c - > dest_ip [ 2 ] , c - > dest_ip [ 3 ] , port ) ;
if ( send_connect ( c ) < 0 ) {
tcp_conn_push_close ( c - > tc ) ;
DEBUG_ERROR ( DEBUG_CATEGORY_SOCKET , " socks_proxy: send_connect failed for %s " , host ) ;
uint8_t resp [ ] = " HTTP/1.1 502 Bad Gateway \r \n \r \n " ;
write_to_client ( c , resp , ( uint16_t ) strlen ( ( char * ) resp ) ) ; tcp_conn_push_close ( c - > tc ) ; return ;
}
const char * version = strstr ( line , " HTTP/ " ) ;
char version_str [ 16 ] = " HTTP/1.1 " ;
if ( version ) {
size_t vlen = strlen ( version ) ;
if ( vlen > = sizeof ( version_str ) ) vlen = sizeof ( version_str ) - 1 ;
memcpy ( version_str , version , vlen + 1 ) ;
}
uint16_t rest_off = line_len + 2 ;
uint16_t rest_len = headers_len - rest_off ;
uint8_t hdr_buf [ 2048 ] ;
int hdr_n = snprintf ( ( char * ) hdr_buf , sizeof ( hdr_buf ) , " %s %s%s \r \n " , method , path_start , version_str ) ;
if ( hdr_n < 0 | | ( size_t ) hdr_n + rest_len > sizeof ( hdr_buf ) ) {
DEBUG_ERROR ( DEBUG_CATEGORY_SOCKET , " socks_proxy: header reconstruction overflow hdr_n=%d rest=%u " , hdr_n , rest_len ) ;
goto error ;
}
memcpy ( hdr_buf + hdr_n , c - > buf + rest_off , rest_len ) ;
send_data ( c , hdr_buf , ( uint16_t ) ( hdr_n + rest_len ) ) ;
if ( headers_len < c - > buf_len ) {
send_data ( c , c - > buf + headers_len , c - > buf_len - headers_len ) ;
}
c - > buf_len = 0 ;
c - > state = HTTP_STATE_RELAY ;
return ;
error : {