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: add Interface.InterfaceAddrs #42694

Open
jeroenjacobs79 opened this issue Nov 18, 2020 · 23 comments
Open

net: add Interface.InterfaceAddrs #42694

jeroenjacobs79 opened this issue Nov 18, 2020 · 23 comments

Comments

@jeroenjacobs79
Copy link

jeroenjacobs79 commented Nov 18, 2020

Update, Sep 15 2021 Current proposal is #42694 -@rsc


Background

IPv6 has a concept of "privacy extensions" (RFC4941). When these extensions are active, a temporary IPv6 address is created, and is used for outbound connections. One this address expires, it gets the status "expired", and a new temporary IPv6 address is created.

Reason for this proposal

At the moment, when we use net.Interfaces(), we can get a list of associated addresses using the .Addrs() method. However, there is no platform-independent way to determine if the IPv6 address are temporary or deprecated. We need to resort to running and parsing output of ip, ifconfig, and ipconfig. IPv6 keeps growing, so frameworks and programming languages need to support the more advanced features of IPv6 in the near future.

Possible solutions

  • Add functions like IsTemporary() and isDeprecated() to net.IP (similar to isLoopback). However, that might not be the best solution, as the temporary nature of the address is not strictly tied to the numbers of the IP address.
  • Add extra functions to net.Interface type to determine expired and temporary addresses?
@rsc
Copy link
Contributor

rsc commented Jul 14, 2021

Can you please point to the specific definitions of "temporary" and "deprecated" IP addresses in an RFC? I skimmed RFC4941 very quickly and do not see how to tell, given an IP, whether it is one of those.

@rsc rsc changed the title Proposal: Extra methods for net.IP package to determine temporary and deprecated IPv6 addresses proposal: net: add IP.IsTemporary and IP.IsDeprecated Jul 14, 2021
@jeroenjacobs79
Copy link
Author

@rsc To be honest, I don't know exactly either. There should be an API for it, since ifconfig is able to determine them:

en8: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
	options=40b<RXCSUM,TXCSUM,VLAN_HWTAGGING,CHANNEL_IO>
	ether 58:ef:68:e7:31:1a
	inet6 fe80::d2:46b6:623a:b72d%en8 prefixlen 64 secured scopeid 0xa
	inet6 xxxx:1810:3e1e:8b31:149b:e16e:63de:3eeb prefixlen 64 autoconf secured
	inet6 xxxx:1810:3e1e:8b31:f43a:7ed8:5927:bec3 prefixlen 64 deprecated autoconf temporary
	inet 192.168.10.100 netmask 0xffffff00 broadcast 192.168.10.255
	inet6 xxxx:1810:3e1e:8b31:6ca3:1414:97d5:f184 prefixlen 64 deprecated autoconf temporary
	inet6 xxxx:1810:3e1e:8b31:89fb:df56:c110:7cab prefixlen 64 autoconf temporary
	nd6 options=201<PERFORMNUD,DAD>
	media: autoselect (1000baseT <full-duplex>)
	status: active

So, we need to look into the ifconfig sourcecode, I guess? Not sure how this works on Windows, but it supports temp. ipv6 addresses as well.

@ianlancetaylor
Copy link
Contributor

@jeroenjacobs79 What version of ifconfig are you running? What operating system?

@neild
Copy link
Contributor

neild commented Jul 14, 2021

To the best of my knowledge, there is no way to identify an IPv6 temporary address by examining the address bits.

RFC 8981 suggests generating temporary IIDs (interface identifiers) by simply generating the necessary number of random bits, and emphasizes, "Note: there are no special bits in an IID".

RFC 7136 states that the 'u' and 'g' bits in IPv6 IIDs have no meaning for IIDs not generated from IEEE EUI-64 addresses, and that no conclusions can be drawn from the state of these bits.

There is definitely no way to identify a deprecated address by examining its bits: A deprecated address is a temporary which has expired and will be used for existing connections, but not new ones.

Presumably, ifconfig can display the temporary and deprecated state of addresses associated with an interface because these are properties of the interface, not the address.

@jeroenjacobs79
Copy link
Author

I think I already mentioned that in the "possible solutions" section of my post.

It's probably an interface thing, not sure how hard it is to add this information to the net.Interface type. I assume that code in the standard library is already OS-specific, as the way to get network interface information is already different for Unix-like operating systems vs Windows.

@rsc
Copy link
Contributor

rsc commented Jul 21, 2021

It's not clear that it fits into net.Interface either.
Interface describes an interface like "eth0", which can have many IP addresses,
and only some of them might be temporary or deprecated.
Interface has an Addrs method that returns addresses but only addresses, not extra bits.
We have some other things in x/net but I don't see any more detailed enumeration of addresses.

This may be below the bar for being worth adding special API to a standard library for.

@rsc
Copy link
Contributor

rsc commented Jul 21, 2021

/cc @mikioh

@neild
Copy link
Contributor

neild commented Jul 21, 2021

If we want to do this, something like this might work:

type InterfaceAddrFlags int

const (
  FlagTemporary InterfaceAddrFlags = 1 << iota
  FlagDeprecated
  FlagMulticast
)

type InterfaceAddr struct {
  Addr Addr
  Flags AddrFlags
}

func (*Interface) InterfaceAddrs() ([]InterfaceAddr, error) { ... }

There's probably other per-address information that could go in there.

What's the use-case for detecting temporary and deprecated addresses? (Aside from implementing "ifconfig", of course.) The OS should generally manage address selection for you.

@jamesog
Copy link

jamesog commented Jul 24, 2021

