Skip to content

Commit 5b9a3a8

Browse files
fixup! iptunnel: add support to ipip, ipip6 and ip6ip6 tunnels
1 parent 27d9f7d commit 5b9a3a8

File tree

3 files changed

+129
-53
lines changed

3 files changed

+129
-53
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: 50 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
// B
22
// SPDX-License-Identifier: MIT
33

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

66
use anyhow::Context;
77
use byteorder::{ByteOrder, NativeEndian};
88
use netlink_packet_utils::{
99
nla::{DefaultNla, Nla, NlaBuffer},
1010
parsers::{parse_u16, parse_u32, parse_u8},
11-
traits::Parseable,
11+
traits::{Parseable, ParseableParametrized},
1212
DecodeError,
1313
};
1414

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

1717
const IFLA_IPTUN_LINK: u16 = 1;
1818
const IFLA_IPTUN_LOCAL: u16 = 2;
@@ -45,7 +45,9 @@ pub enum InfoIpTunnel {
4545
Tos(u8),
4646
EncapLimit(u8),
4747
FlowInfo(u32),
48-
Flags(TunnelFlags),
48+
Ipv6SitFlags(u16),
49+
Ipv4Flags(u16),
50+
Ipv6Flags(u32),
4951
Protocol(IpProtocol),
5052
PMtuDisc(bool),
5153
Ipv6RdPrefix(Ipv6Addr),
@@ -70,8 +72,10 @@ impl Nla for InfoIpTunnel {
7072
IpAddr::V4(_) => 4,
7173
IpAddr::V6(_) => 16,
7274
},
73-
Link(_) | FwMark(_) | FlowInfo(_) | Flags(_) => 4,
74-
EncapType(_)
75+
Link(_) | FwMark(_) | FlowInfo(_) | Ipv6Flags(_) => 4,
76+
Ipv6SitFlags(_)
77+
| Ipv4Flags(_)
78+
| EncapType(_)
7579
| EncapFlags(_)
7680
| EncapSPort(_)
7781
| EncapDPort(_)
@@ -92,8 +96,11 @@ impl Nla for InfoIpTunnel {
9296
Link(value) | FwMark(value) | FlowInfo(value) => {
9397
NativeEndian::write_u32(buffer, *value)
9498
}
95-
Flags(f) => {
96-
NativeEndian::write_u32(buffer, f.bits());
99+
Ipv6Flags(val) => {
100+
NativeEndian::write_u32(buffer, *val);
101+
}
102+
Ipv6SitFlags(val) | Ipv4Flags(val) => {
103+
NativeEndian::write_u16(buffer, *val);
97104
}
98105
Local(value) | Remote(value) => match value {
99106
IpAddr::V4(ipv4) => buffer.copy_from_slice(&ipv4.octets()),
@@ -109,7 +116,7 @@ impl Nla for InfoIpTunnel {
109116
| Ipv6RdRelayPrefixLen(value) => {
110117
NativeEndian::write_u16(buffer, *value)
111118
}
112-
Protocol(value) => buffer[0] = i32::from(*value) as u8,
119+
Protocol(value) => buffer[0] = u8::from(*value),
113120
Ttl(value) | Tos(value) | EncapLimit(value) => buffer[0] = *value,
114121
PMtuDisc(value) | CollectMetada(value) => {
115122
buffer[0] = if *value { 1 } else { 0 }
@@ -128,7 +135,7 @@ impl Nla for InfoIpTunnel {
128135
Tos(_) => IFLA_IPTUN_TOS,
129136
EncapLimit(_) => IFLA_IPTUN_ENCAP_LIMIT,
130137
FlowInfo(_) => IFLA_IPTUN_FLOWINFO,
131-
Flags(_) => IFLA_IPTUN_FLAGS,
138+
Ipv6SitFlags(_) | Ipv4Flags(_) | Ipv6Flags(_) => IFLA_IPTUN_FLAGS,
132139
Protocol(_) => IFLA_IPTUN_PROTO,
133140
PMtuDisc(_) => IFLA_IPTUN_PMTUDISC,
134141
Ipv6RdPrefix(_) => IFLA_IPTUN_6RD_PREFIX,
@@ -146,45 +153,28 @@ impl Nla for InfoIpTunnel {
146153
}
147154
}
148155

149-
impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for InfoIpTunnel {
150-
fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
156+
impl<'a, T: AsRef<[u8]> + ?Sized>
157+
ParseableParametrized<NlaBuffer<&'a T>, super::InfoKind> for InfoIpTunnel
158+
{
159+
fn parse_with_param(
160+
buf: &NlaBuffer<&'a T>,
161+
kind: super::InfoKind,
162+
) -> Result<Self, DecodeError> {
151163
use self::InfoIpTunnel::*;
152164
let payload = buf.value();
153165
Ok(match buf.kind() {
154166
IFLA_IPTUN_LINK => Link(
155167
parse_u32(payload).context("invalid IFLA_IPTUN_LINK value")?,
156168
),
157169
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-
}
170+
let ip = parse_ip_addr(payload)
171+
.context("invalid IFLA_IPTUN_LOCAL")?;
172+
Self::Local(ip)
172173
}
173174
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-
}
175+
let ip = parse_ip_addr(payload)
176+
.context("invalid IFLA_IPTUN_REMOTE")?;
177+
Self::Remote(ip)
188178
}
189179
IFLA_IPTUN_TTL => {
190180
Ttl(parse_u8(payload)
@@ -202,12 +192,27 @@ impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for InfoIpTunnel {
202192
parse_u32(payload)
203193
.context("invalid IFLA_IPTUN_FLOWINFO value")?,
204194
),
205-
IFLA_IPTUN_FLAGS => Flags(TunnelFlags::from_bits_retain(
206-
parse_u32(payload).context("invalid IFLA_IPTUN_FLAGS value")?,
207-
)),
195+
IFLA_IPTUN_FLAGS => match kind {
196+
super::InfoKind::IpIp => InfoIpTunnel::Ipv4Flags(
197+
parse_u16(payload)
198+
.context("invalid IFLA_IPTUN_FLAGS for IPIP")?,
199+
),
200+
super::InfoKind::SitTun => InfoIpTunnel::Ipv6SitFlags(
201+
parse_u16(payload)
202+
.context("invalid IFLA_IPTUN_FLAGS for SIT")?,
203+
),
204+
super::InfoKind::Ip6Tnl => InfoIpTunnel::Ipv6Flags(
205+
parse_u32(payload)
206+
.context("invalid IFLA_IPTUN_FLAGS for IP6")?,
207+
),
208+
_ => {
209+
return Err(DecodeError::from(format!(
210+
"unsupported InfoKind for IFLA_IPTUN_FLAGS: {kind:?}"
211+
)));
212+
}
213+
},
208214
IFLA_IPTUN_PROTO => Protocol(IpProtocol::from(
209-
parse_u8(payload).context("invalid IFLA_IPTUN_PROTO value")?
210-
as i32,
215+
parse_u8(payload).context("invalid IFLA_IPTUN_PROTO value")?,
211216
)),
212217
IFLA_IPTUN_PMTUDISC => PMtuDisc(
213218
parse_u8(payload)

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)