How to get interface index from interface ip addres
Can anyone tell me how to get interface index from interface ip address? e.g. If in开发者_开发知识库terface 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.
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.
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
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;
}
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
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.
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)
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
精彩评论