Skip to content

Commit 943f9ff

Browse files
authored
Multi address (#84)
1 parent d2ed20e commit 943f9ff

10 files changed

+107
-53
lines changed

Cargo.lock

+12-12
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "defguard_wireguard_rs"
3-
version = "0.6.1"
3+
version = "0.7.0"
44
edition = "2021"
55
rust-version = "1.80"
66
description = "A unified multi-platform high-level API for managing WireGuard interfaces"
@@ -37,7 +37,7 @@ nix = { version = "0.29", features = ["ioctl", "socket"] }
3737
[target.'cfg(target_os = "linux")'.dependencies]
3838
netlink-packet-core = "0.7"
3939
netlink-packet-generic = "0.3"
40-
netlink-packet-route = "0.20"
40+
netlink-packet-route = "0.21"
4141
netlink-packet-utils = "0.5"
4242
netlink-packet-wireguard = "0.2"
4343
netlink-sys = "0.8"

examples/client.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
4343
let interface_config = InterfaceConfiguration {
4444
name: ifname.clone(),
4545
prvkey: "AAECAwQFBgcICQoLDA0OD/Dh0sO0pZaHeGlaSzwtHg8=".to_string(),
46-
address: "10.6.0.30".to_string(),
46+
addresses: vec!["10.6.0.30".parse().unwrap()],
4747
port: 12345,
4848
peers: vec![peer],
4949
mtu: None,

examples/server.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
4141
let interface_config = InterfaceConfiguration {
4242
name: ifname.clone(),
4343
prvkey: "AAECAwQFBgcICQoLDA0OD/Dh0sO0pZaHeGlaSzwtHg8=".to_string(),
44-
address: "10.6.0.30".to_string(),
44+
addresses: vec!["10.6.0.30".parse().unwrap()],
4545
port: 12345,
4646
peers: vec![peer],
4747
mtu: None,

examples/userspace.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ fn pause() {
1313
let mut stdout = stdout();
1414
stdout.write_all(b"Press Enter to continue...").unwrap();
1515
stdout.flush().unwrap();
16-
stdin().read_exact(&mut [0]).unwrap();
16+
stdin().read(&mut [0]).unwrap();
1717
}
1818

1919
#[cfg(target_os = "macos")]
@@ -22,7 +22,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
2222
let ifname: String = if cfg!(target_os = "linux") || cfg!(target_os = "freebsd") {
2323
"wg0".into()
2424
} else {
25-
"utun3".into()
25+
"utun5".into()
2626
};
2727
let api = WGApi::<Userspace>::new(ifname.clone())?;
2828

@@ -54,7 +54,10 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
5454
let interface_config = InterfaceConfiguration {
5555
name: ifname.clone(),
5656
prvkey: "AAECAwQFBgcICQoLDA0OD/Dh0sO0pZaHeGlaSzwtHg8=".to_string(),
57-
address: "10.6.0.30".to_string(),
57+
addresses: vec![
58+
"10.6.0.30".parse().unwrap(),
59+
"fc00:def9::0a1d".parse().unwrap(),
60+
],
5861
port: 12345,
5962
peers: vec![peer],
6063
mtu: None,

src/bsd/ifconfig.rs

+44-6
Original file line numberDiff line numberDiff line change
@@ -17,37 +17,52 @@ const ND6_INFINITE_LIFETIME: u32 = u32::MAX;
1717

1818
// SIOCIFDESTROY
1919
ioctl_write_ptr!(destroy_clone_if, b'i', 121, IfReq);
20+
2021
// SIOCIFCREATE2
2122
// FIXME: not on NetBSD
2223
ioctl_readwrite!(create_clone_if, b'i', 124, IfReq);
24+
2325
// SIOCGIFMTU
2426
#[cfg(any(target_os = "freebsd", target_os = "macos"))]
2527
ioctl_readwrite!(get_if_mtu, b'i', 51, IfMtu);
2628
#[cfg(target_os = "netbsd")]
2729
ioctl_readwrite!(get_if_mtu, b'i', 126, IfMtu);
30+
2831
// SIOCSIFMTU
2932
#[cfg(any(target_os = "freebsd", target_os = "macos"))]
3033
ioctl_write_ptr!(set_if_mtu, b'i', 52, IfMtu);
3134
#[cfg(target_os = "netbsd")]
3235
ioctl_write_ptr!(set_if_mtu, b'i', 127, IfMtu);
36+
37+
// SIOCSIFADDR
38+
ioctl_write_ptr!(set_addr_if, b'i', 12, IfReq);
39+
3340
// SIOCAIFADDR
3441
#[cfg(target_os = "freebsd")]
3542
ioctl_write_ptr!(add_addr_if, b'i', 43, InAliasReq);
3643
#[cfg(any(target_os = "macos", target_os = "netbsd"))]
3744
ioctl_write_ptr!(add_addr_if, b'i', 26, InAliasReq);
45+
3846
// SIOCDIFADDR
3947
ioctl_write_ptr!(del_addr_if, b'i', 25, IfReq);
48+
49+
// SIOCSIFADDR_IN6
50+
ioctl_write_ptr!(set_addr_if_in6, b'i', 12, IfReq6);
51+
4052
// SIOCAIFADDR_IN6
4153
#[cfg(target_os = "freebsd")]
4254
ioctl_write_ptr!(add_addr_if_in6, b'i', 27, In6AliasReq);
4355
#[cfg(target_os = "macos")]
4456
ioctl_write_ptr!(add_addr_if_in6, b'i', 26, In6AliasReq);
4557
#[cfg(target_os = "netbsd")]
4658
ioctl_write_ptr!(add_addr_if_in6, b'i', 107, In6AliasReq);
59+
4760
// SIOCDIFADDR_IN6
4861
ioctl_write_ptr!(del_addr_if_in6, b'i', 25, IfReq6);
62+
4963
// SIOCSIFFLAGS
5064
ioctl_write_ptr!(set_if_flags, b'i', 16, IfReqFlags);
65+
5166
// SIOCGIFFLAGS
5267
ioctl_readwrite!(get_if_flags, b'i', 17, IfReqFlags);
5368

@@ -71,6 +86,14 @@ pub struct IfReq {
7186
}
7287

7388
impl IfReq {
89+
#[must_use]
90+
pub(super) fn new_with_address(if_name: &str, address: Ipv4Addr) -> Self {
91+
Self {
92+
ifr_name: make_ifr_name(if_name),
93+
ifr_ifru: address.into(),
94+
}
95+
}
96+
7497
#[must_use]
7598
pub(super) fn new(if_name: &str) -> Self {
7699
Self {
@@ -99,9 +122,16 @@ impl IfReq {
99122
Ok(())
100123
}
101124

102-
pub(super) fn delete_address(&mut self, addr: Ipv4Addr) -> Result<(), IoError> {
103-
self.ifr_ifru = addr.into();
125+
pub(super) fn set_address(&self) -> Result<(), IoError> {
126+
let socket = create_socket(AddressFamily::Inet).map_err(IoError::WriteIo)?;
127+
unsafe {
128+
set_addr_if(socket.as_raw_fd(), self).map_err(IoError::WriteIo)?;
129+
}
130+
131+
Ok(())
132+
}
104133

134+
pub(super) fn delete_address(&self) -> Result<(), IoError> {
105135
let socket = create_socket(AddressFamily::Inet).map_err(IoError::WriteIo)?;
106136
unsafe {
107137
del_addr_if(socket.as_raw_fd(), self).map_err(IoError::WriteIo)?;
@@ -161,17 +191,25 @@ pub struct IfReq6 {
161191

162192
impl IfReq6 {
163193
#[must_use]
164-
pub(super) fn new(if_name: &str) -> Self {
194+
pub(super) fn new_with_address(if_name: &str, address: Ipv6Addr) -> Self {
165195
Self {
166196
ifr_name: make_ifr_name(if_name),
167-
ifr_ifru: SockAddrIn6::default(),
197+
ifr_ifru: address.into(),
168198
_padding: [0u8; 244],
169199
}
170200
}
171201

172-
pub(super) fn delete_address(&mut self, addr: Ipv6Addr) -> Result<(), IoError> {
173-
self.ifr_ifru = addr.into();
202+
pub(super) fn set_address(&self) -> Result<(), IoError> {
203+
let socket = create_socket(AddressFamily::Inet6).map_err(IoError::WriteIo)?;
204+
205+
unsafe {
206+
set_addr_if_in6(socket.as_raw_fd(), self).map_err(IoError::WriteIo)?;
207+
}
208+
209+
Ok(())
210+
}
174211

212+
pub(super) fn delete_address(&self) -> Result<(), IoError> {
175213
let socket = create_socket(AddressFamily::Inet6).map_err(IoError::WriteIo)?;
176214
unsafe {
177215
del_addr_if_in6(socket.as_raw_fd(), self).map_err(IoError::WriteIo)?;

src/bsd/mod.rs

+17-4
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,19 @@ pub fn delete_interface(if_name: &str) -> Result<(), IoError> {
327327
ifreq.destroy()
328328
}
329329

330+
pub fn set_address(if_name: &str, address: &IpAddrMask) -> Result<(), IoError> {
331+
match address.ip {
332+
IpAddr::V4(address) => {
333+
let ifreq = IfReq::new_with_address(if_name, address);
334+
ifreq.set_address()
335+
}
336+
IpAddr::V6(address) => {
337+
let ifreq6 = IfReq6::new_with_address(if_name, address);
338+
ifreq6.set_address()
339+
}
340+
}
341+
}
342+
330343
pub fn assign_address(if_name: &str, address: &IpAddrMask) -> Result<(), IoError> {
331344
let broadcast = address.broadcast();
332345
let mask = address.mask();
@@ -347,12 +360,12 @@ pub fn assign_address(if_name: &str, address: &IpAddrMask) -> Result<(), IoError
347360
pub fn remove_address(if_name: &str, address: &IpAddrMask) -> Result<(), IoError> {
348361
match address.ip {
349362
IpAddr::V4(address) => {
350-
let mut ifreq = IfReq::new(if_name);
351-
ifreq.delete_address(address)
363+
let ifreq = IfReq::new_with_address(if_name, address);
364+
ifreq.delete_address()
352365
}
353366
IpAddr::V6(address) => {
354-
let mut ifreq6 = IfReq6::new(if_name);
355-
ifreq6.delete_address(address)
367+
let ifreq6 = IfReq6::new_with_address(if_name, address);
368+
ifreq6.delete_address()
356369
}
357370
}
358371
}

src/lib.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
//! let interface_config = InterfaceConfiguration {
3030
//! name: ifname.clone(),
3131
//! prvkey: "AAECAwQFBgcICQoLDA0OD/Dh0sO0pZaHeGlaSzwtHg8=".to_string(),
32-
//! address: "10.6.0.30".to_string(),
32+
//! addresses: vec!["10.6.0.30".parse().unwrap()],
3333
//! port: 12345,
3434
//! peers: vec![],
3535
//! mtu: None,
@@ -98,13 +98,13 @@ pub enum IpVersion {
9898
IPv6,
9999
}
100100

101-
/// Host WireGuard interface configuration
101+
/// Host WireGuard interface configuration.
102102
#[derive(Clone)]
103103
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
104104
pub struct InterfaceConfiguration {
105105
pub name: String,
106106
pub prvkey: String,
107-
pub address: String,
107+
pub addresses: Vec<IpAddrMask>,
108108
pub port: u32,
109109
pub peers: Vec<Peer>,
110110
/// Maximum transfer unit. `None` means do not set MTU, but keep the system default.
@@ -116,7 +116,7 @@ impl fmt::Debug for InterfaceConfiguration {
116116
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
117117
f.debug_struct("InterfaceConfiguration")
118118
.field("name", &self.name)
119-
.field("address", &self.address)
119+
.field("addresses", &self.addresses)
120120
.field("port", &self.port)
121121
.field("peers", &self.peers)
122122
.field("mtu", &self.mtu)

src/wgapi_linux.rs

+13-14
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::{net::IpAddr, str::FromStr};
1+
use std::net::IpAddr;
22

33
use crate::{
44
netlink,
@@ -50,17 +50,15 @@ impl WireguardInterfaceApi for WGApi<Kernel> {
5050
self.ifname
5151
);
5252

53-
// assign IP address to interface
54-
debug!(
55-
"Assigning address {} to interface {}",
56-
config.address, self.ifname
57-
);
58-
let address = IpAddrMask::from_str(&config.address)?;
59-
self.assign_address(&address)?;
60-
debug!(
61-
"Address {} assigned to interface {} successfully",
62-
config.address, self.ifname
63-
);
53+
// Assign IP addresses to the interface.
54+
for address in &config.addresses {
55+
debug!("Assigning address {address} to interface {}", self.ifname);
56+
self.assign_address(&address)?;
57+
debug!(
58+
"Address {address} assigned to interface {} successfully",
59+
self.ifname
60+
);
61+
}
6462

6563
// configure interface
6664
debug!(
@@ -88,8 +86,9 @@ impl WireguardInterfaceApi for WGApi<Kernel> {
8886
}
8987

9088
info!(
91-
"Interface {} has been successfully configured. It has been assigned the following address: {}",
92-
self.ifname, address
89+
"Interface {} has been successfully configured. \
90+
It has been assigned the following addresses: {:?}",
91+
self.ifname, config.addresses
9392
);
9493
debug!(
9594
"Interface {} configured with config: {config:?}",

0 commit comments

Comments
 (0)