Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions examples/del_address.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// SPDX-License-Identifier: MIT

use futures::stream::TryStreamExt;
use std::{
env,
net::{IpAddr, Ipv4Addr, Ipv6Addr},
};

use ipnetwork::IpNetwork;
use rtnetlink::{new_connection, AddressMessageBuilder, Error, Handle};

#[tokio::main]
async fn main() -> Result<(), ()> {
let args: Vec<String> = env::args().collect();
if args.len() != 3 {
usage();
return Ok(());
}

let link_name = &args[1];
let ip: IpNetwork = args[2].parse().unwrap_or_else(|_| {
eprintln!("invalid address");
std::process::exit(1);
});

let (connection, handle, _) = new_connection().unwrap();
tokio::spawn(connection);

if let Err(e) = del_address(link_name, ip, handle.clone()).await {
eprintln!("{e}");
}
Ok(())
}

async fn del_address(
link_name: &str,
ip: IpNetwork,
handle: Handle,
) -> Result<(), Error> {
let mut links = handle
.link()
.get()
.match_name(link_name.to_string())
.execute();
if let Some(link) = links.try_next().await? {
let index = link.header.index;
let address = ip.ip();
let prefix_len = ip.prefix();
let message = match address {
IpAddr::V4(address) => AddressMessageBuilder::<Ipv4Addr>::new()
.index(index)
.address(address, prefix_len)
.build(),
IpAddr::V6(address) => AddressMessageBuilder::<Ipv6Addr>::new()
.index(index)
.address(address, prefix_len)
.build(),
};
handle.address().del(message).execute().await?
}
Ok(())
}

fn usage() {
eprintln!(
"usage:
cargo run --example del_address -- <link_name> <ip_address>
Note that you need to run this program as root. Instead of running cargo as root,
build the example normally:
cd rtnetlink ; cargo build --example del_address
Then find the binary in the target directory:
cd ../target/debug/example ; sudo ./del_address <link_name> <ip_address>"
);
}
51 changes: 12 additions & 39 deletions src/addr/add.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
// SPDX-License-Identifier: MIT

use futures::stream::StreamExt;
use std::net::{IpAddr, Ipv4Addr};
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};

use netlink_packet_core::{
NetlinkMessage, NLM_F_ACK, NLM_F_CREATE, NLM_F_EXCL, NLM_F_REPLACE,
NLM_F_REQUEST,
};

use netlink_packet_route::{
address::{AddressAttribute, AddressMessage},
AddressFamily, RouteNetlinkMessage,
};
use netlink_packet_route::{address::AddressMessage, RouteNetlinkMessage};

use crate::{try_nl, Error, Handle};
use crate::{addr::AddressMessageBuilder, try_nl, Error, Handle};

