ioctl通过SIOCGIFCONF获取IP地址

        SIOCGIFCONF返回接口中所有配置信息,目前该命令只在AF_INET地址族中有效。如果其他协议想使用该接口获取地址列表需要在协议初始化时去注册ioctl相关函数,下文分享该接口的使用方法、注册方法。

        获取IPV4地址的使用方法:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>


int main (int argc, const char* argv[])
{
  int socketfd;
  struct ifconf conf;
  char data[4096];
  struct ifreq *ifr;
  char addrbuf[1024];
  int i;

  printf("Opening socket...");
  socketfd = socket(AF_INET, SOCK_DGRAM, 0);
  if (socketfd >= 0) {
    printf(" OK\n");
    conf.ifc_len = sizeof(data);
    conf.ifc_buf = (caddr_t) data;
    if (ioctl(socketfd,SIOCGIFCONF,&conf) < 0) {
      perror("ioctl");
    }

    printf("Discovering interfaces...\n");
    i = 0;
    ifr = (struct ifreq*)data;
    while ((char*)ifr < data+conf.ifc_len) {
      if(ifr->ifr_addr.sa_family == AF_INET) {
            ++i;
            printf("%d. %s : %s\n", i, ifr->ifr_name, inet_ntop(ifr->ifr_addr.sa_family, &((struct sockaddr_in*)&ifr->ifr_addr)->sin_addr, addrbuf, sizeof(addrbuf)));
      }
      ifr++;
    }
    close(socketfd);
  }
  else {
    printf(" Failed!\n");
  }
  return 0;
}

       返回的数据会写入data内,按照ifreq格式去循环读取即可,获取的是所有地址列信息,所以需要判断 if(ifr->ifr_addr.sa_family == AF_INET) 来区分获取的地址类型,代码比较简单对照内核对应执行的函数看的话会更容易理解一些,如下:

//linux内核最终调用的对应接口,在所有的接口里面循环把地址等信息返回用户态
static int inet_gifconf(struct net_device *dev, char __user *buf, int len, int size)
{
	struct in_device *in_dev = __in_dev_get_rtnl(dev);
	const struct in_ifaddr *ifa;
	struct ifreq ifr;
	int done = 0;

	if (WARN_ON(size > sizeof(struct ifreq)))
		goto out;

	if (!in_dev)
		goto out;

	in_dev_for_each_ifa_rtnl(ifa, in_dev) {
		if (!buf) {
			done += size;
			continue;
		}
		if (len < size)
			break;
		memset(&ifr, 0, sizeof(struct ifreq));
		strcpy(ifr.ifr_name, ifa->ifa_label);

		(*(struct sockaddr_in *)&ifr.ifr_addr).sin_family = AF_INET;
		(*(struct sockaddr_in *)&ifr.ifr_addr).sin_addr.s_addr =
								ifa->ifa_local;

		if (copy_to_user(buf + done, &ifr, size)) {
			done = -EFAULT;
			break;
		}
		len  -= size;
		done += size;
	}
out:
	return done;
}

        register_gifconf函数是用来注册对应SIOCGIFCONF这个系统调用的一个回调函数,这个函数对于AF_INET来说就是register_gifconf(PF_INET, inet_gifconf)函数。如果需要自己注册相关函数参考即可。

         感兴趣的可以看下,调用注册函数的相关接口:

int dev_ifconf(struct net *net, struct ifconf *ifc, int size)
{
	struct net_device *dev;
	char __user *pos;
	int len;
	int total;
	int i;

	/*
	 *	Fetch the caller's info block.
	 */

	pos = ifc->ifc_buf;
	len = ifc->ifc_len;

	/*
	 *	Loop over the interfaces, and write an info block for each.
	 */

	total = 0;
	for_each_netdev(net, dev) {
		for (i = 0; i < NPROTO; i++) {
			if (gifconf_list[i]) {
				int done;
				if (!pos)
					done = gifconf_list[i](dev, NULL, 0, size);
				else
					done = gifconf_list[i](dev, pos + total,
							       len - total, size);
				if (done < 0)
					return -EFAULT;
				total += done;
			}
		}
	}

	/*
	 *	All done.  Write the updated control block back to the caller.
	 */
	ifc->ifc_len = total;

	/*
	 * 	Both BSD and Solaris return 0 here, so we do too.
	 */
	return 0;
}

    dev_ifconf函数被dev_ioctl函数调用,通用接口配置链表gifconf_list是一个装有SIOCGIFCONF注册接口的函数指针数组,对于AF_INET来说此处通过回调函数inet_gifconf得到相应的地址信息。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值