Giter Site home page Giter Site logo

ipnetwork's Introduction

ipnetwork

This is a library to work with IPv4 and IPv6 CIDRs in Rust

Build Status Merit Badge

Run Clippy by doing

rustup component add clippy
cargo clippy

Installation

This crate works with Cargo. Assuming you have Rust and Cargo installed, simply check out the source and run tests:

git clone https://github.com/achanda/ipnetwork
cd ipnetwork
cargo test

You can also add ipnetwork as a dependency to your project's Cargo.toml:

[dependencies]
ipnetwork = "*"

ipnetwork's People

Contributors

achanda avatar admwrd avatar ahl avatar aurelilys avatar bgermann avatar cholcombe973 avatar ctrlcctrlv avatar dependabot-preview[bot] avatar dependabot-support avatar dependabot[bot] avatar ebarnard avatar faern avatar jethrogb avatar keens avatar kolgotko avatar lucab avatar lukaskalbertodt avatar nrdmn avatar paolobarbolini avatar pinkisemils avatar renovate[bot] avatar sancho20021 avatar tailhook avatar thepacketgeek avatar tshepang avatar vorner 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  avatar  avatar  avatar

ipnetwork's Issues

Ipv6Network::nth

nth method is implemented for Ipv4Network but not for Ipv6Network. Is it due to some fundamental difference between IP4/IP6 neworks or just forgotten?

This crate's Cargo.toml claims to support serde < 1.0 but it doesn't

This crate's Cargo.toml says serde_derive = ">=0.8.0, <2.0", but this crate does not compile if Cargo selects serde 0.8.

It just happens to work usually because cargo publish runs cargo update, and people tend to keep packages up to date. I've encountered this often because I build this crate in a project that contains another dependency that only supports serde 0.8, and sometimes Cargo assigns serde 0.8 to this crate as well. This results in suprious build errors.

I'm happy to write a PR to fix this, but the version specification ">=0.8.0, <2.0" is so specific and unique that I'd like to understand why this came about first.

Serde support doesn't work as expected

For example, if you get a JSON payload with network addresses like "10.0.0.0/24" or "fd00::/64" it won't be deserialised to IpNetwork. A quick look at the code confirms this. derive(Serialize, Deserialize) doesn't cut it here. Those traits will need to be implemented manually.

convenience: Iterator improvements

Hello

