ACP: Extended logic for IP networks · Issue #235 · rust-lang/libs-team (original) (raw)
Proposal
Problem statement
While most networked applications only need to deal with individual IP addresses, it is sometimes desirable to work with entire ranges of IP addresses, especially under IPv6.
Motivating examples or use cases
The primary use case for most workflows will be filtering (allow-listing or deny-listing) ranges of IPs for connections, although more dedicated networking code that routes traffic among several hosts could also benefit from this.
Additionally, configuring IP addresses for certain applications can benefit from logic surrounding IP networks. For example, under IPv6, it's very common for a host to have access to an entire 64-bit address space and to have free reign over which specific addresses they actually listen on. In these cases, ad-hoc connections can be made on a randomized IP address within this space, where a randomly chosen IP is then checked for collision with an existing address rather than iterating over all possible addresses.
Solution sketch
A good minimal proposal is the following:
BitAnd
andBitOr
impls forIpv4Addr
andIpv6Addr
(not forIpAddr
, since the operands must be the same address type)Not
forIpv4Addr
,Ipv6Addr
, and maybeIpAddr
(we can implement this for generic IP addresses, but I'm not sure if it'd be useful)leading_zeros
,leading_ones
,trailing_zeros
, andtrailing_ones
methods forIpv4Addr
,Ipv6Addr
, and potentiallyIpAddr
(there isn't the same restriction as for binary operations, although it's likely you'll still need to narrow down the address type anyway)BITS
associated constant forIpv4Addr
andIpv6Addr
set to 32 and 128 respectivelyStep
forIpv4Addr
andIpv6Addr
(again not forIpAddr
, since ranges of IPs must have the same type on both ends)
Note that this proposal does not currently include separate IP network types, although that could be a future extension. The main benefit here is to provide operations which can only be provided by the standard library since it owns the IP address types, while leaving the usage of those operations to implement dedicated types up to the end user and various crate authors.
Examples
Checking a network mask with BitAnd
:
let addr = Ipv6Addr::new(0x2001, 0xdb8, 0x692e, 0x6e2e, 0x672e, 0x672e, 0x792e, 0x752e); let mask = Ipv6Addr::new(0xffff, 0xffff, 0, 0, 0, 0, 0, 0); let net = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0); assert_eq!(addr & mask, net);
Creating an address in a network with BitOr
:
let rand_token = Ipv6Addr::new(0, 0, 0, 0, 0, 4); let net = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0); let addr = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 4); assert_eq!(net | rand, addr);
Checking validity of a network mask:
let valid = Ipv4Addr::new(255, 255, 255, 192) let invalid = Ipv4Addr::new(192, 255, 255, 255); assert_eq!(valid.leading_ones() + valid.trailing_zeros(), Ipv4Addr::BITS); assert_ne!(invalid.leading_ones() + invalid.trailing_zeros(), Ipv6Addr::BITS);
Getting the first and last IPs in a network:
let net = Ipv4Addr::new(192, 168, 0, 0); let mask = Ipv4Addr::new(255, 255, 255, 0); let mut range = net..=(net | !mask); let first = range.skip(1).next().unwrap(); let last = range.next_back().unwrap(); assert_eq!(first, Ipv4Addr::new(192, 168, 0, 1)); assert_eq!(last, Ipv4Addr::new(192, 168, 0, 255));
Alternatives
All of these operations could be done through the conversions to u32
and u128
, and this is indeed what existing crates do. The primary alternative would be to have users rely on these conversions for any of the proposed operations that are not implemented.
Links and related work
Some existing IP network crates:
What happens now?
This issue is part of the libs-api team API change proposal process. Once this issue is filed the libs-api team will review open proposals as capability becomes available. Current response times do not have a clear estimate, but may be up to several months.
Possible responses
The libs team may respond in various different ways. First, the team will consider the problem (this doesn't require any concrete solution or alternatives to have been proposed):
- We think this problem seems worth solving, and the standard library might be the right place to solve it.
- We think that this probably doesn't belong in the standard library.
Second, if there's a concrete solution:
- We think this specific solution looks roughly right, approved, you or someone else should implement this. (Further review will still happen on the subsequent implementation PR.)
- We're not sure this is the right solution, and the alternatives or other materials don't give us enough information to be sure about that. Here are some questions we have that aren't answered, or rough ideas about alternatives we'd want to see discussed.