--- get_addrs.c +++ get_addrs.c 1994/02/23 12:41:31 @@ -44,11 +44,33 @@ #include #include "talk_ctl.h" +/* + * Hah. BSD folks may have thought too simple on this one. + * If you are a multihomed host, this program will miserably fail, + * as it will use the IP address of "hostname" as the source of the + * messages, not the address of the interface over which the packet + * will be routed. + * + * With Linux NET-2E, a possible solution is to perform an UDP CONNECT + * operation on a socket, so the kernel sets the correct source address + * of the socket's packets. Then we do a getsockname on that socket, + * and voila... we have the correct source address! + * + * Note that this only works with NET-2E BETA-4 and newer kernels. + */ get_addrs(my_machine_name, his_machine_name) char *my_machine_name, *his_machine_name; { struct hostent *hp; struct servent *sp; +#ifdef __linux__ + struct sockaddr_in sin; + struct sockaddr_in foo; + int sock, i; + + /* If socket fails, code will see it. */ + sock = socket(AF_INET, SOCK_DGRAM, 0); +#endif msg.pid = htonl(getpid()); /* look up the address of the local host */ @@ -81,4 +103,22 @@ exit(-1); } daemon_port = sp->s_port; +#ifdef __linux__ + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = his_machine_addr.s_addr; + sin.sin_port = sp->s_port; + + /* Now here is the trick. We connect to the other side. */ + if ((sock >= 0) && + (connect(sock, (struct sockaddr *) &sin, sizeof(sin)) == 0)) { + /* Bingo. Now fetch the address. */ + foo = sin; + i = sizeof(foo); + if (getsockname(sock, (struct sockaddr *) &foo, &i) == 0) { + my_machine_addr = foo.sin_addr; + } + } + /* Loose the socket. */ + (void) close(sock); +#endif }