Code Monkey home page Code Monkey logo

rust-netaddr2's Introduction

rust-netaddr2 (netaddr2) • Build Status codecov version downloads docs.rs

This crate is meant as a replacement for an existing reimplementation of various "netaddr" libraries that other languages have. There does exist another netaddr crate, however the author of this crate did not respond when asked about maintainership status.

What it does

NetAddr arose out of a need to mask and subnet IP space in a manner identical to that which routers and network interfaces do. Its utility may be most fully realized in the development of tooling for such purposes.

Usage

There are a few ways to use this library. Perhaps most ergonomical of these is to use the FromStr trait:

let net: NetAddr = "ff02::1/128".parse().unwrap();
let net: Netv4Addr = "203.0.113.19/29".parse().unwrap();

You can do some operations with these parsed structures, like checking address containment:

let net: NetAddr = "10.10.10.0/24".parse().unwrap();
let addr: IpAddr = "10.10.10.1".parse().unwrap();
assert!(net.contains(&addr));

(More options will be added eventually.)

Vision

This crate aims to be as simple and straightforward as possible. We accomplish this by mirroring the structure of the std::net::Ip.*Addr data structures. Most of the operations on NetAddr structs are implemented through the use of traits which are implemented both on the main structures and on the enum that bridges them. These are also implemented, where appropriate, for standard library structures.

This crate has no dependencies, and will not accept any unless required for no_std support. The only part of this crate that uses std is the part that bridges with std::net::IpAddr, so a potential contribution would be to generalize std::net::IpAddr in a no_std environment.

Maintenance Status

This codebase is still not feature-complete. Check out the issue tracker if you want to contribute, and don't hesistate to ask for something in an Issue. That said, the business logic is tested and should work. We will release version 1.0 when the GitHub milestone has been fully resolved.

License

Copyright © 2019—2022 Kristofer J. Rye

This software is released under either of:

at your discretion. Please see the license file (LICENSE.md) for more information.

Acknowledgements

We would like to thank the developers of the netaddr Ruby gem for inspiring the development and ergonomics of this project.

rust-netaddr2's People

Contributors

dependabot-preview[bot] avatar rye avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

rust-netaddr2's Issues

Panic when parsing a string that doesn't split

This should not happen; FromStr should not panic but instead return a variable.

While these are obvious garbage, you can see what's happening here—we're trying to index poorly into obvious garbage. Maybe don't do that!

Examples from my fuzzer:

"2620:132:b004:20::0o73".parse(); // panic
"2620:132:b004:20::0�73".parse(); // panic
"�ʦ2\n�d����3�".parse(); // panic
"䀀".parse(); // panic
"򜜜".parse(); // panic
"10.4.32.0/204:20::0/睝00MMMMMMMMMMMMMMMMMM����dMMMMMMM0#7�".parse(); // panic
"100.4.32.0/20::0/7睝Νŝ0  � ///// 0S3Ν�AŝE0�3Νŝ0S3Ν0W0S3Ν\nAŝ07睝Νŝ00S3Ν�Aŝ00�3Νŝ00S3    W:22G3Ν���3Νŝ00S3ʝ�A3ų\n\nŝ00W3΂� W W:22G W WD2@G�022222222222222222=:24\n0=:".parse(); // panic

Improved Contains ergonomics

The current ergonomics of Contains are… not the most fantastically optimal:

/// Check containment of one object within another
pub trait Contains {
fn contains<T: Copy>(&self, other: &T) -> bool
where
Self: From<T>;
}

The problem with this is that all impls are constrained to From-convertible types (which is nice) but this means that some additional work is always done to first create a new Net.*Addr type and then take the address. In cases where we're checking IP containment, we only need to mask the provided IP; there's no need to create anything and copy bytes around.

I propose to add a type parameter to the Contains type and require the contains method to take that value. Ideally, without breaking existing code.

Add Validations

As part of #26, we should include some kind of implementation for C-VALIDATE in all of the methods that require the NetAddr to be fully masked.

The worst case I can think of is a NetAddr that isn't masked, which doesn't really cause any harm as masking usually happens regardless. But, if somehow memory gets corrupted and a mask changes, the NetAddr's addr might be wrong. (Think: unsafeness through FFI or something ridiculous like that.)

I think it's sufficient to add debug_assert!'s. Could also add a feature for checks which would be on by default.

Worth some thinking.

Implement Iterator-y traits

I think I've finally settled on a way of doing this.

