【问题标题】:How to get interface index from interface ip addres如何从接口IP地址获取接口索引
【发布时间】:2022-03-08 03:29:33
【问题描述】:

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

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

【问题讨论】:

标签: linux networking tcp


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    以编程方式使用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
    

    【讨论】:

      【解决方案3】:

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

      【讨论】:

      • 上次查的,SIOCGIFCONF只给你每个接口的主地址;因此,具有 >1 的接口将丢失其第二个和后续地址。
      • 你是对的。他没有指明辅助地址,而且每个设备有多个地址并不常见。
      • 嘿 Paolo,您的编辑打算改变什么? API 是否发生了变化?
      【解决方案4】:

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

      【讨论】:

      • 我喜欢这种方法,但我认为最好在这些论坛中拼出命令而不是缩写它们。这样,刚接触该主题的人将能够更轻松地阅读命令并找到文档。所以这里是新手解码环(tm):ip -json a s lo 表示 ip -json address show loip -json a s enp2s0 表示 ip -json address show enp2s0
      • 我刚刚意识到这并不能回答 OP,但我仍然喜欢这种方法。如果我能想办法以这种方式回答 OP,我会发布它。
      【解决方案5】:

      你可以使用这个:。它将列出您 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 那里得到的。

      【讨论】:

        【解决方案6】:

        SIOCGIFCONF 不会对使用添加的辅助 IP 地址进行删减

        ip addr add 192.168.25.23/24 dev eth1
        

        如果你真的需要这样做,那么看看“ip addr sh”使用什么 - 可能是一个 netlink 套接字操作(涉及非常奇怪的宏)

        【讨论】:

          【解决方案7】:

          注意:我刚刚注意到 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
          

          【讨论】:

            猜你喜欢
            • 2011-09-08
            • 2010-12-26
            • 2014-05-26
            • 2012-08-02
            • 1970-01-01
            • 2011-01-18
            • 2011-11-09
            • 2013-07-28
            相关资源
            最近更新 更多