Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 16 Jul 1999 09:54:50 +0200 (CEST)
From:      Andre Albsmeier <andre.albsmeier@mchp.siemens.de>
To:        FreeBSD-gnats-submit@freebsd.org
Subject:   ports/12660: Fix for gethostbyname2() problem when using socks5
Message-ID:  <199907160754.JAA16398@internal>

next in thread | raw e-mail | index | archive | help

>Number:         12660
>Category:       ports
>Synopsis:       Fix for gethostbyname2() problem when using socks5
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-ports
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Fri Jul 16 01:00:01 PDT 1999
>Closed-Date:
>Last-Modified:
>Originator:     Andre Albsmeier
>Release:        FreeBSD 3.2-STABLE i386
>Organization:
>Environment:

FreeBSD (any version), socks5 from the ports and a program that uses
gethostbyname2() (fetch, whois,...)

>Description:

When trying to socksify (with runsocks) a program that uses gethostbyname2(),
sometimes the program fails. This is due to the following reason:

1. the program calls gethostbyname2() which is not socksified
2. gethostbyname2() starts his work and calls other functions
   that are socksified (e.g. sendto)
3. sendto (from the sockslib) now starts its work and, as part of
   that, itself does a gethostbyname().
4. gethostbyname() from libc does nothing more than calling gethostbyname2().
5. Now we have entered gethostbyname2() again and that fails...


>How-To-Repeat:

As I said above, the program not always fails. I can make it fail
here when I have only one nameserver in /etc/resolv.conf. With three
nameservers (even if they are the same), it works. I could make
it fail by running "runsocks whois blahblah" with only one
nameserver in /etc/resolv.conf.

>Fix:
	
I have tried to implement the gethostbyname2() call the same way as
gethostbyname() is done in the sockslib. In case socks5 is configured to
fake DNS calls, we call the daemon if the af argument is AF_INET. If
we don't fake DNS calls, we call the original gethostbyname2() function.


*** ./lib/rld.c.ORI	Thu Jul 15 21:48:13 1999
--- ./lib/rld.c	Thu Jul 15 21:34:27 1999
***************
*** 183,188 ****
--- 183,203 ----
      return hp;
  }
  
+ struct hostent *REAL(gethostbyname2)(const char *name, int af) {
+     struct hostent *hp;
+     static void *func = NULL;
+ 
+     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "RLD: gethostbyname2: %s %d", name, af);
+     GetOriginalFunc(&func, "_gethostbyname2", TRY_LIBC | TRY_LIBNSL | TRY_LIBRESOLV);
+     if (!func || func == (void *)-1) return NULL;
+ 
+     lsInRLDFunctions = 1;
+     hp = ((struct hostent *(*)P((const char *, int)))func)(name, af);
+     lsInRLDFunctions = 0;
+     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "RLD: gethostbyname2 results: %s %s", name, hp?hp->h_name:"???");
+     return hp;
+ }
+ 
  int REAL(getpeername) (S5IOHandle sd, ss *sa, int *slen) {
      GETFUNC("_getpeername", TRY_LIBC | TRY_LIBSOCKET,  -1, (int (*)P((S5IOHandle, ss *, int *))),                            (sd, sa, slen), int);
  }
*** ./lib/hostname.c.ORI	Thu Jul 15 21:48:52 1999
--- ./lib/hostname.c	Thu Jul 15 21:43:28 1999
***************
*** 312,317 ****
--- 312,409 ----
      return &h;
  }
  
