Git Product home page Git Product logo

ipnet's Introduction

Build Status

This module provides types and useful methods for working with IPv4 and IPv6 network addresses, commonly called IP prefixes. The new IpNet, Ipv4Net, and Ipv6Net types build on the existing IpAddr, Ipv4Addr, and Ipv6Addr types already provided in Rust's standard library and align to their design to stay consistent.

The module also provides the IpSubnets, Ipv4Subnets, and Ipv6Subnets types for iterating over the subnets contained in an IP address range. The IpAddrRange, Ipv4AddrRange, and Ipv6AddrRange types for iterating over IP addresses in a range. And traits that extend Ipv4Addr and Ipv6Addr with methods for addition, subtraction, bitwise-and, and bitwise-or operations that are missing in Rust's standard library.

The module only uses stable features so it is guaranteed to compile using the stable toolchain. Tests aim for thorough coverage and can be found in both the test modules and doctests. Please file an issue on GitHub if you have any problems, requests, or suggested improvements.

Read the documentation for the full details. And find it on Crates.io.

Release 2.0 requirements

Release 2.0 requires Rust 1.26 or later. Release 1.0 used a custom emulated 128-bit integer type (Emu128) to fully support IPv6 addresses. This has been replaced with Rust's built-in 128-bit integer, which is now stable as of Rust 1.26. There are reports of issues using Rust's 128-bit integers on some targets (e.g. Emscripten). If you have issues on your chosen target, please continue to use the 1.0 release until that has been resolved.

Examples

Create a network address and print the hostmask and netmask

extern crate ipnet;
use std::net::{Ipv4Addr, Ipv6Addr};
use std::str::FromStr;
use ipnet::{IpNet, Ipv4Net, Ipv6Net};

fn main() {
    // Create an Ipv4Net and Ipv6Net from their constructors.

    let net4 = Ipv4Net::new(Ipv4Addr::new(10, 1, 1, 0), 24).unwrap();
    let net6 = Ipv6Net::new(Ipv6Addr::new(0xfd, 0, 0, 0, 0, 0, 0, 0), 24).unwrap();

    // They can also be created by a constructor that panics when the prefix length is invalid,

    let net4 = Ipv4Net::new_assert(Ipv4Addr::new(10, 1, 1, 0), 24);
    let net6 = Ipv6Net::new_assert(Ipv6Addr::new(0xfd, 0, 0, 0, 0, 0, 0, 0), 24);

    // or does not compile when called from a const context.

    const NET4: Ipv4Net = Ipv4Net::new_assert(Ipv4Addr::new(10, 1, 1, 0), 24);
    const NET6: Ipv6Net = Ipv6Net::new_assert(Ipv6Addr::new(0xfd, 0, 0, 0, 0, 0, 0, 0), 24);

    // They can also be created from string representations.

    let net4 = Ipv4Net::from_str("10.1.1.0/24").unwrap();
    let net6 = Ipv6Net::from_str("fd00::/24").unwrap();

    // Or alternatively as follows.
    
    let net4: Ipv4Net = "10.1.1.0/24".parse().unwrap();
    let net6: Ipv6Net = "fd00::/24".parse().unwrap();

    // IpNet can represent either an IPv4 or IPv6 network address.

    let net = IpNet::from(net4);
    
    // It can also be created from string representations.

    let net = IpNet::from_str("10.1.1.0/24").unwrap();
    let net: IpNet = "10.1.1.0/24".parse().unwrap();

    // There are a number of methods that can be used. Read the
    // documentation for the full details.

    println!("{} hostmask = {}", net, net.hostmask());
    println!("{} netmask = {}", net4, net4.netmask());
}

Subdivide an existing IP network into smaller subnets

extern crate ipnet;
use ipnet::Ipv4Net;