My use-case for detecting IPv6 deprecated addresses is for a server which enumerates all local IP addresses via net.Interfaces() and be able to skip over deprecated addresses so they won't be used by the service.

Concretely, I have a FreeBSD system with several jails. Each jail gets an IPv6 address allocated but these are on the same network interface as the host. To ensure the host doesn't use a jail IP address, they're marked as deprecated; the jail can still use it (as it's its only address) but the kernel won't use any jail IPs for outgoing connections from the host. I have noticed, though, that some services (such as Tailscale) are using jail IPv6 addresses even though they're marked as deprecated.

@neild:

The OS should generally manage address selection for you.

You're right, for when the OS is performing address selection - e.g. a client application tells the kernel "give me a socket so I can make an outbound connection" - but sometimes a service may do this selection on its own and it may use addresses which are not appropriate, as above.

@rsc also said:

This may be below the bar for being worth adding special API to a standard library for.

This is possibly true, although the syscall package already includes many IFF_ link flags for each platform. In FreeBSD, the IPv6 flags used by ifconfig are define in /usr/include/netinet6/in6_var.h: https://github.com/freebsd/freebsd-src/blob/main/sys/netinet6/in6_var.h#L492-L502. I'm afraid I don't know how Linux/netlink implements it.

Naively (I'm not sure I understand the Go internals well enough) I wonder if these can be added to the syscall package to be used by the net package.

This does demonstrate the problem that the current net.IP type (being a []byte) makes things awkward as we can't add these per-IP flags. #46518 might help with that.

@neild
Copy link
Contributor

neild commented Jul 24, 2021

This does demonstrate the problem that the current net.IP type (being a []byte) makes things awkward as we can't add these per-IP flags. #46518 might help with that.

No, this has nothing to do with the net.IP type. A net.IP is an IP address. The temporary and deprecated statuses are not properties of an IP address, but of an (interface, IP) tuple. Perhaps we should add a type (as I suggest above) that describes an IP address plus additional interface-specific information, but net.IP is not the right place for this and #46518 doesn't change that.

@josharian
Copy link
Contributor

Or instead of a type, a net.Interface method?

@neild
Copy link
Contributor

neild commented Jul 24, 2021

Or instead of a type, a net.Interface method?

We'd need a new net.Interface method either way, but a single method returning a type with information about an address (as here) means we'd have a simple way to add new per-address information in the future.

@neild neild changed the title proposal: net: add IP.IsTemporary and IP.IsDeprecated proposal: net: report temporary/deprecated status of addresses in net.Interface Jul 24, 2021
@neild
Copy link
Contributor

neild commented Jul 24, 2021

Retitling proposal: New methods on net.IP are not the right way to provide this information, but some mechanism to identify temporary/deprecated addresses on an interface seems reasonable.

@rsc
Copy link
Contributor

rsc commented Jul 28, 2021

This proposal has been added to the active column of the proposals project
and will now be reviewed at the weekly proposal review meetings.
— rsc for the proposal review group

@rsc
Copy link
Contributor

rsc commented Aug 4, 2021

It is unclear what the new API should be. Any ideas?

net.Interfaces.Addrs and net.InterfaceAddrs return []net.Addr, so if we were going to expose the temporary/deprecated bit it would have to be an optional interface on that, but probably the concrete type of the net.Addr is net.IPNet, which has no room for bits.

@neild
Copy link
Contributor

neild commented Aug 4, 2021

It is unclear what the new API should be. Any ideas?

What do you think of this earlier suggestion?
#42694 (comment)

Add a new method to net.Interface returning a []InterfaceAddr where InterfaceAddr is a struct containing an address plus additional information.

@scott-cotton
Copy link

It is unclear what the new API should be. Any ideas?

What do you think of this earlier suggestion?
#42694 (comment)

Add a new method to net.Interface returning a []InterfaceAddr where InterfaceAddr is a struct containing an address plus additional information.

This makes sense to me.

@rsc
Copy link
Contributor

rsc commented Aug 11, 2021

@neild, the new method returning []InterfaceAddr seems fine, but maybe InterfaceAddr should be an opaque struct to make it easier to add more information (and keep it read-only)? Especially with the potential netaddr changes.

@rsc
Copy link
Contributor

rsc commented Aug 25, 2021

Ping @neild about interface vs struct.

@neild
Copy link
Contributor

neild commented Sep 8, 2021

I think a struct makes the most sense here.

The net.Interface type is a struct. Perhaps if we were redesigning the package it would make sense to make net.Interface an interface, but given that it is a struct I think it's best to remain consistent and use a struct for net.InterfaceAddr as well.

We can add new fields to a struct, so I don't think expansion is a concern. And we can copy any information that needs to be read-only when returning a []InterfaceAddr, since listing interfaces isn't an operation that needs to be so optimized that we worry about every allocation.

That said, I don't feel terribly strongly about this.

@rsc rsc changed the title proposal: net: report temporary/deprecated status of addresses in net.Interface proposal: net: add Interface.InterfaceAddrs Sep 15, 2021
@rsc
Copy link
Contributor

rsc commented Sep 15, 2021

Retitled to match current proposal (#42694 (comment))

@rsc
Copy link
Contributor

rsc commented Sep 15, 2021

Based on the discussion above, this proposal seems like a likely accept.
— rsc for the proposal review group

@rsc
Copy link
Contributor

rsc commented Sep 22, 2021

No change in consensus, so accepted. 🎉
This issue now tracks the work of implementing the proposal.
— rsc for the proposal review group

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Accepted
Development

No branches or pull requests

8 participants