Reputation: 130
Can anyone tell me how to get interface index from interface ip address? e.g. If interface ip address is 192.168.23.25 then what is it's interface index.
I want to add on that i need to use it in one code written in c so if any function with some option can give me the interface index number on the base of the interface ip address.
Upvotes: 5
Views: 26688
Reputation: 638
NOTE: I just noticed that the OP asked for a solution in C
. My apologies. However, since the intergoogles sent me here when explicitly including bash at the front of my search phrase (and since I've already typed all of this up), I hope people don't mind me leaving it here. If I have time I will turn this into a gist later and see if I can delete it here.
I have a relatively easy solution that works with shell scripts. I liked @Oliver's suggestion, but it did not meet the original goal of obtaining the interface index for a given IP address. I have tweaked his answer a bit. Suppose I want to know which interface index is currently bound to 192.168.1.96. This approach will work:
chris@anglesey:~$ ip -json address show \
| jq '.[] | select(.addr_info[].local == "192.168.1.96") | .ifindex'
output:
60
You can check that it is correct by removing the selection of the .ifindex
element to retrieve all of the JSON for the NIC:
chris@anglesey:~$ ip -json address show | jq '.[] | select(.addr_info[].local == "192.168.1.96") '
{
"ifindex": 60,
"ifname": "enx808abdbef5eb",
"flags": [
"BROADCAST",
"MULTICAST",
"UP",
"LOWER_UP"
],
"mtu": 1500,
"qdisc": "fq_codel",
"operstate": "UP",
"group": "default",
"txqlen": 1000,
"link_type": "ether",
"address": "80:8a:bd:be:f5:eb",
"broadcast": "ff:ff:ff:ff:ff:ff",
"addr_info": [
{
"family": "inet",
"local": "192.168.1.96",
"prefixlen": 24,
"broadcast": "192.168.1.255",
"scope": "global",
"dynamic": true,
"noprefixroute": true,
"label": "enx808abdbef5eb",
"valid_life_time": 71302,
"preferred_life_time": 71302
},
{
"family": "inet6",
"local": "fe80::767a:4f36:1fb0:cd0b",
"prefixlen": 64,
"scope": "link",
"noprefixroute": true,
"valid_life_time": 4294967295,
"preferred_life_time": 4294967295
}
]
}
This method will work automatically with secondary addresses and IPv6 addresses by just changing the IP address given in the command.
Also, if you only know a substring of the address you are looking for, a minor adjustment allows you to find that as well. It's not as useful as being able to filter by subnet, but it may be helpful sometimes.
chris@anglesey:~$ ip -json addr show | jq '.[] | select(.addr_info[].local | contains("192.168.1")) | .ifindex'
output:
60
Upvotes: 0
Reputation: 21
You can simply use the json-Output of ip and scan it via jq:
# ip a s
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: enp2s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
...
gives with the correct parameters:
# ip -json a s lo | jq '.[] | .ifindex'
1
# ip -json a s enp2s0 | jq '.[] | .ifindex'
2
Upvotes: 2
Reputation: 1414
Programmatically, use if_nametoindex(). I have verified this on Ubuntu 12.04 (kernel 3.11.0-15-generic).
Here is the sample code snippet,
#include <net/if.h>
#include <stdio.h>
#include <errno.h>
int main(int argc, char *argv[])
{
for (int ix=1; ix<argc; ix++)
{
unsigned int rc = if_nametoindex(argv[ix]);
if (rc) {
printf("interface [%s] has index : %d\n", argv[ix], rc);
}
else {
perror("if_nametoindex");
}
}
}
Usage example:
$ ./if_index eth0
interface [eth0] has index : 2
In addition, non-programming approach is to read /proc/net/if_inet6 entry. The second column is the corresponding interface index.
$ cat /proc/net/if_inet6
00000000000000000000000000000001 01 80 10 80 lo
fe800000000000000a0027fffe1a2a32 03 40 20 80 eth1
fe800000000000000a0027fffe08b9ca 02 40 20 80 eth0
Upvotes: 4
Reputation: 706
You can't do that, you have to look at all interfaces, then loop through all IP addresses until you find the one you want. I think this code does what you want.
#include <sys/ioctl.h>
#include <net/if.h>
#include <netinet/in.h>
#include <stdio.h>
#include <arpa/inet.h>
int main(int argc, char *argv[])
{
in_addr_t ia;
int id;
ia = inet_addr(argv[1]);
id = do_lookup(ia);
}
int do_lookup(in_addr_t ia) {
char buf[1024];
struct ifconf ifc;
struct ifreq *ifr;
int sck;
int nInterfaces;
int i;
/* Get a socket handle. */
sck = socket(AF_INET, SOCK_DGRAM, 0);
if(sck < 0)
{
perror("socket");
return -1;
}
/* Query available interfaces. */
ifc.ifc_len = sizeof(buf);
ifc.ifc_buf = buf;
if(ioctl(sck, SIOCGIFCONF, &ifc) < 0)
{
perror("ioctl(SIOCGIFCONF)");
return -1;
}
/* Iterate through the list of interfaces. */
ifr = ifc.ifc_req;
nInterfaces = ifc.ifc_len / sizeof(struct ifreq);
for(i = 0; i < nInterfaces; i++)
{
struct ifreq *item = &ifr[i];
if(((struct sockaddr_in *)&item->ifr_addr)->sin_addr.s_addr == ia) {
return i;
}
}
return -1;
}
Upvotes: 2
Reputation: 27542
You should be able to do this with getifaddrs(). It should account for MarkR's concern about secondary addresses. As a test,
After adding something like this:
ip addr add 192.168.25.23/24 dev eth0
compiling and running the example program on the man page should show something like:
lo address family: 17 (AF_PACKET)
eth0 address family: 17 (AF_PACKET)
lo address family: 2 (AF_INET)
address: <127.0.0.1>
eth0 address family: 2 (AF_INET)
address: <192.168.1.105>
eth0 address family: 2 (AF_INET)
address: <192.168.25.23>
lo address family: 10 (AF_INET6)
address: <::1>
eth0 address family: 10 (AF_INET6)
address: <fe84::82d6:baaf:fe14:4c22%eth0>
You should be able to get the index as you traverse the list but you can also additionally look at the if_nametoindex(), if_indextoname(), and if_nameindex() functions. Since you will be able to associate an address with an interface name you could just call these as appropriate.
Upvotes: 5
Reputation: 63538
SIOCGIFCONF won't cut it for secondary IP addresses added using
ip addr add 192.168.25.23/24 dev eth1
If you really need to do this, then look at whatever "ip addr sh" uses - probably a netlink socket operation (which involves really strange macros)
Upvotes: -1
Reputation: 3060
You could use this:. It will list the network interfaces on your Linux box.
#include <sys/ioctl.h>
#include <net/if.h>
#include <netinet/in.h>
#include <stdio.h>
#include <arpa/inet.h>
int main(void)
{
char buf[1024];
struct ifconf ifc;
struct ifreq *ifr;
int sck;
int nInterfaces;
int i;
/* Get a socket handle. */
sck = socket(AF_INET, SOCK_DGRAM, 0);
if(sck < 0)
{
perror("socket");
return 1;
}
/* Query available interfaces. */
ifc.ifc_len = sizeof(buf);
ifc.ifc_buf = buf;
if(ioctl(sck, SIOCGIFCONF, &ifc) < 0)
{
perror("ioctl(SIOCGIFCONF)");
return 1;
}
/* Iterate through the list of interfaces. */
ifr = ifc.ifc_req;
nInterfaces = ifc.ifc_len / sizeof(struct ifreq);
for(i = 0; i < nInterfaces; i++)
{
struct ifreq *item = &ifr[i];
/* Show the device name and IP address */
printf("%s: IP %s",
item->ifr_name,
inet_ntoa(((struct sockaddr_in *)&item->ifr_addr)->sin_addr));
/* Get the MAC address */
if(ioctl(sck, SIOCGIFHWADDR, item) < 0)
{
perror("ioctl(SIOCGIFHWADDR)");
return 1;
}
/* Get the broadcast address (added by Eric) */
if(ioctl(sck, SIOCGIFBRDADDR, item) >= 0)
printf(", BROADCAST %s", inet_ntoa(((struct sockaddr_in *)&item->ifr_broadaddr)->sin_addr));
printf("\n");
}
return 0;
}
I got it from here.
Upvotes: 0