printf the IP address used to send a datagram

How do I fetch the source IP address used out of a simple transmission?  For instance, if my UDP client code is:

int main(int argc, char *argv[])
{
   int sock, length, fromlen, n;
   struct sockaddr_in server;
   struct sockaddr_in from;
   char buf[1024];

   if (argc < 2) {
      fprintf(stderr, "ERROR, no port provided\n");
      exit(0);
   }
   
   sock=socket(AF_INET, SOCK_DGRAM, 0);
   if (sock < 0) error("Opening socket");
   length = sizeof(server);
   bzero(&server,length);
   server.sin_family=AF_INET;
   server.sin_addr.s_addr=INADDR_ANY;
   server.sin_port=htons(atoi(argv[1]));
   if (bind(sock,(struct sockaddr *)&server,length)<0)
       error("binding");
   fromlen = sizeof(struct sockaddr_in);
   while (1) {
       n = recvfrom(sock,buf,1024,0,(struct sockaddr *)&from,&fromlen);
       if (n < 0) error("recvfrom");
       write(1,"Received a datagram: ",21);
       write(1,buf,n);
       n = sendto(sock,"Got your message\n",17,
                  0,(struct sockaddr *)&from,fromlen);
       if (n  < 0) error("sendto");
   }
 }

How do I printf the IP address I used in sending the datagram as a string (not the destination address)?

Thanks!
LVL 1
jchristn123Asked:
Who is Participating?
 
jkrConnect With a Mentor Commented:
You can use 'getsockname()' after 'bind()' to learn the address and the port that has been assigned to it ('gethostbyname()' might return an incorrect one, since one machine can have multiple interfaces), i.e.

struct sockaddr sa;

getsockname(sock,&sa,sizeof(sa));
ptintf("Local IP for sending: %s\n",inet_ntoa((struct sockaddr_in*)&sa)->sin_addr);
0
 
Infinity08Commented:
You could simply use gethostname to get your machine's host name :

        char hostname[256] = { 0 };
        gethostname(hostname, sizeof(hostname));

Which you can then convert using gethostbyname to get the IP address(es) for the hostname :

        struct hostent *host = gethostbyname(hostname);

The hostent struct contains these fields :

        (a) h_name (char*) : the main name of the host
        (b) h_aliases (char**) : an array (null terminated) of alternate names of the host
        (c) h_addrtype (int) : the type of the address (probably AF_INET)
        (d) h_length (int) : the length of the address (in bytes)
        (e) h_addr_list (char**) : an array (null terminated) of IP addresses for the host (in network byte order)
        (f) h_addr (char*) : the first IP address in the h_addr_list array

So, you can get the first IP address assigned to the host like this :

        printf("IP Address = %s\n", inet_ntoa(*((struct in_addr *) h->h_addr)));
0
 
Infinity08Commented:
That last line should have been :

        printf("IP Address = %s\n", inet_ntoa(*((struct in_addr *) host->h_addr)));

of course.
0
Cloud Class® Course: Certified Penetration Testing

This CPTE Certified Penetration Testing Engineer course covers everything you need to know about becoming a Certified Penetration Testing Engineer. Career Path: Professional roles include Ethical Hackers, Security Consultants, System Administrators, and Chief Security Officers.

 
Infinity08Commented:
Oh, and when it comes to socket programming, I've always liked this guide :

        http://beej.us/guide/bgnet/

("Beej's Guide to Network Programming - Using Internet Sockets")
0
 
Infinity08Commented:
>> ('gethostbyname()' might return an incorrect one, since one machine can have multiple interfaces)

Oh, I guess I misunderstood. jchristn123, do you need the address of the interface that was used to send the message ? Or just the local address of the machine ? In the former case, follow jkr's advice, in the latter, follow mine :)
0
 
jchristn123Author Commented:
Thanks for the help thus far.  I tried jkr's solution as follows:

            getsockname(connectionId,&myIPaddr,sizeof(myIPaddr));
            sprintf(myIP,"%s",(inet_ntoa((struct sockaddr_in*)&myIPaddr)->sin_addr));
            printf("MY IP=%s\n",myIP);

and I'm getting the following on compile:

warning: passing argument 3 of 'getsockname' makes pointer from integer without a cast
error: incompatible type for argument 1 of 'inet_ntoa'
error: request for member 'sin_addr' in something not a structure or union

Any thoughts?
0
 
jkrCommented:
Sorry, my fault - make that

