| 1 | #! /bin/sh /usr/share/dpatch/dpatch-run |
| 2 | ## 04_getpeername.dpatch by Nico Golde <nion@debian.org> |
| 3 | ## |
| 4 | ## All lines beginning with `## DP:' are a description of the patch. |
| 5 | ## DP: No description. |
| 6 | |
| 7 | --- a/acconfig.h |
| 8 | +++ b/acconfig.h |
| 9 | @@ -43,6 +43,9 @@ allows socksified DNS */ |
| 10 | /* Prototype and function header for close function */ |
| 11 | #undef CLOSE_SIGNATURE |
| 12 | |
| 13 | +/* Prototype and function header for getpeername function */ |
| 14 | +#undef GETPEERNAME_SIGNATURE |
| 15 | + |
| 16 | /* Work out which function we have for conversion from string IPs to |
| 17 | numerical ones */ |
| 18 | #undef HAVE_INET_ADDR |
| 19 | --- a/config.h.in |
| 20 | +++ b/config.h.in |
| 21 | @@ -46,6 +46,9 @@ allows socksified DNS */ |
| 22 | /* Prototype and function header for close function */ |
| 23 | #undef CLOSE_SIGNATURE |
| 24 | |
| 25 | +/* Prototype and function header for close function */ |
| 26 | +#undef GETPEERNAME_SIGNATURE |
| 27 | + |
| 28 | /* Work out which function we have for conversion from string IPs to |
| 29 | numerical ones */ |
| 30 | #undef HAVE_INET_ADDR |
| 31 | --- a/configure |
| 32 | +++ b/configure |
| 33 | @@ -2225,14 +2225,60 @@ cat >> confdefs.h <<EOF |
| 34 | EOF |
| 35 | |
| 36 | |
| 37 | + |
| 38 | +echo $ac_n "checking for correct getpeername prototype""... $ac_c" 1>&6 |
| 39 | +echo "configure:2231: checking for correct getpeername prototype" >&5 |
| 40 | +PROTO= |
| 41 | +PROTO1='int __fd, const struct sockaddr * __name, int *__namelen' |
| 42 | +PROTO2='int __fd, const struct sockaddr_in * __name, socklen_t *__namelen' |
| 43 | +PROTO3='int __fd, struct sockaddr * __name, socklen_t *__namelen' |
| 44 | +PROTO4='int __fd, const struct sockaddr * __name, socklen_t *__namelen' |
| 45 | +for testproto in "${PROTO1}" \ |
| 46 | + "${PROTO2}" \ |
| 47 | + "${PROTO3}" \ |
| 48 | + "${PROTO4}" |
| 49 | +do |
| 50 | + if test "${PROTO}" = ""; then |
| 51 | + cat > conftest.$ac_ext <<EOF |
| 52 | +#line 2244 "configure" |
| 53 | +#include "confdefs.h" |
| 54 | + |
| 55 | + #include <sys/socket.h> |
| 56 | + int getpeername($testproto); |
| 57 | + |
| 58 | +int main() { |
| 59 | + |
| 60 | +; return 0; } |
| 61 | +EOF |
| 62 | +if { (eval echo configure:2254: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then |
| 63 | + rm -rf conftest* |
| 64 | + PROTO="$testproto"; |
| 65 | +else |
| 66 | + echo "configure: failed program was:" >&5 |
| 67 | + cat conftest.$ac_ext >&5 |
| 68 | +fi |
| 69 | +rm -f conftest* |
| 70 | + fi |
| 71 | +done |
| 72 | +if test "${PROTO}" = ""; then |
| 73 | + { echo "configure: error: "no match found!"" 1>&2; exit 1; } |
| 74 | +fi |
| 75 | +echo "$ac_t""getpeername(${PROTO})" 1>&6 |
| 76 | +cat >> confdefs.h <<EOF |
| 77 | +#define GETPEERNAME_SIGNATURE ${PROTO} |
| 78 | +EOF |
| 79 | + |
| 80 | + |
| 81 | + |
| 82 | + |
| 83 | echo $ac_n "checking for correct poll prototype""... $ac_c" 1>&6 |
| 84 | -echo "configure:2230: checking for correct poll prototype" >&5 |
| 85 | +echo "configure:2276: checking for correct poll prototype" >&5 |
| 86 | PROTO= |
| 87 | for testproto in 'struct pollfd *ufds, unsigned long nfds, int timeout' |
| 88 | do |
| 89 | if test "${PROTO}" = ""; then |
| 90 | cat > conftest.$ac_ext <<EOF |
| 91 | -#line 2236 "configure" |
| 92 | +#line 2282 "configure" |
| 93 | #include "confdefs.h" |
| 94 | |
| 95 | #include <sys/poll.h> |
| 96 | @@ -2242,7 +2288,7 @@ int main() { |
| 97 | |
| 98 | ; return 0; } |
| 99 | EOF |
| 100 | -if { (eval echo configure:2246: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then |
| 101 | +if { (eval echo configure:2292: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then |
| 102 | rm -rf conftest* |
| 103 | PROTO="$testproto"; |
| 104 | else |
| 105 | --- a/configure.in |
| 106 | +++ b/configure.in |
| 107 | @@ -309,6 +309,34 @@ fi |
| 108 | AC_MSG_RESULT([close(${PROTO})]) |
| 109 | AC_DEFINE_UNQUOTED(CLOSE_SIGNATURE, [${PROTO}]) |
| 110 | |
| 111 | + |
| 112 | +dnl Find the correct getpeername prototype on this machine |
| 113 | +AC_MSG_CHECKING(for correct getpeername prototype) |
| 114 | +PROTO= |
| 115 | +PROTO1='int __fd, const struct sockaddr * __name, int *__namelen' |
| 116 | +PROTO2='int __fd, const struct sockaddr_in * __name, socklen_t *__namelen' |
| 117 | +PROTO3='int __fd, struct sockaddr * __name, socklen_t *__namelen' |
| 118 | +PROTO4='int __fd, const struct sockaddr * __name, socklen_t *__namelen' |
| 119 | +for testproto in "${PROTO1}" \ |
| 120 | + "${PROTO2}" \ |
| 121 | + "${PROTO3}" \ |
| 122 | + "${PROTO4}" |
| 123 | +do |
| 124 | + if test "${PROTO}" = ""; then |
| 125 | + AC_TRY_COMPILE([ |
| 126 | + #include <sys/socket.h> |
| 127 | + int getpeername($testproto); |
| 128 | + ],,[PROTO="$testproto";],) |
| 129 | + fi |
| 130 | +done |
| 131 | +if test "${PROTO}" = ""; then |
| 132 | + AC_MSG_ERROR("no match found!") |
| 133 | +fi |
| 134 | +AC_MSG_RESULT([getpeername(${PROTO})]) |
| 135 | +AC_DEFINE_UNQUOTED(GETPEERNAME_SIGNATURE, [${PROTO}]) |
| 136 | + |
| 137 | + |
| 138 | + |
| 139 | dnl Find the correct poll prototype on this machine |
| 140 | AC_MSG_CHECKING(for correct poll prototype) |
| 141 | PROTO= |
| 142 | --- a/tsocks.c |
| 143 | +++ b/tsocks.c |
| 144 | @@ -62,6 +62,7 @@ static int (*realconnect)(CONNECT_SIGNAT |
| 145 | static int (*realselect)(SELECT_SIGNATURE); |
| 146 | static int (*realpoll)(POLL_SIGNATURE); |
| 147 | static int (*realclose)(CLOSE_SIGNATURE); |
| 148 | +static int (*realgetpeername)(GETPEERNAME_SIGNATURE); |
| 149 | static struct parsedfile *config; |
| 150 | static struct connreq *requests = NULL; |
| 151 | static int suid = 0; |
| 152 | @@ -73,6 +74,7 @@ int connect(CONNECT_SIGNATURE); |
| 153 | int select(SELECT_SIGNATURE); |
| 154 | int poll(POLL_SIGNATURE); |
| 155 | int close(CLOSE_SIGNATURE); |
| 156 | +int getpeername(GETPEERNAME_SIGNATURE); |
| 157 | #ifdef USE_SOCKS_DNS |
| 158 | int res_init(void); |
| 159 | #endif |
| 160 | @@ -109,14 +111,15 @@ void _init(void) { |
| 161 | /* most programs that are run won't use our services, so */ |
| 162 | /* we do our general initialization on first call */ |
| 163 | |
| 164 | - /* Determine the logging level */ |
| 165 | - suid = (getuid() != geteuid()); |
| 166 | + /* Determine the logging level */ |
| 167 | + suid = (getuid() != geteuid()); |
| 168 | |
| 169 | #ifndef USE_OLD_DLSYM |
| 170 | realconnect = dlsym(RTLD_NEXT, "connect"); |
| 171 | realselect = dlsym(RTLD_NEXT, "select"); |
| 172 | realpoll = dlsym(RTLD_NEXT, "poll"); |
| 173 | realclose = dlsym(RTLD_NEXT, "close"); |
| 174 | + realgetpeername = dlsym(RTLD_NEXT, "getpeername"); |
| 175 | #ifdef USE_SOCKS_DNS |
| 176 | realresinit = dlsym(RTLD_NEXT, "res_init"); |
| 177 | #endif |
| 178 | @@ -125,14 +128,15 @@ void _init(void) { |
| 179 | realconnect = dlsym(lib, "connect"); |
| 180 | realselect = dlsym(lib, "select"); |
| 181 | realpoll = dlsym(lib, "poll"); |
| 182 | + realgetpeername = dlsym(lib, "getpeername"); |
| 183 | #ifdef USE_SOCKS_DNS |
| 184 | realresinit = dlsym(lib, "res_init"); |
| 185 | #endif |
| 186 | - dlclose(lib); |
| 187 | + dlclose(lib); |
| 188 | |
| 189 | lib = dlopen(LIBC, RTLD_LAZY); |
| 190 | - realclose = dlsym(lib, "close"); |
| 191 | - dlclose(lib); |
| 192 | + realclose = dlsym(lib, "close"); |
| 193 | + dlclose(lib); |
| 194 | #endif |
| 195 | } |
| 196 | |
| 197 | @@ -350,8 +354,10 @@ int select(SELECT_SIGNATURE) { |
| 198 | |
| 199 | /* If we're not currently managing any requests we can just |
| 200 | * leave here */ |
| 201 | - if (!requests) |
| 202 | + if (!requests) { |
| 203 | + show_msg(MSGDEBUG, "No requests waiting, calling real select\n"); |
| 204 | return(realselect(n, readfds, writefds, exceptfds, timeout)); |
| 205 | + } |
| 206 | |
| 207 | get_environment(); |
| 208 | |
| 209 | @@ -705,6 +711,50 @@ int close(CLOSE_SIGNATURE) { |
| 210 | return(rc); |
| 211 | } |
| 212 | |
| 213 | +/* If we are not done setting up the connection yet, return |
| 214 | + * -1 and ENOTCONN, otherwise call getpeername |
| 215 | + * |
| 216 | + * This is necessary since some applications, when using non-blocking connect, |
| 217 | + * (like ircII) use getpeername() to find out if they are connected already. |
| 218 | + * |
| 219 | + * This results in races sometimes, where the client sends data to the socket |
| 220 | + * before we are done with the socks connection setup. Another solution would |
| 221 | + * be to intercept send(). |
| 222 | + * |
| 223 | + * This could be extended to actually set the peername to the peer the |
| 224 | + * client application has requested, but not for now. |
| 225 | + * |
| 226 | + * PP, Sat, 27 Mar 2004 11:30:23 +0100 |
| 227 | + */ |
| 228 | +int getpeername(GETPEERNAME_SIGNATURE) { |
| 229 | + struct connreq *conn; |
| 230 | + int rc; |
| 231 | + |
| 232 | + if (realgetpeername == NULL) { |
| 233 | + show_msg(MSGERR, "Unresolved symbol: getpeername\n"); |
| 234 | + return(-1); |
| 235 | + } |
| 236 | + |
| 237 | + show_msg(MSGDEBUG, "Call to getpeername for fd %d\n", __fd); |
| 238 | + |
| 239 | + |
| 240 | + rc = realgetpeername(__fd, __name, __namelen); |
| 241 | + if (rc == -1) |
| 242 | + return rc; |
| 243 | + |
| 244 | + /* Are we handling this connect? */ |
| 245 | + if ((conn = find_socks_request(__fd, 1))) { |
| 246 | + /* While we are at it, we might was well try to do something useful */ |
| 247 | + handle_request(conn); |
| 248 | + |
| 249 | + if (conn->state != DONE) { |
| 250 | + errno = ENOTCONN; |
| 251 | + return(-1); |
| 252 | + } |
| 253 | + } |
| 254 | + return rc; |
| 255 | +} |
| 256 | + |
| 257 | static struct connreq *new_socks_request(int sockid, struct sockaddr_in *connaddr, |
| 258 | struct sockaddr_in *serveraddr, |
| 259 | struct serverent *path) { |
| 260 | @@ -854,7 +904,7 @@ static int connect_server(struct connreq |
| 261 | sizeof(conn->serveraddr)); |
| 262 | |
| 263 | show_msg(MSGDEBUG, "Connect returned %d, errno is %d\n", rc, errno); |
| 264 | - if (rc) { |
| 265 | + if (rc) { |
| 266 | if (errno != EINPROGRESS) { |
| 267 | show_msg(MSGERR, "Error %d attempting to connect to SOCKS " |
| 268 | "server (%s)\n", errno, strerror(errno)); |