+ /* wrapper around the gethostbyname2 call.                                   */
+ /* similar to gethostbyname2() except for:                                   */
+ /* *** if gethostbyname2() fails, then it returns a pointer to a hostent     */
+ /*     structure filled with a special value, so that SOCKSxxxxxx() will     */
+ /*     realize that this host was unresolved and fill in the protocol        */
+ /*     accordingly...                                                        */
+ /*                                                                           */
+ /* 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];
+     static char	my_name[MAXNAMELEN], *my_aliases[S5_HOSTALIASES_SIZE+1];
+     static struct hostent h;
+     struct hostent *hp;
+     char *local, *fake;
+     int hlen, i;
+ 
+ #ifdef FOR_SHARED_LIBRARY
+     if (lsInRLDFunctions || lsInWrapFunction || lsInWrapHostname) return REAL(gethostbyname2)(name,af);
+ #endif
+ 
+     lsInWrapFunction = 1;
+     lsInWrapHostname = 1;
+     LIBPREFIX2(init)("libsocks5");
+     S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "SOCKS gethostbyname2: looking up %s", name);
+ 
+     fake  = getenv("SOCKS5_FAKEALLHOSTS");
+     local = getenv("SOCKS5_LOCALDNSONLY");
+ 
+     if (!fake && (hp = REAL(gethostbyname2)(name,af)) != NULL) {
+ 	S5LogUpdate(S5LogDefaultHandle, S5_LOG_DEBUG(10), 0, "SOCKS gethostbyname2: REAL: %s", inet_ntoa(*(struct in_addr *)hp->h_addr));
+ 
+         hlen = MIN(strlen(hp->h_name)+1, sizeof(my_name));
+         strncpy(my_name, hp->h_name, hlen);
+         if (hlen == sizeof(my_name)) my_name[hlen-1] = '\0';
+ 
+ 	HostentCopy(my_addr_list, my_aliases, hp);
+ 
+     	h.h_name      = my_name;
+     	h.h_aliases   = my_aliases;
+     	h.h_addrtype  = hp->h_addrtype;
+     	h.h_length    = hp->h_length;
+     	h.h_addr_list = (char **)my_addr_list;
+ 	
+         lsInWrapFunction = 0;
+         lsInWrapHostname = 0;
+ 	return &h;
+     }
+ 
+     /* 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 gethostbyname2: REAL: Fake not configured");
+         lsInWrapFunction = 0;
+         lsInWrapHostname = 0;
+ 	return NULL;
+     }
+ 
+     /* The daemon can only do AF_INET */
+     if (af != AF_INET) {
+         h_errno = NO_RECOVERY;
+         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 gethostbyname2: Get fake host failed");
+         lsInWrapFunction = 0;
+         lsInWrapHostname = 0;
+         return NULL;
+     }
+ 
+     hlen = MIN(strlen(name)+1, sizeof(my_name));
+     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]));
+     lsInWrapFunction = 0;
+     lsInWrapHostname = 0;
+     return &h;
+ }
+ 
  int lsGetCachedAddress(const char *name, S5NetAddr *na) {
      int i;
      char hostname[256];
*** ./include/hide.h.ORI	Thu Jul 15 21:47:22 1999
--- ./include/hide.h	Thu Jul 15 06:18:39 1999
***************
*** 16,21 ****
--- 16,22 ----
  /* Try to hide these functions so we don't get compiler pukage.              */
  #define HIDE(x)       _hidden_ ## x
  #define gethostbyname HIDE(gethostbyname)
+ #define gethostbyname2 HIDE(gethostbyname2)
  #define getpeername   HIDE(getpeername)
  #define getsockname   HIDE(getsockname)
  #define accept        HIDE(accept)
***************
*** 48,53 ****
--- 49,55 ----
  /* Unhide these functions so we can deal with them now that includes are     */
  /* done...Hopefully...                                                       */
  #undef gethostbyname 
+ #undef gethostbyname2
  #undef getpeername   
  #undef getsockname   
  #undef accept        
*** ./include/socks.h.ORI	Thu Jul 15 21:47:39 1999
--- ./include/socks.h	Thu Jul 15 06:19:27 1999
***************
*** 50,55 ****
--- 50,56 ----
  extern int LIBPREFIX(select)      P((int, fd_set *, fd_set *, fd_set *, struct timeval *));
  
  extern struct hostent *LIBPREFIX(gethostbyname) P((char *));
+ extern struct hostent *LIBPREFIX(gethostbyname2) P((char *, int));
  #endif /* include prototypes */
  
  #ifndef LIBPREFIX
***************
*** 89,94 ****
--- 90,96 ----
  #endif
  
  #define gethostbyname LIBPREFIX(gethostbyname)
+ #define gethostbyname2 LIBPREFIX(gethostbyname2)
  #define rresvport     LIBPREFIX(rresvport)
  #define connect       LIBPREFIX(connect)
  #define listen        LIBPREFIX(listen)
*** ./include/system.h.ORI	Thu Jul 15 21:47:57 1999
--- ./include/system.h	Thu Jul 15 06:19:48 1999
***************
*** 22,27 ****
--- 22,28 ----
  #define LIBPREFIX(x)  x
  
  struct hostent * REAL(gethostbyname) P((const char *));
+ struct hostent * REAL(gethostbyname2) P((const char *, int));
  struct hostent * REAL(gethostbyaddr) P((const void *, int, int));
  struct servent * REAL(getservbyname) P((const char *, const char *)); 
  

>Release-Note:
>Audit-Trail:
>Unformatted:


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-ports" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199907160754.JAA16398>