pfctl/rule/
endpoint.rs

1// Copyright 2025 Mullvad VPN AB.
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9use super::{AddrFamily, Ip, Port};
10use crate::{
11    conversion::{CopyTo, TryCopyTo},
12    ffi,
13};
14use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
17pub struct Endpoint {
18    ip: Ip,
19    port: Port,
20}
21
22impl Endpoint {
23    pub fn new<IP: Into<Ip>, PORT: Into<Port>>(ip: IP, port: PORT) -> Self {
24        Endpoint {
25            ip: ip.into(),
26            port: port.into(),
27        }
28    }
29
30    pub fn ip(&self) -> Ip {
31        self.ip
32    }
33
34    pub fn port(&self) -> Port {
35        self.port
36    }
37
38    pub fn get_af(&self) -> AddrFamily {
39        self.ip.get_af()
40    }
41}
42
43impl From<Ip> for Endpoint {
44    fn from(ip: Ip) -> Self {
45        Endpoint::new(ip, Port::default())
46    }
47}
48
49impl From<Port> for Endpoint {
50    fn from(port: Port) -> Self {
51        Endpoint::new(Ip::default(), port)
52    }
53}
54
55impl From<Ipv4Addr> for Endpoint {
56    fn from(ip: Ipv4Addr) -> Self {
57        Self::from(Ip::from(ip))
58    }
59}
60
61impl From<Ipv6Addr> for Endpoint {
62    fn from(ip: Ipv6Addr) -> Self {
63        Self::from(Ip::from(ip))
64    }
65}
66
67impl From<IpAddr> for Endpoint {
68    fn from(ip: IpAddr) -> Self {
69        Self::from(Ip::from(ip))
70    }
71}
72
73impl From<SocketAddrV4> for Endpoint {
74    fn from(socket_addr: SocketAddrV4) -> Self {
75        Endpoint::new(Ip::from(*socket_addr.ip()), Port::from(socket_addr.port()))
76    }
77}
78
79impl From<SocketAddrV6> for Endpoint {
80    fn from(socket_addr: SocketAddrV6) -> Self {
81        Endpoint::new(Ip::from(*socket_addr.ip()), Port::from(socket_addr.port()))
82    }
83}
84
85impl From<SocketAddr> for Endpoint {
86    fn from(socket_addr: SocketAddr) -> Self {
87        match socket_addr {
88            SocketAddr::V4(addr) => Endpoint::from(addr),
89            SocketAddr::V6(addr) => Endpoint::from(addr),
90        }
91    }
92}
93
94impl TryCopyTo<ffi::pfvar::pf_rule_addr> for Endpoint {
95    type Error = crate::Error;
96
97    fn try_copy_to(&self, pf_rule_addr: &mut ffi::pfvar::pf_rule_addr) -> crate::Result<()> {
98        self.ip.copy_to(&mut pf_rule_addr.addr);
99        self.port
100            .try_copy_to(unsafe { &mut pf_rule_addr.xport.range })?;
101        Ok(())
102    }
103}