Both Dns.GetHostAddress and Dns.GetHostEntry retur

2019-06-11 15:04发布

问题:

A simlar question has been asked here and here and here but none of the answers seem to work so I'm posting actual code and showing it running on an ipv6 capable machine hoping someone can suggest a solution

Here's the code taken from both questions

using System;

public class HelloWorld
{
    static public void Main ()
    {
        string hostName = "google.com"; // uri.DnsSafeHost;
        Console.WriteLine("DNS.GetHostAddresses: " + hostName);
        var hostAddresses = System.Net.Dns.GetHostAddresses(hostName);
        Console.WriteLine("DNS.NumAddreses:" + hostAddresses.Length);
        foreach (System.Net.IPAddress hostAddress in hostAddresses)
        {
            Console.WriteLine(
                "addr: " + hostAddress.ToString() + 
                " family: " + hostAddress.AddressFamily.ToString());
        }


        System.Net.IPHostEntry ipHostEntry = System.Net.Dns.GetHostEntry(hostName);
        Console.WriteLine("DNS.GetHostEntry NumAddresses:" + ipHostEntry.AddressList.Length);
        foreach (System.Net.IPAddress hostAddress in ipHostEntry.AddressList)
        {
            Console.WriteLine(
                "addr: " + hostAddress.ToString() + 
                " family: " + hostAddress.AddressFamily.ToString());
        }
    }
}

I'm running it on Ubuntu 14.04 with ipv6. Here's some possibly relevant info

# ip -6 addr show eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qlen 1000
    inet6 2400:6180:0:d0::691:9001/64 scope global 
       valid_lft forever preferred_lft forever
    inet6 fe80::601:eeff:fe7e:201/64 scope link 
       valid_lft forever preferred_lft forever

Proof Google.com has an ipv6 address

# dig google.com AAAA +short
2404:6800:4003:c00::8a

Show I can ping google.com directly on its ipv6 address

# ping6 2404:6800:4003:c00::8a
PING 2404:6800:4003:c00::8a(2404:6800:4003:c00::8a) 56 data bytes
64 bytes from 2404:6800:4003:c00::8a: icmp_seq=1 ttl=58 time=2.25 ms
64 bytes from 2404:6800:4003:c00::8a: icmp_seq=2 ttl=58 time=2.12 ms
^C

Show my mono version

# mono --version
Mono JIT compiler version 4.2.3 (Stable 4.2.3.4/832de4b Wed Mar 16 13:19:08 UTC 2016)
Copyright (C) 2002-2014 Novell, Inc, Xamarin Inc and Contributors. www.mono-project.com
    TLS:           __thread
    SIGSEGV:       altstack
    Notifications: epoll
    Architecture:  amd64
    Disabled:      none
    Misc:          softdebug 
    LLVM:          supported, not enabled.
    GC:            sgen
# mcs --version
Mono C# compiler version 4.2.3.0

Compile and run example above

# mcs dns.cs
# mono dns.exe
DNS.GetHostAddresses: google.com
DNS.NumAddreses:6
addr: 74.125.200.102 family: InterNetwork
addr: 74.125.200.139 family: InterNetwork
addr: 74.125.200.138 family: InterNetwork
addr: 74.125.200.101 family: InterNetwork
addr: 74.125.200.113 family: InterNetwork
addr: 74.125.200.100 family: InterNetwork
DNS.GetHostEntry NumAddresses:6
addr: 74.125.200.100 family: InterNetwork
addr: 74.125.200.113 family: InterNetwork
addr: 74.125.200.139 family: InterNetwork
addr: 74.125.200.102 family: InterNetwork
addr: 74.125.200.138 family: InterNetwork
addr: 74.125.200.101 family: InterNetwork

Some answers/comments suggested .NET filters out ipv6 on an ipv4 only machine. This is clearly not an ipv4 only machine.

Note: here's doing the same thing in node.js on the same machine. It correctly gets the ipv6 address as well as the ipv4 addresses

# node
> require('dns').lookup("google.com", {all:true}, (err, addresses) => { console.log(addresses); });
GetAddrInfoReqWrap {
  callback: { [Function: asyncCallback] immediately: true },
  family: 0,
  hostname: 'google.com',
  oncomplete: [Function: onlookupall],
  domain: 
   Domain {
     domain: null,
     _events: { error: [Function] },
     _eventsCount: 1,
     _maxListeners: undefined,
     members: [] } }
> [ { address: '74.125.200.101', family: 4 },
  { address: '74.125.200.138', family: 4 },
  { address: '74.125.200.102', family: 4 },
  { address: '74.125.200.139', family: 4 },
  { address: '74.125.200.113', family: 4 },
  { address: '74.125.200.100', family: 4 },
  { address: '2404:6800:4003:c00::65', family: 6 } ]

