** Socks-Trans Patch ** This file is a patch for SOCKS-based IPv6/IPv4 Translator (Socks-Trans) version 1.3. To apply this patch, you should go to the top directory of socks5-v1.0r10 source tree (where INSTALL and README reside), then do: patch -p < thisFile The building process of Socks Translator is similar to the original Socks5 except that there are several new configuration options. See README.trans included in this patch for details. Please note that Socks5 Translator has somewhat more restrictive license than the original Socks5. Please refer Copyright.trans, which is also included in this patch, for details. Index: Copyright.trans diff -c /dev/null src/socks5/Copyright.trans:1.1.2.4 *** Copyright.trans Fri Aug 20 14:27:13 1999 --- Copyright.trans Mon Aug 16 09:54:22 1999 *************** *** 0 **** --- 1,122 ---- + Copyright (C) 1998 NEC Corporation. All rights reserved. + + License Agreement + + NEC Corporation ("NEC") hereby grants you the use of SOCKS-based + IPv6/IPv4 Translator system (Socks-Trans) version 1.3 ("Software") in + source or binary forms, subject to the following terms and conditions: + + 1. Software + + You acknowledge that the Software is a Beta version which is still + under development and may contain bugs. While NEC intends to + distribute a commercial release of the Software, NEC reserves the + right at any time not to release a commercial release of the Software + or if released, to alter prices, features, specifications, + capabilities, functions, licensing terms, general availability or + other characteristics of the commercial release. + + 2. Grant of License + + NEC hereby grants to you a non-transferable, non-exclusive and + royalty-free license to use, reproduce and modify the Software + solely for the purpose of non-commercial and internal research + and/or evaluation. You shall make no other use of the Software, + including internal business use, without prior written approval of + NEC. + + 3. Modifications + + 3.1 In the event that you discover any defect or bug in the Software, + you will notify NEC in writing of such defect/bug in reasonable + detail. + + 3.2 In the event that you modify any part of the Software, including + addition, deletion or any other changes of the Software + ("Modifications"), you will furnish NEC with such Modifications + in source code and its related documentation which describes at + least (i)your name, (ii)the date of any change, and (iii)what + changes you made. NEC may distribute at its discretion the + Modifications with the furnished documentation. + + 3.3 You may distribute the Modifications you made on your own + responsibility, provided that you include documentation in the + Modifications which describes at least (i)your name, (ii)the date + of any change, (iii)what changes you made and (iv)that the + Modification is derived, directly or indirectly, from the Software + owned and distributed by NEC. In this event you shall promptly + notify NEC by what means you distribute the Modifications. + + 3.4 The use of the Modifications shall be subject to the terms and + conditions set forth in this Agreement. You shall not use the + Modifications for any other purposes than non-commercial and + internal research and/or evaluation set forth in above Section 2. + + 4. Restrictions + + You shall not distribute, transfer, rent, lease, or convey any + copies of the Software or any portions thereof to any third party. + + 5. Rights in Software + + NEC retains ownership, copyright or any other rights in the Software + or sequential versions of the Software made by NEC based on your + comments, suggestions, recommendations, Modifications, etc. NEC + will make reference to such contribution in some appropriate + documentation for the Software at the time of release of a sequential + version of the Software. + + 6. Use of name + + The name of NEC or any of its affiliates shall not be used in any + advertising or publicity pertaining to the use or modification of + this Software without the prior express, written consent of NEC. + + 7. Disclaimer of Warranty + + NEC will not be obliged to make error corrections or bug fixes or + provide you any support with regard to the Software. THIS SOFTWARE + IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + SATISFACTORY QUALITY, MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE, NON-INFRINGEMENT OR ARISING FROM A COURSE OF DEALING, USAGE, + TRADE OR PRACTICE. Some jurisdictions do not allow the exclusion + of implied warranties, so the above disclaimer may not apply to you. + IN NO EVENT SHALL NEC OR ANY OF ITS AFFILIATES BE LIABLE FOR ANY + SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + 8. Export Control + + You agree and certify that the Software will not be exported outside + the United States except as authorized and as permitted by the laws + and regulations of the United States. If the Software has been + rightfully obtained outside of the United States, you agree that + you will not re-export the Software, except as permitted by the laws + and regulations of the United States and the laws and regulations + of the jurisdiction in which you obtained the Software. + + 9. Notice to Government End Users. + + If this Software is acquired under the terms of a GSA contract -- + Use, reproduction or disclosure is subject to the restrictions set + forth in the applicable ADP Schedule contract; DoD contract. Use, + duplication or disclosure by the Government is subject to + restrictions set forth in subparagraph (c) (1) (ii) of 252.227- + 7013 Civilian Agency Contract. Use, reproduction, or disclosure is + subject to 52.227-19 (a) through (d) and restrictions set forth in + the accompanying End User License Agreement. + + 10. Termination + + NEC may terminate your license upon notification if you fail to + comply with any of the provisions of this Agreement. In the event + of such termination, you shall immediately destroy all copies, + Modifications or derivative works of the Software. + + 11. Governing Law + + This Agreement shall be governed by the laws of the State of New + York. Index: README.trans diff -c /dev/null src/socks5/README.trans:1.1.2.9 *** README.trans Fri Aug 20 14:27:14 1999 --- README.trans Fri Aug 20 14:19:41 1999 *************** *** 0 **** --- 1,315 ---- + Welcome to the SOCKS-based IPv6/IPv4 Translator world! + + + What is the SOCKS-based IPv6/IPv4 Translator system (Socks-Trans)? + ================================================================== + + Socks-Trans is an advanced SOCKS5 system which has following extended + features: + + + supports IPv6 homogenous communication + + enables a SOCKS server to be used as a translator for + IPv4 and IPv6 mixed heterogenous communications + + The detail of the Socks-Trans are described in following enclosed two + internet-drafts with this package. + + 1. A SOCKS-based IPv6/IPv4 Gateway Mechanism + + 2. SOCKSv5 Protocol Extensions for IPv6/IPv4 Communication Environment + + + + explains the mechanism + of the Socks-Trans. All of described features have been implemented + and verified. + + proposed extensions of current + SOCKSv5 protocol. A part of proposed extensions are implemented. + + Please visit http://www.socks.nec.com/ to see picture supported brief + explanation of the Socks-Trans. + + + Socks-Trans Package + =================== + + Socks-Trans package is a special release. It is a set of patch files + to Socks5-v1.0r9 as a temporary format. From next release, Socks-Trans + package is planed to merge original socks source tree. + + Socks-Trans package has own copyright that is different from original + socks. Please read COPYRIGHT.trans to understand copyright issues. + + + Configuration Parameters + ======================== + + Socks-Trans has following new configuration parameters. For other + parameters, please refer to README and INSTALL documents of original + socks5. + + --enable-ipv6 + Enables IPv6 features. If you omit this option, socks5 tries to + figure out if your system supports IPv6, and enables it automatically + if so. + + --disable-ipv6 + Disables IPv6 feature. Note that this eliminates almost all the + features added to the original socks5. + + --enable-mapped-address + Specifies that your OS supports IPv4-mapped IPv6 address. With this + option, socks5 assumes that you can connect to IPv4 hosts from IPv6 + sockets by specifying so-called IPv4-mapped IPv6 addresses. Since + this feature is described in RFC 2133, and most IPv6 implementations + claim to conform to it, this is the default. + + --disable-mapped-address + Specifies that your OS doesn't support IPv4-mapped IPv6 address. + + --with-ipv6-ping=PATH + Specifies the command name (or pathname) of `ping' program for IPv6. + The default is `ping6'. + + --with-ipv6-traceroute=PATH + Specifies the command name (or pathname) of `traceroute' program for IPv6. + The default is `traceroute6'. + + + Server Configuration File + ========================= + + * A new entry is added to the socks5 server configuration file (socks5.conf). + + filter NAME AUTH CMD SRC-HOST DST-HOST SRC-PORT DST-PORT [USER-LIST] + + NAME Specifies the name of the filter to install. + Currently there is only one filter named `ftpv6', + which translate between normal FTP protocol defined + by RFC 959 and IPv6 enhanced FTP protocol defined + by RFC 1639 (FOOBAR). + + AUTH Specifies list of authentication methods. + It must be a valid authpattern. + + CMD Specifies commands to apply the filter. + It must be a valid commandpattern. + + SRC-HOST Specifies the source or destination host to apply + DST-HOST the filter. It must be a valid hostpattern. + + SRC-PORT Specifies the source or destination port to apply + DST-PORT the filter. It must be a valid portpattern. + + USER-LIST Specifies the list of users to apply the filter. + It must be a valid userpattern. + + See socks5.conf(5) for authpattern, command pattern, etc. + + To enable FTP between IPv4 host and IPv6 host, you should add following + line to your socks5.conf: + + filter ftpv6 - c - - - ftp + + * IPv6 addresses can be specified as hostpattern in the following format: + + ipv6-address/prefix-length + + This matches when the first prefix-len bits of a host IPv6 address + equals to the first prefix-len bits of ipv6-address. For example, + + ::/0 matches to all IPv6 hosts. + fe80::/10 matches to all link-local unicast addresses. + + Note that ipv6-address must be in a valid format. So + + fe80:/10 + + is invalid because `fe80:' is not a valid address specification. + + * Numerical IPv6 address expression can be used in proxypattern by + enclosing it in box brackets as follows: + + socks5 - - 10.1.2.3,[1080::417a],[1080::417b]:1078 + + A colon(:) is used in both a host-port separator and numerical IPv6 + address expression. In order to suppress the ambiguity, box brackets + are necessary to specify numerical IPv6 addresses. + + + Library Configuration File + ========================== + + * Numerical IPv6 address expression can be used in proxypattern by + enclosing it in box brackets. See above for details. + + + Environment Variables + ===================== + + A number of new environment variables are introduced. + + * Variables for Server + + SOCKS5_BINDINTFC_IPV4 [host:port] or [port] + Specifies IPv4 address and port number on which socks5 server runs. + This overrides the setting of SOCKS5_BINDINTFC. + + SOCKS5_BINDINTFC_IPV6 [host:port] or [port] + Specifies IPv6 address and port number on which socks5 server runs. + If host is specified as a numeric address, you must enclose + it with brackets. + This overrides the setting of SOCKS5_BINDINTFC. + + * Variables for Library + + SOCKS5_SERVER_IPV4 [host:port] or [host] + Specifies the default socks5 server when using IPv4 sockets. + This overrides the setting of SOCKS5_SERVER. + + SOCKS5_SERVER_IPV6 [host:port] or [host] + Specifies the default socks5 server when using IPv6 sockets. + If host is specified as a numeric address, you must enclose + it with brackets. + This overrides the setting of SOCKS5_SERVER. + + SOCKS5_ACCEPT_BOTH_AF + If defined, socks5 library assumes the application can handle + both IPv4 and IPv6 addresses, and always return true addresses. + This means, for example, you may get IPv6 address as the result + of getsockname() to IPv4 socket, and vice versa. + The default behavior is to always return address in the same + address family (thus it may not be correct, but your application + won't be astonished by seeing totally unexpected address data). + + + Supported IPv6 Implementation Platforms + ======================================= + + Socks-Trans does NOT depend on IPv6 implementation platforms basically, + because it is an application level program. The Socks-Trans should + work on any IPv6 implementation platforms. + + Each IPv6 implementations has small variety, because detail of the + specification for IPv6 implementation has not completed yet. + + For example, there is no standard method to get IP address information + of a network interface by its logical name. This fact cause following + restrictions to run the Socks-Trans on any implementation platforms. + + + Network interface cannot be specified by name in `interface' lines + in the server configuration file (socks5.conf). It must be + specified by numerical address instead. + + When you connect to hosts on the same subnet, your application + may connect via socks5 server instead of direct connection. + This behavior is similar to original socks5's behavior where + SOCKS5_NONETMASKCHECK is set. + + In order to remove the constrains, implementation-dependent code must + be introduces. Currently, the Socks-Trans has already introduced + implementation dependent code for FreeBSD 2.2.x + KAME IPv6, and it has + verified. + + To run the Socks-Trans without restrictions on the other platforms, + Please see next section for detail. + + + Porting to Other IPv6 Implementation Platforms + ============================================== + + The main implementation-dependent portion in the source code is + the function lsRefreshIntfcAddr6(), defined in lib/confutil.c. This + function scans through each network interface and finds IPv6 addresses + and associated prefix length assigned to them. This function is + heavily implementation dependent because there seems no standard + method (ex. ioctl()) to get those data. + + The porting takes 5 steps: + 1. Add code for your IPv6 implementation to lsRefreshIntfcAddr6(). + Don't forget to enclose the code with appropriate #ifdef. + 2. Add code which figures out your IPv6 implementation type and defines + appropriate symbol, to configure.in. Also add the symbol to acconfig.h. + 3. Run `autoconf' and `autoheader' to rebuild configure script and + include/config.h.in. + 4. Run `configure' and make sure configure script detects your implementation + correctly. Then compile, install and see if everything works right. + 5. If you satisfy the result, and hope your fix will be included in the + next release, please send your fix to socks5-bugs@syl.dl.nec.com. + + + Note to KAME Users + ================== + + Since normally IPv6 libaries are installed under /usr/local/v6/lib, + you should set the library path to environment variable LDFLAGS + before executing configure. + % setenv LDFLAGS -L/usr/local/v6/lib + % ./configure + for csh-like shells) or + % LDFLAGS=-L/usr/local/v6/lib ./configure + for /bin/sh-like shells. + + You may meet with a compilation error while you build the socks5 + shared library (libsocks5_sh.so). You can safely ignore this error if + you don't use runsocks command (in this case you should do 'make -k + install' for installation). If you would like to use runsocks, you + have to build a shared version of libinet6 (see below). + + For runsocks command to work correctly for commands that make use of + libinet6 (such as /usr/local/v6/bin/telnet), you need a shared version + of libinet6. This is needed because socks5 library has to trap some + functions defined in libinet6, and this can be accomplished only if + libinet6 is a shared library. But the current KAME implementation (as + of 19981130 stable release) doesn't provide it by default. + + For those who would like to use runsocks, the following are brief + steps of what to do. (a simple shell script doing step 1 and 2 + automatically is provided as utils/mk_shared_libinet6_for_kame) + + 1. Apply following patch to the Makefile of libinet6 + (.../kit/src/libinet6/Makefile), then `make', `make install'. + This will build libinet6.so.1.0 and install it to /usr/local/v6/lib. + + *** Makefile.org Wed Sep 2 09:43:24 1998 + --- Makefile Fri Oct 23 10:43:37 1998 + *************** + *** 29,34 **** + --- 29,37 ---- + # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + # SUCH DAMAGE. + + + SHLIB_MAJOR=1 + + SHLIB_MINOR=0 + + + .if exists(${.CURDIR}/../Makefile.opsys) + .include "${.CURDIR}/../Makefile.opsys" + .endif + + 2. Rebuild and re-install commands that links libinet6 in order for + them to use the shared version. + + 3. Add installed library to the ldconfig cache. To do this, run + `ldconfig -m /usr/local/v6/lib'. And add /usr/local/v6/lib to + variable `ldconfig_paths' defined in /etc/rc.conf. + + 4. (Re)build and (re)install socks-trans. + + 5. Since socks5's configure script can only find shared libraries + installed in the standard places (which is /usr/lib for FreeBSD), + you should specify the pathname of the library explicitly by + setting LIBINET6_NAME environment variable. Since this variable + will be refered at run time, put + setenv LIBINET6_NAME /usr/local/v6/lib/libinet6.so.1.0 + in ~/.cshrc (for csh-like shells) or, + LIBINET6_NAME=/usr/local/v6/lib/libinet6.so.1.0 + export LIBINET6_NAME + in ~/.profile for /bin/sh-like shells (bash users can put them in + ~/.bashrc). + + + Reporting Bugs + ============== + + To submit problem reports regarding this release, send mail to: + socks5-bugs@socks.nec.com Index: acconfig.h diff -c src/socks5/acconfig.h:1.1.1.4 src/socks5/acconfig.h:1.4.2.4 *** acconfig.h Thu Aug 5 13:20:52 1999 --- acconfig.h Tue Aug 10 17:05:24 1999 *************** *** 49,54 **** --- 49,60 ---- /* define this if you have IPPORT_RESERVED somewhere...usually netinet/in.h */ #undef HAVE_IPPORT_RESERVED + /* define this if you have libident library. */ + #undef HAVE_LIBIDENT + + /* define this if you use shadow passwd file. */ + #undef USE_SHADOW_PASSWD + /* define this to your libc, if it has a version number (/lib/libc.so.1.9) */ #undef LIBC_NAME #undef LIBDGC_NAME *************** *** 56,61 **** --- 62,70 ---- #undef LIBRESOLV_NAME #undef LIBSOCKET_NAME + /* define if SunOS 5.5 */ + #undef USE_SYSTEM_SEMAPHORE + /* define if you want to use threading (if available) */ #undef USE_THREADS *************** *** 67,69 **** --- 76,99 ---- /* Define if the compiler can handle function prototyping */ #undef HAVE_FUNC_PROTOTYPE + + /* define if your system supports IPv6 */ + #undef SUPPORT_IPV6 + + /* define if your system uses KAME IPv6 implementation */ + #undef KAME + + /* define if your system uses PTCPIP (NEC's proprietary implementation of TCP/IP) */ + #undef PTCPIP + + /* define if your system supports IPv4-mapped IPv6 addresses */ + #undef SUPPORT_MAPPED_ADDRESS + + /* define this to the path of your traceroute for IPv6 */ + #undef TROUTE6PROG + + /* define this to the path of your ping for IPv6 */ + #undef PING6PROG + + /* define this according to your libinet6, if any. */ + #undef LIBINET6_NAME Index: configure diff -c src/socks5/configure:1.1.1.7 src/socks5/configure:1.5.2.4 *** configure Thu Aug 5 13:20:54 1999 --- configure Thu Aug 5 17:50:38 1999 *************** *** 43,48 **** --- 43,58 ---- --with-passwd=val Turn on use of passwd file for passwords" ac_help="$ac_help --with-shadow-passwd=val Turn on use of shadow passwd file for passwords" + ac_help="$ac_help + --enable-ipv6 Enable IPv6 support + --disable-ipv6 Disable IPv6 support" + ac_help="$ac_help + --enable-mapped-address Enable IPv4-mapped IPv6 address (default) + --disable-mapped-address Enable IPv4-mapped IPv6 address" + ac_help="$ac_help + --with-ipv6-ping=PATH Specify the pathname of 'ping' program for IPv6" + ac_help="$ac_help + --with-ipv6-traceroute=PATH Specify the pathname of 'traceroute' program for IPv6" # Initialize some variables set by options. # The variables have the same names as the options, with *************** *** 561,567 **** # Extract the first word of "gcc2", so it can be a program name with args. set dummy gcc2; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 ! echo "configure:565: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else --- 571,577 ---- # Extract the first word of "gcc2", so it can be a program name with args. set dummy gcc2; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 ! echo "configure:575: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else *************** *** 591,597 **** # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 ! echo "configure:595: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else --- 601,607 ---- # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 ! echo "configure:605: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else *************** *** 620,626 **** # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 ! echo "configure:624: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else --- 630,636 ---- # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 ! echo "configure:634: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else *************** *** 668,674 **** fi echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 ! echo "configure:672: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 ac_ext=c # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. --- 678,684 ---- fi echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 ! echo "configure:682: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 ac_ext=c # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. *************** *** 678,688 **** cross_compiling=$ac_cv_prog_cc_cross cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then ac_cv_prog_cc_works=yes # If we can't run a trivial program, we are probably using a cross compiler. if (./conftest; exit) 2>/dev/null; then --- 688,698 ---- cross_compiling=$ac_cv_prog_cc_cross cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then ac_cv_prog_cc_works=yes # If we can't run a trivial program, we are probably using a cross compiler. if (./conftest; exit) 2>/dev/null; then *************** *** 702,713 **** { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } fi echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 ! echo "configure:706: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 cross_compiling=$ac_cv_prog_cc_cross echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 ! echo "configure:711: checking whether we are using GNU C" >&5 if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else --- 712,723 ---- { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } fi echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 ! echo "configure:716: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 cross_compiling=$ac_cv_prog_cc_cross echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 ! echo "configure:721: checking whether we are using GNU C" >&5 if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else *************** *** 716,722 **** yes; #endif EOF ! if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:720: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then ac_cv_prog_gcc=yes else ac_cv_prog_gcc=no --- 726,732 ---- yes; #endif EOF ! if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:730: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then ac_cv_prog_gcc=yes else ac_cv_prog_gcc=no *************** *** 731,737 **** ac_save_CFLAGS="$CFLAGS" CFLAGS= echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 ! echo "configure:735: checking whether ${CC-cc} accepts -g" >&5 if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else --- 741,747 ---- ac_save_CFLAGS="$CFLAGS" CFLAGS= echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 ! echo "configure:745: checking whether ${CC-cc} accepts -g" >&5 if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else *************** *** 777,790 **** elif test "$OS" = "HP-UX" -a "$use_env_cc" != "yes"; then CFLAGS="-Ae" cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* s5_have_ansi_cc="yes" else --- 787,800 ---- elif test "$OS" = "HP-UX" -a "$use_env_cc" != "yes"; then CFLAGS="-Ae" cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* s5_have_ansi_cc="yes" else *************** *** 801,807 **** # Extract the first word of "c89", so it can be a program name with args. set dummy c89; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 ! echo "configure:805: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else --- 811,817 ---- # Extract the first word of "c89", so it can be a program name with args. set dummy c89; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 ! echo "configure:815: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else *************** *** 831,844 **** fi elif test "$OS" = "SunOS" -a "$use_env_cc" != "yes"; then cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* s5_have_ansi_cc="yes" else --- 841,854 ---- fi elif test "$OS" = "SunOS" -a "$use_env_cc" != "yes"; then cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* s5_have_ansi_cc="yes" else *************** *** 854,860 **** # Extract the first word of "acc", so it can be a program name with args. set dummy acc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 ! echo "configure:858: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else --- 864,870 ---- # Extract the first word of "acc", so it can be a program name with args. set dummy acc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 ! echo "configure:868: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else *************** *** 885,898 **** fi if test "$savedcc" != "$CC"; then echo "$ac_t""resetting CC to $CC" 1>&6; fi cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* cat >> confdefs.h <<\EOF #define HAVE_FUNC_PROTOTYPE 1 --- 895,908 ---- fi if test "$savedcc" != "$CC"; then echo "$ac_t""resetting CC to $CC" 1>&6; fi cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* cat >> confdefs.h <<\EOF #define HAVE_FUNC_PROTOTYPE 1 *************** *** 907,913 **** rm -f conftest* echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 ! echo "configure:911: checking how to run the C preprocessor" >&5 # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= --- 917,923 ---- rm -f conftest* echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 ! echo "configure:921: checking how to run the C preprocessor" >&5 # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= *************** *** 922,934 **** # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. cat > conftest.$ac_ext < Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ! { (eval echo configure:932: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then : --- 932,944 ---- # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. cat > conftest.$ac_ext < Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ! { (eval echo configure:942: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then : *************** *** 939,951 **** rm -rf conftest* CPP="${CC-cc} -E -traditional-cpp" cat > conftest.$ac_ext < Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ! { (eval echo configure:949: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then : --- 949,961 ---- rm -rf conftest* CPP="${CC-cc} -E -traditional-cpp" cat > conftest.$ac_ext < Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ! { (eval echo configure:959: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then : *************** *** 969,981 **** if test $ac_cv_prog_gcc = yes; then echo $ac_n "checking whether ${CC-cc} needs -traditional""... $ac_c" 1>&6 ! echo "configure:973: checking whether ${CC-cc} needs -traditional" >&5 if eval "test \"`echo '$''{'ac_cv_prog_gcc_traditional'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_pattern="Autoconf.*'x'" cat > conftest.$ac_ext < Autoconf TIOCGETP --- 979,991 ---- if test $ac_cv_prog_gcc = yes; then echo $ac_n "checking whether ${CC-cc} needs -traditional""... $ac_c" 1>&6 ! echo "configure:983: checking whether ${CC-cc} needs -traditional" >&5 if eval "test \"`echo '$''{'ac_cv_prog_gcc_traditional'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_pattern="Autoconf.*'x'" cat > conftest.$ac_ext < Autoconf TIOCGETP *************** *** 993,999 **** if test $ac_cv_prog_gcc_traditional = no; then cat > conftest.$ac_ext < Autoconf TCGETA --- 1003,1009 ---- if test $ac_cv_prog_gcc_traditional = no; then cat > conftest.$ac_ext < Autoconf TCGETA *************** *** 1015,1026 **** fi echo $ac_n "checking for working const""... $ac_c" 1>&6 ! echo "configure:1019: checking for working const" >&5 if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 ! echo "configure:1029: checking for working const" >&5 if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_c_const=yes else --- 1079,1085 ---- ; return 0; } EOF ! if { (eval echo configure:1083: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_c_const=yes else *************** *** 1090,1110 **** fi echo $ac_n "checking for inline""... $ac_c" 1>&6 ! echo "configure:1094: checking for inline" >&5 if eval "test \"`echo '$''{'ac_cv_c_inline'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_cv_c_inline=no for ac_kw in inline __inline__ __inline; do cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_c_inline=$ac_kw; break else --- 1100,1120 ---- fi echo $ac_n "checking for inline""... $ac_c" 1>&6 ! echo "configure:1104: checking for inline" >&5 if eval "test \"`echo '$''{'ac_cv_c_inline'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_cv_c_inline=no for ac_kw in inline __inline__ __inline; do cat > conftest.$ac_ext <&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_c_inline=$ac_kw; break else *************** *** 1135,1141 **** # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 ! echo "configure:1139: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else --- 1145,1151 ---- # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 ! echo "configure:1149: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else *************** *** 1191,1197 **** # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # ./install, which can be erroneously created by make from ./install.sh. echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 ! echo "configure:1195: checking for a BSD compatible install" >&5 if test -z "$INSTALL"; then if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 --- 1201,1207 ---- # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # ./install, which can be erroneously created by make from ./install.sh. echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 ! echo "configure:1205: checking for a BSD compatible install" >&5 if test -z "$INSTALL"; then if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 *************** *** 1243,1249 **** # Extract the first word of "makedepend", so it can be a program name with args. set dummy makedepend; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 ! echo "configure:1247: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_MAKED'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else --- 1253,1259 ---- # Extract the first word of "makedepend", so it can be a program name with args. set dummy makedepend; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 ! echo "configure:1257: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_MAKED'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else *************** *** 1272,1278 **** # Extract the first word of "autoconf", so it can be a program name with args. set dummy autoconf; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 ! echo "configure:1276: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_AUTOCONF'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else --- 1282,1288 ---- # Extract the first word of "autoconf", so it can be a program name with args. set dummy autoconf; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 ! echo "configure:1286: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_AUTOCONF'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else *************** *** 1301,1307 **** # Extract the first word of "autoheader", so it can be a program name with args. set dummy autoheader; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 ! echo "configure:1305: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_AUTOHDR'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else --- 1311,1317 ---- # Extract the first word of "autoheader", so it can be a program name with args. set dummy autoheader; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 ! echo "configure:1315: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_AUTOHDR'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else *************** *** 1334,1350 **** do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 ! echo "configure:1338: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ! { (eval echo configure:1348: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then rm -rf conftest* --- 1344,1360 ---- do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 ! echo "configure:1348: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ! { (eval echo configure:1358: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then rm -rf conftest* *************** *** 1374,1390 **** do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 ! echo "configure:1378: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ! { (eval echo configure:1388: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then rm -rf conftest* --- 1384,1400 ---- do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 ! echo "configure:1388: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ! { (eval echo configure:1398: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then rm -rf conftest* *************** *** 1414,1430 **** do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 ! echo "configure:1418: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ! { (eval echo configure:1428: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then rm -rf conftest* --- 1424,1440 ---- do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 ! echo "configure:1428: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ! { (eval echo configure:1438: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then rm -rf conftest* *************** *** 1454,1470 **** do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 ! echo "configure:1458: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ! { (eval echo configure:1468: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then rm -rf conftest* --- 1464,1480 ---- do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 ! echo "configure:1468: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ! { (eval echo configure:1478: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then rm -rf conftest* *************** *** 1494,1510 **** do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 ! echo "configure:1498: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ! { (eval echo configure:1508: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then rm -rf conftest* --- 1504,1520 ---- do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 ! echo "configure:1508: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ! { (eval echo configure:1518: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then rm -rf conftest* *************** *** 1534,1550 **** do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 ! echo "configure:1538: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ! { (eval echo configure:1548: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then rm -rf conftest* --- 1544,1560 ---- do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 ! echo "configure:1548: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ! { (eval echo configure:1558: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then rm -rf conftest* *************** *** 1571,1582 **** done echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6 ! echo "configure:1575: checking whether time.h and sys/time.h may both be included" >&5 if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include --- 1581,1592 ---- done echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6 ! echo "configure:1585: checking whether time.h and sys/time.h may both be included" >&5 if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include *************** *** 1585,1591 **** struct tm *tp; ; return 0; } EOF ! if { (eval echo configure:1589: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_header_time=yes else --- 1595,1601 ---- struct tm *tp; ; return 0; } EOF ! if { (eval echo configure:1599: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_header_time=yes else *************** *** 1606,1617 **** fi echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6 ! echo "configure:1610: checking for ANSI C header files" >&5 if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include --- 1616,1627 ---- fi echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6 ! echo "configure:1620: checking for ANSI C header files" >&5 if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include *************** *** 1619,1625 **** #include EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ! { (eval echo configure:1623: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then rm -rf conftest* --- 1629,1635 ---- #include EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ! { (eval echo configure:1633: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then rm -rf conftest* *************** *** 1636,1642 **** if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat > conftest.$ac_ext < EOF --- 1646,1652 ---- if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat > conftest.$ac_ext < EOF *************** *** 1654,1660 **** if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat > conftest.$ac_ext < EOF --- 1664,1670 ---- if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat > conftest.$ac_ext < EOF *************** *** 1675,1681 **** : else cat > conftest.$ac_ext < #define ISLOWER(c) ('a' <= (c) && (c) <= 'z') --- 1685,1691 ---- : else cat > conftest.$ac_ext < #define ISLOWER(c) ('a' <= (c) && (c) <= 'z') *************** *** 1686,1692 **** exit (0); } EOF ! if { (eval echo configure:1690: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null then : else --- 1696,1702 ---- exit (0); } EOF ! if { (eval echo configure:1700: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null then : else *************** *** 1714,1725 **** do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6 ! echo "configure:1718: checking for $ac_hdr that defines DIR" >&5 if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include <$ac_hdr> --- 1724,1735 ---- do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6 ! echo "configure:1728: checking for $ac_hdr that defines DIR" >&5 if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include <$ac_hdr> *************** *** 1727,1733 **** DIR *dirp = 0; ; return 0; } EOF ! if { (eval echo configure:1731: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* eval "ac_cv_header_dirent_$ac_safe=yes" else --- 1737,1743 ---- DIR *dirp = 0; ; return 0; } EOF ! if { (eval echo configure:1741: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* eval "ac_cv_header_dirent_$ac_safe=yes" else *************** *** 1752,1758 **** # Two versions of opendir et al. are in -ldir and -lx on SCO Xenix. if test $ac_header_dirent = dirent.h; then echo $ac_n "checking for opendir in -ldir""... $ac_c" 1>&6 ! echo "configure:1756: checking for opendir in -ldir" >&5 ac_lib_var=`echo dir'_'opendir | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 --- 1762,1768 ---- # Two versions of opendir et al. are in -ldir and -lx on SCO Xenix. if test $ac_header_dirent = dirent.h; then echo $ac_n "checking for opendir in -ldir""... $ac_c" 1>&6 ! echo "configure:1766: checking for opendir in -ldir" >&5 ac_lib_var=`echo dir'_'opendir | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 *************** *** 1760,1766 **** ac_save_LIBS="$LIBS" LIBS="-ldir $LIBS" cat > conftest.$ac_ext < conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else --- 1781,1787 ---- opendir() ; return 0; } EOF ! if { (eval echo configure:1785: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else *************** *** 1793,1799 **** else echo $ac_n "checking for opendir in -lx""... $ac_c" 1>&6 ! echo "configure:1797: checking for opendir in -lx" >&5 ac_lib_var=`echo x'_'opendir | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 --- 1803,1809 ---- else echo $ac_n "checking for opendir in -lx""... $ac_c" 1>&6 ! echo "configure:1807: checking for opendir in -lx" >&5 ac_lib_var=`echo x'_'opendir | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 *************** *** 1801,1807 **** ac_save_LIBS="$LIBS" LIBS="-lx $LIBS" cat > conftest.$ac_ext < conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else --- 1822,1828 ---- opendir() ; return 0; } EOF ! if { (eval echo configure:1826: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else *************** *** 1840,1846 **** if test "$OS" != "IRIX"; then echo $ac_n "checking for main in -lsocket""... $ac_c" 1>&6 ! echo "configure:1844: checking for main in -lsocket" >&5 ac_lib_var=`echo socket'_'main | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 --- 1850,1856 ---- if test "$OS" != "IRIX"; then echo $ac_n "checking for main in -lsocket""... $ac_c" 1>&6 ! echo "configure:1854: checking for main in -lsocket" >&5 ac_lib_var=`echo socket'_'main | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 *************** *** 1848,1861 **** ac_save_LIBS="$LIBS" LIBS="-lsocket $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else --- 1858,1871 ---- ac_save_LIBS="$LIBS" LIBS="-lsocket $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else *************** *** 1883,1889 **** fi echo $ac_n "checking for main in -ldl""... $ac_c" 1>&6 ! echo "configure:1887: checking for main in -ldl" >&5 ac_lib_var=`echo dl'_'main | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 --- 1893,1899 ---- fi echo $ac_n "checking for main in -ldl""... $ac_c" 1>&6 ! echo "configure:1897: checking for main in -ldl" >&5 ac_lib_var=`echo dl'_'main | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 *************** *** 1891,1904 **** ac_save_LIBS="$LIBS" LIBS="-ldl $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else --- 1901,1914 ---- ac_save_LIBS="$LIBS" LIBS="-ldl $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else *************** *** 1927,1933 **** fi echo $ac_n "checking for main in -ldld""... $ac_c" 1>&6 ! echo "configure:1931: checking for main in -ldld" >&5 ac_lib_var=`echo dld'_'main | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 --- 1937,1943 ---- fi echo $ac_n "checking for main in -ldld""... $ac_c" 1>&6 ! echo "configure:1941: checking for main in -ldld" >&5 ac_lib_var=`echo dld'_'main | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 *************** *** 1935,1948 **** ac_save_LIBS="$LIBS" LIBS="-ldld $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else --- 1945,1958 ---- ac_save_LIBS="$LIBS" LIBS="-ldld $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else *************** *** 1970,1976 **** fi echo $ac_n "checking for main in -lsvld""... $ac_c" 1>&6 ! echo "configure:1974: checking for main in -lsvld" >&5 ac_lib_var=`echo svld'_'main | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 --- 1980,1986 ---- fi echo $ac_n "checking for main in -lsvld""... $ac_c" 1>&6 ! echo "configure:1984: checking for main in -lsvld" >&5 ac_lib_var=`echo svld'_'main | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 *************** *** 1978,1991 **** ac_save_LIBS="$LIBS" LIBS="-lsvld $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else --- 1988,2001 ---- ac_save_LIBS="$LIBS" LIBS="-lsvld $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else *************** *** 2013,2019 **** fi echo $ac_n "checking for setupterm in -ltermcap""... $ac_c" 1>&6 ! echo "configure:2017: checking for setupterm in -ltermcap" >&5 ac_lib_var=`echo termcap'_'setupterm | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 --- 2023,2029 ---- fi echo $ac_n "checking for setupterm in -ltermcap""... $ac_c" 1>&6 ! echo "configure:2027: checking for setupterm in -ltermcap" >&5 ac_lib_var=`echo termcap'_'setupterm | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 *************** *** 2021,2027 **** ac_save_LIBS="$LIBS" LIBS="-ltermcap $LIBS" cat > conftest.$ac_ext < conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else --- 2042,2048 ---- setupterm() ; return 0; } EOF ! if { (eval echo configure:2046: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else *************** *** 2051,2057 **** else echo "$ac_t""no" 1>&6 echo $ac_n "checking for setupterm in -lcurses""... $ac_c" 1>&6 ! echo "configure:2055: checking for setupterm in -lcurses" >&5 ac_lib_var=`echo curses'_'setupterm | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 --- 2061,2067 ---- else echo "$ac_t""no" 1>&6 echo $ac_n "checking for setupterm in -lcurses""... $ac_c" 1>&6 ! echo "configure:2065: checking for setupterm in -lcurses" >&5 ac_lib_var=`echo curses'_'setupterm | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 *************** *** 2059,2065 **** ac_save_LIBS="$LIBS" LIBS="-lcurses $LIBS" cat > conftest.$ac_ext < conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else --- 2080,2086 ---- setupterm() ; return 0; } EOF ! if { (eval echo configure:2084: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else *************** *** 2089,2095 **** else echo "$ac_t""no" 1>&6 echo $ac_n "checking for setupterm in -lncurses""... $ac_c" 1>&6 ! echo "configure:2093: checking for setupterm in -lncurses" >&5 ac_lib_var=`echo ncurses'_'setupterm | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 --- 2099,2105 ---- else echo "$ac_t""no" 1>&6 echo $ac_n "checking for setupterm in -lncurses""... $ac_c" 1>&6 ! echo "configure:2103: checking for setupterm in -lncurses" >&5 ac_lib_var=`echo ncurses'_'setupterm | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 *************** *** 2097,2103 **** ac_save_LIBS="$LIBS" LIBS="-lncurses $LIBS" cat > conftest.$ac_ext < conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else --- 2118,2124 ---- setupterm() ; return 0; } EOF ! if { (eval echo configure:2122: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else *************** *** 2127,2133 **** else echo "$ac_t""no" 1>&6 echo $ac_n "checking for tgetent in -ltermcap""... $ac_c" 1>&6 ! echo "configure:2131: checking for tgetent in -ltermcap" >&5 ac_lib_var=`echo termcap'_'tgetent | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 --- 2137,2143 ---- else echo "$ac_t""no" 1>&6 echo $ac_n "checking for tgetent in -ltermcap""... $ac_c" 1>&6 ! echo "configure:2141: checking for tgetent in -ltermcap" >&5 ac_lib_var=`echo termcap'_'tgetent | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 *************** *** 2135,2141 **** ac_save_LIBS="$LIBS" LIBS="-ltermcap $LIBS" cat > conftest.$ac_ext < conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else --- 2156,2162 ---- tgetent() ; return 0; } EOF ! if { (eval echo configure:2160: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else *************** *** 2165,2171 **** else echo "$ac_t""no" 1>&6 echo $ac_n "checking for tgetent in -lcurses""... $ac_c" 1>&6 ! echo "configure:2169: checking for tgetent in -lcurses" >&5 ac_lib_var=`echo curses'_'tgetent | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 --- 2175,2181 ---- else echo "$ac_t""no" 1>&6 echo $ac_n "checking for tgetent in -lcurses""... $ac_c" 1>&6 ! echo "configure:2179: checking for tgetent in -lcurses" >&5 ac_lib_var=`echo curses'_'tgetent | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 *************** *** 2173,2179 **** ac_save_LIBS="$LIBS" LIBS="-lcurses $LIBS" cat > conftest.$ac_ext < conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else --- 2194,2200 ---- tgetent() ; return 0; } EOF ! if { (eval echo configure:2198: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else *************** *** 2203,2209 **** else echo "$ac_t""no" 1>&6 echo $ac_n "checking for tgetent in -lncurses""... $ac_c" 1>&6 ! echo "configure:2207: checking for tgetent in -lncurses" >&5 ac_lib_var=`echo ncurses'_'tgetent | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 --- 2213,2219 ---- else echo "$ac_t""no" 1>&6 echo $ac_n "checking for tgetent in -lncurses""... $ac_c" 1>&6 ! echo "configure:2217: checking for tgetent in -lncurses" >&5 ac_lib_var=`echo ncurses'_'tgetent | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 *************** *** 2211,2217 **** ac_save_LIBS="$LIBS" LIBS="-lncurses $LIBS" cat > conftest.$ac_ext < conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else --- 2232,2238 ---- tgetent() ; return 0; } EOF ! if { (eval echo configure:2236: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else *************** *** 2254,2260 **** fi echo $ac_n "checking for gethostbyname in -lc""... $ac_c" 1>&6 ! echo "configure:2258: checking for gethostbyname in -lc" >&5 ac_lib_var=`echo c'_'gethostbyname | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 --- 2264,2270 ---- fi echo $ac_n "checking for gethostbyname in -lc""... $ac_c" 1>&6 ! echo "configure:2268: checking for gethostbyname in -lc" >&5 ac_lib_var=`echo c'_'gethostbyname | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 *************** *** 2262,2268 **** ac_save_LIBS="$LIBS" LIBS="-lc $LIBS" cat > conftest.$ac_ext < conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else --- 2283,2289 ---- gethostbyname() ; return 0; } EOF ! if { (eval echo configure:2287: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else *************** *** 2292,2298 **** else echo "$ac_t""no" 1>&6 echo $ac_n "checking for gethostbyname in -lresolv""... $ac_c" 1>&6 ! echo "configure:2296: checking for gethostbyname in -lresolv" >&5 ac_lib_var=`echo resolv'_'gethostbyname | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 --- 2302,2308 ---- else echo "$ac_t""no" 1>&6 echo $ac_n "checking for gethostbyname in -lresolv""... $ac_c" 1>&6 ! echo "configure:2306: checking for gethostbyname in -lresolv" >&5 ac_lib_var=`echo resolv'_'gethostbyname | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 *************** *** 2300,2306 **** ac_save_LIBS="$LIBS" LIBS="-lresolv $LIBS" cat > conftest.$ac_ext < conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else --- 2321,2327 ---- gethostbyname() ; return 0; } EOF ! if { (eval echo configure:2325: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else *************** *** 2335,2341 **** echo $ac_n "checking if we can use -lnsl""... $ac_c" 1>&6 ! echo "configure:2339: checking if we can use -lnsl" >&5 if eval "test \"`echo '$''{'r_cv_use_libnsl'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else --- 2345,2351 ---- echo $ac_n "checking if we can use -lnsl""... $ac_c" 1>&6 ! echo "configure:2349: checking if we can use -lnsl" >&5 if eval "test \"`echo '$''{'r_cv_use_libnsl'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else *************** *** 2343,2353 **** r_cv_use_libnsl=yes else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null then r_cv_use_libnsl=no else --- 2353,2363 ---- r_cv_use_libnsl=yes else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null then r_cv_use_libnsl=no else *************** *** 2370,2376 **** ac_safe=`echo "$r_lib_name" | tr './\055' '___'` echo $ac_n "checking for shared $r_lib_name""... $ac_c" 1>&6 ! echo "configure:2374: checking for shared $r_lib_name" >&5 if eval "test \"`echo '$''{'r_cv_name_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else --- 2380,2386 ---- ac_safe=`echo "$r_lib_name" | tr './\055' '___'` echo $ac_n "checking for shared $r_lib_name""... $ac_c" 1>&6 ! echo "configure:2384: checking for shared $r_lib_name" >&5 if eval "test \"`echo '$''{'r_cv_name_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else *************** *** 2493,2504 **** echo echo $ac_n "checking for pid_t""... $ac_c" 1>&6 ! echo "configure:2497: checking for pid_t" >&5 if eval "test \"`echo '$''{'ac_cv_type_pid_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #if STDC_HEADERS --- 2503,2514 ---- echo echo $ac_n "checking for pid_t""... $ac_c" 1>&6 ! echo "configure:2507: checking for pid_t" >&5 if eval "test \"`echo '$''{'ac_cv_type_pid_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #if STDC_HEADERS *************** *** 2526,2537 **** fi echo $ac_n "checking for size_t""... $ac_c" 1>&6 ! echo "configure:2530: checking for size_t" >&5 if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #if STDC_HEADERS --- 2536,2547 ---- fi echo $ac_n "checking for size_t""... $ac_c" 1>&6 ! echo "configure:2540: checking for size_t" >&5 if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #if STDC_HEADERS *************** *** 2559,2570 **** fi echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6 ! echo "configure:2563: checking return type of signal handlers" >&5 if eval "test \"`echo '$''{'ac_cv_type_signal'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include --- 2569,2580 ---- fi echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6 ! echo "configure:2573: checking return type of signal handlers" >&5 if eval "test \"`echo '$''{'ac_cv_type_signal'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include *************** *** 2581,2587 **** int i; ; return 0; } EOF ! if { (eval echo configure:2585: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_type_signal=void else --- 2591,2597 ---- int i; ; return 0; } EOF ! if { (eval echo configure:2595: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_type_signal=void else *************** *** 2601,2612 **** echo $ac_n "checking whether sockaddr_un has sun_len""... $ac_c" 1>&6 ! echo "configure:2605: checking whether sockaddr_un has sun_len" >&5 if eval "test \"`echo '$''{'sc_cv_sockaddr_sun_len'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include --- 2611,2622 ---- echo $ac_n "checking whether sockaddr_un has sun_len""... $ac_c" 1>&6 ! echo "configure:2615: checking whether sockaddr_un has sun_len" >&5 if eval "test \"`echo '$''{'sc_cv_sockaddr_sun_len'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < #include *************** *** 2614,2620 **** struct sockaddr_un s_un; s_un.sun_len=0; ; return 0; } EOF ! if { (eval echo configure:2618: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* sc_cv_sockaddr_sun_len=yes else --- 2624,2630 ---- struct sockaddr_un s_un; s_un.sun_len=0; ; return 0; } EOF ! if { (eval echo configure:2628: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* sc_cv_sockaddr_sun_len=yes else *************** *** 2634,2645 **** echo $ac_n "checking for sig_atomic_t""... $ac_c" 1>&6 ! echo "configure:2638: checking for sig_atomic_t" >&5 if eval "test \"`echo '$''{'r_cv_type_sig_atomic_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < --- 2644,2655 ---- echo $ac_n "checking for sig_atomic_t""... $ac_c" 1>&6 ! echo "configure:2648: checking for sig_atomic_t" >&5 if eval "test \"`echo '$''{'r_cv_type_sig_atomic_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < *************** *** 2668,2686 **** fi echo $ac_n "checking for cc_t""... $ac_c" 1>&6 ! echo "configure:2672: checking for cc_t" >&5 if eval "test \"`echo '$''{'r_cv_have_cct'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < ; return 0; } EOF ! if { (eval echo configure:2684: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* cc_t foo; else --- 2678,2696 ---- fi echo $ac_n "checking for cc_t""... $ac_c" 1>&6 ! echo "configure:2682: checking for cc_t" >&5 if eval "test \"`echo '$''{'r_cv_have_cct'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < ; return 0; } EOF ! if { (eval echo configure:2694: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* cc_t foo; else *************** *** 2699,2717 **** echo "$ac_t""$r_cv_have_cct" 1>&6 echo $ac_n "checking for sig_t""... $ac_c" 1>&6 ! echo "configure:2703: checking for sig_t" >&5 if eval "test \"`echo '$''{'r_cv_have_sigt'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < int main() { sig_t i = (sig_t)0; ; return 0; } EOF ! if { (eval echo configure:2715: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* r_cv_have_sigt=yes else --- 2709,2727 ---- echo "$ac_t""$r_cv_have_cct" 1>&6 echo $ac_n "checking for sig_t""... $ac_c" 1>&6 ! echo "configure:2713: checking for sig_t" >&5 if eval "test \"`echo '$''{'r_cv_have_sigt'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < int main() { sig_t i = (sig_t)0; ; return 0; } EOF ! if { (eval echo configure:2725: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* r_cv_have_sigt=yes else *************** *** 2727,2738 **** echo "$ac_t""$r_cv_have_sigt" 1>&6 echo $ac_n "checking for getpassphrase""... $ac_c" 1>&6 ! echo "configure:2731: checking for getpassphrase" >&5 if eval "test \"`echo '$''{'ac_cv_func_getpassphrase'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 echo $ac_n "checking for getpassphrase""... $ac_c" 1>&6 ! echo "configure:2741: checking for getpassphrase" >&5 if eval "test \"`echo '$''{'ac_cv_func_getpassphrase'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func_getpassphrase=yes" else --- 2765,2771 ---- ; return 0; } EOF ! if { (eval echo configure:2769: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func_getpassphrase=yes" else *************** *** 2780,2798 **** echo echo $ac_n "checking for sys_errlist""... $ac_c" 1>&6 ! echo "configure:2784: checking for sys_errlist" >&5 if eval "test \"`echo '$''{'r_cv_have_sysel'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* r_cv_have_sysel=yes else --- 2790,2808 ---- echo echo $ac_n "checking for sys_errlist""... $ac_c" 1>&6 ! echo "configure:2794: checking for sys_errlist" >&5 if eval "test \"`echo '$''{'r_cv_have_sysel'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* r_cv_have_sysel=yes else *************** *** 2813,2824 **** for ac_func in dlopen shl_load do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 ! echo "configure:2817: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 ! echo "configure:2827: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else --- 2851,2857 ---- ; return 0; } EOF ! if { (eval echo configure:2855: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else *************** *** 2871,2882 **** for ac_func in setupterm do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 ! echo "configure:2875: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 ! echo "configure:2885: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else --- 2909,2915 ---- ; return 0; } EOF ! if { (eval echo configure:2913: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else *************** *** 2926,2937 **** for ac_func in tgetent do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 ! echo "configure:2930: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 ! echo "configure:2940: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else --- 2964,2970 ---- ; return 0; } EOF ! if { (eval echo configure:2968: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else *************** *** 2983,2994 **** for ac_func in gethostbyname2 do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 ! echo "configure:2987: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 ! echo "configure:2997: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else --- 3021,3027 ---- ; return 0; } EOF ! if { (eval echo configure:3025: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else *************** *** 3038,3049 **** for ac_func in gethostbyname_r gethostbyaddr_r getpwuid_r getservbyname_r do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 ! echo "configure:3042: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 ! echo "configure:3052: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else --- 3076,3082 ---- ; return 0; } EOF ! if { (eval echo configure:3080: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else *************** *** 3093,3104 **** for ac_func in memset memcmp memmove strchr strrchr strdup strerror do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 ! echo "configure:3097: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 ! echo "configure:3107: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else --- 3131,3137 ---- ; return 0; } EOF ! if { (eval echo configure:3135: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else *************** *** 3148,3159 **** for ac_func in bcopy bcmp bzero index rindex do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 ! echo "configure:3152: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 ! echo "configure:3162: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else --- 3186,3192 ---- ; return 0; } EOF ! if { (eval echo configure:3190: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else *************** *** 3203,3214 **** for ac_func in setenv putenv unsetenv getenv do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 ! echo "configure:3207: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 ! echo "configure:3217: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else --- 3241,3247 ---- ; return 0; } EOF ! if { (eval echo configure:3245: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else *************** *** 3258,3269 **** for ac_func in getdomainname rresvport sendmsg setsid setpgid setpgrp getifaddrs do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 ! echo "configure:3262: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 ! echo "configure:3272: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else --- 3296,3302 ---- ; return 0; } EOF ! if { (eval echo configure:3300: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else *************** *** 3313,3324 **** for ac_func in waitpid flock dgettext sigaction sigprocmask do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 ! echo "configure:3317: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 ! echo "configure:3327: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else --- 3351,3357 ---- ; return 0; } EOF ! if { (eval echo configure:3355: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else *************** *** 3368,3379 **** for ac_func in re_comp strspn getcwd vfork herror genget getopt do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 ! echo "configure:3372: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 ! echo "configure:3382: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else --- 3406,3412 ---- ; return 0; } EOF ! if { (eval echo configure:3410: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else *************** *** 3421,3432 **** done echo $ac_n "checking for vprintf""... $ac_c" 1>&6 ! echo "configure:3425: checking for vprintf" >&5 if eval "test \"`echo '$''{'ac_cv_func_vprintf'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 ! echo "configure:3435: checking for vprintf" >&5 if eval "test \"`echo '$''{'ac_cv_func_vprintf'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func_vprintf=yes" else --- 3459,3465 ---- ; return 0; } EOF ! if { (eval echo configure:3463: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func_vprintf=yes" else *************** *** 3473,3484 **** if test "$ac_cv_func_vprintf" != yes; then echo $ac_n "checking for _doprnt""... $ac_c" 1>&6 ! echo "configure:3477: checking for _doprnt" >&5 if eval "test \"`echo '$''{'ac_cv_func__doprnt'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 ! echo "configure:3487: checking for _doprnt" >&5 if eval "test \"`echo '$''{'ac_cv_func__doprnt'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func__doprnt=yes" else --- 3511,3517 ---- ; return 0; } EOF ! if { (eval echo configure:3515: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func__doprnt=yes" else *************** *** 3526,3532 **** fi echo $ac_n "checking whether setpgrp takes no argument""... $ac_c" 1>&6 ! echo "configure:3530: checking whether setpgrp takes no argument" >&5 if eval "test \"`echo '$''{'ac_cv_func_setpgrp_void'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else --- 3536,3542 ---- fi echo $ac_n "checking whether setpgrp takes no argument""... $ac_c" 1>&6 ! echo "configure:3540: checking whether setpgrp takes no argument" >&5 if eval "test \"`echo '$''{'ac_cv_func_setpgrp_void'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else *************** *** 3534,3540 **** { echo "configure: error: cannot check setpgrp if cross compiling" 1>&2; exit 1; } else cat > conftest.$ac_ext <&2; exit 1; } else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null then ac_cv_func_setpgrp_void=no else --- 3560,3566 ---- } EOF ! if { (eval echo configure:3564: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null then ac_cv_func_setpgrp_void=no else *************** *** 3585,3591 **** if test "$KRB5" != "no"; then echo echo $ac_n "checking Kerberos 5""... $ac_c" 1>&6 ! echo "configure:3589: checking Kerberos 5" >&5 if eval "test \"`echo '$''{'r_cv_krb5_home'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else --- 3595,3601 ---- if test "$KRB5" != "no"; then echo echo $ac_n "checking Kerberos 5""... $ac_c" 1>&6 ! echo "configure:3599: checking Kerberos 5" >&5 if eval "test \"`echo '$''{'r_cv_krb5_home'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else *************** *** 3614,3620 **** LDFLAGS="$LDFLAGS -L$KRB5_HOME/lib" fi echo $ac_n "checking for main in -ldb""... $ac_c" 1>&6 ! echo "configure:3618: checking for main in -ldb" >&5 ac_lib_var=`echo db'_'main | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 --- 3624,3630 ---- LDFLAGS="$LDFLAGS -L$KRB5_HOME/lib" fi echo $ac_n "checking for main in -ldb""... $ac_c" 1>&6 ! echo "configure:3628: checking for main in -ldb" >&5 ac_lib_var=`echo db'_'main | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 *************** *** 3622,3635 **** ac_save_LIBS="$LIBS" LIBS="-ldb $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else --- 3632,3645 ---- ac_save_LIBS="$LIBS" LIBS="-ldb $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else *************** *** 3658,3664 **** if test "$ac_cv_lib_db_main" = "no"; then echo $ac_n "checking for main in -lndbm""... $ac_c" 1>&6 ! echo "configure:3662: checking for main in -lndbm" >&5 ac_lib_var=`echo ndbm'_'main | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 --- 3668,3674 ---- if test "$ac_cv_lib_db_main" = "no"; then echo $ac_n "checking for main in -lndbm""... $ac_c" 1>&6 ! echo "configure:3672: checking for main in -lndbm" >&5 ac_lib_var=`echo ndbm'_'main | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 *************** *** 3666,3679 **** ac_save_LIBS="$LIBS" LIBS="-lndbm $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else --- 3676,3689 ---- ac_save_LIBS="$LIBS" LIBS="-lndbm $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else *************** *** 3702,3708 **** fi echo $ac_n "checking for main in -lisode""... $ac_c" 1>&6 ! echo "configure:3706: checking for main in -lisode" >&5 ac_lib_var=`echo isode'_'main | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 --- 3712,3718 ---- fi echo $ac_n "checking for main in -lisode""... $ac_c" 1>&6 ! echo "configure:3716: checking for main in -lisode" >&5 ac_lib_var=`echo isode'_'main | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 *************** *** 3710,3723 **** ac_save_LIBS="$LIBS" LIBS="-lisode $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else --- 3720,3733 ---- ac_save_LIBS="$LIBS" LIBS="-lisode $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else *************** *** 3745,3751 **** fi echo $ac_n "checking for main in -lcom_err""... $ac_c" 1>&6 ! echo "configure:3749: checking for main in -lcom_err" >&5 ac_lib_var=`echo com_err'_'main | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 --- 3755,3761 ---- fi echo $ac_n "checking for main in -lcom_err""... $ac_c" 1>&6 ! echo "configure:3759: checking for main in -lcom_err" >&5 ac_lib_var=`echo com_err'_'main | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 *************** *** 3753,3766 **** ac_save_LIBS="$LIBS" LIBS="-lcom_err $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else --- 3763,3776 ---- ac_save_LIBS="$LIBS" LIBS="-lcom_err $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else *************** *** 3788,3794 **** fi echo $ac_n "checking for main in -lcrypto""... $ac_c" 1>&6 ! echo "configure:3792: checking for main in -lcrypto" >&5 ac_lib_var=`echo crypto'_'main | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 --- 3798,3804 ---- fi echo $ac_n "checking for main in -lcrypto""... $ac_c" 1>&6 ! echo "configure:3802: checking for main in -lcrypto" >&5 ac_lib_var=`echo crypto'_'main | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 *************** *** 3796,3809 **** ac_save_LIBS="$LIBS" LIBS="-lcrypto $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else --- 3806,3819 ---- ac_save_LIBS="$LIBS" LIBS="-lcrypto $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else *************** *** 3831,3837 **** fi echo $ac_n "checking for main in -lkrb5""... $ac_c" 1>&6 ! echo "configure:3835: checking for main in -lkrb5" >&5 ac_lib_var=`echo krb5'_'main | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 --- 3841,3847 ---- fi echo $ac_n "checking for main in -lkrb5""... $ac_c" 1>&6 ! echo "configure:3845: checking for main in -lkrb5" >&5 ac_lib_var=`echo krb5'_'main | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 *************** *** 3839,3852 **** ac_save_LIBS="$LIBS" LIBS="-lkrb5 $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else --- 3849,3862 ---- ac_save_LIBS="$LIBS" LIBS="-lkrb5 $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else *************** *** 3874,3880 **** fi echo $ac_n "checking for main in -lgssapi_krb5""... $ac_c" 1>&6 ! echo "configure:3878: checking for main in -lgssapi_krb5" >&5 ac_lib_var=`echo gssapi_krb5'_'main | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 --- 3884,3890 ---- fi echo $ac_n "checking for main in -lgssapi_krb5""... $ac_c" 1>&6 ! echo "configure:3888: checking for main in -lgssapi_krb5" >&5 ac_lib_var=`echo gssapi_krb5'_'main | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 *************** *** 3882,3895 **** ac_save_LIBS="$LIBS" LIBS="-lgssapi_krb5 $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else --- 3892,3905 ---- ac_save_LIBS="$LIBS" LIBS="-lgssapi_krb5 $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else *************** *** 3942,3958 **** do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 ! echo "configure:3946: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ! { (eval echo configure:3956: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then rm -rf conftest* --- 3952,3968 ---- do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 ! echo "configure:3956: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ! { (eval echo configure:3966: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then rm -rf conftest* *************** *** 3981,3987 **** CPPFLAGS="$SAVED_CPPFLAGS" echo $ac_n "checking for main in -lident""... $ac_c" 1>&6 ! echo "configure:3985: checking for main in -lident" >&5 ac_lib_var=`echo ident'_'main | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 --- 3991,3997 ---- CPPFLAGS="$SAVED_CPPFLAGS" echo $ac_n "checking for main in -lident""... $ac_c" 1>&6 ! echo "configure:3995: checking for main in -lident" >&5 ac_lib_var=`echo ident'_'main | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 *************** *** 3989,4002 **** ac_save_LIBS="$LIBS" LIBS="-lident $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else --- 3999,4012 ---- ac_save_LIBS="$LIBS" LIBS="-lident $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else *************** *** 4027,4033 **** # Extract the first word of "finger", so it can be a program name with args. set dummy finger; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 ! echo "configure:4031: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_ORIG_FINGER'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else --- 4037,4043 ---- # Extract the first word of "finger", so it can be a program name with args. set dummy finger; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 ! echo "configure:4041: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_ORIG_FINGER'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else *************** *** 4058,4064 **** # Extract the first word of "traceroute", so it can be a program name with args. set dummy traceroute; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 ! echo "configure:4062: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_TROUTEPROG'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else --- 4068,4074 ---- # Extract the first word of "traceroute", so it can be a program name with args. set dummy traceroute; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 ! echo "configure:4072: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_TROUTEPROG'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else *************** *** 4095,4101 **** # Extract the first word of "ping", so it can be a program name with args. set dummy ping; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 ! echo "configure:4099: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_PINGPROG'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else --- 4105,4111 ---- # Extract the first word of "ping", so it can be a program name with args. set dummy ping; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 ! echo "configure:4109: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_path_PINGPROG'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else *************** *** 4176,4192 **** do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 ! echo "configure:4180: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ! { (eval echo configure:4190: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then rm -rf conftest* --- 4186,4202 ---- do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 ! echo "configure:4190: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ! { (eval echo configure:4200: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then rm -rf conftest* *************** *** 4216,4222 **** saved_libs="$LIBS" echo $ac_n "checking for main in -lpthreads""... $ac_c" 1>&6 ! echo "configure:4220: checking for main in -lpthreads" >&5 ac_lib_var=`echo pthreads'_'main | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 --- 4226,4232 ---- saved_libs="$LIBS" echo $ac_n "checking for main in -lpthreads""... $ac_c" 1>&6 ! echo "configure:4230: checking for main in -lpthreads" >&5 ac_lib_var=`echo pthreads'_'main | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 *************** *** 4224,4237 **** ac_save_LIBS="$LIBS" LIBS="-lpthreads $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else --- 4234,4247 ---- ac_save_LIBS="$LIBS" LIBS="-lpthreads $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else *************** *** 4252,4258 **** fi echo $ac_n "checking for main in -lpthread""... $ac_c" 1>&6 ! echo "configure:4256: checking for main in -lpthread" >&5 ac_lib_var=`echo pthread'_'main | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 --- 4262,4268 ---- fi echo $ac_n "checking for main in -lpthread""... $ac_c" 1>&6 ! echo "configure:4266: checking for main in -lpthread" >&5 ac_lib_var=`echo pthread'_'main | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 *************** *** 4260,4273 **** ac_save_LIBS="$LIBS" LIBS="-lpthread $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else --- 4270,4283 ---- ac_save_LIBS="$LIBS" LIBS="-lpthread $LIBS" cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else *************** *** 4307,4318 **** for ac_func in pthread_create pthread_self pthread_exit do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 ! echo "configure:4311: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 ! echo "configure:4321: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else --- 4345,4351 ---- ; return 0; } EOF ! if { (eval echo configure:4349: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else *************** *** 4362,4373 **** for ac_func in pthread_attr_init pthread_attr_setscope do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 ! echo "configure:4366: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 ! echo "configure:4376: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else --- 4400,4406 ---- ; return 0; } EOF ! if { (eval echo configure:4404: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else *************** *** 4417,4428 **** for ac_func in pthread_attr_setdetachstate do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 ! echo "configure:4421: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 ! echo "configure:4431: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else --- 4455,4461 ---- ; return 0; } EOF ! if { (eval echo configure:4459: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else *************** *** 4472,4483 **** for ac_func in pthread_detach do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 ! echo "configure:4476: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 ! echo "configure:4486: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else --- 4510,4516 ---- ; return 0; } EOF ! if { (eval echo configure:4514: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else *************** *** 4527,4538 **** for ac_func in pthread_sigmask pthread_kill do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 ! echo "configure:4531: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&6 ! echo "configure:4541: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else --- 4565,4571 ---- ; return 0; } EOF ! if { (eval echo configure:4569: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else *************** *** 4687,4692 **** --- 4697,5166 ---- fi + # Check whether --enable-ipv6 or --disable-ipv6 was given. + if test "${enable_ipv6+set}" = set; then + enableval="$enable_ipv6" + ipv6_support=$enableval + else + ipv6_support=guess + fi + + if test $ipv6_support = guess; then + echo $ac_n "checking IPv6 support by creating socket""... $ac_c" 1>&6 + echo "configure:4711: checking IPv6 support by creating socket" >&5 + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } + else + cat > conftest.$ac_ext < + #include + main() { exit(socket(PF_INET6, SOCK_DGRAM, 0) < 0); } + + EOF + if { (eval echo configure:4724: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null + then + ipv6_support=yes + else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + fi + rm -fr conftest* + fi + + if test $ipv6_support = yes; then + echo "$ac_t""yes" 1>&6 + else + echo "$ac_t""no" 1>&6 + fi + fi + if test $ipv6_support = yes; then + cat >> confdefs.h <<\EOF + #define SUPPORT_IPV6 1 + EOF + + echo $ac_n "checking IPv6 implementation""... $ac_c" 1>&6 + echo "configure:4746: checking IPv6 implementation" >&5 + ipv6probe=ng + if test $ipv6probe != ok; then + cat > conftest.$ac_ext < + #ifdef __KAME__ + kame_implementation + #endif + + EOF + if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "kame_implementation" >/dev/null 2>&1; then + rm -rf conftest* + is_kame=yes + else + rm -rf conftest* + is_kame=no + fi + rm -f conftest* + + if test $is_kame = yes; then + echo "$ac_t""KAME" 1>&6 + cat >> confdefs.h <<\EOF + #define KAME 1 + EOF + + ipv6probe=ok + fi + fi + if test $ipv6probe != ok; then + cat > conftest.$ac_ext < + #ifdef _PTCPIP_IN6_H_ + ptcpip_implementation + #endif + + EOF + if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "ptcpip_implementation" >/dev/null 2>&1; then + rm -rf conftest* + is_ptcpip=yes + else + rm -rf conftest* + is_ptcpip=no + fi + rm -f conftest* + + if test $is_ptcpip = yes; then + echo "$ac_t""PTCPIP" 1>&6 + cat >> confdefs.h <<\EOF + #define PTCPIP 1 + EOF + + ipv6probe=ok + fi + fi + if test $ipv6probe != ok; then + echo "$ac_t""unknown" 1>&6 + echo "configure: warning: Unknown IPv6 implementation." 1>&2 + fi + echo $ac_n "checking for main in -linet6""... $ac_c" 1>&6 + echo "configure:4811: checking for main in -linet6" >&5 + ac_lib_var=`echo inet6'_'main | sed 'y%./+-%__p_%'` + if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 + else + ac_save_LIBS="$LIBS" + LIBS="-linet6 $LIBS" + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" + else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" + fi + rm -f conftest* + LIBS="$ac_save_LIBS" + + fi + if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_lib=HAVE_LIB`echo inet6 | sed -e 's/[^a-zA-Z0-9_]/_/g' \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` + cat >> confdefs.h <&6 + fi + + + for r_lib_name in libinet6 + do + + ac_safe=`echo "$r_lib_name" | tr './\055' '___'` + echo $ac_n "checking for shared $r_lib_name""... $ac_c" 1>&6 + echo "configure:4859: checking for shared $r_lib_name" >&5 + if eval "test \"`echo '$''{'r_cv_name_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 + else + + case `uname -rs` in + IRIX*5.*) + if test -n "`ls /usr/lib/$ac_safe.so.* 2>/dev/null | sort -r | head -1`"; then + eval "r_cv_name_$ac_safe=`cd /usr/lib; ls $ac_safe.so.* | sort -r | head -1`" + elif test -n "`ls /lib/$ac_safe.so.* 2>/dev/null | sort -r | head -1`"; then + eval "r_cv_name_$ac_safe=`cd /lib; ls $ac_safe.so.* | sort -r | head -1`" + elif test -f /usr/lib/$ac_safe.so; then + eval "r_cv_name_$ac_safe=$ac_safe.so" + elif test -f /lib/$ac_safe.so; then + eval "r_cv_name_$ac_safe=$ac_safe.so" + fi + ;; + OSF1*) + if test -f /usr/shlib/$ac_safe.so; then + eval "r_cv_name_$ac_safe=$ac_safe.so" + elif test -f /usr/lib/$ac_safe.so; then + eval "r_cv_name_$ac_safe=$ac_safe.so" + elif test -f /lib/$ac_safe.so; then + eval "r_cv_name_$ac_safe=$ac_safe.so" + fi + ;; + Linux*) + if test -n "`ls /lib/$ac_safe.so.? 2>/dev/null | sort -r | head -1`"; then + eval "r_cv_name_$ac_safe=`cd /lib; ls $ac_safe.so.? | sort -r | head -1`" + elif test -n "`ls /usr/lib/$ac_safe.so.? 2>/dev/null | sort -r | head -1`"; then + eval "r_cv_name_$ac_safe=`cd /usr/lib; ls $ac_safe.so.* | sort -r | head -1`" + elif test -n "`ls /lib/$ac_safe.so.* 2>/dev/null | sort -r | head -1`"; then + eval "r_cv_name_$ac_safe=`cd /lib; ls $ac_safe.so.* | sort -r | head -1`" + elif test -n "`ls /usr/lib/$ac_safe.so.* 2>/dev/null | sort -r | head -1`"; then + eval "r_cv_name_$ac_safe=`cd /usr/lib; ls $ac_safe.so.* | sort -r | head -1`" + elif test -f /lib/$ac_safe.so; then + eval "r_cv_name_$ac_safe=$ac_safe.so" + elif test -f /usr/lib/$ac_safe.so; then + eval "r_cv_name_$ac_safe=$ac_safe.so" + fi + ;; + SunOS*) + if test -f /usr/lib/$ac_safe.so; then + eval "r_cv_name_$ac_safe=$ac_safe.so" + elif test -n "`ls /usr/lib/$ac_safe.so.* 2>/dev/null | sort -r | head -1`"; then + eval "r_cv_name_$ac_safe=`cd /usr/lib; ls $ac_safe.so.* | sort -r | head -1`" + elif test -f /lib/$ac_safe.so; then + eval "r_cv_name_$ac_safe=$ac_safe.so" + elif test -n "`ls /lib/$ac_safe.so.* 2>/dev/null | sort -r | head -1`"; then + eval "r_cv_name_$ac_safe=`cd /lib; ls $ac_safe.so.* | sort -r | head -1`" + fi + ;; + dgux*) + if test -f /usr/dglib/$ac_safe.so; then + eval "r_cv_name_$ac_safe=$ac_safe.so" + elif test -n "`ls /usr/dglib/$ac_safe.so.* 2>/dev/null | sort -r | head -1`"; then + eval "r_cv_name_$ac_safe=`cd /usr/dglib; ls $ac_safe.so.* | sort -r | head -1`" + fi + ;; + FreeBSD*) + if test -f /lib/$ac_safe.so; then + eval "r_cv_name_$ac_safe=/lib/$ac_safe.so" + elif test -n "`ls /lib/$ac_safe.so.* 2>/dev/null | sort -r | head -1`"; then + eval "r_cv_name_$ac_safe=`ls /lib/$ac_safe.so.* | sort -r | head -1`" + elif test -f /usr/lib/$ac_safe.so; then + eval "r_cv_name_$ac_safe=/usr/lib/$ac_safe.so" + elif test -n "`ls /usr/lib/$ac_safe.so.* 2>/dev/null | sort -r | head -1`"; then + eval "r_cv_name_$ac_safe=`ls /usr/lib/$ac_safe.so.* | sort -r | head -1`" + fi + ;; + *) + if test -f /lib/$ac_safe.so; then + eval "r_cv_name_$ac_safe=$ac_safe.so" + elif test -n "`ls /lib/$ac_safe.so.* 2>/dev/null | sort -r | head -1`"; then + eval "r_cv_name_$ac_safe=`cd /lib; ls $ac_safe.so.* | sort -r | head -1`" + elif test -f /usr/lib/$ac_safe.so; then + eval "r_cv_name_$ac_safe=$ac_safe.so" + elif test -n "`ls /usr/lib/$ac_safe.so.* 2>/dev/null | sort -r | head -1`"; then + eval "r_cv_name_$ac_safe=`cd /usr/lib; ls $ac_safe.so.* | sort -r | head -1`" + fi + ;; + esac + + fi + ac_result=`eval echo '$r_cv_name_'$ac_safe` + if test "$ac_result" != ""; then + echo "$ac_t""$ac_result" 1>&6 + + r_fixed=`echo $r_lib_name | tr '[a-z]./\055' '[A-Z]___'`_NAME + cat >> confdefs.h <&6 + fi + done + + if test "yes" = "no"; then + cat >> confdefs.h <&6 + echo "configure:4966: checking for $ac_hdr" >&5 + if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 + else + cat > conftest.$ac_ext < + EOF + ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" + { (eval echo configure:4976: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } + ac_err=`grep -v '^ *+' conftest.out` + if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" + else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" + fi + rm -f conftest* + fi + if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 + fi + done + + for ac_func in gethostbyname2 getnodebyname getipnodebyname freehostent getaddrinfo freeaddrinfo + do + echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 + echo "configure:5005: checking for $ac_func" >&5 + if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 + else + cat > conftest.$ac_ext < + /* Override any gcc2 internal prototype to avoid an error. */ + /* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ + char $ac_func(); + + int main() { + + /* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ + #if defined (__stub_$ac_func) || defined (__stub___$ac_func) + choke me + #else + $ac_func(); + #endif + + ; return 0; } + EOF + if { (eval echo configure:5033: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" + else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" + fi + rm -f conftest* + fi + + if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 + fi + done + + fi + # Check whether --enable-mapped-address or --disable-mapped-address was given. + if test "${enable_mapped_address+set}" = set; then + enableval="$enable_mapped_address" + mapped_addr=$enableval + else + mapped_addr=yes + fi + + if test $mapped_addr = yes; then + cat >> confdefs.h <<\EOF + #define SUPPORT_MAPPED_ADDRESS 1 + EOF + + fi + # Check whether --with-ipv6-ping or --without-ipv6-ping was given. + if test "${with_ipv6_ping+set}" = set; then + withval="$with_ipv6_ping" + ping6=$withval + else + ping6=ping6 + fi + + # Check whether --with-ipv6-traceroute or --without-ipv6-traceroute was given. + if test "${with_ipv6_traceroute+set}" = set; then + withval="$with_ipv6_traceroute" + troute6=$withval + else + troute6=traceroute6 + fi + + # Extract the first word of "$ping6", so it can be a program name with args. + set dummy $ping6; ac_word=$2 + echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 + echo "configure:5091: checking for $ac_word" >&5 + if eval "test \"`echo '$''{'ac_cv_path_ping6path'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 + else + case "$ping6path" in + /*) + ac_cv_path_ping6path="$ping6path" # Let the user override the test with a path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_ping6path="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_path_ping6path" && ac_cv_path_ping6path="notexist" + ;; + esac + fi + ping6path="$ac_cv_path_ping6path" + if test -n "$ping6path"; then + echo "$ac_t""$ping6path" 1>&6 + else + echo "$ac_t""no" 1>&6 + fi + + # Extract the first word of "$troute6", so it can be a program name with args. + set dummy $troute6; ac_word=$2 + echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 + echo "configure:5123: checking for $ac_word" >&5 + if eval "test \"`echo '$''{'ac_cv_path_troute6path'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 + else + case "$troute6path" in + /*) + ac_cv_path_troute6path="$troute6path" # Let the user override the test with a path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_troute6path="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_path_troute6path" && ac_cv_path_troute6path="notexist" + ;; + esac + fi + troute6path="$ac_cv_path_troute6path" + if test -n "$troute6path"; then + echo "$ac_t""$troute6path" 1>&6 + else + echo "$ac_t""no" 1>&6 + fi + + if test $ping6path != notexist; then + cat >> confdefs.h <> confdefs.h <&6 ! echo "configure:4707: checking shared library support" >&5 if test "$ac_cv_func_dlopen" = "yes" -o "$ac_cv_func_shl_load" = "yes"; then SHARED_LIBSOCKS5_CFLAGS="-DFOR_SHARED_LIBRARY -DIN_LIBRARY" if test "$ac_cv_func_dlopen" = "yes"; then SHLIB_LIB="libsocks5_sh.so"; fi --- 5177,5183 ---- PRELOADS="echo Shared libraries not supported; exit; :" PRELOADA="" echo $ac_n "checking shared library support""... $ac_c" 1>&6 ! echo "configure:5181: checking shared library support" >&5 if test "$ac_cv_func_dlopen" = "yes" -o "$ac_cv_func_shl_load" = "yes"; then SHARED_LIBSOCKS5_CFLAGS="-DFOR_SHARED_LIBRARY -DIN_LIBRARY" if test "$ac_cv_func_dlopen" = "yes"; then SHLIB_LIB="libsocks5_sh.so"; fi *************** *** 4978,4983 **** --- 5452,5459 ---- s%@ORIG_FINGER@%$ORIG_FINGER%g s%@TROUTEPROG@%$TROUTEPROG%g s%@PINGPROG@%$PINGPROG%g + s%@ping6path@%$ping6path%g + s%@troute6path@%$troute6path%g s%@DLLIBS@%$DLLIBS%g s%@SHLIB_LD@%$SHLIB_LD%g s%@SHLIB_DIR@%$SHLIB_DIR%g Index: configure.in diff -c src/socks5/configure.in:1.1.1.6 src/socks5/configure.in:1.9.2.5 *** configure.in Thu Aug 5 13:20:52 1999 --- configure.in Thu Aug 5 17:50:39 1999 *************** *** 207,212 **** --- 207,295 ---- AC_ARG_WITH(passwd, --with-passwd=val Turn on use of passwd file for passwords, AC_DEFINE(USE_PASSWD)) AC_ARG_WITH(shadow-passwd, --with-shadow-passwd=val Turn on use of shadow passwd file for passwords, AC_DEFINE(USE_SHADOW_PASSWD)) + dnl IPv6 staff. + AC_ARG_ENABLE(ipv6, + [--enable-ipv6 Enable IPv6 support + --disable-ipv6 Disable IPv6 support], + ipv6_support=$enableval, ipv6_support=guess) + if test $ipv6_support = guess; then + AC_MSG_CHECKING([IPv6 support by creating socket]) + dnl AC_EGREP_HEADER([struct sockaddr_in6], netinet/in.h, ipv6_support=yes) + AC_TRY_RUN([ + #include + #include + main() { exit(socket(PF_INET6, SOCK_DGRAM, 0) < 0); } + ], ipv6_support=yes) + if test $ipv6_support = yes; then + AC_MSG_RESULT(yes) + else + AC_MSG_RESULT(no) + fi + fi + if test $ipv6_support = yes; then + AC_DEFINE(SUPPORT_IPV6) + AC_MSG_CHECKING([IPv6 implementation]) + ipv6probe=ng + if test $ipv6probe != ok; then + AC_EGREP_CPP(kame_implementation, + [#include + #ifdef __KAME__ + kame_implementation + #endif + ], is_kame=yes, is_kame=no) + if test $is_kame = yes; then + AC_MSG_RESULT(KAME) + AC_DEFINE(KAME) + ipv6probe=ok + fi + fi + if test $ipv6probe != ok; then + AC_EGREP_CPP(ptcpip_implementation, + [#include + #ifdef _PTCPIP_IN6_H_ + ptcpip_implementation + #endif + ], is_ptcpip=yes, is_ptcpip=no) + if test $is_ptcpip = yes; then + AC_MSG_RESULT(PTCPIP) + AC_DEFINE(PTCPIP) + ipv6probe=ok + fi + fi + if test $ipv6probe != ok; then + AC_MSG_RESULT(unknown) + AC_MSG_WARN([Unknown IPv6 implementation.]) + fi + AC_CHECK_LIB(inet6, main) + AC_CHECK_SHLIBS(libinet6) + if test "yes" = "no"; then + AC_DEFINE_UNQUOTED(LIBINET6_NAME) + fi + AC_CHECK_HEADERS(resolv.h arpa/nameser.h) + AC_CHECK_FUNCS(gethostbyname2 getnodebyname getipnodebyname freehostent getaddrinfo freeaddrinfo) + fi + AC_ARG_ENABLE(mapped-address, + [--enable-mapped-address Enable IPv4-mapped IPv6 address (default) + --disable-mapped-address Enable IPv4-mapped IPv6 address], + mapped_addr=$enableval, mapped_addr=yes) + if test $mapped_addr = yes; then + AC_DEFINE(SUPPORT_MAPPED_ADDRESS) + fi + AC_ARG_WITH(ipv6-ping, + [--with-ipv6-ping=PATH Specify the pathname of 'ping' program for IPv6], + ping6=$withval, ping6=ping6) + AC_ARG_WITH(ipv6-traceroute, + [--with-ipv6-traceroute=PATH Specify the pathname of 'traceroute' program for IPv6], + troute6=$withval, troute6=traceroute6) + AC_PATH_PROG(ping6path, $ping6, notexist) + AC_PATH_PROG(troute6path, $troute6, notexist) + if test $ping6path != notexist; then + AC_DEFINE_UNQUOTED(PING6PROG, "$ping6path") + fi + if test $troute6path != notexist; then + AC_DEFINE_UNQUOTED(TROUTE6PROG, "$troute6path") + fi + AC_MAKE_SHAREDLIB AC_SUBST(SHLIB_LFLAGS) AC_SUBST(SHLIB_LIBS) Index: clients/pt/rping.c diff -c src/socks5/clients/pt/rping.c:1.1.1.2 src/socks5/clients/pt/rping.c:1.2.4.1 *** clients/pt/rping.c Thu Apr 1 11:05:01 1999 --- clients/pt/rping.c Wed Apr 7 14:35:35 1999 *************** *** 17,31 **** S5NetAddr rsin; lsSocksInfo *pcon; struct hostent *rhp; ! if (argc != 2 || *argv[1] == '-') { fprintf(stderr, "Usage: %s host\n", argv[0]); exit(-1); } if (LIBPREFIX2(init)(NULL) != 0) EXITERROR(-1); memset((char *)&rsin, 0, sizeof(S5NetAddr)); rsin.sin.sin_family = AF_INET; if ((rsin.sin.sin_addr.s_addr = inet_addr(argv[1])) == INVALIDADDR) { --- 17,71 ---- S5NetAddr rsin; lsSocksInfo *pcon; struct hostent *rhp; ! #ifdef SUPPORT_IPV6 ! char *host; ! int af = AF_INET; ! #endif ! ! #ifdef SUPPORT_IPV6 ! if (argc == 3) { ! if (!strcmp(argv[1], "-ipv4")) { ! af = AF_INET; ! } else if (!strcmp(argv[1], "-ipv6")) { ! af = AF_INET6; ! } else { ! goto usage; ! } ! host = argv[2]; ! } else if (argc == 2 && argv[1][0] != '-') { ! host = argv[1]; ! } else { ! usage: ! fprintf(stderr, "Usage: %s [-ipv4|-ipv6] host\n", argv[0]); ! exit(-1); ! } ! #else if (argc != 2 || *argv[1] == '-') { fprintf(stderr, "Usage: %s host\n", argv[0]); exit(-1); } + #endif if (LIBPREFIX2(init)(NULL) != 0) EXITERROR(-1); memset((char *)&rsin, 0, sizeof(S5NetAddr)); + #ifdef SUPPORT_IPV6 + if (inet_pton(AF_INET, host, &rsin.sin.sin_addr) > 0) { + rsin.sa.sa_family = AF_INET; + } else if (inet_pton(AF_INET6, host, &rsin.sin6.sin6_addr) > 0) { + rsin.sa.sa_family = AF_INET6; + } else if ((rhp = LIBPREFIX(gethostbyname2)(host, AF_INET)) != NULL || + (rhp = LIBPREFIX(gethostbyname2)(host, AF_INET6)) != NULL) { + rsin.sa.sa_family = rhp->h_addrtype; + if (rhp->h_addrtype == AF_INET) { + memcpy(&rsin.sin.sin_addr, rhp->h_addr, rhp->h_length); + } else { + memcpy(&rsin.sin6.sin6_addr, rhp->h_addr, rhp->h_length); + } + } else { + EXITERROR(-1); + } + #else rsin.sin.sin_family = AF_INET; if ((rsin.sin.sin_addr.s_addr = inet_addr(argv[1])) == INVALIDADDR) { *************** *** 34,41 **** --- 74,86 ---- memcpy((char *)&rsin.sin.sin_addr.s_addr, (char *)rhp->h_addr_list[0], rhp->h_length); rsin.sin.sin_family = rhp->h_addrtype; } + #endif + #ifdef SUPPORT_IPV6 + if ((fd = socket(af, SOCK_STREAM, 0)) == S5InvalidIOHandle) return -1; + #else if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == S5InvalidIOHandle) return -1; + #endif Signal(SIGPIPE, SIG_IGN); if ((pcon = lsLibProtoExchg(fd, &rsin, SOCKS_PING)) == NULL) { *************** *** 46,51 **** --- 91,107 ---- if (!pcon->pri || pcon->pri->how == DIRECT || !lsAddrAddrComp(&rsin, &pcon->pri->prxyin)) { LIBPREFIX(close)(fd); + #ifdef SUPPORT_IPV6 + if (rsin.sa.sa_family == AF_INET6) { + #ifndef PING6PROG + fprintf(stderr, "Real ping unavailable.\n"); + exit(0); + #else + execlp(PING6PROG, "ping", argv[1], NULL); + _exit(0); + #endif + } + #endif #ifndef PINGPROG fprintf(stderr, "Real ping unavailable.\n"); exit(0); Index: clients/pt/rtrace.c diff -c src/socks5/clients/pt/rtrace.c:1.1.1.2 src/socks5/clients/pt/rtrace.c:1.3.4.2 *** clients/pt/rtrace.c Thu Apr 1 11:04:59 1999 --- clients/pt/rtrace.c Wed Apr 7 14:35:35 1999 *************** *** 28,35 **** --- 28,42 ---- } } + #ifdef SUPPORT_IPV6 + static int Popen(const char *name, int af) { + #else static int Popen(const char *name) { + #endif int pds[2]; + #ifdef SUPPORT_IPV6 + char *cmd = NULL; + #endif if (pipe(pds) < 0) return -1; if (dup2(pds[0], STDIN_FILENO) < 0) return -1; *************** *** 43,51 **** if (dup2(pds[1], STDERR_FILENO) < 0) _exit(1); close(pds[1]); if (noname) execlp(TROUTEPROG, "traceroute", "-n", (verbose?"-v":name), verbose?name:NULL, NULL); else execlp(TROUTEPROG, "traceroute", (verbose?"-v":name), verbose?name:NULL, NULL); ! _exit(1); } --- 50,72 ---- if (dup2(pds[1], STDERR_FILENO) < 0) _exit(1); close(pds[1]); + #ifdef SUPPORT_IPV6 + if (af == AF_INET) { + #ifdef TROUTEPROG + cmd = TROUTEPROG; + #endif + } else { + #ifdef TROUTE6PROG + cmd = TROUTE6PROG; + #endif + } + if (cmd == NULL) _exit(0); + if (noname) execlp(cmd, "traceroute", "-n", (verbose?"-v":name), verbose?name:NULL, NULL); + else execlp(cmd, "traceroute", (verbose?"-v":name), verbose?name:NULL, NULL); + #else if (noname) execlp(TROUTEPROG, "traceroute", "-n", (verbose?"-v":name), verbose?name:NULL, NULL); else execlp(TROUTEPROG, "traceroute", (verbose?"-v":name), verbose?name:NULL, NULL); ! #endif _exit(1); } *************** *** 57,64 **** static int TraceProxy(S5NetAddr *proxy) { int childpid, ret; if ((childpid = Popen(lsAddr2Ascii(proxy))) < 0) return -1; ! fprintf(stdout, "Traceroute to the proxy server %s\n", lsAddr2Ascii(proxy)); ret = DataRelay(STDIN_FILENO, NULL, childpid); --- 78,88 ---- static int TraceProxy(S5NetAddr *proxy) { int childpid, ret; + #ifdef SUPPORT_IPV6 + if ((childpid = Popen(lsAddr2Ascii(proxy), proxy->sa.sa_family)) < 0) return -1; + #else if ((childpid = Popen(lsAddr2Ascii(proxy))) < 0) return -1; ! #endif fprintf(stdout, "Traceroute to the proxy server %s\n", lsAddr2Ascii(proxy)); ret = DataRelay(STDIN_FILENO, NULL, childpid); *************** *** 82,88 **** --- 106,116 ---- */ void usage(char *progname) { + #ifdef SUPPORT_IPV6 + fprintf(stderr, "Usage: %s [-n] [-v] [-ipv4|-ipv6] host\n", progname); + #else fprintf(stderr, "Usage: %s [-n] [-v] host\n", progname); + #endif exit(-1); } *************** *** 92,102 **** --- 120,137 ---- S5NetAddr rsin; lsSocksInfo *pcon; struct hostent *rhp; + #ifdef SUPPORT_IPV6 + int af = AF_INET; + #endif for (progname = *argv, argc--, argv++; argc > 0; argc--, argv++) { if (**argv == '-') { if (!strcmp(*argv, "-n")) noname = 1; else if (!strcmp(*argv, "-v")) verbose = 1; + #ifdef SUPPORT_IPV6 + else if (!strcmp(*argv, "-ipv4")) af = AF_INET; + else if (!strcmp(*argv, "-ipv6")) af = AF_INET6; + #endif else { fprintf(stderr, "%s: Unrecognized option %s\n", progname, *argv); usage(progname); *************** *** 111,116 **** --- 146,168 ---- if (LIBPREFIX2(init)(NULL) != 0) EXITERROR(-1); memset((char *)&rsin, 0, sizeof(S5NetAddr)); + #ifdef SUPPORT_IPV6 + if (inet_pton(AF_INET, hostname, &rsin.sin.sin_addr) > 0) { + rsin.sa.sa_family = AF_INET; + } else if (inet_pton(AF_INET6, hostname, &rsin.sin6.sin6_addr) > 0) { + rsin.sa.sa_family = AF_INET6; + } else if ((rhp = LIBPREFIX(gethostbyname2)(hostname, AF_INET)) != NULL || + (rhp = LIBPREFIX(gethostbyname2)(hostname, AF_INET6)) != NULL) { + rsin.sa.sa_family = rhp->h_addrtype; + if (rhp->h_addrtype == AF_INET) { + memcpy(&rsin.sin.sin_addr, rhp->h_addr, rhp->h_length); + } else { + memcpy(&rsin.sin6.sin6_addr, rhp->h_addr, rhp->h_length); + } + } else { + EXITERROR(-1); + } + #else rsin.sin.sin_family = AF_INET; if ((rsin.sin.sin_addr.s_addr = inet_addr(hostname)) == INVALIDADDR) { *************** *** 119,126 **** --- 171,183 ---- memcpy((char *)&rsin.sin.sin_addr.s_addr, (char *)rhp->h_addr_list[0], rhp->h_length); rsin.sin.sin_family = rhp->h_addrtype; } + #endif + #ifdef SUPPORT_IPV6 + if ((fd = socket(af, SOCK_STREAM, 0)) == S5InvalidIOHandle) return -1; + #else if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == S5InvalidIOHandle) return -1; + #endif Signal(SIGPIPE, SIG_IGN); if ((pcon = lsLibProtoExchg(fd, &rsin, SOCKS_TRACER)) == NULL) { *************** *** 131,136 **** --- 188,210 ---- if (!pcon->pri || pcon->pri->how == DIRECT || !lsAddrAddrComp(&rsin, &pcon->pri->prxyin)) { LIBPREFIX(close)(fd); + #ifdef SUPPORT_IPV6 + if (rsin.sa.sa_family == AF_INET6) { + #ifndef TROUTE6PROG + fprintf(stderr, "Real traceroute unavailable.\n"); + exit(0); + #else + if (noname) { + execlp(TROUTE6PROG, "traceroute", "-n", + (verbose?"-v":hostname), verbose?hostname:NULL, NULL); + } else { + execlp(TROUTE6PROG, "traceroute", + (verbose?"-v":hostname), verbose?hostname:NULL, NULL); + } + _exit(1); + #endif + } + #endif /* SUPPORT_IPV6 */ #ifndef TROUTEPROG fprintf(stderr, "Real traceroute unavailable.\n"); exit(0); Index: doc/draft-ietf-ngtrans-socks-gateway-02.txt diff -c /dev/null src/socks5/doc/draft-ietf-ngtrans-socks-gateway-02.txt:1.1.2.1 *** doc/draft-ietf-ngtrans-socks-gateway-02.txt Fri Aug 20 14:27:18 1999 --- doc/draft-ietf-ngtrans-socks-gateway-02.txt Mon Aug 16 11:23:50 1999 *************** *** 0 **** --- 1,708 ---- + INTERNET-DRAFT H. Kitamura + NEC Corporation + Expires in six months A. Jinzaki + S. Kobayashi + Fujitsu Laboratories LTD. + 29 July 1999 + + A SOCKS-based IPv6/IPv4 Gateway Mechanism + + + Status of this Memo + + This document is an Internet-Draft and is in full conformance with + all provisions of Section 10 of RFC2026. + + Internet-Drafts are working documents of the Internet Engineering + Task Force (IETF), its areas, and its working groups. Note that + other groups may also distribute working documents as Internet- + Drafts. + + Internet-Drafts are draft documents valid for a maximum of six months + and may be updated, replaced, or obsoleted by other documents at any + time. It is inappropriate to use Internet- Drafts as reference + material or to cite them other than as "work in progress." + + The list of current Internet-Drafts can be accessed at + http://www.ietf.org/ietf/1id-abstracts.txt + + The list of Internet-Draft Shadow Directories can be accessed at + http://www.ietf.org/shadow.html. + + Abstract + + This document describes an IPv6/IPv4 gateway mechanism that is based + on the SOCKS protocol [SOCKSv5]. By enhancing the SOCKS mechanism to + support the heterogeneous communications relays between IPv6 and IPv4 + at the SOCKS server, the SOCKS-based IPv6/IPv4 gateway mechanism is + accomplished. + + The SOCKS-based gateway mechanism enables the IPv6 nodes and IPv4 + nodes to communicate with each other smoothly without sacrificing any + conveniences and functionalities of current communication methods. + + H. Kitamura et al. [Page 1] + + INTERNET-DRAFT A SOCKS-based IPv6/IPv4 Gateway July 1999 + + 1. Introduction + + This document describes an IPv6/IPv4 gateway mechanism that is based + on the SOCKS protocol [SOCKSv5]. By enhancing the SOCKS mechanism to + support heterogeneous communications, the SOCKS-based IPv6/IPv4 + gateway mechanism is accomplished. + + The SOCKS-based gateway mechanism is designed to satisfy the + following requirements. + + 1. Maintain the conveniences of current IPv4 communication methods + and frameworks (infrastructure) of existing communication networks + (e.g., DNS). + + 2. Utilize existing user applications that are designed only for IPv4 + communications to heterogeneous communications without modifying + them. + + 3. Be scalable and able to support the translations for various IPv4 + and IPv6 communication services. + + 4. Can easily introduce IPv6 new features (e.g., IPsec). + + Since the SOCKS-based IPv6/IPv4 gateway mechanism is based on + relaying two "terminated" IPv4 and IPv6 connections, most problems of + the NAT-based translator mechanisms are eliminated. + + Another advantage of the mechanism is that there is no need to modify + the DNS system, because it has a mechanism that enable the DNS name + resolving actions of SOCKS clients to be delegated to an enhanced + SOCKS server that has both IPv6 and IPv4 stacks. + + This DNS name resolving delegation mechanism is realized by modifying + (socksifying) client applications. This is a constraint. To eliminate + the need to modify the DNS system, it is necessary to socksify the + applications. Thus, there is a dilemma in that either socksification + or DNS modification is necessary. + + Also, the mechanism has the following additional by-product benefits. + Since the SOCKS-based gateway mechanism has much flexibility, it can + support various topologies that mix IPv4 and IPv6 communications. In + case of multiple chained relay topologies, the SOCKS-based gateway + mechanism can realize similar topologies that are supported by packet + tunneling techniques. Compared with other translator mechanisms, the + SOCKS-based gateway mechanism has the following benefits. There is no + packet fragmentation vulnerability, and the connection can be + authenticated by the native SOCKS authentication methods. + + H. Kitamura et al. [Page 2] + + INTERNET-DRAFT A SOCKS-based IPv6/IPv4 Gateway July 1999 + + 2. Basic SOCKS-based Gateway Mechanism + + The Fig. 1 shows the basic SOCKS-based gateway mechanism. + + Client C Gateway G Destination D + +-----------+ (Server) + |Application| + +-->+===========+ +-------------+ +-----------+ + same-+ |*SOCKS Lib*| | *Gateway* | |Application| + API +-->+===========+ +=====---=====+ +-----------+ + | Socket DNS| | Socket DNS | | Socket DNS| + +-----------+ +-------------+ +-----------+ + | [ IPv X ] | |[IPvX]|(IPvY)| | ( IPv Y ) | + +-----------+ +-------------+ +-----------+ + |Network I/F| | Network I/F | |Network I/F| + +-----+-----+ +---+-----+---+ +-----+-----+ + | | | | + +============+ +------------+ + socksified normal + connection connection + (ctrl)+data data only + + Fig. 1 Basic SOCKS-based Gateway Mechanism + + In this figure, the Client C initiates the communication to the + Destination D. Two new functional blocks that compose the system are + introduced. + + One, *Socks Lib*, is introduced into the client side (Client C) (this + procedure is called "socksifying"). It is located between application + layer and socket layer, and can replace applications' socket APIs and + DNS name resolving APIs (e.g., gethostbyname(), getaddrinfo() etc.) + dynamically. A mapping management table exists in it for "DNS name + resolving delegation" mechanism (described below). Each socksified + application has its own *Socks Lib*. + + The other, *Gateway*, is an enhanced SOCKS server. It is installed on + the IPv6 and IPv4 dual stack node (Gateway G). All types of protocol + combinations are relayed there between Client C (IPvX) and + Destination D (IPvY). The *Socks Lib* invokes it. Each *Gateway* + takes charge of one socksified connection. + + H. Kitamura et al. [Page 3] + + INTERNET-DRAFT A SOCKS-based IPv6/IPv4 Gateway July 1999 + + The following four types of combinations of IPvX and IPvY are + possible in this mechanism. + + type C ------ G ------ D + [IPvX] (IPvY) + A IPv4 IPv4 homogeneous (normal SOCKS) + B IPv4 IPv6 * heterogeneous * + C IPv6 IPv4 * heterogeneous * + D IPv6 IPv6 homogeneous + + Type A is supported by the normal SOCKS mechanism. Type B and C are + the main targets for the SOCKS-based gateway mechanism. They provide + heterogeneous communication topologies. Type D can be supported by + the natural extension of the SOCKS mechanism, because it is a + homogeneous communication. + + The *Socks Lib* communicates with the *Gateway* by using SOCKS + protocol [SOCKSv5]. The connection between the Client C and the + Gateway G is called a "socksified connection." It can transfer not + only data but also control information (e.g. location information of + the Destination, etc.). + + In order to provide appropriate destination information to the + application on the Client C, the *Socks Lib* also replaces other + types of socket APIs (e.g., getpeername(), etc.) that provide + information about the destination, and necessary information for this + replacement is transferred via the socksified connection. This + mechanism provides the same usability of current communication + methods to the applications on the Client C, and it is not necessary + to modify the applications at all to utilize this mechanism. + + The connection between the Gateway G and the Destination D is an + ordinary connection. Server applications on Destination D understand + that the source of the connection is the Gateway G (not Client C). It + is not necessary to modify (socksify) them. + + 3. DNS Name Resolving Procedure + + As [TRANSMECH] mentioned, it is essential for the transition + mechanisms to cooperate with the DNS name resolving mechanism. The + SOCKS-based gateway mechanism has the capability to cooperate with it + without modifying the DNS system. This function is one of the big + advantages of the SOCKS-based gateway mechanism. + + In this section, the procedure of how the SOCKS-based gateway + mechanism cooperate with the DNS name resolving mechanism is + described. + + H. Kitamura et al. [Page 4] + + INTERNET-DRAFT A SOCKS-based IPv6/IPv4 Gateway July 1999 + + 1. An application on the source terminal (Client C) tries to get the + IP address information of the destination terminal (Destination D) by + calling the DNS name resolving function (e.g., gethostbyname2()). At + this time, the logical host name ("FQDN") information of the + Destination D is passed to the *Socks Lib* as an argument of called + APIs. + + 2. Since the *Socks Lib* has replaced such DNS name resolving APIs, + the real DNS name resolving APIs is not called here. The argued + "FQDN" information is merely registered into a mapping management + table of *Socks Lib*, and a "fake IP" address is selected as a reply + value from a reserved special IP address space that is never used in + real communications. The "fake IP" address must be suitable for + requests called by the applications. Namely, it must belong to the + same address family of the Client C, even if the address family of + the Destination D is different from it. After the selected "fake IP" + address is registered into the mapping management table as a pair + with the "FQDN", it is replied to the application. + + 3. The application receives the "fake IP" address, and prepares a + socket. The "fake IP" address information is used as an element of + the "socket". The application calls socket APIs (e.g., connect()) to + start a communication. The "socket" is used as an argument of them. + + 4. Since the *Socks Lib* has replaced such socket APIs, the real + socket function is not called. The IP address information of the + argued socket is checked. If the address belongs to the special + address space for the fake address, the matched registered "FQDN" + information of the "fake IP" address is obtained from the mapping + management table. + + 5. The "FQDN" information is transferred to the *Gateway* on the + relay server (Gateway G) by using the SOCKS command that is matched + to the called socket APIs. (In case of connect(), the CONNECT command + is used.) + + 6. Finally, the *Gateway* calls the real DNS name resolving APIs + (e.g., gethostbyname2()). At this time, the received "FQDN" + information is used as an argument of the called APIs. + + 7. The *Gateway* receives the "real IP" address from a DNS server, + and creates a "socket", The "real IP" address information is used as + an element of the "socket". + + 8. The *Gateway* calls socket APIs (e.g., connect()) to communicate + with the Destination D. The "socket" is used as an argument of them. + + By using this mechanism, DNS name resolving actions are delegated + + H. Kitamura et al. [Page 5] + + INTERNET-DRAFT A SOCKS-based IPv6/IPv4 Gateway July 1999 + + from the source terminal (Client C) to the relay server (Gateway G). + Thus the mechanism is called "DNS name resolving delegation." + + * DNS Name Resolving Delegation and address mapping + + The advantages of the "DNS name resolving delegation" mechanism come + from the fact that the DNS name resolving actions are taken at the + relay server (Gateway G). Since the relay server is an IPv4 and IPv6 + dual stack node, DNS name resolving queries for any types of + destinations can be done without causing problems. It is not + necessary to modify the existing DNS mechanism at all. + + Without this mechanism, an IPv4 application can not resolve the host + name of an IPv6 destination. Even if it can get the IPv6 address by + some method, it is impossible for the IPv4 application to deal with + such an IPv6 address. It is impossible because the IPv6 address is + four times longer than the IPv4 address, and the IPv4 application + does not have any long address space in which to store it. + + Using this mechanism brings forth an additional advantage: an IPv4 + application can also use a numerical IPv6 address expression to + specify an IPv6 destination terminal. Since the IPv6 address + expression includes colons (":"), it is identified as an FQDN + expression (not a numerical IP expression) for the IPv4 application. + Thus the numerical IPv6 address expression is treated the same as the + DNS expression in the "DNS name resolving delegation" mechanism. + + The problem with the mechanism is that a failure of the DNS name + resolving process is detected incorrectly at the source terminal + (Client C). It is detected as a failure of the connection creation. + + * Address Translation and Mapping + + One of the good characteristics of the SOCKS-based gateway mechanism + is its ability to manage address translation and mapping wisely. + + In case of the NAT-based transparent model translator mechanism + (e.g., [NATPT]), it is necessary to reserve global and wide address + space for the address mapping. Also, complex address allocation and + management mechanisms (by introducing address mappers, etc.) are + needed. + + In case of the SOCKS-based gateway mechanism, such complex mechanisms + are not necessary, because corresponding address mapping is done at + the *Socks Lib* by using the fake IP address and the mapping + management table. The mapping management table is prepared on each + application. It is locally closed and independent from others. + + H. Kitamura et al. [Page 6] + + INTERNET-DRAFT A SOCKS-based IPv6/IPv4 Gateway July 1999 + + Therefore, it is easy to manage the table, and it is not necessary to + reserve global and wide address space. + + As [CATTRANS] mentioned, the SOCKS-based gateway mechanism is free of + the address mapping problem. + + 4. Multiple Chained Relay Mechanism (Advanced usage) + + The SOCKS-based gateway mechanism has the flexibility to support + multiple chained relay topologies. With the mechanism, IPv4 and IPv6 + mixed various communication topologies are realized. + + The Fig. 2 shows the structure of the multiple chained relay + mechanism. + + Client C Gateway G1 Gateway G2 Destination D + +-----------+ (Server 1) (Server 2) + |Application| + +===========+ +-------------+ +-------------+ +-----------+ + |*SOCKS Lib*| | *Gateway1* | | *Gateway2* | |Application| + +===========+ +=====---=====+ +=====---=====+ +-----------+ + | Socket DNS| | Socket DNS | | Socket DNS | | Socket DNS| + +-----------+ +-------------+ +-------------+ +-----------+ + | [ IPv X ] | |[IPvX]|(IPvY)| |(IPvY)|{IPvZ}| | { IPv Z } | + +-----------+ +-------------+ +-------------+ +-----------+ + |Network I/F| | Network I/F | | Network I/F | |Network I/F| + +-----+-----+ +---+-----+---+ +---+-----+---+ +-----+-----+ + | | | | | | + +============+ +==========+ +------------+ + socksified socksified normal + connection connection connection + (ctrl)+data (ctrl)+data data only + + Fig. 2 Multiple Chained Relay Mechanism + + In this figure, the source terminal (Client C) initiates the + communication with the destination (Destination D). Underneath, the + connection is replaced with three connections, and they are relayed + at the two relay servers (Gateway G1 and G2). The *Gateway* includes + the same type of the functions of *Socks Lib*. By enabling the *Socks + Lib* functions at the *Gateway1* on the first relay server (Gateway + G1), the multiple chained relay topology is realized + + There is no limitation on the number of relay operations between the + source terminal and the destination terminal. It is possible to have + more than two intermediate relay servers. To simplify the + + H. Kitamura et al. [Page 7] + + INTERNET-DRAFT A SOCKS-based IPv6/IPv4 Gateway July 1999 + + explanation, twice-relayed topology is shown here. All types of the + protocol relay combinations are possible. + + In case of twice-relayed topology, the following eight types of + combinations of IPvX, IPvY, and IPvZ are possible. + + type C ------ G1 ------ G2 ------ D + [IPvX] (IPvY) {IPvZ} + E IPv4 IPv4 IPv4 homogeneous (normal SOCKS) + F IPv4 IPv4 IPv6 * heterogeneous * + G IPv4 IPv6 IPv4 * heterogeneous * (tunnel-like) + H IPv4 IPv6 IPv6 * heterogeneous * + I IPv6 IPv4 IPv4 * heterogeneous * + J IPv6 IPv4 IPv6 * heterogeneous * (tunnel-like) + K IPv6 IPv6 IPv4 * heterogeneous * + L IPv6 IPv6 IPv6 homogeneous + + Type E is supported by the normal SOCKS mechanism. The types from F + to K are the main targets for the gateway mechanisms. They provide + heterogeneous communication topologies. Type L can be supported by + the natural extension of the SOCKS mechanism, because it is a + homogeneous communication. + + Type G and type J can provide interesting topology cases. They are + similar to the topologies that the tunneling techniques can provide. + Compared with the tunneling techniques, the SOCKS-based gateway is + advantageous, because it is composed of relays of real socket + connections. This mechanism does not have to suffer from the + following problems that are caused by tunneling techniques. + + * Fragmentation vulnerability + + The tunneling technique uses the packet encapsulation mechanism. In + the encapsulation mechanism, the packet length is changed because + of the additional header, and it may exceed the MTU of the network. + Thus, the tunneling technique is vulnerable in that the packet + might be fragmented. With the SOCKS-based gateway mechanism, there + is no fragmentation vulnerability because the packet size is + adjusted at the application layer. + + As an added advantage, well-authenticated connections are provided. + This is because the SOCKS mechanism is originally designed for + firewall systems, and it has various authentication methods. + + H. Kitamura et al. [Page 8] + + INTERNET-DRAFT A SOCKS-based IPv6/IPv4 Gateway July 1999 + + 5. Characteristics of the SOCKS-based gateway mechanism + + In this section, the characteristics of the SOCKS-based gateway + mechanism are summarized. + + 1. DNS modification is not necessary: + + It is not necessary to reserve global and wide address space for + address mapping. + + Also, address map servers are not necessary, because there is a + "DNS Name Resolving Delegation" mechanism. + + 2. Application independent: + + If the applications use socket APIs and DNS name resolving APIs, + the gateway mechanism is applied to them, since the mechanism is + realized by replacing these APIs that at the *Socks Lib*. + + As most communication programs use these APIs, there is no + application dependency. + + (Applications that exchange IP address information with peers are + exceptions) + + 3. OS and NIC types independent: + + Since the *Socks Lib* and the *Gateway* run at the application + layer, the SOCKS-base gateway mechanism runs on any platforms of + either UNIX or Windows OSs, and there is no dependency on the + types of physical NICs. + + 4. Only an easy socksification procedure is necessary: + + It is easy to install the *Socks Lib* (socksify) to the source + terminal, because the dynamic link library technique helps this + procedure. + + 5. IPv6 new features (e.g., IPSEC) can be utilized easily: + + Since connections are first terminated and then relayed at the + *Gateway*, it is easy to enable IPv6 new features on the IPv6 + side. + + With NAT-based translators, it is impossible to do the same thing. + + H. Kitamura et al. [Page 9] + + INTERNET-DRAFT A SOCKS-based IPv6/IPv4 Gateway July 1999 + + 6. Current existing client SOCKSv5 library can be used: + + In case of the IPv4 -> IPv6 relay, the current existing client + SOCKSv5 library that is designed for IPv4 -> IPv4 communication + can be used without modification. + + 7. Both TCP and UDP relays are possible: + + Since the SOCKS protocol supports both TCP and UDP relays, this + mechanism can also relay both TCP and UDP connections. + + 8. Both IPv4 -> IPv6 and IPv6 -> IPv4 relays are possible: + + This mechanism can realize not only the IPv4 -> IPv6 relay but + also the IPv6 -> IPv4 relay with the same method. + + 9. Multiple chained relays are possible: + + Since the mechanism has flexibility, all types of protocol + combinations of multiple chained relays are possible. + + 10. Can support exceptional applications that exchange IP address + information at the application level: + + It is easy for the SOCKS-based gateway mechanism to introduce + special management routines. If such protocols as ftp are known, + the SOCKS-based gateway mechanism can support them by introducing + special protocol translation routines. + + (Implementations of the SOCKS-based gateway mechanism have + supported the ftp protocol translation [see Appendix A]) + + 11. Easy load balancing: + + Since the *Gateway* is installed as a server, it is easy to + balance the load by supplying multiple servers. + + 6. Applicability statement + + The SOCKS-based gateway mechanism requests socksification of + applications (install *Socks Lib*) to realize heterogeneous + communications. Though the socksification is not difficult, it is one + of the constraints for users. + + The socksification mechanism provides the advantage that the SOCKS- + based gateway mechanism does not require modification of the DNS + system. Thus, there is a dilemma in that either socksification or DNS + modification is necessary. + + H. Kitamura et al. [Page 10] + + INTERNET-DRAFT A SOCKS-based IPv6/IPv4 Gateway July 1999 + + Other than the socksification, the SOCKS-based gateway mechanism has + the following three types of constraints. + + 1. Essential constraints: + + Constraints are caused by the address length difference between + IPv4 and IPv6. + + Functions that request an IP address as one of the return values + (e.g., getpeername() and getsockname() etc.) can not provide the + correct IP address as a return value. However, an appropriate + port value can be provided, because IPv4 and IPv6 use the same + size port space and necessary port information is transferred by + the SOCKS protocol. + + From a realistic viewpoint, this is a minor constraint, because + such functions are called in order to get port information (not IP + address information). + + 2. Limitation of the SOCKS mechanism: + + Since the current SOCKS system can not socksify all of the tricky + applications in which extraordinary means are used to create + connections, the SOCKS-based gateway mechanism can not be applied + to them. + + 3. Constraints to deal with the fake address: + + The fake address must be dealt with as a temporary value at the + application; it must not be recorded permanently as a bookmark, + etc. After the application is finished, the fake address + information must be released. Otherwise, problems will happen. + + From a realistic viewpoint, this is also a minor constraint, + because most applications record FQDN information instead of fake + addresses. + + It is theoretically possible for the SOCKS mechanism to support ICMP + relays, but the current SOCKS mechanism does not. So, the SOCKS-based + gateway mechanism does not support ICMP relays. + + However, the reference implementation of the current SOCKS mechanism + support typical ICMP applications (ping and traceroute) by using + different methods. So, the SOCKS-based gateway mechanism can support + ping and traceroute. + + (Implementations of the SOCKS-based gateway mechanism have supported + ping and traceroute [see Appendix A]) + + H. Kitamura et al. [Page 11] + + INTERNET-DRAFT A SOCKS-based IPv6/IPv4 Gateway July 1999 + + 7. Experiments + + We have been testing SOCKS64, one of the SOCKS-based gateway + implementations in many environments. Since July 1998, we have been + running the SOCKS64 server in between the 6bone and the internal + network of Fujitsu Ltd., Japan. Computers in Fujitsu's internal + network already have been "socksified", so users can connect to 6bone + hosts merely selecting our SOCKS64 server as their SOCKS gateway. + + For an interoperability test, we have been providing a SOCKS64 server + in the WIDE Project[WIDEV6WG] Camp, where about 200 Internet + researchers are participating in the camp. A temporary network called + "camp-net" is constructed at the camp for a variety of experiments + and provides services to the attendees. More than a hundred hosts are + connected to the camp-net. + + In these environments, we have tested many types of SOCKS5 clients, + including the SocksCap32[SOCKSCAP] on Windows and a variety of UNIX + based SOCKS libraries, and confirmed any clients successfully + connected to the IPv6 hosts using telnet, ftp, http, ssh. + + Also we have tested very complicated interconnection of IPv4 and + IPv6. At the WIDE camp held in September 1998, we constructed an + IPv4 over IPv6 tunnel using the SOCKS64 and the FAITH translator. In + this system, the SOCKS5 clients had no problems connecting to the + IPv4 hosts through the IPv6 networks. + + IPv4 host --SOCKS-- SOCKS64 --IPv6-- IPv6-IPv4 -- IPv4 host + /IPv4 server translator + + In conclusion, SOCKS64 provides an easy and sure way to let IPv4 + hosts connect to IPv6 hosts. + + H. Kitamura et al. [Page 12] + + INTERNET-DRAFT A SOCKS-based IPv6/IPv4 Gateway July 1999 + + 8. Conclusion + + As described above, the SOCKS-based IPv6/IPv4 gateway mechanism has + many advantages. From a realistic viewpoint, constraints are + negligible. + + Only two things are necessary to utilize this gateway mechanism. + + 1. Prepare an enhanced SOCKS sever on the dual stack node. + [see Appendix A. two implementations are available] + 2. Socksify applications when you execute them. + This is a very easy procedure. + + You don't have to modify the DNS system at all. + You don't have to reserve any addresses. + You don't have to prepare address mapping servers. etc. + + Since the mechanism is based on relaying two "terminated" + connections, most problems of the NAT-based translator mechanisms are + eliminated. + + Also, the "DNS name resolving delegation" mechanism works + effectively. It enables smooth heterogenous communications between + IPv6 and IPv4 nodes without modifying the DNS system. + + 9. Security Considerations + + Since the SOCKS-based IPv6/IPv4 gateway mechanism is based on SOCKSv5 + protocol, the security feature of the mechanism follows that of + SOCKSv5. It is described in the Security Considerations section of + the SOCKS Protocol Version 5 [SOCKSv5]. + + Appendix A. Implementations + + Currently, there are two independent implementations of the SOCKS- + based IPv6/IPv4 gateway mechanism. Both of them are open to the + public. + + One is Fujitsu Lab.'s implementation, which is called "SOCKS64." Its + source codes are available at the following URL. + ftp://ftp.kame.net/pub/kame/misc/socks64-... + + The other is NEC's implementation. Its source codes are available at + the following URL. + http://www.socks.nec.com/ + + H. Kitamura et al. [Page 13] + + INTERNET-DRAFT A SOCKS-based IPv6/IPv4 Gateway July 1999 + + References + + [SOCKSv5] Leech, M., Ganis, M., Lee, Y., Kuris, R. Koblas, D., & + Jones, L., "SOCKS Protocol V5," RFC1928, April 1996. + + [TRANSMECH] R. Gilligan and E. Nordmark, "Transition Mechanisms for + IPv6 Hosts and Routers", RFC 1933, April 1996. + + [IPv6] S. Deering, R. Hinden, "Internet Protocol, Version 6 + (IPv6) Specification," RFC2460, December 1998. + + [INET] H. Kitamura, "Entering the IPv6 communication world by + the SOCKS-based IPv6/IPv4 Translator," + in Proceedings of INET99, 1999. + + [NATPT] G. Tsirtsis and P. Srishuresh, "Network Address + Translation - Protocol Translation (NAT-PT)", + work in progress + + [CATTRANS] K. Yamamoto, M. Sumikawa, "Categorizing Translators + between IPv4 and IPv6," + work in progress + + [WIDEV6WG] WIDE Project IPv6 Working Group, "WIDE Project IPv6 + Working Group Home Page", http://www.v6.wide.ad.jp/. + + [SOCKSCAP] NEC, "SocksCap Home Page", + http://www.socks.nec.com/sockscap.html. + + Authors' Addresses: + + Hiroshi Kitamura + NEC Corporation + C&C Media Research Laboratories + 1-1, Miyazaki, 4-Chome, Miyamae-ku, + Kawasaki, Kanagawa, 216-8555, JAPAN + + Phone: +81 (44) 856-2123 + Fax: +81 (44) 856-2230 + Email: kitamura@ccm.cl.nec.co.jp + + Akira Jinzaki + Fujitsu Laboratories LTD. + 4-1-1 Kamikodanaka, Nakahara-ku, + Kawasaki, Kanagawa, 211-8588 Japan + + H. Kitamura et al. [Page 14] + + INTERNET-DRAFT A SOCKS-based IPv6/IPv4 Gateway July 1999 + + Phone: +81 (44) 777-1111 ex. 2-6331 + Fax: +81 (44) 754-2771 + Email: zinzin@flab.fujitsu.co.jp + + Shinji Kobayashi + Fujitsu Laboratories LTD. + 4-1-1 Kamikodanaka, Nakahara-ku, + Kawasaki, Kanagawa, 211-8588 Japan + + Phone: +81 (44) 754-2627 + Fax: +81 (44) 754-2771 + Email: koba@flab.fujitsu.co.jp + + H. Kitamura et al. [Page 15] Index: doc/draft-kitamura-socks-ipv6-01.txt diff -c /dev/null src/socks5/doc/draft-kitamura-socks-ipv6-01.txt:1.1.2.2 *** doc/draft-kitamura-socks-ipv6-01.txt Fri Aug 20 14:27:18 1999 --- doc/draft-kitamura-socks-ipv6-01.txt Mon Jan 25 14:33:52 1999 *************** *** 0 **** --- 1,506 ---- + + + + + + + INTERNET-DRAFT H. Kitamura + NEC Corporation + Expires in six months 26 January 1999 + + SOCKSv5 Protocol Extensions for IPv6/IPv4 Communication Environment + + + Status of this Memo + + This document is an Internet-Draft. Internet-Drafts are working + documents of the Internet Engineering Task Force (IETF), its areas, + and its working groups. Note that other groups may also distribute + working documents as Internet-Drafts. + + Internet-Drafts are draft documents valid for a maximum of six months + and may be updated, replaced, or obsoleted by other documents at any + time. It is inappropriate to use Internet- Drafts as reference + material or to cite them other than as "work in progress." + + To view the entire list of current Internet-Drafts, please check the + "1id-abstracts.txt" listing contained in the Internet-Drafts Shadow + Directories on ftp.is.co.za (Africa), ftp.nordu.net (Northern + Europe), ftp.nis.garr.it (Southern Europe), munnari.oz.au (Pacific + Rim), ftp.ietf.org (US East Coast), or ftp.isi.edu (US West Coast). + + Abstract + + This document describes three types of extensions of SOCKS Version 5 + protocol [RFC1928]. A new address type and a new command for Requests + and Replies are introduced. These extensions supplement the + insufficient generic functions of the SOCKSv5 protocol. + + These extensions enable a SOCKS server to be used as a translator for + IPv4 and IPv6 mixed heteregenous communications with ease. In + addition, they make each homogeneous IPv4 and IPv6 communication + efficient. + + + + + + + + + + + + + + + + H. Kitamura [Page 1] + + INTERNET-DRAFT SOCKSv5 Extensions for IPv6 Support January 1999 + + + Introduction + + The SOCKS Version 5 protocol [RFC1928] can deal with IPv6 address + type. Only with this specification, however, it is insufficient to + support IPv6 based efficient communication environment. Especially, + it is difficult to support IPv4 and IPv6 mixed heterogeneous + communication environment and to use a SOCKS server as a translator + for mixed heterogeneous communication environment. + + In this document, three types of extensions of SOCKSv5 protocol are + described. A new address type notion and a new command for Requests + and Replies are introduced as the extensions. + + These extensions enable a SOCKS server to be used as a translator for + IPv4 and IPv6 mixed heteregenous communications with ease. In + addition, they make each homogeneous IPv4 and IPv6 communication + efficient. Because they supplement the insufficient generic functions + of the SOCKSv5 protocol. + + Extension + + * Extension 1 (New address type notion) + + As a new address type (ATYP) notion, "ADDRESS ID" is introduced. + This extension is closely related with Extension 2 (New command), + which is described below. + + An ADDRESS ID is an identifier that represents an entry of the + address association mapping table between a SOCKS client and a SOCKS + server. Typically, the ADDRESS ID represents the servers' internal + address association table identifier. + + Internal ADDRESS ID Format + +-----+-----------+ + |CLASS|REALID(key)| + +-----+-----------+ + | 1 | 3 | + +-----+-----------+ + + An ADDRESS ID occupies 4 octets. Internally, the first octet is used + for a CLASS. The CLASS indicates categories and characteristics of + the ADDRESS ID. For the time being, it is reserved and filled with + zero. The rest octets are used for the real identifier (REALID) of + the ADDRESS ID. + + Since the ADDRESS ID dose not include explicit address information, + there are potential vulnerabilities. If some SOCKS clients use the + same ADDRESS ID that is already used, the SOCKS server may cause + + + + H. Kitamura [Page 2] + + INTERNET-DRAFT SOCKSv5 Extensions for IPv6 Support January 1999 + + + confusion. (It depends on implementation methods of the SOCKS.) Most + of the vulnerabilities can be avoided by the difference of the SOCKS + clients' IP addresses, but they still exist for the processes at the + same host. + + In order to avoid such potential problems and to enhance the + security of the system, a simple key exchange mechanism is + introduced. The SOCKS server provides a REALID as a key to the SOCKS + client. It means that the REALID works as both a identifier and a + key. A series of the provided REALIDs by the SOCKS server are not + simple sequential numbers. The randomness of the REALIDs avoids the + vulnerabilities. 3 octets are long enough to realize this mechanism, + and long enough to support the number of the addresses to be dealt + between the client and the server. + + The length of the ADDRESS ID is fixed and shorter than other address + types that are specified in the current SOCKSv5 protocol, and the + ADDRESS ID shows essential information between the client and the + server. So, the introduction of the ADDRESS ID address type makes + efficient communications via the SOCKS server. Especially, in case of + UDP communications via the SOCKS server, the utilization of the + ADDRESS ID address type contributes to shorten the length of the UDP + Packet Structure header and to make the filtering procedure + efficient. + + Since the introduction of the ADDRESS ID conceals the address family + types, it becomes easy to enable to relay different address based + connections (e.g., between IPv4 and IPv6) at the SOCKS server. + + * Extension 2 (New command for Requests and Replies) + + As a new command (CMD), "ADDRESS ASSOCIATE" is introduced. This + extension is closely related with Extension 1 (New address type + notion). + + This command is prepared for a SOCKS client to get a ADDRESS ID from + a SOCKS server. Followings are the procedure to get the ADDRESS ID. + 1. A SOCKS client sends a Request filled with the ADDRESS ASSOCIATE + command to a SOCKS server. + 2. The server sends a Reply filled with the ADDRESS ID information + to the BND.ADDR field. + + After the procedure is finished successfully, the client can use the + received ADDRESS ID to any ADDR fields instead of other address types + (IP V4 address, DOMAINNAME, or IP V6 address) for the Requests and + the UDP Packet Structure header. + + With this extension, the client's DNS query delegation to the server + + + + H. Kitamura [Page 3] + + INTERNET-DRAFT SOCKSv5 Extensions for IPv6 Support January 1999 + + + can be accomplished explicitly in the SOCKS protocol. + + An ADDRESS ASSOCIATE command has different characteristics from + other commands. It can be executed as a dedicated command, but also, + it is possible to execute the ADDRESS ASSOCIATE command with other + commands (CONNECT, BIND, or UDP ASSOCIATE) simultaneously under the + special conditions that the client does not require explicit BND.ADDR + information from the Replies. With the simultaneous commands + execution can reduce the handshake times between the SOCKS client and + the server. In order to realize this function, the ADDRESS ASSOCIATE + command needs to be assigned to an appropriate bit of the CMD field + of the Requests. + + In case an ADDRESS ASSOCIATE command is executed with other command + simultaneously, the meanings of the REP field of the Replies may + become unclear, and the client can not get explicit BND.ADDR + information from the Replies, because BND.ADDR field is filled with + ADDRESS ID information. (BND.PORT field is filled with normal + information.) In case confusion may happen, an orthodox method that + the each command is executed as one dedicated function must be taken. + Only when the client does not need BND.ADDR information and the + meanings of the REP field is clear, this simultaneous commands + execution can be taken. + + In case of the dedicated ADDRESS ASSOCIATE command Requests, + DST.PORT field does not make sense. The meanings of this field is + changed and reused. The name of it is changed to ADR.PREF. It shows + the preference of the reply address type of the client. In the + Extension 3 (Show the preference of the reply address type), the + details of this specification are described. + + * Extension 3 (Show the preference of the reply address type) + + In case the SOCKS server relays different address based connections + (e.g., between IPv4 and IPv6), the address type (ATYP) and the bound + address (BND.ADDR) of the Replies are important. If the client can + not deal with the replied address type, it causes confusion in the + client. + + In order to avoid this confusion, the client needs to show the + preference of the reply address type to the server. There are three + methods to realize this feature. + + 1. Do nothing special + + The client shows nothing special to the server and expects a + default reply address type that can be associated naturally. It + means to expect the same address (family) type that is used for + + + + H. Kitamura [Page 4] + + INTERNET-DRAFT SOCKSv5 Extensions for IPv6 Support January 1999 + + + the connection between the client and the server. In this + method, the client dose not care which address family type is + used in the connection between the server and the desired + destination. + + 2. Use FLAG field of the Requests + + The client shows the reply address type preference by setting + the flag field FLAG of the Requests. An appropriate bit of the + FLAG field shows off or on of the preference of the client. + If the appropriate bit is off (0), it is the same case of the + "Do nothing special." Default address type is replied. + If the appropriate bit is on (1), the client asks the server to + reply the address as the same address (family) type that is used + in the connection between the server and the desired + destination. In this case, the client must deal with all of the + expected address family types. + + 3. Use DST.PORT field of the dedicated ADDRESS ASSOCIATE Requests + + In case of the dedicated ADDRESS ASSOCIATE Requests, the name + of the DST.PORT field is changed to ADR.PREF, and it shows the + preference of the reply address type. + Since the ADR.PREF has 2 octets, it has a possibility to show + complex preference. For the time being, the upper octet of the + ADR.PREF is reserved. The lower octet is used to show the show + the preference. The format is the same to the ATYP field. + (As an additional function, this mechanism enables the client + to realize the deligation of the reverse DNS query, also.) + The appropriate bit of the FLAG has a high priority and can + overwrite the preference that is shown by the ADR.PREF field. + + Formats + + In the following sections, the formats that include the described + extensions are shown. Most parts are quoted from the [RFC1928] and + the current SOCKS version 5 specification [SOCKSv5]. Since [RFC1928] + and [SOCKSv5] explain the meanings of the fields except extensions + that are described in this document, they are omitted here. + + x marks (instead of o marks) indicate extensions. + + Note: + + Unless otherwise noted, the decimal numbers appearing in packet- + format diagrams represent the length of the corresponding field, in + octets. Where a given octet must take on a specific value, the + syntax X'hh' is used to denote the value of the single octet in that + + + + H. Kitamura [Page 5] + + INTERNET-DRAFT SOCKSv5 Extensions for IPv6 Support January 1999 + + + field. When the word 'Variable' is used, it indicates that the + corresponding field has a variable length defined either by an + associated (one or two octet) length field, or by a data type field. + + Requests Format + + +----+-----+------+------+----------+----------+ + |VER | CMD | FLAG | ATYP | DST.ADDR | DST.PORT | + +----+-----+------+------+----------+----------+ + | 1 | 1 | 1 | 1 | Variable | 2 | + +----+-----+------+------+----------+----------+ + + o VER protocol version: X'05' + o CMD + o CONNECT X'01' + o BIND X'02' + o UDP ASSOCIATE X'03' + x ADDRESS ASSOCIATE X'08' (bit set) + x CONNECT + +ADDRESS ASSOCIATE X'09' + x BIND + +ADDRESS ASSOCIATE X'0A' + x UDP ASSOCIATE + +ADDRESS ASSOCIATE X'0B' + o X'10' to X'7F' IANA ASSIGNED + o X'80' to X'FF' RESERVED FOR PRIVATE METHODS + o FLAG command dependent flag (defaults to X'00') + x Prefer Default address family type + X'00' (off) + x Prefer address family type of the Destination + X'10' (on) + o ATYP address type of following address + o IP V4 address: X'01' + o DOMAINNAME: X'03' + o IP V6 address: X'04' + x ADDRESS ID: X'08' + o DST.ADDR desired destination address + o DST.PORT desired destination port in network octet + order + + In case of the dedicated ADDRESS ASSOCIATE Requests: + x DST.PORT => ADR.PREF + show the preference of the reply address type. + X'00'(reserved)+ ATYP + x IP V4 address: X'01' + x DOMAINNAME: X'03' + x IP V6 address: X'04' + + + + + H. Kitamura [Page 6] + + INTERNET-DRAFT SOCKSv5 Extensions for IPv6 Support January 1999 + + + Addressing Format + + In an address field (DST.ADDR, BND.ADDR), the ATYP field specifies + the type of address contained within the field: + + o X'01' + + the address is a version-4 IP address, with a length of 4 octets + + o X'03' + + the address field contains a fully-qualified domain name. The first + octet of the address field contains the number of octets of name that + follow, there is no terminating NUL octet. + + o X'04' + + the address is a version-6 IP address, with a length of 16 octets. + + x X'08' + + the address is a identifier of the servers' internal address + association table, with a length of 1 octet. + + Replies Format + + +----+-----+------+------+----------+----------+ + |VER | REP | FLAG | ATYP | BND.ADDR | BND.PORT | + +----+-----+------+------+----------+----------+ + | 1 | 1 | 1 | 1 | Variable | 2 | + +----+-----+------+------+----------+----------+ + + o VER protocol version: X'05' + o REP Reply field: + o X'00' succeeded + o X'01' general SOCKS server failure + o X'02' connection not allowed by ruleset + o X'03' Network unreachable + o X'04' Host unreachable + o X'05' Connection refused + o X'06' TTL expired + o X'07' Command not supported + o X'08' Address type not supported + o X'09' Invalid address + o X'0A' to X'FF' unassigned + o FLAG command dependent flag + o ATYP address type of following address + o IP V4 address: X'01' + + + + H. Kitamura [Page 7] + + INTERNET-DRAFT SOCKSv5 Extensions for IPv6 Support January 1999 + + + o DOMAINNAME: X'03' + o IP V6 address: X'04' + x ADDRESS ID: X'08' + o BND.ADDR server bound address + o BND.PORT server bound port in network octet order + + UDP Control Channel Requests Format + + +----+-----+------+------+----------+------+ + |RSV | SUB | FLAG | ATYP | ADDR | PORT | + +----+-----+------+------+----------+------+ + | 1 | 1 | 1 | 1 | Variable | 2 | + +----+-----+------+------+----------+------+ + + o RSV Reserved X'00' + o SUB Subcommand + o INTERFACE DATA: X'01' + o FLAG A subcommand dependent flag (normally X'00') + o ATYP address type of following address + o IP V4 address: X'01' + o DOMAINNAME: X'03' + o IP V6 address: X'04' + x ADDRESS ID: X'08' + o ADDR destination address information + o PORT destination port information + + UDP Packet Structure Format + + +------+------+------+----------+----------+----------+ + | FLAG | FRAG | ATYP | DST.ADDR | DST.PORT | DATA | + +------+------+------+----------+----------+----------+ + | 2 | 1 | 1 | Variable | 2 | Variable | + +------+------+------+----------+----------+----------+ + + The fields in the UDP request header are: + + o FLAG Reserved X'0000' + o FRAG Current fragment number + o ATYP address type of following address + o IP V4 address: X'01' + o DOMAINNAME: X'03' + o IP V6 address: X'04' + x ADDRESS ID: X'08' + o DST.ADDR desired destination address + o DST.PORT desired destination port + o DATA user data + + + + + + H. Kitamura [Page 8] + + INTERNET-DRAFT SOCKSv5 Extensions for IPv6 Support January 1999 + + + Security Considerations + + This document describes a protocol for the application-layer + traversal of IP network firewalls. The security of such traversal is + highly dependent on the particular authentication and encapsulation + methods provided in a particular implementation, and selected during + negotiation between SOCKS client and SOCKS server. + + Careful consideration should be given by the administrator to the + selection of authentication methods. + + + References + + [RFC1928] Leech, M., Ganis, M., Lee, Y., Kuris, R. Koblas, D., & + Jones, L., "SOCKS Protocol V5," RFC1928, April 1996. + + [SOCKSv5] VanHeyningen, M, "SOCKS Protocol Version 5," June 1998 + currently draft-ietf-aft-socks-pro-v5-03.txt + + [IPv6] S. Deering, R. Hinden, "Internet Protocol, Version 6 + (IPv6) Specification", RFC2460, December 1998. + + Author's Address + + Hiroshi Kitamura + NEC Corporation + C&C Media Research Laboratories + 1-1, Miyazaki, 4-Chome, Miyamae-ku, + Kawasaki, Kanagawa, 216-8555, JAPAN + + Phone: +81 (44) 856-2123 + Fax: +81 (44) 856-2230 + EMail: kitamura@ccm.cl.nec.co.jp + + + + + + + + + + + + + + + + + + H. Kitamura [Page 9] Index: examples/libsocks5.conf.translator diff -c /dev/null src/socks5/examples/libsocks5.conf.translator:1.2 *** examples/libsocks5.conf.translator Fri Aug 20 14:27:18 1999 --- examples/libsocks5.conf.translator Tue Oct 27 11:23:51 1998 *************** *** 0 **** --- 1,8 ---- + # A Socks5 Library Config file + #noproxy - 10. - + #noproxy - fe80::/16 - + # To specify IPv6 address for a server, enclose it with '[' and ']' + # to avoid ambiguity on ':', as in: + # socks5 - - - - [5ffe:272::ff]:1080 + socks5 - - - - 127.0.0.1:1080,[::1]:1080 + #socks5 - - - - socks5-ipv4-server:port,socks5-ipv6-server:port Index: examples/socks5.conf.translator diff -c /dev/null src/socks5/examples/socks5.conf.translator:1.1 *** examples/socks5.conf.translator Fri Aug 20 14:27:18 1999 --- examples/socks5.conf.translator Thu Oct 22 16:40:55 1998 *************** *** 0 **** --- 1,4 ---- + # A Socks5 Config file for IPv4-IPv6 translator + permit - - - - - - + # Following line enables FTP protocol translation between IPv4 and IPv6 hosts. + filter ftpv6 - c - - - ftp Index: include/config.h.in diff -c src/socks5/include/config.h.in:1.1.1.6 src/socks5/include/config.h.in:1.5.2.3 *** include/config.h.in Thu Aug 5 13:21:03 1999 --- include/config.h.in Thu Aug 5 17:50:45 1999 *************** *** 18,23 **** --- 18,26 ---- /* Define as the return type of signal handlers (int or void). */ #undef RETSIGTYPE + /* Define if the `setpgrp' function takes no argument. */ + #undef SETPGRP_VOID + /* Define to `unsigned' if doesn't define. */ #undef size_t *************** *** 69,74 **** --- 72,83 ---- /* define this to whatever is you can set within a signal handler. */ #undef sig_atomic_t + /* define this if you have libident library. */ + #undef HAVE_LIBIDENT + + /* define this if you use shadow passwd file. */ + #undef USE_SHADOW_PASSWD + /* define this to your libc, if it has a version number (/lib/libc.so.1.9) */ #undef LIBC_NAME #undef LIBDGC_NAME *************** *** 85,99 **** /* define if you want to use /etc/passwd for user/pass authentication */ #undef USE_PASSWD - /* define if you want to use /etc/shadow for user/pass authentication */ - #undef USE_SHADOW_PASSWD - /* Define if struct sockaddr_un contains sun_len. */ #undef HAVE_SOCKADDR_SUN_LEN /* Define if the compiler can handle function prototyping */ #undef HAVE_FUNC_PROTOTYPE /* Define if you have the bcmp function. */ #undef HAVE_BCMP --- 94,126 ---- /* define if you want to use /etc/passwd for user/pass authentication */ #undef USE_PASSWD /* Define if struct sockaddr_un contains sun_len. */ #undef HAVE_SOCKADDR_SUN_LEN /* Define if the compiler can handle function prototyping */ #undef HAVE_FUNC_PROTOTYPE + /* define if your system supports IPv6 */ + #undef SUPPORT_IPV6 + + /* define if your system uses KAME IPv6 implementation */ + #undef KAME + + /* define if your system uses PTCPIP (NEC's proprietary implementation of TCP/IP) */ + #undef PTCPIP + + /* define if your system supports IPv4-mapped IPv6 addresses */ + #undef SUPPORT_MAPPED_ADDRESS + + /* define this to the path of your traceroute for IPv6 */ + #undef TROUTE6PROG + + /* define this to the path of your ping for IPv6 */ + #undef PING6PROG + + /* define this according to your libinet6, if any. */ + #undef LIBINET6_NAME + /* Define if you have the bcmp function. */ #undef HAVE_BCMP *************** *** 112,120 **** --- 139,156 ---- /* Define if you have the flock function. */ #undef HAVE_FLOCK + /* Define if you have the freeaddrinfo function. */ + #undef HAVE_FREEADDRINFO + + /* Define if you have the freehostent function. */ + #undef HAVE_FREEHOSTENT + /* Define if you have the genget function. */ #undef HAVE_GENGET + /* Define if you have the getaddrinfo function. */ + #undef HAVE_GETADDRINFO + /* Define if you have the getcwd function. */ #undef HAVE_GETCWD *************** *** 136,141 **** --- 172,183 ---- /* Define if you have the getifaddrs function. */ #undef HAVE_GETIFADDRS + /* Define if you have the getipnodebyname function. */ + #undef HAVE_GETIPNODEBYNAME + + /* Define if you have the getnodebyname function. */ + #undef HAVE_GETNODEBYNAME + /* Define if you have the getopt function. */ #undef HAVE_GETOPT *************** *** 208,221 **** /* Define if you have the setpgid function. */ #undef HAVE_SETPGID - /* Define if you have the setsid function. */ - #undef HAVE_SETSID - /* Define if you have the setpgrp function. */ #undef HAVE_SETPGRP ! /* Define if you have the setpgrp(), not setpgrp(x,y) */ ! #undef SETPGRP_VOID /* Define if you have the setupterm function. */ #undef HAVE_SETUPTERM --- 250,260 ---- /* Define if you have the setpgid function. */ #undef HAVE_SETPGID /* Define if you have the setpgrp function. */ #undef HAVE_SETPGRP ! /* Define if you have the setsid function. */ ! #undef HAVE_SETSID /* Define if you have the setupterm function. */ #undef HAVE_SETUPTERM *************** *** 256,261 **** --- 295,303 ---- /* Define if you have the waitpid function. */ #undef HAVE_WAITPID + /* Define if you have the header file. */ + #undef HAVE_ARPA_NAMESER_H + /* Define if you have the header file. */ #undef HAVE_BSTRING_H *************** *** 268,273 **** --- 310,318 ---- /* Define if you have the header file. */ #undef HAVE_FCNTL_H + /* Define if you have the header file. */ + #undef HAVE_IDENT_H + /* Define if you have the header file. */ #undef HAVE_IFADDRS_H *************** *** 295,300 **** --- 340,348 ---- /* Define if you have the header file. */ #undef HAVE_PTHREAD_H + /* Define if you have the header file. */ + #undef HAVE_RESOLV_H + /* Define if you have the header file. */ #undef HAVE_STDARG_H *************** *** 397,411 **** /* Define if you have the header file. */ #undef HAVE_VARARGS_H - /* Define if you have the bsd library (-lbsd). */ - #undef HAVE_LIBBSD - /* Define if you have the com_err library (-lcom_err). */ #undef HAVE_LIBCOM_ERR - /* Define if you have the compat library (-lcompat). */ - #undef HAVE_LIBCOMPAT - /* Define if you have the crypto library (-lcrypto). */ #undef HAVE_LIBCRYPTO --- 445,453 ---- *************** *** 420,431 **** /* Define if you have the gssapi_krb5 library (-lgssapi_krb5). */ #undef HAVE_LIBGSSAPI_KRB5 - - /* Define if you have the ident library (-lident). */ - #undef HAVE_LIBIDENT ! /* Define if you have the ipc library (-lipc). */ ! #undef HAVE_LIBIPC /* Define if you have the isode library (-lisode). */ #undef HAVE_LIBISODE --- 462,470 ---- /* Define if you have the gssapi_krb5 library (-lgssapi_krb5). */ #undef HAVE_LIBGSSAPI_KRB5 ! /* Define if you have the inet6 library (-linet6). */ ! #undef HAVE_LIBINET6 /* Define if you have the isode library (-lisode). */ #undef HAVE_LIBISODE *************** *** 435,443 **** /* Define if you have the ndbm library (-lndbm). */ #undef HAVE_LIBNDBM - - /* Define if you have the otp library (-lotp). */ - #undef HAVE_LIBOTP /* Define if you have the socket library (-lsocket). */ #undef HAVE_LIBSOCKET --- 474,479 ---- Index: include/defs.h diff -c src/socks5/include/defs.h:1.1.1.6 src/socks5/include/defs.h:1.11.2.5 *** include/defs.h Thu Aug 5 13:21:04 1999 --- include/defs.h Mon Aug 16 09:54:23 1999 *************** *** 11,17 **** --- 11,21 ---- #ifndef DEFS_H #define DEFS_H + #ifdef SUPPORT_IPV6 + #define SOCKS5_VERSION_NAME "Socks5 v1.0r10 + Trans 1.3 " + #else #define SOCKS5_VERSION_NAME "Socks5 v1.0r10 " + #endif #ifndef P #if defined(__STDC__) || defined(HAVE_FUNC_PROTOTYPE) *************** *** 184,189 **** --- 188,202 ---- #define SOCKS5_IPV4ADDR 0x01 #define SOCKS5_HOSTNAME 0x03 #define SOCKS5_IPV6ADDR 0x04 + #ifdef ID_KITAMURA_SOCKS_IPV6 + #define SOCKS5_ADDRESSID 0x08 + #endif + #ifdef SUPPORT_IPV6 + /* defines the following flag to be 8, */ + /* but NEC's commercial version of SOCKS seems to use the value for a private*/ + /* purpose. So use 0x10 instead. */ + #define SOCKS5_FLAG_IPV4V6 0x10 + #endif /* socks5 offsets */ #define RP_VERSION 0 *************** *** 204,217 **** #define MINHDRSIZE 10 #define IPV4HDRSIZE 10 #define IPV6HDRSIZE 22 #define MAXHDRSIZE 262 #define NAMEHDRSIZE(x) (7 + strlen((x))) #define UDP_MAX_PAYLOAD ((2<<16) - 18 - 8) /* 8 = sizeof(struct udp), 18 = sizeof(struct ip) */ ! #ifdef HAVE_NETINET6_IN6_H #define HOSTLEN(x) (((x)[RP_FLAGS] == SOCKS5_HOSTNAME)?((x)[RP_HOSTOFF]+1): \ ! (((x)[RP_FLAGS] == SOCKS5_IPV4ADDR)?sizeof(struct in_addr):sizeof(struct in_addr6))) #else #define HOSTLEN(x) (((x)[RP_FLAGS] == SOCKS5_HOSTNAME)?((x)[RP_HOSTOFF]+1):sizeof(struct in_addr)) #endif --- 217,241 ---- #define MINHDRSIZE 10 #define IPV4HDRSIZE 10 #define IPV6HDRSIZE 22 + #ifdef ID_KITAMURA_SOCKS_IPV6 + #define IDHDRSIZE 10 + #endif #define MAXHDRSIZE 262 #define NAMEHDRSIZE(x) (7 + strlen((x))) #define UDP_MAX_PAYLOAD ((2<<16) - 18 - 8) /* 8 = sizeof(struct udp), 18 = sizeof(struct ip) */ ! #ifdef SUPPORT_IPV6 ! #ifdef ID_KITAMURA_SOCKS_IPV6 ! #define HOSTLEN(x) (((x)[RP_FLAGS] == SOCKS5_HOSTNAME)?((x)[RP_HOSTOFF]+1): \ ! (((x)[RP_FLAGS] == SOCKS5_IPV4ADDR)?sizeof(struct in_addr):\ ! (((x)[RP_FLAGS] == SOCKS5_ADDRESSID)?4: \ ! sizeof(struct in6_addr)))) ! #else #define HOSTLEN(x) (((x)[RP_FLAGS] == SOCKS5_HOSTNAME)?((x)[RP_HOSTOFF]+1): \ ! (((x)[RP_FLAGS] == SOCKS5_IPV4ADDR)?sizeof(struct in_addr):\ ! sizeof(struct in6_addr))) ! #endif #else #define HOSTLEN(x) (((x)[RP_FLAGS] == SOCKS5_HOSTNAME)?((x)[RP_HOSTOFF]+1):sizeof(struct in_addr)) #endif Index: include/socks.h diff -c src/socks5/include/socks.h:1.1.1.5 src/socks5/include/socks.h:1.7.2.3 *** include/socks.h Thu Aug 5 13:21:03 1999 --- include/socks.h Thu Aug 5 17:50:45 1999 *************** *** 49,57 **** --- 49,73 ---- extern int LIBPREFIX(select) P((int, fd_set *, fd_set *, fd_set *, struct timeval *)); extern struct hostent *LIBPREFIX(gethostbyname) P((char *)); + #ifdef HAVE_GETHOSTBYNAME2 extern struct hostent *LIBPREFIX(gethostbyname2) P((char *, int)); #endif + #ifdef HAVE_GETNODEBYNAME + extern struct hostent *LIBPREFIX(getnodebyname) P((const char *, int, int)); + #endif + #ifdef HAVE_GETIPNODEBYNAME + extern struct hostent *LIBPREFIX(getipnodebyname) P((const char *, int, int, int *)); + #endif + #ifdef HAVE_FREEHOSTENT + extern void LIBPREFIX(freehostent) P((struct hostent *)); + #endif + #ifdef HAVE_GETADDRINFO + extern int LIBPREFIX(getaddrinfo) P((const char *, const char *, const struct addrinfo *, struct addrinfo **)); + #endif + #ifdef HAVE_FREEADDRINFO + extern void LIBPREFIX(freeaddrinfo) P((struct addrinfo *)); + #endif #endif /* include prototypes */ #ifndef LIBPREFIX *************** *** 90,99 **** #define recvfrom LIBPREFIX(recvfrom) #endif - #ifdef HAVE_GETHOSTBYNAME2 - #define gethostbyname2 LIBPREFIX(gethostbyname2) - #endif #define gethostbyname LIBPREFIX(gethostbyname) #define rresvport LIBPREFIX(rresvport) #define connect LIBPREFIX(connect) #define listen LIBPREFIX(listen) --- 106,118 ---- #define recvfrom LIBPREFIX(recvfrom) #endif #define gethostbyname LIBPREFIX(gethostbyname) + #define gethostbyname2 LIBPREFIX(gethostbyname2) + #define getnodebyname LIBPREFIX(getnodebyname) + #define getipnodebyname LIBPREFIX(getipnodebyname) + #define freehostent LIBPREFIX(freehostent) + #define getaddrinfo LIBPREFIX(getaddrinfo) + #define freeaddrinfo LIBPREFIX(freeaddrinfo) #define rresvport LIBPREFIX(rresvport) #define connect LIBPREFIX(connect) #define listen LIBPREFIX(listen) *************** *** 135,140 **** --- 154,168 ---- #define Rgetpeername LIBPREFIX(getpeername) #endif + + /* IPv6: new API for applications to tell SOCKS library that they will */ + /* IPv6: accept both IPv4 address and IPv6 address. */ + #ifdef __STDC__ + extern int LIBPREFIX(accept_both_af)(int); + #else + extern int LIBPREFIX(accept_both_af)(); + #endif + #endif /* SOCKS */ #endif /* included socks.h */ Index: include/socks5api.h diff -c src/socks5/include/socks5api.h:1.1.1.3 src/socks5/include/socks5api.h:1.3.4.2 *** include/socks5api.h Thu Apr 1 11:04:37 1999 --- include/socks5api.h Wed Apr 7 14:35:43 1999 *************** *** 48,59 **** #define AF_S5NAME 0xff union tagS5NetAddr { struct sockaddr sa; struct sockaddr_in sin; struct sockaddr_name sn; ! #ifdef HAVE_NETINET6_IN6_H struct sockaddr_in6 sin6; #endif }; --- 48,72 ---- #define AF_S5NAME 0xff + #ifdef ID_KITAMURA_SOCKS_IPV6 + struct sockaddr_id { + unsigned short sid_family; + unsigned short sid_port; + char sid_id[4]; + }; + + #define AF_S5ID 0xfe + #endif + union tagS5NetAddr { struct sockaddr sa; struct sockaddr_in sin; struct sockaddr_name sn; ! #ifdef SUPPORT_IPV6 struct sockaddr_in6 sin6; + #endif + #ifdef ID_KITAMURA_SOCKS_IPV6 + struct sockaddr_id sid; #endif }; Index: include/system.h diff -c src/socks5/include/system.h:1.1.1.5 src/socks5/include/system.h:1.2.2.3 *** include/system.h Thu Aug 5 13:21:04 1999 --- include/system.h Thu Aug 5 17:50:46 1999 *************** *** 59,64 **** --- 59,83 ---- int REAL(close) P((S5IOHandle)); int REAL(shutdown) P((S5IOHandle, int)); + #ifdef HAVE_GETHOSTBYNAME2 + struct hostent *REAL(gethostbyname2) P((const char *, int)); + #endif + #ifdef HAVE_GETNODEBYNAME + struct hostent *REAL(getnodebyname) P((const char *, int, int)); + #endif + #ifdef HAVE_GETIPNODEBYNAME + struct hostent *REAL(getipnodebyname) P((const char *, int, int, int *)); + #endif + #ifdef HAVE_FREEHOSTENT + void REAL(freehostent) P((struct hostent *)); + #endif + #ifdef HAVE_GETADDRINFO + int REAL(getaddrinfo) P((const char *, const char *, const struct addrinfo *, struct addrinfo **)); + #endif + #ifdef HAVE_FREEADDRINFO + void REAL(freeaddrinfo) P((struct addrinfo *)); + #endif + #endif /* FOR_SHARED_LIBRARY */ #endif /* HAVE_DLOPEN */ #endif /* IN_LIBRARY */ Index: lib/addr.c diff -c src/socks5/lib/addr.c:1.1.1.3 src/socks5/lib/addr.c:1.15.2.2 *** lib/addr.c Thu Aug 5 13:20:57 1999 --- lib/addr.c Thu Aug 5 17:50:47 1999 *************** *** 12,30 **** --- 12,274 ---- #include "threads.h" #include "addr.h" #include "log.h" + #ifdef HAVE_ARPA_NAMESER_H + /* some version of resolv.h requires arpa/nameser.h. */ + #include + #endif + #ifdef HAVE_RESOLV_H + #include + #endif + + #define ID_MASINTER_URL_IPV6 IFTHREADED(extern MUTEX_T gh_mutex;) IFTHREADED(extern MUTEX_T gs_mutex;) + #ifdef SUPPORT_IPV6 + #if !defined(HAVE_GETNODEBYNAME) && !defined(HAVE_GETIPNODEBYNAME) + static struct hostent *CopyHostent(const struct hostent *hp) { + struct hostent *copy; + int sz; + char **aliases; + int naliases = 0; + char **addrs; + int naddrs = 0; + char *ap, *cp; + int hlen = hp->h_length; + int i; + + sz = sizeof(struct hostent); + + sz += strlen(hp->h_name) + 1; /* one for NUL character */ + + if (hp->h_aliases != NULL) { + for (i = 0; hp->h_aliases[i] != NULL; i++) { + sz += strlen(hp->h_aliases[i]) + 1; /* one for NUL character */ + } + naliases = i; + sz += sizeof(char *) * (naliases + 1); /* one for NULL terminator */ + } + + if (hp->h_addr_list != NULL) { + for (i = 0; hp->h_addr_list[i] != NULL; i++) + ; + naddrs = i; + sz += hlen * i; + sz += sizeof(char *) * (naddrs + 1); /* one for NULL terminator */ + } + + if ((copy = (struct hostent *)malloc(sz)) == NULL) return NULL; + + aliases = (char **)(copy + 1); + addrs = aliases + naliases + (hp->h_aliases != NULL); + ap = (char *)(addrs + naddrs + (hp->h_addr_list != NULL)); + cp = ap + naddrs * hlen; + + /* copy hp->h_name */ + copy->h_name = cp; + strcpy(cp, hp->h_name); + cp += strlen(hp->h_name) + 1; + + /* copy hp->h_aliases */ + if (hp->h_aliases) { + copy->h_aliases = aliases; + for (i = 0; i < naliases; i++) { + aliases[i] = cp; + strcpy(cp, hp->h_aliases[i]); + cp += strlen(hp->h_aliases[i]) + 1; + } + aliases[naliases] = NULL; + } else { + copy->h_aliases = NULL; + } + + /* copy hp->h_addrtype */ + copy->h_addrtype = hp->h_addrtype; + + /* copy hp->h_length */ + copy->h_length = hlen; + + /* copy hp->h_addr_list */ + if (hp->h_addr_list) { + copy->h_addr_list = addrs; + for (i = 0; i < naddrs; i++) { + addrs[i] = ap; + memcpy(addrs[i], hp->h_addr_list[i], hlen); + ap += hlen; + } + addrs[naddrs] = NULL; + } else { + copy->h_addr_list = NULL; /* unlikely */ + } + + return copy; + } + #endif + + struct hostent *lsGetHostByName(const char *name, int af) { + #ifdef HAVE_GETIPNODEBYNAME + int dummy; + return REAL(getipnodebyname)(name, af, 0, &dummy); + #else + #ifdef HAVE_GETNODEBYNAME + /* IPv6: We prefer getnodebyname, which is thread-safe and its behavior */ + /* IPv6: is not affected by _res.options. */ + return REAL(getnodebyname)(name, af, 0); + #else + #ifdef HAVE_GETHOSTBYNAME2 + struct hostent *hp; + #ifdef RES_USE_INET6 + u_long resopt; + #endif + + MUTEX_LOCK(gh_mutex); + #ifdef RES_USE_INET6 + /* IPv6: There seems to be some implementations of gethostbyname2 */ + /* IPv6: that don't conform RFC2133, where gethostbyname2("localhost", */ + /* IPv6: AF_INET) failes when RES_USE_INET6 bit is set (it should */ + /* IPv6: succeed and return :FFFF:127.0.0.1). So turn off temporarily */ + /* IPv6: and restore later. If RES_USE_INET6 isn't available, we assume */ /* IPv6: gethostbyname2 does the right thing. */ + if (!(_res.options & RES_INIT)) res_init(); + resopt = _res.options; + _res.options &= ~RES_USE_INET6; + #endif + if ((hp = REAL(gethostbyname2)(name, af)) != NULL) { + hp = CopyHostent(hp); + if (af == AF_INET && hp->h_length == 16) { + /* Addresses are represented as IPv4-mapped IPv6 addresses due */ + /* to RES_USE_INET6 bit. Convert them back to IPv4 addresses. */ + int i; + + hp->h_length = 4; + for (i = 0; hp->h_addr_list[i] != NULL; i++) { + memmove(hp->h_addr_list[i], hp->h_addr_list[i] + 12, 4); + } + } + } + #ifdef RES_USE_INET6 + _res.options = resopt; + #endif + MUTEX_UNLOCK(gh_mutex); + + return hp; + #else + /* IPv6: We have neither getnodebyname nor gethostbyname2. So we must */ + /* IPv6: rely on the good old gethostbyname using _res.options. Note */ + /* IPv6: that _res code is not surrounded by "#ifdef RES_USE_INET6" as */ + /* IPv6: in the gethostbyname2 code above, because it's mandatory. */ + struct hostent *hp; + u_long resopt; + + MUTEX_LOCK(gh_mutex); + if (!(_res.options & RES_INIT)) res_init(); + resopt = _res.options; + + if (af == AF_INET) { + _res.options &= ~RES_USE_INET6; + } else { + _res.options |= RES_USE_INET6; + } + + if ((hp = REAL(gethostbyname)(name)) != NULL) { + if (af == AF_INET6 && hp->h_length == 16 && + IN6_IS_ADDR_V4COMPAT((struct in6_addr *)&(hp->h_addr_list[0]))) { + hp = NULL; + } else { + hp = CopyHostent(hp); + } + } + _res.options = resopt; + MUTEX_UNLOCK(gh_mutex); + + return hp; + #endif /* HAVE_GETHOSTBYNAME2 */ + #endif /* HAVE_GETNODEBYNAME */ + #endif /* HAVE_GETIPNODEBYNAME */ + } + + void lsFreeHostent(struct hostent *hp) { + #if defined(HAVE_GETNODEBYNAME) || defined(HAVE_GETIPNODEBYNAME) + freehostent(hp); + #else + free(hp); + #endif + } + + #ifdef ID_MASINTER_URL_IPV6 + static int decodeDotIpv6(const char *name, S5NetAddr *na) { + int len = strlen(name); + + /* + * Decode IPv6 address encoded using the syntax defined by + * draft-masinter-url-ipv6-01. The syntax is: + * + all the ':'s are replaced with '-'s. + * + a pseudo domain '.ipv6' is appended. + */ + if (len > 5 && /* if name is not too short, */ + len < INET6_ADDRSTRLEN + 5 && /* nor too long, */ + !strcmp(name + len - 5, ".ipv6")) { /* and ends with ".ipv6" */ + int i; + char decode[INET6_ADDRSTRLEN]; + + for (i = 0; i < len - 5; i++) { + /* replace '-' with ':' */ + decode[i] = (name[i] == '-') ? ':' : name[i]; + } + decode[i] = '\0'; + + if (inet_pton(AF_INET6, decode, &na->sin6.sin6_addr) > 0) { + na->sin6.sin6_family = AF_INET6; + return 1; + } + } + return 0; + } + #endif /* ID_MASINTER_URL_IPV6 */ + #endif + /* Given a name return the network ordered address associated with that */ /* name or INVALIDADDR (-1) on an error. */ + /* IPv6: newly added af specifies the address family. */ + #ifdef SUPPORT_IPV6 + int lsName2Addr(const char *name, S5NetAddr *na, int af) { + #else int lsName2Addr(const char *name, S5NetAddr *na) { + #endif struct hostent *hp; if (!name || *name == '\0' || !strcmp(name, "-")) { return -1; } + #ifdef SUPPORT_IPV6 + memset(na, 0, sizeof(*na)); + + if (af == AF_INET6) { + if (inet_pton(AF_INET6, name, &na->sin6.sin6_addr) > 0) { + na->sin6.sin6_family = AF_INET6; + return 0; + } + #ifdef ID_MASINTER_URL_IPV6 + if (decodeDotIpv6(name, na)) return 0; + #endif + if ((hp = lsGetHostByName(name, AF_INET6)) != NULL) { + na->sin6.sin6_family = AF_INET6; + memcpy(&na->sin6.sin6_addr, hp->h_addr_list[0], hp->h_length); + lsFreeHostent(hp); + } + } else { /* AF_INET */ + if (inet_pton(AF_INET, name, &na->sin.sin_addr) > 0) { + na->sin.sin_family = AF_INET; + return 0; + } + if ((hp = lsGetHostByName(name, AF_INET)) != NULL) { + na->sin.sin_family = AF_INET; + memcpy(&na->sin.sin_addr, hp->h_addr_list[0], hp->h_length); + lsFreeHostent(hp); + } + } + #else /* XXX needs IPv6 support eventually */ memset(&na->sin, 0, sizeof(ssi)); na->sin.sin_family = AF_INET; *************** *** 37,42 **** --- 281,287 ---- MUTEX_LOCK(gh_mutex); if ((hp = REAL(gethostbyname)(name))) memcpy(&na->sin.sin_addr.s_addr, hp->h_addr_list[0], hp->h_length); MUTEX_UNLOCK(gh_mutex); + #endif return hp?0:-1; } *************** *** 73,81 **** case AF_INET: if (addr->sin.sin_addr.s_addr != INADDR_ANY && addr->sin.sin_addr.s_addr != htonl(INADDR_LOOPBACK)) rval = -1; break; ! #ifdef HAVE_NETINET6_IN6_H case AF_INET6: ! if (addr->sin6.sin6_addr != INADDR_ANY && addr->sin6.sin6_addr != htonl(INADDR_LOOPBACK)) rval = -1; break; #endif default: --- 318,327 ---- case AF_INET: if (addr->sin.sin_addr.s_addr != INADDR_ANY && addr->sin.sin_addr.s_addr != htonl(INADDR_LOOPBACK)) rval = -1; break; ! #ifdef SUPPORT_IPV6 case AF_INET6: ! if (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6.sin6_addr) && ! !IN6_IS_ADDR_LOOPBACK(&addr->sin6.sin6_addr)) rval = -1; break; #endif default: *************** *** 95,104 **** case AF_INET: if (a1->sin.sin_port != a2->sin.sin_port) return -1; return memcmp(&a1->sin.sin_addr, &a2->sin.sin_addr, sizeof(struct in_addr)); ! #ifdef HAVE_NETINET6_IN6_H case AF_INET6: if (a1->sin6.sin6_port != a2->sin6.sin6_port) return -1; ! return memcmp(&a1->sin6.sin6_addr, &a2->sin6.sin6_addr, sizeof(struct in_addr6)); #endif default: return -1; --- 341,350 ---- case AF_INET: if (a1->sin.sin_port != a2->sin.sin_port) return -1; return memcmp(&a1->sin.sin_addr, &a2->sin.sin_addr, sizeof(struct in_addr)); ! #ifdef SUPPORT_IPV6 case AF_INET6: if (a1->sin6.sin6_port != a2->sin6.sin6_port) return -1; ! return memcmp(&a1->sin6.sin6_addr, &a2->sin6.sin6_addr, sizeof(struct in6_addr)); #endif default: return -1; *************** *** 113,121 **** return strcmp(a1->sn.sn_name, a2->sn.sn_name); case AF_INET: return memcmp(&a1->sin.sin_addr, &a2->sin.sin_addr, sizeof(struct in_addr)); ! #ifdef HAVE_NETINET6_IN6_H case AF_INET6: ! return memcmp(&a1->sin6.sin6_addr, &a2->sin6.sin6_addr, sizeof(struct in_addr6)); #endif default: return -1; --- 359,367 ---- return strcmp(a1->sn.sn_name, a2->sn.sn_name); case AF_INET: return memcmp(&a1->sin.sin_addr, &a2->sin.sin_addr, sizeof(struct in_addr)); ! #ifdef SUPPORT_IPV6 case AF_INET6: ! return memcmp(&a1->sin6.sin6_addr, &a2->sin6.sin6_addr, sizeof(struct in6_addr)); #endif default: return -1; *************** *** 127,140 **** } const char *lsAddr2Ascii(const S5NetAddr *na) { switch (na->sa.sa_family) { case AF_S5NAME: return na->sn.sn_name; case AF_INET: return inet_ntoa(na->sin.sin_addr); ! #ifdef HAVE_NETINET6_IN6_H case AF_INET6: ! return addr2ascii(AF_INET6, (char *)&na->sin6.sin6_addr, sizeof(struct in_addr6), NULL); #endif default: return ""; --- 373,389 ---- } const char *lsAddr2Ascii(const S5NetAddr *na) { + #ifdef SUPPORT_IPV6 + static char tmp[INET6_ADDRSTRLEN]; + #endif switch (na->sa.sa_family) { case AF_S5NAME: return na->sn.sn_name; case AF_INET: return inet_ntoa(na->sin.sin_addr); ! #ifdef SUPPORT_IPV6 case AF_INET6: ! return inet_ntop(AF_INET6, &na->sin6.sin6_addr, tmp, sizeof(tmp)); #endif default: return ""; *************** *** 147,153 **** return na->sn.sn_port; case AF_INET: return na->sin.sin_port; ! #ifdef HAVE_NETINET6_IN6_H case AF_INET6: return na->sin6.sin6_port; #endif --- 396,402 ---- return na->sn.sn_port; case AF_INET: return na->sin.sin_port; ! #ifdef SUPPORT_IPV6 case AF_INET6: return na->sin6.sin6_port; #endif *************** *** 164,170 **** case AF_INET: na->sin.sin_port = port; break; ! #ifdef HAVE_NETINET6_IN6_H case AF_INET6: na->sin6.sin6_port = port; break; --- 413,419 ---- case AF_INET: na->sin.sin_port = port; break; ! #ifdef SUPPORT_IPV6 case AF_INET6: na->sin6.sin6_port = port; break; *************** *** 178,184 **** return na->sn.sn_name; case AF_INET: return (char *)&na->sin.sin_addr; ! #ifdef HAVE_NETINET6_IN6_H case AF_INET6: return (char *)&na->sin6.sin6_addr; #endif --- 427,433 ---- return na->sn.sn_name; case AF_INET: return (char *)&na->sin.sin_addr; ! #ifdef SUPPORT_IPV6 case AF_INET6: return (char *)&na->sin6.sin6_addr; #endif *************** *** 193,201 **** return strlen(na->sn.sn_name); case AF_INET: return sizeof(struct in_addr); ! #ifdef HAVE_NETINET6_IN6_H case AF_INET6: ! return sizeof(struct in_addr6); #endif default: return 0; --- 442,450 ---- return strlen(na->sn.sn_name); case AF_INET: return sizeof(struct in_addr); ! #ifdef SUPPORT_IPV6 case AF_INET6: ! return sizeof(struct in6_addr); #endif default: return 0; *************** *** 208,214 **** return sizeof(ssn); case AF_INET: return sizeof(ssi); ! #ifdef HAVE_NETINET6_IN6_H case AF_INET6: return sizeof(ssi6); #endif --- 457,463 ---- return sizeof(ssn); case AF_INET: return sizeof(ssi); ! #ifdef SUPPORT_IPV6 case AF_INET6: return sizeof(ssi6); #endif *************** *** 216,218 **** --- 465,506 ---- return 0; } } + + #ifdef SUPPORT_IPV6 + /* IPv6: Convert between IPv4 address and IPv6 address. IPv4->IPv6 */ + /* IPv6: conversion is always possible, but the reverse conversion is */ + /* IPv6: possible only if the IPv6 address is a IPv4-mapped address. */ + /* IPv6: This function returns 1 if conversion is successful, 0 otherwise. */ + int lsMappedAddrConvert(S5NetAddr *na, int af) { + if ((na->sa.sa_family == AF_INET && af == AF_INET6) || + (na->sa.sa_family == AF_INET6 && af == AF_INET && + IN6_IS_ADDR_V4MAPPED(&na->sin6.sin6_addr))) { + S5NetAddr tmp; + u_char *p; + + memset(&tmp, 0, sizeof(tmp)); + tmp.sa.sa_family = af; + if (af == AF_INET) { + /* IPv6 (mapped) -> IPv4 */ + tmp.sin.sin_port = na->sin6.sin6_port; + p = (u_char *)&na->sin6.sin6_addr; + memcpy(&tmp.sin.sin_addr, p + 12, 4); + #ifdef SIN6_LEN + tmp.sin.sin_len = sizeof(struct sockaddr_in); + #endif + } else { + /* IPv4 -> IPv6 (mapped) */ + tmp.sin6.sin6_port = na->sin.sin_port; + p = (u_char *)&tmp.sin6.sin6_addr; + memcpy(p + 12, &na->sin.sin_addr, 4); + p[10] = p[11] = 0xff; + #ifdef SIN6_LEN + tmp.sin6.sin6_len = sizeof(struct sockaddr_in6); + #endif + } + memcpy(na, &tmp, sizeof(tmp)); + return 1; + } + return 0; + } + #endif Index: lib/addr.h diff -c src/socks5/lib/addr.h:1.1.1.3 src/socks5/lib/addr.h:1.7.2.1 *** lib/addr.h Thu Apr 1 11:04:05 1999 --- lib/addr.h Wed Apr 7 14:35:46 1999 *************** *** 12,18 **** #define ADDR_H /* for convenience and space's sake... */ ! #ifdef HAVE_NETINET6_IN6_H typedef struct sockaddr_in6 ssi6; #endif typedef struct sockaddr_name ssn; --- 12,18 ---- #define ADDR_H /* for convenience and space's sake... */ ! #ifdef SUPPORT_IPV6 typedef struct sockaddr_in6 ssi6; #endif typedef struct sockaddr_name ssn; *************** *** 33,44 **** extern const char *lsAddr2Ascii P((const S5NetAddr *na)); extern const char *lsAddr2Ptr P((const S5NetAddr *na)); int lsName2Addr P((const char *, S5NetAddr *)); int lsName2Port P((const char *, const char *, u_short *)); #define ADDRANDPORT(x) lsAddr2Ascii((x)), ntohs(lsAddr2Port((x))) ! #ifdef HAVE_NETINET6_IN6_H #define ISINET(x) (((x)->sa_family == AF_INET) || ((x)->sa_family == AF_INET6)) #else #define ISINET(x) ((x)->sa_family == AF_INET) --- 33,54 ---- extern const char *lsAddr2Ascii P((const S5NetAddr *na)); extern const char *lsAddr2Ptr P((const S5NetAddr *na)); + #ifdef SUPPORT_IPV6 + int lsName2Addr P((const char *, S5NetAddr *, int)); + #else int lsName2Addr P((const char *, S5NetAddr *)); + #endif int lsName2Port P((const char *, const char *, u_short *)); + #ifdef SUPPORT_IPV6 + extern int lsMappedAddrConvert P((S5NetAddr *, int)); + extern struct hostent *lsGetHostByName P((const char *, int)); + extern void lsFreeHostent P((struct hostent *)); + #endif + #define ADDRANDPORT(x) lsAddr2Ascii((x)), ntohs(lsAddr2Port((x))) ! #ifdef SUPPORT_IPV6 #define ISINET(x) (((x)->sa_family == AF_INET) || ((x)->sa_family == AF_INET6)) #else #define ISINET(x) ((x)->sa_family == AF_INET) Index: lib/cache.c diff -c src/socks5/lib/cache.c:1.1.1.3 src/socks5/lib/cache.c:1.5.4.2 *** lib/cache.c Thu Aug 5 13:20:57 1999 --- lib/cache.c Thu Aug 5 17:50:47 1999 *************** *** 22,27 **** --- 22,51 ---- lsSocksInfo *lsConList = NULL; /* all current lib connections */ lsSocksInfo *lsLastCon = NULL; /* pointer to the proxy connect */ + #ifdef SUPPORT_IPV6 + static int acceptBothAF = -1; + #endif + + #ifdef SUPPORT_IPV6 + /* Initialize variable acceptBothAF. */ + static void InitAcceptBothAF() { + if (acceptBothAF >= 0) return; + acceptBothAF = getenv("SOCKS5_ACCEPT_BOTH_AF") != NULL; + } + + /* Get the address family of socket. */ + static int GetSocketAF(S5IOHandle fd) { + struct sockaddr_in6 sa6; + int sa6len = sizeof(sa6); + + sa6.sin6_family = AF_UNSPEC; + if (REAL(getsockname)(fd, (struct sockaddr *)&sa6, &sa6len) < 0) { + return -1; + } + return sa6.sin6_family; + } + #endif + static void lsProxyCacheDelete(lsProxyInfo **pp, S5IOHandle rfd) { lsProxyInfo *n, *p = *pp; *************** *** 115,121 **** --- 139,162 ---- return p; } } + #ifdef SUPPORT_IPV6 + if (na->sa.sa_family == AF_INET6) { + if (IN6_IS_ADDR_UNSPECIFIED(&na->sin6.sin6_addr)) { + return NULL; + } + for (p = pcon?pcon->pri:NULL; p; p = p->next) { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Checking %d (%s:%d)", p->how, ADDRANDPORT(&p->prxyin)); + + if (p->how != how) continue; + if (p->prxyin.sin6.sin6_family != na->sin6.sin6_family) continue; + if (memcmp(&p->prxyin.sin6.sin6_addr, &na->sin6.sin6_addr, sizeof(struct in6_addr))) continue; + if (checkport && p->prxyin.sin6.sin6_port != na->sin6.sin6_port) continue; + return p; + } + } + #endif + return NULL; } *************** *** 204,209 **** --- 245,263 ---- p->next = lsConList; p->fd = fd; p->afd = S5InvalidIOHandle; + #ifdef SUPPORT_IPV6 + p->af = GetSocketAF(fd); + InitAcceptBothAF(); + if (acceptBothAF) { + p->handlev4v6 = V4V6_BOTH; + } else { + #ifdef SUPPORT_MAPPED_ADDRESS + p->handlev4v6 = (p->af == AF_INET6) ? V4V6_MAPPED : V4V6_NO; + #else + p->handlev4v6 = V4V6_NO; + #endif + } + #endif lsConList = p; S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsConnectionAdd: fdset added fd #%d", fd); *************** *** 237,239 **** --- 291,302 ---- return NULL; } + #ifdef SUPPORT_IPV6 + int LIBPREFIX(accept_both_af)(int yesno) { + int prev; + InitAcceptBothAF(); + prev = acceptBothAF; + acceptBothAF = yesno ? 1 : 0; + return prev; + } + #endif Index: lib/conf.c diff -c src/socks5/lib/conf.c:1.1.1.4 src/socks5/lib/conf.c:1.9.2.3 *** lib/conf.c Thu Apr 1 11:04:23 1999 --- lib/conf.c Wed Apr 7 14:35:48 1999 *************** *** 55,61 **** --- 55,65 ---- static u_char DefaultProto = (u_char)-1; /* default protocol to use... */ static u_short DefaultPort = INVALIDPORT; static S5NetAddr Socks4Addr; + #ifdef SUPPORT_IPV6 + static S5NetAddr Socks5Addr_IPv4, Socks5Addr_IPv6; + #else static S5NetAddr Socks5Addr; + #endif static void ProxyHandler(void **array, int indx, int i, char *tmp) { ProxyTuple *pa = (*(ProxyTuple **)array); *************** *** 98,108 **** --- 102,124 ---- case SOCKS5IND: pa[indx].version = SOCKS5_VERSION; break; } + #ifdef SUPPORT_IPV6 + /* IPv6: lsGetHostAddressAndPort may return two addresses */ + /* IPv6: (IPv4 and IPv6). */ + for (j = 0; j < S5_SERVER_NUM - 1 && *tmp && *tmp != '\n'; j++, tmp++) { + int r; + if ((r = lsGetHostAddressAndPort(&tmp, &pa[indx].netaddr[j])) < 0) { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "Bad line in configuration (%s) file: %d", "Servers", lsLineNo); + return; + } + if (r == 2) j++; + #else for (j = 0; j < S5_SERVER_NUM && *tmp && *tmp != '\n'; j++, tmp++) { if (lsGetHostAddressAndPort(&tmp, &pa[indx].netaddr[j])) { S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "Bad line in configuration (%s) file: %d", "Servers", lsLineNo); return; } + #endif SKIPSPACE(tmp); *************** *** 118,125 **** --- 134,148 ---- void SetUpDefaults() { u_short tmpport = INVALIDPORT; char *tmp, *tmp2; + #ifdef SUPPORT_IPV6 + char *tmp3 = NULL; + #endif DefaultProto = + #ifdef SUPPORT_IPV6 + getenv("SOCKS5_SERVER_IPV4")?SOCKS5_VERSION: + getenv("SOCKS5_SERVER_IPV6")?SOCKS5_VERSION: + #endif getenv("SOCKS5_SERVER")?SOCKS5_VERSION: getenv("SOCKS4_SERVER")?SOCKS4_VERSION: getenv("SOCKS_SERVER")?SOCKS5_VERSION: *************** *** 142,153 **** --- 165,238 ---- tmpport = DefaultPort; } + #ifdef SUPPORT_IPV6 + lsName2Addr(tmp, &Socks4Addr, AF_INET); + #else lsName2Addr(tmp, &Socks4Addr); + #endif lsAddrSetPort(&Socks4Addr, tmpport); if (tmp2) *tmp2 = ':'; S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Default socks4 server is: %s %s:%d", tmp, ADDRANDPORT(&Socks4Addr)); + #ifdef SUPPORT_IPV6 + /* IPv6: We need a socks5 server for IPv4 connections, and another for */ + /* IPv6: IPv6. */ + + if (!(tmp = getenv("SOCKS5_SERVER_IPV4")) && + !(tmp = getenv("SOCKS5_SERVER")) && !(tmp = getenv("SOCKS_SERVER"))) + tmp = SOCKS_DEFAULT_SERVER; + + Socks5Addr_IPv4.sin.sin_family = AF_INET; + + if ((tmp2 = strchr(tmp, ':'))) { + *tmp2 = '\0'; + lsName2Port(tmp2+1, "tcp", &tmpport); + } else { + tmpport = DefaultPort; + } + + lsName2Addr(tmp, &Socks5Addr_IPv4, AF_INET); + lsAddrSetPort(&Socks5Addr_IPv4, tmpport); + + if (tmp2) *tmp2 = ':'; + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Default socks5 serverfor IPv4 is: %s %s:%d", tmp, ADDRANDPORT(&Socks5Addr_IPv4)); + + if (!(tmp = getenv("SOCKS5_SERVER_IPV6")) && + !(tmp = getenv("SOCKS5_SERVER")) && !(tmp = getenv("SOCKS_SERVER"))) + tmp = SOCKS_DEFAULT_SERVER; + + Socks5Addr_IPv6.sin.sin_family = AF_INET6; + + if (*tmp == '[') { + tmp++; + if ((tmp3 = strchr(tmp, ']')) == NULL) { + Socks5Addr_IPv6.sin.sin_family = AF_UNSPEC; + } else { + *tmp3 = '\0'; + } + if ((tmp2 = strchr(tmp3 + 1, ':'))) { + *tmp2 = '\0'; + lsName2Port(tmp2+1, "tcp", &tmpport); + } else { + tmpport = DefaultPort; + } + } else { + if ((tmp2 = strchr(tmp, ':'))) { + *tmp2 = '\0'; + lsName2Port(tmp2+1, "tcp", &tmpport); + } else { + tmpport = DefaultPort; + } + } + + lsName2Addr(tmp, &Socks5Addr_IPv6, AF_INET6); + lsAddrSetPort(&Socks5Addr_IPv6, tmpport); + + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Default socks5 serverfor IPv6 is: %s %s:%d", tmp, ADDRANDPORT(&Socks5Addr_IPv6)); + if (tmp2) *tmp2 = ':'; + if (tmp3) *tmp3 = ']'; + #else if (!(tmp = getenv("SOCKS5_SERVER")) && !(tmp = getenv("SOCKS_SERVER"))) tmp = SOCKS_DEFAULT_SERVER; *************** *** 165,175 **** --- 250,271 ---- if (tmp2) *tmp2 = ':'; S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Default socks5 server is: %s %s:%d", tmp, ADDRANDPORT(&Socks5Addr)); + #endif if (getenv("SOCKS5_NONETMASKCHECK") == NULL) lsSetupIntfcs(&intfcs, &ifcnt); } + #ifdef SUPPORT_IPV6 + /* IPv6: The last argument conn_af specifies the address family to use */ + /* IPv6: for the connection to the SOCKS server. However, the proxy list */ + /* IPv6: returned in proxy argument may contain addresses with different */ + /* IPv6: family from conn_af. Caller must filter out those servers. Of */ + /* IPv6: course it's better to filter out by this function, but this is */ + /* IPv6: easier to implement.. */ + u_char lsHowToConnect(const S5NetAddr *dest, u_char command, S5NetAddr **proxy, int *nproxies, char *user, S5NetAddr *ret, int conn_af) { + #else u_char lsHowToConnect(const S5NetAddr *dest, u_char command, S5NetAddr **proxy, int *nproxies, char *user, S5NetAddr *ret) { + #endif u_char proto = (u_char)-1; static int read = 0; static S5NetAddr defaddr; *************** *** 208,215 **** --- 304,317 ---- rval = lsGetCachedHostname((S5NetAddr *)dest, hostname, sizeof(hostname)); /* If the destination is localhost or the host itself return DIRECT. */ + #ifdef SUPPORT_IPV6 + if (rval && dest->sin.sin_family == AF_INET && conn_af == AF_INET) { + if (dest->sin.sin_addr.s_addr == htonl(INADDR_LOOPBACK) && + getenv("SOCKS5_NOLOOPBACKCHECK") == NULL) return DIRECT; + #else if (rval && dest->sin.sin_family == AF_INET) { if (dest->sin.sin_addr.s_addr == htonl(INADDR_LOOPBACK)) return DIRECT; + #endif if (getenv("SOCKS5_NONETMASKCHECK") == NULL) { for (i = 0; i < ifcnt; i++) { *************** *** 227,236 **** --- 329,367 ---- } } } + #ifdef SUPPORT_IPV6 + else if (rval && dest->sin.sin_family == AF_INET6 && conn_af == AF_INET6) { + if (IN6_IS_ADDR_LOOPBACK(&dest->sin6.sin6_addr) && + getenv("SOCKS5_NOLOOPBACKCHECK") == NULL) return DIRECT; + if (getenv("SOCKS5_NONETMASKCHECK") == NULL) { + for (i = 0; i < ifcnt; i++) { + for (j = 0; j < intfcs[i].addr6cnt; j++) { + if (lsCheckIfc6(&intfcs[i].addr6list[j], &dest->sin6.sin6_addr)) { + char tmp1[INET6_ADDRSTRLEN], tmp2[INET6_ADDRSTRLEN]; + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, + "lsHowToConnect: dest(%s) matches if (%s/%s)", + inet_ntop(AF_INET6, &dest->sin6.sin6_addr, + tmp1, sizeof(tmp1)), + intfcs[i].name, + inet_ntop(AF_INET6, + &intfcs[i].addr6list[j].ip, + tmp2, sizeof(tmp2))); + return DIRECT; + } + } + } + } + } + #endif + for (i = 0; i < nplines; i++) { if (pts[i].version == SOCKS4_VERSION) { if ((command != SOCKS_BIND && command != SOCKS_CONNECT) || !rval) continue; + #ifdef SUPPORT_IPV6 + /* IPv6: SOCKS4 doesn't support IPv6. */ + if (conn_af == AF_INET6) continue; + #endif } if (!lsCheckByte(pts[i].command, command, "commands")) continue; *************** *** 249,268 **** if (proto == DIRECT) return proto; } else *proxy = &defaddr; - if (*nproxies == 0) *nproxies = 1; - if (proto == (u_char)-1) proto = DefaultProto; /* Fill in the default ports and addresses if any are still invalid... */ for (i = 0; i < *nproxies; i++) { (*proxy)[i].sa.sa_family = AF_INET; if ((*proxy)[i].sin.sin_addr.s_addr == 0L || (*proxy)[i].sin.sin_addr.s_addr == INVALIDADDR) { lsAddrCopy(&(*proxy)[i], (proto == SOCKS4_VERSION)?&Socks4Addr:&Socks5Addr, sizeof((*proxy)[i])); } if (lsAddr2Port(&(*proxy)[i]) == 0 || lsAddr2Port(&(*proxy)[i]) == INVALIDPORT) { lsAddrSetPort(&(*proxy)[i], lsAddr2Port((proto == SOCKS4_VERSION)?&Socks4Addr:&Socks5Addr)); } /* If the destination matches the proxy server, client must be able */ --- 380,421 ---- if (proto == DIRECT) return proto; } else *proxy = &defaddr; if (proto == (u_char)-1) proto = DefaultProto; + #ifdef SUPPORT_IPV6 + if (*proxy == &defaddr) { + *nproxies = 1; + if (conn_af == AF_INET) { + lsAddrCopy(&defaddr, + proto == SOCKS4_VERSION ? + &Socks4Addr : &Socks5Addr_IPv4, + sizeof(defaddr)); + } else { /* AF_INET6 */ + lsAddrCopy(&defaddr, &Socks5Addr_IPv6, sizeof(defaddr)); + } + } + #else + if (*nproxies == 0) *nproxies = 1; + #endif + /* Fill in the default ports and addresses if any are still invalid... */ for (i = 0; i < *nproxies; i++) { + #ifndef SUPPORT_IPV6 + /* IPv6: All the proxy addresses must be valid. So need not to */ + /* IPv6: check them. */ (*proxy)[i].sa.sa_family = AF_INET; if ((*proxy)[i].sin.sin_addr.s_addr == 0L || (*proxy)[i].sin.sin_addr.s_addr == INVALIDADDR) { lsAddrCopy(&(*proxy)[i], (proto == SOCKS4_VERSION)?&Socks4Addr:&Socks5Addr, sizeof((*proxy)[i])); } + #endif if (lsAddr2Port(&(*proxy)[i]) == 0 || lsAddr2Port(&(*proxy)[i]) == INVALIDPORT) { + #ifdef SUPPORT_IPV6 + lsAddrSetPort(&(*proxy)[i], lsAddr2Port((proto == SOCKS4_VERSION)?&Socks4Addr:&Socks5Addr_IPv4)); + #else lsAddrSetPort(&(*proxy)[i], lsAddr2Port((proto == SOCKS4_VERSION)?&Socks4Addr:&Socks5Addr)); + #endif } /* If the destination matches the proxy server, client must be able */ Index: lib/conf.h diff -c src/socks5/lib/conf.h:1.1.1.2 src/socks5/lib/conf.h:1.2.4.1 *** lib/conf.h Thu Apr 1 11:04:23 1999 --- lib/conf.h Wed Apr 7 14:35:49 1999 *************** *** 11,16 **** --- 11,20 ---- #ifndef __CONF_H__ #define __CONF_H__ + #ifdef SUPPORT_IPV6 + extern u_char lsHowToConnect P((const S5NetAddr *, u_char, S5NetAddr **, int *, char *, S5NetAddr *, int)); + #else extern u_char lsHowToConnect P((const S5NetAddr *, u_char, S5NetAddr **, int *, char *, S5NetAddr *)); + #endif #endif Index: lib/confutil.c diff -c src/socks5/lib/confutil.c:1.1.1.5 src/socks5/lib/confutil.c:1.15.2.3 *** lib/confutil.c Thu Apr 1 11:04:17 1999 --- lib/confutil.c Wed Apr 7 14:35:49 1999 *************** *** 14,26 **** #include "addr.h" #include "confutil.h" #include "log.h" #ifdef HAVE_IFADDRS_H #include #define ifassi(x) (((ssi *)(x))->sin_addr.s_addr) #endif ! #ifdef OSIOCGIFCONF #define RSIOCGIFCONF OSIOCGIFCONF #else #define RSIOCGIFCONF SIOCGIFCONF --- 14,32 ---- #include "addr.h" #include "confutil.h" #include "log.h" + #if defined(SUPPORT_IPV6) && defined(KAME) + #include + #endif #ifdef HAVE_IFADDRS_H #include #define ifassi(x) (((ssi *)(x))->sin_addr.s_addr) #endif ! /* IPv6: Unfortunately, struct sockaddr_in6 is bigger than struct sockaddr, */ ! /* IPv6: so it doesn't fit into struct ifreq. This means we cannot use */ ! /* IPv6: good old OSIOCGIFCONF if the system supports IPv6. */ ! #if defined(OSIOCGIFCONF) && !(defined(SUPPORT_IPV6) && defined(SIN6_LEN)) #define RSIOCGIFCONF OSIOCGIFCONF #else #define RSIOCGIFCONF SIOCGIFCONF *************** *** 44,49 **** --- 50,78 ---- + #ifdef SUPPORT_IPV6 + /* IPv6: A function that checks if a1 and a2 have the same prefix of length */ + /* IPv6: plen. */ + static int EqualPrefix(const struct in6_addr *a1, const struct in6_addr *a2, int plen) { + static unsigned char mask[] = { + 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff, + }; + int i; + + if (plen > 128) plen = 128; /* just in case.. */ + + for (i = 0; plen >= 8; i++, plen -= 8) { + if (a1->s6_addr[i] != a2->s6_addr[i]) return 0; + } + if (plen > 0 && (a1->s6_addr[i] ^ a2->s6_addr[i]) & mask[i]) return 0; + return 1; + } + + int lsCheckIfc6(const struct intaddr6 *intfc, const struct in6_addr *in) { + return EqualPrefix(in, &intfc->ip, intfc->prefixlen); + } + #endif + /* A function that checks if s1 is the first string in s1, and is followed */ /* by whitespace. Used for configuration file entries. */ static int CheckString(char *s1, char *s2) { *************** *** 120,125 **** --- 149,155 ---- } } + #if 0 /* Look at the buffer that ptr points to, and read an address... */ /* */ /* Arguments: ptr -- a ptr to the buffer we are working with...(in/out) */ *************** *** 139,144 **** --- 169,175 ---- *(*ptr = tmp) = tc; return rval; } + #endif /* Look at the buffer that ptr points to, and read a port... check ,'s */ /* */ *************** *** 176,210 **** --- 207,330 ---- return rval; } + #ifdef SUPPORT_IPV6 + char *lsExtractEnclosedAddr(char *ptr, char *buf) { + /* buf must be at least INET6_ADDRSTRLEN bytes long. */ + char *closeb; + int len; + + if (*ptr++ != '[') return NULL; + + /* Find close bracket. */ + if ((closeb = strchr(ptr, ']')) == NULL) { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, + "Conf: missing close bracket"); + return NULL; + } + len = closeb - ptr; + + /* Check the length of address string. */ + if (len + 1 > INET6_ADDRSTRLEN) { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, + "Conf: enclosed address is too long"); + return NULL; + } + + /* Copy the address string. It also checks if the characters are valid. */ + while (ptr < closeb) { + if (!isxdigit((unsigned char)*ptr) && *ptr != ':' && *ptr != '.') { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, + "Conf: invalid character in enclosed address"); + return NULL; + } + *buf++ = *ptr++; + } + *buf = '\0'; + + return closeb + 1; + } + #endif + /* Look at the buffer that ptr points to, and read an address and a port... */ /* The address and port are separated by ':' ... */ /* */ /* Arguments: ptr -- a ptr to the buffer we are working with...(in/out) */ /* na -- a ptr to the address we are looking up...(out) */ + /* IPv6: This function may return two addresses, one for IPv4 and another */ + /* IPv6: for IPv6. The return value of this function is the number of */ + /* IPv6: returned addresses, or -1 if error occured. */ int lsGetHostAddressAndPort(char **ptr, S5NetAddr *na) { int rval; char *tmp, tc; + #ifdef SUPPORT_IPV6 + u_short port = INVALIDPORT; + char buf[INET6_ADDRSTRLEN]; + #endif SKIPSPACE(*ptr); tmp = *ptr; + #ifdef SUPPORT_IPV6 + if (tmp[0] == '[') { + if ((tmp = lsExtractEnclosedAddr(tmp, buf)) == NULL) return -1; + *ptr = buf; + if (*tmp != '\0' && !isspace((unsigned char)*tmp) && + *tmp != ',' && *tmp != ':') { + *ptr = tmp; + return -1; + } + } else { + SKIPNSPNCOLNCOM(tmp); + } + #else SKIPNSPNCOLNCOM(tmp); + #endif if (tmp == *ptr) return 0; tc = *tmp; *tmp = '\0'; + #ifdef SUPPORT_IPV6 + rval = 0; + /* IPv6: First, try IPv4 address. */ + if (lsName2Addr(*ptr, na, AF_INET) == 0) { + rval++; + na++; + } + /* IPv6: Then, try IPv6 address. */ + if (lsName2Addr(*ptr, na, AF_INET6) == 0) { + rval++; + na++; + } + /* IPv6: If both failed.. */ + if (rval == 0) rval = -1; + #else rval = lsName2Addr(*ptr, na); + #endif *(*ptr = tmp) = tc; if (rval < 0) return rval; if (tc == ':') { (*ptr)++; + #ifdef SUPPORT_IPV6 + if (lsGetPort(ptr, &port) == 0) { + lsAddrSetPort(na - 1, port); + if (rval == 2) lsAddrSetPort(na - 2, port); + return rval; + } else { + return -1; + } + #else return lsGetHostPort(ptr, na); + #endif } + #ifdef SUPPORT_IPV6 + return rval; + #else return 0; + #endif } /* Given ip (address in net order) return the standard subnet mask for it. */ *************** *** 230,239 **** --- 350,364 ---- /* */ /* Arguments: ptr -- a ptr to the buffer we are working with...(in/out) */ /* host -- a ptr to the address/mask we are looking up...(out) */ + /* IPv6: IPv6 address and associated prefix length is represented by */ + /* IPv6: ipv6-address/prefix-length (x:x:x:x:x:x:x:x/n). */ int lsGetHostAndMask(char **ptr, struct host *h) { int i, nd = 0, rval = 0; struct hostent *hp; char *tmp, *st, c; + #ifdef SUPPORT_IPV6 + char buf[INET6_ADDRSTRLEN]; + #endif if (!h) return -1; memset((char *)h, 0, sizeof(struct host)); *************** *** 256,266 **** --- 381,394 ---- /* - */ /* This is obviously the easiest case...its a -, so any body matches */ + /* IPv6: This is a special case and this pattern even matches to */ + /* IPv6: IPv6 addresses. See comments in lsCheckHost(). */ h->type = IN_ADDR; h->mask.s_addr = htonl(0x00000000); h->ip.s_addr = htonl(0x00000000); } else if (c == '/') { /* n.n.n.n/[m.m.m.m|h|s|n|a] */ + /* IPv6: or x:x:x:x:x:x:x:x/n */ char *end, c2; for (end = tmp+1; !isspace((unsigned char)*end) && *end != '\0'; end++); *************** *** 268,273 **** --- 396,441 ---- /* There was a /, so there has to have been an IP address before it. */ /* Read the address, then read the mask... Pretty straight forward. */ + #ifdef SUPPORT_IPV6 + if (inet_pton(AF_INET6, st, &h->ip6) > 0 || + (lsExtractEnclosedAddr(st, buf) != NULL && + inet_pton(AF_INET6, buf, &h->ip6) > 0)) { + /* IPv6 address */ + char *term; + + h->type = IN6_ADDR; + /* get prefix length */ + h->prefixlen = (int)strtol(tmp + 1, &term, 0); + if (h->prefixlen < 0 || h->prefixlen > 128 || *term != '\0') { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, + "Conf: Invalid prefix length"); + rval = -1; + } + if (h->prefixlen == 128 && getenv("SOCKS5_REVERSEMAP") != NULL) { + /* Map the IP, since the name we will be comparing it to */ + /* will already have been resolved and mapped (hopefully). */ + MUTEX_LOCK(gh_mutex); + if ((hp = gethostbyaddr((char *)&h->ip6, sizeof(struct in6_addr), AF_INET6)) != NULL) { + /* Store all the aliases and the ip addresses */ + h->resolve = 1; + strncpy(h->name, hp->h_name, MIN(strlen(hp->h_name), S5_HOSTNAME_SIZE-1)); + h->name[MIN(strlen(hp->h_name), S5_HOSTNAME_SIZE-1)] = '\0'; + + for (i = 0; hp->h_aliases[i] && i < S5_HOSTALIASES_NUM; i++) { + strncpy(h->aliases[i], hp->h_aliases[i], MIN(strlen(hp->h_aliases[i]), S5_HOSTNAME_SIZE-1)); + h->aliases[i][MIN(strlen(hp->h_aliases[i]), S5_HOSTNAME_SIZE-1)] = '\0'; + } + h->aliascnt = i; + + for (i = 0; hp->h_addr_list[i] && i < S5_HOSTIP_NUM; i++) { + memcpy((char *)&h->back6[i], hp->h_addr_list[i], sizeof(struct in6_addr)); + } + h->ip6cnt = i; + } + MUTEX_UNLOCK(gh_mutex); + } + } else { + #endif if ((h->ip.s_addr = inet_addr(st)) == INVALIDADDR) { S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "Conf: Invalid address in address/mask host pair"); rval = -1; *************** *** 308,313 **** --- 476,484 ---- MUTEX_UNLOCK(gh_mutex); } + #ifdef SUPPORT_IPV6 + } + #endif *tmp = c; tmp = end; c = c2; *************** *** 366,371 **** --- 537,577 ---- } MUTEX_UNLOCK(gh_mutex); } + #ifdef SUPPORT_IPV6 + } else if (inet_pton(AF_INET6, st, &h->ip6) > 0 || + (lsExtractEnclosedAddr(st, buf) != NULL && + inet_pton(AF_INET6, buf, &h->ip6) > 0)) { + h->type = IN6_ADDR; + h->prefixlen = 128; + + /* Map the IP, since the name we will be comparing it to */ + /* will already have been resolved and mapped (hopefully). */ + if (getenv("SOCKS5_REVERSEMAP") != NULL) { + MUTEX_LOCK(gh_mutex); + if ((hp = gethostbyaddr((char *)&h->ip6, sizeof(struct in6_addr), + AF_INET6)) != NULL) { + /* Store all the aliases and the ip addresses */ + h->resolve = 1; + strncpy(h->name, hp->h_name, + MIN(strlen(hp->h_name), S5_HOSTNAME_SIZE-1)); + h->name[MIN(strlen(hp->h_name), S5_HOSTNAME_SIZE-1)] = '\0'; + + for (i = 0; hp->h_aliases[i] && i < S5_HOSTALIASES_NUM; i++) { + strncpy(h->aliases[i], hp->h_aliases[i], + MIN(strlen(hp->h_aliases[i]), S5_HOSTNAME_SIZE-1)); + h->aliases[i][MIN(strlen(hp->h_aliases[i]), S5_HOSTNAME_SIZE-1)] = '\0'; + } + h->aliascnt = i; + + for (i = 0; hp->h_addr_list[i] && i < S5_HOSTIP_NUM; i++) { + memcpy((char *)&h->back6[i], hp->h_addr_list[i], + sizeof(struct in6_addr)); + } + h->ip6cnt = i; + } + MUTEX_UNLOCK(gh_mutex); + } + #endif } else { /* name */ h->type = NAME; *************** *** 382,387 **** --- 588,629 ---- /* Reverse map the name, since the name we will be comparing it to */ /* will already have been reverse and mapped (hopefully). */ MUTEX_LOCK(gh_mutex); + #ifdef SUPPORT_IPV6 + if ((hp = lsGetHostByName(st, AF_INET)) != NULL) { + /* Store all the aliases and the ip addresses */ + strncpy(h->name, hp->h_name, MIN(strlen(hp->h_name), S5_HOSTNAME_SIZE-1)); + h->name[MIN(strlen(hp->h_name), S5_HOSTNAME_SIZE-1)] = '\0'; + + for (i = 0; hp->h_aliases[i] && i < S5_HOSTALIASES_NUM; i++) { + strncpy(h->aliases[i], hp->h_aliases[i], MIN(strlen(hp->h_aliases[i]), S5_HOSTNAME_SIZE-1)); + h->aliases[i][MIN(strlen(hp->h_aliases[i]), S5_HOSTNAME_SIZE-1)] = '\0'; + } + h->aliascnt = i; + + for (i = 0; hp->h_addr_list[i] && i < S5_HOSTIP_NUM; i++) { + memcpy((char *)&h->back[i], hp->h_addr_list[i], sizeof(struct in_addr)); + } + h->ipcnt = i; + lsFreeHostent(hp); + } + if ((hp = lsGetHostByName(st, AF_INET6)) != NULL) { + /* Store all the aliases and the ip addresses */ + strncpy(h->name, hp->h_name, MIN(strlen(hp->h_name), S5_HOSTNAME_SIZE-1)); + h->name[MIN(strlen(hp->h_name), S5_HOSTNAME_SIZE-1)] = '\0'; + + for (i = h->aliascnt; hp->h_aliases[i] && i < S5_HOSTALIASES_NUM; i++) { + strncpy(h->aliases[i], hp->h_aliases[i], MIN(strlen(hp->h_aliases[i]), S5_HOSTNAME_SIZE-1)); + h->aliases[i][MIN(strlen(hp->h_aliases[i]), S5_HOSTNAME_SIZE-1)] = '\0'; + } + h->aliascnt = i; + + for (i = 0; hp->h_addr_list[i] && i < S5_HOSTIP_NUM; i++) { + memcpy((char *)&h->back6[i], hp->h_addr_list[i], sizeof(struct in6_addr)); + } + h->ip6cnt = i; + lsFreeHostent(hp); + } + #else if ((hp = REAL(gethostbyname)(st)) != NULL) { /* Store all the aliases and the ip addresses */ strncpy(h->name, hp->h_name, MIN(strlen(hp->h_name), S5_HOSTNAME_SIZE-1)); *************** *** 398,403 **** --- 640,646 ---- } h->ipcnt = i; } + #endif MUTEX_UNLOCK(gh_mutex); } *************** *** 707,716 **** --- 950,970 ---- if (s && s->sa.sa_family == AF_INET && s->sin.sin_addr.s_addr == INVALIDADDR) return 0; /* The address was stored, not the name => compare addresses. */ + #ifdef SUPPORT_IPV6 + if (h->type == IN_ADDR || h->type == IN6_ADDR) { + #else if (h->type == IN_ADDR) { + #endif + #ifdef SUPPORT_IPV6 + if (h->type == IN_ADDR) { + #endif if (h->ip.s_addr == INVALIDADDR) return 0; /* It is all.... */ + /* IPv6: This does not check s, so it also matches IPv6 addresses. */ if (h->ip.s_addr == htonl(0x00000000) && h->mask.s_addr == htonl(0x00000000)) return 1; + #ifdef SUPPORT_IPV6 + } + #endif /* s is S5NAME but IP is not mapped... */ if ((!s || s->sa.sa_family == AF_S5NAME) && !h->resolve) return 0; *************** *** 736,741 **** --- 990,1017 ---- return 0; } + #ifdef SUPPORT_IPV6 + if ((s->sa.sa_family == AF_INET && h->type == IN6_ADDR) || + (s->sa.sa_family == AF_INET6 && h->type == IN_ADDR)) return 0; + + if (s->sa.sa_family == AF_INET6) { + char tmp1[INET6_ADDRSTRLEN], tmp2[INET6_ADDRSTRLEN]; + + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(5), 0, + "Check: Checking address prefix (%s/%d == %s/%d)?", + inet_ntop(AF_INET6, &s->sin6.sin6_addr, tmp1, + sizeof(tmp1)), + h->prefixlen, + inet_ntop(AF_INET6, &h->ip6, tmp2, sizeof(tmp2)), + h->prefixlen); + if(EqualPrefix(&s->sin6.sin6_addr, &h->ip6, h->prefixlen)) { + return 1; + } + for (i = 0; i < h->ip6cnt; i++) { + if (!memcmp(&h->back6[i], &s->sin6.sin6_addr, sizeof(struct in6_addr))) return 1; + } + } else { + #endif /* s is AF_INET... */ if (s->sin.sin_addr.s_addr != INADDR_ANY) addr = s->sin.sin_addr; else addr.s_addr = (name)?inet_addr((char *)name):INVALIDADDR; *************** *** 747,752 **** --- 1023,1031 ---- if (h->back[i].s_addr == addr.s_addr) return 1; } + #ifdef SUPPORT_IPV6 + } + #endif /* last possibility, the name maches... */ if (name && h->resolve) { if (!strcmp(h->name, name)) return 1; *************** *** 762,767 **** --- 1041,1053 ---- /* The name was stored, not the address => compare names. */ /* If we stored a backup address, check and see if it matches... */ if (h->resolve) { + #ifdef SUPPORT_IPV6 + if (s && s->sa.sa_family == AF_INET6) { + for (i = 0; i < h->ip6cnt; i++) { + if (!memcmp(&h->back6[i], &s->sin6.sin6_addr, sizeof(struct in6_addr))) return 1; + } + } + #endif if (s && s->sa.sa_family == AF_INET && s->sin.sin_addr.s_addr != INADDR_ANY) addr = s->sin.sin_addr; else addr.s_addr = (name)?inet_addr((char *)name):INVALIDADDR; *************** *** 772,782 **** --- 1058,1076 ---- if (s && s->sa.sa_family == AF_S5NAME) strcpy(tmp, s->sn.sn_name); else if (name) strcpy(tmp, name); + #ifdef SUPPORT_IPV6 + else if (s && (s->sa.sa_family == AF_INET || s->sa.sa_family == AF_INET6)) { + #else else if (s && s->sa.sa_family == AF_INET) { + #endif struct hostent *hp = NULL; MUTEX_LOCK(gh_mutex); + #ifdef SUPPORT_IPV6 + if (!(hp = gethostbyaddr((char *)&s->sin.sin_addr.s_addr, sizeof(struct in_addr), s->sa.sa_family))) { + #else if (!(hp = gethostbyaddr((char *)&s->sin.sin_addr.s_addr, sizeof(struct in_addr), AF_INET))) { + #endif MUTEX_UNLOCK(gh_mutex); return 0; } *************** *** 909,914 **** --- 1203,1226 ---- *sizep = 0; + #ifdef ALLOW_MULTIPLE_CONFIG + if (strchr(filename, ':') != NULL) { + char *copy = strdup(filename), *p, *q; + + for (p = copy, q = strchr(p, ':'); + p != NULL; + p = (q == NULL) ? NULL : (q + 1)) { + if (q != NULL) *q = '\0'; + while ((fd = open(p, O_RDONLY)) < 0 && errno == EINTR); + if (fd >= 0) { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, + "Config: %s is selected", p); + break; + } + } + free(copy); + } else + #endif while ((fd = open(filename, O_RDONLY)) < 0 && errno == EINTR); if (fd < 0) { *************** *** 1007,1018 **** --- 1319,1452 ---- return rval; } + #ifdef SUPPORT_IPV6 + void lsRefreshIntfcAddr6(struct intfc *ifc) { + #ifdef KAME + int s; + struct ifconf conf; + struct ifreq ibuf[1024]; + struct ifreq *rq, *rq_top, *rq_end; + int rq_sz; + int remain; + int naddrs; + + if (ifc->addr6list != NULL) { + free(ifc->addr6list); + ifc->addr6list = NULL; + } + ifc->addr6cnt = 0; + + if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, + "Interface Query: socket (INET6): %m"); + return; + } + + /* Get interface configuration. */ + memset(ibuf, 0, sizeof(ibuf)); + conf.ifc_len = sizeof(ibuf); + conf.ifc_buf = (caddr_t)ibuf; + if (ioctl(s, SIOCGIFCONF, (char *)&conf) < 0) { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, + "Interface Query: SIOCGIFCONF: %m"); + goto done; + } + + #define RQ(rq, off) ((struct ifreq *)((char *)(rq) + off)) + #define RQ_SZ(rq) \ + (sizeof(struct ifreq) + \ + ((rq)->ifr_addr.sa_len > sizeof((rq)->ifr_addr) ? \ + ((rq)->ifr_addr.sa_len - sizeof((rq)->ifr_addr)) : 0)) + #define RQ_NEXT(rq) RQ(rq, RQ_SZ(rq)) + + /* Pass 1: count the number of IPv6 addresses assigned to the interface. */ + for (rq = ibuf, remain = conf.ifc_len, naddrs = 0, rq_top = rq_end = NULL; + remain >= sizeof(struct ifreq); + rq_sz = RQ_SZ(rq), rq = RQ(rq, rq_sz), remain -= rq_sz) { + if (!strcmp(ifc->name, rq->ifr_name)) { + if (rq_top == NULL) rq_top = rq; + if (rq->ifr_addr.sa_family == AF_INET6) naddrs++; + } else if (rq_top != NULL) { + rq_end = rq; + break; + } + } + if (naddrs == 0) goto done; + + /* Allocate memory. */ + ifc->addr6cnt = naddrs; + ifc->addr6list = (struct intaddr6 *)malloc(naddrs * sizeof(struct intaddr6)); + + /* Pass 2: retrieve address and prefix pairs. */ + for (rq = rq_top, naddrs = 0; rq < rq_end; rq = RQ_NEXT(rq)) { + if (rq->ifr_addr.sa_family == AF_INET6) { + struct in6_ifreq ifr6; + struct sockaddr_in6 *sin6; + unsigned char *p; + int prefix; + int i, j; + char tmp[INET6_ADDRSTRLEN]; + + sin6 = (struct sockaddr_in6 *)&rq->ifr_addr; + ifc->addr6list[naddrs].ip = sin6->sin6_addr; + + /* Get associated prefix mask. */ + strcpy(ifr6.ifr_name, ifc->name); + memcpy(&ifr6.ifr_addr, sin6, sizeof(*sin6)); + if (ioctl(s, SIOCGIFNETMASK_IN6, (char *)&ifr6) < 0) { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, + "Interface Query: SIOCGIFNETMASK_IN6 for %s: %m", + ifc->name); + ifc->addr6cnt = naddrs; + goto done; + } + + /* Compute prefix length. */ + p = (unsigned char *)&ifr6.ifr_addr.sin6_addr; + for (i = prefix = 0; i < 16; i++, prefix += 8) { + if (p[i] != 255) { + for (j = 7; j > 0 && p[i] & (1 << j); j--, prefix++) + ; + break; + } + } + ifc->addr6list[naddrs].prefixlen = prefix; + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, + "Interface Query: %s IPv6 addr/prefix is %s/%d", + ifc->name, + inet_ntop(AF_INET6, &ifc->addr6list[naddrs].ip, + tmp, sizeof(tmp)), prefix); + naddrs++; + } + } + + done: + CLOSESOCKET(s); + #undef RQ + #undef RQ_SZ + #undef RQ_NEXT + #endif + } + + static void RefreshIntfcAddr6(struct intfc *ifcs, int nifcs) { + int i; + + for (i = 0; i < nifcs; i++) { + lsRefreshIntfcAddr6(&ifcs[i]); + } + } + #endif + /* Get a list of valid interfaces... */ void lsSetupIntfcs(struct intfc **intfc, int *cnt) { #ifdef HAVE_GETIFADDRS struct ifaddrs *ifp, *ibuf = NULL; #else struct ifreq ibuf[1024]; + #ifdef SUPPORT_IPV6 + struct ifreq *ifrq, *ifrq_next, *ifrq_end; + struct ifreq itmp; + #endif struct ifconf ifc; S5IOHandle s; #endif *************** *** 1022,1028 **** --- 1456,1478 ---- char tmpname[16]; int i, j, k, m, n; + #ifdef SUPPORT_IPV6 + #ifdef SIN6_LEN + #define IFREQ_NEXT(x) \ + (((x)->ifr_addr.sa_len <= sizeof(struct sockaddr)) ? \ + ((x) + 1) : \ + ((struct ifreq *)((char *)((x)+1)+(x)->ifr_addr.sa_len-sizeof(struct sockaddr)))) + #else + #define IFREQ_NEXT(x) ((x) + 1) + #endif + #endif /* SUPPORT_IPV6 */ + if (*intfc) { + #ifdef SUPPORT_IPV6 + for (i = 0; i < *cnt; i++) { + if (intfc[i]->addr6list) free(intfc[i]->addr6list); + } + #endif if (intfc[0]->addrlist) free(intfc[0]->addrlist); free(*intfc); *intfc = NULL; *************** *** 1054,1061 **** --- 1504,1516 ---- return; } + #ifdef SUPPORT_IPV6 + ifrq_end = (struct ifreq *)((char *)ibuf + ifc.ifc_len); + if (ifc.ifc_len > 0) strcpy(tmpname, ibuf[0].ifr_name); + #else n = ifc.ifc_len/sizeof(struct ifreq); if (n > 0) strcpy(tmpname, ibuf[0].ifr_name); + #endif /* SUPPORT_IPV6 */ #endif /* Walk through the list and count the interfaces that are configured */ *************** *** 1083,1088 **** --- 1538,1557 ---- } if (n) j++; #else + #ifdef SUPPORT_IPV6 + for (ifrq = ibuf; ifrq < ifrq_end; ifrq = IFREQ_NEXT(ifrq)) { + if (strcmp(tmpname, ifrq->ifr_name)) { + j++; + strcpy(tmpname, ifrq->ifr_name); + } + + if (ifrq->ifr_addr.sa_family != AF_INET) continue; + if (k > 0 && tmpaddr.s_addr == ifssi((*ifrq))->sin_addr.s_addr) continue; + + tmpaddr.s_addr = ifssi((*ifrq))->sin_addr.s_addr; + k++; + } + #else for (; i < n; i++) { if (strcmp(tmpname, ibuf[i].ifr_name)) { j++; *************** *** 1096,1101 **** --- 1565,1571 ---- tmpaddr.s_addr = ifssi(ibuf[i])->sin_addr.s_addr; k++; } + #endif /* SUPPORT_IPV6 */ j++; #endif *************** *** 1158,1163 **** --- 1628,1671 ---- free(ibuf); #else + #ifdef SUPPORT_IPV6 + strcpy(pintfc[j].name, ibuf[0].ifr_name); + strncpy(itmp.ifr_name, ibuf[0].ifr_name, sizeof(itmp.ifr_name)); + pintfc[j].up = lsLookupIntfc(s, NET_STAT, &itmp); + pintfc[j].type = lsLookupIntfc(s, NET_TYPE, &itmp); + pintfc[j].addrlist = &pintaddr[k]; + pintfc[j].addrcnt = 0; + m = 0; + + for (ifrq = ibuf; ifrq < ifrq_end; ifrq = ifrq_next) { + ifrq_next = IFREQ_NEXT(ifrq); + if (strcmp(pintfc[j].name, ifrq->ifr_name)) { + pintfc[j].addrcnt = m; + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Interface Query: if%d is %s(%d) with %d IPs", j, pintfc[j].name, pintfc[j].up, m); + j++; + strcpy(pintfc[j].name, ifrq->ifr_name); + strncpy(itmp.ifr_name, ifrq->ifr_name, sizeof(itmp.ifr_name)); + pintfc[j].up = lsLookupIntfc(s, NET_STAT, &itmp); + pintfc[j].type = lsLookupIntfc(s, NET_TYPE, &itmp); + pintfc[j].addrlist = &pintaddr[k]; + pintfc[j].addrcnt = 0; + m = 0; + } + + if (lsLookupIntfc(s, NET_ADDR, &itmp) < 0) continue; + if (ifssi(itmp)->sin_family != AF_INET) continue; + if (k > 0 && pintaddr[k-1].ip.s_addr == ifssi(itmp)->sin_addr.s_addr) continue; + + pintaddr[k].ip.s_addr = ifssi(itmp)->sin_addr.s_addr; + if (lsLookupIntfc(s, NET_MASK, &itmp) >= 0) { + pintaddr[k].net.s_addr = ifssi(itmp)->sin_addr.s_addr; + } else pintaddr[k].net.s_addr = 0xffffffff; + + m++; k++; + + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Interface Query: if%d addr/mask is %08x:%08x", j, pintaddr[k-1].ip.s_addr, pintaddr[k-1].net.s_addr); + } + #else /* SUPPORT_IPV6 */ strcpy(pintfc[j].name, ibuf[i].ifr_name); pintfc[j].up = lsLookupIntfc(s, NET_STAT, &ibuf[i]); pintfc[j].type = lsLookupIntfc(s, NET_TYPE, &ibuf[i]); *************** *** 1191,1196 **** --- 1699,1705 ---- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Interface Query: if%d addr/mask is %08x:%08x", j, pintaddr[k-1].ip.s_addr, pintaddr[k-1].net.s_addr); } + #endif /* SUPPORT_IPV6 */ pintfc[j].addrcnt = m; S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Interface Query: if%d is %s(%d) with %d IPs", j, pintfc[j].name, pintfc[j].up, m); *************** *** 1198,1203 **** --- 1707,1715 ---- *cnt = ++j; *intfc = pintfc; + #ifdef SUPPORT_IPV6 + RefreshIntfcAddr6(pintfc, j); + #endif CLOSESOCKET(s); #endif } Index: lib/confutil.h diff -c src/socks5/lib/confutil.h:1.1.1.4 src/socks5/lib/confutil.h:1.6.2.2 *** lib/confutil.h Thu Aug 5 13:21:00 1999 --- lib/confutil.h Thu Aug 5 17:50:48 1999 *************** *** 44,64 **** --- 44,76 ---- #define IN_ADDR 0 /* is the type for address */ #define IN_PORT 0 /* is the type d_port (is it a port range?) */ #define NAME 1 /* is the type for name */ + #ifdef SUPPORT_IPV6 + #define IN6_ADDR 2 /* is the type for IPv6 address */ + #endif /* a struct telling us how the address is stored...(for matching). It can be */ /* stred as an ip address and mask (type = IN_ADDR) or as a string/substring */ /* (type = NAME). */ + /* IPv6: or ipv6 address and prefix length (type = IN6_ADDR). */ struct host { char type; char resolve; struct in_addr ip; struct in_addr mask; + #ifdef SUPPORT_IPV6 + struct in6_addr ip6; + int prefixlen; + #endif char name[S5_HOSTNAME_SIZE]; int length; char aliases[S5_HOSTALIASES_NUM][S5_HOSTNAME_SIZE]; int aliascnt; struct in_addr back[S5_HOSTIP_NUM]; int ipcnt; + #ifdef SUPPORT_IPV6 + struct in6_addr back6[S5_HOSTIP_NUM]; + int ip6cnt; + #endif }; /* a struct telling us how the service is stored...(for matching). It can be */ *************** *** 75,80 **** --- 87,100 ---- struct in_addr net; }; + #ifdef SUPPORT_IPV6 + /* a structure contains interface's IPv6 address and prefix length */ + struct intaddr6 { + struct in6_addr ip; + int prefixlen; + }; + #endif + /* a structure contains interfaces' information */ struct intfc { char name[16]; *************** *** 82,87 **** --- 102,111 ---- int up; int addrcnt; struct intaddr *addrlist; + #ifdef SUPPORT_IPV6 + int addr6cnt; + struct intaddr6 *addr6list; + #endif }; /* macros for using struct port...they hide the union-ness of it all.... */ *************** *** 142,147 **** --- 166,177 ---- extern int lsLookupIntfc P((S5IOHandle, int, struct ifreq *ifr)); extern void lsReadConfig P((const char *, struct confid *, int)); + + #ifdef SUPPORT_IPV6 + extern char *lsExtractEnclosedAddr P((char *, char *)); + extern int lsCheckIfc6 P((const struct intaddr6 *, const struct in6_addr *)); + extern void lsRefreshIntfcAddr6 P((struct intfc *)); + #endif extern int lsLineNo; Index: lib/hostname.c diff -c src/socks5/lib/hostname.c:1.1.1.5 src/socks5/lib/hostname.c:1.11.2.7 *** lib/hostname.c Thu Aug 5 13:20:59 1999 --- lib/hostname.c Thu Aug 5 17:50:48 1999 *************** *** 13,18 **** --- 13,25 ---- #include "addr.h" #include "wrap.h" #include "log.h" + #ifdef HAVE_ARPA_NAMESER_H + /* some version of resolv.h requires arpa/nameser.h. */ + #include + #endif + #ifdef HAVE_RESOLV_H + #include + #endif #define S5_HOSTLIST_SIZE 256 #define S5_HOSTALIASES_SIZE 16 *************** *** 28,39 **** --- 35,101 ---- static int fd = 0; /* local array of host address list and aliases list */ + #ifdef SUPPORT_IPV6 + /* IPv6: host_addr must be big enough to hold IPv6 addresses. */ + static struct in6_addr host_addr[S5_HOSTLIST_SIZE]; + #else static struct in_addr host_addr[S5_HOSTLIST_SIZE]; + #endif static char host_aliases[S5_HOSTALIASES_SIZE][S5_HOSTNAME_SIZE]; /* The address of unresolved host will be of the format "0.0.0.i", where i */ /* ranges from 1 to 254, pretty simple... */ #define FAKEPREFIX "0.0.0." + #ifdef SUPPORT_IPV6 + /* IPv6: For IPv6, use the format "100::0.0.0.i", which is currently not */ + /* IPv6: assigned. Most simple format would be "::0.0.0.i", but it's a bad */ + /* IPv6: choice since "::1" is a loopback. */ + #define FAKEPREFIX_IPV6 "100::" + #define FAKEPREFIX_IPV6_MAPPED "::FFFF:0.0.0.0" + static struct in6_addr sin6_fake_prefix; + static struct in6_addr sin6_mapped_fake_prefix; + #endif + + #ifdef SUPPORT_IPV6 + #define FAKE_ENTRY_BUF_SZ 100 + static void *fake_entry_buf[FAKE_ENTRY_BUF_SZ]; + static void **fake_entry_addrs = fake_entry_buf; + static int fake_entries; + static int fake_entry_size = FAKE_ENTRY_BUF_SZ; + + /* Remember that addr points to a fake entry. */ + static void RegisterFakeEntry(void *addr) { + if (fake_entries >= fake_entry_size) { + int sz; + fake_entry_size += FAKE_ENTRY_BUF_SZ; + sz = fake_entry_size * sizeof(void *); + if (fake_entry_addrs == fake_entry_buf) { + fake_entry_addrs = (void **)malloc(sz); + memcpy(fake_entry_addrs, fake_entry_buf, sizeof(fake_entry_buf)); + } else { + fake_entry_addrs = (void **)realloc(fake_entry_addrs, sz); + } + } + fake_entry_addrs[fake_entries++] = addr; + } + + /* Unregister addr if it points to a fake entry. */ + static int UnregisterFakeEntry(void *addr) { + int i; + for (i = 0; i < fake_entries; i++) { + if (fake_entry_addrs[i] == addr) { + if (fake_entries - i - 1 > 0) { + memmove(&fake_entry_addrs[i], &fake_entry_addrs[i + 1], + (fake_entries - i - 1) * sizeof(void *)); + } + fake_entries--; + return 1; + } + } + /* Not a fake entry */ + return 0; + } + #endif static int SetReadLock(int lock) { struct flock locks; *************** *** 123,128 **** --- 185,195 ---- } } + #ifdef SUPPORT_IPV6 + /* IPv6: Initialize fake address prefix. */ + inet_pton(AF_INET6, FAKEPREFIX_IPV6, &sin6_fake_prefix); + inet_pton(AF_INET6, FAKEPREFIX_IPV6_MAPPED, &sin6_mapped_fake_prefix); + #endif inited = 1; return 0; } *************** *** 220,231 **** --- 287,355 ---- for (i = 0; i < S5_HOSTLIST_SIZE; i++) { if (h->h_addr_list[i] == NULL) break; + #ifdef SUPPORT_IPV6 + memcpy((char *)&host_addr[i], h->h_addr_list[i], h->h_length); + addr_list[i] = (struct in_addr *)&host_addr[i]; + #else memcpy((char *)&host_addr[i], h->h_addr_list[i], sizeof(struct in_addr)); addr_list[i] = &host_addr[i]; + #endif } addr_list[i] = NULL; } + #ifdef SUPPORT_IPV6 + static struct in6_addr *MakeMappedAddress(struct in6_addr *ia6, const struct in_addr *ia) { + unsigned char *p = (unsigned char *)ia6; + + memset(p, 0, sizeof(struct in6_addr)); + p[10] = p[11] = 0xff; + memcpy(p + 12, ia, 4); + return ia6; + } + + #if defined(HAVE_GETNODEBYNAME) || defined(HAVE_GETIPNODEBYNAME) + static struct hostent *CreateFakeHostent(int af, const char *name, int idx) { + struct hostent *hp; + struct hostent_dummy { + struct hostent h; + char *aliases[1]; + char *addr_list[2]; + struct in6_addr ia; + char name[1]; + } *hdp; + /* Allocate memory for struct hostent and associated data. */ + hdp = (struct hostent_dummy *)malloc(sizeof(struct hostent_dummy) + + strlen(name)); /* for h_name */ + if (hdp == NULL) return NULL; + + hp = (struct hostent *)hdp; + hp->h_name = hdp->name; + strcpy(hp->h_name, name); + hp->h_aliases = hdp->aliases; + hp->h_aliases[0] = NULL; + hp->h_addrtype = af; + hp->h_addr_list = hdp->addr_list; + hp->h_addr_list[0] = (char *)(&hdp->ia); + memset(hp->h_addr_list[0], 0, sizeof(struct in6_addr)); + hp->h_addr_list[1] = NULL; + + if (af == AF_INET) { + struct in_addr *sin = (struct in_addr *)hp->h_addr_list[0]; + sin->s_addr = htonl(idx); + hp->h_length = sizeof(struct in_addr); + } else { /* AF_INET6 */ + struct in6_addr *sin6 = (struct in6_addr *)hp->h_addr_list[0]; + *sin6 = sin6_fake_prefix; + sin6->s6_addr[15] = idx; + hp->h_length = sizeof(struct in6_addr); + } + RegisterFakeEntry((void *)hp); + return hp; + } + #endif + #endif + /* wrapper around the gethostbyname call. */ /* similar to gethostbyname() except for: */ /* *** if gethostbyname() fails, then it returns a pointer to a hostent */ *************** *** 236,241 **** --- 360,368 ---- /* returns a pointer to a gethostent structure on success; NULL on failure */ struct hostent *LIBPREFIX(gethostbyname)(const char *name) { static struct in_addr special_addr, *my_addr_list[S5_HOSTLIST_SIZE+1]; + #if defined(SUPPORT_IPV6) && defined(RES_USE_INET6) + static struct in6_addr special_addr6; + #endif static char my_name[MAXNAMELEN], *my_aliases[S5_HOSTALIASES_SIZE+1]; static struct hostent h; struct hostent *hp; *************** *** 304,309 **** --- 431,446 ---- h.h_aliases = my_aliases; h.h_addrtype = AF_INET; h.h_length = sizeof(struct in_addr); + #if defined(SUPPORT_IPV6) && defined(RES_USE_INET6) + if (!(_res.options & RES_INIT)) res_init(); + if (_res.options & RES_USE_INET6) { + h.h_addrtype = AF_INET6; + h.h_length = sizeof(struct in6_addr); + special_addr6 = sin6_fake_prefix; + special_addr6.s6_addr[15] = i; + my_addr_list[0] = (struct in_addr *)&special_addr6; + } + #endif h.h_addr_list = (char **)my_addr_list; S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "SOCKS gethostbyname: FAKE: %s", inet_ntoa(*(struct in_addr *)h.h_addr_list[0])); *************** *** 323,328 **** --- 460,468 ---- /* returns a pointer to a gethostent structure on success; NULL on failure */ struct hostent *LIBPREFIX(gethostbyname2)(const char *name, int af) { static struct in_addr special_addr, *my_addr_list[S5_HOSTLIST_SIZE+1]; + #ifdef SUPPORT_IPV6 + static struct in6_addr special_addr6; + #endif static char my_name[MAXNAMELEN], *my_aliases[S5_HOSTALIASES_SIZE+1]; static struct hostent h; struct hostent *hp; *************** *** 333,339 **** --- 473,483 ---- if (lsInRLDFunctions || lsInWrapFunction || lsInWrapHostname) return REAL(gethostbyname2)(name, af); #endif + #ifdef SUPPORT_IPV6 + if (af != AF_INET && af != AF_INET6) return REAL(gethostbyname2)(name, af); + #else if (af != AF_INET) return REAL(gethostbyname2)(name, af); + #endif lsInWrapFunction = 1; lsInWrapHostname = 1; *************** *** 344,350 **** --- 488,499 ---- local = getenv("SOCKS5_LOCALDNSONLY"); if (!fake && (hp = REAL(gethostbyname2)(name, af)) != NULL) { + #ifdef SUPPORT_IPV6 + char tmp[INET6_ADDRSTRLEN]; + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "SOCKS gethostbyname2: REAL: %s", inet_ntop(af, hp->h_addr, tmp, sizeof(tmp))); + #else S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "SOCKS gethostbyname2: REAL: %s", inet_ntoa(*(struct in_addr *)hp->h_addr)); + #endif hlen = MIN(strlen(hp->h_name)+1, sizeof(my_name)); strncpy(my_name, hp->h_name, hlen); *************** *** 368,374 **** if (local) { S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "SOCKS gethostbyname2: REAL: Fake not configured"); lsInWrapFunction = 0; ! lsInWrapHostname = 0; return NULL; } --- 517,523 ---- if (local) { S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "SOCKS gethostbyname2: REAL: Fake not configured"); lsInWrapFunction = 0; ! lsInWrapHostname = 0; return NULL; } *************** *** 384,398 **** strncpy(my_name, name, hlen); if (hlen == sizeof(my_name)) my_name[hlen-1] = '\0'; my_aliases[0] = NULL; ! special_addr.s_addr = htonl(i); my_addr_list[0] = &special_addr; my_addr_list[1] = NULL; h.h_name = my_name; h.h_aliases = my_aliases; h.h_addrtype = AF_INET; h.h_length = sizeof(struct in_addr); h.h_addr_list = (char **)my_addr_list; S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "SOCKS gethostbyname2: FAKE: %s", inet_ntoa(*(struct in_addr *)h.h_addr_list[0])); --- 533,570 ---- strncpy(my_name, name, hlen); if (hlen == sizeof(my_name)) my_name[hlen-1] = '\0'; my_aliases[0] = NULL; ! ! #ifdef SUPPORT_IPV6 ! if (af == AF_INET) { ! special_addr.s_addr = htonl(i); ! my_addr_list[0] = &special_addr; ! #ifdef RES_USE_INET6 ! if (!(_res.options & RES_INIT)) res_init(); ! if (_res.options & RES_USE_INET6) { ! af = AF_INET6; ! my_addr_list[0] = (struct in_addr *)MakeMappedAddress(&special_addr6, &special_addr); ! } ! #endif ! } else { /* AF_INET6 */ ! special_addr6 = sin6_fake_prefix; ! special_addr6.s6_addr[15] = i; ! my_addr_list[0] = (struct in_addr *)&special_addr6; ! } ! #else special_addr.s_addr = htonl(i); my_addr_list[0] = &special_addr; + #endif my_addr_list[1] = NULL; h.h_name = my_name; h.h_aliases = my_aliases; + #ifdef SUPPORT_IPV6 + h.h_addrtype = af; + h.h_length = (af == AF_INET) ? sizeof(struct in_addr) : sizeof(struct in6_addr); + #else h.h_addrtype = AF_INET; h.h_length = sizeof(struct in_addr); + #endif h.h_addr_list = (char **)my_addr_list; S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "SOCKS gethostbyname2: FAKE: %s", inet_ntoa(*(struct in_addr *)h.h_addr_list[0])); *************** *** 402,408 **** --- 574,1033 ---- } #endif + #ifdef SUPPORT_IPV6 + #ifdef HAVE_GETNODEBYNAME + /* wrapper around the getnodebyname, which is defined by the current IETF */ + /* draft . */ + /* similar to gethostbyname(). */ + struct hostent *LIBPREFIX(getnodebyname)(const char *name, int af, int flags) { + struct hostent *hp; + char *local, *fake; + int i; + char tmp[INET6_ADDRSTRLEN]; + + #ifdef FOR_SHARED_LIBRARY + if (lsInRLDFunctions || lsInWrapFunction || lsInWrapHostname) { + return REAL(getnodebyname)(name, af, flags); + } + #endif + if (af != AF_INET && af != AF_INET6) { + return REAL(getnodebyname)(name, af, flags); + } + + lsInWrapFunction = 1; + lsInWrapHostname = 1; + LIBPREFIX2(init)("libsocks5"); + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, + "SOCKS getnodebyname: looking up %s", name); + + fake = getenv("SOCKS5_FAKEALLHOSTS"); + local = getenv("SOCKS5_LOCALDNSONLY"); + + if (!fake && (hp = REAL(getnodebyname)(name, af, flags)) != NULL) { + char tmp[INET6_ADDRSTRLEN]; + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, + "SOCKS getnodebyname: REAL: %s", + inet_ntop(af, hp->h_addr, tmp, sizeof(tmp))); + lsInWrapFunction = 0; + lsInWrapHostname = 0; + return hp; + } + + /* If your DNS is the same as the socks server, don't fake a correct */ + /* lookup when you know it won't work... */ + if (local) { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "SOCKS getnodebyname: REAL: Fake not configured"); + lsInWrapFunction = 0; + lsInWrapHostname = 0; + return NULL; + } + + /* Fill in some UNRESOLVED values and let the daemon resolve it */ + if ((i = GetFakeHost(name)) <= 0) { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, + "SOCKS getnodebyname: Get fake host failed"); + lsInWrapFunction = 0; + lsInWrapHostname = 0; + return NULL; + } + + /* Create fake hostent */ + hp = CreateFakeHostent(af, name, i); + if (hp != NULL) { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, + "SOCKS getnodebyname: FAKE: %s", + inet_ntop(af, hp->h_addr_list[0], tmp, sizeof(tmp))); + } + lsInWrapFunction = 0; + lsInWrapHostname = 0; + return hp; + } + #endif + + #ifdef HAVE_GETIPNODEBYNAME + /* wrapper around the getipnodebyname, which is defined by IETF draft */ + /* . */ + struct hostent *LIBPREFIX(getipnodebyname)(const char *name, int af, int flags, int *err_num) { + struct hostent *hp; + char *local, *fake; + int i; + char tmp[INET6_ADDRSTRLEN]; + + #ifdef FOR_SHARED_LIBRARY + if (lsInRLDFunctions || lsInWrapFunction || lsInWrapHostname) { + return REAL(getipnodebyname)(name, af, flags, err_num); + } + #endif + if (af != AF_INET && af != AF_INET6) { + return REAL(getipnodebyname)(name, af, flags, err_num); + } + + lsInWrapFunction = 1; + lsInWrapHostname = 1; + LIBPREFIX2(init)("libsocks5"); + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, + "SOCKS getipnodebyname: looking up %s", name); + + fake = getenv("SOCKS5_FAKEALLHOSTS"); + local = getenv("SOCKS5_LOCALDNSONLY"); + + if (!fake && (hp = REAL(getipnodebyname)(name, af, flags, err_num)) != NULL) { + char tmp[INET6_ADDRSTRLEN]; + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, + "SOCKS getipnodebyname: REAL: %s", + inet_ntop(af, hp->h_addr, tmp, sizeof(tmp))); + lsInWrapFunction = 0; + lsInWrapHostname = 0; + return hp; + } + + /* If your DNS is the same as the socks server, don't fake a correct */ + /* lookup when you know it won't work... */ + if (local) { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "SOCKS getipnodebyname: REAL: Fake not configured"); + lsInWrapFunction = 0; + lsInWrapHostname = 0; + return NULL; + } + + /* Fill in some UNRESOLVED values and let the daemon resolve it */ + if ((i = GetFakeHost(name)) <= 0) { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, + "SOCKS getipnodebyname: Get fake host failed"); + lsInWrapFunction = 0; + lsInWrapHostname = 0; + return NULL; + } + + /* Create fake hostent */ + hp = CreateFakeHostent(af, name, i); + if (hp != NULL) { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, + "SOCKS getipnodebyname: FAKE: %s", + inet_ntop(af, hp->h_addr_list[0], tmp, sizeof(tmp))); + } + lsInWrapFunction = 0; + lsInWrapHostname = 0; + return hp; + } + #endif + + #ifdef HAVE_FREEHOSTENT + /* wrapper around the freehostent, which accompanies getnodebyname. */ + void LIBPREFIX(freehostent)(struct hostent *hp) { + #ifdef FOR_SHARED_LIBRARY + if (lsInRLDFunctions || lsInWrapFunction || lsInWrapHostname) { + REAL(freehostent)(hp); + return; + } + #endif + if (hp == NULL) return; + + lsInWrapFunction = 1; + lsInWrapHostname = 1; + LIBPREFIX2(init)("libsocks5"); + + /* If hp is a fake entry, it must be allocated by socks5 library, so we */ + /* must free it. Otherwise, let REAL(freehostent) do the job. */ + if (UnregisterFakeEntry((void *)hp)) { + free(hp); + } else { + REAL(freehostent)(hp); + } + + lsInWrapFunction = 0; + lsInWrapHostname = 0; + } + #endif + + #ifdef HAVE_GETADDRINFO + static struct addrinfo *create_fake_addrinfo(int family, int type, const char *name, int idx, int port, int *err) { + struct addrinfo *aip; + struct addrinfo_dummy { + struct addrinfo ai; + struct sockaddr_in6 sin6; + char name[1]; + } *adp; + int nlen = strlen(name); + int alen; + + *err = 0; + + if (family == PF_INET) { + alen = sizeof(struct sockaddr_in); + } else { + alen = sizeof(struct sockaddr_in6); + } + + if ((adp = (struct addrinfo_dummy *)malloc(sizeof(struct addrinfo_dummy) + nlen)) == NULL) { + *err = EAI_MEMORY; + return NULL; + } + memset(adp, 0, sizeof(*adp) + nlen); + aip = (struct addrinfo *)adp; + + aip->ai_flags = 0; /* should I set AI_CANONNAME? */ + aip->ai_family = family; + aip->ai_socktype = type; + aip->ai_protocol = (type == SOCK_STREAM) ? IPPROTO_TCP : + ((type == SOCK_DGRAM) ? IPPROTO_UDP : 0); + aip->ai_addrlen = alen; + aip->ai_canonname = adp->name; + strcpy(aip->ai_canonname, name); + aip->ai_addr = (struct sockaddr *)&adp->sin6; + aip->ai_next = NULL; + + if (family == PF_INET) { + struct sockaddr_in *sin = (struct sockaddr_in *)aip->ai_addr; + sin->sin_family = AF_INET; + sin->sin_addr.s_addr = htonl(idx); + sin->sin_port = port; + #ifdef SIN6_LEN + sin->sin_len = sizeof(struct sockaddr_in); + #endif + } else { /* PF_INET6 */ + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)aip->ai_addr; + sin6->sin6_family = AF_INET6; + sin6->sin6_addr = sin6_fake_prefix; + sin6->sin6_addr.s6_addr[15] = idx; + sin6->sin6_port = port; + #ifdef SIN6_LEN + sin6->sin6_len = sizeof(struct sockaddr_in6); + #endif + } + + RegisterFakeEntry((void *)aip); + return aip; + } + + static struct addrinfo *supply_fake_addrinfo(const char *nodename, struct addrinfo *real_info) { + struct addrinfo *aip, *last; + struct addrinfo *a4p, *a6p; + int idx; + int dummy; + int port; + int prefer_v4 = 0; + + /* Check if real_info contains IPv4/IPv6 address data */ + for (aip = real_info, a4p = a6p = last = NULL; + aip != NULL; + last = aip, aip = aip->ai_next) { + if (aip->ai_family == PF_INET) a4p = aip; + else if (aip->ai_family == PF_INET6) a6p = aip; + } + /* + * If both IPv4 and IPv6 addresses are provided, or neither of them + * are provided, do nothing. + */ + if ((a4p == NULL && a6p == NULL) || (a4p != NULL && a6p != NULL)) { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(20), 0, + "SOCKS getaddrinfo: % of v4/v6 addresses found", + a4p == NULL ? "neither" : "both"); + return real_info; + } + + /* Register to the fake address table. */ + if ((idx = GetFakeHost(nodename)) <= 0) return real_info; + + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, + "SOCKS getaddrinfo: supplying IPv%d address", + a4p ? 4 : 6); + + if (a4p != NULL && a6p == NULL) { + /* Only IPv4 address found. Append fake IPv6 entry. */ + port = ((struct sockaddr_in *)(a4p->ai_addr))->sin_port; + a6p = create_fake_addrinfo(PF_INET6, a4p->ai_socktype, nodename, idx, + port, &dummy); + if (a6p != NULL) last->ai_next = a6p; + } else { /* a4p == NULL && a6p != NULL */ + /* Only IPv6 address found. Append fake IPv4 entry. */ + port = ((struct sockaddr_in6 *)(a6p->ai_addr))->sin6_port; + a4p = create_fake_addrinfo(PF_INET, a6p->ai_socktype, nodename, idx, + port, &dummy); + if (a4p != NULL) last->ai_next = a4p; + } + return real_info; + } + + /* wrapper around the getaddrinfo call. */ + /* similar to gethostbyname(). */ + int LIBPREFIX(getaddrinfo)(const char *nodename, const char *servname, const struct addrinfo *hints, struct addrinfo **res) { + char *fake, *local; + int port = 0; + int r = 0; + int socktype = 0; + int i; + + #ifdef FOR_SHARED_LIBRARY + if (lsInRLDFunctions || lsInWrapFunction || lsInWrapHostname) { + return REAL(getaddrinfo)(nodename, servname, hints, res); + } + #endif + if (nodename == NULL || + (hints != NULL && hints->ai_family != PF_UNSPEC && + hints->ai_family != PF_INET && hints->ai_family != PF_INET6)) { + return REAL(getaddrinfo)(nodename, servname, hints, res); + } + + lsInWrapFunction = 1; + lsInWrapHostname = 1; + LIBPREFIX2(init)("libsocks5"); + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "SOCKS getaddrinfo: looking up %s", nodename); + + fake = getenv("SOCKS5_FAKEALLHOSTS"); + local = getenv("SOCKS5_LOCALDNSONLY"); + + if (!fake) { + if ((r = REAL(getaddrinfo)(nodename, servname, hints, res)) == 0) { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, + "SOCKS getaddrinfo: REAL: %s", + lsAddr2Ascii((S5NetAddr *)((*res)->ai_addr))); + if ((hints == NULL || hints->ai_family == PF_UNSPEC) && + getenv("SOCKS5_SUPPLYBOTHADDR") != NULL) { + *res = supply_fake_addrinfo(nodename, *res); + } + lsInWrapFunction = 0; + lsInWrapHostname = 0; + return r; + } else if (r != EAI_ADDRFAMILY && r != EAI_NODATA && r != EAI_FAIL) { + /* If getaddrinfo fails for a reason other than hostname lookup */ + /* failure, there's nothing we can do... */ + lsInWrapFunction = 0; + lsInWrapHostname = 0; + return r; + } + } + + /* If your DNS is the same as the socks server, don't fake a correct */ + /* lookup when you know it won't work... */ + if (local) { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, + "SOCKS getaddrinfo: REAL: Fake not configured"); + lsInWrapFunction = 0; + lsInWrapHostname = 0; + return NULL; + } + + if (servname != NULL) { + struct servent *svp; + char *term; + char *proto; + + socktype = (hints != NULL && hints->ai_socktype == SOCK_DGRAM) ? + SOCK_DGRAM : SOCK_STREAM; + if ((port = (int)strtol(servname, &term, 0)) > 0 && *term == '\0') { + port = htons(port); + } else { + proto = (socktype == SOCK_DGRAM) ? "udp" : "tcp"; + if ((svp = getservbyname(servname, proto)) == NULL) { + lsInWrapFunction = 0; + lsInWrapHostname = 0; + return EAI_NONAME; + } + port = svp->s_port; + } + } + + /* Fill in some UNRESOLVED values and let the daemon resolve it */ + if ((i = GetFakeHost(nodename)) <= 0) { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, + "SOCKS getaddrinfo: Get fake host failed"); + lsInWrapFunction = 0; + lsInWrapHostname = 0; + return (r == 0) ? EAI_FAIL : r; + } + + if (socktype == 0 && hints != NULL) { + socktype = hints->ai_socktype; + } + + if (hints == NULL || hints->ai_family == PF_UNSPEC) { + struct addrinfo *ai4p, *ai6p; + + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, + "SOCKS getaddrinfo: generating both IPv4/IPv6 addresses"); + ai4p = create_fake_addrinfo(PF_INET, socktype, nodename, i, port, &r); + if (ai4p == NULL) goto ret; + ai6p = create_fake_addrinfo(PF_INET6, socktype, nodename, i, port, &r); + if (ai6p == NULL) { + free(ai4p); + goto ret; + } + if (getenv("SOCKS5_PREFERIPV4")) { + ai4p->ai_next = ai6p; + *res = ai4p; + } else { + ai6p->ai_next = ai4p; + *res = ai6p; + } + } else { + struct addrinfo *aip; + + aip = create_fake_addrinfo(hints->ai_family, socktype, + nodename, i, port, &r); + if (aip == NULL) goto ret; + *res = aip; + } + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, + "SOCKS getaddrinfo: FAKE: %s", + lsAddr2Ascii((S5NetAddr *)((*res)->ai_addr))); + ret: + lsInWrapFunction = 0; + lsInWrapHostname = 0; + return r; + } + #endif + + #ifdef HAVE_FREEADDRINFO + /* wrapper around the freeaddrinfo call. */ + void LIBPREFIX(freeaddrinfo)(struct addrinfo *ai) { + struct addrinfo *ptr, *prev; + + #ifdef FOR_SHARED_LIBRARY + if (lsInRLDFunctions || lsInWrapFunction || lsInWrapHostname) { + REAL(freeaddrinfo)(ai); + return; + } + #endif + if (ai == NULL) return; + lsInWrapFunction = 1; + lsInWrapHostname = 1; + LIBPREFIX2(init)("libsocks5"); + + /* Scan through the list and remove fake entries. */ + for (ptr = ai, prev = NULL; ptr != NULL;) { + struct addrinfo *next = ptr->ai_next; + if (UnregisterFakeEntry((void *)ptr)) { + /* a fake entry */ + if (prev == NULL) { + ai = next; + } else { + prev->ai_next = next; + } + free(ptr); + ptr = next; + } else { + prev = ptr; + ptr = next; + } + } + + /* If there are any remaining entries, they must be true entries. */ + if (ai != NULL) { + REAL(freeaddrinfo)(ai); + } + + lsInWrapFunction = 0; + lsInWrapHostname = 0; + } + #endif + #endif + + #ifdef SUPPORT_IPV6 + int lsGetCachedAddress(const char *name, S5NetAddr *na, int af) { + #else int lsGetCachedAddress(const char *name, S5NetAddr *na) { + #endif int i; char hostname[S5_HOSTNAME_SIZE]; *************** *** 441,446 **** --- 1066,1082 ---- if (i < 256) { S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(20), 0, "lsGetCachedAddress: Faked host #%d, name is: %s", i, hostname); + #ifdef SUPPORT_IPV6 + if (af == AF_INET6) { + memset(&na->sin6, 0, sizeof(ssi6)); + na->sin6.sin6_family = AF_INET6; + na->sin6.sin6_port = 0; + na->sin6.sin6_flowinfo = 0; + na->sin6.sin6_addr = sin6_fake_prefix; + na->sin6.sin6_addr.s6_addr[15] = i; + return 0; + } + #endif memset(&na->sin, 0, sizeof(ssi)); na->sin.sin_family = AF_INET; na->sin.sin_port = 0; *************** *** 460,465 **** --- 1096,1115 ---- if (inited <= 0) return -1; if (!na || !hostname) return -1; + #ifdef SUPPORT_IPV6 + if (na->sa.sa_family == AF_INET6) { + if ((memcmp(&na->sin6.sin6_addr, &sin6_fake_prefix, 15) && + memcmp(&na->sin6.sin6_addr, &sin6_mapped_fake_prefix, 15)) || + (i = (int)na->sin6.sin6_addr.s6_addr[15]) > 255 || i < 1) { + char tmp[INET6_ADDRSTRLEN]; + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(20), 0, + "lsGetCachedHostname: Not a fake hostname: %s", + inet_ntop(AF_INET6, &na->sin6.sin6_addr, tmp, sizeof(tmp))); + return -1; + } + goto found; + } + #endif if (na->sin.sin_family != AF_INET) { S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(20), 0, "lsGetCachedHostname: Not a fake address, wrong address family: %d", na->sin.sin_family); return -1; *************** *** 470,475 **** --- 1120,1128 ---- return -1; } + #ifdef SUPPORT_IPV6 + found: + #endif if (fd > 0) { SetReadLock(1); lseek(fd, (i-1)*256+sizeof(int), SEEK_SET); Index: lib/hostname.h diff -c src/socks5/lib/hostname.h:1.1.1.3 src/socks5/lib/hostname.h:1.2.4.2 *** lib/hostname.h Thu Apr 1 11:04:13 1999 --- lib/hostname.h Wed Apr 7 14:35:54 1999 *************** *** 12,17 **** --- 12,21 ---- #define __HOSTNAME_H__ extern int lsGetCachedHostname P((const S5NetAddr *, char *, int)); + #ifdef SUPPORT_IPV6 + extern int lsGetCachedAddress P((const char *, S5NetAddr *, int)); + #else extern int lsGetCachedAddress P((const char *, S5NetAddr *)); + #endif #endif Index: lib/libproto.c diff -c src/socks5/lib/libproto.c:1.1.1.3 src/socks5/lib/libproto.c:1.7.4.2 *** lib/libproto.c Thu Apr 1 11:04:15 1999 --- lib/libproto.c Wed Apr 7 14:35:54 1999 *************** *** 67,78 **** --- 67,86 ---- /* Not sure when/if this is ever necessary during failed connects... */ /* XXX What to do in the nt case...where there's no dup? */ + #ifdef SUPPORT_IPV6 + static S5IOHandle Reset(S5IOHandle fd, int oaf, int otype, u_short port) { + #else static S5IOHandle Reset(S5IOHandle fd, int otype, u_short port) { + #endif S5NetAddr bndAddr; int len = sizeof(S5NetAddr), optval = 1; S5IOHandle nfd; + #ifdef SUPPORT_IPV6 + nfd = socket(oaf, otype, 0); + #else nfd = socket(AF_INET, otype, 0); + #endif if (nfd == S5InvalidIOHandle && port != INVALIDPORT) return nfd; if (fd != S5InvalidIOHandle && port != INVALIDPORT) { *************** *** 81,88 **** --- 89,104 ---- setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&optval, sizeof(int)); memset((char *)&bndAddr, 0, sizeof(S5NetAddr)); + #ifdef SUPPORT_IPV6 + bndAddr.sa.sa_family = oaf; + if (oaf == AF_INET6) + bndAddr.sin6.sin6_port = port; + else + bndAddr.sin.sin_port = port; + #else bndAddr.sa.sa_family = AF_INET; bndAddr.sin.sin_port = port; + #endif while ((fd = REAL(dup2)(nfd, fd)) < 0) { if (!ISSOCKETERROR(EINTR)) break; *************** *** 130,136 **** --- 146,156 ---- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsLibProtoExchg: rsin is (%s:%d)", ADDRANDPORT(rsin)); lsAddrCopy(&pcon->peer, rsin, lsAddrSize(rsin)); + #ifdef SUPPORT_IPV6 + if ((how = lsHowToConnect(rsin, command, &proxies, &nproxies, lsEffUser(), &dest, pcon->af)) == (u_char)-1) { + #else if ((how = lsHowToConnect(rsin, command, &proxies, &nproxies, lsEffUser(), &dest)) == (u_char)-1) { + #endif S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsProtoExchg: Authorization failed"); if (command != SOCKS_UDP) lsConnectionDel(fd); return NULL; *************** *** 168,177 **** --- 188,209 ---- memset((char *)&junk, 0 , sizeof(S5NetAddr)); if (REAL(getsockname)(fd, &junk.sa, &len) == 0) port = lsAddr2Port(&junk); + #ifdef SUPPORT_IPV6 + } else if ((cfd = socket(pcon->af, SOCK_STREAM, 0)) == S5InvalidIOHandle) return NULL; + #else } else if ((cfd = socket(AF_INET, SOCK_STREAM, 0)) == S5InvalidIOHandle) return NULL; + #endif /* Then we connect to proxy server now... */ for (i = 0; i < nproxies; i++) { + #ifdef SUPPORT_IPV6 + /* IPv6: Check if the IP version of the proxy matches the socket's */ + /* IPv6: version. */ + if (proxies[i].sa.sa_family != pcon->af) { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsLibProtoExchg: IP version mismatch."); + continue; + } + #endif S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsLibProtoExchg: Adding to proxy cache..."); if ((pri = lsProxyCacheAdd(pcon, &proxies[i], how)) == NULL) { *************** *** 186,192 **** --- 218,228 ---- if (!ISSOCKETERROR(EINPROGRESS) && !ISSOCKETERROR(EINTR) && !ISSOCKETERROR(EWOULDBLOCK)) { S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "Unable to connect to socks server: %s:%d: %m", ADDRANDPORT(&pri->prxyin)); lsProxyCacheDel(pcon, pri); + #ifdef SUPPORT_IPV6 + if ((cfd = Reset(cfd, pcon->af, SOCK_STREAM, port)) == S5InvalidIOHandle) goto error; + #else if ((cfd = Reset(cfd, SOCK_STREAM, port)) == S5InvalidIOHandle) goto error; + #endif continue; } *************** *** 215,221 **** --- 251,261 ---- if (connected) break; lsProxyCacheDel(pcon, pri); + #ifdef SUPPORT_IPV6 + if ((cfd = Reset(cfd, pcon->af, SOCK_STREAM, port)) == S5InvalidIOHandle) goto error; + #else if ((cfd = Reset(cfd, SOCK_STREAM, port)) == S5InvalidIOHandle) goto error; + #endif } else { connected = 1; break; *************** *** 248,257 **** --- 288,302 ---- if (command == SOCKS_UDP) { usectl = S5UDP_USECTRL; + len = sizeof(S5NetAddr); memset((char *)&junk, 0, sizeof(S5NetAddr)); if (REAL(getsockname)(fd, &junk.sa, &len) < 0 || lsAddr2Port(&junk) == 0) { + #ifdef SUPPORT_IPV6 + junk.sa.sa_family = pcon->af; + #else junk.sin.sin_family = AF_INET; + #endif if (REAL(bind)(fd, &junk.sa, lsAddrSize(&junk)) < 0) goto error; REAL(getsockname)(fd, &junk.sa, &len); } else pcon->myport = lsAddr2Port(&junk); *************** *** 259,264 **** --- 304,312 ---- REAL(getsockname)(cfd, &dest.sa, &len); lsAddrSetPort(&dest, lsAddr2Port(&junk)); } + #ifdef SUPPORT_IPV6 + if (pcon->handlev4v6 != V4V6_NO) usectl |= SOCKS5_FLAG_IPV4V6; + #endif if (lsProtoExchg(cfd, &pri->cinfo, &dest, lsEffUser(), pri->how, command, usectl) < 0) { S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsLibProtoExchg: lsProtoExchg Failed"); *************** *** 288,295 **** --- 336,350 ---- if (command != SOCKS_UDP) lsConnectionDel(fd); else { if (cfd != S5InvalidIOHandle) CLOSESOCKET(cfd); + #ifdef SUPPORT_IPV6 + if (pri != NULL) { + pri->cinfo.fd = S5InvalidIOHandle; + lsProxyCacheDel(pcon, pri); + } + #else pri->cinfo.fd = S5InvalidIOHandle; lsProxyCacheDel(pcon, pri); + #endif } return NULL; Index: lib/protocol.c diff -c src/socks5/lib/protocol.c:1.1.1.3 src/socks5/lib/protocol.c:1.5.4.2 *** lib/protocol.c Thu Apr 1 11:04:06 1999 --- lib/protocol.c Wed Apr 7 14:35:57 1999 *************** *** 93,99 **** case AF_S5NAME: if (version != SOCKS5_VERSION) return -1; return NAMEHDRSIZE(na->sn.sn_name); ! #ifdef HAVE_NETINET6_IN6_H case AF_INET6: if (version != SOCKS5_VERSION) return -1; return IPV6HDRSIZE; --- 93,99 ---- case AF_S5NAME: if (version != SOCKS5_VERSION) return -1; return NAMEHDRSIZE(na->sn.sn_name); ! #ifdef SUPPORT_IPV6 case AF_INET6: if (version != SOCKS5_VERSION) return -1; return IPV6HDRSIZE; *************** *** 118,127 **** return sizeof(u_short) + sizeof(struct in_addr); case SOCKS5_HOSTNAME: return sizeof(u_short) + (u_char)buf[RP_HOSTOFF] + 1; ! #ifdef HAVE_NETINET6_IN6_H case SOCKS5_IPV6ADDR: ! return sizeof(u_short) + sizeof(struct in_addr6); #endif default: return -1; } --- 118,131 ---- return sizeof(u_short) + sizeof(struct in_addr); case SOCKS5_HOSTNAME: return sizeof(u_short) + (u_char)buf[RP_HOSTOFF] + 1; ! #ifdef SUPPORT_IPV6 case SOCKS5_IPV6ADDR: ! return sizeof(u_short) + sizeof(struct in6_addr); #endif + #ifdef ID_KITAMURA_SOCKS_IPV6 + case SOCKS5_ADDRESSID: + return sizeof(u_short) + 4; + #endif default: return -1; } *************** *** 150,164 **** memcpy(&result->sin.sin_addr, buf+RP_HOSTOFF, sizeof(struct in_addr)); memcpy(&result->sin.sin_port, buf+RP_HOSTOFF + sizeof(struct in_addr), sizeof(u_short)); return 0; ! #ifdef HAVE_NETINET6_IN6_H case SOCKS5_IPV6ADDR: memset(result, 0, sizeof(ssi6)); #ifdef SIN6_LEN result->sin6.sin6_len = sizeof(struct sockaddr_in6); #endif result->sin6.sin6_family = AF_INET6; ! memcpy(&result->sin6.sin6_addr, buf+RP_HOSTOFF, sizeof(struct in_addr6)); ! memcpy(&result->sin6.sin6_port, buf+RP_HOSTOFF + sizeof(struct in_addr6), sizeof(u_short)); return 0; #endif default: --- 154,176 ---- memcpy(&result->sin.sin_addr, buf+RP_HOSTOFF, sizeof(struct in_addr)); memcpy(&result->sin.sin_port, buf+RP_HOSTOFF + sizeof(struct in_addr), sizeof(u_short)); return 0; ! #ifdef SUPPORT_IPV6 case SOCKS5_IPV6ADDR: memset(result, 0, sizeof(ssi6)); #ifdef SIN6_LEN result->sin6.sin6_len = sizeof(struct sockaddr_in6); #endif result->sin6.sin6_family = AF_INET6; ! memcpy(&result->sin6.sin6_addr, buf+RP_HOSTOFF, sizeof(struct in6_addr)); ! memcpy(&result->sin6.sin6_port, buf+RP_HOSTOFF + sizeof(struct in6_addr), sizeof(u_short)); ! return 0; ! #endif ! #ifdef ID_KITAMURA_SOCKS_IPV6 ! case SOCKS5_ADDRESSID: ! memset(result, 0, sizeof(struct sockaddr_id)); ! result->sa.sa_family = AF_S5ID; ! memcpy(&result->sid.sid_id, buf+RP_HOSTOFF, 4); ! memcpy(&result->sid.sid_port, buf+RP_HOSTOFF + 4, sizeof(u_short)); return 0; #endif default: *************** *** 187,197 **** memcpy(buf+RP_HOSTOFF, &name->sin.sin_addr, sizeof(struct in_addr)); memcpy(buf+RP_HOSTOFF + sizeof(struct in_addr), &name->sin.sin_port, sizeof(u_short)); return 0; ! #ifdef HAVE_NETINET6_IN6_H case AF_INET6: buf[RP_FLAGS] = SOCKS5_IPV6ADDR; ! memcpy(buf+RP_HOSTOFF, &name->sin6.sin6_addr, sizeof(struct in_addr6)); ! memcpy(buf+RP_HOSTOFF + sizeof(struct in_addr6), &name->sin6.sin6_port, sizeof(u_short)); return 0; #endif default: --- 199,209 ---- memcpy(buf+RP_HOSTOFF, &name->sin.sin_addr, sizeof(struct in_addr)); memcpy(buf+RP_HOSTOFF + sizeof(struct in_addr), &name->sin.sin_port, sizeof(u_short)); return 0; ! #ifdef SUPPORT_IPV6 case AF_INET6: buf[RP_FLAGS] = SOCKS5_IPV6ADDR; ! memcpy(buf+RP_HOSTOFF, &name->sin6.sin6_addr, sizeof(struct in6_addr)); ! memcpy(buf+RP_HOSTOFF + sizeof(struct in6_addr), &name->sin6.sin6_port, sizeof(u_short)); return 0; #endif default: *************** *** 270,275 **** --- 282,292 ---- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "Socks5: Invalid address passed from client"); return -1; } + #ifdef SUPPORT_IPV6 + /* IPv6: If the specified address is IPv6, try converting IPv4-mapped */ + /* IPv6: address to the normal IPv4 address. */ + if (peer->sa.sa_family == AF_INET6) lsMappedAddrConvert(peer, AF_INET); + #endif *cmd = (u_char)buf[RP_COMMAND]; *flags = (u_char)buf[RP_RESERVE]; Index: lib/rld.c diff -c src/socks5/lib/rld.c:1.1.1.6 src/socks5/lib/rld.c:1.7.2.6 *** lib/rld.c Thu Aug 5 13:20:57 1999 --- lib/rld.c Mon Aug 16 11:23:18 1999 *************** *** 41,46 **** --- 41,49 ---- #ifndef LIBDGC_NAME #define LIBDGC_NAME NULL #endif + #ifndef LIBINET6_NAME + #define LIBINET6_NAME NULL + #endif /* Lets hope we don't have to do this for too many OS's...Maybe configure */ /* should figure it out...? */ *************** *** 52,57 **** --- 55,64 ---- #define NO_RTLD_NEXT (1 << 4) #define USE_RTLD_GLOBAL (1 << 5) + #ifdef SUPPORT_IPV6 + #define TRY_LIBINET6 (1 << 6) + #endif + #ifdef FOR_SHARED_LIBRARY #define GETSYM(handle, libname, flags) \ *************** *** 131,136 **** --- 138,146 ---- } #endif + #ifdef SUPPORT_IPV6 + GETSYMHANDLE(TRY_LIBINET6, libinet6_handle, LIBINET6_NAME, "LIBINET6_NAME", RTLD_LAZY); + #endif GETSYMHANDLE(TRY_LIBRESOLV, libresolv_handle, LIBRESOLV_NAME, "LIBRESOLV_NAME", RTLD_LAZY); GETSYMHANDLE(TRY_LIBNSL, libnsl_handle, LIBNSL_NAME, "LIBNSL_NAME", RTLD_LAZY); GETSYMHANDLE(TRY_LIBSOCKET, libsocket_handle, LIBSOCKET_NAME, "LIBSOCKET_NAME", RTLD_LAZY); *************** *** 159,164 **** --- 169,177 ---- } #endif + #ifdef SUPPORT_IPV6 + DGETSYMHANDLE(TRY_LIBINET6, libinet6_handle, LIBINET6_NAME, "LIBINET6_NAME", RTLD_LAZY); + #endif DGETSYMHANDLE(TRY_LIBRESOLV, libresolv_handle, LIBRESOLV_NAME, "LIBRESOLV_NAME", RTLD_LAZY); DGETSYMHANDLE(TRY_LIBNSL, libnsl_handle, LIBNSL_NAME, "LIBNSL_NAME", RTLD_LAZY); DGETSYMHANDLE(TRY_LIBSOCKET, libsocket_handle, LIBSOCKET_NAME, "LIBSOCKET_NAME", RTLD_LAZY); *************** *** 189,195 **** --- 202,212 ---- static void *func = NULL; S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "RLD: gethostbyname2: %s:%d", name, af); + #ifdef SUPPORT_IPV6 + GetOriginalFunc(&func, "_gethostbyname2", TRY_LIBC | TRY_LIBNSL | TRY_LIBRESOLV | TRY_LIBINET6); + #else GetOriginalFunc(&func, "_gethostbyname2", TRY_LIBC | TRY_LIBNSL | TRY_LIBRESOLV); + #endif if (!func || func == (void *)-1) return NULL; lsInRLDFunctions = 1; *************** *** 198,203 **** --- 215,311 ---- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "RLD: gethostbyname2 results: %s %s", name, hp?hp->h_name:"???"); return hp; } + #endif + + #ifdef SUPPORT_IPV6 + #ifdef HAVE_GETNODEBYNAME + struct hostent *REAL(getnodebyname)(const char *name, int af, int flags) { + struct hostent *hp; + static void *func = NULL; + + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "RLD: getnodebyname: %s", name); + GetOriginalFunc(&func, "_getnodebyname", TRY_LIBC | TRY_LIBNSL | TRY_LIBRESOLV | TRY_LIBINET6); + if (!func || func == (void *)-1) return NULL; + + lsInRLDFunctions = 1; + hp = ((struct hostent *(*)P((const char *, int, int)))func)(name, af, flags); + lsInRLDFunctions = 0; + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "RLD: getnodebyname results: %s %s", name, hp?hp->h_name:"???"); + return hp; + } + #endif + + #ifdef HAVE_GETIPNODEBYNAME + struct hostent *REAL(getipnodebyname)(const char *name, int af, int flags, int *err_num) { + struct hostent *hp; + static void *func = NULL; + + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "RLD: getipnodebyname: %s", name); + GetOriginalFunc(&func, "_getipnodebyname", TRY_LIBC | TRY_LIBNSL | TRY_LIBRESOLV | TRY_LIBINET6); + if (!func || func == (void *)-1) return NULL; + + lsInRLDFunctions = 1; + hp = ((struct hostent *(*)P((const char *, int, int, int*)))func)(name, af, flags, err_num); + lsInRLDFunctions = 0; + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "RLD: getipnodebyname results: %s %s", name, hp?hp->h_name:"???"); + return hp; + } + #endif + + #ifdef HAVE_FREEHOSTENT + void REAL(freehostent)(struct hostent *ptr) { + static void *func = NULL; + + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "RLD: freehostent"); + GetOriginalFunc(&func, "_freehostent", TRY_LIBC | TRY_LIBNSL | TRY_LIBRESOLV | TRY_LIBINET6); + if (!func || func == (void *)-1) return; + + lsInRLDFunctions = 1; + ((void (*)P((struct hostent *)))func)(ptr); + lsInRLDFunctions = 0; + } + #endif + + #ifdef HAVE_GETADDRINFO + int REAL(getaddrinfo)(const char *nodename, const char *servname, const struct addrinfo *hints, struct addrinfo **res) { + int r; + static void *func = NULL; + + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, + "RLD: getaddrinfo: %s %s", nodename ? nodename : "NULL", + servname ? servname : "NULL"); + GetOriginalFunc(&func, "_getaddrinfo", TRY_LIBC | TRY_LIBNSL | TRY_LIBRESOLV | TRY_LIBINET6); + if (!func || func == (void *)-1) return NULL; + + lsInRLDFunctions = 1; + r = ((int (*)P((const char *, const char *, const struct addrinfo *, struct addrinfo **)))func)(nodename, servname, hints, res); + lsInRLDFunctions = 0; + if (r == 0) { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, + "RLD: getaddrinfo results: %s %s", + nodename ? nodename : "NULL", (*res)->ai_canonname); + } else { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, + "RLD: getaddrinfo failed: %s %d", + nodename ? nodename : "NULL", r); + } + return r; + } + #endif + + #ifdef HAVE_FREEADDRINFO + void REAL(freeaddrinfo)(struct addrinfo *ai) { + static void *func = NULL; + + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "RLD: freeaddrinfo"); + GetOriginalFunc(&func, "_freeaddrinfo", TRY_LIBC | TRY_LIBNSL | TRY_LIBRESOLV | TRY_LIBINET6); + if (!func || func == (void *)-1) return; + + lsInRLDFunctions = 1; + ((void (*)P((struct addrinfo *)))func)(ai); + lsInRLDFunctions = 0; + } + #endif #endif int REAL(getpeername) (S5IOHandle sd, ss *sa, int *slen) { Index: lib/wrap.c diff -c src/socks5/lib/wrap.c:1.1.1.5 src/socks5/lib/wrap.c:1.3.2.3 *** lib/wrap.c Thu Aug 5 13:20:56 1999 --- lib/wrap.c Thu Aug 5 17:50:49 1999 *************** *** 65,70 **** --- 65,73 ---- /* wrapper around the connect system call. */ int LIBPREFIX(connect)(S5IOHandle sd, CONST ss *name, int namelen) { int rval; + #ifdef SUPPORT_IPV6 + struct sockaddr_in6 buf; + #endif #ifdef FOR_SHARED_LIBRARY if (lsInRLDFunctions || lsInWrapFunction) return REAL(connect)(sd, (ss *)name, namelen); *************** *** 72,77 **** --- 75,115 ---- lsInWrapFunction = 1; LIBPREFIX2(init)("libsocks5"); + + #if defined(SUPPORT_IPV6) && defined(SIN6_LEN) + /* The following change is not IPv6 specific. */ + if (name->sa_family == 0){ + /* Some old applications believe that that the first 2 bytes of */ + /* struct sockaddr is always sa_family. However, 4.4BSD-derived */ + /* systems have the definition: */ + /* struct sockaddr { u_char sa_len; u_char sa_family; ... } */ + /* So on little-endian machines, such applications stores address */ + /* family into sa_len instead of sa_family. The following code */ + /* saves this situation. You can find the fimilar treatment in */ + /* kern/uipc_syscalls.c of such systems. */ + + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(5), 0, + "connect: sa_family is 0"); + if (name->sa_len == AF_INET && namelen >= sizeof(struct sockaddr_in)) { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, + "connect: sa_family reset to AF_INET"); + memcpy(&buf, name, sizeof(struct sockaddr_in)); + buf.sin6_len = 0; + buf.sin6_family = AF_INET; + name = (struct sockaddr *)&buf; + namelen = sizeof(struct sockaddr_in); + } else if (name->sa_len == AF_INET6 && + namelen >= sizeof(struct sockaddr_in6)) { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, + "connect: sa_family reset to AF_INET6"); + memcpy(&buf, name, sizeof(struct sockaddr_in6)); + buf.sin6_len = 0; + buf.sin6_family = AF_INET6; + name = (struct sockaddr *)&buf; + namelen = sizeof(struct sockaddr_in6); + } + } + #endif switch (lsSocketType(sd, name)) { case SOCK_DGRAM: Index: lib/wrap.h diff -c src/socks5/lib/wrap.h:1.1.1.3 src/socks5/lib/wrap.h:1.4.2.1 *** lib/wrap.h Thu Apr 1 11:04:02 1999 --- lib/wrap.h Wed Apr 7 14:36:01 1999 *************** *** 49,54 **** --- 49,62 ---- lsProxyInfo *pri, *cur; /* proxies we used... */ S5NetAddr peer; /* bound address or connect... */ int serrno; /* stored error (from nbconnect) */ + #ifdef SUPPORT_IPV6 + int af; /* address family */ + int handlev4v6; /* whether application can handle both */ + /* IPv4 and IPv6 addresses */ + #define V4V6_NO 0 + #define V4V6_MAPPED 1 + #define V4V6_BOTH 2 + #endif struct socksinfo *next; /* next structure... */ }; Index: lib/wrap_tcp.c diff -c src/socks5/lib/wrap_tcp.c:1.1.1.5 src/socks5/lib/wrap_tcp.c:1.7.2.2 *** lib/wrap_tcp.c Thu Apr 1 11:04:19 1999 --- lib/wrap_tcp.c Wed Apr 7 14:36:01 1999 *************** *** 32,39 **** S5NetAddr na; memset((char *)&na, 0, sizeof(S5NetAddr)); ! #ifdef HAVE_NETINET6_IN6_H ! na.sin6.sin_family = AF_INET6; #else na.sin.sin_family = AF_INET; na.sin.sin_addr.s_addr = INADDR_ANY; --- 32,41 ---- S5NetAddr na; memset((char *)&na, 0, sizeof(S5NetAddr)); ! #if defined(SUPPORT_IPV6) && defined(RRESVPORT_IPV6) ! na.sin6.sin6_family = AF_INET6; ! na.sin6.sin6_flowinfo = 0; ! na.sin6.sin6_addr = in6addr_any; #else na.sin.sin_family = AF_INET; na.sin.sin_addr.s_addr = INADDR_ANY; *************** *** 168,180 **** S5IOHandle nsd; memset(&sa, 0, sizeof(sa)); ! sa.sa.sa_family = AF_INET; if (REAL(getsockname)(sd, (ss *)&sa, &ssasize) < 0) { SETSOCKETERROR(EBADF); return -1; } ! if ((nsd = socket(AF_INET, SOCK_STREAM, 0)) == S5InvalidIOHandle) { SETSOCKETERROR(EBADF); return -1; } --- 170,182 ---- S5IOHandle nsd; memset(&sa, 0, sizeof(sa)); ! /* sa.sa.sa_family = AF_INET; */ if (REAL(getsockname)(sd, (ss *)&sa, &ssasize) < 0) { SETSOCKETERROR(EBADF); return -1; } ! if ((nsd = socket(sa.sa.sa_family, SOCK_STREAM, 0)) == S5InvalidIOHandle) { SETSOCKETERROR(EBADF); return -1; } *************** *** 260,266 **** --- 262,278 ---- memset(&baddr, 0, sizeof(S5NetAddr)); lsAddrCopy(&baddr, (S5NetAddr *)name, namelen); if (lsAddr2Port(&baddr) != (u_short)0) { + #ifdef SUPPORT_IPV6 + if (lsAddrIsNull(&baddr)) { + if (baddr.sa.sa_family == AF_INET6) { + baddr.sin6.sin6_addr = in6addr_any; + } else { + baddr.sin.sin_addr.s_addr = INADDR_ANY; + } + } + #else if (lsAddrIsNull(&baddr)) baddr.sin.sin_addr.s_addr = INADDR_ANY; + #endif if (REAL(bind)(sd, &baddr.sa, lsAddrSize(&baddr)) < 0) { S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsTcpBind: Local bind failed %m"); *************** *** 350,360 **** --- 362,378 ---- } if (lsLastCon && lsLastCon->pri && lsLastCon->pri->how != DIRECT) { + #ifdef SUPPORT_IPV6 + int len = sizeof(rbind); + #else int len = sizeof(rbind.sa); + #endif int rport; memset(&rbind, 0, sizeof(rbind)); + #ifndef SUPPORT_IPV6 rbind.sin.sin_family = AF_INET; + #endif if (!REAL(getsockname)(lsLastCon->fd, &rbind.sa, &len)) { rport = (int)ntohs(lsAddr2Port(&rbind)); *************** *** 376,382 **** --- 394,404 ---- } memset(&rbind, 0, sizeof(rbind)); + #if defined(SUPPORT_IPV6) && defined(RRESVPORT_IPV6) + rbind.sin6.sin6_family = AF_INET6; + #else rbind.sin.sin_family = AF_INET; + #endif lsAddrSetPort(&rbind, (u_short)*port); lsAddrCopy(&pcon->peer, &rbind, lsAddrSize(&rbind)); *************** *** 445,452 **** --- 467,487 ---- } if (name) { + #ifdef SUPPORT_IPV6 + S5NetAddr tmp; + S5NetAddr *na = &pcon->pri->prxyout; + + if (pcon->handlev4v6 == V4V6_MAPPED && na->sa.sa_family == AF_INET) { + tmp = *na; + lsMappedAddrConvert(&tmp, AF_INET6); + na = &tmp; + } + *namelen = MIN(*namelen, lsAddrSize(na)); + lsAddrCopy((S5NetAddr *)name, na, *namelen); + #else *namelen = MIN(*namelen, lsAddrSize(&pcon->pri->prxyout)); lsAddrCopy((S5NetAddr *)name, &pcon->pri->prxyout, *namelen); + #endif } S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "SOCKS getsockname (fd: %d) %s:%d", sd, ADDRANDPORT(&pcon->pri->prxyout)); *************** *** 476,483 **** --- 511,531 ---- } if (name) { + #ifdef SUPPORT_IPV6 + S5NetAddr tmp; + S5NetAddr *na = &pcon->peer; + + if (pcon->handlev4v6 == V4V6_MAPPED && na->sa.sa_family == AF_INET) { + tmp = *na; + lsMappedAddrConvert(&tmp, AF_INET6); + na = &tmp; + } + *namelen = MIN(*namelen, lsAddrSize(na)); + lsAddrCopy((S5NetAddr *)name, na, *namelen); + #else *namelen = MIN(*namelen, lsAddrSize(&pcon->peer)); lsAddrCopy((S5NetAddr *)name, &pcon->peer, *namelen); + #endif } S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Getpeername (fd: %d) %s:%d", sd, ADDRANDPORT(&pcon->peer)); *************** *** 641,648 **** --- 689,709 ---- } if (from) { + #ifdef SUPPORT_IPV6 + S5NetAddr tmp; + S5NetAddr *na = &pcon->peer; + + if (pcon->handlev4v6 == V4V6_MAPPED && na->sa.sa_family == AF_INET) { + tmp = *na; + lsMappedAddrConvert(&tmp, AF_INET6); + na = &tmp; + } + *fromlen = MIN(*fromlen, lsAddrSize(na)); + lsAddrCopy((S5NetAddr *)from, na, *fromlen); + #else *fromlen = MIN(*fromlen, lsAddrSize(&pcon->peer)); lsAddrCopy((S5NetAddr *)from, &pcon->peer, *fromlen); + #endif } return lsTcpRecv(sd, msg, len, flags); Index: lib/wrap_udp.c diff -c src/socks5/lib/wrap_udp.c:1.1.1.5 src/socks5/lib/wrap_udp.c:1.8.2.2 *** lib/wrap_udp.c Thu Apr 1 11:04:17 1999 --- lib/wrap_udp.c Wed Apr 7 14:36:02 1999 *************** *** 88,100 **** --- 88,109 ---- } S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "SOCKS sendto: Sent %d byte msg to proxy %s:%d...", nlen, ADDRANDPORT(&pri->prxyin)); + #ifdef SUPPORT_IPV6 + rval = REAL(sendto)(fd, header, nlen, flags, (ss *)&pri->prxyin, + lsAddrSize(&pri->prxyin)); + #else rval = REAL(sendto)(fd, header, nlen, flags, (ss *)&pri->prxyin, sizeof(ssi)); + #endif return (rval == nlen)?len:-1; } /* extracts the header info from msg and fills in the appropriate fields... */ /* returns 0 on success and -1 on failure... */ + #ifdef SUPPORT_IPV6 + static int lsUdpExtractHeader(char *msg, int n, int *headerlen, ss *from, int fromlen, lsSocksInfo *pcon) { + #else static int lsUdpExtractHeader(char *msg, int n, int *headerlen, ss *from, int fromlen) { + #endif S5NetAddr netaddr; /* Here we make sure that we really go a valid message... */ *************** *** 114,122 **** --- 123,142 ---- /* it as... */ switch (netaddr.sa.sa_family) { case AF_S5NAME: + #ifdef SUPPORT_IPV6 + lsGetCachedAddress(netaddr.sn.sn_name, (S5NetAddr *)from, pcon->af); + #else lsGetCachedAddress(netaddr.sn.sn_name, (S5NetAddr *)from); + #endif lsAddrSetPort((S5NetAddr *)from, netaddr.sn.sn_port); break; + #ifdef SUPPORT_IPV6 + case AF_INET: + if (pcon->handlev4v6 == V4V6_MAPPED) { + lsMappedAddrConvert(&netaddr, AF_INET6); + } + /* fall through */ + #endif default: lsAddrCopy((S5NetAddr *)from, &netaddr, fromlen); break; *************** *** 152,158 **** --- 172,182 ---- } /* If we're already talking to the right person, we're done... */ + #ifdef SUPPORT_IPV6 + if (pcon && !lsAddrComp((S5NetAddr *)name, &pcon->peer)) return 0; + #else if (pcon && ADDRCOMP((ssi *)name, &pcon->peer.sin)) return 0; + #endif } /* Make a connection since one didn't exit... or qthe address was wrong */ *************** *** 215,224 **** --- 239,255 ---- return REAL(bind)(sd, (ss *)name, namelen); } + #ifdef SUPPORT_IPV6 + if (lsAddr2Port((S5NetAddr *)name) != (u_short)0) { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsUdpBind: bind local to %d", (int)lsAddr2Port((S5NetAddr *)name)); + if (REAL(bind)(sd, (ss *)name, namelen) < 0) return -1; + } + #else if (((ssi *)name)->sin_port != (u_short)0) { S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsUdpBind: bind local to %d", (int)((ssi *)name)->sin_port); if (REAL(bind)(sd, (ss *)name, namelen) < 0) return -1; } + #endif if (proxy_bind(sd, &lsLastCon->peer) < 0) { if (pcon && pcon->pri) lsProxyCacheDel(pcon, pcon->pri); *************** *** 272,278 **** --- 303,313 ---- /* only ok to sendto() the person we're connected to... */ if (pcon && (pcon->status == CON_ESTABLISHED || pcon->status == CON_ESTABLISHEDSEND)) { + #ifdef SUPPORT_IPV6 + if (lsAddrComp((S5NetAddr *)to, &pcon->peer)) { + #else if (!ADDRCOMP((ssi *)to, &pcon->peer.sin)) { + #endif memset(&bp, 0 , sizeof(S5NetAddr)); lsAddrCopy(&bp, &pcon->peer, lsAddrSize(&pcon->peer)); bs = pcon->status; *************** *** 304,312 **** --- 339,355 ---- IORETTYPE lsUdpRecvfrom(S5IOHandle s, IOPTRTYPE msg, IOLENTYPE len, int flags, ss *from, int *fromlen, int isRecv) { lsSocksInfo *pcon = lsConnectionFind(s); char recvbuf[UDP_MAX_PAYLOAD+1], *obuf = NULL; + #ifdef SUPPORT_IPV6 + int olen = 0, oset, fl = sizeof(S5NetAddr); + #else int olen = 0, oset, fl = sizeof(ssi); + #endif lsProxyInfo *pri; + #ifdef SUPPORT_IPV6 + S5NetAddr tmp; + #else ssi tmp; + #endif S5Packet buf[2]; if (!isRecv) { *************** *** 358,364 **** --- 401,411 ---- return -1; } + #ifdef SUPPORT_IPV6 + if (lsAddrComp(&pri->prxyin, (S5NetAddr *)from)) { + #else if (!ADDRCOMP(&pri->prxyin.sin, (ssi *)from)) { + #endif S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Recv from wrong host"); return -1; } *************** *** 380,386 **** --- 427,437 ---- olen = buf[1].len; } + #ifdef SUPPORT_IPV6 + if (lsUdpExtractHeader(obuf, olen, &oset, from, *fromlen, pcon) != 0) { + #else if (lsUdpExtractHeader(obuf, olen, &oset, from, *fromlen) != 0) { + #endif S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Header extraction failed"); if (obuf && obuf != recvbuf) free(obuf); return -1; *************** *** 402,409 **** --- 453,473 ---- return REAL(getpeername)(sd, name, namelen); if (name) { + #ifdef SUPPORT_IPV6 + S5NetAddr tmp; + S5NetAddr *na = &pcon->peer; + + if (pcon->handlev4v6 == V4V6_MAPPED && na->sa.sa_family == AF_INET) { + tmp = *na; + lsMappedAddrConvert(&tmp, AF_INET6); + na = &tmp; + } + *namelen = MIN(*namelen, lsAddrSize(na)); + lsAddrCopy((S5NetAddr *)name, na, *namelen); + #else *namelen = MIN(*namelen, lsAddrSize(&pcon->peer)); lsAddrCopy((S5NetAddr *)name, &pcon->peer, *namelen); + #endif } return 0; *************** *** 427,435 **** if (lsAddr2Port(&pri->prxyout) == (u_short)0 && lsLibExchgUdpCmd(pcon, &junk, S5UDP_GETSOCKNAME) < 0) return -1; ((ssi *)name)->sin_addr.s_addr = INADDR_ANY; - lsAddrSetPort((S5NetAddr *)name, lsAddr2Port(&pri->prxyout)); if (*namelen > sizeof(ssi)) *namelen = sizeof(ssi); S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsUdpGetSockname: %s:%d", ADDRANDPORT((S5NetAddr *)name)); return 0; } --- 491,509 ---- if (lsAddr2Port(&pri->prxyout) == (u_short)0 && lsLibExchgUdpCmd(pcon, &junk, S5UDP_GETSOCKNAME) < 0) return -1; + #ifdef SUPPORT_IPV6 + if (pcon->af == AF_INET6) { + ((ssi6 *)name)->sin6_addr = in6addr_any; + if (*namelen > sizeof(ssi6)) *namelen = sizeof(ssi6); + } else { + ((ssi *)name)->sin_addr.s_addr = INADDR_ANY; + if (*namelen > sizeof(ssi)) *namelen = sizeof(ssi); + } + #else ((ssi *)name)->sin_addr.s_addr = INADDR_ANY; if (*namelen > sizeof(ssi)) *namelen = sizeof(ssi); + #endif + lsAddrSetPort((S5NetAddr *)name, lsAddr2Port(&pri->prxyout)); S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "lsUdpGetSockname: %s:%d", ADDRANDPORT((S5NetAddr *)name)); return 0; } *************** *** 507,519 **** --- 581,601 ---- lsUdpRecvmsg(S5IOHandle s, ms *msg, int flags) { char recvbuf[UDP_MAX_PAYLOAD+1], *obuf = NULL; + #ifdef SUPPORT_IPV6 + int olen = 0, oset, fl = sizeof(S5NetAddr); + #else int olen = 0, oset, fl = sizeof(ssi); + #endif lsProxyInfo *pri; ss *from; int fromlen; int len=0; int i; + #ifdef SUPPORT_IPV6 + S5NetAddr tmp; + #else ssi tmp; + #endif lsSocksInfo *pcon = lsConnectionFind(s); *************** *** 580,586 **** --- 662,672 ---- continue; } + #ifdef SUPPORT_IPV6 + if(lsAddrComp(&pri->prxyin, (S5NetAddr *)from)) { + #else if(!ADDRCOMP(&pri->prxyin.sin, (ssi *)from)) { + #endif S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0,"Recvmsg from wrong host"); continue; } *************** *** 601,607 **** --- 687,697 ---- olen = buf[1].len; } + #ifdef SUPPORT_IPV6 + if(lsUdpExtractHeader(obuf, olen, &oset, from, fromlen, pcon) != 0) { + #else if(lsUdpExtractHeader(obuf, olen, &oset, from, fromlen) != 0) { + #endif S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0,"Header extraction failed"); if(obuf != recvbuf) free(obuf); *************** *** 609,615 **** --- 699,709 ---- } if((pcon->status == CON_ESTABLISHED || pcon->status == CON_ESTABLISHEDSEND)) { + #ifdef SUPPORT_IPV6 + if (lsAddrComp(&pcon->peer, (S5NetAddr *)from)) { + #else if (!ADDRCOMP(&pcon->peer.sin, (ssi *)from)) { + #endif S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0,"Recvmsg from wrong host"); if(obuf != recvbuf) free(obuf); *************** *** 618,625 **** --- 712,726 ---- } /* if(isRecv && (pcon->status == CON_ESTABLISHED....*/ done: + #ifdef SUPPORT_IPV6 + if (from->sa_family == AF_INET6 && fromlen > sizeof(ssi6)) + fromlen = sizeof(ssi6); + else if (from->sa_family == AF_INET && fromlen > sizeof(ssi)) + fromlen = sizeof(ssi); + #else if(fromlen > sizeof(ssi)) fromlen = sizeof(ssi); + #endif memcpy((u_char *)msg, obuf + oset, olen = MIN((int)len, olen - oset)); if(obuf != recvbuf) Index: server/Makefile.in diff -c src/socks5/server/Makefile.in:1.1.1.4 src/socks5/server/Makefile.in:1.2.4.3 *** server/Makefile.in Thu Aug 5 13:21:06 1999 --- server/Makefile.in Thu Aug 5 17:50:51 1999 *************** *** 25,31 **** OBJS = daemon.o socket.o proxy.o tcp.o flow.o info.o \ validate.o sema.o udp.o udputil.o tracer.o \ msg.o protocol.o log.o confutil.o buffer.o null.o \ ! addr.o s2s.o sident.o upwd.o packet.o gss.o $(EXTRA_OBJS) SRCS = $(srcdir)/daemon.c $(srcdir)/socket.c $(srcdir)/proxy.c \ $(srcdir)/tcp.c $(srcdir)/flow.c $(srcdir)/info.c \ --- 25,32 ---- OBJS = daemon.o socket.o proxy.o tcp.o flow.o info.o \ validate.o sema.o udp.o udputil.o tracer.o \ msg.o protocol.o log.o confutil.o buffer.o null.o \ ! addr.o s2s.o sident.o upwd.o packet.o gss.o $(EXTRA_OBJS) \ ! repeater.o ftpfilter.o SRCS = $(srcdir)/daemon.c $(srcdir)/socket.c $(srcdir)/proxy.c \ $(srcdir)/tcp.c $(srcdir)/flow.c $(srcdir)/info.c \ *************** *** 36,42 **** $(srcdir)/../lib/null.c $(srcdir)/../lib/addr.c \ $(srcdir)/s2s.c $(srcdir)/sident.c \ $(srcdir)/../lib/upwd.c $(srcdir)/../lib/gss.c \ ! $(srcdir)/packet.c HDRS = $(srcdir)/daemon.h $(srcdir)/socket.h $(srcdir)/proxy.h \ $(srcdir)/tcp.h $(srcdir)/flow.h $(srcdir)/info.h \ --- 37,44 ---- $(srcdir)/../lib/null.c $(srcdir)/../lib/addr.c \ $(srcdir)/s2s.c $(srcdir)/sident.c \ $(srcdir)/../lib/upwd.c $(srcdir)/../lib/gss.c \ ! $(srcdir)/packet.c \ ! $(srcdir)/repeater.c $(srcdir)/ftpfilter.c HDRS = $(srcdir)/daemon.h $(srcdir)/socket.h $(srcdir)/proxy.h \ $(srcdir)/tcp.h $(srcdir)/flow.h $(srcdir)/info.h \ *************** *** 48,55 **** $(srcdir)/../include/socks5p.h $(srcdir)/../include/socks5api.h \ $(srcdir)/../include/block.h $(srcdir)/../include/threads.h \ $(srcdir)/s2s.h $(srcdir)/sident.h \ ! $(srcdir)/../lib/upwd.h $(srcdir)/../lib/gss.h $(srcdir)/packet.h ! all: Makefile socks5 stopsocks @(if [ ! -x stopsocks ] ; then (chmod +x stopsocks); fi) --- 50,57 ---- $(srcdir)/../include/socks5p.h $(srcdir)/../include/socks5api.h \ $(srcdir)/../include/block.h $(srcdir)/../include/threads.h \ $(srcdir)/s2s.h $(srcdir)/sident.h \ ! $(srcdir)/../lib/upwd.h $(srcdir)/../lib/gss.h $(srcdir)/packet.h \ ! $(srcdir)/repeater.h $(srcdir)/ftpfilter.h all: Makefile socks5 stopsocks @(if [ ! -x stopsocks ] ; then (chmod +x stopsocks); fi) Index: server/ftpfilter.c diff -c /dev/null src/socks5/server/ftpfilter.c:1.4.2.2 *** server/ftpfilter.c Fri Aug 20 14:27:22 1999 --- server/ftpfilter.c Mon Jan 11 10:45:08 1999 *************** *** 0 **** --- 1,413 ---- + /* Copyright (c) 1998 NEC Corporation. All rights reserved. */ + /* */ + /* The redistribution, use and modification in source or binary forms of */ + /* this software is subject to the conditions set forth in the copyright */ + /* document ("Copyright.trans") included with this distribution. */ + + /* + * $Id: ftpfilter.c,v 1.4.2.2 1999/01/11 01:45:08 ishisone Exp $ + */ + + #include "socks5p.h" + #include "threads.h" + #include "daemon.h" + #include "log.h" + #include "repeater.h" + #include "ftpfilter.h" + #include "sigfix.h" + + #ifdef SUPPORT_IPV6 + + #define REPEATER_TIMEOUT 60 /* 60 seconds */ + + typedef struct ftpOption { + int next; /* starting position of next command in inPacket */ + char buf[1024]; /* must be large enough to hold single FTP command */ + int (*proc_command) P((S5LinkInfo *, const char *, char *)); + int (*proc_reply) P((S5LinkInfo *, const char *, char *)); + } FtpOption; + + static RETSIGTYPE reapchild(void) { + int r; + do { + int state; + #ifdef HAVE_WAITPID + r = waitpid(-1, &state, WNOHANG); + #else + r = wait3(&state, WNOHANG, NULL); + #endif + } while (r > 0); + } + + static int cicmp(const char *s, const char *ref) { + while (*ref != '\0') { + if (*s != *ref && toupper((unsigned char)*s) != (unsigned char)*ref) { + return *s - *ref; + } + s++, ref++; + } + return 0; + } + + static int ProcessCmdC4S6(S5LinkInfo *li, const char *cmd, char *buf) { + if (cmd[0] == 'P' || cmd[0] == 'p') { + if (!cicmp(cmd, "PORT ")) { + /* + * PORT -> LPRT + */ + unsigned char *a; + int p1, p2; + + /* Parse command and extract address information. Actually, */ + /* what we want is only the port number, and use li->intAddr */ + /* for the destination's address. */ + if (sscanf(cmd + 5, "%*d,%*d,%*d,%*d,%d,%d", &p1, &p2) != 2) { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(5), 0, + "FTPFilter: PORT command invalid format"); + return 0; + } + + /* Construct a LPRT command. The arguments are: */ + /* + IP version number (6) */ + /* + Host address length (16) */ + /* + Host address (li->dstAddr) */ + /* + Port length (2) */ + /* + Port number */ + a = (unsigned char *)&li->intAddr.sin6.sin6_addr; + sprintf(buf, + "LPRT 6,16,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,2,%d,%d\r\n", + a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8], + a[9],a[10],a[11],a[12],a[13],a[14],a[15], + p1,p2); + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, + "FTPFilter: rewrite PORT -> LPRT"); + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(20), 0, + "FTPFilter: < %s", cmd); + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(20), 0, + "FTPFilter: > %s", buf); + return 1; + } else if (!cicmp(cmd, "PASV") && (cmd[4] == '\0' || cmd[4] == ' ')) { + /* + * PASV -> LPSV + */ + strcpy(buf, "LPSV\r\n"); + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, + "FTPFilter: rewrite PASV -> LPSV"); + return 1; + } + } + return 0; + } + + static int ProcessCmdC6S4(S5LinkInfo *li, const char *cmd, char *buf) { + if (cmd[0] == 'L' || cmd[0] == 'l') { + if (!cicmp(cmd, "LPRT ")) { + /* + * LPRT -> PORT + */ + unsigned char *a; + int af, hal, pal, p1, p2; + int n; + + n = sscanf(cmd + 5, + "%d,%d,%*d,%*d,%*d,%*d,%*d,%*d,%*d,%*d,%*d,%*d,%*d,%*d,%*d,%*d,%*d,%*d,%d,%d,%d", + &af, &hal, &pal, &p1, &p2); + if (n != 5 || af != 6 || hal != 16 || pal != 2) { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(5), 0, + "FTPFilter: LPRT command invalid format"); + return 0; + } + + a = (unsigned char *)&li->intAddr.sin.sin_addr; + sprintf(buf, "PORT %d,%d,%d,%d,%d,%d\r\n", + a[0], a[1], a[2], a[3], p1, p2); + + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, + "FTPFilter: rewrite LPRT -> PORT"); + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(20), 0, + "FTPFilter: < %s", cmd); + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(20), 0, + "FTPFilter: > %s", buf); + return 1; + } else if (!cicmp(cmd, "LPSV") && (cmd[4] == '\0' || cmd[4] == ' ')) { + /* + * LPSV -> PASV + */ + strcpy(buf, "PASV\r\n"); + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, + "FTPFilter: rewrite LPSV -> PASV"); + return 1; + } + } + return 0; + } + + static int ProcessRepC4S6(S5LinkInfo *li, const char *cmd, char *buf) { + if (cmd[0] == '2' && !strncmp(cmd, "228 ", 4)) { + /* + * 228 Entering Long Passive Mode... -> 227 Entering Passive Mode... + */ + S5NetAddr conn, bnd; + char *paren; + unsigned char *ap, *pp; + int af, hal, pal; + int h[16], p[2]; + int pid; + int i, n; + + /* Parse reply message and extract address information. */ + /* Find left paren, then extract comma-separated address values. */ + if ((paren = strchr(cmd, '(')) == NULL) return 0; + + /* The expected format is: */ + /* 1st. IP version number -- 6 */ + /* 2nd. Address length -- 16 */ + /* 3rd-18th. Host address */ + /* 19th. Port length -- 2 */ + /* 20th-21st. Port number */ + n = sscanf(paren + 1, + "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", + &af, &hal, + &h[0],&h[1],&h[2],&h[3],&h[4],&h[5],&h[6],&h[7],&h[8], + &h[9],&h[10],&h[11],&h[12],&h[13],&h[14],&h[15], + &pal, &p[0], &p[1]); + /* sanity check */ + if (n != 21 || af != 6 || hal != 16 || pal != 2) { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(5), 0, + "FTPFilter: Invalid format for reply 228"); + return 0; + } + + /* Setup connection address and bind address. */ + memset(&conn, 0, sizeof(conn)); + memset(&bnd, 0, sizeof(bnd)); + conn.sin6.sin6_family = AF_INET6; + bnd.sin.sin_family = AF_INET; + + ap = (unsigned char *)&conn.sin6.sin6_addr; + for (i = 0; i < 16; i++) ap[i] = h[i]; + pp = (unsigned char *)&conn.sin6.sin6_port; + for (i = 0; i < 2; i++) pp[i] = p[i]; + + /* Use li->bndAddr for the listening port address. */ + bnd.sin.sin_addr = li->bndAddr.sin.sin_addr; + bnd.sin.sin_port = 0; + + /* Spawn a repeater process. Repeater connects to the specified */ + /* port (conn), then creates a listening port (bnd), and returns the */ + /* address of the listening port. If the client connects to the */ + /* port, it starts relaying. */ + if ((pid = SpawnRepeater(&conn, &bnd, li, REPEATER_TIMEOUT)) < 0) { + return 0; + } + + ap = (unsigned char *)&bnd.sin.sin_addr; + pp = (unsigned char *)&bnd.sin.sin_port; + sprintf(buf, "227 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n", + ap[0],ap[1],ap[2],ap[3],pp[0],pp[1]); + + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, + "FTPFilter: rewrite 228 -> 227"); + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(20), 0, + "FTPFilter: < %s", cmd); + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(20), 0, + "FTPFilter: > %s", buf); + return 1; + } + return 0; + } + + static int ProcessRepC6S4(S5LinkInfo *li, const char *cmd, char *buf) { + if (cmd[0] == '2' && !strncmp(cmd, "227 ", 4)) { + /* + * 227 Entering Passive Mode... -> 228 Entering Long Passive Mode... + */ + S5NetAddr conn, bnd; + unsigned char *ap, *pp; + int h[4], p[2]; + char *paren; + int pid; + int i; + + /* Parse reply message and extract address information. */ + /* Find left paren, then extract comma-separated address values. */ + if ((paren = strchr(cmd, '(')) == NULL) return 0; + + if (sscanf(paren + 1, "%d,%d,%d,%d,%d,%d", + &h[0], &h[1], &h[2], &h[3], &p[0], &p[1]) != 6) { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(5), 0, + "FTPFilter: Invalid format for reply 227"); + return 0; + } + + /* Setup connection address and bind address. */ + memset(&conn, 0, sizeof(conn)); + memset(&bnd, 0, sizeof(bnd)); + conn.sin.sin_family = AF_INET; + bnd.sin6.sin6_family = AF_INET6; + + ap = (unsigned char *)&conn.sin.sin_addr; + for (i = 0; i < 4; i++) ap[i] = h[i]; + pp = (unsigned char *)&conn.sin.sin_port; + for (i = 0; i < 2; i++) pp[i] = p[i]; + + /* Use li->bndAddr for the listening port address. */ + bnd.sin6.sin6_addr = li->bndAddr.sin6.sin6_addr; + bnd.sin6.sin6_port = 0; + + /* Spawn a repeater process. Repeater connects to the specified */ + /* port (conn), then creates a listening port (bnd), and returns the */ + /* address of the listening port. If the client connects to the */ + /* port, it starts relaying. */ + if ((pid = SpawnRepeater(&conn, &bnd, li, REPEATER_TIMEOUT)) < 0) { + return 0; + } + + ap = (unsigned char *)&bnd.sin6.sin6_addr; + pp = (unsigned char *)&bnd.sin6.sin6_port; + sprintf(buf, + "228 Entering Long Passive Mode (6,16,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,2,%d,%d)\r\n", + ap[0],ap[1],ap[2],ap[3],ap[4],ap[5],ap[6],ap[7],ap[8], + ap[9],ap[10],ap[11],ap[12],ap[13],ap[14],ap[15], + pp[0],pp[1]); + + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, + "FTPFilter: rewrite 227 -> 228"); + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(20), 0, + "FTPFilter: < %s", cmd); + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(20), 0, + "FTPFilter: > %s", buf); + return 1; + } + return 0; + } + + static char *FindCRLF(const char *p, const char *end) { + while ((p = memchr(p, '\r', end - p - 1)) != NULL) { + if (p[1] == '\n') return p + 2; + p++; + } + return NULL; + } + + static int FtpFilter(S5Packet *inPacket, S5Packet *outPacket, + S5LinkInfo *li, void *option, int *dir, int *action) { + FtpOption *fopt = (FtpOption *)option; + int (*procfp) P((S5LinkInfo *, const char *, char *)); + char *end, *bot; + int r; + + procfp = (*dir == S5_DIRECTION_IN) ? + fopt->proc_reply : fopt->proc_command; + + switch (*action) { + case S5_ACTION_READ: + case S5_ACTION_MORE_READ: + break; + case S5_ACTION_MORE_WRITE: + /* More commands/replies remain in inPacket. Move the data at the */ + /* beginning. */ + memmove(inPacket->data, inPacket->data + fopt->next, + inPacket->off - fopt->next); + inPacket->off -= fopt->next; + break; + default: + /* Invalid action. */ + return -1; + } + + bot = inPacket->data + inPacket->off; + if ((end = FindCRLF(inPacket->data, bot)) == NULL) { + /* What we have is only a part of a command. We need more. */ + *action = S5_ACTION_MORE_READ; + return 0; + } + + end[-2] = '\0'; /* terminate before \r\n */ + r = (*procfp)(li, inPacket->data, fopt->buf); + end[-2] = '\r'; /* restore */ + + if (r) { + /* This command/reply needs substitution. New command/reply line is */ + /* in fopt->buf. */ + outPacket->data = fopt->buf; + outPacket->len = sizeof(fopt->buf); + outPacket->off = strlen(fopt->buf); + outPacket->oob = 0; + } else { + *outPacket = *inPacket; + outPacket->off = end - inPacket->data; + } + if (end < bot) { + /* There exist remaining commands/replies (I think it is rare). */ + /* Anyway, remember the starting position of the remaining data, and */ + /* set the action to MORE_WRITE in order to have the control come */ + /* back to this function after sending. */ + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, + "FTPFilter: inPacket contains multiple command/reply"); + fopt->next = end - inPacket->data; + *action = S5_ACTION_MORE_WRITE; + } else { + /* There's no remaining data. Just send and go back to read. */ + *action = S5_ACTION_WRITE; + } + return 0; + } + + static int FtpClean(void *opt) { + /* Free allocated memory. */ + free(opt); + return 0; + } + + int FTPFilterSetup(S5LinkInfo *li, S5FilterInfo *finfo) { + FtpOption *opt; + int type; + int client_af; + int server_af; + + /* Determine filter type based on the IP version of the client connection*/ + /* and server connection. Note that li->sckAddr should be used instead */ + /* of li->dstAddr to determine server-side version. Otherwise it won't */ + /* work if there are more than one SOCKS servers between the client and */ + /* the FTP server. Consider: */ + /* client --IPv4--> SOCKS#1 --IPv6--> SOCKS#2 --IPv4--> FTP-server */ + client_af = li->srcAddr.sa.sa_family; + server_af = li->nextVersion ? li->sckAddr.sa.sa_family : li->dstAddr.sa.sa_family; + + if (client_af == AF_INET && server_af == AF_INET6) { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, + "FTPFilter installed (client IPv4, server IPv6)"); + type = 46; + } else if (client_af == AF_INET6 && server_af == AF_INET) { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, + "FTPFilter installed (client IPv6, server IPv4)"); + type = 64; + } else { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, + "FTPFilter unnecessary. not installed."); + finfo->filter = NULL; + finfo->clean = NULL; + return -1; + } + + Signal(SIGCHLD, reapchild); + + opt = (FtpOption *)malloc(sizeof(FtpOption)); + if (type == 46) { + /* Client side: IPv4, Server side: IPv6 */ + opt->proc_command = ProcessCmdC4S6; + opt->proc_reply = ProcessRepC4S6; + } else { + /* Client side: IPv6, Server side: IPv4 */ + opt->proc_command = ProcessCmdC6S4; + opt->proc_reply = ProcessRepC6S4; + } + + finfo->option = opt; + finfo->filter = FtpFilter; + finfo->clean = FtpClean; + + return 0; + } + #endif Index: server/ftpfilter.h diff -c /dev/null src/socks5/server/ftpfilter.h:1.1.4.1 *** server/ftpfilter.h Fri Aug 20 14:27:22 1999 --- server/ftpfilter.h Mon Jan 11 10:45:08 1999 *************** *** 0 **** --- 1,16 ---- + /* Copyright (c) 1998 NEC Corporation. All rights reserved. */ + /* */ + /* The redistribution, use and modification in source or binary forms of */ + /* this software is subject to the conditions set forth in the copyright */ + /* document ("Copyright.trans") included with this distribution. */ + + /* + * $Id: ftpfilter.h,v 1.1.4.1 1999/01/11 01:45:08 ishisone Exp $ + */ + + #ifndef FTPFILTER_H + #define FTPFILTER_H + + extern int FTPFilterSetup P((S5LinkInfo *, S5FilterInfo *)); + + #endif Index: server/info.c diff -c src/socks5/server/info.c:1.1.1.3 src/socks5/server/info.c:1.5.2.1 *** server/info.c Thu Apr 1 11:04:56 1999 --- server/info.c Wed Apr 7 14:36:07 1999 *************** *** 38,43 **** --- 38,49 ---- if (eres) { MUTEX_LOCK(gh_mutex); + #ifdef SUPPORT_IPV6 + if (addr->sa.sa_family == AF_INET6) { + hp = gethostbyaddr((char *)&addr->sin6.sin6_addr, + sizeof(struct in6_addr), AF_INET6); + } else + #endif hp = gethostbyaddr((char *)&addr->sin.sin_addr, sizeof(struct in_addr), AF_INET); if (!hp) { MUTEX_UNLOCK(gh_mutex); } else res = hp->h_name; *************** *** 106,112 **** --- 112,129 ---- strncpy(pri->retName, pri->dstAddr.sn.sn_name, MIN(strlen(pri->dstAddr.sn.sn_name) + 1, S5_HOSTNAME_SIZE)); if (strlen(pri->dstAddr.sn.sn_name) + 1 > S5_HOSTNAME_SIZE) pri->retName[S5_HOSTNAME_SIZE-1] = '\0'; + #ifdef SUPPORT_IPV6 + /* IPv6: Resolve hostname. If the client uses IPv4, we prefer IPv4, */ + /* IPv6: otherwise, IPv6. */ + if ((pri->srcAddr.sa.sa_family == AF_INET && + (!lsName2Addr(pri->dstAddr.sn.sn_name, &tmp, AF_INET) || + !lsName2Addr(pri->dstAddr.sn.sn_name, &tmp, AF_INET6))) || + (pri->srcAddr.sa.sa_family == AF_INET6 && + (!lsName2Addr(pri->dstAddr.sn.sn_name, &tmp, AF_INET6) || + !lsName2Addr(pri->dstAddr.sn.sn_name, &tmp, AF_INET)))) { + #else if (!lsName2Addr(pri->dstAddr.sn.sn_name, &tmp)) { + #endif S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Resolve Names: host name: %s is %s", pri->dstAddr.sn.sn_name, lsAddr2Ascii(&tmp)); lsAddrSetPort(&tmp, lsAddr2Port(&pri->dstAddr)); lsAddrCopy(&pri->dstAddr, &tmp, lsAddrSize(&tmp)); *************** *** 117,122 **** --- 134,149 ---- } GetName(pri->dstName, &pri->dstAddr); + #ifdef SUPPORT_IPV6 + } else if (pri->dstAddr.sa.sa_family == AF_INET6) { + struct in6_addr junk; + + lsAddrCopy(&pri->retAddr, &pri->dstAddr, lsAddrSize(&pri->dstAddr)); + GetName(pri->dstName, &pri->dstAddr); + + if (inet_pton(AF_INET6, pri->dstName, &junk) == 0) + strcpy(pri->retName, pri->dstName); + #endif } else { if (pri->dstAddr.sin.sin_addr.s_addr != INADDR_ANY && !(pri->dstAddr.sin.sin_addr.s_addr & inet_addr("255.255.255.0"))) { Index: server/packet.c diff -c src/socks5/server/packet.c:1.1.1.4 src/socks5/server/packet.c:1.2.4.3 *** server/packet.c Thu Aug 5 13:21:08 1999 --- server/packet.c Thu Aug 5 17:50:52 1999 *************** *** 15,25 **** --- 15,33 ---- #include "log.h" static const char *Addr2Ascii(const S5NetAddr *na) { + #ifdef SUPPORT_IPV6 + static char ntop_buf[INET6_ADDRSTRLEN]; + #endif switch (na->sa.sa_family) { case AF_S5NAME: return na->sn.sn_name; case AF_INET: return inet_ntoa(na->sin.sin_addr); + #ifdef SUPPORT_IPV6 + case AF_INET6: + return inet_ntop(AF_INET6, &na->sin6.sin6_addr, + ntop_buf, sizeof(ntop_buf)); + #endif default: return ""; } *************** *** 31,36 **** --- 39,48 ---- return na->sn.sn_port; case AF_INET: return na->sin.sin_port; + #ifdef SUPPORT_IPV6 + case AF_INET6: + return na->sin6.sin6_port; + #endif default: return (u_short)0; } Index: server/proxy.c diff -c src/socks5/server/proxy.c:1.1.1.4 src/socks5/server/proxy.c:1.10.2.2 *** server/proxy.c Thu Apr 1 11:04:57 1999 --- server/proxy.c Wed Apr 7 14:36:09 1999 *************** *** 24,29 **** --- 24,32 ---- #include "udp.h" #include "tracer.h" #include "packet.h" + #ifdef SUPPORT_IPV6 + #include "ftpfilter.h" + #endif #ifndef ESTABLISH_TIMEOUT #define ESTABLISH_TIMEOUT 10 *************** *** 66,71 **** --- 69,81 ---- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "Socks4: Read failed: %m"); return EXIT_ERR; } + #ifdef SUPPORT_IPV6 + if (pri->srcAddr.sa.sa_family == AF_INET6) { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "Socks4: Connection via IPv6"); + S5IOSend(iio->fd, NULL, resp, sizeof(resp), 0, PROXY_IOFLAGS, timerm); + return EXIT_ERR; + } + #endif pri->peerAuth = AUTH_NONE; pri->peerVersion = buf[SP_VERSION]; *************** *** 186,195 **** --- 196,234 ---- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "Socks5: Read request failed: %m"); return EXIT_ERR; } + #ifdef ID_KITAMURA_SOCKS_IPV6 + if (pri->dstAddr.sa.sa_family == AF_S5ID) { + /* not supported yet */ + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, + "Socks5: ADDRESS ID is specified, but not supported"); + lsSendResponse(iio->fd, iio, &pri->bndAddr, pri->peerVersion, + SOCKS5_BADADDR, 0, NULL); + return EXIT_ERR; + } + #endif return EXIT_OK; } + #ifdef SUPPORT_IPV6 + static int FilterSetup(S5LinkInfo *pri, S5FilterInfo *fip) { + char filtername[S5_NAME_SIZE]; + + if (!GetFilter(pri, filtername)) { + if (!strcmp(filtername, "packetprint")) { + PacketPrintSetup(pri, fip); + } else if (!strcmp(filtername, "ftpv6")) { + FTPFilterSetup(pri, fip); + } else { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, + "Socks5: unknown filtername %s", filtername); + return -1; + } + } + return 0; + } + #endif + /* HandlePxyConnection will be the routine for Socks5, which handles the */ /* initial part of the connection. Specifically, we want to do several */ /* things here. We want to check the version, if its not version 5, we can */ *************** *** 228,233 **** --- 267,277 ---- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "Proxy: getpeername failed: %m"); goto cleanup; } + #ifdef SUPPORT_IPV6 + /* IPv6: If it is an IPv4-mapped IPv6 address, convert it to normal IPv4 */ + /* IPv6: address. */ + (void)lsMappedAddrConvert(&li.srcAddr, AF_INET); + #endif len = sizeof(S5NetAddr); *************** *** 235,240 **** --- 279,287 ---- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "Proxy: getsockname failed: %m"); goto cleanup; } + #ifdef SUPPORT_IPV6 + (void)lsMappedAddrConvert(&li.bndAddr, AF_INET); + #endif GetName(li.srcName, &li.srcAddr); *************** *** 242,249 **** --- 289,304 ---- /* If somehow we got a connection from somewhere on an interface which */ /* we wouldn't use to get to that same place, this is bad (IP SPOOF?), */ /* so we'll quit. */ + #ifdef SUPPORT_IPV6 + if (!(route.sa.sa_family == AF_INET && + route.sin.sin_addr.s_addr == INADDR_ANY) && + !(route.sa.sa_family == AF_INET6 && + IN6_IS_ADDR_UNSPECIFIED(&route.sin6.sin6_addr)) && + lsAddrAddrComp(&route, &li.bndAddr) != 0) { + #else if (route.sin.sin_addr.s_addr != INADDR_ANY && route.sin.sin_addr.s_addr != li.bndAddr.sin.sin_addr.s_addr) { + #endif S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, MSGID_SERVER_WRONG_ROUTE, "Proxy: Received connection via wrong route"); S5LogUpdate(S5LogDefaultHandle, S5_LOG_INFO, MSGID_SERVER_AUTH_FAILED, "Auth Failed: (%s:%d)", li.srcName, (int)ntohs(lsAddr2Port(&li.srcAddr))); goto cleanup; *************** *** 302,308 **** --- 357,370 ---- default: S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, MSGID_SERVER_BAD_COMMAND, "Proxy: Bad command number %d", (int)li.peerCommand); + #ifdef SUPPORT_IPV6 + /* IPv6: Since this is an error reply, BND.ADDR is irrelevant. */ + /* IPv6: We use li.bndAddr because the client can always */ + /* IPv6: recognize its address family. */ + lsSendResponse(iio.fd, &iio, &li.bndAddr, li.peerVersion, (li.peerVersion == SOCKS5_VERSION)?SOCKS5_BADCMND:SOCKS_BAD_ID, 0, NULL); + #else lsSendResponse(iio.fd, &iio, &li.dstAddr, li.peerVersion, (li.peerVersion == SOCKS5_VERSION)?SOCKS5_BADCMND:SOCKS_BAD_ID, 0, NULL); + #endif S5BufCleanContext(&iio); rval = -1; } *************** *** 313,319 **** --- 375,385 ---- goto cleanup; } + #ifdef SUPPORT_IPV6 + FilterSetup(&li, &fi); + #else PacketPrintSetup(&li, &fi); + #endif inPacket.data = NULL; outPacket.data = NULL; *************** *** 389,392 **** S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Proxy: done cleaning up"); return rval; } - --- 455,457 ---- Index: server/repeater.c diff -c /dev/null src/socks5/server/repeater.c:1.5.2.2 *** server/repeater.c Fri Aug 20 14:27:22 1999 --- server/repeater.c Mon Jan 11 10:45:09 1999 *************** *** 0 **** --- 1,257 ---- + /* Copyright (c) 1998 NEC Corporation. All rights reserved. */ + /* */ + /* The redistribution, use and modification in source or binary forms of */ + /* this software is subject to the conditions set forth in the copyright */ + /* document ("Copyright.trans") included with this distribution. */ + + /* + * $Id: repeater.c,v 1.5.2.2 1999/01/11 01:45:09 ishisone Exp $ + */ + + #include "socks5p.h" + #include "addr.h" + #include "log.h" + #include "repeater.h" + + #ifndef NO_CHECK_CLIENT_ADDRESS + #define CHECK_CLIENT_ADDRESS + #endif + + #define BSIZE 8192 + #define RD_THRE (BSIZE * 2 / 3) + + typedef struct { + int rfd; /* socket for read */ + int wfd; /* socket for write */ + int len; /* length of data in the buffer */ + int eof; /* EOF has been received? */ + int weof; /* EPIPE has occured? */ + char buf[BSIZE]; /* data buffer */ + } RData; + + /* Wait for a connection request from client with timeout. */ + static int WaitForConnection(int s, S5LinkInfo *client, int timeout) { + fd_set fds; + struct timeval tv; + S5NetAddr sa; + int salen = sizeof(S5NetAddr); + int r; + + again: + FD_ZERO(&fds); + FD_SET(s, &fds); + tv.tv_sec = timeout; + tv.tv_usec = 0; + + memset(&sa, 0, sizeof(sa)); + if (select(s + 1, &fds, NULL, NULL, &tv) > 0) { + if ((r = accept(s, (struct sockaddr *)&sa, &salen)) < 0) { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, + "Repeater: accept failed (%m)"); + return r; + } + #ifdef CHECK_CLIENT_ADDRESS + /* + * Check the peer address. We want to allow connction only + * from the client. The client might connect directly, or + * via socks5. So we accept connection: + * a) from the client host (in case of direct connection) + * b) from one of the local addresses, more specifically + * loopback address or the interface address which + * is used for connection to the client (in case of + * indirect connection via socks5) + */ + if (client != NULL && + lsAddrAddrComp(&client->srcAddr, &sa) != 0 && + lsAddrIsNull(&sa) && /* <- this means `NOT null'. oh. */ + lsAddrAddrComp(&client->bndAddr, &sa) != 0) { + /* Connection from an unexpected client. */ + S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, + "Repeater: reject connection from an invalid client %s:%d", + ADDRANDPORT(&sa)); + close(r); + /* It's better to adjust timeout... */ + goto again; + } + #endif + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, + "Repeater: accept connection from %s:%d", + ADDRANDPORT(&sa)); + return r; + } + return -1; + } + + static int FillBuffer(RData *d) { + int n; + if (d->len >= sizeof(d->buf)) return 0; + if ((n = read(d->rfd, d->buf + d->len, sizeof(d->buf) - d->len)) < 0) { + if (errno == EPIPE) n = 0; + } else if (n == 0) { + /* EOF received */ + d->eof = 1; + } else if (n > 0) { + d->len += n; + } + return n; + } + + static int FlushBuffer(RData *d) { + int n; + if (d->len <= 0) return 0; + if ((n = write(d->wfd, d->buf, d->len)) == 0 || + (n < 0 && errno == EPIPE)) { + /* EOF */ + d->weof = 1; + n = 0; + } else if (n > 0) { + d->len -= n; + if (d->len > 0) memmove(d->buf, d->buf + n, d->len); + } + return n; + } + + static void Relay(int s1, int s2) { + RData r[2]; + fd_set rfds, wfds; + int maxfd = s1 > s2 ? s1 : s2; + int i; + + r[0].rfd = r[1].wfd = s1; + r[1].rfd = r[0].wfd = s2; + r[0].len = r[1].len = 0; + r[0].eof = r[1].eof = 0; + r[0].weof = r[1].weof = 0; + + FD_ZERO(&rfds); + FD_ZERO(&wfds); + for (i = 0; i < 2; i++) { + FD_SET(r[i].rfd, &rfds); + } + + for (;;) { + fd_set tmp_r, tmp_w; + + tmp_r = rfds; + tmp_w = wfds; + if (select(maxfd + 1, &tmp_r, &tmp_w, NULL, NULL) < 0) { + if (errno == EINTR) continue; + return; + } + + for (i = 0; i < 2; i++) { + RData *d = &r[i]; + + if (FD_ISSET(d->rfd, &tmp_r)) { + if (FillBuffer(d) < 0) { + if (errno != EINTR) _exit(1); + } else if (d->eof) { + shutdown(d->rfd, 0); + FD_CLR(d->rfd, &rfds); + /* If there are nothing to be sent, shutdown write-side. */ + if (d->len == 0) { + shutdown(d->wfd, 1); + FD_CLR(d->wfd, &wfds); + } + } else { + /* Start writing. */ + if (d->len > 0) FD_SET(d->wfd, &wfds); + /* If buffer is full, stop reading. */ + if (d->len >= sizeof(d->buf)) FD_CLR(d->rfd, &rfds); + } + } + if (FD_ISSET(d->wfd, &tmp_w)) { + if (FlushBuffer(d) < 0) { + if (errno != EINTR) _exit(1); + } else if (d->weof) { + /* Cannot write. Shutdown both read and write side. */ + shutdown(d->rfd, 0); + FD_CLR(d->rfd, &rfds); + shutdown(d->wfd, 1); + FD_CLR(d->wfd, &wfds); + d->eof = 1; + d->len = 0; + } else { + /* Restart reading. */ + if (!d->eof && d->len < RD_THRE) FD_SET(d->rfd, &rfds); + /* If buffer is empty, stop writing. */ + if (d->len == 0) { + FD_CLR(d->wfd, &wfds); + if (d->eof) shutdown(d->wfd, 1); + } + } + } + } + /* If all the relaying is finished, we're done. */ + if (r[0].eof && r[1].eof && r[0].len == 0 && r[1].len == 0) { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, + "Repeater: relay finished"); + return; + } + } + } + + int SpawnRepeater(const S5NetAddr *conn_addr, S5NetAddr *bind_addr, S5LinkInfo *client, int timeout) { + int conn_af = conn_addr->sa.sa_family; + int bind_af = bind_addr->sa.sa_family; + int conn_sock = S5InvalidIOHandle, bind_sock = S5InvalidIOHandle; + int addrlen = sizeof(S5NetAddr); + int pid; + + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, + "Repeater: destination is %s:%d", ADDRANDPORT(conn_addr)); + + if ((conn_sock = socket(conn_af, SOCK_STREAM, 0)) < 0) { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, + "Repeater: Socket creation failed: %m"); + goto cleanup; + } + if (connect(conn_sock, &conn_addr->sa, lsAddrSize(conn_addr)) < 0) { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, + "Repeater: TCP Connect to %s:%d failed: %m", + ADDRANDPORT(conn_addr)); + goto cleanup; + } + if ((bind_sock = socket(bind_af, SOCK_STREAM, 0)) < 0) { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, + "Repeater: Socket creation failed: %m"); + goto cleanup; + } + + if (bind(bind_sock, &bind_addr->sa, lsAddrSize(bind_addr)) < 0 || + getsockname(bind_sock, &bind_addr->sa, &addrlen) < 0) { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, + "Repeater: TCP Bind to %s:%d failed: %m", + ADDRANDPORT(bind_addr)); + goto cleanup; + } + listen(bind_sock, 5); + + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, + "Repeater: listening at %s:%d", ADDRANDPORT(bind_addr)); + + if ((pid = fork()) < 0) { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, + "Repeater: Fork failed: %m"); + goto cleanup; + } else if (pid > 0) { + /* parent */ + CLOSESOCKET(conn_sock); + CLOSESOCKET(bind_sock); + } else { + int acc_sock; + + signal(SIGPIPE, SIG_IGN); + if ((acc_sock = WaitForConnection(bind_sock, client, timeout)) >= 0) { + CLOSESOCKET(bind_sock); + Relay(conn_sock, acc_sock); + } + _exit(0); + } + return pid; + + cleanup: + if (conn_sock != S5InvalidIOHandle) CLOSESOCKET(conn_sock); + if (bind_sock != S5InvalidIOHandle) CLOSESOCKET(bind_sock); + return -1; + } Index: server/repeater.h diff -c /dev/null src/socks5/server/repeater.h:1.2.4.2 *** server/repeater.h Fri Aug 20 14:27:22 1999 --- server/repeater.h Mon Jan 11 10:45:09 1999 *************** *** 0 **** --- 1,16 ---- + /* Copyright (c) 1998 NEC Corporation. All rights reserved. */ + /* */ + /* The redistribution, use and modification in source or binary forms of */ + /* this software is subject to the conditions set forth in the copyright */ + /* document ("Copyright.trans") included with this distribution. */ + + /* + * $Id: repeater.h,v 1.2.4.2 1999/01/11 01:45:09 ishisone Exp $ + */ + + #ifndef REPEATER_H + #define REPEATER_H + + extern int SpawnRepeater P((const S5NetAddr *conn_addr, S5NetAddr *bind_addr, S5LinkInfo *client, int timeout)); + + #endif Index: server/s2s.c diff -c src/socks5/server/s2s.c:1.1.1.4 src/socks5/server/s2s.c:1.5.2.2 *** server/s2s.c Thu Apr 1 11:04:39 1999 --- server/s2s.c Wed Apr 7 14:36:10 1999 *************** *** 17,26 **** #include "log.h" /* Not sure when/if this is ever necessary during failed connects... */ static int Reset(S5IOInfo *info, int otype) { S5IOHandle nfd; ! if ((nfd = socket(AF_INET, otype, 0)) == S5InvalidIOHandle) return -1; CLOSESOCKET(info->fd); info->fd = nfd; --- 17,33 ---- #include "log.h" /* Not sure when/if this is ever necessary during failed connects... */ + #ifdef SUPPORT_IPV6 + static int Reset(S5IOInfo *info, int af, int otype) { + #else static int Reset(S5IOInfo *info, int otype) { + #endif S5IOHandle nfd; ! #ifdef SUPPORT_IPV6 ! if ((nfd = socket(af, otype, 0)) == S5InvalidIOHandle) return -1; ! #else if ((nfd = socket(AF_INET, otype, 0)) == S5InvalidIOHandle) return -1; + #endif CLOSESOCKET(info->fd); info->fd = nfd; *************** *** 55,61 **** --- 62,74 ---- getsockopt(oiop->fd, SOL_SOCKET, SO_TYPE, (char *)&optval, &optlen); for (i = 1; i < pri->nAltSckAddrs; i++) { + #ifdef SUPPORT_IPV6 + int af = pri->altSckAddrs[i].sa.sa_family; + + if (Reset(oiop, af, optval) < 0) goto error; + #else if (Reset(oiop, optval) < 0) goto error; + #endif lsAddrCopy(&pri->sckAddr, &pri->altSckAddrs[i], lsAddrSize(&pri->altSckAddrs[i])); GetName(pri->sckName, &pri->sckAddr); *************** *** 77,83 **** --- 90,101 ---- strcpy(effuser, lsEffUser()); MUTEX_UNLOCK(gpw_mutex); + #ifdef SUPPORT_IPV6 + /* IPv6: Set always SOCKS5_FLAG_IPV4V6 flag since we can handle both. */ + if (lsProtoExchg(oiop->fd, oiop, dest, effuser, pri->nextVersion, pri->peerCommand, pri->peerReserved|SOCKS5_FLAG_IPV4V6) < 0) { + #else if (lsProtoExchg(oiop->fd, oiop, dest, effuser, pri->nextVersion, pri->peerCommand, pri->peerReserved) < 0) { + #endif S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "S2S Protocol exchange with proxy (%s:%d) failed", ADDRANDPORT(&pri->sckAddr)); goto error; } Index: server/socket.c diff -c src/socks5/server/socket.c:1.1.1.7 src/socks5/server/socket.c:1.7.2.5 *** server/socket.c Thu Aug 5 13:21:08 1999 --- server/socket.c Thu Aug 5 17:50:52 1999 *************** *** 32,43 **** --- 32,52 ---- #define ISMASTER() (!iamachild && (servermode == PREFORKING || servermode == THREADED)) #define ISSLAVE() (iamachild && (servermode == PREFORKING || servermode == THREADED)) + #ifdef SUPPORT_IPV6 + #define VALID_BOTH(in) ((in)[0] != S5InvalidIOHandle && (in)[1] != S5InvalidIOHandle) + #define S5DontCareIOHandle 9999 + #endif + static int acceptor = 0; /* the pid of the accepting process if threaded */ static int nconns = 0; /* the number of proxies the daemon has had... */ static int nchildren = 0; /* the number of children the daemon has had... */ static int iamachild = 0; /* Am I a child, or the parent... */ static void *asem = NULL; + #ifdef SUPPORT_IPV6 + static S5IOHandle in[2] = { S5InvalidIOHandle, S5InvalidIOHandle }; + #else static S5IOHandle in = S5InvalidIOHandle; + #endif static sig_atomic_t hadfatalsig = 0; /* Has a sighup/sigusr1 occured? */ static sig_atomic_t hadsigint = 0; /* Has a sigint occured? */ *************** *** 124,141 **** --- 133,241 ---- } } + #ifdef SUPPORT_IPV6 + static int GetBindAddr(int af, char *str, S5NetAddr *addr) { + u_short port = 0; + char *s_addr = NULL, *s_port = NULL; + char *saveptr = NULL, save; + + if (str != NULL) { + if (str[0] == '[') { + s_addr = ++str; + if ((str = strchr(str, ']')) == NULL) { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, + " Invalid address %s specified", s_addr); + return -1; + } + saveptr = str; + save = *saveptr; + *str++ = '\0'; + if (str[0] == ':') s_port = str + 1; + } else if ((s_port = strchr(str, ':'))) { + saveptr = s_port; + save = *saveptr; + *s_port++ = '\0'; + if (str[0] != '\0') s_addr = str; + } else if (isdigit((unsigned char)str[0]) && + (strchr(str, '.') == NULL && strchr(str, ':') == NULL)) { + s_port = str; + } else { + s_addr = str; + } + } + + memset(addr, 0, sizeof(addr)); + if (s_addr == NULL) { + if (af == AF_INET) { + addr->sin.sin_family = af; + addr->sin.sin_addr.s_addr = htonl(INADDR_ANY); + } else { + addr->sin6.sin6_family = af; + addr->sin6.sin6_addr = in6addr_any; + } + } else if (lsName2Addr(s_addr, addr, af) < 0) { + if (saveptr != NULL) *saveptr = save; + return 0; + } + + if (s_port) lsName2Port(s_port, "tcp", &port); + else lsName2Port("socks", "tcp", &port); + + if (port == INVALIDPORT) port = htons(SOCKS_DEFAULT_PORT); + + lsAddrSetPort(addr, port); + + if (saveptr != NULL) *saveptr = save; + return 1; + } + #endif + + /* IPv6: GetBindIntfc may return 2 addresses -- one for IPv4 and another */ + /* IPv6: for IPv6. IPv6 address always comes first. GetBindIntfc returns */ + /* IPv6: the number of addresses (or -1). */ static int GetBindIntfc(S5NetAddr *bndaddr) { + #ifdef SUPPORT_IPV6 + char *tmp = NULL, *tmp_ip4 = NULL, *tmp_ip6 = NULL; + int r, naddrs; + #else u_short bindport = 0; char *tmp = NULL, *tmpaddr = NULL, *tmpport = NULL; + #endif if (bindif) tmp = strdup(bindif); else { MUTEX_LOCK(env_mutex); tmp = getenv("SOCKS5_BINDINTFC"); if (tmp) tmp = strdup(tmp); + #ifdef SUPPORT_IPV6 + tmp_ip4 = getenv("SOCKS5_BINDINTFC_IPV4"); + if (tmp_ip4) tmp_ip4 = strdup(tmp_ip4); + tmp_ip6 = getenv("SOCKS5_BINDINTFC_IPV6"); + if (tmp_ip6) tmp_ip6 = strdup(tmp_ip6); + #endif MUTEX_UNLOCK(env_mutex); } + #ifdef SUPPORT_IPV6 + if (!tmp_ip4) tmp_ip4 = tmp; + if (!tmp_ip6) tmp_ip6 = tmp; + + if ((r = GetBindAddr(AF_INET6, tmp_ip6, bndaddr)) < 0) return -1; + naddrs = r; + if ((r = GetBindAddr(AF_INET, tmp_ip4, bndaddr + naddrs)) < 0) return -1; + naddrs += r; + if (naddrs == 0) { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, + " Invalid addresses %s (IPv4) and %s (IPv6) specified", + tmp_ip4, tmp_ip6); + naddrs = -1; + } + /* XXX possible memory leak. */ + if (tmp_ip4) free(tmp_ip4); + if (tmp_ip6 && tmp_ip6 != tmp_ip4) free(tmp_ip6); + + return naddrs; + #else if (tmp) { if ((tmpport = strchr(tmp, ':'))) { *tmpport++ = '\0'; *************** *** 164,169 **** --- 264,270 ---- if (tmp) free(tmp); return 0; + #endif } static void GetUdpPortRange(void) { *************** *** 194,200 **** --- 295,307 ---- /* should become invalid, the r->fd should be set to -1, so other places */ /* know to ignore it... */ static int MakeSocket(int start, S5IOHandle *infd) { + #ifdef SUPPORT_IPV6 + static S5NetAddr bndaddr[2]; + static int nbndaddrs; + int i; + #else S5NetAddr bndaddr; + #endif int on = 1; if (!start) { *************** *** 207,220 **** --- 314,391 ---- S5LogUpdate(S5LogDefaultHandle, S5_LOG_INFO, MSGID_SERVER_RESTART, "Socks5 restarting at %s", tbuf); } + #ifdef SUPPORT_IPV6 + if (infd[0] != S5InvalidIOHandle && infd[1] != S5InvalidIOHandle) { + #else if (*infd != S5InvalidIOHandle) { + #endif return 0; } if (start) { + #ifdef SUPPORT_IPV6 + if ((nbndaddrs = GetBindIntfc(bndaddr)) < 0) goto cleanup; + #else if (GetBindIntfc(&bndaddr) < 0) goto cleanup; + #endif } + #ifdef SUPPORT_IPV6 + /* IPv6: First we try creating IPv6 socket, then IPv4. IPv4 creation */ + /* IPv6: might fail if TCP port space of IPv4 and IPv6 are shared. */ + for (i = 0; i < nbndaddrs; i++) { + int af = bndaddr[i].sa.sa_family; + + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(12), 0, + "Socks5 attempting to run on interface %s:%d", + ADDRANDPORT(&bndaddr[i])); + if ((infd[i] = socket(af, SOCK_STREAM, 0)) == S5InvalidIOHandle) { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, + "Socket failed for %s:%d: %m", + ADDRANDPORT(&bndaddr[i])); + goto cleanup; + } + + if (setsockopt(infd[i], SOL_SOCKET, SO_REUSEADDR, + (char *)&on, sizeof(int)) < 0) { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, + "Turning on address reuse failed for %s:%d: %m", + ADDRANDPORT(&bndaddr[i])); + goto cleanup; + } + + if (bind(infd[i], (ss *)&bndaddr[i], (af == AF_INET) ? sizeof(ssi) : sizeof(ssi6)) < 0) { + /* IPv6: Binding IPv4 socket might fail if the TCP port space is */ + /* IPv6: shared between IPv4 and IPv6, the port number is same, */ + /* IPv6: and both IPv4 and IPv6 addresses are unspecified (any) */ + /* IPv6: (or loopback?). In this case, IPv6 can accept IPv4 */ + /* IPv6: connection, so there is no problem. */ + if (i == 1 && + lsAddr2Port(&bndaddr[0]) == lsAddr2Port(&bndaddr[1]) && + !lsAddrIsNull(&bndaddr[0]) && !lsAddrIsNull(&bndaddr[1])) { + CLOSESOCKET(infd[1]); + nbndaddrs = 1; + break; + } else { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, + MSGID_SERVER_SOCKS_BIND, + "Bind failed for %s:%d: %m", + ADDRANDPORT(&bndaddr[i])); + goto cleanup; + } + } + + if (listen(infd[i], 5) < 0) { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, + "Listen failed for %s:%d: %m", + ADDRANDPORT(&bndaddr[i])); + goto cleanup; + } + } + + /* IPv6: Fill in S5DontCareIOHandle for unused socket handle. */ + if (nbndaddrs == 1) infd[1] = S5DontCareIOHandle; + #else S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(12), 0, "Socks5 attempting to run on interface %s:%d", ADDRANDPORT(&bndaddr)); if ((*infd = socket(AF_INET, SOCK_STREAM, 0)) == S5InvalidIOHandle) { *************** *** 236,241 **** --- 407,413 ---- S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "Listen failed for %s:%d: %m", ADDRANDPORT(&bndaddr)); goto cleanup; } + #endif /* If we bound, we're the owner, so put our pid in the pidfile. */ #ifndef DONT_STORE_PID *************** *** 251,257 **** --- 423,433 ---- MUTEX_UNLOCK(env_mutex); if ((ofile = malloc(strlen(myfl)+7))) { + #ifdef SUPPORT_IPV6 + sprintf(ofile, "%s-%d", myfl, (int)ntohs(lsAddr2Port(bndaddr))); + #else sprintf(ofile, "%s-%d", myfl, (int)ntohs(bndaddr.sin.sin_port)); + #endif free(myfl); myfl = ofile; } else { *************** *** 279,289 **** --- 455,475 ---- } #endif + #ifdef SUPPORT_IPV6 + return nbndaddrs; + #else return 0; + #endif cleanup: if (*infd != S5InvalidIOHandle) CLOSESOCKET(*infd); *infd = S5InvalidIOHandle; + #ifdef SUPPORT_IPV6 + if (infd[1] != S5InvalidIOHandle && infd[1] != S5DontCareIOHandle) { + CLOSESOCKET(infd[1]); + } + infd[1] = S5InvalidIOHandle; + #endif return -1; } *************** *** 306,312 **** --- 492,502 ---- /* we're forking or setting things up... */ for (set = SigBlock(SIGHUP); ; ) { /* Do our thing if everything is ok... */ + #ifdef SUPPORT_IPV6 + if (VALID_BOTH(infd)) { + #else if (*infd != S5InvalidIOHandle) { + #endif switch (servermode) { case THREADED: if (acceptor == 0) acceptor = DoFork(); *************** *** 326,332 **** --- 516,526 ---- /* Wait for any signal to arrive, esp SIGCHLD and SIGHUP. SIGHUP */ /* will cause a re-read of the config file, everything else: loop. */ + #ifdef SUPPORT_IPV6 + if (!hadfatalsig && !hadsigint && !hadresetsig && VALID_BOTH(infd)) { + #else if (!hadfatalsig && !hadsigint && !hadresetsig && *infd != S5InvalidIOHandle) { + #endif SigPause(); } *************** *** 391,396 **** --- 585,603 ---- if (eval > 0 || errno == EAGAIN) return; exit(-1); } + #if 1 + /* Close listening socket.. */ + if (servermode == NORMAL) { + #ifdef SUPPORT_IPV6 + CLOSESOCKET(in[0]); + if (in[1] != S5InvalidIOHandle && in[1] != S5DontCareIOHandle) { + CLOSESOCKET(in[1]); + } + #else + CLOSESOCKET(in); + #endif + } + #endif eval = HandlePxyConnection(sd); *************** *** 402,407 **** --- 609,615 ---- exit(eval); } + #ifndef SUPPORT_IPV6 static int AcceptConnection(int sd, struct sockaddr *sa, int *alen) { struct timeval acceptout; static fd_set rfds; *************** *** 429,435 **** --- 637,689 ---- return -1; } } + #else + static int AcceptConnection(int *sd, struct sockaddr *sa, int *alen) { + struct timeval acceptout; + static fd_set rfds; + int maxfd; + int afd; + if (servermode != THREADED && sd[1] == S5DontCareIOHandle) { + return accept(sd[0], sa, alen); + } + + maxfd = sd[0]; + if (sd[1] != S5DontCareIOHandle && sd[1] > maxfd) maxfd = sd[1]; + + FD_ZERO(&rfds); + for (;;) { + acceptout.tv_sec = 180; + acceptout.tv_usec = 0; + + FD_SET(sd[0], &rfds); + if (sd[1] != S5DontCareIOHandle) FD_SET(sd[1], &rfds); + + switch (select(maxfd + 1, &rfds, NULL, NULL, &acceptout)) { + case -1: + if (errno == EINTR || errno == EAGAIN) continue; + return -1; + case 0: + errno = ETIMEDOUT; + return -1; + default: + afd = -1; + if (FD_ISSET(sd[0], &rfds)) { + afd = sd[0]; + } else if (sd[1] != S5DontCareIOHandle && FD_ISSET(sd[1], &rfds)) { + afd = sd[1]; + } + if (afd >= 0) { + FD_CLR(sd[0], &rfds); + if (sd[1] != S5DontCareIOHandle) FD_CLR(sd[1], &rfds); + return accept(afd, sa, alen); + } + } + return -1; + } + } + #endif + static void WaitSecond(void) { static int ud = 0; struct timeval waitout; *************** *** 548,554 **** --- 802,812 ---- ReadConfig(); + #ifdef SUPPORT_IPV6 + if (MakeSocket(1, in) < 0) { + #else if (MakeSocket(1, &in) < 0) { + #endif S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "Accept: Failed to make listening socket"); exit(-1); } *************** *** 561,567 **** --- 819,829 ---- if (ISMASTER()) { asem = semcreate(1); + #ifdef SUPPORT_IPV6 + GetSignals(asem, in); + #else GetSignals(asem, &in); + #endif } if (ISMASTER()) { *************** *** 579,587 **** --- 841,858 ---- /* If an important signal has arrived or the acc fd is corrupted, */ /* got into the signal waiting state (and possibly exit - if child). */ + #ifdef SUPPORT_IPV6 + if (hadfatalsig || hadsigint || in[0] == S5InvalidIOHandle || + in[1] == S5InvalidIOHandle) { + #else if (hadfatalsig || hadsigint || in == S5InvalidIOHandle) { + #endif S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(2), 0, "Accept: Processing exception"); + #ifdef SUPPORT_IPV6 + GetSignals(asem, in); + #else GetSignals(asem, &in); + #endif hadfatalsig = 0; } *************** *** 627,633 **** --- 898,909 ---- MUTEX_UNLOCK(accept_mutex); exit(-1); } else { + #ifdef SUPPORT_IPV6 + CLOSESOCKET(in[0]); + CLOSESOCKET(in[1]); + #else CLOSESOCKET(in); + #endif exit(-1); } } *************** *** 695,701 **** --- 971,984 ---- errno = aerrno; S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, MSGID_SERVER_SOCKS_ACCEPT, "Accept: Accept failed: %m"); + #ifdef SUPPORT_IPV6 + if (servermode != THREADED) { + close(in[0]); + close(in[1]); + } + #else if (servermode != THREADED) close(in); + #endif exit(-1); } else if (servermode == THREADED) { #if defined(USE_THREADS) && defined(HAVE_PTHREAD_H) *************** *** 739,745 **** --- 1022,1035 ---- #endif afd = S5InvalidIOHandle; } else { + #ifdef SUPPORT_IPV6 + if (servermode == SINGLESHOT) { + CLOSESOCKET(in[0]); + CLOSESOCKET(in[1]); + } + #else if (servermode == SINGLESHOT) CLOSESOCKET(in); + #endif DoWork(afd); } } Index: server/tcp.c diff -c src/socks5/server/tcp.c:1.1.1.5 src/socks5/server/tcp.c:1.9.2.3 *** server/tcp.c Thu Aug 5 13:21:07 1999 --- server/tcp.c Thu Aug 5 17:50:53 1999 *************** *** 67,72 **** --- 67,75 ---- } } + #ifdef SUPPORT_IPV6 + res = SubstituteAddress(pri->peerReserved, res, &pri->bndAddr, &tmp); + #endif if (!lsSendResponse(tcpinfo->iio.fd, &tcpinfo->iio, res, pri->peerVersion, (pri->peerVersion == SOCKS5_VERSION)?s5error:s4error, pri->nextReserved, NULL)) return 0; S5LogUpdate(S5LogDefaultHandle, S5_LOG_WARNING, 0, "TCP Sending Response failed"); return -1; *************** *** 76,82 **** --- 79,89 ---- /* protocol necessary (via RRconnect), get our peer's name, and then send */ /* that info back to the client...(dumb?)... */ static int TcpConnect(S5LinkInfo *pri, TcpInfo *tcpinfo, u_char *s5ep, u_char *s4ep) { + #ifdef SUPPORT_IPV6 + int len = sizeof(S5NetAddr); + #else int len = sizeof(ssi); + #endif if (pri->nextVersion) { if (S5SExchangeProtocol(&tcpinfo->iio, &tcpinfo->oio, pri, tcpinfo->idtentry, &pri->dstAddr, &pri->intAddr) < 0) { *************** *** 266,271 **** --- 273,281 ---- /* We need to check first that the accepted address (pri->dstAddr) */ /* matches the requested address (wtdaddr). */ if (lsAddrAddrComp(&pri->dstAddr, &wtdaddr) != 0) { + #ifdef SUPPORT_IPV6 + struct in6_addr dummy_for_inetpton; + #endif /* People are not happy with this checking because it breaks */ /* round robin DNS entries... */ if (pri->dstAddr.sa.sa_family == AF_INET && *************** *** 294,299 **** --- 304,336 ---- MUTEX_UNLOCK(gh_mutex); S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(15), MSGID_SERVER_TCP_ACCEPT_AUTH, "TCP Accepted the host(%s:%d) has multiple IP", pri->dstName, (int)ntohs(lsAddr2Port(&pri->dstAddr))); } + #ifdef SUPPORT_IPV6 + } else if (pri->dstAddr.sa.sa_family == AF_INET6 && + (pri->retName[0] != '\0' && + inet_pton(AF_INET6, pri->retName, &dummy_for_inetpton) != 0)) { + struct hostent *hp; + int i; + + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "TCP Accepted: Checking round robin DNS entries"); + + if (!pri->nextVersion && !(hp = lsGetHostByName(pri->retName, AF_INET6))) { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), MSGID_SERVER_TCP_ACCEPT_AUTH, "TCP Accepted authorization failed for host: %s:%d", pri->dstName, (int)ntohs(lsAddr2Port(&pri->dstAddr))); + *s5ep = SOCKS5_AUTHORIZE; + return EXIT_AUTH; + } + + for (i = 0; hp->h_addr_list[i]; i++) { + if (!memcmp((char *)&pri->dstAddr.sin6.sin6_addr, + hp->h_addr_list[i], sizeof(struct in6_addr))) break; + } + + if (!hp->h_addr_list[i]) { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), MSGID_SERVER_TCP_ACCEPT_AUTH, "TCP Accepted assuming the host(%s:%d) has multiple IP", pri->dstName, (int)ntohs(lsAddr2Port(&pri->dstAddr))); + } else { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(15), MSGID_SERVER_TCP_ACCEPT_AUTH, "TCP Accepted the host(%s:%d) has multiple IP", pri->dstName, (int)ntohs(lsAddr2Port(&pri->dstAddr))); + } + lsFreeHostent(hp); + #endif /* SUPPORT_IPV6 */ } else { S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), MSGID_SERVER_TCP_ACCEPT_AUTH, "TCP Accepted authorization failed for host: %s:%d", pri->dstName, (int)ntohs(lsAddr2Port(&pri->dstAddr))); *s5ep = SOCKS5_AUTHORIZE; *************** *** 388,393 **** --- 425,433 ---- int turnon = 1, rval = EXIT_ERR; u_char s5error = SOCKS5_FAIL, s4error = SOCKS_FAIL; TcpInfo *tcpinfo = NULL; + #ifdef SUPPORT_IPV6 + int o_af; + #endif if (ResolveNames(linkinfo) < 0) { s5error = SOCKS5_BADADDR; *************** *** 421,427 **** --- 461,473 ---- } /* Make the socket we'll use for the server side... */ + #ifdef SUPPORT_IPV6 + o_af = linkinfo->nextVersion ? + linkinfo->sckAddr.sa.sa_family : linkinfo->dstAddr.sa.sa_family; + if ((tcpinfo->oio.fd = socket(o_af, SOCK_STREAM,0)) == S5InvalidIOHandle) { + #else if ((tcpinfo->oio.fd = socket(AF_INET, SOCK_STREAM,0)) == S5InvalidIOHandle) { + #endif S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "TCP Setup: Socket() failed: %m"); goto cleanup; } *************** *** 480,486 **** --- 526,545 ---- return EXIT_OK; cleanup: + #ifdef SUPPORT_IPV6 + if (rval != EXIT_NETERR) { + S5NetAddr *res; + S5NetAddr tmp; + + res = SubstituteAddress(linkinfo->peerReserved, + &linkinfo->dstAddr, &linkinfo->bndAddr, &tmp); + lsSendResponse(ioinfo->fd, ioinfo, res, linkinfo->peerVersion, + (linkinfo->peerVersion == SOCKS5_VERSION)?s5error:s4error, + 0, NULL); + } + #else if (rval != EXIT_NETERR) lsSendResponse(ioinfo->fd, ioinfo, &linkinfo->dstAddr, linkinfo->peerVersion, (linkinfo->peerVersion == SOCKS5_VERSION)?s5error:s4error, 0, NULL); + #endif if (tcpinfo != NULL) { tcpinfo->exitval = EXIT_ERR; Index: server/tracer.c diff -c src/socks5/server/tracer.c:1.1.1.3 src/socks5/server/tracer.c:1.5.4.2 *** server/tracer.c Thu Apr 1 11:04:43 1999 --- server/tracer.c Wed Apr 7 14:36:14 1999 *************** *** 37,43 **** --- 37,87 ---- static int Popen(S5LinkInfo *pri, PTInfo *ptinfo) { S5IOHandle pds[2]; + #ifdef SUPPORT_IPV6 + int dest_af = pri->nextVersion ? + pri->sckAddr.sa.sa_family :pri->dstAddr.sa.sa_family; + char *exec_prog = NULL; + #endif + + #ifdef SUPPORT_IPV6 + if (dest_af == AF_INET && pri->peerCommand == SOCKS_TRACER) { + #ifndef TROUTEPROG + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "%s: No real program to exec", CommandName(pri)); + return -1; + #else + exec_prog = TROUTEPROG; + #endif + } + if (dest_af == AF_INET6 && pri->peerCommand == SOCKS_TRACER) { + #ifndef TROUTE6PROG + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "%s: No real program to exec", CommandName(pri)); + return -1; + #else + exec_prog = TROUTE6PROG; + #endif + } + if (dest_af == AF_INET && pri->peerCommand != SOCKS_TRACER) { + #ifndef PINGPROG + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "%s: No real program to exec", CommandName(pri)); + return -1; + #else + exec_prog = PINGPROG; + #endif + } + if (dest_af == AF_INET6 && pri->peerCommand != SOCKS_TRACER) { + #ifndef PING6PROG + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "%s: No real program to exec", CommandName(pri)); + return -1; + #else + exec_prog = PING6PROG; + #endif + } + if (exec_prog == NULL) { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "%s: Unknown command", CommandName(pri)); + return -1; + } + #else /* SUPPORT_IPV6 */ #ifndef TROUTEPROG if (pri->peerCommand == SOCKS_TRACER) { S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "%s: No real program to exec", CommandName(pri)); *************** *** 51,56 **** --- 95,101 ---- return -1; } #endif + #endif /* SUPPORT_IPV6 */ if (pipe(pds) < 0) { S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "%s pipe failed: %m", CommandName(pri)); *************** *** 73,78 **** --- 118,143 ---- if (dup2(pds[1], STDERR_FILENO) < 0) _exit(-1); close(pds[1]); + #ifdef SUPPORT_IPV6 + if ((pri->peerCommand == SOCKS_TRACER)) { + int verbose = pri->peerReserved & SOCKS5_FLAG_VERBOSE; + int noname = pri->peerReserved & SOCKS5_FLAG_NONAME; + + if (pri->nextVersion) { + if (noname) execlp(exec_prog, "traceroute", "-n", (verbose?"-v":pri->sckName), verbose?pri->sckName:NULL, NULL); + else execlp(exec_prog, "traceroute", (verbose?"-v":pri->sckName), verbose?pri->sckName:NULL, NULL); + } else { + if (noname) execlp(exec_prog, "traceroute", "-n", (verbose?"-v":pri->dstName), verbose?pri->dstName:NULL, NULL); + else execlp(exec_prog, "traceroute", (verbose?"-v":pri->dstName), verbose?pri->dstName:NULL, NULL); + } + } + + #ifdef PINGPROG + if (!(pri->peerCommand == SOCKS_TRACER)) { + execlp(exec_prog, "ping", pri->dstName, NULL); + } + #endif + #else /* SUPPORT_IPV6 */ #ifdef TROUTEPROG if ((pri->peerCommand == SOCKS_TRACER)) { int verbose = pri->peerReserved & SOCKS5_FLAG_VERBOSE; *************** *** 93,99 **** execlp(PINGPROG, "ping", pri->dstName, NULL); } #endif ! _exit(0); } --- 158,164 ---- execlp(PINGPROG, "ping", pri->dstName, NULL); } #endif ! #endif /* SUPPORT_IPV6 */ _exit(0); } *************** *** 108,114 **** --- 173,183 ---- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "%s Using proxy (version %d) %s:%d", CommandName(pri), (int)pri->nextVersion, ADDRANDPORT(&pri->sckAddr)); + #ifdef SUPPORT_IPV6 + if ((ptinfo->oio.fd = socket(pri->sckAddr.sa.sa_family, SOCK_STREAM, 0)) == S5InvalidIOHandle) { + #else if ((ptinfo->oio.fd = socket(AF_INET, SOCK_STREAM, 0)) == S5InvalidIOHandle) { + #endif S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "%s socket failed: %m", CommandName(pri)); return -1; } *************** *** 228,233 **** --- 297,305 ---- int PTSetup(S5IOInfo *ioinfo, S5LinkInfo *linkinfo, S5CommandInfo *cinfo) { int turnon = 1, rval = EXIT_ERR; PTInfo *ptinfo = NULL; + #ifdef SUPPORT_IPV6 + S5NetAddr *res, tmp; + #endif if (ResolveNames(linkinfo) < 0) { goto cleanup; *************** *** 291,297 **** --- 363,375 ---- S5LogUpdate(S5LogDefaultHandle, S5_LOG_INFO, MSGID_SERVER_PT_ESTAB, "%s Proxy Established: (%s to %s) for user %s", CommandName(linkinfo), linkinfo->srcName, linkinfo->dstName, linkinfo->srcUser); + #ifdef SUPPORT_IPV6 + res = SubstituteAddress(linkinfo->peerReserved, &linkinfo->dstAddr, + &linkinfo->bndAddr, &tmp); + if (lsSendResponse(ptinfo->iio.fd, &ptinfo->iio, res, linkinfo->peerVersion, 0, 0, NULL) < 0) { + #else if (lsSendResponse(ptinfo->iio.fd, &ptinfo->iio, &linkinfo->dstAddr, linkinfo->peerVersion, 0, 0, NULL) < 0) { + #endif S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Client closed connection"); rval = EXIT_NETERR; goto cleanup; *************** *** 304,310 **** --- 382,396 ---- return EXIT_OK; cleanup: + #ifdef SUPPORT_IPV6 + if (rval != EXIT_NETERR) { + res = SubstituteAddress(linkinfo->peerReserved, &linkinfo->dstAddr, + &linkinfo->bndAddr, &tmp); + lsSendResponse(ioinfo->fd, ioinfo, res, linkinfo->peerVersion, 1, 0, NULL); + } + #else if (rval != EXIT_NETERR) lsSendResponse(ioinfo->fd, ioinfo, &linkinfo->dstAddr, linkinfo->peerVersion, 1, 0, NULL); + #endif if (ptinfo != NULL) { ptinfo->exitval = EXIT_ERR; Index: server/udp.c diff -c src/socks5/server/udp.c:1.1.1.7 src/socks5/server/udp.c:1.8.2.3 *** server/udp.c Thu Aug 5 13:21:07 1999 --- server/udp.c Thu Aug 5 17:50:53 1999 *************** *** 93,101 **** --- 93,111 ---- /* do we need this ???? */ S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "UDP Command: Doing USECLIENTPORT command"); + #ifdef SUPPORT_IPV6 if (!lsAddrAddrComp(&pri->dstAddr, &pri->srcAddr) || + (pri->dstAddr.sa.sa_family == AF_INET && + (pri->dstAddr.sin.sin_addr.s_addr == INADDR_ANY || + pri->dstAddr.sin.sin_addr.s_addr == htonl(INADDR_LOOPBACK))) || + (pri->dstAddr.sa.sa_family == AF_INET6 && + (IN6_IS_ADDR_UNSPECIFIED(&pri->dstAddr.sin6.sin6_addr) || + IN6_IS_ADDR_LOOPBACK(&pri->dstAddr.sin6.sin6_addr)))) { + #else + if (!lsAddrAddrComp(&pri->dstAddr, &pri->srcAddr) || pri->dstAddr.sin.sin_addr.s_addr == INADDR_ANY || pri->dstAddr.sin.sin_addr.s_addr == htonl(INADDR_LOOPBACK)) { + #endif pri->clientPort = lsAddr2Port(&pri->dstAddr); *err = SOCKS5_NOERR; } *************** *** 195,203 **** --- 205,220 ---- /* able to add new sub-commands */ static int HandleCommand(S5LinkInfo *pri, UdpInfo *u) { u_char cmd = 0, res = 0, s5err = SOCKS5_BADCMND; + #ifdef SUPPORT_IPV6 + S5NetAddr *re, tmp; + #endif memset((char *)&pri->intAddr, 0, sizeof(S5NetAddr)); + #ifdef SUPPORT_IPV6 + pri->intAddr.sa.sa_family = pri->srcAddr.sa.sa_family; + #else pri->intAddr.sa.sa_family = AF_INET; + #endif if (lsReadRequest(u->iio.fd, &u->iio, &pri->dstAddr, &pri->peerVersion, &cmd, &res) < 0) { S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "UDP Command: Read request command failed"); *************** *** 221,227 **** --- 238,250 ---- break; } + #ifdef SUPPORT_IPV6 + re = SubstituteAddress(pri->peerVersion, &pri->intAddr, &pri->srcAddr, + &tmp); + return lsSendResponse(u->iio.fd, &u->iio, re, pri->peerVersion, s5err, 0, NULL); + #else return lsSendResponse(u->iio.fd, &u->iio, &pri->intAddr, pri->peerVersion, s5err, 0, NULL); + #endif } /* Proxy a request for the client. This basically involves checking to see */ *************** *** 233,238 **** --- 256,264 ---- /* Arguments: sin -- the address of the person who sent the message to us */ static int RecvFromClient(S5Packet *packet, S5LinkInfo *pri, UdpInfo *u, S5NetAddr *sender) { S5Packet buf[2]; + #ifdef SUPPORT_IPV6 + int org_af; + #endif /* Make sure the client really sent this message. If not, assume it is */ /* a forgery. */ *************** *** 269,274 **** --- 295,303 ---- return -1; } + #ifdef SUPPORT_IPV6 + org_af = pri->dstAddr.sa.sa_family; + #endif if (ResolveNames(pri) < 0) { return -1; } *************** *** 279,284 **** --- 308,321 ---- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "UDP Client Receive: send failed: permission denied"); return -1; } + #ifdef SUPPORT_IPV6 + /* IPv6: If the client specified the destination address as a domain */ + /* IPv6: name (i.e. AF_S5NAME), and it has been resolved, mark the */ + /* IPv6: address. */ + if (org_af == AF_S5NAME && pri->dstAddr.sa.sa_family != AF_S5NAME) { + MarkResolved(u, &pri->dstAddr, pri->retName); + } + #endif packet->data = u->obuf + HDRSIZE(u->obuf); packet->off = u->obuflen - HDRSIZE(u->obuf); *************** *** 497,502 **** --- 534,569 ---- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "UDP Send: Sending to %s:%d", ADDRANDPORT(dst)); if (*dir == S5_DIRECTION_IN || pri->nextVersion == SOCKS5_VERSION) { + #ifdef SUPPORT_IPV6 + /* IPv6: If the client has specified this address (pri->dstAddr) as */ + /* IPv6: a domain name, convert it back to the original name so that */ + /* IPv6: the client can translate it to the correct fake address it */ + /* IPv6: has generated for the domain name. */ + S5NetAddr *rep_dst, nameaddr; + + if (WasResolved(u, &pri->dstAddr, nameaddr.sn.sn_name)) { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, + "UDP Send: Fill hostname %s in packet header", + nameaddr.sn.sn_name); + /* Don't use nameaddr.sn.sn_family -- it doesn't work if struct */ + /* sockaddr is of 4.4BSD type which has sa_len field. */ + nameaddr.sa.sa_family = AF_S5NAME; + lsAddrSetPort(&nameaddr, lsAddr2Port(&pri->dstAddr)); + rep_dst = &nameaddr; + } else { + rep_dst = &pri->dstAddr; + } + if ((alen = lsGetProtoAddrLenFromAddr(SOCKS5_VERSION, rep_dst)) < 0) { + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "UDP Send: Error filling in address in packet header"); + u->obuflen = -1; + goto end; + } + + u->obuf -= alen; + memset(u->obuf, 0, 3); + lsSetProtoAddr(SOCKS5_VERSION, u->obuf, rep_dst); + u->obuflen += HDRSIZE(u->obuf); + #else if ((alen = lsGetProtoAddrLenFromAddr(SOCKS5_VERSION, &pri->dstAddr)) < 0) { S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "UDP Send: Error filling in address in packet header"); u->obuflen = -1; *************** *** 507,512 **** --- 574,580 ---- memset(u->obuf, 0, 3); lsSetProtoAddr(SOCKS5_VERSION, u->obuf, &pri->dstAddr); u->obuflen += HDRSIZE(u->obuf); + #endif } /* Encode the packet if necessary... This includes changing obuf to */ *************** *** 535,541 **** --- 603,613 ---- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "UDP Send: Sending a message of length %d", u->obuflen); /* Send the message and log the fact that we have. */ + #ifdef SUPPORT_IPV6 + if (sendto(fd, u->obuf, u->obuflen, 0, &dst->sa, lsAddrSize(dst)) < 0) { + #else if (sendto(fd, u->obuf, u->obuflen, 0, &dst->sa, sizeof(ssi)) < 0) { + #endif S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(0), 0, "UDP Send: Sendto failed: %m"); } else if (*dir == S5_DIRECTION_OUT) { S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "UDP Send: Client Sent Message to %s:%d", ADDRANDPORT(dst)); *************** *** 560,571 **** --- 632,655 ---- S5NetAddr route; u_char s5err = SOCKS5_FAIL; UdpInfo *u = NULL; + #ifdef SUPPORT_IPV6 + S5NetAddr *res; + #endif /* The destination is really the port we'll be receiving request from */ /* it is allowed to be 0, but we take that to mean we'll be recv'ing it */ /* from the same place the tcp connection came from, different port */ if (lsAddrAddrComp(&pri->dstAddr, &pri->srcAddr) != 0) { + #ifdef SUPPORT_IPV6 + if ((pri->dstAddr.sa.sa_family == AF_INET && + pri->dstAddr.sin.sin_addr.s_addr != INADDR_ANY && + pri->dstAddr.sin.sin_addr.s_addr != htonl(INADDR_LOOPBACK)) || + (pri->dstAddr.sa.sa_family == AF_INET6 && + !IN6_IS_ADDR_UNSPECIFIED(&pri->dstAddr.sin6.sin6_addr) && + !IN6_IS_ADDR_LOOPBACK(&pri->dstAddr.sin6.sin6_addr))) { + #else if (pri->dstAddr.sin.sin_addr.s_addr != INADDR_ANY && pri->dstAddr.sin.sin_addr.s_addr != htonl(INADDR_LOOPBACK)) { + #endif s5err = SOCKS5_BADADDR; goto cleanup; } *************** *** 612,618 **** --- 696,708 ---- lsAddrSetPort(&pri->bndAddr, lsAddr2Port(&route)); + #ifdef SUPPORT_IPV6 + res = SubstituteAddress(pri->peerReserved, &pri->bndAddr, + &pri->srcAddr, &route); + if (lsSendResponse(u->iio.fd, &u->iio, res, pri->peerVersion, SOCKS5_RESULT, (pri->peerReserved & S5UDP_USECTRL)?S5UDP_USECTRL:0, NULL) < 0) { + #else if (lsSendResponse(u->iio.fd, &u->iio, &pri->bndAddr, pri->peerVersion, SOCKS5_RESULT, (pri->peerReserved & S5UDP_USECTRL)?S5UDP_USECTRL:0, NULL) < 0) { + #endif S5LogUpdate(S5LogDefaultHandle, S5_LOG_ERROR, 0, "UDP Setup: couldn't send response"); rval = EXIT_NETERR; goto cleanup; *************** *** 627,633 **** --- 717,732 ---- return EXIT_OK; cleanup: + #ifdef SUPPORT_IPV6 + if (rval != EXIT_NETERR) { + res = SubstituteAddress(pri->peerReserved, &pri->bndAddr, + &pri->srcAddr, &route); + lsSendResponse(ioinfo->fd, ioinfo, res, pri->peerVersion, + s5err, 0, NULL); + } + #else if (rval != EXIT_NETERR) lsSendResponse(ioinfo->fd, ioinfo, &pri->bndAddr, pri->peerVersion, s5err, 0, NULL); + #endif if (u != NULL) UdpCleanup(pri, u); else { Index: server/udputil.c diff -c src/socks5/server/udputil.c:1.1.1.5 src/socks5/server/udputil.c:1.6.2.2 *** server/udputil.c Thu Apr 1 11:04:42 1999 --- server/udputil.c Wed Apr 7 14:36:16 1999 *************** *** 21,26 **** --- 21,30 ---- #include "msg.h" #include "s2s.h" + #ifdef SUPPORT_IPV6 + #define SENDBACK_NAMES + #endif + /* Find out which socket we're going to be using to get to host dest... */ /* Allocate a new entry if we make a new socket to go there... */ static S5IOHandle MakeOutUdpSocket(UdpInfo *u, S5NetAddr *addr, u_short port) { *************** *** 29,35 **** --- 33,43 ---- S5IOHandle sd; S5NetAddr tmpaddr; + #ifdef SUPPORT_IPV6 + if ((sd = socket(addr->sa.sa_family, SOCK_DGRAM, 0)) == S5InvalidIOHandle) { + #else if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) == S5InvalidIOHandle) { + #endif S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "UDP socket failed for address %s:%d: %m", ADDRANDPORT(addr)); return S5InvalidIOHandle; } *************** *** 174,180 **** --- 182,192 ---- S5BufSetupContext(&sc->cinfo); u->scache = sc; + #ifdef SUPPORT_IPV6 + if ((sc->cinfo.fd = socket(sc->tcpsin.sa.sa_family, SOCK_STREAM, 0)) < 0) { + #else if ((sc->cinfo.fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + #endif S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "UDP socket failed when contacting proxy: %m"); goto error; } *************** *** 212,218 **** --- 224,234 ---- UdpSocksCache *sc, *prev = NULL; for (sc = u->scache; sc; sc = sc->next) { + #ifdef SUPPORT_IPV6 + if (lsAddrComp(tcp?&sc->tcpsin:&sc->udpsin, sckAddr) == 0) break; + #else if (ADDRCOMP((tcp?&sc->tcpsin.sin:&sc->udpsin.sin), &sckAddr->sin)) break; + #endif prev = sc; } *************** *** 345,363 **** #ifdef SENDBACK_NAMES UdpHostCache *h; char *res; if (dst->sa.sa_family != AF_INET) { return 0; } /* Find out if we looked up a name and found this address... */ for (h = u->hcache; h; h=h->next) { if (h->addr.s_addr == dst->sin_addr.s_addr) break; } if (h && strcmp(h->name, name)) { ! strncpy(name, h->name, MIN(strlen(h->name)+1, S5_HOSTNAME_LEN)); ! if (strlen(h->h_name)+1 > S5_HOSTNAME_SIZE) name[S5_HOSTNAME_SIZE-1] = '\0'; } return h?1:0; --- 361,397 ---- #ifdef SENDBACK_NAMES UdpHostCache *h; char *res; + #ifdef SUPPORT_IPV6 + int af; + #endif + #ifdef SUPPORT_IPV6 + if ((af = dst->sa.sa_family) == AF_S5NAME) { + return 0; + } + #else if (dst->sa.sa_family != AF_INET) { return 0; } + #endif /* Find out if we looked up a name and found this address... */ for (h = u->hcache; h; h=h->next) { + #ifdef SUPPORT_IPV6 + if ((af == AF_INET && (h->flags & HC_V4) && + !memcmp(&h->addr, &dst->sin.sin_addr, sizeof(h->addr))) || + (af == AF_INET6 && (h->flags & HC_V6) && + !memcmp(&h->addr6, &dst->sin6.sin6_addr, sizeof(h->addr6)))) { + break; + } + #else if (h->addr.s_addr == dst->sin_addr.s_addr) break; + #endif } if (h && strcmp(h->name, name)) { ! strncpy(name, h->name, MIN(strlen(h->name)+1, S5_HOSTNAME_SIZE)); ! if (strlen(h->name)+1 > S5_HOSTNAME_SIZE) name[S5_HOSTNAME_SIZE-1] = '\0'; } return h?1:0; *************** *** 369,380 **** --- 403,423 ---- void MarkResolved(UdpInfo *u, S5NetAddr *dst, char *name) { #ifdef SENDBACK_NAMES UdpHostCache *h; + #ifdef SUPPORT_IPV6 + int af; + #endif /* If this host wasn't resolve (we're giving the name to the next */ /* server), don't cache it, we won't be using it... */ + #ifdef SUPPORT_IPV6 + if ((af = dst->sa.sa_family) == AF_S5NAME) { + return; + } + #else if (dst->sa.sa_family != AF_INET) { return; } + #endif /* Find out if there was an entry already... */ for (h = u->hcache; h; h=h->next) { *************** *** 382,388 **** --- 425,445 ---- } if (h) { + #ifdef SUPPORT_IPV6 + if (!(h->flags & (af == AF_INET ? HC_V4 : HC_V6))) { + if (af == AF_INET) { + memcpy(&h->addr, &dst->sin.sin_addr, sizeof(h->addr)); + h->flags |= HC_V4; + } else { + memcpy(&h->addr6, &dst->sin6.sin6_addr, sizeof(h->addr6)); + h->flags |= HC_V6; + } + } else { + return; + } + #else return; + #endif } if (!(h = (UdpHostCache *)malloc(sizeof(UdpHostCache)))) { *************** *** 391,397 **** --- 448,464 ---- } strcpy(h->name, name); + #ifdef SUPPORT_IPV6 + if (af == AF_INET) { + h->flags = HC_V4; + memcpy(&h->addr, &dst->sin.sin_addr, sizeof(h->addr)); + } else { + h->flags = HC_V6; + memcpy(&h->addr6, &dst->sin6.sin6_addr, sizeof(h->addr6)); + } + #else h->addr = dst->sin.sin_addr; + #endif h->next = u->hcache; u->hcache = h; #endif Index: server/udputil.h diff -c src/socks5/server/udputil.h:1.1.1.3 src/socks5/server/udputil.h:1.3.2.1 *** server/udputil.h Thu Apr 1 11:04:42 1999 --- server/udputil.h Wed Apr 7 14:36:16 1999 *************** *** 54,59 **** --- 54,65 ---- struct hinfo { char name[MAXHOSTNAMELEN]; struct in_addr addr; + #ifdef SUPPORT_IPV6 + struct in6_addr addr6; + int flags; + #define HC_V4 1 + #define HC_V6 2 + #endif struct hinfo *next; }; Index: server/validate.c diff -c src/socks5/server/validate.c:1.1.1.4 src/socks5/server/validate.c:1.10.2.4 *** server/validate.c Thu Apr 1 11:04:49 1999 --- server/validate.c Fri Aug 20 14:23:51 1999 *************** *** 31,36 **** --- 31,39 ---- char type; int calloced; struct in_addr ifaddr; + #ifdef SUPPORT_IPV6 + struct in6_addr ifaddr6; + #endif struct intfc *ifp; }; *************** *** 148,153 **** --- 151,160 ---- /* val -- a ptr to the address we are looking up...(out) */ static int lsGetHostOrIntfc(char **ptr, struct sroute *val) { struct in_addr guess; + #ifdef SUPPORT_IPV6 + char buf[INET6_ADDRSTRLEN]; + int af; + #endif char *tmp, tc; int i, j; *************** *** 161,167 **** --- 168,181 ---- SKIPNONSPACE(tmp); tc = *tmp; *tmp = '\0'; + #ifdef SUPPORT_IPV6 + if (inet_pton((af = AF_INET), *ptr, &guess) <= 0 && + inet_pton((af = AF_INET6), *ptr, &val->ifaddr6) <= 0 && + (lsExtractEnclosedAddr(*ptr, buf) == NULL || + inet_pton((af = AF_INET6), buf, &val->ifaddr6) <= 0)) { + #else if ((guess.s_addr = inet_addr(*ptr)) == INVALIDADDR) { + #endif val->type = NAME; val->ifp = NULL; *************** *** 177,182 **** --- 191,211 ---- val->ifp->name[15] = '\0'; val->calloced = 1; } + #ifdef SUPPORT_IPV6 + } else if (af == AF_INET6) { + val->type = IN6_ADDR; + val->ifp = NULL; + for (i = 0; i < ifcnt; i++) { + for (j = 0; j < intfcs[i].addr6cnt; j++) { + if (!memcmp(&intfcs[i].addr6list[j].ip, &val->ifaddr6, + sizeof(struct in6_addr))) break; + } + if (j < intfcs[i].addr6cnt) { + val->ifp = &intfcs[i]; + break; + } + } + #endif } else { val->type = IN_ADDR; val->ifaddr.s_addr = guess.s_addr; *************** *** 445,456 **** --- 474,497 ---- entry->nextver = (i == SOCKS5_IND)?SOCKS5_VERSION:SOCKS4_VERSION; + #ifdef SUPPORT_IPV6 + for (i = 0; i < S5_SERVER_NUM - 1 && *tmp && *tmp != '\n'; i++, tmp++) { + int n; + if ((n = lsGetHostAddressAndPort(&tmp, &entry->nextaddr[i])) < 0) { + badline(entry->realline, "server address"); + } + if (n == 2) i++; + #else for (i = 0; i < S5_SERVER_NUM && *tmp && *tmp != '\n'; i++, tmp++) { if (lsGetHostAddressAndPort(&tmp, &entry->nextaddr[i]) < 0) badline(entry->realline, "server address"); + #endif if ((port = lsAddr2Port(&entry->nextaddr[i])) == INVALIDPORT || port == (u_short)0) { if (!socksport && lsName2Port("socks", "tcp", &socksport) < 0) socksport = htons(SOCKS_DEFAULT_PORT); lsAddrSetPort(&entry->nextaddr[i], socksport); + #ifdef SUPPORT_IPV6 + if (n == 2) lsAddrSetPort(&entry->nextaddr[i - 1], socksport); + #endif } SKIPSPACE(tmp); *************** *** 602,608 **** --- 643,659 ---- /* if dst == LOOPBACK => AUTH_FAIL... */ /* if src is one of the next proxy => AUTH_FAIL (avoid looping)... */ if (pri->peerCommand != SOCKS_UDP && !lsAddrComp(&pri->srcAddr, &pri->dstAddr)) return AUTH_FAIL; + #ifdef SUPPORT_IPV6 + if (getenv("SOCKS5_NOLOOPBACKCHECK") == NULL && + ((pri->dstAddr.sa.sa_family == AF_INET && + pri->dstAddr.sin.sin_addr.s_addr == htonl(INADDR_LOOPBACK)) || + (pri->dstAddr.sa.sa_family == AF_INET6 && + IN6_IS_ADDR_LOOPBACK(&pri->dstAddr.sin6.sin6_addr)))) { + return AUTH_FAIL; + } + #else if (pri->dstAddr.sin.sin_addr.s_addr == htonl(INADDR_LOOPBACK)) return AUTH_FAIL; + #endif for (i = 0; i < pri->nAltSckAddrs; i++) { if (!lsAddrComp(&pri->srcAddr, &pri->altSckAddrs[i])) return AUTH_FAIL; *************** *** 686,696 **** --- 737,756 ---- struct intaddr tmpaddr; struct ifreq ifr; int i, j, k = 0; + #ifdef SUPPORT_IPV6 + int dst_af = dst->sa.sa_family; + #endif memset((char *)&ifr, 0, sizeof(struct ifreq)); for (i = 0; i < ifcnt; i++) { + #ifdef SUPPORT_IPV6 + if ((dst_af == AF_INET && intfcs[i].addrcnt == 0) || + (dst_af == AF_INET6 && intfcs[i].addr6cnt == 0) || + intfcs[i].up != 1 || intfcs[i].type == 1) { + #else if (intfcs[i].addrcnt == 0 || intfcs[i].up != 1 || intfcs[i].type == 1) { + #endif /* not an IP interface... */ if (intfcs[i].up == 1 && intfcs[i].type != 1) continue; *************** *** 700,705 **** --- 760,771 ---- /* the interface is up now. Find the address and mask, and */ /* check if the dst is on the same subnet ... */ + #ifdef SUPPORT_IPV6 + if (dst_af == AF_INET6) { + lsRefreshIntfcAddr6(&intfcs[i]); + goto next; + } + #endif if (lsLookupIntfc(S5InvalidIOHandle, NET_ADDR, &ifr) < 0) continue; if (ifssi(ifr)->sin_family != AF_INET) continue; tmpaddr.ip = ifssi(ifr)->sin_addr; *************** *** 715,720 **** --- 781,801 ---- continue; } + #ifdef SUPPORT_IPV6 + next: + if (dst_af == AF_INET6) { + if (intfcs[i].addr6cnt > 0 && + IN6_IS_ADDR_LOOPBACK(&intfcs[i].addr6list[0].ip)) continue; + for (j = 0; j < intfcs[i].addr6cnt; j++) { + /* on the same subnet... */ + if (lsCheckIfc6(&intfcs[i].addr6list[j], + &dst->sin6.sin6_addr)) { + addr->sin6.sin6_addr = intfcs[i].addr6list[j].ip; + k++; + } + } + } else { + #endif /* loopback interface ... */ if (intfcs[i].addrlist[0].ip.s_addr == htonl(INADDR_LOOPBACK)) continue; *************** *** 728,733 **** --- 809,817 ---- k++; } } + #ifdef SUPPORT_IPV6 + } + #endif } return k; *************** *** 769,776 **** --- 853,866 ---- } #define REALDEST(x) ((x)->sa.sa_family == AF_INET && (x)->sin.sin_addr.s_addr != INVALIDADDR && (x)->sin.sin_addr.s_addr != INADDR_ANY) + #ifdef SUPPORT_IPV6 + #define REALDEST6(x) ((x)->sa.sa_family == AF_INET6 && !IN6_IS_ADDR_UNSPECIFIED(&(x)->sin6.sin6_addr)) + if (proxyList[i].nextver && !REALDEST(&proxyList[i].nextaddr[0]) && + !REALDEST6(&proxyList[i].nextaddr[0])) { + #else if (proxyList[i].nextver && !REALDEST(&proxyList[i].nextaddr[0])) { + #endif S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Proxy: Line %d: Invalid server address", proxyList[i].realline); continue; } *************** *** 790,806 **** --- 880,938 ---- return -1; } + #ifdef SUPPORT_IPV6 + static void MostGeneralAddr6(struct intfc *ifc, struct in6_addr *addr) { + struct intaddr6 *list = ifc->addr6list; + int len = ifc->addr6cnt; + int i; + #define IS_ADDR_GLOBAL(x) (((x)->s6_addr[0] & 0xe0) == 0x20) + /* IPv6: Most preferable address is an aggregatable global unicast one. */ + /* IPv6: Then comes unassigned address, followed by IPv4 compatible */ + /* IPv6: address and site-local address. */ + for (i = 0; i < len; i++) { + if (IS_ADDR_GLOBAL(&list[i].ip)) goto found; + } + for (i = 0; i < len; i++) { + if (!IN6_IS_ADDR_MULTICAST(&list[i].ip) && + !IN6_IS_ADDR_V4COMPAT(&list[i].ip) && + !IN6_IS_ADDR_SITELOCAL(&list[i].ip) && + !IN6_IS_ADDR_LINKLOCAL(&list[i].ip)) { + goto found; + } + } + for (i = 0; i < len; i++) { + if (IN6_IS_ADDR_V4COMPAT(&list[i].ip)) goto found; + } + for (i = 0; i < len; i++) { + if (IN6_IS_ADDR_SITELOCAL(&list[i].ip)) goto found; + } + for (i = 0; i < len; i++) { + if (!IN6_IS_ADDR_MULTICAST(&list[i].ip)) goto found; + } + i = 0; + found: + *addr = list[i].ip; + } + #endif + /* Determine the outbound address for a given destination */ /* If not route does match, default will by any interface */ int GetRoute(const S5NetAddr *dst, const char *name, char *proto, S5NetAddr *addr) { struct ifreq ifr; int i; + #ifdef SUPPORT_IPV6 + int dst_af = dst->sa.sa_family; + #endif memset((char *)&ifr, 0, sizeof(struct ifreq)); /* If we return before we change this, there was an error... */ memset((char *)addr, 0, sizeof(S5NetAddr)); + #ifdef SUPPORT_IPV6 + addr->sa.sa_family = dst_af; + #else addr->sin.sin_family = AF_INET; + #endif /* If dst is loopback, the route will be loopback.... */ if (dst->sa.sa_family != AF_S5NAME && !lsAddrIsNull(dst)) { *************** *** 831,837 **** --- 963,976 ---- /* If the interface is not up when the daemon started or the interface */ /* has multiple addresses, get the current active address... otherwise */ /* we are done... */ + #ifdef SUPPORT_IPV6 + if (routeList[i].nexthop.ifp->type == 1 || + routeList[i].nexthop.ifp->up <= 0 || + (dst_af == AF_INET && routeList[i].nexthop.ifp->addrcnt != 1) || + (dst_af == AF_INET6 && routeList[i].nexthop.ifp->addr6cnt == 0)) { + #else if (routeList[i].nexthop.ifp->type == 1 || routeList[i].nexthop.ifp->up <= 0 || routeList[i].nexthop.ifp->addrcnt != 1) { + #endif strcpy(ifr.ifr_name, routeList[i].nexthop.ifp->name); if (lsLookupIntfc(S5InvalidIOHandle, NET_STAT, &ifr) <= 0) { *************** *** 839,844 **** --- 978,989 ---- continue; } + #ifdef SUPPORT_IPV6 + if (dst_af == AF_INET6) { + lsRefreshIntfcAddr6(routeList[i].nexthop.ifp); + goto check6; + } + #endif if (lsLookupIntfc(S5InvalidIOHandle, NET_ADDR, &ifr) < 0 || ifssi(ifr)->sin_family != AF_INET) { S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Route: Line %d: Invalid interface address", routeList[i].realline); continue; *************** *** 846,860 **** --- 991,1033 ---- addr->sin.sin_addr = ifssi(ifr)->sin_addr; break; + #ifdef SUPPORT_IPV6 + } else if (dst_af == AF_INET) { + if (routeList[i].nexthop.ifp->addrcnt == 0) continue; + addr->sin.sin_family = AF_INET; + addr->sin.sin_addr = routeList[i].nexthop.ifp->addrlist[0].ip; + break; + } else { + check6: + if (routeList[i].nexthop.ifp->addr6cnt == 0) continue; + addr->sin6.sin6_family = AF_INET6; + MostGeneralAddr6(routeList[i].nexthop.ifp, + &addr->sin6.sin6_addr); + break; + } + #else } else if (routeList[i].nexthop.ifp->addrcnt == 0) continue; else { addr->sin.sin_addr = routeList[i].nexthop.ifp->addrlist[0].ip; break; } + #endif + #ifdef SUPPORT_IPV6 + } else if (dst_af == AF_INET6 && + routeList[i].nexthop.type == IN6_ADDR) { + addr->sin6.sin6_addr = routeList[i].nexthop.ifaddr6; + break; + } else if (dst_af == AF_INET && + routeList[i].nexthop.type == IN_ADDR) { + addr->sin.sin_addr = routeList[i].nexthop.ifaddr; + break; + } + #else } else { addr->sin.sin_addr = routeList[i].nexthop.ifaddr; break; } + #endif } if (i < nrlines) { *************** *** 933,935 **** --- 1106,1173 ---- S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "Filter: No line matched"); return -1; } + + #ifdef SUPPORT_IPV6 + S5NetAddr *SubstituteAddress(int flags, const S5NetAddr *addr, const S5NetAddr *defaddr, S5NetAddr *buf) { + int af = defaddr->sa.sa_family; + int i, j; + + if (flags & SOCKS5_FLAG_IPV4V6) return addr; + if (addr->sa.sa_family == af) return addr; + + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, + "SubstituteAddress: convert %s to %s", + lsAddr2Ascii(addr), (af == AF_INET) ? "AF_INET" : "AF_INET6"); + + if (addr->sa.sa_family == AF_INET && af == AF_INET6) { + const struct in_addr *p = &addr->sin.sin_addr; + + for (i = 0; i < ifcnt; i++) { + struct intaddr *iap = intfcs[i].addrlist; + int cnt = intfcs[i].addrcnt; + for (j = 0; j < cnt; j++) { + if (!memcmp(p, &iap[j].ip, sizeof(struct in_addr))) { + if (intfcs[i].addr6cnt == 0) goto notfound; + memset(buf, 0, sizeof(*buf)); + buf->sin6.sin6_family = AF_INET6; + buf->sin6.sin6_port = lsAddr2Port(addr); + MostGeneralAddr6(&intfcs[i], &buf->sin6.sin6_addr); + goto found; + } + } + } + } else if (addr->sa.sa_family == AF_INET6 && af == AF_INET) { + const struct in6_addr *p = &addr->sin6.sin6_addr; + + for (i = 0; i < ifcnt; i++) { + struct intaddr6 *iap = intfcs[i].addr6list; + int cnt = intfcs[i].addr6cnt; + for (j = 0; j < cnt; j++) { + if (!memcmp(p, &iap[j].ip, sizeof(struct in6_addr))) { + if (intfcs[i].addrcnt == 0) goto notfound; + memset(buf, 0, sizeof(*buf)); + buf->sin.sin_family = AF_INET; + buf->sin.sin_port = lsAddr2Port(addr); + buf->sin.sin_addr = intfcs[i].addrlist[0].ip; + goto found; + } + } + } + } + + notfound: + /* Copy defaddr */ + lsAddrCopy(buf, defaddr, lsAddrSize(defaddr)); + /* Reset port number */ + lsAddrSetPort(buf, lsAddr2Port(addr)); + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, + "SubstituteAddress: conversion failed. use default (%s)", + lsAddr2Ascii(buf)); + return buf; + + found: + S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, + "SubstituteAddress: convert to %s", lsAddr2Ascii(buf)); + return buf; + } + #endif Index: server/validate.h diff -c src/socks5/server/validate.h:1.1.1.3 src/socks5/server/validate.h:1.3.2.1 *** server/validate.h Thu Apr 1 11:04:49 1999 --- server/validate.h Wed Apr 7 14:36:17 1999 *************** *** 21,25 **** extern int GetRoute P((const S5NetAddr *, const char *, char *, S5NetAddr *)); extern int GetProxy P((const S5NetAddr *, const char *, char *, S5NetAddr *, int *, u_char *)); extern int GetFilter P((S5LinkInfo *, char *)); ! #endif --- 21,27 ---- extern int GetRoute P((const S5NetAddr *, const char *, char *, S5NetAddr *)); extern int GetProxy P((const S5NetAddr *, const char *, char *, S5NetAddr *, int *, u_char *)); extern int GetFilter P((S5LinkInfo *, char *)); ! #ifdef SUPPORT_IPV6 ! extern S5NetAddr *SubstituteAddress P((int, const S5NetAddr *, const S5NetAddr *, S5NetAddr *)); ! #endif #endif Index: test/socks5-debug diff -c /dev/null src/socks5/test/socks5-debug:1.1.2.1 *** test/socks5-debug Fri Aug 20 14:27:23 1999 --- test/socks5-debug Fri Nov 27 11:59:13 1998 *************** *** 0 **** --- 1,24 ---- + #! /bin/sh + # $Id: socks5-debug,v 1.1.2.1 1998/11/27 02:59:13 ishisone Exp $ + # Run socks5 applications with debug mode turned on. + # + # Usage: socks5-debug [-d LEVEL] command [args..] + # + # ex) socks5-debug -d 10 rtelnet some.where.net + # socks5-debug runsocks ftp getit.org + # + + # default debug level. + LEVEL=5 + + if [ X$1 = X-d ]; then + shift + LEVEL=$1 + shift + fi + + # Setup enviroment variables controlling debug mode. + SOCKS5_DEBUG=$LEVEL + SOCKS5_LOG_STDERR=1 + export SOCKS5_DEBUG SOCKS5_LOG_STDERR + exec ${1+"$@"} Index: utils/mk_shared_libinet6_for_kame diff -c /dev/null src/socks5/utils/mk_shared_libinet6_for_kame:1.1.2.3 *** utils/mk_shared_libinet6_for_kame Fri Aug 20 14:27:24 1999 --- utils/mk_shared_libinet6_for_kame Fri Jan 22 14:35:29 1999 *************** *** 0 **** --- 1,118 ---- + #! /bin/sh + # $Id: mk_shared_libinet6_for_kame,v 1.1.2.3 1999/01/22 05:35:29 ishisone Exp $ + # + # This file is for KAME IPv6 implementation. + # + # This little shell script is to create shared version of libinet6, + # and recompile network applications such as telnet to use the shared + # library. + # + # The shared libinet6 and recompilation of those applications are + # necessary for "runsocks" command to work properly. + # + # Usage: mk_shared_libinet6_for_kame kame-kit-dir + # + # where "kame-kit-dir" is a top directory (kit) of KAME distribution, + # such as /usr/src/kame/kit. + # + # If you have any problem, please feel free to contact + # socks5-bugs@syl.dl.nec.com. + # + + if [ $# -ne 1 ]; then + echo "Usage: $0 kame-kit-dir" + echo " kame-kit-dir is a top directory (kit) of KAME distribution," + echo " such as '/usr/src/kame/kit'." + exit 1 + fi + + KAMEROOT=$1 + + # Make sure you're a super-user. + if [ `id -u` != 0 ]; then + echo 'You must be a super-user to run this script.' + exit 1 + fi + + # Make sure KAMEROOT is correct. + if [ ! -f $KAMEROOT/Makefile.kit ]; then + echo 'Please specify correct path to KAME kit directory, as in:' + echo " $0 /usr/src/kame/kit" + exit 1 + fi + + echo '***' + echo '*** Building libinet6.so..' + echo '***' + + cd $KAMEROOT/src/libinet6 + + # Make sure patch isn't applied yet. + if [ -f Makefile.orig ]; then + echo "Makefile.orig detected. Have you run this script before?" + echo "Normally you do not have to run twice." + echo -n "If you want to rebuild the library, type 'go': " + read ans + if [ $ans != go ]; then + echo 'good bye.' + exit 0 + fi + echo "Okay, skip applying patch." + else + + patch << 'EOF' + *** Makefile.org Wed Sep 2 09:43:24 1998 + --- Makefile Fri Oct 23 10:43:37 1998 + *************** + *** 29,34 **** + --- 29,37 ---- + # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + # SUCH DAMAGE. + + + SHLIB_MAJOR=1 + + SHLIB_MINOR=0 + + + .if exists(${.CURDIR}/../Makefile.opsys) + .include "${.CURDIR}/../Makefile.opsys" + .endif + EOF + + fi + + make + + echo '***' + echo '*** Installing libinet6.so..' + echo '***' + make install + + echo '***' + echo '*** Adding /usr/local/v6/lib to the shared library search path..' + echo '*** (only temporarily)' + echo '***' + ldconfig -m /usr/local/v6/lib + + echo '***' + echo '*** Rebuilding network applications..' + echo '***' + cd ../../usr.bin + make clean + make + + echo '***' + echo '*** Re-installing network applications..' + echo '***' + make install + + echo '*** Done.' + + echo + echo '** IMPORTANT NOTICE **' + echo + echo '/usr/local/v6/lib is added to the shared library search path' + echo 'only temporarily by this script. You have to make it permanent,' + echo "or you'll lose it after rebooting the system." + echo + echo 'To make it permanent, you should edit /etc/rc.conf and add' + echo '/usr/local/v6/lib to the variable "ldconfig_paths", like:' + echo ' ldconfig_paths="/usr/lib/compat /usr/X11R6/lib /usr/local/lib /usr/local/v6/lib"'