@Peter
I'm attaching the patch I've written again, so everyone can find it. It tries 
to find out the public IP by walkind the Interfaces available through the 
Kernel.

@Pavel
I think that such a patch should be applied, Peter just said what I wanted to 
hear :-) 

Windows just acts different in this, and wine should act exactly the same. You 
can't expect every Linux-user to specially hand-write his /etc/hosts so that 
his windows-programs/games work. :)

greetings

Am Dienstag, 13. Dezember 2005 16:57 schrieb Peter Åstrand:
> On Tue, 13 Dec 2005, Pavel Troller wrote:
> >> 127.0.0.1  localhost.localdomain   localhost       Zwirch
> >
> >  Yes, I know that *MANY* well-known distros are wrong with /etc/hosts and
> > similar files..
> >
> >  I think that it is NOT GOOD to patch wine to fix this case; it behaves
> > absolutely correctly and all the problem should be solved by correctly
> > configuring your Linux networking. Please see any good document about
> > naming principles of network interfaces.
>
> I haven't followed the whole thread, so sorry if I've missed something
> obvious, but:
>
> I think you are wrong. POSIX does not say that it's wrong to have the
> computer name associated with 127.0.0.1 in /etc/hosts, and it doesn't say
> that gethostbyname(my_name) should return a "real" IP. If I remember
> correctly, though, Microsoft, specifies that gethostbyname(my_name)
> *should* return real IP.
>
> This subtle difference means that Wine must take extra care. Fetching a
> real IP on a UNIX host is not trivial, but doable.
>
> Instead of just fetching the IP by looking up the hostname, I suggest
> using the approach below instead. It will fail if there is no route to
> 192.168.1.1 (typically this means that you don't have a default gateway).
> When this happens, you can resolv the hostname as a fallback.
>
> #include <stdio.h>
> #include <stdlib.h>
> #include <sys/socket.h>
> #include <netinet/in.h>
> #include <arpa/inet.h>
>
> int main()
> {
>      int s, c, got_sockname = 0;
>      struct sockaddr_in serv_addr;
>      struct sockaddr_in my_addr;
>      char *my_ip;
>
>      serv_addr.sin_family = AF_INET;
>      serv_addr.sin_port = htons(1);
>      /* Even better: Use the server you will connect to */
>      inet_aton("192.168.1.1", &serv_addr.sin_addr);
>
>      s = socket (PF_INET, SOCK_DGRAM, 0);
>      if (s < 0) {
>          perror("socket");
>          exit(EXIT_FAILURE);
>      }
>
>      /* connect fails if if server is unreachable, for example */
>      if ((c = connect(s, (struct sockaddr*) &serv_addr, sizeof(serv_addr)))
> >= 0) { socklen_t my_addrlen;
>          my_addrlen = sizeof(my_addr);
>          if (getsockname(s, (struct sockaddr*)&my_addr, &my_addrlen) >= 0)
> { got_sockname = 1;
>          }
>      }
>
>      if (!got_sockname)
>          /* Use 127.0.0.1 as a fallback. Even better: Resolv the
>             hostname.  */
>          inet_aton("127.0.0.1", &my_addr.sin_addr);
>
>      my_ip = inet_ntoa(my_addr.sin_addr);
>      printf("%s\n", my_ip);
>
>      return 0;
> }
>
> Regards,
Index: dlls/winsock/socket.c
===================================================================
RCS file: /home/wine/wine/dlls/winsock/socket.c,v
retrieving revision 1.203
diff -b -B -c -r1.203 socket.c
*** dlls/winsock/socket.c	12 Dec 2005 12:49:05 -0000	1.203
--- dlls/winsock/socket.c	13 Dec 2005 12:26:18 -0000
***************
*** 2927,2932 ****
--- 2927,2991 ----
      return retval;
  }
  