How do I get either DNS.GetHostAddresses or DNS.GetHostEntry to return both ipv6 and ipv4 addresses?

回答1:

This is taken from the MSDN site (https://msdn.microsoft.com/en-us/library/system.net.ipaddress(v=vs.110).aspx), it shows how to find all the relevant info on addresses, hopefully that might help:

// This program shows how to use the IPAddress class to obtain a server 
// IP addressess and related information.

using System;
using System.Net;
using System.Net.Sockets;
using System.Text.RegularExpressions;

namespace Mssc.Services.ConnectionManagement
{

  class TestIPAddress 
  {

    /**
      * The IPAddresses method obtains the selected server IP address information.
      * It then displays the type of address family supported by the server and its 
      * IP address in standard and byte format.
      **/
    private static void IPAddresses(string server) 
    {
      try 
      {
        System.Text.ASCIIEncoding ASCII = new System.Text.ASCIIEncoding();

        // Get server related information.
        IPHostEntry heserver = Dns.GetHostEntry(server);

        // Loop on the AddressList
        foreach (IPAddress curAdd in heserver.AddressList) 
        {


          // Display the type of address family supported by the server. If the
          // server is IPv6-enabled this value is: InternNetworkV6. If the server
          // is also IPv4-enabled there will be an additional value of InterNetwork.
          Console.WriteLine("AddressFamily: " + curAdd.AddressFamily.ToString());

          // Display the ScopeId property in case of IPV6 addresses.
          if(curAdd.AddressFamily.ToString() == ProtocolFamily.InterNetworkV6.ToString())
            Console.WriteLine("Scope Id: " + curAdd.ScopeId.ToString());


          // Display the server IP address in the standard format. In 
          // IPv4 the format will be dotted-quad notation, in IPv6 it will be
          // in in colon-hexadecimal notation.
          Console.WriteLine("Address: " + curAdd.ToString());

          // Display the server IP address in byte format.
          Console.Write("AddressBytes: ");



          Byte[] bytes = curAdd.GetAddressBytes();
          for (int i = 0; i < bytes.Length; i++) 
          {
            Console.Write(bytes[i]);
          }                          

          Console.WriteLine("\r\n");

        }

      }
      catch (Exception e) 
      {
        Console.WriteLine("[DoResolve] Exception: " + e.ToString());
      }
    }

    // This IPAddressAdditionalInfo displays additional server address information.
    private static void IPAddressAdditionalInfo() 
    {
      try 
      {
        // Display the flags that show if the server supports IPv4 or IPv6
        // address schemas.
        Console.WriteLine("\r\nSupportsIPv4: " + Socket.SupportsIPv4);
        Console.WriteLine("SupportsIPv6: " + Socket.SupportsIPv6);

        if (Socket.SupportsIPv6)
        {
          // Display the server Any address. This IP address indicates that the server 
          // should listen for client activity on all network interfaces. 
          Console.WriteLine("\r\nIPv6Any: " + IPAddress.IPv6Any.ToString());

          // Display the server loopback address. 
          Console.WriteLine("IPv6Loopback: " + IPAddress.IPv6Loopback.ToString());

          // Used during autoconfiguration first phase.
          Console.WriteLine("IPv6None: " + IPAddress.IPv6None.ToString());

          Console.WriteLine("IsLoopback(IPv6Loopback): " + IPAddress.IsLoopback(IPAddress.IPv6Loopback));
        }
        Console.WriteLine("IsLoopback(Loopback): " + IPAddress.IsLoopback(IPAddress.Loopback));
      }
      catch (Exception e) 
      {
        Console.WriteLine("[IPAddresses] Exception: " + e.ToString());
      }
    }


    public static void Main(string[] args) 
    {
      string server = null;

      // Define a regular expression to parse user's input.
      // This is a security check. It allows only
      // alphanumeric input string between 2 to 40 character long.
      Regex rex = new Regex(@"^[a-zA-Z]\w{1,39}$");

      if (args.Length < 1)
      {
        // If no server name is passed as an argument to this program, use the current 
        // server name as default.
        server = Dns.GetHostName();
        Console.WriteLine("Using current host: " + server);
      }
      else
      {
        server = args[0];
        if (!(rex.Match(server)).Success)
        {
          Console.WriteLine("Input string format not allowed.");
          return;
        }
      }

      // Get the list of the addresses associated with the requested server.
      IPAddresses(server);

      // Get additonal address information.
      IPAddressAdditionalInfo();
    }

  }
}

EDIT

Research on my Win 10 machine indicates that IPv6 addresses are only returned for local hosts, not internet hosts with either GetHostEntry or GetHostAddresses. Will look further.