module NetworkInterface

Constants

AF_12844
AF_APPLETALK
AF_ASH
AF_ATM
AF_ATMPVC
AF_ATMSVC
AF_AX25
AF_BAN
AF_BLUETOOTH
AF_BRIDGE
AF_CCITT
AF_CHAOS
AF_CLUSTER
AF_CNT
AF_COIP
AF_DATAKIT
AF_DECnet
AF_DLI
AF_ECMA
AF_ECONET
AF_FILE
AF_FIREFOX
AF_INET
AF_INET6
AF_IPX
AF_IRDA
AF_ISDN
AF_ISO
AF_KEY
AF_LAT
AF_NATM
AF_NDRV
AF_NETBEUI
AF_NETBIOS
AF_NETDES
AF_NETGRAPH
AF_NETROM
AF_NS
AF_PACKET
AF_PPP
AF_PPPOX
AF_PUP
AF_ROSE
AF_ROUTE
AF_SECURITY
AF_SIP
AF_SNA
AF_SYSTEM
AF_UNIX
AF_UNKNOWN1
AF_UNSPEC
AF_VOICEVIEW
AF_WANPIPE
AF_X25
VERSION

Public Class Methods

addresses(p1) click to toggle source
VALUE
rbnetifaces_s_addresses (VALUE class, VALUE dev)
{
  VALUE result;
  int found = FALSE;
#if defined(WIN32)
  PIP_ADAPTER_INFO pAdapterInfo = NULL;
  PIP_ADAPTER_INFO pInfo = NULL;
  ULONG ulBufferLength = 0;
  DWORD dwRet;
  PIP_ADDR_STRING str;
#elif HAVE_GETIFADDRS
  struct ifaddrs *addrs = NULL;
  struct ifaddrs *addr = NULL;
  VALUE result2;
#elif HAVE_SOCKET_IOCTLS
  int sock;
  struct CNAME(ifreq) ifr;
  char buffer[256];
  int is_p2p = FALSE;
  VALUE rbaddr = Qnil;
  VALUE rbnetmask = Qnil;
  VALUE rbbraddr = Qnil;
  VALUE rbdstaddr = Qnil;
  VALUE result2;
#endif

  Check_Type(dev, T_STRING);
  result = rb_hash_new();

#if defined(WIN32)
  //First, retrieve the adapter information.  We do this in a loop, in
  //case someone adds or removes adapters in the meantime.
  do
  {
    dwRet = GetAdaptersInfo(pAdapterInfo, &ulBufferLength);

    if (dwRet == ERROR_BUFFER_OVERFLOW)
    {
      if (pAdapterInfo)
        free (pAdapterInfo);
      pAdapterInfo = (PIP_ADAPTER_INFO)malloc (ulBufferLength);

      if (!pAdapterInfo)
      {
        rb_raise(rb_eRuntimeError, "Unknow error at OS level");
        return Qnil;
    }
    }
  } while (dwRet == ERROR_BUFFER_OVERFLOW);

  // If we failed, then fail in Ruby too
  if (dwRet != ERROR_SUCCESS && dwRet != ERROR_NO_DATA)
  {
    if (pAdapterInfo)
      free (pAdapterInfo);
    rb_raise(rb_eRuntimeError, "Unable to obtain adapter information.");
    return Qnil;
  }

  for (pInfo = pAdapterInfo; pInfo; pInfo = pInfo->Next)
  {
    char buffer[256];
    //dev is the iface GUID on windows with "\\Device\\NPF_" prefix
    int cmpAdapterNamelen = (MAX_ADAPTER_NAME_LENGTH + 4) + 12;
    char cmpAdapterName[cmpAdapterNamelen];
    int AdapterName_len = strlen(pInfo->AdapterName);

    VALUE rbhardw = Qnil;
    VALUE rbaddr = Qnil;
    VALUE rbnetmask = Qnil;
    VALUE rbbraddr = Qnil;

    memset(cmpAdapterName, 0x00, cmpAdapterNamelen);
    strncpy(cmpAdapterName, "\\Device\\NPF_", 12);
    strncpy(cmpAdapterName + 12, pInfo->AdapterName, AdapterName_len);
    if (strcmp (cmpAdapterName, StringValuePtr(dev)) != 0)
      continue;

    found = TRUE;

    // Do the physical address
    if (256 >= 3 * pInfo->AddressLength)
    {
      char *ptr = buffer;
      unsigned n;
      VALUE hash_hardw;
      hash_hardw = rb_hash_new();

      *ptr = '\0';
      for (n = 0; n < pInfo->AddressLength; ++n)
      {
        sprintf (ptr, "%02x:", pInfo->Address[n] & 0xff);
        ptr += 3;
      }
      *--ptr = '\0';

      rbhardw = rb_str_new2(buffer);
      rb_hash_aset(hash_hardw, rb_str_new2("addr"), rbhardw);
      result = add_to_family(result, INT2FIX(AF_LINK), hash_hardw);
    }

    for (str = &pInfo->IpAddressList; str; str = str->Next)
    {

      VALUE result2;
      result2 = rb_hash_new();

      if(str->IpAddress.String)
        rbaddr = rb_str_new2(str->IpAddress.String);
      if(str->IpMask.String)
        rbnetmask = rb_str_new2(str->IpMask.String);

      //If this isn't the loopback interface, work out the broadcast
      //address, for better compatibility with other platforms.
      if (pInfo->Type != MIB_IF_TYPE_LOOPBACK)
      {
        unsigned long inaddr = inet_addr (str->IpAddress.String);
        unsigned long inmask = inet_addr (str->IpMask.String);
        struct in_addr in;
        char *brstr;

        in.S_un.S_addr = (inaddr | ~inmask) & 0xfffffffful;

        brstr = inet_ntoa (in);

        if (brstr)
          rbbraddr = rb_str_new2(brstr);
      }

      if (rbaddr)
        rb_hash_aset(result2, rb_str_new2("addr"), rbaddr);
      if (rbnetmask)
        rb_hash_aset(result2, rb_str_new2("netmask"), rbnetmask);
      if (rbbraddr)
        rb_hash_aset(result2, rb_str_new2("broadcast"), rbbraddr);

      result = add_to_family(result, INT2FIX(AF_INET), result2);

    }
  } // for

  free (pAdapterInfo);

#elif HAVE_GETIFADDRS
  if (getifaddrs (&addrs) < 0)
  {
    rb_raise(rb_eRuntimeError, "Unknow error at OS level");
    }

    for (addr = addrs; addr; addr = addr->ifa_next)
  {
    char buffer[256];
    VALUE rbaddr = Qnil;
    VALUE rbnetmask = Qnil;
    VALUE rbbraddr = Qnil;

    if (strcmp (addr->ifa_name, StringValuePtr(dev)) != 0)
      continue;

    /* Sometimes there are records without addresses (e.g. in the case of a
    dial-up connection via ppp, which on Linux can have a link address
    record with no actual address).  We skip these as they aren't useful.
    Thanks to Christian Kauhaus for reporting this issue. */
    if (!addr->ifa_addr)
      continue;

    found = TRUE;

    if (string_from_sockaddr (addr->ifa_addr, buffer, sizeof (buffer)) == 0)
      rbaddr = rb_str_new2(buffer);

    if (string_from_sockaddr (addr->ifa_netmask, buffer, sizeof (buffer)) == 0)
      rbnetmask = rb_str_new2(buffer);

    if (string_from_sockaddr (addr->ifa_broadaddr, buffer, sizeof (buffer)) == 0)
      rbbraddr = rb_str_new2(buffer);

    result2 = rb_hash_new();

    if (rbaddr)
      rb_hash_aset(result2, rb_str_new2("addr"), rbaddr);
    if (rbnetmask)
      rb_hash_aset(result2, rb_str_new2("netmask"), rbnetmask);
    if (rbbraddr)
    {
      if (addr->ifa_flags & (IFF_POINTOPOINT | IFF_LOOPBACK))
        rb_hash_aset(result2, rb_str_new2("peer"), rbbraddr);
      else
        rb_hash_aset(result2, rb_str_new2("broadcast"), rbbraddr);
    }
    if (rbaddr || rbnetmask || rbbraddr)
      result = add_to_family(result, INT2FIX(addr->ifa_addr->sa_family), result2);
  }
    freeifaddrs (addrs);
#elif HAVE_SOCKET_IOCTLS

  sock = socket(AF_INET, SOCK_DGRAM, 0);

  if (sock < 0)
  {
        rb_raise(rb_eRuntimeError, "Unknow error at OS level");
    return Qnil;
  }

  strncpy (ifr.CNAME(ifr_name), StringValuePtr(dev), IFNAMSIZ);

#if HAVE_SIOCGIFHWADDR
  if (ioctl (sock, SIOCGIFHWADDR, &ifr) == 0)
  {
    if (string_from_sockaddr (&(ifr.CNAME(ifr_addr)), buffer, sizeof (buffer)) == 0)
    {
      found = TRUE;

      VALUE rbhardw = Qnil;
      VALUE hash_hardw;
      hash_hardw = rb_hash_new();
      rbhardw = rb_str_new2(buffer);
      rb_hash_aset(hash_hardw, rb_str_new2("addr"), rbhardw);
      result = add_to_family(result, INT2FIX(AF_LINK), hash_hardw);
    }
  }
#endif


#if HAVE_SIOCGIFADDR
#if HAVE_SIOCGLIFNUM
  if (ioctl (sock, SIOCGLIFADDR, &ifr) == 0)
  {
#else
  if (ioctl (sock, SIOCGIFADDR, &ifr) == 0)
  {
#endif
    if (string_from_sockaddr ((struct sockaddr *)&ifr.CNAME(ifr_addr), buffer, sizeof (buffer)) == 0)
    {
      found = TRUE;
            rbaddr = rb_str_new2(buffer);
    }
    }
#endif

#if HAVE_SIOCGIFNETMASK
#if HAVE_SIOCGLIFNUM
  if (ioctl (sock, SIOCGLIFNETMASK, &ifr) == 0)
  {
#else
    if (ioctl (sock, SIOCGIFNETMASK, &ifr) == 0)
  {
#endif
    if (string_from_sockaddr ((struct sockaddr *)&ifr.CNAME(ifr_addr), buffer, sizeof (buffer)) == 0)
    {
      found = TRUE;
      rbnetmask = rb_str_new2(buffer);
    }
  }
#endif

#if HAVE_SIOCGIFFLAGS
#if HAVE_SIOCGLIFNUM
  if (ioctl (sock, SIOCGLIFFLAGS, &ifr) == 0)
  {
#else
  if (ioctl (sock, SIOCGIFFLAGS, &ifr) == 0)
  {
#endif

    if (ifr.CNAME(ifr_flags) & IFF_POINTOPOINT)
    {
      is_p2p = TRUE;
    }
    }
#endif

#if HAVE_SIOCGIFBRDADDR
#if HAVE_SIOCGLIFNUM
  if (!is_p2p && ioctl (sock, SIOCGLIFBRDADDR, &ifr) == 0)
  {
#else
  if (!is_p2p && ioctl (sock, SIOCGIFBRDADDR, &ifr) == 0)
  {
#endif


    if (string_from_sockaddr ((struct sockaddr *)&ifr.CNAME(ifr_addr), buffer, sizeof (buffer)) == 0)
    {
          found = TRUE;
      rbbraddr = rb_str_new2(buffer);
    }
    }
#endif

#if HAVE_SIOCGIFDSTADDR
#if HAVE_SIOCGLIFNUM
  if (is_p2p && ioctl (sock, SIOCGLIFBRDADDR, &ifr) == 0)
  {
#else
  if (is_p2p && ioctl (sock, SIOCGIFBRDADDR, &ifr) == 0)
  {
#endif
    if (string_from_sockaddr ((struct sockaddr *)&ifr.CNAME(ifr_addr), buffer, sizeof (buffer)) == 0)
    {
      found = TRUE;
            rbdstaddr = rb_str_new2(buffer);
    }
  }

#endif
  result2 = rb_hash_new();

  if (rbaddr)
    rb_hash_aset(result2, rb_str_new2("addr"), rbaddr);
  if (rbnetmask)
    rb_hash_aset(result2, rb_str_new2("netmask"), rbnetmask);
  if (rbbraddr)
    rb_hash_aset(result2, rb_str_new2("broadcast"), rbbraddr);
    if (rbdstaddr)
    rb_hash_aset(result2, rb_str_new2("peer"), rbbraddr);

  if (rbaddr || rbnetmask || rbbraddr || rbdstaddr)
    result = add_to_family(result, INT2FIX(AF_INET), result2);

  close (sock);
#endif /* HAVE_SOCKET_IOCTLS */

  if (found)
    return result;
  else
    return Qnil;

}
interface_info(p1) click to toggle source
informations
VALUE
rbnetifaces_s_interface_info (VALUE self, VALUE dev)
{
  VALUE result = Qnil;

#if defined(WIN32)

  PIP_ADAPTER_INFO pAdapterInfo = NULL;
  PIP_ADAPTER_INFO pInfo = NULL;
  ULONG ulBufferLength = 0;
  DWORD dwRet;

  // First, retrieve the adapter information
  do {
    dwRet = GetAdaptersInfo(pAdapterInfo, &ulBufferLength);

    if (dwRet == ERROR_BUFFER_OVERFLOW)
    {
      if (pAdapterInfo)
      free (pAdapterInfo);
      pAdapterInfo = (PIP_ADAPTER_INFO)malloc (ulBufferLength);

      if (!pAdapterInfo)
      {
        rb_raise(rb_eRuntimeError, "Unknow error at OS level");
      }
      }
    } while (dwRet == ERROR_BUFFER_OVERFLOW);

  // If we failed, then fail in Ruby too
  if (dwRet != ERROR_SUCCESS && dwRet != ERROR_NO_DATA)
  {
    if (pAdapterInfo)
      free (pAdapterInfo);

      rb_raise(rb_eRuntimeError, "Unknow error at OS level");
      return Qnil;
  }
  if (dwRet == ERROR_NO_DATA)
  {
    free (pAdapterInfo);
    return result;
  }

  for (pInfo = pAdapterInfo; pInfo; pInfo = pInfo->Next)
  {
    // registry name location
    const char* prefix = "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\";
    const char* sufix  = "\\Connection";
    int prefix_len, sufix_len, adaptername_len;
    char* keypath = NULL;
    HKEY hKey;
    LONG lRet = 0;
    LPBYTE buffer = NULL;
    DWORD dwSize = 0;

    //dev is the iface GUID on windows with "\\Device\\NPF_" prefix
    int cmpAdapterNamelen = (MAX_ADAPTER_NAME_LENGTH + 4) + 12;
    char cmpAdapterName[cmpAdapterNamelen];
    int AdapterName_len = strlen(pInfo->AdapterName);
    memset(cmpAdapterName, 0x00, cmpAdapterNamelen);
    strncpy(cmpAdapterName, "\\Device\\NPF_", 12);
    strncpy(cmpAdapterName + 12, pInfo->AdapterName, AdapterName_len);
    if (strcmp (cmpAdapterName, StringValuePtr(dev)) != 0)
      continue;

    result = rb_hash_new();
    rb_hash_aset(result, rb_str_new2("description"), rb_str_new2(pInfo->Description));
    rb_hash_aset(result, rb_str_new2("guid"), rb_str_new2(pInfo->AdapterName));

    // Get the name from the registry
    prefix_len = strlen(prefix);
    sufix_len  = strlen(sufix);
    adaptername_len = strlen(pInfo->AdapterName);
    keypath = malloc(prefix_len +  sufix_len + adaptername_len + 1);
    memset(keypath, 0x00, prefix_len +  sufix_len + adaptername_len + 1);
    strncpy(keypath, prefix, prefix_len);
    strncpy(keypath + prefix_len, pInfo->AdapterName, adaptername_len);
    strncpy(keypath + prefix_len + adaptername_len, sufix, sufix_len);

    if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, keypath, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
    {
      // obtain current value size
      lRet = RegQueryValueEx(hKey, "Name", NULL, NULL, NULL, &dwSize);
      if (dwSize > 0 && ERROR_SUCCESS == lRet)
      {
        buffer = malloc((dwSize * sizeof(BYTE)) + 4);
        memset(buffer, 0x00, (dwSize * sizeof(BYTE)) + 4);
        lRet = RegQueryValueEx(hKey, "Name", NULL, NULL, buffer, &dwSize);
        if (ERROR_SUCCESS == lRet)
        {
          rb_hash_aset(result, rb_str_new2("name"), rb_str_new2(buffer));
        }
        else
        {
          rb_hash_aset(result, rb_str_new2("name"), rb_str_new2(""));
        }
        free(buffer);
      }
      else
      {
        rb_hash_aset(result, rb_str_new2("name"), rb_str_new2(""));
      }
      RegCloseKey(hKey);
    }
    else
    {
      rb_hash_aset(result, rb_str_new2("name"), rb_str_new2(""));
    }
    free(keypath);
  }
  free (pAdapterInfo);
#endif

  return result;
}
interfaces() click to toggle source
VALUE
rbnetifaces_s_interfaces (VALUE self)
{
  VALUE result;
#if defined(WIN32)
  PIP_ADAPTER_INFO pAdapterInfo = NULL;
  PIP_ADAPTER_INFO pInfo = NULL;
  ULONG ulBufferLength = 0;
  DWORD dwRet;
#elif HAVE_GETIFADDRS
  const char *prev_name = NULL;
  struct ifaddrs *addrs = NULL;
  struct ifaddrs *addr = NULL;
#elif HAVE_SIOCGIFCONF
  const char *prev_name = NULL;
  int fd, len, n;
  struct CNAME(ifconf) ifc;
  struct CNAME(ifreq) *pfreq;
#endif

  result = rb_ary_new();

#if defined(WIN32)
  // First, retrieve the adapter information
  do {
    dwRet = GetAdaptersInfo(pAdapterInfo, &ulBufferLength);

    if (dwRet == ERROR_BUFFER_OVERFLOW)
    {
      if (pAdapterInfo)
      free (pAdapterInfo);
      pAdapterInfo = (PIP_ADAPTER_INFO)malloc (ulBufferLength);

      if (!pAdapterInfo)
      {
        rb_raise(rb_eRuntimeError, "Unknow error at OS level");
      }
      }
    } while (dwRet == ERROR_BUFFER_OVERFLOW);

  // If we failed, then fail in Ruby too
  if (dwRet != ERROR_SUCCESS && dwRet != ERROR_NO_DATA)
  {
    if (pAdapterInfo)
      free (pAdapterInfo);

      rb_raise(rb_eRuntimeError, "Unknow error at OS level");
      return Qnil;
  }
  if (dwRet == ERROR_NO_DATA)
  {
    free (pAdapterInfo);
    return result;
  }

  for (pInfo = pAdapterInfo; pInfo; pInfo = pInfo->Next)
  {
    int outputnamelen = (MAX_ADAPTER_NAME_LENGTH + 4) + 12;
    char outputname[outputnamelen];
    int AdapterName_len = strlen(pInfo->AdapterName);
    VALUE ifname;
    memset(outputname, 0x00, outputnamelen);
    strncpy(outputname, "\\Device\\NPF_", 12);
    strncpy(outputname + 12, pInfo->AdapterName, AdapterName_len);
    ifname =  rb_str_new2(outputname) ;

    if(!rb_ary_includes(result, ifname))
      rb_ary_push(result, ifname);
  }

  free (pAdapterInfo);

#elif HAVE_GETIFADDRS
  if (getifaddrs (&addrs) < 0)
  {
    rb_raise(rb_eRuntimeError, "Unknow error at OS level");
  }

  for (addr = addrs; addr; addr = addr->ifa_next)
  {
    if (!prev_name || strncmp (addr->ifa_name, prev_name, IFNAMSIZ) != 0)
    {
      VALUE ifname =  rb_str_new2(addr->ifa_name);

    if(!rb_ary_includes(result, ifname))
      rb_ary_push(result, ifname);

    prev_name = addr->ifa_name;
    }
  }

  freeifaddrs (addrs);
#elif HAVE_SIOCGIFCONF

  fd = socket (AF_INET, SOCK_DGRAM, 0);
  len = -1;
  if (fd < 0) {
    rb_raise(rb_eRuntimeError, "Unknow error at OS level");
    return Qnil;
  }

  // Try to find out how much space we need
#if HAVE_SIOCGSIZIFCONF
  if (ioctl (fd, SIOCGSIZIFCONF, &len) < 0)
    len = -1;
#elif HAVE_SIOCGLIFNUM
#error This code need to be checked first
/*
  { struct lifnum lifn;
  lifn.lifn_family = AF_UNSPEC;
  lifn.lifn_flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES;
  ifc.lifc_family = AF_UNSPEC;
  ifc.lifc_flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES;
  if (ioctl (fd, SIOCGLIFNUM, (char *)&lifn) < 0)
    len = -1;
  else
    len = lifn.lifn_count;
  }
*/
#endif

  // As a last resort, guess
  if (len < 0)
  len = 64;

  ifc.CNAME(ifc_len) = len * sizeof (struct CNAME(ifreq));
  ifc.CNAME(ifc_buf) = malloc (ifc.CNAME(ifc_len));

  if (!ifc.CNAME(ifc_buf)) {
    close (fd);
    rb_raise(rb_eRuntimeError, "Not enough memory");
    return Qnil;
    }

#if HAVE_SIOCGLIFNUM
  if (ioctl (fd, SIOCGLIFCONF, &ifc) < 0) {
#else
  if (ioctl (fd, SIOCGIFCONF, &ifc) < 0) {

#endif
    free (ifc.CNAME(ifc_req));
    close (fd);
    rb_raise(rb_eRuntimeError, "Unknow error at OS level");
    return Qnil;
  }

  pfreq = ifc.CNAME(ifc_req);

  for (n = 0; n < ifc.CNAME(ifc_len)/sizeof(struct CNAME(ifreq));n++,pfreq++)
  {
    if (!prev_name || strncmp (prev_name, pfreq->CNAME(ifr_name), IFNAMSIZ) != 0)
    {
      VALUE ifname =  rb_str_new2(pfreq->CNAME(ifr_name));
      if(!rb_ary_includes(result, ifname))
        rb_ary_push(result, ifname);

      prev_name = pfreq->CNAME(ifr_name);
    }
  }

  free (ifc.CNAME(ifc_buf));
  close (fd);

#endif //

  return result;
}