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

Send UDP DNS responses from the address we received them from #95

Closed
omribahumi opened this issue Jul 4, 2014 · 9 comments
Closed

Send UDP DNS responses from the address we received them from #95

omribahumi opened this issue Jul 4, 2014 · 9 comments

Comments

@omribahumi
Copy link
Contributor

I have a problem with a server that has multiple IP address and is bound to 0.0.0.0.
I expect the DNS queries to be responded from the source IP address it was received on, but because of the way a UDP socket works when it's bound to 0.0.0.0, the OS is choosing the source IP when calling WriteTo().
For example, host(1) won't handle the response properly if it wasn't received from the destination address the query was sent to.

See this stackoverflow message for more information about this UDP problem:
http://stackoverflow.com/questions/3062205/setting-the-source-ip-for-a-udp-socket

So:

  1. Is this is a problem we even want to be addressing?
  2. How do other DNS servers (or any other UDP server that binds to 0.0.0.0) handle this?
  3. Is it possible to handle this in a cross-platform way on Go?

Thanks.

@andrewtj
Copy link
Collaborator

andrewtj commented Jul 4, 2014

Bert from PowerDNS blogged about this a while back. It's the wrong end of the day for me so I haven't refreshed myself on the details or dug into go's syscall/net interfaces to see how much trouble it'd be. I'll take a look tomorrow if no one else does.

@miekg
Copy link
Owner

miekg commented Jul 4, 2014

Some magic syscall.SetsockOptInt might do the trick. I have a bug open for this on skydns as well

@omribahumi
Copy link
Contributor Author

I've played with this a bit, got it working on Linux, but not on OSX.
I'll keep trying

Here is my progress:
https://gist.github.com/omribahumi/5da8517497042152691e

@miekg
Copy link
Owner

miekg commented Jul 4, 2014

[ Quoting notifications@github.com in "Re: [dns] Send UDP DNS responses fr..." ]

I've played with this a bit, got it working on Linux, but not on OSX.
I'll keep trying

Here is my progress:
https://gist.github.com/omribahumi/5da8517497042152691e

And the magic there is this line?

 syscall.SetsockoptInt(int(file.Fd()), syscall.IPPROTO_IP, 
 syscall.IP_PKTINFO, 1)

Sadly not portable as you say.

I wonder if this is a broader Go UDP issue, i.e. if we should look
for a solution in Go itself instead of fixing it here.

Thanks for your effort(s), I might have some time this weekend to also look
into this.

/Miek

Miek Gieben

@omribahumi
Copy link
Contributor Author

Not that simple. You should also be using ReadMsgUDP() instead of RecvFromUDP().
Then, the oob data contains the structs syscall.Cmsghdr and syscall.Inet4Pktinfo, which contains the information we need.

According to Google (and the BSD man pages), the exact same implementation should be working with OSX, just by changing the setsockopt() line to:

syscall.SetsockoptInt(int(file.Fd()), syscall.IPPROTO_IP, syscall.IP_RECVDSTADDR, 1)

But it returns invalid argument err. I've also tried

syscall.SetsockoptByte(int(file.Fd()), syscall.IPPROTO_IP, syscall.IP_RECVDSTADDR, 1)

But it yields the same results (setsockopt() failing). I'm not sure why.
The setsockopt() call works in Python. I even made sure the constants are right (0 and 7, respectively).

As for the Go way of solving this - I couldn't find any, but maybe the force is just stronger with you :)

Waiting for your feedback. Thanks

@miekg
Copy link
Owner

miekg commented Jul 4, 2014

Hmm. Thanks for the thorough update.

To frame the problem state properly: this is only a problem when listening
on 0.0.0.0.for UDP.

But I also agree a elegant solution would be nice.
On 4 Jul 2014 22:13, "Omri Bahumi" notifications@github.com wrote:

Not that simple. You should also be using ReadMsgUDP() instead of
RecvFromUDP().
Then, the oob data contains the structs syscall.Cmsghdr and
syscall.Inet4Pktinfo, which contains the information we need.

According to Google (and the BSD man pages), the exact same implementation
should be working with OSX, just by changing the setsockopt() line to:

syscall.SetsockoptInt(int(file.Fd()), syscall.IPPROTO_IP, syscall.IP_RECVDSTADDR, 1)

But it returns invalid argument err. I've also tried

syscall.SetsockoptByte(int(file.Fd()), syscall.IPPROTO_IP, syscall.IP_RECVDSTADDR, 1)

But it yields the same results (setsockopt() failing). I'm not sure why.
The setsockopt() call works in Python. I even made sure the constants are
right (0 and 7, respectively).

As for the Go way of solving this - I couldn't find any, but maybe the
force is just stronger with you :)

Waiting for your feedback. Thanks


Reply to this email directly or view it on GitHub
#95 (comment).

@omribahumi
Copy link
Contributor Author

@omribahumi
Copy link
Contributor Author

@miekg how would you feel about it if I'd fix it only for Linux (preserving the old behavior for OSX)?

@miekg
Copy link
Owner

miekg commented Jul 7, 2014

[ Quoting notifications@github.com in "Re: [dns] Send UDP DNS responses fr..." ]

@miekg how would you feel about it if I'd fix it only for Linux (preserving the old behavior for OSX)?

I think that is OK and having an pull request make it easier to reason about it.

It might be worth putting this in a seperate file to make it easier to contain
(think that is needed anyway to make it compile for Linux only)

/Miek

Miek Gieben

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

Successfully merging a pull request may close this issue.

3 participants