代码改变世界

Get local ip in C on linux

2012-07-14 00:13  Rollen Holt  阅读(1583)  评论(0编辑  收藏  举报

The local ip is the source ip in IP packets send out from a system. The kernal maintains routing tables which it uses to decide the default gateway , its interface and the local ip configured for that interface. The /proc/net/route file (not really a file but appears like one) has more information about it.

A typical /proc/net/route output would look like :

1 cat /proc/net/route
2 Iface   Destination     Gateway         Flags   RefCnt  Use     Metric  Mask            MTU     Window  IRTT                                                      
3 eth0    0000A8C0        00000000        0001    0       0       1       00FFFFFF        0       0       0                                                                              
4 eth0    0000FEA9        00000000        0001    0       0       1000    0000FFFF        0       0       0                                                                           
5 eth0    00000000        0100A8C0        0003    0       0       0       00000000        0       0       0

The above lists the interface , destination , gateway etc. The interface (Iface) whose destination is 00000000 is the interface of the default gateway.

Now have a look at the route command output

1 $ route -n
2 Kernel IP routing table
3 Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
4 192.168.0.0     0.0.0.0         255.255.255.0   U     1      0        0 eth0
5 169.254.0.0     0.0.0.0         255.255.0.0     U     1000   0        0 eth0
6 0.0.0.0         192.168.0.1     0.0.0.0         UG    0      0        0 eth0

Now the gateway for the destination 0.0.0.0 is the default gateway. So from the /proc/net/route output this line is of interest :

1 eth0    00000000        0100A8C0        0003    0       0       0       00000000        0       0       0

Its destination is 00000000 and gateway is 0100A8C0. The gateway is actually the IP address of the gateway in hex format in reverse order (little endian). Its 01.00.A8.C0 or 1.0.168.192

So by reading that line in a C program we can find out the default gateway and its interface. The IP address of this interface shall be the source ip in IP packets send out from this system.

The code for this is pretty simple as we can see :

1 FILE *f;
2 char line[100] , *p , *c;
3  
4 f = fopen("/proc/net/route" "r");
5  
6 while(fgets(line , 100 , f))
7 {
8     p = strtok(line , " \t");
9     c = strtok(NULL , " \t");
10      
11     if(p!=NULL && c!=NULL)
12     {
13         if(strcmp(c , "00000000") == 0)
14         {
15             printf("Default interface is : %s \n" , p);
16             break;
17         }
18     }
19 }

The above code prints : “Default interface is : eth0″

Now we need to get the ip address of the default interface eth0. The getnameinfo function can be used for this.
Sample code is found here.

Combining that with our previous code we get :

1 /*
2  * Find local ip used as source ip in ip packets.
3  * Read the /proc/net/route file
4  */
5  
6 #include<stdio.h> //printf
7 #include<string.h>    //memset
8 #include<errno.h> //errno
9 #include<sys/socket.h>
10 #include<netdb.h>
11 #include<ifaddrs.h>
12 #include<stdlib.h>
13 #include<unistd.h>
14  
15 int main ( int argc , char *argv[] )
16 {
17     FILE *f;
18     char line[100] , *p , *c;
19      
20     f = fopen("/proc/net/route" "r");
21      
22     while(fgets(line , 100 , f))
23     {
24         p = strtok(line , " \t");
25         c = strtok(NULL , " \t");
26          
27         if(p!=NULL && c!=NULL)
28         {
29             if(strcmp(c , "00000000") == 0)
30             {
31                 printf("Default interface is : %s \n" , p);
32                 break;
33             }
34         }
35     }
36      
37     //which family do we require , AF_INET or AF_INET6
38     int fm = AF_INET;
39     struct ifaddrs *ifaddr, *ifa;
40     int family , s;
41     char host[NI_MAXHOST];
42  
43     if (getifaddrs(&ifaddr) == -1)
44     {
45         perror("getifaddrs");
46         exit(EXIT_FAILURE);
47     }
48  
49     //Walk through linked list, maintaining head pointer so we can free list later
50     for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
51     {
52         if (ifa->ifa_addr == NULL)
53         {
54             continue;
55         }
56  
57         family = ifa->ifa_addr->sa_family;
58  
59         if(strcmp( ifa->ifa_name , p) == 0)
60         {
61             if (family == fm)
62             {
63                 s = getnameinfo( ifa->ifa_addr, (family == AF_INET) ? sizeof(structsockaddr_in) : sizeof(struct sockaddr_in6) , host , NI_MAXHOST , NULL , 0 , NI_NUMERICHOST);
64                  
65                 if (s != 0)
66                 {
67                     printf("getnameinfo() failed: %s\n", gai_strerror(s));
68                     exit(EXIT_FAILURE);
69                 }
70                  
71                 printf("address: %s", host);
72             }
73             printf("\n");
74         }
75     }
76  
77     freeifaddrs(ifaddr);
78      
79     return 0;
80 }

Output

1 Default interface is : eth0
2  
3 address: 192.168.0.6

Another method is to open a connection to a remote server and call getsockname

Code

1 /*
2  * Find local ip used as source ip in ip packets.
3  * Use getsockname and a udp connection
4  */
5  
6 #include<stdio.h> //printf
7 #include<string.h>    //memset
8 #include<errno.h> //errno
9 #include<sys/socket.h>    //socket
10 #include<netinet/in.h> //sockaddr_in
11 #include<arpa/inet.h> //getsockname
12 #include<unistd.h>    //close
13  
14 int main ( int argc , char *argv[] )
15 {
16     const char* google_dns_server = "8.8.8.8";
17     int dns_port = 53;
18      
19     struct sockaddr_in serv;
20      
21     int sock = socket ( AF_INET, SOCK_DGRAM, 0);
22      
23     //Socket could not be created
24     if(sock < 0)
25     {
26         perror("Socket error");
27     }
28      
29     memset( &serv, 0, sizeof(serv) );
30     serv.sin_family = AF_INET;
31     serv.sin_addr.s_addr = inet_addr( google_dns_server );
32     serv.sin_port = htons( dns_port );
33  
34     int err = connect( sock , (const struct sockaddr*) &serv , sizeof(serv) );
35      
36     struct sockaddr_in name;
37     socklen_t namelen = sizeof(name);
38     err = getsockname(sock, (struct sockaddr*) &name, &namelen);
39          
40     char buffer[100];
41     const char* p = inet_ntop(AF_INET, &name.sin_addr, buffer, 100);
42          
43     if(p != NULL)
44     {
45         printf("Local ip is : %s \n" , buffer);
46     }
47     else
48     {
49         //Some error
50         printf ("Error number : %d . Error message : %s \n" errno strerror(errno));
51     }
52  
53     close(sock);
54      
55     return 0;
56 }

Output

1 Local ip is : 192.168.0.6