UDP connect: Can't assign requested address or "how todetermine
the outgoing IP address?"
Lev Walkin
vlm at netli.com
Wed Oct 22 19:52:10 PDT 2003
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 at netli.com
More information about the freebsd-net
mailing list