diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 69a8c23..fa8e72e 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -18,7 +18,7 @@ jobs: strategy: matrix: # Keep MSRV in sync with rust-version in Cargo.toml as much as possible. - rust: [stable, beta, nightly, 1.77.0] + rust: [stable, beta, nightly, 1.80.0] runs-on: macos-latest steps: - uses: actions/checkout@v4 diff --git a/CHANGELOG.md b/CHANGELOG.md index bfd374d..a4f467f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,11 +15,15 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/). ## [unreleased] ### Added - Add function for setting and clearing interface flags. +- Add the `IpNetwork` type for representing IPv4 and IPv6 networks. It will replace the use of the + `ipnetwork::{IpNetwork, Ipv4Network, Ipv6Network}` types. ### Changed -- Bump MSRV to 1.77. -- Upgrade `ipnetwork` dependency from 0.20 to 0.21. This is a breaking change since - `ipnetwork` is part of the public API. +- Bump MSRV to 1.80. +- Upgrade `ipnetwork` dependency from 0.20 to 0.21. + +### Removed +- Remove `ipnetwork` from the public API. ## [0.6.1] - 2024-10-02 diff --git a/Cargo.toml b/Cargo.toml index fbcf0c5..9ecd1ee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ readme = "README.md" keywords = ["pf", "firewall", "macos", "packet", "filter"] categories = ["network-programming", "os", "os::macos-apis", "api-bindings"] edition = "2021" -rust-version = "1.77.0" +rust-version = "1.80.0" [badges] travis-ci = { repository = "mullvad/pfctl-rs" } diff --git a/examples/add_rules.rs b/examples/add_rules.rs index 54d8373..ec65218 100644 --- a/examples/add_rules.rs +++ b/examples/add_rules.rs @@ -6,7 +6,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use pfctl::{ipnetwork, FilterRuleBuilder, PfCtl, RedirectRuleBuilder, ScrubRuleBuilder}; +use pfctl::{FilterRuleBuilder, IpNetwork, PfCtl, RedirectRuleBuilder, ScrubRuleBuilder}; use std::net::Ipv4Addr; static ANCHOR_NAME: &str = "test.anchor"; @@ -67,10 +67,10 @@ fn main() { .unwrap(); // Block packets from the entire 10.0.0.0/8 private network. - let private_net = ipnetwork::Ipv4Network::new(Ipv4Addr::new(10, 0, 0, 0), 8).unwrap(); + let private_net = IpNetwork::new(Ipv4Addr::new(10, 0, 0, 0), 8); let block_a_private_net_rule = FilterRuleBuilder::default() .action(pfctl::FilterRuleAction::Drop(pfctl::DropAction::Drop)) - .from(pfctl::Ip::from(ipnetwork::IpNetwork::V4(private_net))) + .from(pfctl::Ip::from(private_net)) .build() .unwrap(); diff --git a/src/lib.rs b/src/lib.rs index 0f19771..eaa5ead 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -68,8 +68,6 @@ use std::{ slice, }; -pub use ipnetwork; - mod ffi; #[macro_use] diff --git a/src/rule/ip.rs b/src/rule/ip.rs index f2b1c47..9b3a989 100644 --- a/src/rule/ip.rs +++ b/src/rule/ip.rs @@ -12,7 +12,6 @@ use crate::{ pooladdr::{PoolAddr, PoolAddrList}, AddrFamily, Result, }; -use ipnetwork::{IpNetwork, Ipv4Network, Ipv6Network}; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)] @@ -26,14 +25,13 @@ impl Ip { pub fn get_af(&self) -> AddrFamily { match *self { Ip::Any => AddrFamily::Any, - Ip::Net(IpNetwork::V4(_)) => AddrFamily::Ipv4, - Ip::Net(IpNetwork::V6(_)) => AddrFamily::Ipv6, + Ip::Net(network) => network.get_af(), } } /// Returns `Ip::Any` represented an as an `IpNetwork`, used for ffi. fn any_ffi_repr() -> IpNetwork { - IpNetwork::V6(Ipv6Network::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0), 0).unwrap()) + IpNetwork::new(Ipv6Addr::UNSPECIFIED, 0) } /// Returns PoolAddrList initialized with receiver @@ -42,6 +40,53 @@ impl Ip { } } +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct IpNetwork(ipnetwork::IpNetwork); + +impl IpNetwork { + pub fn new(ip: impl Into, prefix: u8) -> IpNetwork { + Self::new_checked(ip.into(), prefix).unwrap() + } + + pub const fn new_checked(ip: IpAddr, prefix: u8) -> Option { + match ip { + IpAddr::V4(ipv4_addr) => Self::v4(ipv4_addr, prefix), + IpAddr::V6(ipv6_addr) => Self::v6(ipv6_addr, prefix), + } + } + + /// Create an IPv4 network. + pub const fn v4(ip: Ipv4Addr, prefix: u8) -> Option { + let Some(network) = ipnetwork::Ipv4Network::new_checked(ip, prefix) else { + return None; + }; + Some(IpNetwork(ipnetwork::IpNetwork::V4(network))) + } + + /// Create an IPv6 network. + pub const fn v6(ip: Ipv6Addr, prefix: u8) -> Option { + let Some(network) = ipnetwork::Ipv6Network::new_checked(ip, prefix) else { + return None; + }; + Some(IpNetwork(ipnetwork::IpNetwork::V6(network))) + } + + pub fn ip(&self) -> IpAddr { + self.0.ip() + } + + pub fn mask(&self) -> IpAddr { + self.0.mask() + } + + const fn get_af(&self) -> AddrFamily { + match self.0 { + ipnetwork::IpNetwork::V4(_) => AddrFamily::Ipv4, + ipnetwork::IpNetwork::V6(_) => AddrFamily::Ipv6, + } + } +} + impl From for Ip { fn from(net: IpNetwork) -> Self { Ip::Net(net) @@ -50,13 +95,13 @@ impl From for Ip { impl From for Ip { fn from(ip: Ipv4Addr) -> Self { - Ip::Net(IpNetwork::V4(Ipv4Network::new(ip, 32).unwrap())) + Ip::from(IpNetwork::new(ip, 32)) } } impl From for Ip { fn from(ip: Ipv6Addr) -> Self { - Ip::Net(IpNetwork::V6(Ipv6Network::new(ip, 128).unwrap())) + Ip::from(IpNetwork::new(ip, 128)) } } diff --git a/src/rule/mod.rs b/src/rule/mod.rs index f57871f..ff2729c 100644 --- a/src/rule/mod.rs +++ b/src/rule/mod.rs @@ -10,7 +10,6 @@ use crate::{ conversion::{CopyTo, TryCopyTo}, ffi, Error, ErrorInternal, Result, }; -use ipnetwork::IpNetwork; use std::{ net::{IpAddr, Ipv4Addr, Ipv6Addr}, ops::Deref,