/// A request to create a new address. This is equivalent to the `ip address
/// add` commands.
@@ -30,41 +27,17 @@ impl AddressAddRequest {
address: IpAddr,
prefix_len: u8,
) -> Self {
let mut message = AddressMessage::default();

message.header.prefix_len = prefix_len;
message.header.index = index;

message.header.family = match address {
IpAddr::V4(_) => AddressFamily::Inet,
IpAddr::V6(_) => AddressFamily::Inet6,
let message = match address {
IpAddr::V4(address) => AddressMessageBuilder::<Ipv4Addr>::new()
.index(index)
.address(address, prefix_len)
.build(),
IpAddr::V6(address) => AddressMessageBuilder::<Ipv6Addr>::new()
.index(index)
.address(address, prefix_len)
.build(),
};

if address.is_multicast() {
if let IpAddr::V6(a) = address {
message.attributes.push(AddressAttribute::Multicast(a));
}
} else {
message.attributes.push(AddressAttribute::Address(address));

// for IPv4 the IFA_LOCAL address can be set to the same value as
// IFA_ADDRESS
message.attributes.push(AddressAttribute::Local(address));

// set the IFA_BROADCAST address as well (IPv6 does not support
// broadcast)
if let IpAddr::V4(a) = address {
if prefix_len == 32 {
message.attributes.push(AddressAttribute::Broadcast(a));
} else {
let ip_addr = u32::from(a);
let brd = Ipv4Addr::from(
(0xffff_ffff_u32) >> u32::from(prefix_len) | ip_addr,
);
message.attributes.push(AddressAttribute::Broadcast(brd));
};
}
}
AddressAddRequest {
handle,
message,
112 changes: 112 additions & 0 deletions src/addr/builder.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
// SPDX-License-Identifier: MIT

use std::{
marker::PhantomData,
net::{Ipv4Addr, Ipv6Addr},
};

use netlink_packet_route::{
address::{AddressAttribute, AddressMessage},
AddressFamily,
};

#[derive(Debug)]
/// Helper struct for building [AddressMessage].
pub struct AddressMessageBuilder<T> {
message: AddressMessage,
_phantom: PhantomData<T>,
}

impl<T> AddressMessageBuilder<T> {
/// Create a new [AddressMessageBuilder] without specifying the address family.
fn new_no_address_family() -> Self {
AddressMessageBuilder {
message: AddressMessage::default(),
_phantom: PhantomData,
}
}

/// Sets the interface index.
pub fn index(mut self, index: u32) -> Self {
self.message.header.index = index;
self
}

/// Builds [AddressMessage].
pub fn build(self) -> AddressMessage {
self.message
}
}

impl AddressMessageBuilder<Ipv4Addr> {
/// Create a new [AddressMessageBuilder] for IPv4 addresses.
pub fn new() -> Self {
let mut builder = Self::new_no_address_family();
builder.message.header.family = AddressFamily::Inet;
builder
}

/// Sets the address and prefix length.
pub fn address(mut self, address: Ipv4Addr, prefix_len: u8) -> Self {
self.message.header.prefix_len = prefix_len;

if !address.is_multicast() {
self.message
.attributes
.push(AddressAttribute::Address(address.into()));

// The IFA_LOCAL address can be set to the same value as IFA_ADDRESS.
self.message
.attributes
.push(AddressAttribute::Local(address.into()));

// Set the IFA_BROADCAST address as well.
if prefix_len == 32 {
self.message
.attributes
.push(AddressAttribute::Broadcast(address));
} else {
let ip_addr = u32::from(address);
let brd = Ipv4Addr::from(
(0xffff_ffff_u32) >> u32::from(prefix_len) | ip_addr,
);
self.message
.attributes
.push(AddressAttribute::Broadcast(brd));
};
}

self
}
}

impl AddressMessageBuilder<Ipv6Addr> {
/// Create a new [AddressMessageBuilder] for IPv6 addresses.
pub fn new() -> Self {
let mut builder = Self::new_no_address_family();
builder.message.header.family = AddressFamily::Inet6;
builder
}

/// Sets the address and prefix length.
pub fn address(mut self, address: Ipv6Addr, prefix_len: u8) -> Self {
self.message.header.prefix_len = prefix_len;

if address.is_multicast() {
self.message
.attributes
.push(AddressAttribute::Multicast(address));
} else {
self.message
.attributes
.push(AddressAttribute::Address(address.into()));

// The IFA_LOCAL address can be set to the same value as IFA_ADDRESS.
self.message
.attributes
.push(AddressAttribute::Local(address.into()));
}

self
}
}
2 changes: 2 additions & 0 deletions src/addr/mod.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
// SPDX-License-Identifier: MIT

mod add;
mod builder;
mod del;
mod get;
mod handle;

pub use self::add::AddressAddRequest;
pub use self::builder::AddressMessageBuilder;
pub use self::del::AddressDelRequest;
pub use self::get::AddressGetRequest;
pub use self::handle::AddressHandle;
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -28,6 +28,7 @@ mod traffic_control;

pub use crate::addr::{
AddressAddRequest, AddressDelRequest, AddressGetRequest, AddressHandle,
AddressMessageBuilder,
};
pub use crate::connection::from_socket;
#[cfg(feature = "tokio_socket")]