#! /bin/sh /usr/share/dpatch/dpatch-run
## 04_getpeername.dpatch by Nico Golde <nion@debian.org>
##
## All lines beginning with `## DP:' are a description of the patch.
## DP: No description.
@DPATCH@
diff -urNad tsocks-1.8beta5~/acconfig.h tsocks-1.8beta5/acconfig.h
--- tsocks-1.8beta5~/acconfig.h 2002-05-18 06:59:38.000000000 +0200
+++ tsocks-1.8beta5/acconfig.h 2007-04-02 20:05:30.000000000 +0200
@@ -43,6 +43,9 @@
/* Prototype and function header for close function */
#undef CLOSE_SIGNATURE
+/* Prototype and function header for getpeername function */
+#undef GETPEERNAME_SIGNATURE
+
/* Work out which function we have for conversion from string IPs to
numerical ones */
#undef HAVE_INET_ADDR
diff -urNad tsocks-1.8beta5~/config.h.in tsocks-1.8beta5/config.h.in
--- tsocks-1.8beta5~/config.h.in 2002-05-18 06:59:42.000000000 +0200
+++ tsocks-1.8beta5/config.h.in 2007-04-02 20:05:30.000000000 +0200
@@ -46,6 +46,9 @@
/* Prototype and function header for close function */
#undef CLOSE_SIGNATURE
+/* Prototype and function header for close function */
+#undef GETPEERNAME_SIGNATURE
+
/* Work out which function we have for conversion from string IPs to
numerical ones */
#undef HAVE_INET_ADDR
diff -urNad tsocks-1.8beta5~/configure tsocks-1.8beta5/configure
--- tsocks-1.8beta5~/configure 2002-07-16 00:51:08.000000000 +0200
+++ tsocks-1.8beta5/configure 2007-04-02 20:05:30.000000000 +0200
@@ -2225,14 +2225,60 @@
EOF
+
+echo $ac_n "checking for correct getpeername prototype""... $ac_c" 1>&6
+echo "configure:2231: checking for correct getpeername prototype" >&5
+PROTO=
+PROTO1='int __fd, const struct sockaddr * __name, int *__namelen'
+PROTO2='int __fd, const struct sockaddr_in * __name, socklen_t *__namelen'
+PROTO3='int __fd, struct sockaddr * __name, socklen_t *__namelen'
+PROTO4='int __fd, const struct sockaddr * __name, socklen_t *__namelen'
+for testproto in "${PROTO1}" \
+ "${PROTO2}" \
+ "${PROTO3}" \
+ "${PROTO4}"
+do
+ if test "${PROTO}" = ""; then
+ cat > conftest.$ac_ext <<EOF
+#line 2244 "configure"
+#include "confdefs.h"
+
+ #include <sys/socket.h>
+ int getpeername($testproto);
+
+int main() {
+
+; return 0; }
+EOF
+if { (eval echo configure:2254: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ PROTO="$testproto";
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+fi
+rm -f conftest*
+ fi
+done
+if test "${PROTO}" = ""; then
+ { echo "configure: error: "no match found!"" 1>&2; exit 1; }
+fi
+echo "$ac_t""getpeername(${PROTO})" 1>&6
+cat >> confdefs.h <<EOF
+#define GETPEERNAME_SIGNATURE ${PROTO}
+EOF
+
+
+
+
echo $ac_n "checking for correct poll prototype""... $ac_c" 1>&6
-echo "configure:2230: checking for correct poll prototype" >&5
+echo "configure:2276: checking for correct poll prototype" >&5
PROTO=
for testproto in 'struct pollfd *ufds, unsigned long nfds, int timeout'
do
if test "${PROTO}" = ""; then
cat > conftest.$ac_ext <<EOF
-#line 2236 "configure"
+#line 2282 "configure"
#include "confdefs.h"
#include <sys/poll.h>
@@ -2242,7 +2288,7 @@
; return 0; }
EOF
-if { (eval echo configure:2246: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:2292: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
PROTO="$testproto";
else
diff -urNad tsocks-1.8beta5~/configure.in tsocks-1.8beta5/configure.in
--- tsocks-1.8beta5~/configure.in 2002-07-16 00:51:03.000000000 +0200
+++ tsocks-1.8beta5/configure.in 2007-04-02 20:05:30.000000000 +0200
@@ -309,6 +309,34 @@
AC_MSG_RESULT([close(${PROTO})])
AC_DEFINE_UNQUOTED(CLOSE_SIGNATURE, [${PROTO}])
+
+dnl Find the correct getpeername prototype on this machine
+AC_MSG_CHECKING(for correct getpeername prototype)
+PROTO=
+PROTO1='int __fd, const struct sockaddr * __name, int *__namelen'
+PROTO2='int __fd, const struct sockaddr_in * __name, socklen_t *__namelen'
+PROTO3='int __fd, struct sockaddr * __name, socklen_t *__namelen'
+PROTO4='int __fd, const struct sockaddr * __name, socklen_t *__namelen'
+for testproto in "${PROTO1}" \
+ "${PROTO2}" \
+ "${PROTO3}" \
+ "${PROTO4}"
+do
+ if test "${PROTO}" = ""; then
+ AC_TRY_COMPILE([
+ #include <sys/socket.h>
+ int getpeername($testproto);
+ ],,[PROTO="$testproto";],)
+ fi
+done
+if test "${PROTO}" = ""; then
+ AC_MSG_ERROR("no match found!")
+fi
+AC_MSG_RESULT([getpeername(${PROTO})])
+AC_DEFINE_UNQUOTED(GETPEERNAME_SIGNATURE, [${PROTO}])
+
+
+
dnl Find the correct poll prototype on this machine
AC_MSG_CHECKING(for correct poll prototype)
PROTO=
diff -urNad tsocks-1.8beta5~/tsocks.c tsocks-1.8beta5/tsocks.c
--- tsocks-1.8beta5~/tsocks.c 2002-07-16 00:50:52.000000000 +0200
+++ tsocks-1.8beta5/tsocks.c 2007-04-02 20:05:30.000000000 +0200
@@ -62,6 +62,7 @@
static int (*realselect)(SELECT_SIGNATURE);
static int (*realpoll)(POLL_SIGNATURE);
static int (*realclose)(CLOSE_SIGNATURE);
+static int (*realgetpeername)(GETPEERNAME_SIGNATURE);
static struct parsedfile *config;
static struct connreq *requests = NULL;
static int suid = 0;
@@ -73,6 +74,7 @@
int select(SELECT_SIGNATURE);
int poll(POLL_SIGNATURE);
int close(CLOSE_SIGNATURE);
+int getpeername(GETPEERNAME_SIGNATURE);
#ifdef USE_SOCKS_DNS
int res_init(void);
#endif
@@ -109,14 +111,15 @@
/* most programs that are run won't use our services, so */
/* we do our general initialization on first call */
- /* Determine the logging level */
- suid = (getuid() != geteuid());
+ /* Determine the logging level */
+ suid = (getuid() != geteuid());
#ifndef USE_OLD_DLSYM
realconnect = dlsym(RTLD_NEXT, "connect");
realselect = dlsym(RTLD_NEXT, "select");
realpoll = dlsym(RTLD_NEXT, "poll");
realclose = dlsym(RTLD_NEXT, "close");
+ realgetpeername = dlsym(RTLD_NEXT, "getpeername");
#ifdef USE_SOCKS_DNS
realresinit = dlsym(RTLD_NEXT, "res_init");
#endif
@@ -125,14 +128,15 @@
realconnect = dlsym(lib, "connect");
realselect = dlsym(lib, "select");
realpoll = dlsym(lib, "poll");
+ realgetpeername = dlsym(lib, "getpeername");
#ifdef USE_SOCKS_DNS
realresinit = dlsym(lib, "res_init");
#endif
- dlclose(lib);
+ dlclose(lib);
lib = dlopen(LIBC, RTLD_LAZY);
- realclose = dlsym(lib, "close");
- dlclose(lib);
+ realclose = dlsym(lib, "close");
+ dlclose(lib);
#endif
}
@@ -348,8 +352,10 @@
/* If we're not currently managing any requests we can just
* leave here */
- if (!requests)
+ if (!requests) {
+ show_msg(MSGDEBUG, "No requests waiting, calling real select\n");
return(realselect(n, readfds, writefds, exceptfds, timeout));
+ }
get_environment();
@@ -703,6 +709,50 @@
return(rc);
}
+/* If we are not done setting up the connection yet, return
+ * -1 and ENOTCONN, otherwise call getpeername
+ *
+ * This is necessary since some applications, when using non-blocking connect,
+ * (like ircII) use getpeername() to find out if they are connected already.
+ *
+ * This results in races sometimes, where the client sends data to the socket
+ * before we are done with the socks connection setup. Another solution would
+ * be to intercept send().
+ *
+ * This could be extended to actually set the peername to the peer the
+ * client application has requested, but not for now.
+ *
+ * PP, Sat, 27 Mar 2004 11:30:23 +0100
+ */
+int getpeername(GETPEERNAME_SIGNATURE) {
+ struct connreq *conn;
+ int rc;
+
+ if (realgetpeername == NULL) {
+ show_msg(MSGERR, "Unresolved symbol: getpeername\n");
+ return(-1);
+ }
+
+ show_msg(MSGDEBUG, "Call to getpeername for fd %d\n", __fd);
+
+
+ rc = realgetpeername(__fd, __name, __namelen);
+ if (rc == -1)
+ return rc;
+
+ /* Are we handling this connect? */
+ if ((conn = find_socks_request(__fd, 1))) {
+ /* While we are at it, we might was well try to do something useful */
+ handle_request(conn);
+
+ if (conn->state != DONE) {
+ errno = ENOTCONN;
+ return(-1);
+ }
+ }
+ return rc;
+}
+
static struct connreq *new_socks_request(int sockid, struct sockaddr_in *connaddr,
struct sockaddr_in *serveraddr,
struct serverent *path) {
@@ -852,7 +902,7 @@
sizeof(conn->serveraddr));
show_msg(MSGDEBUG, "Connect returned %d, errno is %d\n", rc, errno);
- if (rc) {
+ if (rc) {
if (errno != EINPROGRESS) {
show_msg(MSGERR, "Error %d attempting to connect to SOCKS "
"server (%s)\n", errno, strerror(errno));