Tracking issue for Ipv{4,6}Addr convenience methods

c9ac0d8
Opened by Alex Crichton at 2025-03-06 12:37:18

The below is a list of methods left to be stabilized under the ip feature. The path forward today is unclear; if you'd like to push through any method on here the libs team is interested in a PR with links to the associated RFCs or other official documentation. Let us know!




  1. The below is a list of methods left to be stabilized under the ip feature. The path forward today is unclear; if you'd like to push through any method on here the libs team is interested in a PR with links to the associated RFCs or other official documentation. Let us know!





    Steps

    • [ ] Implementation https://github.com/rust-lang/rust/pull/22015
    • [ ] Implementation https://github.com/rust-lang/rust/pull/34694
    • [ ] Stabilization attempt https://github.com/rust-lang/rust/pull/66584
    • [ ] Stabilization attempt https://github.com/rust-lang/rust/pull/76098
    • [ ] Stabilization PR(s)

    Subsets of the listed methods can be stabilized, rather than attempting to stabilize everything at once.

    Unresolved Questions

    • [ ] is_documentation is not up to date #137821
    • [ ] Differences between Rust and other languages https://github.com/rust-lang/rust/pull/76098#issuecomment-761234042
    • [ ] More specific case of the above: does the IPv6 unicast interface do what we expect? https://github.com/rust-lang/rust/issues/85604
    • [ ] Do the provided methods pass ipcheck? https://github.com/rust-lang/libs-team/tree/93b78eef2e0d455a3e69c05333cd8f276e4e95f1/tools/ipcheck. Last known run: https://github.com/rust-lang/rust/pull/76098#issuecomment-760651861

    From @KodrAus in https://github.com/rust-lang/rust/pull/76098#issuecomment-760841554:

    • [ ] Should we replace the Ipv6Addr::is_unicast_* methods with a Ipv6Addr::unicast_scope method that returns a Ipv6UnicastScope enum (https://github.com/rust-lang/rust/pull/76098#issuecomment-735019872)?
    • [ ] Should we change the behavior of Ipv6Addr::to_ipv4 to ignore deprecated IPv4-compatible addresses, or deprecate the whole method in favor of the more correct Ipv6Addr::to_ipv4_mapped method (https://github.com/rust-lang/rust/pull/76098#discussion_r530465408)?
    • [ ] Are we ok with Ipv6Addr::is_* methods now properly considering mapped (non-deprecated) IPv4 addresses? I'd personally be comfortable considering the old behavior a bug.
    • [ ] Are there any behavioral differences between other language implementations that we should investigate? (https://github.com/rust-lang/rust/pull/76098#issuecomment-760651861)

    Lukas Kalbertodt at 2020-08-12 19:03:16

  2. I think we should consider this for stabilization in 1.6. Nominating.

    Aaron Turon at 2015-11-03 23:47:11

  3. :bell: This issue is now entering its cycle-long final comment period for stabilization :bell:

    Concretely, we discussed this in the libs meeting and the conclusion was that the boolean accessors are likely ready for stabilization after verifying that they're all the canonical definitions, but the enum-returning variants will likely remain unstable for now.

    Alex Crichton at 2015-11-05 17:44:49

  4. What, exactly, is the "ip feature"? Could you link to the RustDoc(s) of the specific things that are supposed to be reviewed?

    Brian Smith at 2015-11-05 19:20:54

  5. I think "ip feature" in this context refers to things annotated with #![unstable(feature = "ip", …)], which require #![feature(ip)] to be used.

    Simon Sapin at 2015-11-05 20:37:29

  6. I think "ip feature" in this context refers to things annotated with #![unstable(feature = "ip", …)], which require #![feature(ip)] to be used.

    I don't mean to be rude, but that's just a restating my question as the answer. if you want people to actually give feedback on the proposal, it should be easier to understand what the proposal is. In this case, it is pretty difficult to tell what is being proposed because the module mixes stable and unstable features.

    I noticed that a large part of this module could work in #![no_std] mode. I suggest moving the #![no_std]-compatible parts to core::net, or at least consider how making it work with #![no_std] would affect the API.

    It also seems odd that Ipv4Addr and Ipv6Addr have things like is_multicast and is_global but there's no trait that allows code to make these queries generically over those types of addresses. If such a trait were to bad added later, would the existence of these non-trait methods cause problems? If so, it might be worth considering building the trait first.

    Brian Smith at 2015-11-06 00:02:54

  7. @briansmith I don't think that's being rude, there's just tension here between "we've been doing this a while so we're a bit short" and "newer people might not know what that is." @SimonSapin leaned a bit towards a literal explanation, but you're right to point out that more detail is good.

    I read @alexcrichton 's comment as:

    that the boolean accessors are likely ready for stabilization after verifying that they're all the canonical definitions,

    http://doc.rust-lang.org/std/net/struct.Ipv4Addr.html and http://doc.rust-lang.org/std/net/struct.Ipv6Addr.html <- all the stuff here that is -> bool

    but the enum-returning variants will likely remain unstable for now.

    http://doc.rust-lang.org/std/net/struct.Ipv6Addr.html#method.multicast_scope is the only one I see that's unstable.

    Steve Klabnik at 2015-11-06 00:23:00

  8. FWIW, I filed https://github.com/rust-lang/rust/issues/29221 a while ago, which would make tracking down what these tracking issues refer to slightly easier.

    Huon Wilson at 2015-11-06 00:32:40

  9. Yes, to be concrete, I was proposing stabilizing:

    • Ipv4Addr::is_unspecified
    • Ipv4Addr::is_loopback
    • Ipv4Addr::is_private
    • Ipv4Addr::is_link_local
    • Ipv4Addr::is_global
    • Ipv4Addr::is_multicast
    • Ipv4Addr::is_broadcast
    • Ipv4Addr::is_documentation
    • Ipv6Addr::is_unspecified
    • Ipv6Addr::is_loopback
    • Ipv6Addr::is_global
    • Ipv6Addr::is_unique_local
    • Ipv6Addr::is_unicast_link_local
    • Ipv6Addr::is_unicast_site_local
    • Ipv6Addr::is_unicast_global
    • Ipv6Addr::is_multicast

    Note that this is all pending actually verifying that these are standard properties of the respective IP address space and are well known with canonical implementations. I believe they fit this requirement already but would like to double-check.


    @briansmith

    I suggest moving the #![no_std]-compatible parts to core::net

    Yeah these things can certainly move around over time (it's backwards compatible to move them at a later date). I'd be a little wary of putting things in core "just because" without a concrete purpose, and these kinda fall into the category I'd be wary of. For example the internal representation of each of these primitives is the libc equivalent (e.g. libc::sockaddr_in6 or libc::in_addr) which unfortunately isn't available in libcore, so if we move it to core we'd have to invent our own storage format.

    It also seems odd that Ipv4Addr and Ipv6Addr have things like is_multicast and is_global but there's no trait that allows code to make these queries generically over those types of addresses. If such a trait were to bad added later, would the existence of these non-trait methods cause problems?

    Method resolution favors inherent methods (methods defined on the type itself) over trait methods (e.g. impl'd traits plus the trait being in scope), so in that sense we're covered to add a trait at a future date. That being said the standard library doesn't have too many traits like this for abstracting between one or two types, so I would personally want to hold off on this extension for now.

    A possible alternative, however, could be adding the common set of methods to IpAddr if we end up stabilizing that as well.

    Alex Crichton at 2015-11-06 16:32:31

  10. A couple of issues I have noticed with what we have:

    • 0.0.0.0/8, :: and many more ranges shouldn't return true for is_global()
    • Ipv6Addr::is_documentation is missing and should be 2001:db8::/32

    On a more general note, might some of these functions need to be updated in the future if new ranges are assigned? How would that be handled?

    Oliver Middleton at 2015-11-09 11:00:56

  11. Ah I unfortunately did not have time to do an audit of these APIs this cycle, so when the libs team talked about this during triage today the conclusion was to punt this to next cycle, I hope to have the time to investigate it then and incorportate @ollie27's suggestions!

    Alex Crichton at 2015-12-03 02:41:24

  12. :bell: This issue is now yet again entering its final comment period :bell:

    Hopefully I get a chance to researching this API this time around!

    Alex Crichton at 2015-12-17 22:25:29

  13. Better late than never! -- my analysis:

    Of the ipv4 properties, there's more listed on wikipedia at least, for example:

    • Current network
    • Shared
    • protocol assignments (and DS-Lite)
    • ipv6 to ipv4 relay
    • benchmark tests
    • reserved

    These sound relatively obscure (at least to me) though, so it seems fine that we don't add them just yet. In terms of what we currently have:

    • [x] Ipv4Addr::is_unspecified - appears to be an ipv6 property, not ipv4?
    • [x] Ipv4Addr::is_loopback - ref
    • [x] Ipv4Addr::is_private - ref1, ref2, ref3
    • [x] Ipv4Addr::is_link_local - ref
    • [x] Ipv4Addr::is_global - not found, this is a property, but haven't found exhaustive documentation
    • [x] Ipv4Addr::is_multicast - ref
    • [x] Ipv4Addr::is_broadcast - ref
    • [x] Ipv4Addr::is_documentation - ref1, ref2, ref3

    Like with ipv4 we're missing some ipv6 properties (according to RFC 6890):

    • ipv4-ipv6 transit
    • ipv4-mapped (although we have a method to access this, so probably ok)
    • discard only
    • protocol assignments
    • TEREDO (wut?)
    • benchmarking
    • documentation
    • ORCHID
    • 6to4

    Of the ipv6 methods:

    • [x] Ipv6Addr::is_unspecified - ref
    • [x] Ipv6Addr::is_loopback - ref
    • [x] Ipv6Addr::is_global - couldn't find a reference online quickly, seems to have some interesting logic though?
    • [x] Ipv6Addr::is_unique_local - ref
    • [x] Ipv6Addr::is_unicast_link_local - ref, called "Linked-Scope Unicast" in the RFC at least, not sure about the name in that case.
    • [x] Ipv6Addr::is_unicast_site_local - didn't find a reference in this RFC at least
    • [x] Ipv6Addr::is_unicast_global - same as above, didn't find a reference (doesn't mean it's wrong though!)
    • [x] Ipv6Addr::is_multicast - ref

    From this I'm comfortable stabilizing the checked methods (they've got verified names and implementations at least), but I would personally want some more verification of the unchecked methods before stabilizing.

    Alex Crichton at 2016-01-12 23:45:24

  14. From this I'm comfortable stabilizing the checked methods (they've got verified names and implementations at least), but I would personally want some more verification of the unchecked methods before stabilizing.

    Sounds like a good start. The is_loopback would be already useful for me. Having to use only one standard type to represent an ip, no matter whether v4 or v6, would be very useful already.

    VinΓ­cius dos Santos Oliveira at 2016-01-13 09:52:47

  15. The libs team discussed this during triage yesterday and the decision was to stabilize the methods I've checked above

    Alex Crichton at 2016-01-15 17:46:30

  16. Removing from FCP as the initial round of stabilization has happened.

    Alex Crichton at 2016-01-21 18:39:25

  17. I know I'm late to the party on this, but I just got bitten by this issue when trying to implement a generic IpAddr is_unspecified method for my own use.

    The IPv4 unspecified address (which is not checked above at the time of this writing) definitely exists and is standard. It is defined on p891 of Stevens, Volume 1, Second Edition, which notes that it is all zeroes and is also referred to as INADDR_ANY. (There are numerous other references to it, but this is the most compact.) If you want an online reference, http://man7.org/linux/man-pages/man7/ip.7.html also confirms this.

    Ben Stern at 2016-07-08 00:19:44

  18. @therealbstern oh interesting! I think we're fine stabilizing if it's actually a property documented somewhere, I just couldn't find it at the time. Want to send a PR updating the docs accordingly? We may be able to consider it for stabilization next cycle.

    Alex Crichton at 2016-07-08 05:53:53

  19. I think PR #34739 does what you want, though I wasn't 100% sure what to put into the stable block. I defer future commentary to that PR.

    Ben Stern at 2016-07-10 01:34:05

  20. :bell: This issue is now entering a cycle-long final comment period πŸ””

    Specifically, the libs team is considering stabilizing Ipv4Addr::is_unspecified as proposed in https://github.com/rust-lang/rust/issues/34739. The other methods on these types will remain unstable.

    Alex Crichton at 2016-07-12 23:49:58

  21. IPv6 site local is also in Stevens, p895. I'll look for an online reference. I take it that IPv4Addr.is_global will stay unstable, despite the (admittedly inelegant) discussion at the iana-ipv4-special-registry? [That link is already documented.]

    Ben Stern at 2016-07-13 01:44:53

  22. I apologize; IPv6 site local is deprecated by RFC 3879, so I don't think stabilizing it is as good an idea.

    Ben Stern at 2016-07-13 01:46:41

  23. @therealbstern probably, yeah. Most of the instability here is just because of a lack of motivation to push them towards stable, but if they're well accepted concepts elsewhere that can be documented, we'd be fine stabilizing!

    Alex Crichton at 2016-07-13 17:58:41

  24. The libs team has also decided to throw the methods introduced in https://github.com/rust-lang/rust/pull/34694 into FCP, which is just all of these methods that are shared between v4 and v6 addrs also being exported from IpAddr

    Alex Crichton at 2016-07-19 04:22:50

  25. Discussed recently, the libs team decided to stabilize the shared methods and the is_unspecified method on Ipv4Addr

    Alex Crichton at 2016-08-11 21:14:51

  26. @rfcbot fcp close

    I feel like the remaining methods have languished long enough in the standard library. Anything that's not stable I'd think we should just deprecate/remove at this point.

    Alex Crichton at 2016-11-01 23:10:01

  27. Team member @alexcrichton has proposed to close this. The next step is review by the rest of the tagged teams:

    • [ ] @BurntSushi
    • [ ] @Kimundi
    • [x] @alexcrichton
    • [ ] @aturon
    • [ ] @brson
    • [ ] @sfackler

    No concerns currently listed.

    Once these reviewers reach consensus, this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up!

    See this document for info about what commands tagged team members can give me.

    Rust RFC bot at 2016-11-01 23:48:52

  28. Looks like

    Why is Ipv4Addr::is_documentation stable but not Ipv6::is_documentation?

    Brian Anderson at 2016-11-03 23:52:02

  29. Seems like perhaps is_documentation should be stabilized, everything else deprecated.

    Brian Anderson at 2016-11-03 23:53:36

  30. @brson I was able to find documentation for Ipv4Addr::is_documentation but couldn't find documentation on the Ipv6Addr. That being said, briefly taking a look at the ipv4 docs points me to https://tools.ietf.org/html/rfc3849 which has documentation for ipv6. In that sense I'd be fine considering stabilization of that and deprecation of everything else.

    Alex Crichton at 2016-11-04 02:03:04

  31. Some more docs: Ipv4Addr::is_global https://tools.ietf.org/html/rfc5735#page-3 Ipv6Addr::is_global https://tools.ietf.org/html/rfc4291#section-2.5.4 Ipv6Addr::is_unicast_link_local https://tools.ietf.org/html/rfc4291#section-2.5.6 Ipv6Addr::is_unicast_site_local https://tools.ietf.org/html/rfc4291#section-2.5.7 Ipv6Addr::is_unicast_global https://tools.ietf.org/html/rfc4291#section-2.5.4 Ipv6Addr::multicast_scope and Ipv6MulticastScope https://tools.ietf.org/html/rfc4291#section-2.7

    Abhishek Chanda at 2016-11-04 09:29:35

  32. @rfcbot fcp cancel

    ok, seems like we shouldn't deprecate!

    Alex Crichton at 2016-11-04 20:08:19

  33. Can we fcp to stabilize then (assuming that the implementations correspond to what they should be)?

    Steven Fackler at 2016-11-04 20:11:57

  34. @alexcrichton proposal cancelled.

    Rust RFC bot at 2016-11-04 20:12:29

  35. @sfackler presumably, yeah, but I don't really have the time right now to audit everything much less deal with Ipv6MulticastScope, so I'll leave that to someone else to propose FCP :)

    Alex Crichton at 2016-11-04 21:43:51

  36. @alexcrichton let me know if I can help with anything here

    Abhishek Chanda at 2016-11-04 22:44:49

  37. @achanda sure yeah the next step for stabilizing this would be to audit all implementations to ensure they match precisely what the RFCs mention, and then ensure all document references the relevant RFC as well. We may want to leave multicast_scope out for now as it has an enum, but it'd be good to read up on that and ensure it matches the RFC.

    Alex Crichton at 2016-11-07 05:19:08

  38. ping @achanda, any updates? I just came across a use for is_global and possibly is_link_local, would be nice to get them in stable.

    Kamal Al Marhubi at 2017-01-30 05:40:53

  39. @kamalmarhubi sorry, I forgot about this one. Let me get back to this as soon as I can (should be a few days).

    Abhishek Chanda at 2017-01-30 09:54:04

  40. @achanda no worries!

    Kamal Al Marhubi at 2017-02-08 04:22:51

  41. Any update on this?

    James Brown at 2017-12-07 05:09:32

  42. I'd also love to have is_global stabilized.

    Craig Hills at 2017-12-07 20:30:04

  43. I have updated the original issue description to include a list of the methods currently unstable under the ip feature. If anyone is interested in pushing any given method to stability, I believe a PR with associated documentation (as in the description above) would be welcomed.

    Mark Rousskov at 2018-01-15 23:22:34

  44. The implementation of Ipv4::is_global is not complete, according to the IANA IPv4 Special-Purpose Address Registry.

    • It compares the address to 0.0.0.0, but anything in 0.0.0.0/8 should not be considered global.
      • 0/8 is not global and is currently forbidden because some systems used to treat it as the local network.
      • The implementation of Ipv4::is_unspecified is correct. 0.0.0.0 is the unspecified address.
    • It does not examine 100.64.0.0/10, which is "Shared Address Space" and not global.
    • Ditto 192.0.0.0/24 (IETF Protocol Assignments), except for 192.0.0.9/32 and 192.0.0.10/32, which are carved out as globally reachable.
    • 198.18.0.0/15 is for "Benchmarking" and should not be globally reachable.
    • 240.0.0.0/4 is reserved and not currently reachable

    There are also no methods that identify the netblocks identified above.

    Ben Stern at 2018-01-16 03:48:50

  45. I may be wrong but Ipv6::is_unicast_link_local() seems wrong to me. The current implementation is:

    pub fn is_unicast_link_local(&self) -> bool {
        (self.segments()[0] & 0xffc0) == 0xfe80
    }
    

    But the RFC says:

       Link-Local addresses are for use on a single link.  Link-Local
       addresses have the following format:
    
       |   10     |
       |  bits    |         54 bits         |          64 bits           |
       +----------+-------------------------+----------------------------+
       |1111111010|           0             |       interface ID         |
       +----------+-------------------------+----------------------------+
    
       Link-Local addresses are designed to be used for addressing on a
       single link for purposes such as automatic address configuration,
       neighbor discovery, or when no routers are present.
    
       Routers must not forward any packets with Link-Local source or
       destination addresses to other links.
    

    So I think this should be:

    pub fn is_unicast_link_local(&self) -> bool {
        (self.segments()[0] & 0xffff) == 0xfe80
            && (self.segments()[1] & 0xffff) == 0
            && (self.segments()[2] & 0xffff) == 0
            && (self.segments()[3] & 0xffff) == 0
    }
    

    If you agree I'll open a PR.

    little-dude at 2018-06-25 23:13:47

  46. Also, I think it would be worth having Ipv6::is_ipv4_compatible and Ipv6::is_ipv4_mapped(). I can also open a PR for that.

    little-dude at 2018-06-25 23:17:01

  47. @Mark-Simulacrum

    I have updated the original issue description to include a list of the methods currently unstable under the ip feature. If anyone is interested in pushing any given method to stability, I believe a PR with associated documentation (as in the description above) would be welcomed.

    I'd like to work on that. I'll try to send a first PR tonight.

    little-dude at 2018-06-25 23:23:13

  48. @little-dude, The errata for RFC 4291, and more specifically erratum 4406 make this much less clear than one might think. /10 is reserved for link-local and similar uses, though only /64 is defined right now, and they don't name what the rest of it for. RFC 7371 also takes the opportunity to mention that the link-local /10 exists and then appears to discuss multicast without regard to whether or not it's a new chunk of the /10 or not.

    Anyway, the point is, although I agreed with your suggestion so much that I initially thought I had written it, I'm no longer so sure how to stand on this.

    Ben Stern at 2018-06-26 05:48:25

  49. I see, it's debatable indeed. To sum up:

    • fe80::/10 is reserved
    • fe80::/64 is the currenttly defined link local unicast

    I have slight preference for validating the second range since that as of today, the only valid unicast link local addresses are in fe80::/64.

    Otherwise, why not having two methods with a detailed documentation of how they differ: is_link_local() for fe80/10 and is_link_local_strict() for fe80/64?

    little-dude at 2018-06-26 14:15:24

  50. @therealbstern I've started working on fixing Ipv4Addr::is_global as per your comment.

    little-dude at 2018-06-26 14:17:44

  51. Obviously, I'm not in charge of the API here, but I personally think your validation plan is the way to fly. Also, the looser method would help more with the "is this globally routable" question.

    Did you understand what RFC 7371 was saying? I thought it meant that some of the /10 link-local space was going to become multicast, but I might have completely misunderstood. :-P

    Ben Stern at 2018-06-26 16:11:46

  52. Why is this still unstable?

    Jens Hausdorf at 2018-10-07 07:31:53

  53. This PR has not been finished. You can pick it up if you want, or I can try finishing it but I won't be able to this week.

    little-dude at 2018-10-07 14:24:50

  54. No, take your time. :) I'm terribly sorry for pressing hard, I just wondered, by no means did I want to attack you and your work. I do not know a lot about the RFC process here and marking things as stable. My laptop is too weak to test out the changes.

    Jens Hausdorf at 2018-10-07 14:46:23

  55. Hey, how do I stabilize these methods? What is the procedure?

    Roman at 2018-11-16 10:28:38

  56. @kpp you can start from my pr if you want https://github.com/rust-lang/rust/pull/51832

    little-dude at 2018-11-16 14:39:04

  57. Or I'll try to finish it off this weekend if you don't. I'm a bit disappointed that I did not push it to the finish line.

    little-dude at 2018-11-16 14:41:13

  58. I won't =) Push it to the finish line!

    Roman at 2018-11-16 14:49:06

  59. FYI, a bug was just filed related to is_global: https://github.com/rust-lang/rust/issues/57558

    Corey Farwell at 2019-01-13 17:54:03

  60. As above, this has been a problem for a while and is not a regression. I did not fix it because it looked like trying to figure how to name the reason that an IPv4 address might not be global looked like a maze of twisty little passages all alike.

    If naming the various blocks or otherwise identifying them in the API is not significant, then I can pick this up and fix it for IPv4.

    Ben Stern at 2019-01-13 19:39:19

  61. @little-dude please finish https://github.com/rust-lang/rust/pull/56050

    Roman at 2019-01-13 21:03:23

  62. ping?

    Roman at 2019-04-07 21:30:05

  63. I'm stuck on nightly because of ip6.is_unicast_link_local(). Is this one ready to become stable yet?

    Tom Pusateri at 2019-04-19 20:55:08

  64. Sorry for the delay, I'll re-open the PR this afternoon. Looking at it, it seems some tests were missing/failing. I had a hard time debugging so I wanted to refactor the tests a bit.

    little-dude at 2019-04-20 08:34:03

  65. Not much has happened since https://github.com/rust-lang/rust/pull/60145. Should we go ahead an stabilize the Ipv4Addr and Ipv6Addr that are behind the ip feature?

    little-dude at 2019-08-15 19:11:34

  66. Do we know what rust release the stabilization would occur in? I'd love to know when I can move to stable for one of my apps that relies on this.

    Craig Hills at 2019-11-20 15:48:41

  67. @chills42 I just opened a PR to stabilize this.

    little-dude at 2019-11-20 20:03:19

  68. Stabilization concern: There are motions under way[0][1] to slowly free up some of the reserved ipv4 ranges to make them useable as unicast addresses at some point in the future.

    We discussed a similar concerns in #60145. For ipv6 the spec already says that is_global is a heuristic and must include reserved ranges per spec, so it wasn't a concern there while IPv4 was presumed set in stone. I wasn't aware of the above-mentioned plans, so we should reconsider.

    Perhaps we could leave Ipv4Addr::is_global unstable or use the ipv6 approach (only exclude known non-global uses) instead. Or we could add a warning that these methods are subject to expected future standard changes, in fact there is an issue open for this #60239, perhaps that should be done before stabilizing.

    [0] https://www.netdevconf.info/0x13/session.html?talk-ipv4-unicast-expansions [1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=96125bf9985a

    the8472 at 2019-11-20 21:23:17

  69. I'd be in favor of stabilizing everything, because if I understand correctly Ipv4Addr::is_global is correct, as per the current state of the RFCs (Linux allows 0.x.y.z addresses, but it hasn't been enacted by an RFC yet).

    I prefer your second proposal: adding the disclaimer discussed in https://github.com/rust-lang/rust/issues/60239.

    little-dude at 2019-11-20 22:03:47

  70. @little-dude you can send a stabilisation PR that stabilises the functions / module and then we can see what's missing or left to be done.

    Dylan DPC at 2019-12-20 09:41:23

  71. @Dylan-DPC I did already: https://github.com/rust-lang/rust/pull/66584

    little-dude at 2019-12-20 10:12:31

  72. Add Ipv6Addr::to_ipv4_mapped: #75019

    ε—ζ΅¦ζœˆ at 2020-08-04 15:49:35

  73. Hey so I think PR #76098 covers this stuff but I'm not sure? It's basically just an extension of #66584.

    Cass Fridkin at 2020-09-04 03:33:24

  74. By the way, why not have a trait Ip for common feature on both ipv4 and ipv6 ?

    Stargateur at 2020-10-02 09:33:20

  75. sorry, the ip interface detoriorated recently

    1. parsing of 001.001.001.001 does NOT work anymore. Broke lots stuff. ARguyable this is valid IP address even with leading zeroes b) where is is_unicast_link_local_strict all of a sudden on rustc 1.54.0-nightly (ed597e7e1 2021-06-08) ?

    Tony Przygienda at 2021-06-09 13:25:03

  76. Yes, code recently get more strict about ipv4 parsing.

    ipv4 didn't have a official ABNF until ipv6 but according to it:

         IPv4address   = dec-octet "." dec-octet "." dec-octet "." dec-octet
         dec-octet     = DIGIT                 ; 0-9
                        / %x31-39 DIGIT         ; 10-99
                        / "1" 2DIGIT            ; 100-199
                        / "2" %x30-34 DIGIT     ; 200-249
                        / "25" %x30-35          ; 250-255
    

    and so 001.001.001.001 is not a valid text representation of an ipv4 address.

    is_unicast_link_local_strict() have never been stable so that can't be considered breaking change. See https://github.com/rust-lang/rust/pull/85819 for more

    Stargateur at 2021-06-09 13:46:40

  77. So what is holding up the stabilization of methods like Ipv6Addr::is_unicast_link_local()? Certainly that could be considered stable by now, right?

    Robert Quattlebaum at 2022-05-19 19:36:38

  78. Regarding the is_global function applied to ipv4 and ipv6 addresses here, when looking at the IANA standard, I realized that there are several addresses considered as Special-Purpose Address which are not listed in the std is_global condition. Is this normal?

    • ipv4 IANA list: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml#note2
    • ipv6 IANA list: https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml

    Despite the fact that some of the addresses in the IANA table are considered globally reachable, it is notified at the beginning of the document:

    Address prefixes listed in the Special-Purpose Address Registry are not guaranteed routability in any particular local or global context.

    So in my view all addresses in the IANA table should be considered in the condition as not being is_global, is there something I've misunderstood here?

    Thomas Coratger at 2023-04-27 17:46:08

  79. Hi everyone,

    The following concerns mostly is_global and a little bit is_unicast_global.

    I took the ipcheck tool[1] (which gave us some very useful data two years ago[2]) and modified it slightly to:

    • Extend the range of addresses tested[3]
    • Use the current Rust implementation as the baseline[4]
    • Optionally compare against multiple Python versions (because I've been working on the Python side of things as well)
    • Only include the differences on the is_global front as the rest didn't interest me

    I present you two tables. The content is collapsed because of its length, you'll have to click on the arrows to see everything.

    <details> <summary>Table 1. The status quo as of today (Rust nightly, Python versions as specified, Go 1.21.5)</summary>

    | addr | Python 3.8 | Python 3.9 | Python 3.10 | Python 3.11 | Python 3.12 | Go | | - | - | - | - | - | - | - | | 0.0.0.0 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | | 0.1.2.3 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | 1.1.1.1 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | | 127.0.0.1 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | | 255.255.255.255 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | | 10.0.0.1 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | 16.89.10.65 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | | 45.22.13.197 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | | 100.64.0.0 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | 100.128.0.0 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | | 169.254.0.0 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | | 172.16.10.10 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | 192.0.0.0 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | 192.0.0.7 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | 192.0.0.8 | ❌ { is_global : false (Rust) β‰  true (Python 3.8) } | ❌ { is_global : false (Rust) β‰  true (Python 3.9) } | ❌ { is_global : false (Rust) β‰  true (Python 3.10) } | ❌ { is_global : false (Rust) β‰  true (Python 3.11) } | ❌ { is_global : false (Rust) β‰  true (Python 3.12) } | ❌ { is_global : false (Rust) β‰  true (Go) } | | 192.0.0.9 | ❌ { is_global : false (Rust) β‰  true (Python 3.8) } | ❌ { is_global : false (Rust) β‰  true (Python 3.9) } | ❌ { is_global : false (Rust) β‰  true (Python 3.10) } | ❌ { is_global : false (Rust) β‰  true (Python 3.11) } | ❌ { is_global : false (Rust) β‰  true (Python 3.12) } | ❌ { is_global : false (Rust) β‰  true (Go) } | | 192.0.0.10 | ❌ { is_global : false (Rust) β‰  true (Python 3.8) } | ❌ { is_global : false (Rust) β‰  true (Python 3.9) } | ❌ { is_global : false (Rust) β‰  true (Python 3.10) } | ❌ { is_global : false (Rust) β‰  true (Python 3.11) } | ❌ { is_global : false (Rust) β‰  true (Python 3.12) } | ❌ { is_global : false (Rust) β‰  true (Go) } | | 192.0.0.169 | ❌ { is_global : false (Rust) β‰  true (Python 3.8) } | ❌ { is_global : false (Rust) β‰  true (Python 3.9) } | ❌ { is_global : false (Rust) β‰  true (Python 3.10) } | ❌ { is_global : false (Rust) β‰  true (Python 3.11) } | ❌ { is_global : false (Rust) β‰  true (Python 3.12) } | ❌ { is_global : false (Rust) β‰  true (Go) } | | 192.0.0.170 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | 192.0.0.171 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | 192.0.0.172 | ❌ { is_global : false (Rust) β‰  true (Python 3.8) } | ❌ { is_global : false (Rust) β‰  true (Python 3.9) } | ❌ { is_global : false (Rust) β‰  true (Python 3.10) } | ❌ { is_global : false (Rust) β‰  true (Python 3.11) } | ❌ { is_global : false (Rust) β‰  true (Python 3.12) } | ❌ { is_global : false (Rust) β‰  true (Go) } | | 192.0.0.255 | ❌ { is_global : false (Rust) β‰  true (Python 3.8) } | ❌ { is_global : false (Rust) β‰  true (Python 3.9) } | ❌ { is_global : false (Rust) β‰  true (Python 3.10) } | ❌ { is_global : false (Rust) β‰  true (Python 3.11) } | ❌ { is_global : false (Rust) β‰  true (Python 3.12) } | ❌ { is_global : false (Rust) β‰  true (Go) } | | 192.0.2.2 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | 192.31.196.2 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | | 192.52.193.2 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | | 192.88.99.2 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | | 192.168.0.2 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | 192.175.48.2 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | | 198.18.0.0 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | 198.51.100.2 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | 203.0.113.6 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | 240.0.0.0 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | 255.255.255.254 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:0.0.0.0 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | | ::ffff:0.1.2.3 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:1.1.1.1 | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Python 3.10) } | ❌ { is_global : false (Rust) β‰  true (Python 3.11) } | ❌ { is_global : false (Rust) β‰  true (Python 3.12) } | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:127.0.0.1 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | | ::ffff:255.255.255.255 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | | ::ffff:10.0.0.1 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:16.89.10.65 | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Python 3.10) } | ❌ { is_global : false (Rust) β‰  true (Python 3.11) } | ❌ { is_global : false (Rust) β‰  true (Python 3.12) } | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:45.22.13.197 | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Python 3.10) } | ❌ { is_global : false (Rust) β‰  true (Python 3.11) } | ❌ { is_global : false (Rust) β‰  true (Python 3.12) } | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:100.64.0.0 | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Python 3.10) } | ❌ { is_global : false (Rust) β‰  true (Python 3.11) } | ❌ { is_global : false (Rust) β‰  true (Python 3.12) } | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:100.128.0.0 | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Python 3.10) } | ❌ { is_global : false (Rust) β‰  true (Python 3.11) } | ❌ { is_global : false (Rust) β‰  true (Python 3.12) } | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:169.254.0.0 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | | ::ffff:172.16.10.10 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:192.0.0.0 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:192.0.0.7 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:192.0.0.8 | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Python 3.10) } | ❌ { is_global : false (Rust) β‰  true (Python 3.11) } | ❌ { is_global : false (Rust) β‰  true (Python 3.12) } | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:192.0.0.9 | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Python 3.10) } | ❌ { is_global : false (Rust) β‰  true (Python 3.11) } | ❌ { is_global : false (Rust) β‰  true (Python 3.12) } | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:192.0.0.10 | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Python 3.10) } | ❌ { is_global : false (Rust) β‰  true (Python 3.11) } | ❌ { is_global : false (Rust) β‰  true (Python 3.12) } | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:192.0.0.169 | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Python 3.10) } | ❌ { is_global : false (Rust) β‰  true (Python 3.11) } | ❌ { is_global : false (Rust) β‰  true (Python 3.12) } | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:192.0.0.170 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:192.0.0.171 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:192.0.0.172 | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Python 3.10) } | ❌ { is_global : false (Rust) β‰  true (Python 3.11) } | ❌ { is_global : false (Rust) β‰  true (Python 3.12) } | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:192.0.0.255 | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Python 3.10) } | ❌ { is_global : false (Rust) β‰  true (Python 3.11) } | ❌ { is_global : false (Rust) β‰  true (Python 3.12) } | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:192.0.2.2 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:192.31.196.2 | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Python 3.10) } | ❌ { is_global : false (Rust) β‰  true (Python 3.11) } | ❌ { is_global : false (Rust) β‰  true (Python 3.12) } | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:192.52.193.2 | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Python 3.10) } | ❌ { is_global : false (Rust) β‰  true (Python 3.11) } | ❌ { is_global : false (Rust) β‰  true (Python 3.12) } | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:192.88.99.2 | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Python 3.10) } | ❌ { is_global : false (Rust) β‰  true (Python 3.11) } | ❌ { is_global : false (Rust) β‰  true (Python 3.12) } | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:192.168.0.2 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:192.175.48.2 | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Python 3.10) } | ❌ { is_global : false (Rust) β‰  true (Python 3.11) } | ❌ { is_global : false (Rust) β‰  true (Python 3.12) } | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:198.18.0.0 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:198.51.100.2 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:203.0.113.6 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:240.0.0.0 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:255.255.255.254 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::1 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | | :: | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | | 64:ff9b:: | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | | 64:ff9b:1:: | ❌ { is_global : false (Rust) β‰  true (Python 3.8) } | ❌ { is_global : false (Rust) β‰  true (Python 3.9) } | ❌ { is_global : false (Rust) β‰  true (Python 3.10) } | ❌ { is_global : false (Rust) β‰  true (Python 3.11) } | ❌ { is_global : false (Rust) β‰  true (Python 3.12) } | ❌ { is_global : false (Rust) β‰  true (Go) } | | 100:: | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | 2001:: | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | 2001:1::1 | ❌ { is_global : true (Rust) β‰  false (Python 3.8) } | ❌ { is_global : true (Rust) β‰  false (Python 3.9) } | ❌ { is_global : true (Rust) β‰  false (Python 3.10) } | ❌ { is_global : true (Rust) β‰  false (Python 3.11) } | ❌ { is_global : true (Rust) β‰  false (Python 3.12) } | βœ”οΈ | | 2001:1::2 | ❌ { is_global : true (Rust) β‰  false (Python 3.8) } | ❌ { is_global : true (Rust) β‰  false (Python 3.9) } | ❌ { is_global : true (Rust) β‰  false (Python 3.10) } | ❌ { is_global : true (Rust) β‰  false (Python 3.11) } | ❌ { is_global : true (Rust) β‰  false (Python 3.12) } | βœ”οΈ | | 2001:2:: | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | 2001:0002:6c::430 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | 2001:3:: | ❌ { is_global : true (Rust) β‰  false (Python 3.8) } | ❌ { is_global : true (Rust) β‰  false (Python 3.9) } | ❌ { is_global : true (Rust) β‰  false (Python 3.10) } | ❌ { is_global : true (Rust) β‰  false (Python 3.11) } | ❌ { is_global : true (Rust) β‰  false (Python 3.12) } | βœ”οΈ | | 2001:4:112:: | ❌ { is_global : true (Rust) β‰  false (Python 3.8) } | ❌ { is_global : true (Rust) β‰  false (Python 3.9) } | ❌ { is_global : true (Rust) β‰  false (Python 3.10) } | ❌ { is_global : true (Rust) β‰  false (Python 3.11) } | ❌ { is_global : true (Rust) β‰  false (Python 3.12) } | βœ”οΈ | | 2001:10:: | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | 2001:10:240:ab::a | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | 2001:20:: | ❌ { is_global : true (Rust) β‰  false (Python 3.8) } | ❌ { is_global : true (Rust) β‰  false (Python 3.9) } | ❌ { is_global : true (Rust) β‰  false (Python 3.10) } | ❌ { is_global : true (Rust) β‰  false (Python 3.11) } | ❌ { is_global : true (Rust) β‰  false (Python 3.12) } | βœ”οΈ | | 2001:30:: | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | 2001:db8:8:4::2 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | 2002:: | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | | 2002:cb0a:3cdd:1::1 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | | 2620:4f:8000:: | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | | fdf8:f53b:82e4::53 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | fe80::200:5aee:feaa:20a2 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | | ff01:0:0:0:0:0:0:2 | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | βœ”οΈ | ❌ { is_global : true (Rust) β‰  false (Go) } |

    </details> <details> <summary>Table 2. Patched Rust, patched CPython, regular Go.</summary>

    | addr | Python | Go | | - | - | - | | 0.0.0.0 | βœ”οΈ | βœ”οΈ | | 0.1.2.3 | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | 1.1.1.1 | βœ”οΈ | βœ”οΈ | | 127.0.0.1 | βœ”οΈ | βœ”οΈ | | 255.255.255.255 | βœ”οΈ | βœ”οΈ | | 10.0.0.1 | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | 16.89.10.65 | βœ”οΈ | βœ”οΈ | | 45.22.13.197 | βœ”οΈ | βœ”οΈ | | 100.64.0.0 | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | 100.128.0.0 | βœ”οΈ | βœ”οΈ | | 169.254.0.0 | βœ”οΈ | βœ”οΈ | | 172.16.10.10 | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | 192.0.0.0 | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | 192.0.0.7 | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | 192.0.0.8 | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | 192.0.0.9 | βœ”οΈ | βœ”οΈ | | 192.0.0.10 | βœ”οΈ | βœ”οΈ | | 192.0.0.169 | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | 192.0.0.170 | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | 192.0.0.171 | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | 192.0.0.172 | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | 192.0.0.255 | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | 192.0.2.2 | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | 192.31.196.2 | βœ”οΈ | βœ”οΈ | | 192.52.193.2 | βœ”οΈ | βœ”οΈ | | 192.88.99.2 | βœ”οΈ | βœ”οΈ | | 192.168.0.2 | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | 192.175.48.2 | βœ”οΈ | βœ”οΈ | | 198.18.0.0 | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | 198.51.100.2 | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | 203.0.113.6 | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | 240.0.0.0 | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | 255.255.255.254 | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:0.0.0.0 | βœ”οΈ | βœ”οΈ | | ::ffff:0.1.2.3 | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:1.1.1.1 | ❌ { is_global : false (Rust) β‰  true (Python) } | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:127.0.0.1 | βœ”οΈ | βœ”οΈ | | ::ffff:255.255.255.255 | βœ”οΈ | βœ”οΈ | | ::ffff:10.0.0.1 | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:16.89.10.65 | ❌ { is_global : false (Rust) β‰  true (Python) } | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:45.22.13.197 | ❌ { is_global : false (Rust) β‰  true (Python) } | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:100.64.0.0 | ❌ { is_global : false (Rust) β‰  true (Python) } | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:100.128.0.0 | ❌ { is_global : false (Rust) β‰  true (Python) } | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:169.254.0.0 | βœ”οΈ | βœ”οΈ | | ::ffff:172.16.10.10 | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:192.0.0.0 | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:192.0.0.7 | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:192.0.0.8 | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:192.0.0.9 | ❌ { is_global : false (Rust) β‰  true (Python) } | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:192.0.0.10 | ❌ { is_global : false (Rust) β‰  true (Python) } | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:192.0.0.169 | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:192.0.0.170 | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:192.0.0.171 | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:192.0.0.172 | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:192.0.0.255 | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:192.0.2.2 | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:192.31.196.2 | ❌ { is_global : false (Rust) β‰  true (Python) } | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:192.52.193.2 | ❌ { is_global : false (Rust) β‰  true (Python) } | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:192.88.99.2 | ❌ { is_global : false (Rust) β‰  true (Python) } | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:192.168.0.2 | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:192.175.48.2 | ❌ { is_global : false (Rust) β‰  true (Python) } | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:198.18.0.0 | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:198.51.100.2 | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:203.0.113.6 | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:240.0.0.0 | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::ffff:255.255.255.254 | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | ::1 | βœ”οΈ | βœ”οΈ | | :: | βœ”οΈ | βœ”οΈ | | 64:ff9b:: | βœ”οΈ | βœ”οΈ | | 64:ff9b:1:: | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | 100:: | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | 2001:: | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | 2001:1::1 | βœ”οΈ | βœ”οΈ | | 2001:1::2 | βœ”οΈ | βœ”οΈ | | 2001:2:: | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | 2001:0002:6c::430 | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | 2001:3:: | βœ”οΈ | βœ”οΈ | | 2001:4:112:: | βœ”οΈ | βœ”οΈ | | 2001:10:: | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | 2001:10:240:ab::a | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | 2001:20:: | βœ”οΈ | βœ”οΈ | | 2001:30:: | βœ”οΈ | βœ”οΈ | | 2001:db8:8:4::2 | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | 2002:: | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | 2002:cb0a:3cdd:1::1 | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | 2620:4f:8000:: | βœ”οΈ | βœ”οΈ | | fdf8:f53b:82e4::53 | βœ”οΈ | ❌ { is_global : false (Rust) β‰  true (Go) } | | fe80::200:5aee:feaa:20a2 | βœ”οΈ | βœ”οΈ | | ff01:0:0:0:0:0:0:2 | βœ”οΈ | ❌ { is_global : true (Rust) β‰  false (Go) } |

    </details>

    In table 1 you'll see some Rust/Python disagreement in the following ranges: 192.0.0.0/24, 64:ff9b:1::/48, 2001::/23.

    You'll also notice that starting with version 3.10 Python started to interpret IPv4-mapped IPv6 addresses as their IPv4 counterparts for the purposes of evaluating is_global – it's not important to my message but I thought I'd mention it. I'm not particularly fond of that.

    I consider both Rust and Python implementations somewhat buggy, sometimes buggy in the same way (for example when it comes to the 2002::/16 range).

    In table 2 we have Rust/Python/Go comparison where

    • Rust is patched with https://github.com/rust-lang/rust/pull/119006
    • Python is patched with https://github.com/python/cpython/pull/113179

    With the patches in place Rust and Python are in almost perfect agreement on the is_global front – the only exception is handling of the IPv4-mapped IPv6 addresses. I believe it's a direction worth pursuing.

    With the Rust patch the number of Rust/Go disagreements decreases by 1 (I think) but the nature of the disagreements changes (in both ways, it's roughly equalized).

    The implementation I propose is consistent with what's proposed by @tcoratger above (https://github.com/rust-lang/rust/issues/27709#issuecomment-1526091769).

    The tables don't capture the difference in is_unicast_global behavior as ipcheck doesn't test that.

    [1] https://github.com/rust-lang/libs-team/tree/main/tools/ipcheck [2] https://github.com/rust-lang/rust/pull/76098#issuecomment-760651861 [3] https://github.com/rust-lang/libs-team/pull/317 [4] https://github.com/rust-lang/libs-team/pull/318

    Jakub Stasiak at 2023-12-16 01:33:23

  80. looking forward to stabilisation of Ipv4Addr::is_reserved!

    could theses simple convenience methods be included? possibly also on SocketAddr

    impl IpAddr {
        pub fn ipv4(&self) -> Option<&Ipv4Addr> {
            match self {
                IpAddr::V4(ip) => Some(ip),
                IpAddr::V6(_) => None,
            }
        }
    
        pub fn ipv6(&self) -> Option<&Ipv6Addr> {
            match self {
                IpAddr::V4(_) => None,
                IpAddr::V6(ip) => Some(ip),
            }
        }
    }
    

    Emilia Hane at 2024-05-20 07:13:14

  81. How can I help with stabilizing Ipv4Addr::is_global()?

    Charlotte Herngreen at 2025-01-27 13:18:35

  82. Hi @alexcrichton , can you please mark stabilize IpAddr::is_global ?

    ssrlive at 2025-03-06 12:37:18