We need three "families" of traits, to be complete, I think.

  • Net.*AddrAddressIterator is the simplest. This struct will cover iteration over a network's addresses, starting from the network address (or whatever the addr field contains, which should be asserted per #70.)
  • Net.*AddrSubnetIterator is the second-simplest. This struct will cover iterating over a network's subnets. I will need to work out how to compute the next sibling of a given network.
    • So for example, iterating over a /24 in groups of /28's will require adding a certain offset rather than just 1.
    • Net.*AddrAddressIterator can be rewritten to just use a SubnetIterator with /32 or /128, and conversion overhead is pretty minimal.
  • Net.*AddrSiblingIterator would yield a network's siblings until IP space is exhausted.

On each of the NetAddr, Netv4Addr, and Netv6Addr types, we need to implement:

  • addresses(&self) -> Net.*AddrAddressIterator,
  • subnets(&self, mask: Into<Ip.*Addr>) -> Net.*AddrSubnetIterator
  • siblings(&self /*, any params???? */ ) -> Net.*AddrSiblingIterator

RFC 1519 / RFC 4632 — Require contiguous netmasks

Conceptually, it's possible to have non-contiguous netmasks when you're building networks.

Some background I've found during research:

  • IETF RFC 950 (1985) specifies that contiguous netmasks are not a requirement. Explicitly,

    Since the bits that identify the subnet are specified by a
    bitmask, they need not be adjacent in the address. However, we
    recommend that the subnet bits be contiguous and located as the
    most significant bits of the local address.

  • IETF RFC 1519 (1993) (superseded by IETF RFC 4632, 2006) seems to require contiguous netmasks instead, though:

    An implementation following these rules should also be generalized,
    so that an arbitrary network number and mask are accepted for all
    routing destinations. The only outstanding constraint is that the
    mask must be left contiguous.

This comes down to a question of intention. I intend for this crate to be used in any networking scenario, and with this scope corner cases abound. I could foresee a network operator deciding that—despite it being a terrible practice—using non-contiguous netmasks is a good idea, and they might want to check only a certain subset of the netmask. The question at hand is: is it even feasible for non-contiguous netmasks to be specified?

  • On the public internet, the answer is no. Since allocations are now based on left-contiguous netmasks only (per RFC1519 and 4632), it's not really possible to get something other than a /xx.
  • But in the private space, the answer is maybe. For example, what if I (as the operator) wanted only to give out DHCP leases that were odd-numbered, within a subnet? Or noncontiguous groups of devices? There's nothing stopping me from doing so.

The problem is that supporting noncontiguous netmasks means we cannot use standard traits like core::ops::RangeBounds. Users might expect those to be implemented, or might not care very much.

convert to Self::V4, Self::V6 once stabilized in 1.37 (2019-08-15)

// TODO convert to Self::V4, Self::V6 once stabilized in 1.37 (2019-08-15)
(IpAddr::V4(a), IpAddr::V4(b)) => Ok(IpAddr::V4(a.mask(&b))),
// TODO convert to Self::V4, Self::V6 once stabilized in 1.37 (2019-08-15)
(IpAddr::V6(a), IpAddr::V6(b)) => Ok(IpAddr::V6(a.mask(&b))),
(_, _) => Err("mismatched address types"),
}


This issue was generated by todo based on a TODO comment in eafc953 when #25 was merged. cc @rye.

Implement the Rust API guidelines

