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
[EMAIL PROTECTED]

_______________________________________________
[EMAIL PROTECTED] mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-net
To unsubscribe, send any mail to "[EMAIL PROTECTED]"

Reply via email to