int namelen = sizeof(myIPaddr);

            getsockname(connectionId,&myIPaddr,&namelen);
            sprintf(myIP,"%s",(inet_ntoa((struct sockaddr_in*)&myIPaddr)->sin_addr));
            printf("MY IP=%s\n",myIP);
0
 
Infinity08Commented:
You probably also want to change the second line to :

            sprintf(myIP,"%s", inet_ntoa(((struct sockaddr_in*)&myIPaddr)->sin_addr));
0
 
jchristn123Author Commented:
Hi infinity08 and jkr,

I changed the code accordingly:

            myIPaddrlen=sizeof(myIPaddr);
            getsockname(connectionId,&myIPaddr,&myIPaddrlen);
            sprintf(myIP,"%s",inet_ntoa(((struct sockaddr_in*)&myIPaddr)->sin_addr));
            printf("MY IP=%s\n",myIP);

Which compiled fine (thank you!)

When I run the code, I get:

MY IP=0.0.0.0

Any thoughts?

Thanks!

0
 
jkrCommented:
What do you get if you use

int result = getsockname(connectionId,&myIPaddr,&myIPaddrlen);

if (0 != result) {

  printf("Error on 'getsockname()': %d\n", result);
}

?
0
 
jchristn123Author Commented:
Hi jkr,

It does not print the error message:

            myIPaddrlen=sizeof(myIPaddr);
            myIPaddrresult=getsockname(connectionId,&myIPaddr,&myIPaddrlen);
            if (0 != myIPaddrresult) {
              printf("ERROR on 'getsockname'\n");
            }
            
            sprintf(myIP,"%s",inet_ntoa(((struct sockaddr_in*)&myIPaddr)->sin_addr));
            printf("MY IP=%s\n",myIP);

Thanks
0
 
jkrCommented:
What does

            sprintf(myIP,"%s (namelen == %d, sizeof(struct sockaddr) == %d, sizeof(struct sockaddr_in) == %d)",inet_ntoa(((struct sockaddr_in*)&myIPaddr)->sin_addr), myIPaddrlen,sizeof(struct sockaddr), sizeof(struct sockaddr_in));

give?
0
 
jchristn123Author Commented:
Hi jkr:

MY IP=0.0.0.0 (namelen == 16, sizeof(struct sockaddr) == 16, sizeof(struct sockaddr_in) == 16)
0
 
Infinity08Commented:
It might be normal since this is UDP ... maybe it only works for TCP ?

Btw, are you running this code AFTER setting up the connection ? If not, then you should.
0
 
jchristn123Author Commented:
Hi infinity08,

I am indeed doing this after setting up the connection.

Thanks
0
 
Infinity08Commented:
Can you try it with a TCP connection - just to see if it makes a difference ?
0
 
jchristn123Author Commented:
Hi infinity08,

I'll be offline for the next few hours but will definitely try it later today.  In the meantime, anything else you can think of (or anyone else)?

Thanks!
0
 
Infinity08Commented:
I'll think about it ...
0
 
Infinity08Connect With a Mentor Commented:
To summarize, here are a few thoughts :

1) It might be because it's UDP. Did you try with a TCP connection ? And what was the result ? If this is WinSock (ie. on Windows), then getsockname will always return 0.0.0.0 for UDP (it's a feature, not a bug ;) )

2) You already said you did, but you NEED to do a successful connect (or bind or accept) first, before doing the getsockname. Otherwise, the name will not be set.
Was the connect successful ?

3) Are you connecting to a different machine ? Or are you using the loopback interface (localhost or 127.0.0.1) ?
0
 
Infinity08Commented:
>> If this is WinSock (ie. on Windows), then getsockname will always return 0.0.0.0 for UDP (it's a feature, not a bug ;) )

Reference for that :

http://support.microsoft.com/kb/129065

So, if you're working with WinSock, that would explain it ...
0
 
jchristn123Author Commented:
What about jkr's suggestion - might it work - any thoughts before I try?  I prefer to get the IP of the interface that will be used, but assuming routing in the network is working (and the interfaces are reachable) I guess it really doesn't matter WHICH IP I use.

I tried for TCP and your suggestion did work infinity08.  
0
 
Infinity08Commented:
>> What about jkr's suggestion - might it work - any thoughts before I try?

What suggestion are you referring to ?


>> I prefer to get the IP of the interface that will be used

Are you using Windows ?


>> I guess it really doesn't matter WHICH IP I use.

Not really - except for debugging purposes maybe.


>> I tried for TCP and your suggestion did work infinity08.  

It was just meant as a test, so it's probably no use to you for your application (you probably need UDP).
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.