LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 3603|回复: 6

如何获取系统的所有ip?[已解决]

[复制链接]
发表于 2006-1-10 20:46:57 | 显示全部楼层 |阅读模式
我只有一张网卡,但我为它绑定了多个ip地址,如
eth0 xxx.xxx.xxx.xxx
eth0:1 xxx.xxx.xxx.xxx
eth0:2 xxx.xxx.xxx.xxx
...........................
我想用程序检测出系统设置的所有ip,但没成功
帖出我的源程序
[PHP]/* file: proc_iface.c */
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <net/if.h>

int
main()
{
  struct if_nameindex * ifni, *p;

  ifni = if_nameindex ();
  if (ifni == NULL){
    perror ("if_nameindex failed");
    exit (1);
  }

  uint32_t ip;
  char ip_str[INET_ADDRSTRLEN];
  for (p = ifni; p->if_index != 0 && p->if_name != NULL; p++){
    if (getifaddr (AF_INET, p->if_index, p->if_name, &ip) == -1){
      perror ("getifaddr failed");
      if_freenameindex (ifni);
      exit (2);
    }
    printf ("Index %u,\tInterface: %s,\tIP: %s\n", p->if_index,                           
            p->if_name, inet_ntop (AF_INET, &ip, ip_str, sizeof (ip_str)));
  }
  if_freenameindex (ifni); // avoid memory leak                                          

  return 0;
}
[/PHP]
这是主程序
下面的getifaddr()的实现是从http://www.linuxsir.cn/bbs/showthread.php?t=195146
copy过来的
[PHP]/* file: getip.c */
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>

inline static int __getifaddr_ipv4(int ifindex, const char *ifname,
                                   struct in_addr *ifaddr)
{
    struct ifreq ifreq;
    int sockfd;
    int ret = -1;
    char ifn[IFNAMSIZ];
                                                                                                                                               
    if (ifindex > 0)
    {
        if (!(ifname = if_indextoname(ifindex, ifn)))
        {
            errno = ENXIO;
            return -1;
        }
    }
                                                                                                                                               
    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) >= 0)
    {
        strncpy(ifreq.ifr_name, ifname, IFNAMSIZ);
        if ((ret = ioctl(sockfd, SIOCGIFADDR, &ifreq)) >= 0)
            *ifaddr = ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr;
                                                                                                                                               
        close(sockfd);
    }
                                                                                                                                               
    return ret;
}
                                                                                                                                               
#ifdef IPV6
                                                                                                                                               
#define PROC_IFINET6_PATH   "/proc/net/if_inet6"
                                                                                                                                               
inline static int __getifaddr_ipv6(unsigned int ifindex, const char *ifname,
                                   struct in6_addr *ifaddr)
{
    FILE *fp = fopen(PROC_IFINET6_PATH, "r");
    char addrstr[INET6_ADDRSTRLEN];
    char seg[8][5];
    int index, plen, scope, flags;
    char ifn[IFNAMSIZ];
    int ret = -1;
                                                                                                                                               
    if (fp)
    {
        while (fscanf(fp, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %s\n"
                      seg[0], seg[1], seg[2], seg[3], seg[4], seg[5], seg[6],
                      seg[7], &index, &plen, &scope, &flags, ifn) != EOF)
        {
            if (ifindex == index || ifindex == 0 && strcmp(ifn, ifname) == 0)
            {
                sprintf(addrstr, "%s:%s:%s:%s:%s:%s:%s:%s", seg[0], seg[1],
                        seg[2], seg[3], seg[4], seg[5], seg[6], seg[7]);
                ret = inet_pton(AF_INET6, addrstr, ifaddr);
                goto out;
            }
        }
                                                                                                                                               
        errno = ENXIO;
out:
        fclose(fp);
    }
                                                                                                                                               
    return ret;
}
                                                                                                                                               
#endif
                                                                                                                                               
