[PHP-DEV] SOCKS support patch From: Paolo Prandini (prandini <email protected>)
Date: 08/09/01

Quoting Zeev Suraski <zeev <email protected>>:

> This change was my last major TODO item for PHP 4.0.7. At this point,
> we
> should try to get PHP 4.0.7 out the door soon. I suggest we branch
> 4.0.7
> away next Tuesday, and start the QA process. This should give people
> enough time to make any final changes they want to put into 4.0.7.

Would you like SOCKS support to be included in the CVS before the branch?
I enclose the diff file.

Regards,

Paolo Prandini
S.P.E.Sistemi e Progetti Elettronici s.a.s.
Via Liguria 5
I-25125 Brescia (BS)
Tel +39 0302427266
Fax +39 0302449252
Email prandini <email protected>
World Wide Web http://www.spe.it

diff file:

diff -urN php-4.0.6.orig/ext/standard/Makefile.in
php-4.0.6/ext/standard/Makefile.in
--- php-4.0.6.orig/ext/standard/Makefile.in Mon Nov 20 11:05:57 2000
+++ php-4.0.6/ext/standard/Makefile.in Thu Aug 9 11:14:51 2001
@@ -7,7 +7,7 @@
         link.c mail.c math.c md5.c metaphone.c microtime.c pack.c pageinfo.c \
         parsedate.c quot_print.c rand.c reg.c soundex.c string.c scanf.c \
         syslog.c type.c uniqid.c url.c url_scanner.c var.c output.c assert.c \
- strnatcmp.c levenshtein.c incomplete_class.c url_scanner_ex.c \
+ strnatcmp.c levenshtein.c incomplete_class.c url_scanner_ex.c socks.c \
         ftp_fopen_wrapper.c http_fopen_wrapper.c php_fopen_wrapper.c credits.c

 include $(top_srcdir)/build/dynlib.mk
diff -urN php-4.0.6.orig/ext/standard/basic_functions.c
php-4.0.6/ext/standard/basic_functions.c
--- php-4.0.6.orig/ext/standard/basic_functions.c Sun May 20 02:31:45 2001
+++ php-4.0.6/ext/standard/basic_functions.c Thu Aug 9 11:21:32 2001
@@ -644,6 +644,15 @@
         PHP_INI_ENTRY_EX("safe_mode_protected_env_vars",
SAFE_MODE_PROTECTED_ENV_VARS, PHP_INI_SYSTEM,
OnUpdateSafeModeProtectedEnvVars, NULL)
         PHP_INI_ENTRY_EX("safe_mode_allowed_env_vars",
SAFE_MODE_ALLOWED_ENV_VARS, PHP_INI_SYSTEM,
OnUpdateSafeModeAllowedEnvVars, NULL)
         STD_PHP_INI_ENTRY("session.use_trans_sid", "1",
PHP_INI_ALL, OnUpdateBool, use_trans_sid, php_basic_globals,
basic_globals)
+
+ PHP_INI_ENTRY("socks.user","",PHP_INI_ALL,NULL)
+ PHP_INI_ENTRY("socks.pass","",PHP_INI_ALL,NULL)
+ PHP_INI_ENTRY("socks.default_pass","",PHP_INI_SYSTEM,NULL)
+ PHP_INI_ENTRY("socks.default_user","",PHP_INI_SYSTEM,NULL)
+ PHP_INI_ENTRY("socks.server","",PHP_INI_SYSTEM,NULL)
+ PHP_INI_ENTRY("socks.type","4",PHP_INI_SYSTEM,NULL)
+ PHP_INI_ENTRY("socks.port","",PHP_INI_SYSTEM,NULL)
+ PHP_INI_ENTRY("socks.local","",PHP_INI_SYSTEM,NULL)
 PHP_INI_END()