fn main() {
    let net: Ipv4Net = "192.168.0.0/23".parse().unwrap();

    println!("\n/25 subnets in {}:", net);

    // Note: `subnets()` returns a `Result`. If the given prefix length
    // is less than the existing prefix length the `Result` will contain
    // an error.

    let subnets = net.subnets(25)
        .expect("PrefixLenError: new prefix length cannot be shorter than existing");

    // Output:
    //  subnet 0 = 192.168.0.0/25
    //  subnet 1 = 192.168.0.128/25
    //  subnet 2 = 192.168.1.0/25
    //  subnet 3 = 192.168.1.128/25

    for (i, n) in subnets.enumerate() {
        println!("\tsubnet {} = {}", i, n);
    }
}

Iterate over the valid subnets between two IPv4 addresses

extern crate ipnet;
use std::net::Ipv4Addr;
use ipnet::Ipv4Subnets;

fn main() {
    let start = Ipv4Addr::new(10, 0, 0, 0);
    let end = Ipv4Addr::new(10, 0, 0, 239);

    println!("\n/0 or greater subnets between {} and {}:", start, end);

    // Output all subnets starting with the largest that will fit. This
    // will give us the smallest possible set of valid subnets.
    //
    // Output:
    //  subnet 0 = 10.0.0.0/25
    //  subnet 1 = 10.0.0.128/26
    //  subnet 2 = 10.0.0.192/27
    //  subnet 3 = 10.0.0.224/28

    let subnets = Ipv4Subnets::new(start, end, 0);

    for (i, n) in subnets.enumerate() {
        println!("\tsubnet {} = {}", i, n);
    }

    println!("\n/26 or greater subnets between {} and {}:", start, end);

    // Output all subnets with prefix lengths less than or equal to 26.
    // This results in more subnets, but limits them to a maximum size.
    //
    // Output:
    //  subnet 0 = 10.0.0.0/26
    //  subnet 1 = 10.0.0.64/26
    //  subnet 2 = 10.0.0.128/26
    //  subnet 3 = 10.0.0.192/27
    //  subnet 4 = 10.0.0.224/28

    let subnets = Ipv4Subnets::new(start, end, 26);

    for (i, n) in subnets.enumerate() {
        println!("\tsubnet {} = {}", i, n);
    }
}

Aggregate a list of IP prefixes

extern crate ipnet;
use ipnet::IpNet;

fn main() {
    // Example input list of overlapping and adjacent prefixes.

    let strings = vec![
        "10.0.0.0/24", "10.0.1.0/24", "10.0.1.1/24", "10.0.1.2/24",
        "10.0.2.0/24",
        "10.1.0.0/24", "10.1.1.0/24",
        "192.168.0.0/24", "192.168.1.0/24", "192.168.2.0/24", "192.168.3.0/24",
        "fd00::/32", "fd00:1::/32",
    ];

    let nets: Vec<IpNet> = strings.iter().filter_map(|p| p.parse().ok()).collect();
    
    println!("\nAggregated IP prefixes:");
    
    // Output:
    //  10.0.0.0/23
    //  10.0.2.0/24
    //  10.1.0.0/23
    //  192.168.0.0/22
    //  fd00::/31
    
    for n in IpNet::aggregate(&nets) {
        println!("\t{}", n);
    }
}

Future

  • Implementing std::ops::{Add, Sub, BitAnd, BitOr} for Ipv4Addr and Ipv6Addr would be useful as these are common operations on IP addresses. If done, the extension traits provided in this module would be removed and the major version incremented. Implementing these requires a change to the standard library. I've started a thread on this topic on the Rust Internals discussion board.
  • The results of hosts() and potentially subnets() should be represented as a Range rather than the custom IpAddrRange and IpSubnets types provided in this module. This requires the target types to have Add and Step implemented for them. Implementing Add for IpAddr, Ipv4Addr, and Ipv6Addr requires a change to the standard library (see above). And Step is still unstable so exploring this will also wait until it has stablized.

License

