1use std::{
4 marker::PhantomData,
5 net::{IpAddr, Ipv4Addr, Ipv6Addr},
6};
7
8#[cfg(not(target_os = "android"))]
9use netlink_packet_route::route::{
10 MplsLabel, RouteLwEnCapType, RouteLwTunnelEncap, RouteMplsIpTunnel,
11};
12use netlink_packet_route::{
13 route::{
14 RouteAddress, RouteAttribute, RouteFlags, RouteHeader, RouteMessage,
15 RouteNextHop, RouteNextHopFlags, RouteProtocol, RouteScope, RouteType,
16 RouteVia,
17 },
18 AddressFamily,
19};
20
21#[derive(Debug, Clone)]
22pub struct RouteMessageBuilder<T = IpAddr> {
23 message: RouteMessage,
24 _phantom: PhantomData<T>,
25}
26
27#[derive(Debug, Clone)]
28pub struct RouteNextHopBuilder {
29 address_family: AddressFamily,
30 nexthop: RouteNextHop,
31}
32
33impl<T> RouteMessageBuilder<T> {
34 fn new_no_address_family() -> Self {
43 let mut message = RouteMessage::default();
44 message.header.table = RouteHeader::RT_TABLE_MAIN;
45 message.header.protocol = RouteProtocol::Static;
46 message.header.scope = RouteScope::Universe;
47 message.header.kind = RouteType::Unicast;
48 Self {
49 message,
50 _phantom: Default::default(),
51 }
52 }
53
54 pub fn input_interface(mut self, index: u32) -> Self {
56 self.message.attributes.push(RouteAttribute::Iif(index));
57 self
58 }
59
60 pub fn output_interface(mut self, index: u32) -> Self {
62 self.message.attributes.push(RouteAttribute::Oif(index));
63 self
64 }
65
66 #[cfg(not(target_os = "android"))]
68 pub fn output_mpls(mut self, labels: Vec<MplsLabel>) -> Self {
69 if labels.is_empty() {
70 return self;
71 }
72 if self.message.header.address_family == AddressFamily::Mpls {
73 self.message
74 .attributes
75 .push(RouteAttribute::NewDestination(labels));
76 } else {
77 self.message
78 .attributes
79 .push(RouteAttribute::EncapType(RouteLwEnCapType::Mpls));
80 let encap = RouteLwTunnelEncap::Mpls(
81 RouteMplsIpTunnel::Destination(labels),
82 );
83 self.message
84 .attributes
85 .push(RouteAttribute::Encap(vec![encap]));
86 }
87 self
88 }
89
90 pub fn multipath(mut self, nexthops: Vec<RouteNextHop>) -> Self {
92 self.message
93 .attributes
94 .push(RouteAttribute::MultiPath(nexthops));
95 self
96 }
97
98 pub fn priority(mut self, priority: u32) -> Self {
100 self.message
101 .attributes
102 .push(RouteAttribute::Priority(priority));
103 self
104 }
105
106 pub fn table_id(mut self, table: u32) -> Self {
110 if table > 255 {
111 self.message.attributes.push(RouteAttribute::Table(table));
112 } else {
113 self.message.header.table = table as u8;
114 }
115 self
116 }
117
118 #[cfg(not(target_os = "android"))]
119 pub fn mark(mut self, mark: u32) -> Self {
121 self.message.attributes.push(RouteAttribute::Mark(mark));
122 self
123 }
124
125 pub fn protocol(mut self, protocol: RouteProtocol) -> Self {
129 self.message.header.protocol = protocol;
130 self
131 }
132
133 pub fn scope(mut self, scope: RouteScope) -> Self {
137 self.message.header.scope = scope;
138 self
139 }
140
141 pub fn kind(mut self, kind: RouteType) -> Self {
145 self.message.header.kind = kind;
146 self
147 }
148
149 pub fn onlink(mut self) -> Self {
154 self.message.header.flags.insert(RouteFlags::Onlink);
155 self
156 }
157
158 pub fn get_mut(&mut self) -> &mut RouteMessage {
160 &mut self.message
161 }
162
163 pub fn build(self) -> RouteMessage {
164 self.message
165 }
166}
167
168impl RouteMessageBuilder<Ipv4Addr> {
169 pub fn new() -> Self {
179 let mut builder = Self::new_no_address_family();
180 builder.get_mut().header.address_family = AddressFamily::Inet;
181 builder
182 }
183
184 pub fn source_prefix(mut self, addr: Ipv4Addr, prefix_length: u8) -> Self {
186 self.message.header.source_prefix_length = prefix_length;
187 self.message
188 .attributes
189 .push(RouteAttribute::Source(RouteAddress::Inet(addr)));
190 self
191 }
192
193 pub fn pref_source(mut self, addr: Ipv4Addr) -> Self {
195 self.message
196 .attributes
197 .push(RouteAttribute::PrefSource(RouteAddress::Inet(addr)));
198 self
199 }
200
201 pub fn destination_prefix(
203 mut self,
204 addr: Ipv4Addr,
205 prefix_length: u8,
206 ) -> Self {
207 self.message.header.destination_prefix_length = prefix_length;
208 self.message
209 .attributes
210 .push(RouteAttribute::Destination(RouteAddress::Inet(addr)));
211 self
212 }
213
214 pub fn gateway(mut self, addr: Ipv4Addr) -> Self {
216 self.message
217 .attributes
218 .push(RouteAttribute::Gateway(RouteAddress::Inet(addr)));
219 self
220 }
221
222 pub fn via(mut self, addr: Ipv6Addr) -> Self {
224 self.message
225 .attributes
226 .push(RouteAttribute::Via(RouteVia::Inet6(addr)));
227 self
228 }
229}
230
231impl Default for RouteMessageBuilder<Ipv4Addr> {
232 fn default() -> Self {
233 Self::new()
234 }
235}
236
237impl RouteMessageBuilder<Ipv6Addr> {
238 pub fn new() -> Self {
248 let mut builder = Self::new_no_address_family();
249 builder.get_mut().header.address_family = AddressFamily::Inet6;
250 builder
251 }
252
253 pub fn source_prefix(mut self, addr: Ipv6Addr, prefix_length: u8) -> Self {
255 self.message.header.source_prefix_length = prefix_length;
256 self.message
257 .attributes
258 .push(RouteAttribute::Source(RouteAddress::Inet6(addr)));
259 self
260 }
261
262 pub fn pref_source(mut self, addr: Ipv6Addr) -> Self {
264 self.message
265 .attributes
266 .push(RouteAttribute::PrefSource(RouteAddress::Inet6(addr)));
267 self
268 }
269
270 pub fn destination_prefix(
272 mut self,
273 addr: Ipv6Addr,
274 prefix_length: u8,
275 ) -> Self {
276 self.message.header.destination_prefix_length = prefix_length;
277 self.message
278 .attributes
279 .push(RouteAttribute::Destination(RouteAddress::Inet6(addr)));
280 self
281 }
282
283 pub fn gateway(mut self, addr: Ipv6Addr) -> Self {
285 self.message
286 .attributes
287 .push(RouteAttribute::Gateway(RouteAddress::Inet6(addr)));
288 self
289 }
290}
291
292impl Default for RouteMessageBuilder<Ipv6Addr> {
293 fn default() -> Self {
294 Self::new()
295 }
296}
297
298#[derive(Debug, thiserror::Error)]
299pub enum InvalidRouteMessage {
300 #[error("invalid address family {:?}", _0)]
301 AddressFamily(AddressFamily),
302
303 #[error("invalid gateway {}", _0)]
304 Gateway(IpAddr),
305
306 #[error("invalid preferred source {}", _0)]
307 PrefSource(IpAddr),
308
309 #[error("invalid source prefix {}/{}", _0, _1)]
310 SourcePrefix(IpAddr, u8),
311
312 #[error("invalid destination prefix {}/{}", _0, _1)]
313 DestinationPrefix(IpAddr, u8),
314}
315
316impl RouteMessageBuilder<IpAddr> {
317 pub fn new() -> Self {
318 Self::new_no_address_family()
319 }
320
321 pub fn source_prefix(
323 mut self,
324 addr: IpAddr,
325 prefix_length: u8,
326 ) -> Result<Self, InvalidRouteMessage> {
327 self.set_address_family_from_ip_addr(addr);
328 match self.message.header.address_family {
329 AddressFamily::Inet => {
330 if addr.is_ipv6() || prefix_length > 32 {
331 return Err(InvalidRouteMessage::SourcePrefix(
332 addr,
333 prefix_length,
334 ));
335 }
336 }
337 AddressFamily::Inet6 => {
338 if addr.is_ipv4() || prefix_length > 128 {
339 return Err(InvalidRouteMessage::SourcePrefix(
340 addr,
341 prefix_length,
342 ));
343 }
344 }
345 af => return Err(InvalidRouteMessage::AddressFamily(af)),
346 };
347 self.message
348 .attributes
349 .push(RouteAttribute::Source(addr.into()));
350 self.message.header.source_prefix_length = prefix_length;
351 Ok(self)
352 }
353
354 pub fn pref_source(
356 mut self,
357 addr: IpAddr,
358 ) -> Result<Self, InvalidRouteMessage> {
359 self.set_address_family_from_ip_addr(addr);
360 match self.message.header.address_family {
361 AddressFamily::Inet => {
362 if addr.is_ipv6() {
363 return Err(InvalidRouteMessage::PrefSource(addr));
364 };
365 }
366 AddressFamily::Inet6 => {
367 if addr.is_ipv4() {
368 return Err(InvalidRouteMessage::PrefSource(addr));
369 };
370 }
371 af => {
372 return Err(InvalidRouteMessage::AddressFamily(af));
373 }
374 }
375 self.message
376 .attributes
377 .push(RouteAttribute::PrefSource(addr.into()));
378 Ok(self)
379 }
380
381 pub fn destination_prefix(
383 mut self,
384 addr: IpAddr,
385 prefix_length: u8,
386 ) -> Result<Self, InvalidRouteMessage> {
387 self.set_address_family_from_ip_addr(addr);
388 match self.message.header.address_family {
389 AddressFamily::Inet => {
390 if addr.is_ipv6() || prefix_length > 32 {
391 return Err(InvalidRouteMessage::DestinationPrefix(
392 addr,
393 prefix_length,
394 ));
395 }
396 }
397 AddressFamily::Inet6 => {
398 if addr.is_ipv4() || prefix_length > 128 {
399 return Err(InvalidRouteMessage::DestinationPrefix(
400 addr,
401 prefix_length,
402 ));
403 }
404 }
405 af => {
406 return Err(InvalidRouteMessage::AddressFamily(af));
407 }
408 };
409 self.message.header.destination_prefix_length = prefix_length;
410 self.message
411 .attributes
412 .push(RouteAttribute::Destination(addr.into()));
413 Ok(self)
414 }
415
416 pub fn gateway(
418 mut self,
419 addr: IpAddr,
420 ) -> Result<Self, InvalidRouteMessage> {
421 let attr = match (self.message.header.address_family, addr) {
422 (AddressFamily::Inet, addr @ IpAddr::V4(_))
423 | (AddressFamily::Inet6, addr @ IpAddr::V6(_)) => {
424 RouteAttribute::Gateway(addr.into())
425 }
426 (AddressFamily::Inet, IpAddr::V6(v6)) => {
427 RouteAttribute::Via(RouteVia::Inet6(v6))
428 }
429 (af, _) => return Err(InvalidRouteMessage::AddressFamily(af)),
430 };
431 self.message.attributes.push(attr);
432 Ok(self)
433 }
434
435 fn set_address_family_from_ip_addr(&mut self, addr: IpAddr) {
439 if self.message.header.address_family != AddressFamily::Unspec {
440 return;
441 }
442 if addr.is_ipv4() {
443 self.message.header.address_family = AddressFamily::Inet;
444 } else {
445 self.message.header.address_family = AddressFamily::Inet6;
446 }
447 }
448}
449
450impl Default for RouteMessageBuilder<IpAddr> {
451 fn default() -> Self {
452 Self::new()
453 }
454}
455
456#[cfg(not(target_os = "android"))]
457impl RouteMessageBuilder<MplsLabel> {
458 pub fn new() -> Self {
468 let mut builder = Self::new_no_address_family();
469 builder.get_mut().header.address_family = AddressFamily::Mpls;
470 builder
471 }
472
473 #[cfg(not(target_os = "android"))]
474 pub fn label(mut self, label: MplsLabel) -> Self {
476 self.message.header.address_family = AddressFamily::Mpls;
477 self.message.header.destination_prefix_length = 20;
478 self.message
479 .attributes
480 .push(RouteAttribute::Destination(RouteAddress::Mpls(label)));
481 self
482 }
483
484 pub fn via(mut self, addr: IpAddr) -> Self {
486 self.message
487 .attributes
488 .push(RouteAttribute::Via(addr.into()));
489 self
490 }
491}
492#[cfg(not(target_os = "android"))]
493impl Default for RouteMessageBuilder<MplsLabel> {
494 fn default() -> Self {
495 Self::new()
496 }
497}
498
499impl RouteNextHopBuilder {
500 pub fn new(address_family: AddressFamily) -> Self {
502 Self {
503 address_family,
504 nexthop: Default::default(),
505 }
506 }
507
508 pub fn new_ipv4() -> Self {
510 Self {
511 address_family: AddressFamily::Inet,
512 nexthop: Default::default(),
513 }
514 }
515
516 pub fn new_ipv6() -> Self {
518 Self {
519 address_family: AddressFamily::Inet6,
520 nexthop: Default::default(),
521 }
522 }
523
524 pub fn interface(mut self, index: u32) -> Self {
526 self.nexthop.interface_index = index;
527 self
528 }
529
530 pub fn via(mut self, addr: IpAddr) -> Result<Self, InvalidRouteMessage> {
532 let attr = match (self.address_family, addr) {
533 (AddressFamily::Inet, addr @ IpAddr::V4(_))
534 | (AddressFamily::Inet6, addr @ IpAddr::V6(_)) => {
535 RouteAttribute::Gateway(addr.into())
536 }
537 (AddressFamily::Inet, IpAddr::V6(v6)) => {
538 RouteAttribute::Via(RouteVia::Inet6(v6))
539 }
540 #[cfg(not(target_os = "android"))]
541 (AddressFamily::Mpls, _) => RouteAttribute::Via(addr.into()),
542 (af, _) => return Err(InvalidRouteMessage::AddressFamily(af)),
543 };
544 self.nexthop.attributes.push(attr);
545 Ok(self)
546 }
547
548 pub fn onlink(mut self) -> Self {
553 self.nexthop.flags.insert(RouteNextHopFlags::Onlink);
554 self
555 }
556
557 #[cfg(not(target_os = "android"))]
559 pub fn mpls(mut self, labels: Vec<MplsLabel>) -> Self {
560 if labels.is_empty() {
561 return self;
562 }
563 if self.address_family == AddressFamily::Mpls {
564 self.nexthop
565 .attributes
566 .push(RouteAttribute::NewDestination(labels));
567 } else {
568 self.nexthop
569 .attributes
570 .push(RouteAttribute::EncapType(RouteLwEnCapType::Mpls));
571 let encap = RouteLwTunnelEncap::Mpls(
572 RouteMplsIpTunnel::Destination(labels),
573 );
574 self.nexthop
575 .attributes
576 .push(RouteAttribute::Encap(vec![encap]));
577 }
578 self
579 }
580
581 pub fn weight(mut self, weight: u8) -> Self {
588 self.nexthop.hops = weight;
589 self
590 }
591
592 pub fn flags(mut self, flags: RouteNextHopFlags) -> Self {
594 self.nexthop.flags = flags;
595 self
596 }
597
598 pub fn build(self) -> RouteNextHop {
599 self.nexthop
600 }
601}