diff -urN php-4.0.6.orig/ext/standard/socks.c php-4.0.6/ext/standard/socks.c
--- php-4.0.6.orig/ext/standard/socks.c Thu Jan 1 01:00:00 1970
+++ php-4.0.6/ext/standard/socks.c Thu Aug 9 11:16:38 2001
@@ -0,0 +1,791 @@
+/*
+
+ phpsocks - an extension to php for use with socks proxies
+ Copyright (C) 2000 Paolo Prandini
+
+ liberally derived from:
+ TSOCKS - Wrapper library for transparent SOCKS
+ Copyright (C) 2000 Shaun Clowes
+
+
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+/* PreProcessor Defines */
+#define DEBUG 1 /* Show error messages? */
+
+/* Header Files */
+#include "php.h"
+#include "php_ini.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <dlfcn.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <pwd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+
+struct socksent {
+ struct in_addr localip;
+ struct in_addr localnet;
+ struct socksent *next;
+};
+
+struct sockaddr_link {
+ struct sockaddr_in ip;
+ struct sockaddr_link *next;
+};
+
+struct sockreq {
+ int8_t version;
+ int8_t command;
+ int16_t dstport;
+ int32_t dstip;
+ /* A null terminated username goes here */
+};
+
+struct sockrep {
+ int8_t version;
+ int8_t result;
+ int16_t ignore1;
+ int32_t ignore2;
+};
+
+/* Global Declarations */
+static struct socksent *localnets = NULL;
+static int initialized = 0;
+static int servertype = 0;
+static int servervalid = 0;
+static unsigned short int sin_port;
+static struct sockaddr_link *servers = NULL;
+static struct sockaddr_link *currentserver = NULL;
+static char *default_user = NULL;
+static char *default_pass = NULL;
+
+/* Exported Function Prototypes */
+int Tconnect (int, __CONST_SOCKADDR_ARG, socklen_t);
+
+/* Private Function Prototypes */
+static int initialize();
+static int read_config();
+static int handle_server(char *);
+static int handle_type(char *);
+static int handle_port(char *);
+static int handle_local(char *);
+static int handle_defuser(char *);
+static int handle_defpass(char *);
+static int is_local(struct in_addr *);
+static int connect_socks(int, struct sockaddr_in *);
+static int connect_socksv4(int, struct sockaddr_in *, struct sockaddr_in
*);
+static int connect_socksv5(int, struct sockaddr_in *, struct sockaddr_in
*);
+static void show_error(char *, ...);
+
+static int initialize () {
+
+ /* Read in the config file */
+ read_config();
+
+ initialized = 1;
+
+ return(0);
+}
+
+static int read_config () {
+
+ int cleardefs = 0;
+ struct sockaddr_link *sal;
+
+ handle_server(INI_STR("socks.server"));
+ handle_port(INI_STR("socks.port"));
+ handle_type(INI_STR("socks.type"));
+ handle_defuser(INI_STR("socks.default_user"));
+ handle_defpass(INI_STR("socks.default_pass"));
+ handle_local(INI_STR("socks.local"));
+
+ /* Always add the 127.0.0.1/255.0.0.0 subnet to local */
+ handle_local("127.0.0.0/255.0.0.0");
+
+ for (sal=servers;sal!=NULL;sal=sal->next)
+ if (is_local(&sal->ip.sin_addr)) {
+ show_error("SOCKS server is not on a local subnet!\n");
+ sal->ip.sin_family=0;
+ } else servervalid=1;
+
+ if (servers == NULL) {
+ show_error("No valid SOCKS server specified in "
+ "configuration file\n");
+ servervalid=0;
+ }
+
+ /* Default to the default SOCKS port */
+ if (sin_port == 0) {
+ sin_port = htons(1080);
+ }
+
+ /* Default to SOCKS V4 */
+ if (servertype == 0) {
+ servertype = 4;
+ }
+
+ if ((default_user != NULL) || (default_pass != NULL)) {
+ /* If the server type is version 4, neither */
+ /* username or password is valid */
+ if (servertype == 4) {
+ show_error("Default username/pass "
+ "only valid for version 5 "
+ "SOCKS servers\n");
+ cleardefs = 1;
+ } else
+ /* If default user and pass not specified */
+ /* together then show an error */
+ if (!((default_user != NULL) &&
+ (default_pass != NULL))) {
+ show_error("Default username and "
+ "pass MUST be specified "
+ "together\n");
+ cleardefs = 1;
+ }
+ if (cleardefs == 1) {
+ if (default_user != NULL) {
+ free(default_user);
+ default_user = NULL;
+ }
+ if (default_pass != NULL) {
+ free(default_user);
+ default_user = NULL;
+ }
+ }
+ }
+
+ return(0);
+}
+
+static int
+handle_server(char *value)
+{
+ struct sockaddr_link *ent;
+ char *ip,*srv;
+
+ while (1) {
+
+ // Process multiple servers delimited by "," symbol
+ srv = strsep(&value, ",");
+ if (srv==NULL) srv=value;
+ if (srv==NULL) break;
+
+ ip = strsep(&srv, " ");
+ if (ip==NULL) break;
+
+ ent=(struct sockaddr_link *)malloc(sizeof(struct sockaddr_link));
+ if (ent==NULL) {
+ /* if we couldn't malloc some storage, leave */
+ exit(-1);
+ }
+ if (!(inet_aton(ip, &ent->ip.sin_addr))) {
+ show_error("The SOCKS server (%s) in configuration "
+ "file is invalid\n", ip);
+ free(ent);
+ } else {
+ /* Construct the addr for the socks server */
+ ent->ip.sin_family = AF_INET; /* host byte order */
+ ent->ip.sin_port = 0;
+ bzero(&(ent->ip.sin_zero), 8);/* zero the rest of the struct */
+ ent->next=servers;
+ servers=ent;
+ }
+ }
+
+ return(0);
+}
+
+static int
+handle_port(char *value)
+{
+
+ if (sin_port != 0) {
+ show_error("Server port may only be specified once "
+ "in configuration file\n");
+ } else {
+ errno = 0;
+ sin_port = (unsigned short int)
+ htons(strtol(value, (char **)NULL, 10));
+ if ((errno != 0) || (sin_port == 0)) {
+ show_error("Invalid server port number "
+ "specified in configuration file "
+ "(%s)\n", value);
+ sin_port = 0;
+ }
+ }
+
+ return(0);
+}
+
+static int
+handle_defuser(char *value)
+{
+
+ if (default_user != NULL) {
+ show_error("Default username may only be specified "
+ "once in configuration file\n");
+ } else {
+ default_user = strdup(value);
+ }
+
+ return(0);
+}
+
+static int
+handle_defpass(char *value)
+{
+
+ if (default_pass != NULL) {
+ show_error("Default password may only be specified "
+ "once in configuration file\n");
+ } else {
+ default_pass = strdup(value);
+ }
+
+ return(0);
+}
+
+static int
+handle_type(char *value)
+{
+
+ if (servertype != 0) {
+ show_error("Server type may only be specified once "
+ "in configuration file\n");
+ } else {
+ errno = 0;
+ servertype = (int) strtol(value, (char **)NULL, 10);
+ if ((errno != 0) || (servertype == 0) ||
+ ((servertype != 4) && (servertype != 5))) {
+ show_error("%d %d\n", errno, servertype);
+ show_error("Invalid server type "
+ "specified in configuration file "
+ "(%s) only 4 or 5 may be "
+ "specified\n", value);
+ servertype = 0;
+ }
+ }
+
+ return(0);
+}
+
+static int
+handle_local(char *value)
+{
+ char *ip;
+ char *subnet;
+ char buf[100];
+ char *split,*net;
+ struct socksent *ent;
+
+ while (1) {
+
+ // Process multiple nets delimited by "," symbol
+ net = strsep(&value, ",");
+ if (net==NULL) net=value;
+ if (net==NULL) break;
+
+ strncpy(buf, net, sizeof(buf) - 1);
+ split = buf;
+ ip = strsep(&split, "/");
+ subnet = strsep(&split, " \n");
+
+ if ((ip == NULL) && (subnet == NULL)) break;
+
+ if ((ip == NULL) || (subnet == NULL)) {
+ show_error("Local network pair (%s) is not validly "
+ "constructed\n", value);
+ return(1);
+ } else {
+ /* Allocate the new entry */
+ if ((ent = (struct socksent *) malloc(sizeof(struct socksent)))
+ == NULL) {
+ /* If we couldn't malloc some storage, leave */
+ exit(-1);
+ }
+
+ if (!(inet_aton(ip, &(ent->localip)))) {
+ show_error("In configuration file IP for local "
+ "network (%s) is not valid\n", ip);
+ free(ent);
+ return(1);
+ }
+ else if ((ent->localnet.s_addr = inet_addr(subnet)) == -1) {
+ show_error("In configuration file SUBNET for "
+ "local network (%s) is not valid\n", ip);
+ free(ent);
+ return(1);
+ }
+ else if ((ent->localip.s_addr &
+ ent->localnet.s_addr) !=
+ ent->localip.s_addr) {
+ show_error("In configuration file IP (%s) & "
+ "SUBNET (%s) != IP. Ignored.\n",
+ ip, subnet);
+ free(ent);
+ continue;
+ } else {
+ /* The entry is valid so add to linked list */
+ ent -> next = localnets;
+ localnets = ent;
+ }
+ }
+ }
+ return(0);
+}
+
+
+static int is_local(struct in_addr *testip) {
+ struct socksent *ent;
+
+ for (ent = localnets; ent != NULL; ent = ent -> next) {
+ if ((testip->s_addr & ent->localnet.s_addr) ==
+ (ent->localip.s_addr & ent->localnet.s_addr)) {
+ return(0);
+ }
+ }
+
+ return(1);
+}
+
+int Tconnect (int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len) {
+ struct sockaddr_in *connaddr;
+ void **kludge;
+ int sock_type = -1;
+ int sock_type_len = sizeof(sock_type);
+
+ /* If we haven't initialized yet, do it now */
+ if (initialized == 0) {
+ initialize();
+ }
+
+ /* Ok, so this method sucks, but it's all I can think of */
+ kludge = (void *) & __addr;
+ connaddr = (struct sockaddr_in *) *kludge;
+
+ /* Get the type of the socket */
+ getsockopt(__fd, SOL_SOCKET, SO_TYPE,
+ (void *) &sock_type, &sock_type_len);
+
+ /* Only try and use socks if the socket is an INET socket, */
+ /* is a TCP stream, isn't on a local subnet and the */
+ /* socks server in the config was valid */
+ if ((connaddr->sin_family != AF_INET) ||
+ (sock_type != SOCK_STREAM) ||
+ (servervalid == 0) ||
+ !(is_local(&(connaddr->sin_addr)))) {
+ return(connect(__fd, __addr, __len));
+ } else {
+ return(connect_socks(__fd, connaddr));
+ }
+
+}
+
+static int connect_socks(int sockid, struct sockaddr_in *connaddr) {
+ int rc = 0;
+ int sockflags;
+ struct sockaddr_link *sal;
+
+ if (currentserver==NULL) currentserver=servers;
+ sal=currentserver;
+
+ do {
+
+ /* Get the flags of the socket, (incase its non blocking */
+ if ((sockflags = fcntl(sockid, F_GETFL)) == -1) {
+ sockflags = 0;
+ }
+
+ /* If the flags show the socket as blocking, set it to */
+ /* blocking for our connection to the socks server */
+ if ((sockflags & O_NONBLOCK) != 0) {
+ fcntl(sockid, F_SETFL, sockflags & (~(O_NONBLOCK)));
+ }
+
+ if (servertype == 4)
+ rc = connect_socksv4(sockid, connaddr, &sal->ip);
+ else
+ rc = connect_socksv5(sockid, connaddr, &sal->ip);
+
+ /* If the socket was in non blocking mode, restore that */
+ if ((sockflags & O_NONBLOCK) != 0) {
+ fcntl(sockid, F_SETFL, sockflags);
+ }
+
+ if (rc==0) break;
+ if (rc==ECONNREFUSED) break;
+
+ sal=sal->next;
+ if (!sal) sal=servers;
+
+ } while (sal!=currentserver);
+
+ if (rc != 0) {
+ errno = rc;
+ return(-1);
+ } else {
+ currentserver=sal;
+ }
+ return(0);
+
+}
+
+static int connect_socksv4(int sockid, struct sockaddr_in *connaddr, struct
sockaddr_in *server) {
+ int rc = 0;
+ int length = 0;
+ char *realreq;
+ struct passwd *user;
+ struct sockreq *thisreq;
+ struct sockrep thisrep;
+ int tmpsock;
+
+ if (server->sin_port==0) server->sin_port=sin_port;
+ if (server->sin_family==0) return ECONNREFUSED;
+
+ /* Determine the current username */
+ user = getpwuid(getuid());
+
+ /* Allocate enough space for the request and the null */
+ /* terminated username */
+ length = sizeof(struct sockreq) +
+ (user == NULL ? 1 : strlen(user->pw_name) + 1);
+ if ((realreq = malloc(length)) == NULL) {
+ /* Could not malloc, bail */
+ exit(1);
+ }
+ thisreq = (struct sockreq *) realreq;
+
+ /* Create the request */
+ thisreq->version = 4;
+ thisreq->command = 1;
+ thisreq->dstport = connaddr->sin_port;
+ thisreq->dstip = connaddr->sin_addr.s_addr;
+
+ /* Copy the username */
+ strcpy(realreq + sizeof(struct sockreq),
+ (user == NULL ? "" : user->pw_name));
+
+ /* open a test socket */
+ tmpsock=socket(AF_INET,SOCK_STREAM,0);
+ if ((rc = connect(tmpsock, (struct sockaddr *) server,
+ sizeof(struct sockaddr_in))) != 0) {
+ show_error("Error %d attempting to test connect to SOCKS "
+ "server %s:%d\n", errno,
+ inet_ntoa(server->sin_addr),
+ ntohs(server->sin_port));
+ close(tmpsock);
+ return(rc);
+ }
+ shutdown(tmpsock,2);
+ close(tmpsock);
+
+ /* Connect this socket to the socks server instead */
+ if ((rc = connect(sockid, (struct sockaddr *) server,
+ sizeof(struct sockaddr_in))) != 0) {
+ show_error("Error %d attempting to connect to SOCKS "
+ "server\n", errno);
+ rc = rc;
+ } else {
+ rc = send(sockid, (void *) thisreq, length,0);
+ if (rc < 0) {
+ show_error("Error %d attempting to send SOCKS "
+ "request\n", errno);
+ rc = rc;
+ } else if ((rc = recv(sockid, (void *) &thisrep,
+ sizeof(struct sockrep), 0)) < 0) {
+ show_error("Error %d attempting to receive SOCKS "
+ "reply\n", errno);
+ rc = ECONNREFUSED;
+ } else if (rc < sizeof(struct sockrep)) {
+ show_error("Short reply from SOCKS server\n");
+ /* Let the application try and see how they */
+ /* go */
+ rc = 0;
+ } else if (thisrep.result == 91) {
+ show_error("SOCKS server refused connection\n");
+ rc = ECONNREFUSED;
+ } else if (thisrep.result == 92) {
+ show_error("SOCKS server refused connection "
+ "because of failed connect to identd "
+ "on this machine\n");
+ rc = ECONNREFUSED;
+ } else if (thisrep.result == 93) {
+ show_error("SOCKS server refused connection "
+ "because identd and this library "
+ "reported different user-ids\n");
+ rc = ECONNREFUSED;
+ } else {
+ rc = 0;
+ }
+ }
+
+ /* Free the SOCKS request storage that was malloced */
+ free(realreq);
+
+ return(rc);
+
+}
+
+static int connect_socksv5(int sockid, struct sockaddr_in *connaddr, struct
sockaddr_in *server) {
+ int rc = 0;
+ int offset = 0;
+ char *verstring = "\x05\x02\x02\x00";
+ char *uname, *upass;
+ struct passwd *nixuser;
+ char buf[200];
+ int tmpsock;
+
+ if (server->sin_port==0) server->sin_port=sin_port;
+ if (server->sin_family==0) return ECONNREFUSED;
+
+ /* open a test socket */
+ tmpsock=socket(AF_INET,SOCK_STREAM,0);
+ if ((rc = connect(tmpsock, (struct sockaddr *) server,
+ sizeof(struct sockaddr_in))) != 0) {
+ show_error("Error %d attempting to test connect to SOCKS "
+ "server %s:%d\n", errno,
+ inet_ntoa(server->sin_addr),
+ ntohs(server->sin_port));
+ close(tmpsock);
+ return(rc);
+ }
+ shutdown(tmpsock,2);
+ close(tmpsock);
+
+ /* Connect this socket to the socks server */
+ if ((rc = connect(sockid, (struct sockaddr *) server,
+ sizeof(struct sockaddr_in))) != 0) {
+ show_error("Error %d attempting to connect to SOCKS "
+ "server %s:%d\n", errno,
+ inet_ntoa(server->sin_addr),
+ ntohs(server->sin_port));
+ return(rc);
+ }
+
+ /* Now send the method negotiation */
+ if ((rc = send(sockid, (void *) verstring, 4,0)) < 0) {
+ show_error("Error %d attempting to send SOCKS "
+ "method negotiation\n", errno);
+ return(rc);
+ }
+
+ /* Now receive the reply as to which method we're using */
+ if ((rc = recv(sockid, (void *) buf, 2, 0)) < 0) {
+ show_error("Error %d attempting to receive SOCKS "
+ "method negotiation reply\n", errno);
+ rc = ECONNREFUSED;
+ return(rc);
+ }
+
+ if (rc < 2) {
+ show_error("Short reply from SOCKS server\n");
+ rc = ECONNREFUSED;
+ return(rc);
+ }
+
+ /* See if we offered an acceptable method */
+ if (buf[1] == '\xff') {
+ show_error("SOCKS server refused authentication methods\n");
+ rc = ECONNREFUSED;
+ return(rc);
+ }
+
+ /* If the socks server chose username/password authentication */
+ /* (method 2) then do that */
+ if ((unsigned short int) buf[1] == 2) {
+
+ /* Determine the current *nix username */
+ nixuser = getpwuid(getuid());
+
+ if (
+ ( strlen(uname = INI_STR("socks.user")) == 0) &&
+ ((uname = getenv("TSOCKS_USERNAME")) == NULL) &&
+ ((uname = default_user) == NULL) &&
+ ((uname = (nixuser == NULL ? NULL : nixuser->pw_name)) == NULL)) {
+ show_error("Could not get SOCKS username from "
+ "local passwd file, php.ini "
+ "or $TSOCKS_USERNAME to authenticate "
+ "with");
+ rc = ECONNREFUSED;
+ return(rc);
+ }
+
+ if (
+ ( strlen(upass = INI_STR("socks.pass")) == 0) &&
+ ((upass = getenv("TSOCKS_PASSWORD")) == NULL) &&
+ ((upass = default_pass) == NULL)) {
+ show_error("Need a password in php.ini or "
+ "$TSOCKS_PASSWORD to authenticate with");
+ rc = ECONNREFUSED;
+ return(rc);
+ }
+
+ offset = 0;
+ buf[offset] = '\x01';
+ offset++;
+ buf[offset] = (int8_t) strlen(uname);
+ offset++;
+ memcpy(&buf[offset], uname, strlen(uname));
+ offset = offset + strlen(uname);
+ buf[offset] = (int8_t) strlen(upass);
+ offset++;
+ memcpy(&buf[offset], upass, strlen(upass));
+ offset = offset + strlen(upass);
+
+ /* Send out the authentication */
+ if ((rc = send(sockid, (void *) buf, offset,0)) < 0) {
+ show_error("Error %d attempting to send SOCKS "
+ "authentication\n", errno);
+ return(rc);
+ }
+
+
+ /* Receive the authentication response */
+ if ((rc = recv(sockid, (void *) buf, 2, 0)) < 0) {
+ show_error("Error %d attempting to receive SOCKS "
+ "authentication reply\n", errno);
+ rc = ECONNREFUSED;
+ return(rc);
+ }
+
+ if (rc < 2) {
+ show_error("Short reply from SOCKS server\n");
+ rc = ECONNREFUSED;
+ return(rc);
+ }
+
+ if (buf[1] != '\x00') {
+ show_error("SOCKS authentication failed, "
+ "check username and password\n");
+ rc = ECONNREFUSED;
+ return(rc);
+ }
+
+ }
+
+ /* Now send the connect */
+ buf[0] = '\x05'; /* Version 5 SOCKS */
+ buf[1] = '\x01'; /* Connect request */
+ buf[2] = '\x00'; /* Reserved */
+ buf[3] = '\x01'; /* IP version 4 */
+ memcpy(&buf[4], &connaddr->sin_addr.s_addr, 4);
+ memcpy(&buf[8], &connaddr->sin_port, 2);
+
+ /* Now send the connection */
+ if ((rc = send(sockid, (void *) buf, 10,0)) < 0) {
+ show_error("Error %d attempting to send SOCKS "
+ "connect command\n", errno);
+ return(rc);
+ }
+
+ /* Now receive the reply to see if we connected */
+ if ((rc = recv(sockid, (void *) buf, 10, 0)) < 0) {
+ show_error("Error %d attempting to receive SOCKS "
+ "connection reply\n", errno);
+ rc = ECONNREFUSED;
+ return(rc);
+ }
+
+ if (rc < 10) {
+ show_error("Short reply from SOCKS server\n");
+ rc = ECONNREFUSED;
+ return(rc);
+ }
+
+ /* See the connection succeeded */
+ if (buf[1] != '\x00') {
+ show_error("SOCKS connect failed: ");
+ switch ((int8_t) buf[1]) {
+ case 1:
+ show_error("General SOCKS server failure\n");
+ return(ECONNABORTED);
+ case 2:
+ show_error("Connection denied by rule\n");
+ return(ECONNABORTED);
+ case 3:
+ show_error("Network unreachable\n");
+ return(ENETUNREACH);
+ case 4:
+ show_error("Host unreachable\n");
+ return(EHOSTUNREACH);
+ case 5:
+ show_error("Connection refused\n");
+ return(ECONNREFUSED);
+ case 6:
+ show_error("TTL Expired\n");
+ return(ETIMEDOUT);
+ case 7:
+ show_error("Command not supported\n");
+ return(ECONNABORTED);
+ case 8:
+ show_error("Address type not supported\n");
+ return(ECONNABORTED);
+ default:
+ show_error("Unknown error\n");
+ return(ECONNABORTED);
+ }
+ }
+
+ return(0);
+
+}
+
+static void show_error(char *fmt, ...) {
+#ifdef DEBUG
+ va_list ap;
+ int saveerr;
+ char *newfmt;
+ FILE *fp;
+ char MYNAME[]= "phpsocks: ";
+
+ if ((newfmt = malloc(strlen(fmt) + strlen(MYNAME) + 1)) == NULL) {
+ /* Could not malloc, bail */
+ exit(1);
+ }
+
+ strcpy(newfmt, MYNAME);
+ strcpy(newfmt + strlen(MYNAME), fmt);
+
+ va_start(ap, fmt);
+
+ /* Save errno */
+ saveerr = errno;
+
+ fp=fopen("/tmp/sock.log","a");
+ if (fp!=NULL) {
+ vfprintf(fp, newfmt, ap);
+ fclose(fp);
+ }
+
+ errno = saveerr;
+
+ va_end(ap);
+
+ free(newfmt);
+#endif
+}
+
diff -urN php-4.0.6.orig/main/network.c php-4.0.6/main/network.c
--- php-4.0.6.orig/main/network.c Sat May 5 20:36:20 2001
+++ php-4.0.6/main/network.c Thu Aug 9 11:24:27 2001
@@ -209,13 +209,13 @@

         if (timeout == NULL) {
                 /* blocking mode */
- return connect(sockfd, addr, addrlen);
+ return Tconnect(sockfd, addr, addrlen);
         }

         flags = fcntl(sockfd, F_GETFL, 0);
         fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);

- if ((n = connect(sockfd, addr, addrlen)) < 0) {
+ if ((n = Tconnect(sockfd, addr, addrlen)) < 0) {
                 if (errno != EINPROGRESS) {
                         return -1;
                 }
@@ -257,7 +257,7 @@
         }
         return ret;
 #else /* !defined(PHP_WIN32) && ... */
- return connect(sockfd, addr, addrlen);
+ return Tconnect(sockfd, addr, addrlen);
 #endif
 }
 /* }}} */

-- 
PHP Development Mailing List <http://www.php.net/>
To unsubscribe, e-mail: php-dev-unsubscribe <email protected>
For additional commands, e-mail: php-dev-help <email protected>
To contact the list administrators, e-mail: php-list-admin <email protected>