Copyright (c) 2017, Juniper Networks, Inc. All rights reserved.

This code is licensed to you under either the MIT License or Apache License, Version 2.0 at your choice (the "License"). You may not use this code except in compliance with the License. This code is not an official Juniper product. You can obtain a copy of the License at: https://opensource.org/licenses/MIT or http://www.apache.org/licenses/LICENSE-2.0

ipnet's People

Contributors

clintfred avatar cuishuang avatar domenukk avatar elrafoon avatar glts avatar hgzimmerman avatar imp avatar jjanowsk avatar jmeggitt avatar krisprice avatar mcginty avatar niklasf avatar paolobarbolini avatar rushmorem avatar sgued avatar smklein avatar stormshield-guillaumed avatar striezel avatar tetsuharuohzeki avatar typr124 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

ipnet's Issues

Interest in Diesel support?

This is a continuation of the discussion originally posted here: diesel-rs/diesel#3164

TL;DR: I like Diesel, I like ipnet, I want them to work well together! However, this leaves the question: where should the bindings to allow IpNet compatibility with Diesel live?

Diesel is a crate which provides a database query builder in Rust. It makes heavy use of the FromSql and ToSql traits to convert "rust types" to/from "sql types". I have an interest in implementing this type for the IpNet object itself.

Actually implementing this trait is relatively straightforward, but there's an open question which I raised in the Diesel discussion - should this be a part of the ipnet crate (behind a "diesel" feature flag) or a part of the diesel crate (behind an "ipnet" feature flag)?

How do y'all feel about this? As some prior art:

  • rust_decimal implemented this trait in the rust_decimal repo, behind a rust_decimal feature flag
  • ipnetwork implemented this trait in the Diesel repo, behind a Diesel feature flag.

Error::description is deprecated

warning: use of deprecated item 'std::error::Error::description': use the Display impl or to_string()
   --> src/ipnet.rs:116:28
    |
116 |         fmt.write_str(self.description())
    |                            ^^^^^^^^^^^
    |
    = note: `#[warn(deprecated)]` on by default

This, as well as implementation of Error::description for this crate's errors.

extended version of `std::net::parser` does not include CVE fix

It looks like the copied and extended version of the std::net::parser module in the ipnet parser doesn't include this recent CVE fix to the standard library that disallows the use of octal format in IPv4 strings: rust-lang/rust#83652.

From the PR to rust-lang/rust:

In its original specification, leading zero in Ipv4 string is interpreted
as octal literals. So a IP address 0127.0.0.1 actually means 87.0.0.1.

This confusion can lead to many security vulnerabilities. Therefore, in
IETF RFC 6943, it suggests to disallow octal/hexadecimal format in Ipv4
string all together.

If I understand correctly, similarly to std::net::parser, it's not that a leading zero would cause the string to be interpreted as an octal literal in ipnet's parser, as the parser specifies the radix as 10 here; however, it would be good to fully disallow leading-zero octal format in an IPv4 string as suggested in the above RFC, since it's invalid in the strict format.

Would it make sense to apply that change to ipnet? I'm happy to put together a PR.

JsonSchema does not correspond to Serde representation

Currently, the JsonSchema trait is derived instead of manually implemented to match the parser for IpNet, IpV4Net, and IpV6Net.
This causes it to generate a schema object that indicates that for IpV4Net, the serde deserializer expects a JSON object like:

{
    "addr": "0.0.0.0",
    "prefix_len": 0
}

when in reality, the deserializer expects, and serializer produces:

"0.0.0.0/0"

This can be resolved by implementing JsonSchema manually

IpAddrRange never ends when start and end are both 0

I noticed this while looking at implementing some of the extra Iterator traits and methods for efficiency. This blocks several possible efficiencies with IpAddrRange and related types.

An easy fix would be to replace start with 1 in the event that start and end are equal (end is already replaced with 0 here)

If this is acceptable, I can open a PR for this, and will likely follow up with some iterator efficiencies.

