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

net: InterfaceAddrs returns invalid network masks on windows/amd64 #12551

Closed
longlongh4 opened this issue Sep 9, 2015 · 12 comments

Comments

Projects
None yet
8 participants
@longlongh4
Copy link

commented Sep 9, 2015

try to run the following code on win8 64 bit system:

package main

import (
    "fmt"
    "net"
)

func main() {
    addrs, _ := net.InterfaceAddrs()
    for _, addr := range addrs {
        fmt.Println(addr.String())
    }
}

the result you get is shown below:

10.0.6.3/16
fe80::3d91:6d95:edef:b57e/28
169.254.181.126/16
fe80::f19d:b003:b060:cbaa/28
192.168.31.164/16
fe80::b066:dca9:cac5:6257/28
192.168.254.1/16
fe80::a4ef:4847:f48:1a5a/28
192.168.10.1/16
::1/28
127.0.0.1/16
fe80::5efe:c0a8:1fa4/28
2001:0:5ef5:79fd:38ce:22a8:d2b0:b417/28
fe80::38ce:22a8:d2b0:b417/28
fe80::5efe:c0a8:a01/28
fe80::5efe:c0a8:fe01/28
fe80::5efe:a00:603/28

the mask value is all the same and not correct.

@ianlancetaylor ianlancetaylor changed the title a bug in net.Addr win8 64bit : can't get network mask correctly net: a bug in net.Addr win8 64bit : can't get network mask correctly Sep 9, 2015

@ianlancetaylor ianlancetaylor added this to the Go1.6 milestone Sep 9, 2015

@ianlancetaylor

This comment has been minimized.

Copy link
Contributor

commented Sep 9, 2015

CC @mikioh

@gopherbot

This comment has been minimized.

Copy link

commented Sep 20, 2015

CL https://golang.org/cl/14747 mentions this issue.

@akevinbailey

This comment has been minimized.

Copy link

commented Oct 8, 2015

I have a fix for this. I'm also getting the DNS Suffix and only the active interfaces. Unfortunately I can't attach the code because I get a "Something went really wrong, and we can’t process that file." error from GitHub.

I posted a more detailed explanation and code snip-it at #12811

@davecheney

This comment has been minimized.

Copy link
Contributor

commented Oct 8, 2015

@akevinbailey please don't send a diff or a pull request because we cannot review it.

We instead use a code review system called Gerrit.
You can find the details in our Contribution Guidelines:
https://golang.org/doc/contribute.html

@akevinbailey

This comment has been minimized.

Copy link

commented Oct 8, 2015

Thanks for the info.

  From: Dave Cheney <notifications@github.com>

To: golang/go go@noreply.github.com
Cc: A. Kevin Bailey akevinbailey@yahoo.com
Sent: Wednesday, October 7, 2015 8:58 PM
Subject: Re: [go] net: a bug in net.Addr win8 64bit : can't get network mask correctly (#12551)

@akevinbailey please don't send a diff or a pull request because we cannot review it.We instead use a code review system called Gerrit.
You can find the details in our Contribution Guidelines:
https://golang.org/doc/contribute.html—
Reply to this email directly or view it on GitHub.

@akevinbailey

This comment has been minimized.

Copy link

commented Oct 8, 2015

@davecheney I posted my own issue on this a few days ago and posted the fix in the issue text. See: #12811

@rsc rsc changed the title net: a bug in net.Addr win8 64bit : can't get network mask correctly net: InterfaceAddrs returns invalid network masks on windows/amd64 Nov 5, 2015

@alexbrainman

This comment has been minimized.

Copy link
Member

commented Nov 9, 2015

I think this is dup of issue #12811.

Alex

@gopherbot

This comment has been minimized.

Copy link

commented Dec 4, 2015

CL https://golang.org/cl/17412 mentions this issue.

mikioh pushed a commit that referenced this issue Dec 10, 2015

Mikio Hara
net, internal/syscall/windows: fix interface and address identificati…
…on on windows

The current implementation including Go 1.5 through 1.5.2 misuses
Windows API and mishandles the returned values from GetAdapterAddresses
on Windows. This change fixes various issues related to network facility
information by readjusting interface and interface address parsers.

