mirror of
https://github.com/outbackdingo/firezone.git
synced 2026-01-27 10:18:54 +00:00
fix(eBPF): incorporate change in UDP payload into checksum (#8603)
The UDP checksum also includes the entire payload. Removing and adding bytes to the payload therefore needs to be reflected in the checksum update that we perform. When we add the channel data header, we need to add the bytes to the checksum and when we remove them, they need to be removed. Related: #7518
This commit is contained in:
@@ -42,6 +42,10 @@ impl<'a> ChannelData<'a> {
|
||||
pub fn number(&self) -> u16 {
|
||||
u16::from_be_bytes(self.inner.number)
|
||||
}
|
||||
|
||||
pub fn length(&self) -> u16 {
|
||||
u16::from_be_bytes(self.inner.length)
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
|
||||
@@ -154,6 +154,8 @@ fn try_handle_ipv4_channel_data_to_udp(ctx: &XdpContext, ipv4: Ip4, udp: Udp) ->
|
||||
port_and_peer.allocation_port(),
|
||||
port_and_peer.peer_port(),
|
||||
new_udp_len,
|
||||
cd.number(),
|
||||
cd.length(),
|
||||
);
|
||||
|
||||
remove_channel_data_header_ipv4(ctx)?;
|
||||
@@ -173,15 +175,21 @@ fn try_handle_ipv4_udp_to_channel_data(ctx: &XdpContext, ipv4: Ip4, udp: Udp) ->
|
||||
|
||||
let udp_len = udp.len();
|
||||
let new_udp_len = udp_len + CdHdr::LEN as u16;
|
||||
|
||||
let channel_number = client_and_channel.channel();
|
||||
let channel_data_length = udp_len - UdpHdr::LEN as u16;
|
||||
|
||||
udp.update(
|
||||
pseudo_header,
|
||||
3478,
|
||||
client_and_channel.client_port(),
|
||||
new_udp_len,
|
||||
channel_number,
|
||||
channel_data_length,
|
||||
);
|
||||
|
||||
let cd_num = client_and_channel.channel().to_be_bytes();
|
||||
let cd_len = (udp_len - UdpHdr::LEN as u16).to_be_bytes(); // The `length` field in the UDP header includes the header itself. For the channel-data field, we only want the length of the payload.
|
||||
let cd_num = channel_number.to_be_bytes();
|
||||
let cd_len = channel_data_length.to_be_bytes(); // The `length` field in the UDP header includes the header itself. For the channel-data field, we only want the length of the payload.
|
||||
|
||||
let channel_data_header = [cd_num[0], cd_num[1], cd_len[0], cd_len[1]];
|
||||
|
||||
@@ -239,15 +247,21 @@ fn try_handle_ipv6_udp_to_channel_data(ctx: &XdpContext, ipv6: Ip6, udp: Udp) ->
|
||||
|
||||
let udp_len = udp.len();
|
||||
let new_udp_len = udp_len + CdHdr::LEN as u16;
|
||||
|
||||
let channel_number = client_and_channel.channel();
|
||||
let channel_data_length = udp_len - UdpHdr::LEN as u16;
|
||||
|
||||
udp.update(
|
||||
pseudo_header,
|
||||
3478,
|
||||
client_and_channel.client_port(),
|
||||
new_udp_len,
|
||||
channel_number,
|
||||
channel_data_length,
|
||||
);
|
||||
|
||||
let cd_num = client_and_channel.channel().to_be_bytes();
|
||||
let cd_len = (udp_len - UdpHdr::LEN as u16).to_be_bytes(); // The `length` field in the UDP header includes the header itself. For the channel-data field, we only want the length of the payload.
|
||||
let cd_num = channel_number.to_be_bytes();
|
||||
let cd_len = channel_data_length.to_be_bytes(); // The `length` field in the UDP header includes the header itself. For the channel-data field, we only want the length of the payload.
|
||||
|
||||
let channel_data_header = [cd_num[0], cd_num[1], cd_len[0], cd_len[1]];
|
||||
|
||||
@@ -274,6 +288,8 @@ fn try_handle_ipv6_channel_data_to_udp(ctx: &XdpContext, ipv6: Ip6, udp: Udp) ->
|
||||
port_and_peer.allocation_port(),
|
||||
port_and_peer.peer_port(),
|
||||
new_udp_len,
|
||||
cd.number(),
|
||||
cd.length(),
|
||||
);
|
||||
|
||||
remove_channel_data_header_ipv6(ctx)?;
|
||||
|
||||
@@ -42,11 +42,23 @@ impl<'a> Udp<'a> {
|
||||
new_src: u16,
|
||||
new_dst: u16,
|
||||
new_len: u16,
|
||||
channel_number: u16,
|
||||
channel_data_len: u16,
|
||||
) {
|
||||
let src = self.src();
|
||||
let dst = self.dst();
|
||||
let len = self.len();
|
||||
|
||||
let payload_checksum_update = if new_len > len {
|
||||
ChecksumUpdate::default()
|
||||
.add_u16(channel_number)
|
||||
.add_u16(channel_data_len)
|
||||
} else {
|
||||
ChecksumUpdate::default()
|
||||
.remove_u16(channel_number)
|
||||
.remove_u16(channel_data_len)
|
||||
};
|
||||
|
||||
self.inner.source = new_src.to_be_bytes();
|
||||
self.inner.dest = new_dst.to_be_bytes();
|
||||
self.inner.len = new_len.to_be_bytes();
|
||||
@@ -56,6 +68,7 @@ impl<'a> Udp<'a> {
|
||||
if crate::config::udp_checksum_enabled() {
|
||||
self.inner.check = ChecksumUpdate::new(u16::from_be_bytes(self.inner.check))
|
||||
.add_update(ip_pseudo_header)
|
||||
.add_update(payload_checksum_update)
|
||||
.remove_u16(len)
|
||||
.add_u16(new_len)
|
||||
.remove_u16(src)
|
||||
|
||||
Reference in New Issue
Block a user