String Representations of `Ipv6Net` allow more than 8 groups

Consider the following program,

use ipnet::IpNet;
use std::net::IpAddr;

fn main() {
    assert!("ffff:ffff:ffff:ffff:ffff:ffff::ffff:ffff/114".parse::<IpNet>().is_ok());
    assert!("ffff:ffff:ffff:ffff:ffff:ffff::ffff:ffff".parse::<IpAddr>().is_ok());
}

The second assertion fails while the first one holds. ffff:ffff:ffff:ffff:ffff:ffff::ffff:ffff contains 8 ffffs and 1 :: that represents at least one all-zero groups.

IpNet.hosts() returns wrong number of hosts.

Given the CIDR 1.1.1.1/30 I would expect to get back the hosts:
1.1.1.0
1.1.1.1
1.1.1.2
1.1.1.3

But I only get back these hosts:
1.1.1.1
1.1.1.2

let cidr = IpNet::from_str("1.1.1.1/30").unwrap(); for host in cidr.hosts() { println!("{}", host); }

`Ipv4Net` `FromStr` allows host bits to be set in CIDR

This should return an error since a /24 would require a zero 4th octet, but it accepts it. Worse, it doesn't seem to transform it, but keeps all the bits set.

use std::str::FromStr;
use ipnet::Ipv4Net;

fn main() {
    let net = Ipv4Net::from_str("1.1.1.1/24");
    assert!(net.is_ok());
    println!("{}", net.unwrap());
}

NOTE: I just found the trunc function so now I'm starting to think this is per design. For the record, I think this is broken behavior as these are in no way valid subnets. My preference, and I believe correct behavior, would be to reject these outright. However, if this is kept, it would be nice if trunc could at least run by default so Serde, etc. can properly transform the data. Since there is no way to call trunc in the deserialization path that I'm aware of, it has to be a per call site type thing which is error prone.

Thanks for looking at this.

Enhancement: Allow parsing of abbreviated IPv4 CIDR addresses

This works:
let net4 = Ipv4Net::from_str("10.1.1.0/24").unwrap();

But this doesn't:
let net4 = Ipv4Net::from_str("10.1.1/24").unwrap();

This abbreviated form of IPv4 CIDR - omitting trailing 0 octets, is fairly common, it would be great if ipnet could accept these.

Comparison to the ipnetwork crate?

Would it be possible to get a short line in the readme with a comparison to the ipnetwork crate please?

I was looking at both seem pretty similar on the surface so I was curious of any deeper items that may be different.

Thank you for the hard work on this library!

Enhancement: Trait for afi-independent methods

I frequently find myself writing code that should be generic over IP address
families, but I'm prevented by the lack of a way to express the bound "has a
prefix_len(&self) -> u8 method", for example.

It should be straight-forward (I say without actually having read the code :-))
to create a trait that provides the functions which currently exist on
Ipv4Net and Ipv6Net, and which have a shared signature, and move the
existing implementations of those to trait implementations.

@krisprice please let me know if you're open to the principal, and I'll take a stab at a PR.

Provide conversion from std::net::IpAddr to ipnet::IpNet

I have recently needed conversion of exact IpAddrs to CIDR network addresses, and found that ipnet does not support conversion from an IpAddr to an IpNet.

Since that conversion is as far as I understand trivial and would always succeed (call Ipv{4,6}Net::new with address and max prefix length [?]), I was wondering if you would consider providing that conversion in IpNet?

This would of course be purely a convenience feature, but perhaps a useful one. Thank you!

Serde is serializing IpNets as strings for binary formats

When Serde was implemented a custom Serializer/Deserializer was created to flatten the IpNet struct to it's string representation. This makes sense for text based serialization formats like JSON, but the result of this is that for binary formats like Bincode the IpNet struct is first converted to a string, and that string is encoded in the Bincode format. This is inefficient and unexpected behavior for someone using a binary format.