Updates #5395.
Updates #10530.
Updates #12301.
Updates #12551.
Updates #13542.
Fixes #12691.
Fixes #12811.
Fixes #13476.
Fixes #13544.

Also fixes fragile screen scraping test cases in net_windows_test.go.

Additional information for reviewers:

It seems like almost all the issues above have the same root cause and
it is misunderstanding of Windows API. If my interpretation of the
information on MSDN is correctly, current implementation contains the
following bugs:

- SIO_GET_INTERFACE_LIST should not be used for IPv6. The behavior of
  SIO_GET_INTERFACE_LIST is different on kernels and probably it doesn't
  work correctly for IPv6 on old kernels such as Windows XP w/ SP2.
  Unfortunately MSDN doesn't describe the detail of
  SIO_GET_INTERFACE_LIST, but information on the net suggests so.

- Fetching IP_ADAPTER_ADDRESSES structures with fixed size area may not
  work when using IPv6. IPv6 generates ton of interface addresses for
  various addressing scopes. We need to adjust the area appropriately.

- PhysicalAddress field of IP_ADAPTER_ADDRESSES structure may have extra
  space. We cannot ignore PhysicalAddressLength field of
  IP_ADAPTER_ADDRESS structure.

- Flags field of IP_ADAPTER_ADDRESSES structure doesn't represent any of
  administratively and operatinal statuses. It just represents settings
  for windows network adapter.

- MTU field of IP_ADAPTER_ADDRESSES structure may have a uint32(-1) on
  64-bit platform. We need to convert the value to interger
  appropriately.

- IfType field of IP_ADAPTER_ADDRESSES structure is not a bit field.
  Bitwire operation for the field is completely wrong.

- OperStatus field of IP_ADAPTER_ADDRESSES structure is not a bit field.
  Bitwire operation for the field is completely wrong.

- IPv6IfIndex field of IP_ADAPTER_ADDRESSES structure is just a
  substitute for IfIndex field. We cannot prefer IPv6IfIndex to IfIndex.

- Windows XP, 2003 server and below don't set OnLinkPrefixLength field
  of IP_ADAPTER_UNICAST_ADDRESS structure. We cannot rely on the field
  on old kernels. We can use FirstPrefix field of IP_ADAPTER_ADDRESSES
  structure and IP_ADAPTER_PREFIX structure instead.

- Length field of IP_ADAPTER_{UNICAST,ANYCAST,MULTICAST}_ADDRESS
  sturecures doesn't represent an address prefix length. It just
  represents a socket address length.

Change-Id: Icabdaf7bd1d41360a981d2dad0b830b02b584528
Reviewed-on: https://go-review.googlesource.com/17412
Reviewed-by: Alex Brainman <alex.brainman@gmail.com>
@AudriusButkevicius

This comment has been minimized.

Copy link
Contributor

commented Dec 18, 2015

This is still not fixed in 1.5.2

package main

import(
    "fmt"
    "net"
    "os"
    "strings"
    "syscall"
    "unsafe"
    "runtime"
)

func main(){
    fmt.Println(runtime.Version())
    fmt.Println(GetV4LansGolang())
    fmt.Println(GetV4LansWinAPI())
}

func GetV4LansGolang() ([]*net.IPNet, error) {
    addrs, err := net.InterfaceAddrs()
    if err != nil {
        return nil, err
    }

    nets := make([]*net.IPNet, 0, len(addrs))

    for _, addr := range addrs {
        netw, ok := addr.(*net.IPNet)
        if ok {

            if netw.IP.To4() != nil {
                nets = append(nets, netw)   
            }

        }
    }
    return nets, nil
}

func getAdapterList() (*syscall.IpAdapterInfo, error) {
    b := make([]byte, 10240)
    l := uint32(len(b))
    a := (*syscall.IpAdapterInfo)(unsafe.Pointer(&b[0]))
    // TODO(mikio): GetAdaptersInfo returns IP_ADAPTER_INFO that
    // contains IPv4 address list only. We should use another API
    // for fetching IPv6 stuff from the kernel.
    err := syscall.GetAdaptersInfo(a, &l)
    if err == syscall.ERROR_BUFFER_OVERFLOW {
        b = make([]byte, l)
        a = (*syscall.IpAdapterInfo)(unsafe.Pointer(&b[0]))
        err = syscall.GetAdaptersInfo(a, &l)
    }
    if err != nil {
        return nil, os.NewSyscallError("GetAdaptersInfo", err)
    }
    return a, nil
}

