【发布时间】:2022-03-08 03:29:33
【问题描述】:
谁能告诉我如何从接口IP地址获取接口索引? 例如如果接口 ip 地址是 192.168.23.25 那么它的接口索引是多少。
我想补充一点,我需要在一个用 c 编写的代码中使用它,所以如果有任何函数 有一些选项可以给我基础上的接口索引号 接口ip地址。
【问题讨论】:
标签: linux networking tcp
谁能告诉我如何从接口IP地址获取接口索引? 例如如果接口 ip 地址是 192.168.23.25 那么它的接口索引是多少。
我想补充一点,我需要在一个用 c 编写的代码中使用它,所以如果有任何函数 有一些选项可以给我基础上的接口索引号 接口ip地址。
【问题讨论】:
标签: linux networking tcp
您应该可以使用getifaddrs() 执行此操作。它应该考虑到 MarkR 对二级地址的担忧。作为测试,
添加如下内容后:
ip addr add 192.168.25.23/24 dev eth0
编译和运行手册页上的示例程序应显示如下内容:
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>
您应该能够在遍历列表时获取索引,但您还可以查看if_nametoindex()、if_indextoname() 和if_nameindex() 函数。由于您可以将地址与接口名称相关联,因此您可以根据需要调用它们。
【讨论】:
以编程方式使用if_nametoindex()。我已经在 Ubuntu 12.04(内核 3.11.0-15-generic)上验证了这一点。
这里是示例代码sn-p,
#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");
}
}
}
使用示例:
$ ./if_index eth0
interface [eth0] has index : 2
另外,非编程方式是读取/proc/net/if_inet6 入口。第二列是对应的接口索引。
$ cat /proc/net/if_inet6
00000000000000000000000000000001 01 80 10 80 lo
fe800000000000000a0027fffe1a2a32 03 40 20 80 eth1
fe800000000000000a0027fffe08b9ca 02 40 20 80 eth0
【讨论】:
您不能这样做,您必须查看所有接口,然后遍历所有 IP 地址,直到找到您想要的那个。我认为这段代码可以满足您的需求。
#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;
}
【讨论】:
您可以简单地使用ip的json-Output并通过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
...
给出正确的参数:
# ip -json a s lo | jq '.[] | .ifindex'
1
# ip -json a s enp2s0 | jq '.[] | .ifindex'
2
【讨论】:
ip -json a s lo 表示 ip -json address show lo 和 ip -json a s enp2s0 表示 ip -json address show enp2s0。
你可以使用这个:。它将列出您 Linux 机器上的网络接口。
#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;
}
我是从here 那里得到的。
【讨论】:
SIOCGIFCONF 不会对使用添加的辅助 IP 地址进行删减
ip addr add 192.168.25.23/24 dev eth1
如果你真的需要这样做,那么看看“ip addr sh”使用什么 - 可能是一个 netlink 套接字操作(涉及非常奇怪的宏)
【讨论】:
注意:我刚刚注意到 OP 在 C 中要求提供解决方案。我很抱歉。但是,由于在我的搜索短语前面明确包含 bash 时,intergoogles 将我发送到这里(并且由于我已经输入了所有这些内容),我希望人们不介意我把它留在这里。如果我有时间,我会稍后把它变成一个要点,看看我是否可以在这里删除它。
我有一个适用于 shell 脚本的相对简单的解决方案。我喜欢@Oliver 的建议,但它不符合获取给定 IP 地址的接口索引的最初目标。我稍微调整了他的答案。假设我想知道哪个接口索引当前绑定到 192.168.1.96。这种方法会奏效:
chris@anglesey:~$ ip -json address show \
| jq '.[] | select(.addr_info[].local == "192.168.1.96") | .ifindex'
输出:
60
您可以通过删除 .ifindex 元素的选择来检查它是否正确,以检索 NIC 的所有 JSON:
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
}
]
}
只需更改命令中给出的 IP 地址,此方法将自动使用辅助地址和 IPv6 地址。
此外,如果您只知道要查找的地址的子字符串,则稍作调整也可以找到它。它不如能够按子网过滤有用,但有时可能会有所帮助。
chris@anglesey:~$ ip -json addr show | jq '.[] | select(.addr_info[].local | contains("192.168.1")) | .ifindex'
输出:
60
【讨论】: