danderson / netboot

Packages and utilities for network booting
Apache License 2.0
1.48k stars 181 forks source link

Pixiecore doesn't work on Windows due to missing x/net/ipv4 support #18

Open techtonik opened 7 years ago

techtonik commented 7 years ago

Fails to run on Windows:

>pixiecore.exe api -d 127.0.0.1:1111
not supported by windows

Why it is not supported? I couldn't find the source of that error.

danderson commented 7 years ago

That error comes from the stdlib's syscall package. I haven't dug deeper yet, but go.universe.tf/netboot/dhcp4 is the package that does the most complex/unusual low-level socket operations (using golang.org/x/net/ipv4), so I suspect it's a codepath in x/net/ipv4 that's doing something not implemented on windows.

If that's the case, unfortunately there's not much I can do about it, the default codepath in dhcp4 is already as portable as I was able to make it, so it's x/net/ipv4 that would need extra windows support.

I'll dig more later today to see if I can identify a specific codepath.

techtonik commented 7 years ago

@danderson how do you debug it? I tried delve, but it doesn't work on 32-bit Windows (https://github.com/derekparker/delve/issues/656).

danderson commented 7 years ago

I don't use windows at all, so I don't know what debugger options exist. My strategy would be to add fmt.Println statements in https://github.com/google/netboot/blob/master/pixiecore/pixiecore.go#L185 to trace the initialization. I suspect it's newDHCP that is returning the error, but I could be wrong.

Once you find the function call that's returning the error, you can continue drilling down from there into that function and see which call is failing.

My guess, just looking at the code, is that the error comes from this SetControlMessage call in the dhcp4 package: https://github.com/google/netboot/blob/master/dhcp4/conn.go#L169 . This uses x/net/ipv4 to get information about the network interface that received a packet (required for DHCP, because we have to broadcast responses on the correct interface). My guess is that x/net/ipv4 has a TODO for supporting interface info.

danderson commented 7 years ago

bingo: https://github.com/golang/net/blob/master/ipv4/control_windows.go#L10

Looks like socket control messages are not at all implemented in x/net/ipv4, so the dhcp4 package cannot initialize on windows. If you know how to support this functionality for windows, pull requests for x/net are very welcome.

techtonik commented 7 years ago

Hmm.. I am trying to understand this. pixiecore listens on all interfaces, and when a packer is received, it is impossible to tell which interface it was? How come?

I found https://stackoverflow.com/questions/3062205/setting-the-source-ip-for-a-udp-socket?noredirect=1&lq=1 - is it talking about the same issue?

danderson commented 7 years ago

The problem pixiecore has is not the same as the stackoverflow question, it's related to how DHCP works.

With a normal client<->server communication, when you receive a packet, you have both the source (client) IP and the destination (server) IP, so you can easily tell where the client is located and how to respond.

But with DHCP, when the client sends the DHCPDISCOVER packet, it does not have an IP address yet. So, the packet has a source IP of 0.0.0.0 (none), and a destination of 255.255.255.255 (broadcast). And we have to broadcast the response to 255.255.255.255 as well.

With the basic socket APIs, when you receive such a packet, you have no information at all about where the client is (which network interface), you just know that it sent a broadcast packet and your machine was able to see it. So, you don't know where you should send the response.

The function call at https://github.com/google/netboot/blob/master/dhcp4/conn.go#L169 uses an extension of the socket API to ask for interface information. So, when we receive a packet using this API, we get the packet, but also the OS tells us exactly the interface the packet arrived on. Then, when we send the response, we use this extension again, and tell the OS "please send this packet on interface X".

This extension to the basic socket API is required to implement DHCP correctly, because it's a slightly weird protocol that has to talk to clients with no IP addresses. I'm sure Windows offers a similar API to get this information, but x/net/ipv4 has no windows experts, so the support is missing (https://github.com/golang/go/issues/7175).

techtonik commented 7 years ago

How the interface on which a message received is identified? Is it an IP address or MAC?

techtonik commented 7 years ago

Need time to wrap my head around system specific socket interface flags. I wish there was some table with socket optons and features. I guess on Linux conn.go wraps IP_PKTINFO flag described at https://linux.die.net/man/7/ip which seems implemented on Windows - https://msdn.microsoft.com/en-us/library/windows/desktop/hh285668(v=vs.85).aspx

Maybe a more simple workaround is to just listen on all interfaces separately?