Tracking issue for Rust API Guidelines Checklist

Rust API Guidelines Checklist

  • Organization (crate is structured in an intelligible way)
    • Crate root re-exports common functionality ([C-REEXPORT])
    • Modules provide a sensible API hierarchy ([C-HIERARCHY])
  • Naming (crate aligns with Rust naming conventions)
    • Casing conforms to RFC 430 ([C-CASE])
    • Ad-hoc conversions follow as_, to_, into_ conventions ([C-CONV])
    • 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])
    • Ownership suffixes use _mut and _ref ([C-OWN-SUFFIX])
    • Single-element containers implement appropriate getters ([C-GETTERS])
    • Feature names are free of placeholder words ([C-FEATURE])
  • 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])
    • Crate has a "serde" cfg option that enables Serde ([C-SERDE-CFG])
    • Types are Send and Sync where possible ([C-SEND-SYNC])
    • Error types are Send and Sync ([C-SEND-SYNC-ERR])
    • Error types are meaningful, not () ([C-MEANINGFUL-ERR])
    • Binary number types provide Hex, Octal, Binary formatting ([C-NUM-FMT])
  • Macros (crate presents well-behaved macros)
    • Input syntax is evocative of the output ([C-EVOCATIVE])
    • Macros compose well with attributes ([C-MACRO-ATTR])
    • Item macros work anywhere that items are allowed ([C-ANYWHERE])
    • Item macros support visibility specifiers ([C-MACRO-VIS])
    • Type fragments are flexible ([C-MACRO-TY])
  • 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 conditions in "Errors" section ([C-ERROR-DOC])
    • Function docs include panic conditions in "Panics" section ([C-PANIC-DOC])
    • 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
    • Cargo.toml documentation key points to "https://docs.rs/CRATE" ([C-DOCS-RS])
    • Crate sets html_root_url attribute "https://docs.rs/CRATE/VER.SI.ON" ([C-HTML-ROOT])
    • Release notes document all significant changes ([C-RELNOTES])
  • 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])
    • Deref and DerefMut never fail ([C-DEREF-FAIL])
    • 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)
    • Functions validate their arguments ([C-VALIDATE])
    • Destructors never fail ([C-DTOR-FAIL])
    • Destructors that may block have alternatives ([C-DTOR-BLOCK])
  • Debuggability (crate is conducive to easy debugging)
    • All public types implement Debug ([C-DEBUG])
    • Debug representation is never empty ([C-DEBUG-NONEMPTY])
  • Future proofing (crate is free to improve without breaking users' code)
    • Structs have private fields ([C-STRUCT-PRIVATE])
    • Newtypes encapsulate implementation details ([C-NEWTYPE-HIDE])
  • 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])

build error

Getting following errors today, Any ideas please?

Compiling lock_api v0.3.1
error[E0658]: use of unstable library feature 'iter_nth_back'
--> /home/zzz/.cargo/registry/src/github.com-1ecc6299db9ec823/ipnet-2.1.0/src/ipext.rs:638:5
|
638 | / fn nth_back(&mut self, n: usize) -> OptionSelf::Item {
639 | | match *self {
640 | | IpAddrRange::V4(ref mut a) => a.nth_back(n).map(IpAddr::V4),
641 | | IpAddrRange::V6(ref mut a) => a.nth_back(n).map(IpAddr::V6),
642 | | }
643 | | }
| |_____^
|
= note: for more information, see #56995

error[E0658]: use of unstable library feature 'iter_nth_back'

...
error: aborting due to 5 previous errors

For more information about this error, try rustc --explain E0658.
error: Could not compile ipnet.
warning: build failed, waiting for other jobs to finish...
error: build failed

Iterator for supernets.

It'd be useful if it was possible to iterate over the supernets of a net. This can already be done with something like

