tsocks (1.8beta5-9.1) 04_getpeername

Summary

 acconfig.h   |    3 ++
 config.h.in  |    3 ++
 configure    |   52 +++++++++++++++++++++++++++++++++++++++++++++--
 configure.in |   28 +++++++++++++++++++++++++
 tsocks.c     |   64 ++++++++++++++++++++++++++++++++++++++++++++++++++++-------
 5 files changed, 140 insertions(+), 10 deletions(-)

    
download this patch

Patch contents

#! /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));