# CIDR Block
[](https://opensource.org/licenses/MIT)
A Rust library for CIDR block manipulation that provides utilities to parse, validate, and manipulate CIDR notation and get individual IP addresses.
## Features
- Calculate the number of IP addresses in IPv4 and IPv6 CIDR blocks
- Generate the next IP address within a CIDR block with wrapping behavior
- Support for both IPv4 and IPv6 address families
- Trait-based extensions for IP address types
- Error handling for invalid CIDR blocks and prefix lengths
## Installation
Add this to your `Cargo.toml`:
```toml
[dependencies]
cidr_block = "0.1.0"
```
Or use the cargo command:
```bash
cargo add cidr_block
```
## Usage Examples
### IPv4 Examples
#### Calculate the number of IP addresses in a CIDR block
```rust
use cidr_block::v4_num_ips;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Calculate how many IP addresses are in a /24 network
let num_ips = v4_num_ips("192.168.1.0/24")?;
assert_eq!(num_ips, 256); // A /24 network has 256 IP addresses
// Calculate how many IP addresses are in a /16 network
let num_ips = v4_num_ips("10.0.0.0/16")?;
assert_eq!(num_ips, 65536); // A /16 network has 65536 IP addresses
Ok(())
}
```
#### Get the next IP address in a CIDR block
```rust
use cidr_block::next_ip_v4;
use std::net::Ipv4Addr;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Parse an IP address
let ip: Ipv4Addr = "192.168.1.1".parse()?;
// Get the next IP address in the /24 network (increment by 1)
let next_ip = next_ip_v4(ip, 24, 1)?;
assert_eq!(next_ip, "192.168.1.2".parse::<Ipv4Addr>()?);
// Skip 10 IP addresses
let next_ip = next_ip_v4(ip, 24, 10)?;
assert_eq!(next_ip, "192.168.1.11".parse::<Ipv4Addr>()?);
// Demonstrate wrapping behavior at the end of the CIDR block
let last_ip: Ipv4Addr = "192.168.1.255".parse()?;
let next_ip = next_ip_v4(last_ip, 24, 1)?;
assert_eq!(next_ip, "192.168.1.0".parse::<Ipv4Addr>()?);
Ok(())
}
```
#### Using the trait-based API
```rust
use cidr_block::IPExt;
use std::net::Ipv4Addr;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Calculate number of IPs using the trait method
let num_ips = Ipv4Addr::num_ips("192.168.1.0/24")?;
assert_eq!(num_ips, 256);
// Get the next IP using the trait method
let ip: Ipv4Addr = "192.168.1.1".parse()?;
let next_ip = ip.next_ip(24, 1)?;
assert_eq!(next_ip, "192.168.1.2".parse::<Ipv4Addr>()?);
Ok(())
}
```
### IPv6 Examples
#### Calculate the number of IP addresses in a CIDR block
```rust
use cidr_block::v6_num_ips;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Calculate how many IP addresses are in a /64 network
let num_ips = v6_num_ips("2001:db8::/64")?;
assert_eq!(num_ips, 18_446_744_073_709_551_616u128); // 2^64 addresses
// Calculate how many IP addresses are in a /128 network (just one)
let num_ips = v6_num_ips("2001:db8::1/128")?;
assert_eq!(num_ips, 1);
Ok(())
}
```
#### Get the next IP address in a CIDR block
```rust
use cidr_block::next_ip_v6;
use std::net::Ipv6Addr;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Parse an IPv6 address
let ip: Ipv6Addr = "2001:db8::1".parse()?;
// Get the next IP address in the /64 network (increment by 1)
let next_ip = next_ip_v6(ip, 64, 1)?;
assert_eq!(next_ip, "2001:db8::2".parse::<Ipv6Addr>()?);
// Skip 10 IP addresses
let next_ip = next_ip_v6(ip, 64, 10)?;
assert_eq!(next_ip, "2001:db8::b".parse::<Ipv6Addr>()?);
// Demonstrate wrapping behavior with large increments
let ip: Ipv6Addr = "2001:db8::ffff".parse()?;
let next_ip = next_ip_v6(ip, 64, 2)?;
assert_eq!(next_ip, "2001:db8::1".parse::<Ipv6Addr>()?);
Ok(())
}
```
#### Using the trait-based API
```rust
use cidr_block::IPExt;
use std::net::Ipv6Addr;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Calculate number of IPs using the trait method
let num_ips = Ipv6Addr::num_ips("2001:db8::/64")?;
// Get the next IP using the trait method
let ip: Ipv6Addr = "2001:db8::1".parse()?;
let next_ip = ip.next_ip(64, 1)?;
assert_eq!(next_ip, "2001:db8::2".parse::<Ipv6Addr>()?);
Ok(())
}
```
## API Reference
### IPv4 Functions
#### `v4_num_ips(block: &str) -> Result<u32, Error>`
Calculates the number of IP addresses in an IPv4 CIDR block.
- **Parameters**:
- `block`: A string slice that represents the IPv4 CIDR block (e.g., "192.168.0.0/24").
- **Returns**:
- `Ok(u32)`: The number of IP addresses in the block.
- `Err(Error)`: If the block format is invalid or if the prefix length is out of range.
#### `next_ip_v4(ip: Ipv4Addr, prefix_length: u8, n: u32) -> Result<Ipv4Addr, Error>`
Calculates the next IPv4 address within the same CIDR block, wrapping around if necessary.
- **Parameters**:
- `ip`: An `Ipv4Addr` that represents the starting IPv4 address.
- `prefix_length`: The prefix length of the CIDR block (e.g., 24 for a /24 network).
- `n`: The number of addresses to skip.
- **Returns**:
- `Ok(Ipv4Addr)`: The next IPv4 address within the CIDR block.
- `Err(Error)`: If the prefix length is invalid (greater than 32).
### IPv6 Functions
#### `v6_num_ips(block: &str) -> Result<u128, Error>`
Calculates the number of IP addresses in an IPv6 CIDR block.
- **Parameters**:
- `block`: A string slice that represents the IPv6 CIDR block (e.g., "2001:db8::/64").
- **Returns**:
- `Ok(u128)`: The number of IP addresses in the block.
- `Err(Error)`: If the block format is invalid or if the prefix length is out of range.
#### `next_ip_v6(ip: Ipv6Addr, prefix_length: u8, n: u128) -> Result<Ipv6Addr, Error>`
Calculates the next IPv6 address within the same CIDR block, wrapping around if necessary.
- **Parameters**:
- `ip`: An `Ipv6Addr` that represents the starting IPv6 address.
- `prefix_length`: The prefix length of the CIDR block (e.g., 64 for a /64 network).
- `n`: The number of addresses to skip.
- **Returns**:
- `Ok(Ipv6Addr)`: The next IPv6 address within the CIDR block.
- `Err(Error)`: If the prefix length is invalid (greater than 128).
### Trait-based API
#### `IPExt` Trait
The `IPExt` trait provides a unified interface for both IPv4 and IPv6 address types.
```rust
pub trait IPExt: Clone + Copy {
type Error;
type LenType;
fn next_ip(&self, prefix_length: u8, n: Self::LenType) -> Result<Self, Self::Error>
where
Self: Sized;
fn num_ips(block: &str) -> Result<Self::LenType, Self::Error>
where
Self: Sized;
}
```
This trait is implemented for both `Ipv4Addr` and `Ipv6Addr` types, allowing for a more ergonomic API when working with different IP address families.
### Error Types
#### `Error` Enum
```rust
pub enum Error {
InvalidBlock,
InvalidPrefixLength,
}
```
- **InvalidBlock**: Returned when the CIDR block format is invalid.
- **InvalidPrefixLength**: Returned when the prefix length is out of range (greater than 32 for IPv4 or greater than 128 for IPv6).
## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.