Skip to content

Commit 055b9c5

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

File tree

3 files changed

+148
-75
lines changed

3 files changed

+148
-75
lines changed

src/link/link_info/info_data.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ 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::{
1111
InfoBond, InfoBridge, InfoGeneve, InfoGreTap, InfoGreTap6, InfoGreTun,
1212
InfoGreTun6, InfoGtp, InfoHsr, InfoIpTunnel, InfoIpVlan, InfoIpVtap,
13-
InfoIpoib, InfoKind, InfoMacSec, InfoMacVlan, InfoMacVtap, InfoSitTun,
14-
InfoTun, InfoVeth, InfoVlan, InfoVrf, InfoVti, InfoVxlan, InfoXfrm,
13+
InfoIpoib, InfoKind, InfoMacSec, InfoMacVlan, InfoMacVtap, InfoTun,
14+
InfoVeth, InfoVlan, InfoVrf, InfoVti, InfoVxlan, InfoXfrm,
1515
};
1616

1717
const IFLA_INFO_DATA: u16 = 2;
@@ -31,7 +31,7 @@ pub enum InfoData {
3131
MacVtap(Vec<InfoMacVtap>),
3232
GreTap(Vec<InfoGreTap>),
3333
GreTap6(Vec<InfoGreTap6>),
34-
SitTun(Vec<InfoSitTun>),
34+
SitTun(Vec<InfoIpTunnel>),
3535
GreTun(Vec<InfoGreTun>),
3636
GreTun6(Vec<InfoGreTun6>),
3737
Vti(Vec<InfoVti>),
@@ -252,7 +252,8 @@ impl InfoData {
252252
let nla = &nla.context(format!(
253253
"invalid IFLA_INFO_DATA for {kind} {payload:?}"
254254
))?;
255-
let parsed = InfoSitTun::parse(nla)?;
255+
let parsed =
256+
InfoIpTunnel::parse_with_param(nla, kind.clone())?;
256257
v.push(parsed);
257258
}
258259
InfoData::SitTun(v)
@@ -362,7 +363,8 @@ impl InfoData {
362363
let nla = &nla.context(format!(
363364
"invalid IFLA_INFO_DATA for {kind} {payload:?}"
364365
))?;
365-
let parsed = InfoIpTunnel::parse(nla)?;
366+
let parsed =
367+
InfoIpTunnel::parse_with_param(nla, kind.clone())?;
366368
v.push(parsed);
367369
}
368370
InfoData::IpTunnel(v)

src/link/link_info/iptunnel.rs

Lines changed: 58 additions & 54 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;
7-
use byteorder::{ByteOrder, NativeEndian};
6+
use byteorder::{BigEndian, 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+
BigEndian::write_u16(buffer, *val);
97103
}
98104
Local(value) | Remote(value) => match value {
99105
IpAddr::V4(ipv4) => buffer.copy_from_slice(&ipv4.octets()),
@@ -103,13 +109,13 @@ impl Nla for InfoIpTunnel {
103109
NativeEndian::write_u16(buffer, (*value).into())
104110
}
105111
EncapFlags(f) => NativeEndian::write_u16(buffer, f.bits()),
106-
EncapSPort(value)
107-
| EncapDPort(value)
108-
| Ipv6RdPrefixLen(value)
109-
| Ipv6RdRelayPrefixLen(value) => {
112+
EncapSPort(value) | EncapDPort(value) => {
113+
BigEndian::write_u16(buffer, *value)
114+
}
115+
Ipv6RdPrefixLen(value) | 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_be(payload)
197+
.context("invalid IFLA_IPTUN_FLAGS for IPIP")?,
198+
),
199+
super::InfoKind::SitTun => InfoIpTunnel::Ipv6SitFlags(
200+
parse_u16_be(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: 82 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use netlink_packet_utils::{Emitable, Parseable};
88
use crate::link::{
99
InfoData, InfoIpTunnel, InfoKind, LinkAttribute, LinkFlags, LinkHeader,
1010
LinkInfo, LinkLayerType, LinkMessage, LinkMessageBuffer, TunnelEncapFlags,
11-
TunnelEncapType, TunnelFlags,
11+
TunnelEncapType,
1212
};
1313

1414
use crate::{AddressFamily, IpProtocol};
@@ -30,8 +30,8 @@ fn test_iptunnel_ipip_link_info() {
3030
0x05, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x09, 0x00,
3131
0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x00, 0x00,
3232
0x08, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0f, 0x00,
33-
0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00,
34-
0x06, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x10, 0x00,
33+
0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x11, 0x00, 0x00, 0x0a, 0x00, 0x00,
34+
0x06, 0x00, 0x12, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x06, 0x00, 0x10, 0x00,
3535
0x00, 0x00, 0x00, 0x00, // data
3636
];
3737

@@ -59,8 +59,8 @@ fn test_iptunnel_ipip_link_info() {
5959
InfoIpTunnel::PMtuDisc(true),
6060
InfoIpTunnel::FwMark(0),
6161
InfoIpTunnel::EncapType(TunnelEncapType::None),
62-
InfoIpTunnel::EncapSPort(0),
63-
InfoIpTunnel::EncapDPort(0),
62+
InfoIpTunnel::EncapSPort(10),
63+
InfoIpTunnel::EncapDPort(12),
6464
InfoIpTunnel::EncapFlags(TunnelEncapFlags::from_bits_retain(0)),
6565
])),
6666
])],
@@ -98,8 +98,8 @@ fn test_iptunnel_ipip6_link_info() {
9898
0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00,
9999
0x05, 0x00, 0x09, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x14, 0x00,
100100
0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
101-
0x06, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x12, 0x00,
102-
0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
101+
0x06, 0x00, 0x11, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x06, 0x00, 0x12, 0x00,
102+
0x00, 0x0c, 0x00, 0x00, 0x06, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
103103
0x00, //data
104104
];
105105

