5

I want to get the eth0's IP. Here is what I've written (maybe there is a way around it?):

int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
check(sockfd > 0, "cannot create socket\n");

#define INTERFACE_NAME "eth0"
#define INTERFACE_NAME_LENGTH 4

char *opt = INTERFACE_NAME;
rc = setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, opt, INTERFACE_NAME_LENGTH);
check(rc == 0, "BINDTODEVICE failed");

struct ifreq req;
strncpy(req.ifr_name, INTERFACE_NAME, IFNAMSIZ);
rc = ioctl(sockfd, SIOCGIFADDR, (unsigned long)&req);
check(rc == 0, "SIOCGIFADDR failed");
server_ip = ((struct sockaddr_in*)&req.ifr_addr)->sin_addr.s_addr;
char str[50];
inet_ntop(AF_INET, &(server_ip), str, INET_ADDRSTRLEN);
debug("serverip: %s", str);

return sockfd;

error:
if (sockfd) close(sockfd);
exit(1); 

I get the following error:

[ERROR] (src/server/server.c:43: errno: Cannot assign requested address) SIOCGIFADDR failed

If I use the same method with wlan0, I get what I'd expected to see.

Here is the netstat output:

netstat -tulpn:

Proto | Local Address   |  PID

udp   | 0.0.0.0:16313   | 4666/dhclient   
udp   | 0.0.0.0:68      | 4687/dhclient   
udp   | 0.0.0.0:68      | 4666/dhclient 

So, I figure that I can't assign the address because of the dhclients? Why there are so many of them? and why there is one on the 16313 port?

UPD:

I added

auto eth0
iface eth0 inet static
        address 192.168.1.1
        netmask 255.255.255.0

to /etc/network/interfaces and restarted the networking and got some progress:

DEBUG src/server/server.c:50: serverip: 192.168.1.1

and then I can successfully bind the socket, but the connection dies for no reason in a couple of seconds.

staroselskii
  • 365
  • 1
  • 3
  • 16
  • 2
    I think you need a `req.ifr_addr.sa_family = AF_INET` to tell the SIOCGIFADDR call what type of address you want. – Mark Plotnick Jan 09 '14 at 18:45
  • 1
    @MarkPlotnick Unfortunately, it didn't help! I used this piece of code: man7.org/linux/man-pages/man3/getifaddrs.3.html and it's said that eth0 is AF_PACKET. No idea why! – staroselskii Jan 09 '14 at 18:53
  • 1
    After seeing the updates to your question, the answer seems to be "SIOCGIFADDR will fail when there's no IP address assigned to the interface". For your new question - why does a connection fail after a few seconds - you should probably post this as a separate question. Include the output of `ifconfig` and the code that does the `connect` and transfers data. My guess: an address ending in `.1` is usually used by a router. The address you chose , 192.168.1.1, may already be in use by a router elsewhere on your network. – Mark Plotnick Jan 13 '14 at 12:40
  • @MarkPlotnick strangely enough the problem has gone away after reboot. but I'm sure it had nothing to do with a router because I haven't been connected to any. – staroselskii Jan 13 '14 at 17:50

3 Answers3

2

Since I was looking for the answer to the original question, I'll officially write up the answer that Mark Plotnick gave above as a comment based on the further research by the person posing the question:

SIOCGIFADDR fails with errno set to EADDRNOTAVAIL if there's no address is assigned to the interface. As the original questioner discovered, to stop it from failing, set the interface's IP address.

strerror() translates EADDRNOTAVAIL to "Cannot assign requested address" which is misleading to the point of being wrong in this situation where you're reading the address, not assigning it.

don provan
  • 71
  • 4
0

I had used this code , few years back . This should help .

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <net/if.h>
#include <unistd.h>
#include <arpa/inet.h>

int main()
{
    int sock;
    struct ifreq ifr;

    char ifname[10] = "eth0";

    sock = socket(AF_INET, SOCK_STREAM, 0);

    //Type of address to retrieve - IPv4 IP address
    ifr.ifr_addr.sa_family = AF_INET;

    //Copy the interface name in the ifreq structure
    strncpy(ifr.ifr_name , ifname , 30);

    ioctl(sock, SIOCGIFADDR, &ifr);

    close(fd);

    //display result
    printf("%s - %s\n" , iface , inet_ntoa(( (struct sockaddr_in *)&ifr.ifr_addr )->sin_addr) );

    return 0;
}
Santhosh Pai
  • 2,535
  • 8
  • 28
  • 49
0

I want to get the eth0's IP

Use getifaddrs instead.

ifaddrs* pList = NULL;
ifaddrs* pAdapter = NULL;
ifaddrs* pAdapterFound = NULL;
const char* pszAdapterName = "eth0";
int family = AF_INET; // can be AF_INET6 if you want ipv6

int result = getifaddrs(&pList);
if (result > 0)
{
    pAdapter = pList;

    while (pAdapter)
    {
        if ((pAdapter->ifa_addr != NULL) && (pAdapter->ifa_name != NULL) && (family == pAdapter->ifa_addr->sa_family))
        {
            if (strcmp(pAdapter->ifa_name, pszAdapterName) == 0)
            {
                pAdapterFound = pAdapter;
                break;
            }
        }
        pAdapter = pAdapter->ifa_next;
    }

    if (pAdapterFound)
    {
        if (family == AF_INET)
        {
            sockaddr_in addr4 =  *(sockaddr_in*)(pAdapter->ifa_addr);
        }
        else if (family == AF_INET6)
        {
            sockaddr_in6 addr6 =  *(sockaddr_in6*)(pAdapter->ifa_addr);
        }
    }

    if (pList)
    {
        freeifaddrs(pList);
        pList = NULL;
    }
}
selbie
  • 100,020
  • 15
  • 103
  • 173