int getifaddr(int family, unsigned int ifindex, const char *ifname,
              void *ifaddr)
{
    switch (family)
    {
    case AF_INET:
        return __getifaddr_ipv4(ifindex, ifname, (struct in_addr *)ifaddr);
#ifdef IPV6
    case AF_INET6:
        return __getifaddr_ipv6(ifindex, ifname, (struct in6_addr *)ifaddr);
#endif
    default:
        errno = EAFNOSUPPORT;
        return -1;
    }
}
                                                                                                                                        [/PHP]
最后的运行结果只能显示lo和eth0两个接口及ip
其它的ip都没找出来,用ifconfig是可以看到设置成功的
不知道怎样修改程序才能达到我的目的?
 楼主| 发表于 2006-1-10 23:11:03 | 显示全部楼层
查了一下ifconfig的源码,终于搞定了
修改后的文件:
[PHP]/* file: proc_iface.c */
// Obtain all IPs of local machine
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <net/if.h>
#include <netdb.h>
#include <sys/ioctl.h>

int
main()
{
  struct if_nameindex * ifni, *p;
  int fd, numreqs = 30, n, err = -1;
  struct ifconf ifc;
  struct ifreq *ifr;

  if ((fd = socket (AF_INET, SOCK_DGRAM, 0)) < 0){
        perror ("socket");
        exit (1);
  }

  ifc.ifc_buf = NULL;
  for (;;) {
        ifc.ifc_len = sizeof (struct ifreq) * numreqs;
        ifc.ifc_buf = realloc(ifc.ifc_buf, ifc.ifc_len);

        if (ioctl (fd, SIOCGIFCONF, &ifc) < 0) {
          perror ("SIOCGIFCONF");
          goto out;
        }

        if (ifc.ifc_len == sizeof (struct ifreq) *numreqs) {
        /* assume it overflowed and try again */
          numreqs += 10;
          continue;
        }
        break;
  }
  close (fd);

  uint32_t ip;
  int i;                                                         
  char ip_str[INET_ADDRSTRLEN];
  ifr = ifc.ifc_req;
  for (i = 0, n = 0; n < ifc.ifc_len; n += sizeof(struct ifreq)) {
        if (getifaddr (AF_INET, ++i, ifr->ifr_name, &ip) == -1){
      perror ("getifaddr failed");
      exit (2);
    }

        printf ("Index: %d,\tInterface: %s,\tIP: %s\n", i,
                        ifr->ifr_name, inet_ntop (AF_INET, &ip, ip_str, sizeof (ip_str)));
        ifr++;
  }

out:
  free(ifc.ifc_buf);

  return 0;
}[/PHP]
同时,getip.c也要改一下,要注释掉tatic int __getifaddr_ipv4()中的开始的if语句,否则eth0:1等就显示不出来了,还是if_indextoname()的问题
[PHP]/* file: getip.c */
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>

inline static int __getifaddr_ipv4(int ifindex, const char *ifname,
                                   struct in_addr *ifaddr)
{
    struct ifreq ifreq;
    int sockfd;
    int ret = -1;
    char ifn[IFNAMSIZ];
                                                                                                                                               
/*
    if (ifindex > 0)
    {
        if (!(ifname = if_indextoname(ifindex, ifn)))
        {
            errno = ENXIO;
            return -1;
        }
    }
*/
                                                                                                                                               
    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) >= 0)
    {
        strncpy(ifreq.ifr_name, ifname, IFNAMSIZ);
        if ((ret = ioctl(sockfd, SIOCGIFADDR, &ifreq)) >= 0)
            *ifaddr = ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr;
                                                                                                                                               
        close(sockfd);
    }
                                                                                                                                               
    return ret;
}
                                                                                                                                               
#ifdef IPV6
                                                                                                                                               
#define PROC_IFINET6_PATH   "/proc/net/if_inet6"
                                                                                                                                               
inline static int __getifaddr_ipv6(unsigned int ifindex, const char *ifname,
                                   struct in6_addr *ifaddr)
{
    FILE *fp = fopen(PROC_IFINET6_PATH, "r");
    char addrstr[INET6_ADDRSTRLEN];
    char seg[8][5];
    int index, plen, scope, flags;
    char ifn[IFNAMSIZ];
    int ret = -1;
                                                                                                                                               