@@ -124,12 +124,12 @@ 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),
131-
InfoIpTunnel::EncapSPort(0),
132-
InfoIpTunnel::EncapDPort(0),
131+
InfoIpTunnel::EncapSPort(10),
132+
InfoIpTunnel::EncapDPort(12),
133133
InfoIpTunnel::EncapFlags(TunnelEncapFlags::from_bits_retain(0)),
134134
])),
135135
])],
@@ -167,8 +167,8 @@ fn test_iptunnel_ip6ip6_link_info() {
167167
0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00,
168168
0x05, 0x00, 0x09, 0x00, 0x29, 0x00, 0x00, 0x00, 0x08, 0x00, 0x14, 0x00,
169169
0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
170-
0x06, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x12, 0x00,
171-
0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
170+
0x06, 0x00, 0x11, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x06, 0x00, 0x12, 0x00,
171+
0x00, 0x0c, 0x00, 0x00, 0x06, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
172172
0x00, // data
173173
];
174174

@@ -193,12 +193,12 @@ 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),
200-
InfoIpTunnel::EncapSPort(0),
201-
InfoIpTunnel::EncapDPort(0),
200+
InfoIpTunnel::EncapSPort(10),
201+
InfoIpTunnel::EncapDPort(12),
202202
InfoIpTunnel::EncapFlags(TunnelEncapFlags::from_bits_retain(0)),
203203
])),
204204
])],
@@ -215,3 +215,70 @@ 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, reserved
223+
0x00, 0x03, // LL type = IPTUNNEL (768)
224+
0x07, 0x00, 0x00, 0x00, // ifindex = 7
225+
0x90, 0x00, 0x00, 0x00, // flags = NoARP|POINTOPOINT
226+
0x00, 0x00, 0x00, 0x00, // change_mask = 0
227+
// --- IFLA_LINK_INFO NLA (len=0x78, type=18) ---
228+
0x78, 0x00, 0x12, 0x00,
229+
// IFLA_INFO_KIND = "sit\0" (len=8, type=1)
230+
0x08, 0x00, 0x01, 0x00, b's', b'i', b't', 0x00, 0x6c, 0x00, 0x02, 0x00,
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+
0x06, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x11, 0x00,
238+
0x00, 0x0a, 0x00, 0x00, 0x06, 0x00, 0x12, 0x00, 0x00, 0x0c, 0x00, 0x00,
239+
0x06, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
240+
];
241+
242+
let expected = LinkMessage {
243+
header: LinkHeader {
244+
interface_family: AddressFamily::Unspec,
245+
index: 7,
246+
link_layer_type: LinkLayerType::Tunnel,
247+
flags: LinkFlags::Noarp | LinkFlags::Pointopoint,
248+
change_mask: LinkFlags::empty(),
249+
},
250+
attributes: vec![LinkAttribute::LinkInfo(vec![
251+
LinkInfo::Kind(InfoKind::SitTun),
252+
LinkInfo::Data(InfoData::SitTun(vec![
253+
InfoIpTunnel::Link(0),
254+
InfoIpTunnel::Local(std::net::IpAddr::V4(
255+
Ipv4Addr::from_str("192.168.122.183").unwrap(),
256+
)),
257+
InfoIpTunnel::Remote(std::net::IpAddr::V4(
258+
Ipv4Addr::from_str("10.255.254.2").unwrap(),
259+
)),
260+
InfoIpTunnel::Ttl(64),
261+
InfoIpTunnel::Tos(0),
262+
InfoIpTunnel::PMtuDisc(true),
263+
InfoIpTunnel::Protocol(IpProtocol::Ipv6),
264+
InfoIpTunnel::Ipv6SitFlags(0),
265+
InfoIpTunnel::FwMark(0),
266+
InfoIpTunnel::EncapType(TunnelEncapType::None),
267+
InfoIpTunnel::EncapSPort(10),
268+
InfoIpTunnel::EncapDPort(12),
269+
InfoIpTunnel::EncapFlags(TunnelEncapFlags::empty()),
270+
])),
271+
])],
272+
};
273+
274+
assert_eq!(
275+
expected,
276+
LinkMessage::parse(&LinkMessageBuffer::new(&raw)).unwrap()
277+
);
278+
279+
let mut buf = vec![0; expected.buffer_len()];
280+
281+
expected.emit(&mut buf);
282+
283+
assert_eq!(buf, raw);
284+
}

0 commit comments

Comments
 (0)