libcontainer/network/
cidr.rs1use std::net::IpAddr;
2
3use netlink_packet_route::address::{AddressAttribute, AddressMessage};
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Clone, Serialize, Deserialize)]
7pub struct CidrAddress {
8 pub prefix_len: u8,
9 pub address: IpAddr,
10}
11
12impl From<&AddressMessage> for CidrAddress {
13 fn from(msg: &AddressMessage) -> Self {
14 let address =
15 parse_ip_address(msg).expect("AddressMessage without IFA_LOCAL or IFA_ADDRESS");
16 CidrAddress {
17 prefix_len: msg.header.prefix_len,
18 address,
19 }
20 }
21}
22
23fn parse_ip_address(addr: &AddressMessage) -> Option<IpAddr> {
38 let local = addr.attributes.iter().find_map(|attr| match attr {
40 AddressAttribute::Local(ip) => Some(*ip),
41 _ => None,
42 });
43
44 if let Some(ip) = local {
46 return Some(ip);
47 }
48
49 addr.attributes.iter().find_map(|attr| match attr {
51 AddressAttribute::Address(ip) => Some(*ip),
52 _ => None,
53 })
54}
55
56#[cfg(test)]
57mod tests {
58 use std::net::{IpAddr, Ipv4Addr};
59
60 use netlink_packet_route::AddressFamily;
61 use netlink_packet_route::address::{AddressFlags, AddressMessage, AddressScope};
62
63 use super::*;
64
65 #[test]
66 fn test_address_message_to_cidr() {
67 let mut msg = AddressMessage::default();
68 msg.header.index = 10;
69 msg.header.prefix_len = 24;
70 msg.header.family = AddressFamily::Inet;
71 msg.header.scope = AddressScope::Universe;
72 let ip = "192.168.1.1".parse().unwrap();
73 msg.attributes.push(AddressAttribute::Address(ip));
74 msg.attributes
75 .push(AddressAttribute::Flags(AddressFlags::Permanent));
76
77 let cidr = CidrAddress::from(&msg);
78 assert_eq!(cidr.prefix_len, 24);
79 assert_eq!(cidr.address, ip);
80 }
81
82 #[test]
83 fn test_parse_ip_address_with_local() {
84 let mut addr_msg = AddressMessage::default();
86 addr_msg
87 .attributes
88 .push(AddressAttribute::Local(IpAddr::V4(Ipv4Addr::new(
89 10, 0, 0, 1,
90 ))));
91 addr_msg
92 .attributes
93 .push(AddressAttribute::Address(IpAddr::V4(Ipv4Addr::new(
94 10, 0, 0, 2,
95 ))));
96
97 let result = parse_ip_address(&addr_msg);
98 assert_eq!(result, Some(IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1))));
99 }
100
101 #[test]
102 fn test_parse_ip_address_without_local() {
103 let mut addr_msg = AddressMessage::default();
105 addr_msg
106 .attributes
107 .push(AddressAttribute::Address(IpAddr::V6(
108 std::net::Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1),
109 )));
110
111 let result = parse_ip_address(&addr_msg);
112 assert_eq!(
113 result,
114 Some(IpAddr::V6(std::net::Ipv6Addr::new(
115 0x2001, 0xdb8, 0, 0, 0, 0, 0, 1
116 )))
117 );
118 }
119
120 #[test]
121 fn test_parse_ip_address_ipv6_with_local() {
122 let mut addr_msg = AddressMessage::default();
124 addr_msg.attributes.push(AddressAttribute::Local(IpAddr::V6(
125 std::net::Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 1),
126 )));
127 addr_msg
128 .attributes
129 .push(AddressAttribute::Address(IpAddr::V6(
130 std::net::Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 2),
131 )));
132
133 let result = parse_ip_address(&addr_msg);
134 assert_eq!(
135 result,
136 Some(IpAddr::V6(std::net::Ipv6Addr::new(
137 0xfe80, 0, 0, 0, 0, 0, 0, 1
138 )))
139 );
140 }
141
142 #[test]
143 fn test_parse_ip_address_no_attributes() {
144 let addr_msg = AddressMessage::default();
146
147 let result = parse_ip_address(&addr_msg);
148 assert_eq!(result, None);
149 }
150}