Skip to content

Commit 3585395

Browse files
fixup! iptunnel: add support to ipip, ipip6 and ip6ip6 tunnels
1 parent 2485df5 commit 3585395

File tree

3 files changed

+132
-57
lines changed

3 files changed

+132
-57
lines changed

src/link/link_info/info_data.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use anyhow::Context;
44

55
use netlink_packet_utils::{
66
nla::{Nla, NlaBuffer, NlasIterator},
7-
DecodeError, Emitable, Parseable,
7+
DecodeError, Emitable, Parseable, ParseableParametrized,
88
};
99

1010
use super::super::{
@@ -362,7 +362,8 @@ impl InfoData {
362362
let nla = &nla.context(format!(
363363
"invalid IFLA_INFO_DATA for {kind} {payload:?}"
364364
))?;
365-
let parsed = InfoIpTunnel::parse(nla)?;
365+
let parsed =
366+
InfoIpTunnel::parse_with_param(nla, kind.clone())?;
366367
v.push(parsed);
367368
}
368369
InfoData::IpTunnel(v)

src/link/link_info/iptunnel.rs

Lines changed: 53 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
1-
// B
21
// SPDX-License-Identifier: MIT
32

4-
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
3+
use std::net::{IpAddr, Ipv6Addr};
54

65
use anyhow::Context;
76
use byteorder::{ByteOrder, NativeEndian};
87
use netlink_packet_utils::{
98
nla::{DefaultNla, Nla, NlaBuffer},
10-
parsers::{parse_u16, parse_u32, parse_u8},
11-
traits::Parseable,
9+
parsers::{parse_u16, parse_u16_be, parse_u32, parse_u8},
10+
traits::{Parseable, ParseableParametrized},
1211
DecodeError,
1312
};
1413

15-
use crate::ip::IpProtocol;
14+
use crate::ip::{parse_ip_addr, IpProtocol};
1615

1716
const IFLA_IPTUN_LINK: u16 = 1;
1817
const IFLA_IPTUN_LOCAL: u16 = 2;
@@ -45,7 +44,9 @@ pub enum InfoIpTunnel {
4544
Tos(u8),
4645
EncapLimit(u8),
4746
FlowInfo(u32),
48-
Flags(TunnelFlags),
47+
Ipv6SitFlags(u16),
48+
Ipv4Flags(u16),
49+
Ipv6Flags(u32),
4950
Protocol(IpProtocol),
5051
PMtuDisc(bool),
5152
Ipv6RdPrefix(Ipv6Addr),
@@ -70,8 +71,10 @@ impl Nla for InfoIpTunnel {
7071
IpAddr::V4(_) => 4,
7172
IpAddr::V6(_) => 16,
7273
},
73-
Link(_) | FwMark(_) | FlowInfo(_) | Flags(_) => 4,
74-
EncapType(_)
74+
Link(_) | FwMark(_) | FlowInfo(_) | Ipv6Flags(_) => 4,
75+
Ipv6SitFlags(_)
76+
| Ipv4Flags(_)
77+
| EncapType(_)
7578
| EncapFlags(_)
7679
| EncapSPort(_)
7780
| EncapDPort(_)
@@ -92,8 +95,11 @@ impl Nla for InfoIpTunnel {
9295
Link(value) | FwMark(value) | FlowInfo(value) => {
9396
NativeEndian::write_u32(buffer, *value)
9497
}
95-
Flags(f) => {
96-
NativeEndian::write_u32(buffer, f.bits());
98+
Ipv6Flags(val) => {
99+
NativeEndian::write_u32(buffer, *val);
100+
}
101+
Ipv6SitFlags(val) | Ipv4Flags(val) => {
102+
NativeEndian::write_u16(buffer, *val);
97103
}
98104
Local(value) | Remote(value) => match value {
99105
IpAddr::V4(ipv4) => buffer.copy_from_slice(&ipv4.octets()),
@@ -109,7 +115,7 @@ impl Nla for InfoIpTunnel {
109115
| Ipv6RdRelayPrefixLen(value) => {
110116
NativeEndian::write_u16(buffer, *value)
111117
}
112-
Protocol(value) => buffer[0] = i32::from(*value) as u8,
118+
Protocol(value) => buffer[0] = u8::from(*value),
113119
Ttl(value) | Tos(value) | EncapLimit(value) => buffer[0] = *value,
114120
PMtuDisc(value) | CollectMetada(value) => {
115121
buffer[0] = if *value { 1 } else { 0 }
@@ -128,7 +134,7 @@ impl Nla for InfoIpTunnel {
128134
Tos(_) => IFLA_IPTUN_TOS,
129135
EncapLimit(_) => IFLA_IPTUN_ENCAP_LIMIT,
130136
FlowInfo(_) => IFLA_IPTUN_FLOWINFO,
131-
Flags(_) => IFLA_IPTUN_FLAGS,
137+
Ipv6SitFlags(_) | Ipv4Flags(_) | Ipv6Flags(_) => IFLA_IPTUN_FLAGS,
132138
Protocol(_) => IFLA_IPTUN_PROTO,
133139
PMtuDisc(_) => IFLA_IPTUN_PMTUDISC,
134140
Ipv6RdPrefix(_) => IFLA_IPTUN_6RD_PREFIX,
@@ -146,45 +152,28 @@ impl Nla for InfoIpTunnel {
146152
}
147153
}
148154

149-
impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for InfoIpTunnel {
150-
fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
155+
impl<'a, T: AsRef<[u8]> + ?Sized>
156+
ParseableParametrized<NlaBuffer<&'a T>, super::InfoKind> for InfoIpTunnel
157+
{
158+
fn parse_with_param(
159+
buf: &NlaBuffer<&'a T>,
160+
kind: super::InfoKind,
161+
) -> Result<Self, DecodeError> {
151162
use self::InfoIpTunnel::*;
152163
let payload = buf.value();
153164
Ok(match buf.kind() {
154165
IFLA_IPTUN_LINK => Link(
155166
parse_u32(payload).context("invalid IFLA_IPTUN_LINK value")?,
156167
),
157168
IFLA_IPTUN_LOCAL => {
158-
if payload.len() == 4 {
159-
let mut data = [0u8; 4];
160-
data.copy_from_slice(&payload[0..4]);
161-
Self::Local(IpAddr::V4(Ipv4Addr::from(data)))
162-
} else if payload.len() == 16 {
163-
let mut data = [0u8; 16];
164-
data.copy_from_slice(&payload[0..16]);
165-
Self::Local(IpAddr::V6(Ipv6Addr::from(data)))
166-
} else {
167-
return Err(DecodeError::from(format!(
168-
"Invalid IFLA_IPTUN_LOCAL, got unexpected length of \
169-
IP address payload {payload:?}"
170-
)));
171-
}
169+
let ip = parse_ip_addr(payload)
170+
.context("invalid IFLA_IPTUN_LOCAL")?;
171+
Self::Local(ip)
172172
}
173173
IFLA_IPTUN_REMOTE => {
174-
if payload.len() == 4 {
175-
let mut data = [0u8; 4];
176-
data.copy_from_slice(&payload[0..4]);
177-
Self::Remote(IpAddr::V4(Ipv4Addr::from(data)))
178-
} else if payload.len() == 16 {
179-
let mut data = [0u8; 16];
180-
data.copy_from_slice(&payload[0..16]);
181-
Self::Remote(IpAddr::V6(Ipv6Addr::from(data)))
182-
} else {
183-
return Err(DecodeError::from(format!(
184-
"Invalid IFLA_IPTUN_REMOTE, got unexpected length of \
185-
IP address payload {payload:?}"
186-
)));
187-
}
174+
let ip = parse_ip_addr(payload)
175+
.context("invalid IFLA_IPTUN_REMOTE")?;
176+
Self::Remote(ip)
188177
}
189178
IFLA_IPTUN_TTL => {
190179
Ttl(parse_u8(payload)
@@ -202,12 +191,27 @@ impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for InfoIpTunnel {
202191
parse_u32(payload)
203192
.context("invalid IFLA_IPTUN_FLOWINFO value")?,
204193
),
205-
IFLA_IPTUN_FLAGS => Flags(TunnelFlags::from_bits_retain(
206-
parse_u32(payload).context("invalid IFLA_IPTUN_FLAGS value")?,
207-
)),
194+
IFLA_IPTUN_FLAGS => match kind {
195+
super::InfoKind::IpIp => InfoIpTunnel::Ipv4Flags(
196+
parse_u16(payload)
197+
.context("invalid IFLA_IPTUN_FLAGS for IPIP")?,
198+
),
199+
super::InfoKind::SitTun => InfoIpTunnel::Ipv6SitFlags(
200+
parse_u16(payload)
201+
.context("invalid IFLA_IPTUN_FLAGS for SIT")?,
202+
),
203+
super::InfoKind::Ip6Tnl => InfoIpTunnel::Ipv6Flags(
204+
parse_u32(payload)
205+
.context("invalid IFLA_IPTUN_FLAGS for IP6")?,
206+
),
207+
_ => {
208+
return Err(DecodeError::from(format!(
209+
"unsupported InfoKind for IFLA_IPTUN_FLAGS: {kind:?}"
210+
)));
211+
}
212+
},
208213
IFLA_IPTUN_PROTO => Protocol(IpProtocol::from(
209-
parse_u8(payload).context("invalid IFLA_IPTUN_PROTO value")?
210-
as i32,
214+
parse_u8(payload).context("invalid IFLA_IPTUN_PROTO value")?,
211215
)),
212216
IFLA_IPTUN_PMTUDISC => PMtuDisc(
213217
parse_u8(payload)
@@ -258,11 +262,11 @@ impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for InfoIpTunnel {
258262
))
259263
}
260264
IFLA_IPTUN_ENCAP_SPORT => EncapSPort(
261-
parse_u16(payload)
265+
parse_u16_be(payload)
262266
.context("invalid IFLA_IPTUN_ENCAP_SPORT value")?,
263267
),
264268
IFLA_IPTUN_ENCAP_DPORT => EncapDPort(
265-
parse_u16(payload)
269+
parse_u16_be(payload)
266270
.context("invalid IFLA_IPTUN_ENCAP_DPORT value")?,
267271
),
268272
IFLA_IPTUN_COLLECT_METADATA => CollectMetada(

src/link/tests/iptunnel.rs

Lines changed: 76 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
use std::net::{Ipv4Addr, Ipv6Addr};
44
use std::str::FromStr;
55

6-
use netlink_packet_utils::{Emitable, Parseable};
6+
use netlink_packet_utils::{nla::DefaultNla, Emitable, Parseable};
77

88
use crate::link::{
9-
InfoData, InfoIpTunnel, InfoKind, LinkAttribute, LinkFlags, LinkHeader,
10-
LinkInfo, LinkLayerType, LinkMessage, LinkMessageBuffer, TunnelEncapFlags,
11-
TunnelEncapType, TunnelFlags,
9+
InfoData, InfoIpTunnel, InfoKind, InfoSitTun, LinkAttribute, LinkFlags,
10+
LinkHeader, LinkInfo, LinkLayerType, LinkMessage, LinkMessageBuffer,
11+
TunnelEncapFlags, TunnelEncapType,
1212
};
1313

1414
use crate::{AddressFamily, IpProtocol};
@@ -124,7 +124,7 @@ fn test_iptunnel_ipip6_link_info() {
124124
InfoIpTunnel::Ttl(64),
125125
InfoIpTunnel::EncapLimit(4),
126126
InfoIpTunnel::FlowInfo(0),
127-
InfoIpTunnel::Flags(TunnelFlags::from_bits_retain(0x30000)),
127+
InfoIpTunnel::Ipv6Flags(0x30000),
128128
InfoIpTunnel::Protocol(IpProtocol::Ipip),
129129
InfoIpTunnel::FwMark(0),
130130
InfoIpTunnel::EncapType(TunnelEncapType::None),
@@ -193,7 +193,7 @@ fn test_iptunnel_ip6ip6_link_info() {
193193
InfoIpTunnel::Ttl(64),
194194
InfoIpTunnel::EncapLimit(4),
195195
InfoIpTunnel::FlowInfo(0),
196-
InfoIpTunnel::Flags(TunnelFlags::from_bits_retain(0x30000)),
196+
InfoIpTunnel::Ipv6Flags(0x30000),
197197
InfoIpTunnel::Protocol(IpProtocol::Ipv6),
198198
InfoIpTunnel::FwMark(0),
199199
InfoIpTunnel::EncapType(TunnelEncapType::None),
@@ -215,3 +215,73 @@ fn test_iptunnel_ip6ip6_link_info() {
215215

216216
assert_eq!(buf, raw);
217217
}
218+
219+
#[test]
220+
fn test_iptunnel_sit_link_info() {
221+
let raw: Vec<u8> = vec![
222+
0x00, 0x00, // AF_UNSPEC and reserved
223+
0x00, 0x03, // Link Layer Type IPTUNNEL (768)
224+
0x07, 0x00, 0x00, 0x00, // iface ifindex 7
225+
0x90, 0x00, 0x00, 0x00, // flags
226+
0x00, 0x00, 0x00, 0x00, // changed flags
227+
0xa4, 0x00, // length = 164
228+
0x12, 0x00, // IFLA_LINK_INFO (18)
229+
0x08, 0x00, 0x01, 0x00, b's', b'i', b't', 0x00, // "sit\0"
230+
0x98, 0x00, 0x02, 0x00, // IFLA_INFO_DATA nested
231+
0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00,
232+
0xc0, 0xa8, 0x7a, 0xb7, 0x08, 0x00, 0x03, 0x00, 0x0a, 0xff, 0xfe, 0x02,
233+
0x05, 0x00, 0x04, 0x00, 0x40, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00,
234+
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x00, 0x00,
235+
0x05, 0x00, 0x09, 0x00, 0x29, 0x00, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00,
236+
0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00,
237+
0x14, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
238+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0c, 0x00,
239+
0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00,
240+
0x06, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0f, 0x00,
241+
0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00,
242+
0x06, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x10, 0x00,
243+
0x00, 0x00, 0x00, 0x00,
244+
];
245+
246+
let expected = LinkMessage {
247+
header: LinkHeader {
248+
interface_family: AddressFamily::Unspec,
249+
index: 7,
250+
link_layer_type: LinkLayerType::Tunnel,
251+
flags: LinkFlags::Noarp | LinkFlags::Pointopoint,
252+
change_mask: LinkFlags::empty(),
253+
},
254+
attributes: vec![LinkAttribute::LinkInfo(vec![
255+
LinkInfo::Kind(InfoKind::SitTun),
256+
LinkInfo::Data(InfoData::SitTun(vec![
257+
InfoSitTun::Other(DefaultNla::new(1, vec![0, 0, 0, 0])),
258+
InfoSitTun::Other(DefaultNla::new(2, vec![192, 168, 122, 183])),
259+
InfoSitTun::Other(DefaultNla::new(3, vec![10, 255, 254, 2])),
260+
InfoSitTun::Other(DefaultNla::new(4, vec![64])),
261+
InfoSitTun::Other(DefaultNla::new(5, vec![0])),
262+
InfoSitTun::Other(DefaultNla::new(10, vec![1])),
263+
InfoSitTun::Other(DefaultNla::new(9, vec![41])),
264+
InfoSitTun::Other(DefaultNla::new(8, vec![0, 0])),
265+
InfoSitTun::Other(DefaultNla::new(20, vec![0, 0, 0, 0])),
266+
InfoSitTun::Other(DefaultNla::new(11, vec![0; 16])),
267+
InfoSitTun::Other(DefaultNla::new(12, vec![0, 0, 0, 0])),
268+
InfoSitTun::Other(DefaultNla::new(13, vec![0, 0])),
269+
InfoSitTun::Other(DefaultNla::new(14, vec![0, 0])),
270+
InfoSitTun::Other(DefaultNla::new(15, vec![0, 0])),
271+
InfoSitTun::Other(DefaultNla::new(17, vec![0, 0])),
272+
InfoSitTun::Other(DefaultNla::new(18, vec![0, 0])),
273+
InfoSitTun::Other(DefaultNla::new(16, vec![0, 0])),
274+
])),
275+
])],
276+
};
277+
278+
assert_eq!(
279+
expected,
280+
LinkMessage::parse(&LinkMessageBuffer::new(&raw)).unwrap()
281+
);
282+
283+
let mut buf = vec![0; expected.buffer_len()];
284+
expected.emit(&mut buf);
285+
286+
assert_eq!(buf, raw);
287+
}

0 commit comments

Comments
 (0)