Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 22 Oct 2003 19:53:10 -0700
From:      Lev Walkin <vlm@netli.com>
To:        Edwin Groothuis <edwin@mavetju.org>
Cc:        freebsd-net@freebsd.org
Subject:   Re: UDP connect: Can't assign requested address or "how todetermine the outgoing IP address?"
Message-ID:  <3F974296.9040304@netli.com>
In-Reply-To: <20031023023146.GA34131@k7.mavetju>
References:  <20031023023146.GA34131@k7.mavetju>

next in thread | previous in thread | raw e-mail | index | archive | help
Edwin Groothuis wrote:
> Hello,
> 
> I got a nice piece of code (see attachment) which could be used to
> determine the outgoing IP address for an UDP socket. It works without
> problem under Linux, but it fails on FreeBSD (-current and -stable)
> during the call to connect() with the error: "Can't assign requested
> address". The code looks like the udpcli09.c example in Richard
> Stevens 'Unix Network Programming' book, which states it doesn't
> work on SVR4 derived kernels.
> 
> So, the question is, how can I determine the outgoing IP address
> for a socket?

Everything's fine apart from one thing: connect() does not like to
connect to places with destination port equal to zero.

> attached code can be compiled with "gcc -Wall -g -o a a.c && ./a"
> 
> 
> 
> ------------------------------------------------------------------------
> 
> #include <sys/types.h>
> #include <sys/socket.h>
> #include <netinet/in.h>
> #include <errno.h>
> #include <netdb.h>
> #include <string.h>
> #include <stdio.h>
> #include <unistd.h>
> #include <stdlib.h>
> 
> int guess_local_address(char *address_to_reach,char **loc);
> 
> int main(void) {
>     char *loc;
> 
>     guess_local_address("218.185.88.1",&loc);printf("%s\n",loc);
>     guess_local_address("192.168.1.3",&loc);printf("%s\n",loc);
>     guess_local_address("127.0.0.1",&loc);printf("%s\n",loc);
>     return 0;
> }
> 
> int guess_local_address(char *address_to_reach,char **loc){
>     int s,err;
>     struct addrinfo hints;
>     struct addrinfo *res=NULL;
>     struct sockaddr addr;
>     int sock;
> 	
>     *loc=NULL;
> 
>     printf("Trying %s: ",address_to_reach);
> 	
>     memset(&hints,0,sizeof(hints));
>     hints.ai_family=PF_UNSPEC;
>     hints.ai_socktype=SOCK_DGRAM;
>     hints.ai_flags=AI_NUMERICHOST|AI_CANONNAME;
> 	
>     err=getaddrinfo(address_to_reach,NULL,&hints,&res);
>     if (err<0){
> 	printf("getaddrinfo: %s\n",gai_strerror(err));
> 	return -1;
>     }
>     if (res==NULL){
> 	printf("getaddrinfo reported nothing !");
> 	return -1;
>     }
>     sock=socket(res->ai_family,SOCK_DGRAM,0);
>     if (err<0){
> 	printf("Error in socket: %s\n",strerror(errno));
> 	return -1;
>     }
>     {
> 	struct sockaddr_in servaddr;
> 	memset(&servaddr,sizeof(servaddr),0);
> 	servaddr.sin_family=AF_INET;
> 	servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
> 	servaddr.sin_port=htons(0);
> 	err=bind(sock,(struct sockaddr *)&servaddr,sizeof(servaddr));
> 	if (err<0){
> 		printf("Error in bind: %s\n",strerror(errno));
> 		return -1;
> 	}
>     }
>     s=1;
>     err=setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&s,sizeof(int));
>     if (err<0){
> 	printf("Error in setsockopt: %s\n",strerror(errno));
> 	return -1;
>     }

/*
  * This will do. Note that it assumes AF_INET.
  */
((struct sockaddr_in *)res->ai_addr)->sin_port = htons(80);

>     err=connect(sock,res->ai_addr,res->ai_addrlen);
>     if (err<0) {
> 	printf("Error in connect: %s\n",strerror(errno));
> 	return -1;
>     }
>     freeaddrinfo(res);
>     res=NULL;
>     s=sizeof(addr);
>     err=getsockname(sock,(struct sockaddr*)&addr,&s);
>     if (err<0) {
> 	printf("Error in getsockname: %s\n",strerror(errno));
> 	return -1;
>     }
>     *loc=malloc(30);
>     err=getnameinfo(&addr,s,*loc,30,NULL,0,NI_NUMERICHOST);
>     if (err<0){
> 	printf("getnameinfo error:%s",strerror(errno));
> 	return -1;
>     }
>     close(sock);
>     return 0;
> }
> 


-- 
Lev Walkin
vlm@netli.com



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