You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

269 lines
8.0 KiB

#! /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.
--- a/acconfig.h
+++ b/acconfig.h
@@ -43,6 +43,9 @@ allows socksified DNS */
/* 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
--- a/config.h.in
+++ b/config.h.in
@@ -46,6 +46,9 @@ allows socksified DNS */
/* 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
--- a/configure
+++ b/configure
@@ -2225,14 +2225,60 @@ cat >> confdefs.h <<EOF
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 @@ int main() {
; 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
--- a/configure.in
+++ b/configure.in
@@ -309,6 +309,34 @@ fi
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=
--- a/tsocks.c
+++ b/tsocks.c
@@ -62,6 +62,7 @@ static int (*realconnect)(CONNECT_SIGNAT
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 connect(CONNECT_SIGNATURE);
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 @@ void _init(void) {
/* 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 @@ void _init(void) {
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
}
@@ -350,8 +354,10 @@ int select(SELECT_SIGNATURE) {
/* 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();
@@ -705,6 +711,50 @@ int close(CLOSE_SIGNATURE) {
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) {
@@ -854,7 +904,7 @@ static int connect_server(struct connreq
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));