func GetV4LansWinAPI() ([]*net.IPNet, error) {
    ifaces, err := net.Interfaces()
    if err != nil {
        return nil, err
    }

    nets := make([]*net.IPNet, 0, len(ifaces))

    aList, err := getAdapterList()
    if err != nil {
        return nil, err
    }

    for _, ifi := range ifaces {
        for ai := aList; ai != nil; ai = ai.Next {
            index := ai.Index

            if ifi.Index == int(index) {
                ipl := &ai.IpAddressList
                for ; ipl != nil; ipl = ipl.Next {
                    ipStr := strings.Trim(string(ipl.IpAddress.String[:]), "\x00")
                    maskStr := strings.Trim(string(ipl.IpMask.String[:]), "\x00")
                    ip := net.ParseIP(ipStr)
                    maskip := net.ParseIP(maskStr)
                    if ip.IsUnspecified() || maskip.IsUnspecified() {
                        continue
                    }
                    nets = append(nets, &net.IPNet{
                        IP: ip,
                        Mask: net.IPv4Mask(
                            maskip[net.IPv6len-net.IPv4len],
                            maskip[net.IPv6len-net.IPv4len+1],
                            maskip[net.IPv6len-net.IPv4len+2],
                            maskip[net.IPv6len-net.IPv4len+3],
                        ),
                    })
                }
            }
        }
    }
    return nets, err
}

Output:

go1.5.2
[169.254.131.41/16 192.168.1.66/16 127.0.0.1/16] <nil>
[192.168.1.66/24] <nil>

ipconfig output:

C:\Users\Audrius>ipconfig

Windows IP Configuration


Wireless LAN adapter Local Area Connection* 2:

   Media State . . . . . . . . . . . : Media disconnected
   Connection-specific DNS Suffix  . :

Wireless LAN adapter Wi-Fi:

   Connection-specific DNS Suffix  . :
   Link-local IPv6 Address . . . . . : fe80::f9a2:1fe9:751f:bc7b%3
   IPv4 Address. . . . . . . . . . . : 192.168.1.66
   Subnet Mask . . . . . . . . . . . : 255.255.255.0
   Default Gateway . . . . . . . . . : 192.168.1.254

Tunnel adapter Teredo Tunneling Pseudo-Interface:

   Connection-specific DNS Suffix  . :
   IPv6 Address. . . . . . . . . . . : 2001:0:9d38:90d7:1c37:3e14:a88d:67e0
   Link-local IPv6 Address . . . . . : fe80::1c37:3e14:a88d:67e0%8
   Default Gateway . . . . . . . . . : ::

Tunnel adapter isatap.{1F734CEB-3098-4579-8169-BA5D2AF5EEDE}:

   Media State . . . . . . . . . . . : Media disconnected
   Connection-specific DNS Suffix  . :
@mikioh

This comment has been minimized.

Copy link
Contributor

commented Dec 19, 2015

@AudriusButkevicius, this is broken Go 1.5 through Go 1.5.2. Try Go 1.6.

@akevinbailey

This comment has been minimized.

Copy link

commented Dec 19, 2015

@AudriusButkevicius, @mikioh the fix is pretty easy. If you want to do it yourself I have posted the code snipit on #12811. If you want the entire file, let me know. I will be happy to share it. I don't have time or the desire to set up and go through Gerrit, so I will just post it on a Google Shared Drive or on my GitHub page if you want.

@AudriusButkevicius

This comment has been minimized.

Copy link
Contributor

commented Dec 19, 2015

So 1.6 does work.
Patching up the building env is more painful than using 1.6 beta, so we'll try to make a windows release with 1.6 beta, and perhaps expose some other bugs.

@golang golang locked and limited conversation to collaborators Dec 29, 2016

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
You can’t perform that action at this time.