let net = "10.0.0.0/8".parse().unwrap();
let mut tmp_net = net.clone();
while let Some(supernet) = tmp_net.supernet() {
  tmp_net = supernet;
  // some code here
}

Doing this here instead would obv be a lot cleaner:

let net = "10.0.0.0/8".parse().unwrap();
for supernet in net.supernets() {
  // some code here
}

I've started implementing this, but wanted to post an issue before I sink more than a few minutes into it, to make sure this is something that would get merged if implemented.

Add method for Ipv4AddrRange

Add networks or cidrs method on Ipv4AddrRange struct ?

Like python https://github.com/drkjam/netaddr/blob/rel-0.7.x/netaddr/ip/__init__.py#L1734

Code:

use std::net::Ipv4Addr;

#[derive(Debug)]
struct Ipv4Cidr {
    addr: Ipv4Addr,
    prefix_len: u8
}

fn ipv4range_to_ipv4cidrs(start_ip: Ipv4Addr, end_ip: Ipv4Addr) -> Vec<Ipv4Cidr> {
    let mut cidrs: Vec<Ipv4Cidr> = Vec::new();

    let mut start = u32::from(start_ip);
    let end = u32::from(end_ip);

    println!("start: {:?}({}) end: {:?}({})", start_ip, start, end_ip, end);

    loop {
        if end > start {
            let total = end - start;
            let mut shift = start.trailing_zeros() as u32;

            let num: u32;
            loop {
                let n = 2u32.pow(shift);
                if start + n > end {
                    if shift == 0 {
                        panic!("oops ...");
                    }
                    shift -= 1;
                } else {
                    num = n;
                    break;
                }
            }
            
            let prefix_len = 32 - shift;

            // println!("total: {}, shift: {:?}  prefix_len: {} num: {}", total, shift, prefix_len, num);

            let ip = Ipv4Addr::from(start);
            let cidr = Ipv4Cidr{ addr: Ipv4Addr::from(start), prefix_len: prefix_len as u8 };

            cidrs.push(cidr);

            start += num;

        } else if end < start {
            break;
        } else if end == start {
            break;
        } else {
            unreachable!()
        }
    }

    cidrs
}

fn main(){
    // 185.30.232.0 - 185.30.232.63  64
    // 23.18.1.0    - 23.18.23.255   5888
    for cidr in ipv4range_to_ipv4cidrs(Ipv4Addr::new(185, 30, 232, 0), Ipv4Addr::from(u32::from(Ipv4Addr::new(185, 30, 232, 0)) + 64)).iter(){
        println!("{}", cidr);
    }

    for cidr in ipv4range_to_ipv4cidrs(Ipv4Addr::new(23, 18, 1, 0), Ipv4Addr::from(u32::from(Ipv4Addr::new(23, 18, 1, 0)) + 5888)).iter(){
        println!("{}", cidr);
    }
}

Allow creation of const items of type IpvXNet

Currently it is not possible to create const item of IpvXNet type, because Result.unwrap() is not const
It would be great to have a constructor for IpvXNet that allows that. I've prepared two PR with two possible implementations.

#56 First one adds new_const method which always checks prefix length at compile time. The drawback is that the syntax is less appealing due to the use of generics:

// Both are verified at compile time:
const NET: Ipv4Net = Ipv4Net::new_const::<24>(Ipv4Addr::new(10, 1, 1, 0));
let net = Ipv4Net::new_const::<24>(Ipv4Addr::new(10, 1, 1, 0));

#57 Second one adds new_assert method which checks prefix length at compile time if called from const context and panics at runtime otherwise:

// This code is verified at compile time:
const NET: Ipv4Net = Ipv4Net::new_assert(Ipv4Addr::new(10, 1, 1, 0), 24);
// This code is verified at runtime:
let net = Ipv4Net::new_assert(Ipv4Addr::new(10, 1, 1, 0), 24);

Should `prefix_len` be it's own type?

Should prefix_len be it's own type? This seems like newtype overload, but the API guidelines would tend to indicate it should be.

Currently the new() constructors clamp the prefix_len to between 0 and 32 or 0 and 128 for IPv4 and IPv6 respectively. This is instead of returning a Result with a error if prefix_len is not in valid bounds. Is returning a Result the better thing to do? This is a very simple library, and the outcome for a prefix_len greater than the bounds is the same as supplying a prefix_len of the maximum bound anyway.

Implementing a new type would mean implementing new types for both IPv4 and IPv6 prefix lengths. A new type for their errors. And, a constructor for each. It's not clear this is any better than changing the constructor on the Ipv4Net and Ipv6Net implementations to return an error as described above. It would seem better to take that option if anything.

Enhancement: Allow parsing of netmask

Allow: let net: Ipv4Net = "10.0.0.0/255.255.255.252".parse().unwrap();

This would allow additional flexibility since unfortunately not everything represents networks using bit notation.

aggregate method does not properly handle subnets containing highest IP address

The aggregate method does not properly handle subnets containing the highest possible IP address. It chops this subnet up, when it should return the subnet unmodified.

Example:

let blah: Vec<Ipv4Net> = vec!["128.0.0.0/1".parse().unwrap()];
let blah: Vec<Ipv4Net> = Ipv4Net::aggregate(&blah);
println!("{:?}", blah);

Expected output:

[128.0.0.0/1]

Actual output:

[128.0.0.0/2, 192.0.0.0/3, 224.0.0.0/4, 240.0.0.0/5, 248.0.0.0/6, 252.0.0.0/7, 254.0.0.0/8, 255.0.0.0/9, 255.128.0.0/10, 255.192.0.0/11, 255.224.0.0/12, 255.240.0.0/13, 255.248.0.0/14, 255.252.0.0/15, 255.254.0.0/16, 255.255.0.0/17, 255.255.128.0/18, 255.255.192.0/19, 255.255.224.0/20, 255.255.240.0/21, 255.255.248.0/22, 255.255.252.0/23, 255.255.254.0/24, 255.255.255.0/25, 255.255.255.128/26, 255.255.255.192/27, 255.255.255.224/28, 255.255.255.240/29, 255.255.255.248/30, 255.255.255.252/31, 255.255.255.254/32]

Build fails with nightly

rustc -V
rustc 1.43.0-nightly (c20d7eecb 2020-03-11)
error: this arithmetic operation will overflow
   --> src/ipext.rs:569:13
    |
569 |             std::usize::MAX + 1 + count as usize
    |             ^^^^^^^^^^^^^^^^^^^ attempt to add with overflow
    |
    = note: `#[deny(arithmetic_overflow)]` on by default

error: this arithmetic operation will overflow
   --> src/ipext.rs:489:21
    |
489 |                     std::usize::MAX + 2 + count as usize
    |                     ^^^^^^^^^^^^^^^^^^^ attempt to add with overflow

error: aborting due to 2 previous errors

Version 2.0.0 tracking

Version 2.0.0 tracking items:

  • Replace Emu128 with Rust native u128 when stable
  • Remove the with-serde feature name, see #8
  • Inherit the Contains::contains() methods in the types so that it's not necessary to use the Contains trait to access these methods.
  • Remove the Deref to the contained IP address
  • Implement relevant methods that were previously Deref'd directly on the IP network types, and make them correct for networks, e.g. 172.16.0.0/8 would previously return true using call to is_private() on the contained IP address, but technically it is not as it's larger than the 172.16.0.0/12 private space.
  • Run through the different comparisons (Eq, Ord, PartialOrd) and make sure they make sense and are working as would be expected.

Please derive/implement Default trait

The types in this crate are very useful and practical. The life of the consumers may be even easier if these types will be implementing Default trait. We are using these types as a part of a complex structures where Default is required. Right now it forces us to implement it manually instead of deriving.

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.