    if (fp)
    {
        while (fscanf(fp, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %s\n"
                      seg[0], seg[1], seg[2], seg[3], seg[4], seg[5], seg[6],
                      seg[7], &index, &plen, &scope, &flags, ifn) != EOF)
        {
            if (ifindex == index || ifindex == 0 && strcmp(ifn, ifname) == 0)
            {
                sprintf(addrstr, "%s:%s:%s:%s:%s:%s:%s:%s", seg[0], seg[1],
                        seg[2], seg[3], seg[4], seg[5], seg[6], seg[7]);
                ret = inet_pton(AF_INET6, addrstr, ifaddr);
                goto out;
            }
        }
                                                                                                                                               
        errno = ENXIO;
out:
        fclose(fp);
    }
                                                                                                                                               
    return ret;
}
                                                                                                                                               
#endif
                                                                                                                                               
int getifaddr(int family, unsigned int ifindex, const char *ifname,
              void *ifaddr)
{
    switch (family)
    {
    case AF_INET:
        return __getifaddr_ipv4(ifindex, ifname, (struct in_addr *)ifaddr);
#ifdef IPV6
    case AF_INET6:
        return __getifaddr_ipv6(ifindex, ifname, (struct in6_addr *)ifaddr);
#endif
    default:
        errno = EAFNOSUPPORT;
        return -1;
    }
}[/PHP]
这样就可以顺利看到所有的ip了
回复 支持 反对

使用道具 举报

 楼主| 发表于 2006-1-11 18:46:32 | 显示全部楼层
又仔细检查了一下,发现已经用不着Tetris兄的哪个程序了
[PHP]// Obtain all IPs of local machine
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <net/if.h>
#include <sys/ioctl.h>

int
main()
{
  struct if_nameindex * ifni, *p;
  int fd, numreqs = 30, n, err = -1;
  struct ifconf ifc;
  struct ifreq *ifr;

  if ((fd = socket (AF_INET, SOCK_DGRAM, 0)) < 0){
        perror ("socket");
        exit (1);
  }

  ifc.ifc_buf = NULL;
  for (;;) {
        ifc.ifc_len = sizeof (struct ifreq) * numreqs;
        ifc.ifc_buf = realloc(ifc.ifc_buf, ifc.ifc_len);

        if (ioctl (fd, SIOCGIFCONF, &ifc) < 0) {
          perror ("SIOCGIFCONF");
          goto out;
        }

        if (ifc.ifc_len == sizeof (struct ifreq) *numreqs) {
        /* assume it overflowed and try again */
          numreqs += 10;
          continue;
        }
        break;
  }
  close (fd);

  //uint32_t ip;
  int i;                                                         
  char ip_str[INET_ADDRSTRLEN];
  ifr = ifc.ifc_req;
  for (i = 0, n = 0; n < ifc.ifc_len; n += sizeof(struct ifreq), i++) {
        /*
        if (getifaddr (AF_INET, ++i, ifr->ifr_name, &ip) == -1){
      perror ("getifaddr failed");
      exit (2);
    }
        */
//ifreq结构已经有了,ip已经存放在里面了
        printf ("Index: %d,\tInterface: %s,\tIP: %s\n", i,
                        ifr->ifr_name, inet_ntop (AF_INET, &((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr, ip_str, sizeof (ip_str)));
        ifr++;
  }

out:
  free(ifc.ifc_buf);

  return 0;
}[/PHP]
回复 支持 反对

使用道具 举报

发表于 2006-1-11 19:02:46 | 显示全部楼层
问一下,怎么看ifconfig的源码?在哪个文件夹下面
回复 支持 反对

使用道具 举报

 楼主| 发表于 2006-1-11 22:06:12 | 显示全部楼层
google net-tools
回复 支持 反对

使用道具 举报

发表于 2006-1-12 09:09:10 | 显示全部楼层
尝试过了,简单实用。赞一个。
但Index输出有错。都是0
回复 支持 反对

使用道具 举报

 楼主| 发表于 2006-1-12 12:28:03 | 显示全部楼层
忘了给i递增了
其实这个index也没什么用,原来是给if_indextoname函数用的
现在用不着了
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表