⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 if_index.c

📁 glibc 库, 不仅可以学习使用库函数,还可以学习函数的具体实现,是提高功力的好资料
💻 C
字号:
/* Copyright (C) 1997, 1998, 1999, 2000, 2002, 2003, 2004, 2005   Free Software Foundation, Inc.   This file is part of the GNU C Library.   The GNU C Library is free software; you can redistribute it and/or   modify it under the terms of the GNU Lesser General Public   License as published by the Free Software Foundation; either   version 2.1 of the License, or (at your option) any later version.   The GNU C Library is distributed in the hope that it will be useful,   but WITHOUT ANY WARRANTY; without even the implied warranty of   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU   Lesser General Public License for more details.   You should have received a copy of the GNU Lesser General Public   License along with the GNU C Library; if not, write to the Free   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA   02111-1307 USA.  */#include <alloca.h>#include <errno.h>#include <string.h>#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <net/if.h>#include <sys/socket.h>#include <sys/ioctl.h>#include <bits/libc-lock.h>#include <not-cancel.h>#include "netlinkaccess.h"/* Variable to signal whether SIOCGIFCONF is not available.  */# if __ASSUME_SIOCGIFNAME == 0static int old_siocgifconf;#else# define old_siocgifconf 0#endifunsigned intif_nametoindex (const char *ifname){#ifndef SIOCGIFINDEX  __set_errno (ENOSYS);  return 0;#else  struct ifreq ifr;  int fd = __opensock ();  if (fd < 0)    return 0;  strncpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));  if (__ioctl (fd, SIOCGIFINDEX, &ifr) < 0)    {      int saved_errno = errno;      close_not_cancel_no_status (fd);      if (saved_errno == EINVAL)	__set_errno (ENOSYS);      return 0;    }  close_not_cancel_no_status (fd);  return ifr.ifr_ifindex;#endif}libc_hidden_def (if_nametoindex)voidif_freenameindex (struct if_nameindex *ifn){  struct if_nameindex *ptr = ifn;  while (ptr->if_name || ptr->if_index)    {      free (ptr->if_name);      ++ptr;    }  free (ifn);}libc_hidden_def (if_freenameindex)#if __ASSUME_NETLINK_SUPPORT == 0static struct if_nameindex *if_nameindex_ioctl (void){  int fd = __opensock ();  struct ifconf ifc;  unsigned int nifs, i;  int rq_len;  struct if_nameindex *idx = NULL;# define RQ_IFS	4  if (fd < 0)    return NULL;  ifc.ifc_buf = NULL;  /* We may be able to get the needed buffer size directly, rather than     guessing.  */  if (! old_siocgifconf)    {      ifc.ifc_buf = NULL;      ifc.ifc_len = 0;      if (__ioctl (fd, SIOCGIFCONF, &ifc) < 0 || ifc.ifc_len == 0)	{# if __ASSUME_SIOCGIFNAME == 0	  old_siocgifconf = 1;# endif	  rq_len = RQ_IFS * sizeof (struct ifreq);	}      else	rq_len = ifc.ifc_len;    }  else    rq_len = RQ_IFS * sizeof (struct ifreq);  /* Read all the interfaces out of the kernel.  */  ifc.ifc_buf = alloca (rq_len);  ifc.ifc_len = rq_len;  while (1)    {        if (__ioctl (fd, SIOCGIFCONF, &ifc) < 0)	{	  close_not_cancel_no_status (fd);	  return NULL;	}      if (ifc.ifc_len < rq_len || ! old_siocgifconf)	break;      ifc.ifc_buf = extend_alloca (ifc.ifc_buf, rq_len, 2 * rq_len);      ifc.ifc_len = rq_len;    }  nifs = ifc.ifc_len / sizeof (struct ifreq);  idx = malloc ((nifs + 1) * sizeof (struct if_nameindex));  if (idx == NULL)    {      close_not_cancel_no_status (fd);      __set_errno (ENOBUFS);      return NULL;    }  for (i = 0; i < nifs; ++i)    {      struct ifreq *ifr = &ifc.ifc_req[i];      idx[i].if_name = __strdup (ifr->ifr_name);      if (idx[i].if_name == NULL	  || __ioctl (fd, SIOCGIFINDEX, ifr) < 0)	{	  int saved_errno = errno;	  unsigned int j;	  for (j =  0; j < i; ++j)	    free (idx[j].if_name);	  free (idx);	  close_not_cancel_no_status (fd);	  if (saved_errno == EINVAL)	    saved_errno = ENOSYS;	  else if (saved_errno == ENOMEM)	    saved_errno = ENOBUFS;	  __set_errno (saved_errno);	  return NULL;	}      idx[i].if_index = ifr->ifr_ifindex;    }  idx[i].if_index = 0;  idx[i].if_name = NULL;  close_not_cancel_no_status (fd);  return idx;}#endifstatic struct if_nameindex *if_nameindex_netlink (void){  struct netlink_handle nh = { 0, 0, 0, NULL, NULL };  struct if_nameindex *idx = NULL;  if (__no_netlink_support || __netlink_open (&nh) < 0)    return NULL;  /* Tell the kernel that we wish to get a list of all     active interfaces.  Collect all data for every interface.  */  if (__netlink_request (&nh, RTM_GETLINK) < 0)    goto exit_free;  /* Count the interfaces.  */  unsigned int nifs = 0;  for (struct netlink_res *nlp = nh.nlm_list; nlp; nlp = nlp->next)    {      struct nlmsghdr *nlh;      size_t size = nlp->size;      if (nlp->nlh == NULL)	continue;      /* Walk through all entries we got from the kernel and look, which         message type they contain.  */      for (nlh = nlp->nlh; NLMSG_OK (nlh, size); nlh = NLMSG_NEXT (nlh, size))	{	  /* Check if the message is what we want.  */	  if ((pid_t) nlh->nlmsg_pid != nh.pid || nlh->nlmsg_seq != nlp->seq)	    continue;	  if (nlh->nlmsg_type == NLMSG_DONE)	    break;		/* ok */	  if (nlh->nlmsg_type == RTM_NEWLINK)	    ++nifs;	}    }  idx = malloc ((nifs + 1) * sizeof (struct if_nameindex));  if (idx == NULL)    {    nomem:      __set_errno (ENOBUFS);      goto exit_free;    }  /* Add the interfaces.  */  nifs = 0;  for (struct netlink_res *nlp = nh.nlm_list; nlp; nlp = nlp->next)    {      struct nlmsghdr *nlh;      size_t size = nlp->size;      if (nlp->nlh == NULL)	continue;      /* Walk through all entries we got from the kernel and look, which         message type they contain.  */      for (nlh = nlp->nlh; NLMSG_OK (nlh, size); nlh = NLMSG_NEXT (nlh, size))	{	  /* Check if the message is what we want.  */	  if ((pid_t) nlh->nlmsg_pid != nh.pid || nlh->nlmsg_seq != nlp->seq)	    continue;	  if (nlh->nlmsg_type == NLMSG_DONE)	    break;		/* ok */	  if (nlh->nlmsg_type == RTM_NEWLINK)	    {	      struct ifinfomsg *ifim = (struct ifinfomsg *) NLMSG_DATA (nlh);	      struct rtattr *rta = IFLA_RTA (ifim);	      size_t rtasize = IFLA_PAYLOAD (nlh);	      idx[nifs].if_index = ifim->ifi_index;	      while (RTA_OK (rta, rtasize))		{		  char *rta_data = RTA_DATA (rta);		  size_t rta_payload = RTA_PAYLOAD (rta);		  if (rta->rta_type == IFLA_IFNAME)		    {		      idx[nifs].if_name = __strndup (rta_data, rta_payload);		      if (idx[nifs].if_name == NULL)			{			  idx[nifs].if_index = 0;			  if_freenameindex (idx);			  idx = NULL;			  goto nomem;			}		      break;		    }		  rta = RTA_NEXT (rta, rtasize);		}	      ++nifs;	    }	}    }  idx[nifs].if_index = 0;  idx[nifs].if_name = NULL; exit_free:  __netlink_free_handle (&nh);  __netlink_close (&nh);  return idx;}struct if_nameindex *if_nameindex (void){#ifndef SIOCGIFINDEX  __set_errno (ENOSYS);  return NULL;#else  struct if_nameindex *result = if_nameindex_netlink ();# if __ASSUME_NETLINK_SUPPORT == 0  if (__no_netlink_support)    result = if_nameindex_ioctl ();# endif  return result;#endif}libc_hidden_def (if_nameindex)char *if_indextoname (unsigned int ifindex, char *ifname){#if !defined SIOCGIFINDEX && __ASSUME_SIOCGIFNAME == 0  __set_errno (ENOSYS);  return NULL;#else# if __ASSUME_SIOCGIFNAME == 0  struct if_nameindex *idx;  struct if_nameindex *p;  char *result = NULL;# endif# if defined SIOCGIFNAME || __ASSUME_SIOCGIFNAME > 0  /* We may be able to do the conversion directly, rather than searching a     list.  This ioctl is not present in kernels before version 2.1.50.  */  struct ifreq ifr;  int fd;#  if __ASSUME_SIOCGIFNAME == 0  static int siocgifname_works_not;  if (!siocgifname_works_not)#  endif    {#  if __ASSUME_SIOCGIFNAME == 0      int serrno = errno;#  endif      int status;      fd = __opensock ();      if (fd < 0)	return NULL;      ifr.ifr_ifindex = ifindex;      status = __ioctl (fd, SIOCGIFNAME, &ifr);      close_not_cancel_no_status (fd);      if (status  < 0)	{#  if __ASSUME_SIOCGIFNAME == 0	  if (errno == EINVAL)	    siocgifname_works_not = 1; /* Don't make the same mistake twice. */	  else#  endif	    {	      if (errno == ENODEV)		/* POSIX requires ENXIO.  */		__set_errno (ENXIO);	      return NULL;	    }	}      else	return strncpy (ifname, ifr.ifr_name, IFNAMSIZ);#  if __ASSUME_SIOCGIFNAME == 0      __set_errno (serrno);#  endif    }# endif# if __ASSUME_SIOCGIFNAME == 0  idx = if_nameindex ();  if (idx != NULL)    {      for (p = idx; p->if_index || p->if_name; ++p)	if (p->if_index == ifindex)	  {	    result = strncpy (ifname, p->if_name, IFNAMSIZ);	    break;	  }      if_freenameindex (idx);      if (result == NULL)	__set_errno (ENXIO);    }  return result;# endif#endif}libc_hidden_def (if_indextoname)#if 0voidinternal_function__protocol_available (int *have_inet, int *have_inet6){  int fd = __opensock ();  unsigned int nifs;  int rq_len;  struct ifconf ifc;# define RQ_IFS	4  /* Wirst case assumption.  */  *have_inet = 0;  *have_inet6 = 0;  if (fd < 0)    /* We cannot open the socket.  No networking at all?  */    return;  /* We may be able to get the needed buffer size directly, rather than     guessing.  */  if (! old_siocgifconf)    {      ifc.ifc_buf = NULL;      ifc.ifc_len = 0;      if (__ioctl (fd, SIOCGIFCONF, &ifc) < 0 || ifc.ifc_len == 0)	{# if __ASSUME_SIOCGIFNAME == 0	  old_siocgifconf = 1;# endif	  rq_len = RQ_IFS * sizeof (struct ifreq);	}      else	rq_len = ifc.ifc_len;    }  else    rq_len = RQ_IFS * sizeof (struct ifreq);  /* Read all the interfaces out of the kernel.  */  do    {      ifc.ifc_buf = alloca (ifc.ifc_len = rq_len);      if (__ioctl (fd, SIOCGIFCONF, &ifc) < 0)	{	  close_not_cancel_no_status (fd);	  return;	}      rq_len *= 2;    }  while (ifc.ifc_len == rq_len && old_siocgifconf);  nifs = ifc.ifc_len / sizeof (struct ifreq);  /* Go through all the interfaces and get the address.  */  while (nifs-- > 0)    if (__ioctl (fd, SIOCGIFADDR, &ifc.ifc_req[nifs]) >= 0)      {	/* We successfully got information about this interface.  Now	   test whether it is an IPv4 or IPv6 address.  */	if (ifc.ifc_req[nifs].ifr_addr.sa_family == AF_INET)	  *have_inet = 1;	else if (ifc.ifc_req[nifs].ifr_addr.sa_family == AF_INET6)	  *have_inet6 = 1;	/* Note, this is & not &&.  It works since the values are always	   0 or 1.  */	if (*have_inet & *have_inet6)	  /* We can stop early.  */	  break;      }  close_not_cancel_no_status (fd);}#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -