如何从接口ip地址获取接口索引

发布于 2024-08-24 08:01:40 字数 140 浏览 8 评论 0原文

谁能告诉我如何从接口IP地址获取接口索引? 例如,如果接口 IP 地址是 192.168.23.25,那么它的接口索引是多少。

我想补充一点,我需要在用 c 编写的代码中使用它,所以如果有任何函数 通过一些选项可以给我基于的接口索引号 接口IP地址。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

怂人 2024-08-31 08:01:40

您应该能够使用 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() 功能。由于您将能够将地址与接口名称关联起来,因此您可以根据需要调用它们。

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.

绾颜 2024-08-31 08:01:40

你不能这样做,你必须查看所有接口,然后循环所有 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;
}

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;
}
彼岸花似海 2024-08-31 08:01:40

以编程方式使用 if_nametoindex()。我已经在 Ubuntu 12.04(内核 3.11.0-15-generic)上验证了这一点。

下面是示例代码片段,

#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

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
终陌 2024-08-31 08:01:40

您可以简单地使用 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

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
北恋 2024-08-31 08:01:40

你可以用这个:它将列出 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;
}

我从这里得到它。

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.

最美的太阳 2024-08-31 08:01:40

注意:我刚刚注意到OP要求使用C解决方案。我很抱歉。然而,由于 intergoogles 在我的搜索短语前面明确包含 bash 时将我发送到这里(并且因为我已经输入了所有这些内容),所以我希望人们不介意我将其留在这里。如果我有时间,我稍后会把它变成要点,看看是否可以在这里删除它。

我有一个相对简单的解决方案,可以使用 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
    }
  ]
}

此方法将自动使用辅助地址和 IPv6只需更改命令中给出的 IP 地址即可地址。

此外,如果您只知道要查找的地址的一个子字符串,则只需进行细微调整即可找到该子字符串。它不如按子网过滤那么有用,但有时可能会有所帮助。

chris@anglesey:~$ ip -json addr show | jq '.[] | select(.addr_info[].local | contains("192.168.1")) | .ifindex'

输出:

60

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
二手情话 2024-08-31 08:01:40

SIOCGIFCONF 不会削减使用添加的辅助 IP 地址

ip addr add 192.168.25.23/24 dev eth1

如果您确实需要这样做,那么看看“ip addr sh”使用的任何内容 - 可能是一个 netlink 套接字操作(其中涉及非常奇怪的宏)

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)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文