I'm reading through the code a bit. I've noticed few places for possible improvements around iterators:

  • There's an iterator support for Ipv4Network as well as Ipv6Network. But there's not one for IpNetwork. I think providing a wrapper iterator would be quite trivial.
  • The iterator types may benefit from some derived traits (eg. #[derive(Debug, Copy, Clone)].
  • Oftentimes, if there's a .iter() method for a type, the type-reference implements IntoIterator. Eg. impl IntoIterator for &Ipv4Network.

If these would be considered reasonable additions, I'd volunteer to send the pull request.

Publish new release?

Hi,

Would it be possible to publish a new release? Since 0.14 a number of things has improved in master. What I'm looking for mostly is the deserialization bugfix in #94, but there are other improvements as well, that are cumbersome to use unless published to crates.io.

Also, would it be possible to push git tags for the commits where the release is made? 0.14 currently has no tag. And the coming release would be good if it was tagged as well.

Thanks!

Split up growing library

The main file, lib.rs is growing quite large. A lot of IPv4 and IPv6 stuff is more or less interleaved. I think this library would benefit from being split up into smaller files. Do you agree @achanda ?

If so, how do we do this? Simplest solution would be to just create ipv4.rs and ipv6.rs and move the respective code (and tests) into those. How about the common stuff? Some stuff is shared between the two versions and the more code they can share the better. Just put it in a common.rs? lib.rs can just reexport everything so the public API is the same as today.

I can start working on this, but I want to discuss what you think first.

Don't return both Ipv4Addr and u32

I know I said earlier that I didn't have any more changes before a new release. But after some thinking I realized one thing. What is the reason for returning the tuple (Ipv4Addr, u32) from mask, network and broadcast? I can't see a reason when a caller would want both. Plus, the caller can always go from one to the other very simply. Returning both feels a bit redundant.

I suggest the public API always return the Ipv4Addr version only and internal functions who need the integer representation simply use u32::from internally. Cleaner API plus makes it easier to cast the value. Today if you want the representation in a u64 for example you need to do it in two rows, but with the proposed change it would be possible to do it in one:

let n = u32::from(cidr.mask()) as u64

I didn't submit this as a PR directly since I didn't know if there was any special reason it was designed like this or not. Also it would require a major version bump (0.9.0?). However, it's no hurry to get any of this out. As I will continue to use this library I will probably find more stuff to implement in it in the coming days.

Version 1.0

As far as I can tell, the public API of this crate has stayed backwards compatible for quite a few versions already. This means that releasing a 1.0 version in the current form would allow to add new features (in 1.x) versions without sacrificing backwards compatibility.

This, in turn, would make it easier for crates such as diesel and sqlx to keep an up to date ipnetwork dependency without having to release a new version themselves whenever a new ipnetwork version is released.

Is there something preventing the release of a 1.0 version?

Ipnetwork mismatched types

Hi !
Since version 0.20.0 I fail to build my tool because there is a mismatch between IpNetwork types :

λ ~/dev/fail(main*) » cargo run
    Updating crates.io index
   Compiling fail v0.1.0 (/home/mathieu/dev/fail)
error[E0308]: mismatched types
 --> src/main.rs:8:17
  |
7 |             match ip {
  |                   -- this expression has type `ipnetwork::IpNetwork`
8 |                 IpNetwork::V4(ipv4) => {
  |                 ^^^^^^^^^^^^^^^^^^^ expected enum `ipnetwork::IpNetwork`, found enum `IpNetwork`
  |
  = note: perhaps two different versions of crate `ipnetwork` are being used?

error[E0308]: mismatched types
  --> src/main.rs:11:17
   |
7  |             match ip {
   |                   -- this expression has type `ipnetwork::IpNetwork`
...
11 |                 IpNetwork::V6(ipv6) => {
   |                 ^^^^^^^^^^^^^^^^^^^ expected enum `ipnetwork::IpNetwork`, found enum `IpNetwork`
   |
   = note: perhaps two different versions of crate `ipnetwork` are being used?

For more information about this error, try `rustc --explain E0308`.
error: could not compile `fail` due to 2 previous errors

Here is the snippet I try to build bellow :

use ipnetwork::IpNetwork;
use pnet_datalink;

fn main() {
    for iface in pnet_datalink::interfaces() {
        for ip in iface.ips {
            match ip {
                IpNetwork::V4(ipv4) => {
                    println!("ipv4 : {}", ipv4.ip());
                }
                IpNetwork::V6(ipv6) => {
                    println!("ipv6 : {}", ipv6.ip());
                }
            }
        }
    }
}

It also uses pnet_datalink, but I only updated ipnetwork, that's why I suspect the issue to be related to this repo (I'm new to Rust so I may be wrong).

Any idea how I can fix this problem ?

Thanks.

Inconvenient NetworkSize

Hello

I wonder what the motivation behind the NetworkSize is. As I understand, the purpose of the IpNetwork enum is to generalize handling of both IPv4 and IPv6 networks. If it is so, why doesn't IpNetwork::size simply return u128? The NetworkSize isn't smaller, doesn't have many traits (eg. can't be summed together, doesn't have a Display implementation, doesn't support comparing to literals well…

Anyway, thank you for working on this, it is something I've stumbled upon multiple times that I'd like to have.

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Detected dependencies

cargo
Cargo.toml
  • serde 1
  • schemars 0.8.15
  • serde_json 1.0
  • criterion 0.5.0
  • does-it-json 0.0.4
github-actions
.github/workflows/publish.yml
  • actions/checkout v3
  • actions-rs/toolchain v1
  • katyo/publish-crates v2
.github/workflows/rust.yml
  • hecrj/setup-rust-action v1

  • Check this box to trigger a request for Renovate to run again on this repository

Question about constructing IpNetWork

I have checked IpNetwork api doc, and I could not find a way to construct IpNewWork from IpAddr which is defined in Rust standard library. It seems I have to specify a prefix field when I construct IpNewWork. Is there other way to construct IpNewWork from IpAddr ?

Set difference of two `IpNetwork`s

We had a need to calculate the set difference between two IpNetworks. So given an initial broad IpNetwork, we wanted to remove a smaller IpNetwork sub-network from it. The operation returned an iterator over the resulting set of IpNetworks.

We have code for this implemented, but we were wondering if this feature is something that would be worthwhile upstreaming. Should I open a PR with the code?

Add a changelog

As far as I can tell, this repository does not have any changelog. This makes it quite hard to figure out what changed between versions.

[Change suggestion] Resetting the device bits to 0 when initiating new objects

When creating an IP network, the network address's device bits should be resets to zero and then save into the struct.

For example, I believe the following two networks should be considered the same: 8.8.8.0/24 and 8.8.8.1/24. But when the resulting IpNetwork are different, and the to_string results are also different.

Relicense to a dual license?

The Apache 2.0 license is more complicated than it needs to be, and the patent clause can get in the way in some scenarios. I would like to respectfully ask that the author, @achanda, and other contributors (primarily @faern) agree to add a second license that does not mention patents (BSD-2-Clause, MIT, BSD-3-Clause, 0BSD, are all great options). This is common in Rust projects that I have seen (including the language implementation itself).

const fn constructors

We can now/soon have const fn constructors thanks to if statements now working in const on nightly: https://blog.rust-lang.org/inside-rust/2019/11/25/const-if-match.html

We could implement it now already with a nightly feature and duplicate all constructors and conditionally compile them with #[cfg(feature = "nightly")]. But unless there is significant demand we could just wait and hope it reaches stable in a few versions.

This would improve the usability of this crate a lot. One of the most common ways I define IP networks in my code is global constants, which I currently have to use lazy_static! or similar to achieve.

is_supernet_of does not work properly

Hi

use ipnetwork::Ipv4Network;
let net: Ipv4Network = "10.1.0.0/16".parse().unwrap();
let net2: Ipv4Network = "10.1.0.0/15".parse().unwrap();
println!("{:?} {} {}", net2, net.is_supernet_of(net2),
    net.is_supernet_of(Ipv4Network::new(net2.network(), net2.prefix()).unwrap()));

Output:
Ipv4Network { addr: 10.1.0.0, prefix: 15 } true false

So, is_supernet_of accidentally thinks that /16 is a supernet of /15 if network address is the same.

PS: Prefix "X/Y" consists of network address X and bits Y. So, function prefix which return bits confuses any network engineer.

New release?

Hello, seeing that 9651b3b bumped the edition to 2021 I imagine the next release will have to be 0.19.0. Since I use this crate through sqlx, which does a low number of minor version bumps, maybe it could make sense to release ipnetwork 0.19.0 now so that we could get it in sqlx 0.6 (coming out in a few days) launchbadge/sqlx#1793 (comment) ?

Otherwise it'll most likely take about a year before sqlx releases 0.7, allowing for another chance to bump the ipnetwork version again

IpNetwork::size() overflows if the prefix is 0

Ipv4Network::size panics if self.prefix == 0 since the result is too large (2^32):

pub fn size(self) -> u32 {
    let host_bits = u32::from(IPV4_BITS - self.prefix);
    (2 as u32).pow(host_bits)
}

This could have been fixed by using u64 if not for the fact that the same problem occurs in Ipv6Network::size, where the type cannot be made any larger.

If a Result cannot be returned, should the potential panic be documented?

JSON schema for IpNetwork does not match its serialized form

See: https://github.com/ahl/ipnetwork/tree/fail

$ cargo test --features=schemars test_ipnetwork_json
    Blocking waiting for file lock on build directory
   Compiling does-it-json v0.0.1 (/Users/ahl/src/does-it-json)
   Compiling ipnetwork v0.19.0 (/Users/ahl/src/ipnetwork)
    Finished test [unoptimized + debuginfo] target(s) in 2.20s
     Running unittests src/lib.rs (target/debug/deps/ipnetwork-5bc3e27d373077a5)

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 63 filtered out; finished in 0.00s

     Running tests/test_json.rs (target/debug/deps/test_json-c7e0909f58ffe5cf)

running 1 test
test tests::test_ipnetwork_json ... FAILED

failures:

---- tests::test_ipnetwork_json stdout ----
thread 'tests::test_ipnetwork_json' panicked at 'error: "127.1.0.0/24" did not conform to the schema at #/definitions/IpNetwork.oneOf: value validated against 0 of 2 `oneOf` schemas (rather than 1)
schema: {
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "MyStruct",
  "type": "object",
  "required": [
    "ipnetwork"
  ],
  "properties": {
    "ipnetwork": {
      "type": "array",
      "items": {
        "$ref": "#/definitions/IpNetwork"
      }
    }
  },
  "definitions": {
    "IpNetwork": {
      "description": "Represents a generic network range. This type can have two variants: the v4 and the v6 case.",
      "oneOf": [
        {
          "type": "object",
          "required": [
            "V4"
          ],
          "properties": {
            "V4": {
              "$ref": "#/definitions/Ipv4Network"
            }
          },
          "additionalProperties": false
        },
        {
          "type": "object",
          "required": [
            "V6"
          ],
          "properties": {
            "V6": {
              "$ref": "#/definitions/Ipv6Network"
            }
          },
          "additionalProperties": false
        }
      ]
    },
    "Ipv4Network": {
      "description": "Represents a network range where the IP addresses are of v4",
      "type": "object",
      "required": [
        "addr",
        "prefix"
      ],
      "properties": {
        "addr": {
          "type": "string",
          "format": "ipv4"
        },
        "prefix": {
          "type": "integer",
          "format": "uint8",
          "minimum": 0.0
        }
      }
    },
    "Ipv6Network": {
      "description": "Represents a network range where the IP addresses are of v6",
      "type": "object",
      "required": [
        "addr",
        "prefix"
      ],
      "properties": {
        "addr": {
          "type": "string",
          "format": "ipv6"
        },
        "prefix": {
          "type": "integer",
          "format": "uint8",
          "minimum": 0.0
        }
      }
    }
  }
}
value: {
  "ipnetwork": [
    "127.1.0.0/24",
    "::1/0"
  ]
}', tests/test_json.rs:69:13
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace


failures:
    tests::test_ipnetwork_json

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 2 filtered out; finished in 0.00s

error: test failed, to rerun pass '--test test_json'

The problem is that #153 simply derived JsonSchema rather than generating a schema that matches the implementation of Serialize. I would be happy to submit a PR; just let me know.

JSONSchema implementation

Hi there!
I was trying to make a json schema for wg-bond (via schemars), and got stuck on missing implementation for IpNetwork. Can I add implementation of JsonSchema for your stuff in your crate?

Should serde support be optional?

The serde support is not optional though someone might not need it. Serde (and especially serde-derive) is somewhat heavy dependency and it is quite common to have serde as a feature flag on many crates.

Would it be OK if I add the support?

If no prefix/mask is given, default to /32

It's a little annoying I need to check this myself, I'd like to be able to parse 127.0.0.1 as a network

use std::net::Ipv4Addr;
use ipnetwork::Ipv4Network;

let net: Ipv4Network = "127.0.0.1".parse().unwrap();
assert_eq!(net.mask(), Ipv4Addr::new(255, 255, 255, 255));
assert_eq!(net.prefix(), 32);

Failing to deserialize after converting to `serde_json::value::Value`.

As it stands, deserializing ipnetwork::IpNetwork into a serde_json::value::Value will make it fail to deserialize into ipnetwork::IpNetwork.

let network = IpNetwork::from_str("0.0.0.0/0").unwrap();
let value: serde_json::value::Value = serde_json::from_str(&serde_json::to_string(&network).unwrap()).unwrap();
let _: IpNetwork = serde_json::from_value(value).expect("Actually fails to deserialize");

This might be a serde related issue, but it'd be great if this could be worked around, as currently this issue implies that one can't use ipnetwork::IpNetwork in requests and responses with libraries such as jsonrpc-core.

Iterators are not public

The types Ipv4NetworkIterator and Ipv6NetworkIterator are not public types in the library. But you can get them from the iter methods on the network types. They should probably be exported?

Also, these hidden iterator types implement Copy. Iterators should usually not implement Copy. Because using them becomes very confusing. Every time you pass the iterator somewhere by value it's copied and the original instance stays where it was and can still be iterated. Meaning you can use a single iterator to iterate over the "collection" many times.

Parsing from ip/mask string

Currently the Ipv4Network can be parsed from ip/prefix representation (eg. 192.168.2.1/24), but the older ip/mask (192.168.2.1/255.255.255.0) is rejected. Would it make sense to add such support too?

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.