Skip to content

Commit 9be24c6

Browse files
committed
route: Use RouteMessageBuilder for querying route
**API BREAKAGE** To align with other route handler, the `RouteHandle::get()` has changed from `new(ip_version: IpVersion)` to `new(route: RouteMessage)`. Once `NETLINK_GET_STRICT_CHK` enabled by `rtnetlink::sys::Socket::set_netlink_get_strict_chk(true)`, kernel will only return match routes only in dump. Example `get_route_kernel_filter.rs` included to demonstrate this. Signed-off-by: Gris Ge <[email protected]>
1 parent a4d2611 commit 9be24c6

File tree

5 files changed

+86
-29
lines changed

5 files changed

+86
-29
lines changed

examples/get_route.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
// SPDX-License-Identifier: MIT
22

3+
use std::net::{Ipv4Addr, Ipv6Addr};
4+
35
use futures::stream::TryStreamExt;
4-
use rtnetlink::{new_connection, Error, Handle, IpVersion};
6+
use rtnetlink::{
7+
new_connection, Error, Handle, IpVersion, RouteMessageBuilder,
8+
};
59

610
#[tokio::main]
711
async fn main() -> Result<(), ()> {
@@ -27,7 +31,11 @@ async fn dump_addresses(
2731
handle: Handle,
2832
ip_version: IpVersion,
2933
) -> Result<(), Error> {
30-
let mut routes = handle.route().get(ip_version).execute();
34+
let route = match ip_version {
35+
IpVersion::V4 => RouteMessageBuilder::<Ipv4Addr>::new().build(),
36+
IpVersion::V6 => RouteMessageBuilder::<Ipv6Addr>::new().build(),
37+
};
38+
let mut routes = handle.route().get(route).execute();
3139
while let Some(route) = routes.try_next().await? {
3240
println!("{route:?}");
3341
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
use std::net::Ipv4Addr;
4+
5+
use futures::stream::TryStreamExt;
6+
use rtnetlink::{
7+
new_connection,
8+
packet_route::route::{RouteProtocol, RouteScope, RouteType},
9+
sys::AsyncSocket,
10+
RouteMessageBuilder,
11+
};
12+
13+
/// Dump IPv4 unicast routes with protocol boot(e.g. route created by ip
14+
/// route)on table 254 only
15+
#[tokio::main]
16+
async fn main() -> Result<(), Box<dyn std::error::Error>> {
17+
let (mut connection, handle, _) = new_connection().unwrap();
18+
19+
connection
20+
.socket_mut()
21+
.socket_mut()
22+
.set_netlink_get_strict_chk(true)?;
23+
24+
tokio::spawn(connection);
25+
26+
println!("dumping routes for IPv4 in table 254");
27+
let route = RouteMessageBuilder::<Ipv4Addr>::new()
28+
.table_id(254)
29+
.protocol(RouteProtocol::Boot)
30+
.scope(RouteScope::Universe)
31+
.kind(RouteType::Unicast)
32+
.build();
33+
let mut routes = handle.route().get(route).execute();
34+
while let Some(route) = routes.try_next().await? {
35+
println!("{route:?}");
36+
}
37+
38+
Ok(())
39+
}

src/route/builder.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,14 @@ pub struct RouteMessageBuilder<T = IpAddr> {
1919
}
2020

2121
impl<T> RouteMessageBuilder<T> {
22+
/// Create default RouteMessage with header set to:
23+
/// * route: [RouteHeader::RT_TABLE_MAIN]
24+
/// * protocol: [RouteProtocol::Static]
25+
/// * scope: [RouteScope::Universe]
26+
/// * kind: [RouteType::Unicast]
27+
///
28+
/// For using this message in querying routes, these settings
29+
/// are ignored unless `NETLINK_GET_STRICT_CHK` been enabled.
2230
fn new_no_address_family() -> Self {
2331
let mut message = RouteMessage::default();
2432
message.header.table = RouteHeader::RT_TABLE_MAIN;
@@ -98,6 +106,15 @@ impl<T> RouteMessageBuilder<T> {
98106
}
99107

100108
impl RouteMessageBuilder<Ipv4Addr> {
109+
/// Create default RouteMessage with header set to:
110+
/// * route: [RouteHeader::RT_TABLE_MAIN]
111+
/// * protocol: [RouteProtocol::Static]
112+
/// * scope: [RouteScope::Universe]
113+
/// * kind: [RouteType::Unicast]
114+
/// * address_family: [AddressFamily::Inet4]
115+
///
116+
/// For using this message in querying routes, these settings
117+
/// are ignored unless `NETLINK_GET_STRICT_CHK` been enabled.
101118
pub fn new() -> Self {
102119
let mut builder = Self::new_no_address_family();
103120
builder.get_mut().header.address_family = AddressFamily::Inet;
@@ -150,6 +167,15 @@ impl Default for RouteMessageBuilder<Ipv4Addr> {
150167
}
151168

152169
impl RouteMessageBuilder<Ipv6Addr> {
170+
/// Create default RouteMessage with header set to:
171+
/// * route: [RouteHeader::RT_TABLE_MAIN]
172+
/// * protocol: [RouteProtocol::Static]
173+
/// * scope: [RouteScope::Universe]
174+
/// * kind: [RouteType::Unicast]
175+
/// * address_family: [AddressFamily::Inet6]
176+
///
177+
/// For using this message in querying routes, these settings
178+
/// are ignored unless `NETLINK_GET_STRICT_CHK` been enabled.
153179
pub fn new() -> Self {
154180
let mut builder = Self::new_no_address_family();
155181
builder.get_mut().header.address_family = AddressFamily::Inet6;

src/route/get.rs

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@ use futures::{
88

99
use netlink_packet_core::{NetlinkMessage, NLM_F_DUMP, NLM_F_REQUEST};
1010
use netlink_packet_route::{
11-
route::{RouteHeader, RouteMessage, RouteProtocol, RouteScope, RouteType},
12-
AddressFamily, RouteNetlinkMessage,
11+
route::RouteMessage, AddressFamily, RouteNetlinkMessage,
1312
};
1413

1514
use crate::{try_rtnl, Error, Handle};
@@ -38,26 +37,7 @@ impl IpVersion {
3837
}
3938

4039
impl RouteGetRequest {
41-
pub(crate) fn new(handle: Handle, ip_version: IpVersion) -> Self {
42-
let mut message = RouteMessage::default();
43-
message.header.address_family = ip_version.family();
44-
45-
// As per rtnetlink(7) documentation, setting the following
46-
// fields to 0 gets us all the routes from all the tables
47-
//
48-
// > For RTM_GETROUTE, setting rtm_dst_len and rtm_src_len to 0
49-
// > means you get all entries for the specified routing table.
50-
// > For the other fields, except rtm_table and rtm_protocol, 0
51-
// > is the wildcard.
52-
message.header.destination_prefix_length = 0;
53-
message.header.source_prefix_length = 0;
54-
message.header.scope = RouteScope::Universe;
55-
message.header.kind = RouteType::Unspec;
56-
57-
// I don't know if these two fields matter
58-
message.header.table = RouteHeader::RT_TABLE_UNSPEC;
59-
message.header.protocol = RouteProtocol::Unspec;
60-
40+
pub(crate) fn new(handle: Handle, message: RouteMessage) -> Self {
6141
RouteGetRequest { handle, message }
6242
}
6343

src/route/handle.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
// SPDX-License-Identifier: MIT
22

3-
use crate::{
4-
Handle, IpVersion, RouteAddRequest, RouteDelRequest, RouteGetRequest,
5-
};
3+
use crate::{Handle, RouteAddRequest, RouteDelRequest, RouteGetRequest};
64
use netlink_packet_route::route::RouteMessage;
75

86
pub struct RouteHandle(Handle);
@@ -14,16 +12,22 @@ impl RouteHandle {
1412

1513
/// Retrieve the list of routing table entries (equivalent to `ip route
1614
/// show`)
17-
pub fn get(&self, ip_version: IpVersion) -> RouteGetRequest {
18-
RouteGetRequest::new(self.0.clone(), ip_version)
15+
/// The `RouteMessage` could be built by [crate::RouteMessageBuilder].
16+
/// In order to perform kernel side filter, please enable
17+
/// `NETLINK_GET_STRICT_CHK` via
18+
/// `rtnetlink::sys::Socket::set_netlink_get_strict_chk(true)`.
19+
pub fn get(&self, route: RouteMessage) -> RouteGetRequest {
20+
RouteGetRequest::new(self.0.clone(), route)
1921
}
2022

2123
/// Add an routing table entry (equivalent to `ip route add`)
24+
/// The `RouteMessage` could be built by [crate::RouteMessageBuilder].
2225
pub fn add(&self, route: RouteMessage) -> RouteAddRequest {
2326
RouteAddRequest::new(self.0.clone(), route)
2427
}
2528

2629
/// Delete the given routing table entry (equivalent to `ip route del`)
30+
/// The `RouteMessage` could be built by [crate::RouteMessageBuilder].
2731
pub fn del(&self, route: RouteMessage) -> RouteDelRequest {
2832
RouteDelRequest::new(self.0.clone(), route)
2933
}

0 commit comments

Comments
 (0)