+ 
+ /***********************************************************************
+  *		getpublicIP		(Internal)
+  *
+  *   Tries to guess the public IP-Adress by enumerating the available Interfaces
+  *   target needs to be a buffer with the maximum size given in "size"
+  */
+ 
+ 
+ BOOL getpublicIP(char* target,int size)
+ {
+     char buff[1024];
+     char buffer[1024];
+     struct ifconf ifc;
+     struct ifreq *ifr;
+     int skfd;
+     int i;
+ 
+     skfd = socket(AF_INET, SOCK_DGRAM, 0);
+     if (skfd < 0)
+     {
+         WARN("A socket could not be created");
+         return FALSE;
+     }
+ 
+     ifc.ifc_len = sizeof(buff);
+     ifc.ifc_buf = buff;
+     if (ioctl(skfd, SIOCGIFCONF, &ifc) < 0)
+     {
+         WARN("ioctl(SIOCGIFCONF) failed");
+         close(skfd);
+         return FALSE;
+     }
+     
+     close(skfd);
+ 
+     ifr = ifc.ifc_req;
+ 
+     for (i = 0; i < ifc.ifc_len / sizeof(struct ifreq); i++)
+     {
+         struct sockaddr_in* addr=(struct sockaddr_in*)&ifr[i].ifr_addr;
+         unsigned char* ip = ((unsigned char*)&addr->sin_addr);
+ 		
+         if(strcmp(ifr[i].ifr_name,"lo")==0)continue;   /*Exclude loopback-device by Name "lo"*/
+ 		
+         if(ip[0]==127&&ip[1]==0&&ip[2]==0&&ip[3]==0)continue; /*Exclude 127.0.0.1*/
+ 		
+         sprintf(buffer,"%i.%i.%i.%i", (int)ip[0],(int)ip[1],(int)ip[2],(int)ip[3]);
+ 
+         if(size>strlen(buffer))strcpy(target,buffer);
+ 		
+         return TRUE;
+     }
+ 
+     return FALSE;
+ }
+ 
+ 
+ 
  /***********************************************************************
   *		gethostbyname		(WS2_32.52)
   */
***************
*** 2930,2937 ****
--- 2989,3000 ----
  /***********************************************************************
   *		gethostbyname		(WS2_32.52)
   */
+ 
  struct WS_hostent* WINAPI WS_gethostbyname(const char* name)
  {
+     char myname[1000];
+     struct in_addr newaddr;
+ 
      struct WS_hostent *retval = NULL;
      struct hostent*     host;
  #ifdef  HAVE_LINUX_GETHOSTBYNAME_R_6
***************
*** 2941,2946 ****
--- 3004,3012 ----
      int locerr = ENOBUFS;
  #endif
      char buf[100];
+ 
+     gethostname(myname,(size_t)1000);
+ 
      if( !name) {
          name = buf;
          if( gethostname( buf, 100) == -1) {
***************
*** 2961,2969 ****
  #else
      EnterCriticalSection( &csWSgetXXXbyYYY );
      host = gethostbyname(name);
      if (!host) SetLastError((h_errno < 0) ? wsaErrno() : wsaHerrno(h_errno));
  #endif
!     if (host) retval = WS_dup_he(host);
  #ifdef  HAVE_LINUX_GETHOSTBYNAME_R_6
      HeapFree(GetProcessHeap(),0,extrabuf);
  #else
--- 3029,3055 ----
  #else
      EnterCriticalSection( &csWSgetXXXbyYYY );
      host = gethostbyname(name);
+     
      if (!host) SetLastError((h_errno < 0) ? wsaErrno() : wsaHerrno(h_errno));
  #endif
!     if (host){
!         if(strcmp(myname,name)==0){
!             /*Replace the gotten Adress*/
!             char buffer[400];
!             if(getpublicIP(buffer,400)&&host->h_length==4)  /*Make sure that it really is an IPv4 Adress by checking h_length==4*/
!             {
!                 inet_aton(buffer,&newaddr);
!                     
!                 memcpy(((struct in_addr *)host->h_addr_list[0]),&newaddr,4);
!                     
!                 TRACE("Using %s as public Adress for local Host %s\n",inet_ntoa(*((struct in_addr *)host->h_addr_list[0])),name);
!             }else{
!                 WARN("Public IP-Adress of local Host could not be recognized");
!             }
!         }
!         
!         retval = WS_dup_he(host);
!     }
  #ifdef  HAVE_LINUX_GETHOSTBYNAME_R_6
      HeapFree(GetProcessHeap(),0,extrabuf);
  #else


Reply via email to