Rust API Guidelines Checklist

  • Naming (crate aligns with Rust naming conventions)
    • Casing conforms to RFC 430 (C-CASE)
    • Ad-hoc conversions follow as_, to_, into_ conventions (C-CONV)
    • Getter names follow Rust convention (C-GETTER)
    • Methods on collections that produce iterators follow iter, iter_mut, into_iter (C-ITER)
    • Iterator type names match the methods that produce them (C-ITER-TY)
    • Feature names are free of placeholder words (C-FEATURE)
    • Names use a consistent word order (C-WORD-ORDER)
  • Interoperability (crate interacts nicely with other library functionality)
    • Types eagerly implement common traits (C-COMMON-TRAITS)
      • Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug,
        Display, Default
    • Conversions use the standard traits From, AsRef, AsMut (C-CONV-TRAITS)
    • Collections implement FromIterator and Extend (C-COLLECT)
    • Data structures implement Serde's Serialize, Deserialize (C-SERDE)
    • Types are Send and Sync where possible (C-SEND-SYNC)
    • Error types are meaningful and well-behaved (C-GOOD-ERR)
    • Binary number types provide Hex, Octal, Binary formatting (C-NUM-FMT)
    • Generic reader/writer functions take R: Read and W: Write by value (C-RW-VALUE)
  • Macros (crate presents well-behaved macros)
  • Documentation (crate is abundantly documented)
    • Crate level docs are thorough and include examples (C-CRATE-DOC)
    • All items have a rustdoc example (C-EXAMPLE)
    • Examples use ?, not try!, not unwrap (C-QUESTION-MARK)
    • Function docs include error, panic, and safety considerations (C-FAILURE)
    • Prose contains hyperlinks to relevant things (C-LINK)
    • Cargo.toml includes all common metadata (C-METADATA)
      • authors, description, license, homepage, documentation, repository,
        readme, keywords, categories
    • Crate sets html_root_url attribute "https://docs.rs/CRATE/X.Y.Z" (C-HTML-ROOT)
    • Release notes document all significant changes (C-RELNOTES)
    • Rustdoc does not show unhelpful implementation details (C-HIDDEN)
  • Predictability (crate enables legible code that acts how it looks)
    • Smart pointers do not add inherent methods (C-SMART-PTR)
    • Conversions live on the most specific type involved (C-CONV-SPECIFIC)
    • Functions with a clear receiver are methods (C-METHOD)
    • Functions do not take out-parameters (C-NO-OUT)
    • Operator overloads are unsurprising (C-OVERLOAD)
    • Only smart pointers implement Deref and DerefMut (C-DEREF)
    • Constructors are static, inherent methods (C-CTOR)
  • Flexibility (crate supports diverse real-world use cases)
    • Functions expose intermediate results to avoid duplicate work (C-INTERMEDIATE)
    • Caller decides where to copy and place data (C-CALLER-CONTROL)
    • Functions minimize assumptions about parameters by using generics (C-GENERIC)
    • Traits are object-safe if they may be useful as a trait object (C-OBJECT)
  • Type safety (crate leverages the type system effectively)
    • Newtypes provide static distinctions (C-NEWTYPE)
    • Arguments convey meaning through types, not bool or Option (C-CUSTOM-TYPE)
    • Types for a set of flags are bitflags, not enums (C-BITFLAG)
    • Builders enable construction of complex values (C-BUILDER)
  • Dependability (crate is unlikely to do the wrong thing)
  • Debuggability (crate is conducive to easy debugging)
  • Future proofing (crate is free to improve without breaking users' code)
  • Necessities (to whom they matter, they really matter)
    • Public dependencies of a stable crate are stable (C-STABLE)
    • Crate and its dependencies have a permissive license (C-PERMISSIVE)

Extract traits into their own files

More of a moving-files-around change, but this would be nice to have from an organization standpoint. I don't like having big files, and moving things to files ensures pub is properly applied from a testing standpoint.

Write tests for non-CIDR address spaces

It'd be nice to write tests for non-CIDR netaddr handling. I know (more or less for a fact) that I've been very selective about which things get CIDR handling, and which things don't.

Ideally, we would do so by manually writing corner cases.

no_std support

While this crate does fit the use case I have for it, (that is, parsing and manipulating crates in non-embedded use cases) it'd be nice to add no_std support in case someone wants to use this crate.

The main barrier here is that IpAddr is not part of core; it is in std::net.

Ipv4Addr and Ipv6Addr, unfortunately, are apparently wrappers over the system in and in6 things…, which unfortunately means it'll be non-trivial to port away.

I might need to implement Ip.*Addr things myself eventually.

Get rid of src/tests/ subdirectory, reorganize source hierarchy

One does not need to have such a directory. There is already a mechanism for integration tests; it is far better to put tests in the modules that they are testing.

  • src/tests/netaddr/from/ipaddr.rs (#39, #48)
  • src/tests/netaddr/merge.rs (#44)
  • src/tests/netaddr/parse.rs (#51)
  • src/tests/netaddr/from.rs (#39)
  • src/tests/netaddr/broadcast.rs (#45)
  • src/tests/netaddr/cmp.rs (#53)
  • src/tests/netaddr/contains.rs (#54)
  • src/tests/util.rs (#50)
  • src/tests/util/gen_v4_mask.rs (#50)
  • src/tests/util/gen_v6_mask.rs (#50)
  • src/tests/netaddr.rs (#55)
  • src/tests/netaddr_error.rs (#55)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.