// The contents of this file are subject to the BOINC Public License // Version 1.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at // http://boinc.berkeley.edu/license_1.0.txt // // Software distributed under the License is distributed on an "AS IS" // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the // License for the specific language governing rights and limitations // under the License. // // The Original Code is the Berkeley Open Infrastructure for Network Computing. // // The Initial Developer of the Original Code is the SETI@home project. // Portions created by the SETI@home project are Copyright (C) 2002 // University of California at Berkeley. All Rights Reserved. // // Contributor(s): // #include "cpp.h" #ifdef _WIN32 #include "boinc_win.h" #endif #ifndef _WIN32 #include #include #if HAVE_SYS_STAT_H #include #endif #if HAVE_SYS_SOCKET_H #include #endif #if HAVE_NETINET_IN_H #include #endif #if HAVE_UNISTD_H #include #endif #endif #include "error_numbers.h" #include "filesys.h" #include "util.h" #include "client_msgs.h" #include "parse.h" #include "proxy.h" // Read the contents of the socket into buf // static int proxy_read_reply(int socket, char* buf, int len) { int i, n; for (i=0; i 0) { len = send(socket, buf+ret, size, 0); if ( len == -1 && errno != ) fatal("atomic_out() failed to send(), %d\n", socks_errno()); ret += len; size -= len; } return ret; } */ void print_buf( char *buf, int n ) { for (int i=0;i")) return 0; else if (match_tag(buf, "")) use_http_proxy = true; else if (match_tag(buf, "")) use_socks_proxy = true; else if (match_tag(buf, "")) use_http_auth = true; else if (parse_int(buf, "", socks_version)) continue; else if (parse_str(buf, "", socks_server_name, sizeof(socks_server_name))) continue; else if (parse_int(buf, "", socks_server_port)) continue; else if (parse_str(buf, "", http_server_name, sizeof(http_server_name))) continue; else if (parse_int(buf, "", http_server_port)) continue; else if (parse_str(buf, "", socks5_user_name, sizeof(socks5_user_name))) continue; else if (parse_str(buf, "", socks5_user_passwd, sizeof(socks5_user_passwd))) continue; else if (parse_str(buf, "", http_user_name, sizeof(http_user_name))) continue; else if (parse_str(buf, "", http_user_passwd, sizeof(http_user_passwd))) continue; else scope_messages.printf("PROXY_INFO::parse(): unrecognized: %s\n", buf); } return 0; } int PROXY_INFO::write(MIOFILE& out) { out.printf( "\n" "%s" "%s" "%s" " %d\n" " %s\n" " %d\n" " %s\n" " %d\n" " %s\n" " %s\n" " %s\n" " %s\n" "\n", use_http_proxy?" \n":"", use_socks_proxy?" \n":"", use_http_auth?" \n":"", socks_version, socks_server_name, socks_server_port, http_server_name, http_server_port, socks5_user_name, socks5_user_passwd, http_user_name, http_user_passwd ); return 0; } void PROXY_INFO::clear() { use_http_proxy = false; use_socks_proxy = false; use_http_auth = false; strcpy(socks_server_name, ""); strcpy(http_server_name, ""); socks_server_port = 80; http_server_port = 80; strcpy(socks5_user_name, ""); strcpy(socks5_user_passwd, ""); strcpy(http_user_name, ""); strcpy(http_user_passwd, ""); socks_version = 0; } PROXY::PROXY() { strcpy(proxy_data,""); proxy_state = PROXY_STATE_CONNECTING; proxy_retval = 0; } void PROXY::init(char *dst_host, int port) { strcpy(dest_serv_name, dst_host); dest_serv_port = port; proxy_state = PROXY_STATE_CONNECTING; } PROXY::~PROXY() { } int PROXY::set_proxy(PROXY_INFO *new_pi) { pi.use_http_proxy = new_pi->use_http_proxy; strcpy(pi.http_user_name, new_pi->http_user_name); strcpy(pi.http_user_passwd, new_pi->http_user_passwd); strcpy(pi.http_server_name, new_pi->http_server_name); pi.http_server_port = new_pi->http_server_port; pi.use_http_auth = new_pi->use_http_auth; pi.use_socks_proxy = new_pi->use_socks_proxy; strcpy(pi.socks5_user_name, new_pi->socks5_user_name); strcpy(pi.socks5_user_passwd, new_pi->socks5_user_passwd); strcpy(pi.socks_server_name, new_pi->socks_server_name); pi.socks_server_port = new_pi->socks_server_port; pi.socks_version = new_pi->socks_version; return 0; } char *PROXY::get_proxy_server_name(char *regular_server) { if (pi.use_socks_proxy) return pi.socks_server_name; else if (pi.use_http_proxy) return pi.http_server_name; else return regular_server; } int PROXY::get_proxy_port(int regular_port) { if (pi.use_socks_proxy) return pi.socks_server_port; else if (pi.use_http_proxy) return pi.http_server_port; else return regular_port; } int PROXY::proxy_failed(int failure_code) { proxy_state = PROXY_STATE_DONE; proxy_retval = failure_code; return 0; } // Initialize proxy_data with a socks4 or socks5 connection request // see http://www.socks.nec.com/rfc/rfc1928.txt // see http://www.socks.nec.com/protocol/socks4.protocol // TODO: add support for GSSAPI authentication, IPv6 addresses, name -> IP resolution // One current problem is that the client may not fully read/write messages // to the server if buffers are full. proxy_atomic_send is an attempt to // compensate, it should be fully implemented and tested if this becomes a // significant issue. I'm not too worried though, since the messages are // always very small, and unlikely to cause space concerns (Eric Heien 3/26/04) // Check available methods on the socks server // int PROXY::socks_prepare_method_req(char *buf) { int nbytes = 0; char *marker = buf; if (pi.socks_version != SOCKS_VERSION_5) return ERR_SOCKS_UNKNOWN_FAILURE; nbytes = 3; *marker++ = SOCKS_VERSION_5; if (*pi.socks5_user_name && *pi.socks5_user_passwd) { *marker++ = 2; // 2 possible methods *marker++ = SOCKS_AUTH_USER_PASS; // user/pass nbytes++; } else { *marker++ = 1; // 1 possible method: } *marker++ = SOCKS_AUTH_NONE_NEEDED; // no authentication return nbytes; } int PROXY::socks_prepare_user_pass(char *buf) { int nbytes; char *marker = buf; if (pi.socks_version != SOCKS_VERSION_5) return ERR_SOCKS_UNKNOWN_FAILURE; // Send user and password *marker++ = SOCKS5_USER_SUBNEG_VERSION_1; *marker++ = strlen(pi.socks5_user_name); strncpy(marker, pi.socks5_user_name, strlen(pi.socks5_user_name)); marker += strlen(pi.socks5_user_name); *marker++ = strlen(pi.socks5_user_passwd); strncpy(marker, pi.socks5_user_passwd, strlen(pi.socks5_user_passwd)); nbytes = 1+1+strlen(pi.socks5_user_name)+1+strlen(pi.socks5_user_passwd); return nbytes; } int PROXY::socks_prepare_connect_req(char *buf, int ns_port, int ip_addr, char *domain_name) { int nbytes; char *marker = buf, *p; if (pi.socks_version == SOCKS_VERSION_4) { *marker++ = SOCKS_VERSION_4; *marker++ = 1; // Request connection p = (char*)&ns_port; // to this port for (int i=0;i<2;i++) *marker++ = *p++; p = (char*)&ip_addr; // at this IP address for (int i=0;i<4;i++) *marker++ = *p++; strncpy(marker, pi.socks5_user_name, strlen(pi.socks5_user_name)); nbytes = 1+1+2+4+strlen(pi.socks5_user_name); } else if (pi.socks_version == SOCKS_VERSION_5) { if (strlen(domain_name) > 255) return ERR_SOCKS_UNKNOWN_FAILURE; *marker++ = SOCKS_VERSION_5; *marker++ = 1; // request connection *marker++ = 0; // reserved nbytes = 3; if (strlen(domain_name) > 0) { nbytes += 2+strlen(domain_name); *marker++ = SOCKS5_ADDR_TYPE_DOMAIN_NAME; *marker++ = strlen(domain_name); p = domain_name; for (unsigned int i=0;i