Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IPv6 Support #45

Closed
seeder opened this issue Dec 13, 2014 · 5 comments
Closed

IPv6 Support #45

seeder opened this issue Dec 13, 2014 · 5 comments

Comments

@seeder
Copy link

seeder commented Dec 13, 2014

Hi,

I see that you have "excluded" IPv6 support. Which is really bad.

When I've used :: as bind host in your example,

INTERFACES = [
    [:udp, "::", 5300],
    [:tcp, "::", 5300]
]

it gave me this error :

  Errno::EAFNOSUPPORT: Address family not supported by protocol - bind(2) for "::" port 5300

Quick look at rubydns-0.9.1/lib/rubydns/handler.rb

shows @126

 def initialize(server, host, port)
      socket = UDPSocket.new

      socket.bind(host, port)

      super(server, socket)
    end

now changing line 127 to :

      socket = UDPSocket.new Socket::AF_INET6

Gets it running like a charm :

ruby example.rb          
I, [2014-12-13T03:05:39.921812 #16965]  INFO -- : Starting RubyDNS server (v0.9.1)...
I, [2014-12-13T03:05:39.921953 #16965]  INFO -- : <> Listening on udp::::5300
I, [2014-12-13T03:05:39.923565 #16965]  INFO -- : <> Listening on tcp::::5300

with netstat confirming opening right sockets:

udp6       0      0 :::5300                 :::*                                16965/ruby      
tcp6       0      0 :::5300                 :::*                    LISTEN      16965/ruby      

and dig confirming it works as expected :

 dig @localhost -p 5300 test.mydomain.org

; <<>> DiG 9.9.5-3ubuntu0.1-Ubuntu <<>> @localhost -p 5300 test.mydomain.org
; (2 servers found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 37126
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; WARNING: recursion requested but not available

;; QUESTION SECTION:
;test.mydomain.org.     IN  A

;; ANSWER SECTION:
test.mydomain.org.  86400   IN  A   10.0.0.80

;; Query time: 2 msec
;; SERVER: ::1#5300(::1)

with that little change you can have it correctly listening on IPv6 sockets, they are brilliant, because on most systems they also enable IPv4 listening :

same example script running, just query over legacy IPv4

dig -4 @localhost -p 5300 test.mydomain.org

; <<>> DiG 9.9.5-3ubuntu0.1-Ubuntu <<>> -4 @localhost -p 5300 test.mydomain.org
; (2 servers found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 55503
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; WARNING: recursion requested but not available

;; QUESTION SECTION:
;test.mydomain.org.     IN  A

;; ANSWER SECTION:
test.mydomain.org.  86400   IN  A   10.0.0.80

;; Query time: 1 msec
;; SERVER: 127.0.0.1#5300(127.0.0.1)

So the only thing missing would be distinguishing between UDP sockets between IPv6 and IPv4 host, which is darn simple with a regex or IPAddr or even, pass it as an attribute so we can decide.

@ioquatix
Copy link
Member

Thanks for the awesome bug report.

I'm surprised you need to specify the constant Socket::AF_INET6, I thought with the correct address (i.e. ::) it would work as expected.

Granted, this has clearly never been tested, so thanks for the thorough review of the current situation.

What solution do you think makes the most sense?

Whatever solution we choose, clearly we should write some specs for it to ensure IPv6 support is well maintained.

@seeder
Copy link
Author

seeder commented Dec 14, 2014

If we forgo using "DNS" hostnames it's as simple as 'ipaddr' ( included in stdlib ) can tell you what to use

example (host is a variable containing IPv4/IPv6 address) :

require 'ipaddr' 
host_address = IPAddr.new host
family = host_address.ipv6? ? Socket::AF_INET6 : Socket::AF_INET 

socket = UDPSocket.new family

@ioquatix
Copy link
Member

Okay, so we could make a wrapper, e.g.

def network_address(address)
    if IPAddr === address
       return address
    else
        return IPAddr.new(address)
    end
end

Then in the code for the socket use the code you proposed?

@seeder
Copy link
Author

seeder commented Dec 14, 2014

Yup, looks good :)

@ioquatix
Copy link
Member

Okay just release 0.9.2 which fixes this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants