Skip to content

Commit

Permalink
recompute checksums for TCP & UDP
Browse files Browse the repository at this point in the history
  • Loading branch information
akiroz committed Jan 25, 2024
1 parent 52b6d6c commit 9e249f6
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 36 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "zika"
version = "3.3.1"
version = "3.3.2"
license = "MIT"
description = "IP Tunneling over MQTT"
repository = "https://github.com/akiroz/zika"
Expand Down
26 changes: 8 additions & 18 deletions src/client.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::io::{Cursor, Write};
use std::error::Error as StdError;
use std::net::Ipv4Addr;
use std::sync::Arc;

Expand All @@ -8,16 +8,17 @@ use futures::{SinkExt, stream::{SplitSink, StreamExt}};
use rand::{thread_rng, Rng, distributions::Standard};

use rumqttc;
use etherparse::Ipv4Header;
use ipnetwork::Ipv4Network;
use tokio::{task, sync::{broadcast, Mutex}};
use tokio_util::codec::Framed;
use tun::{AsyncDevice, TunPacket, TunPacketCodec};

use crate::nat;
use crate::config;
use crate::remote;
use crate::ip_iter::SizedIpv4NetworkIterator;


type TunSink = SplitSink<Framed<AsyncDevice, TunPacketCodec>, TunPacket>;

pub struct Client {
Expand Down Expand Up @@ -165,25 +166,14 @@ impl Client {
}

// mqtt -> tun
async fn handle_remote_message(&self, tun_sink: &mut TunSink, topic: &str, msg: &[u8]) -> Result<bool, etherparse::WriteError> {
async fn handle_remote_message(&self, tun_sink: &mut TunSink, topic: &str, msg: &[u8]) -> Result<bool, Box<dyn StdError>> {
if let Some(tunnel) = self.tunnels.iter().find(|&t| t.topic == topic) {
match Ipv4Header::from_slice(&msg) {
Err(error) => {
log::debug!("packet parse failed {:?}", error);
Ok(false)
}
Ok((mut ipv4_header, rest)) => {
ipv4_header.source = tunnel.bind_addr.octets();
ipv4_header.destination = self.local_addr.octets();
let mut cursor = Cursor::new(Vec::new());
ipv4_header.write(&mut cursor)?;
cursor.write_all(rest)?;
tun_sink.send(TunPacket::new(cursor.into_inner())).await?;
Ok(true)
}
}
let pkt = nat::do_nat(msg, tunnel.bind_addr, self.local_addr)?;
tun_sink.send(TunPacket::new(pkt)).await?;
Ok(true)
} else {
Ok(false)
}
}

}
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ pub mod server;
pub mod config;

// Utils
pub mod nat;
pub mod ip_iter;
pub mod lookup_pool;


mod remote;

31 changes: 31 additions & 0 deletions src/nat.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use std::error::Error as StdError;
use std::io::{Cursor, Write as _};
use std::net::Ipv4Addr;
use etherparse::{Ipv4Header, TcpHeader, UdpHeader};

pub fn do_nat(pkt: &[u8], src: Ipv4Addr, dst: Ipv4Addr) -> Result<Vec<u8>, Box<dyn StdError>> {
let mut cursor = Cursor::new(Vec::with_capacity(pkt.len()));

// NOTE: IPv6 not supported currently
let (mut ip_hdr, ip_body) = Ipv4Header::from_slice(&pkt)?;
ip_hdr.source = src.octets();
ip_hdr.destination = dst.octets();
// NOTE: write method calculates checksum automatically
ip_hdr.write(&mut cursor)?;

if ip_hdr.protocol == 6 { // TCP
let (mut tcp_hdr, tcp_body) = TcpHeader::from_slice(ip_body)?;
tcp_hdr.checksum = tcp_hdr.calc_checksum_ipv4(&ip_hdr, tcp_body)?;
tcp_hdr.write(&mut cursor)?;
cursor.write_all(tcp_body)?;
} else if ip_hdr.protocol == 17 { // UDP
let (mut udp_hdr, udp_body) = UdpHeader::from_slice(ip_body)?;
udp_hdr.checksum = udp_hdr.calc_checksum_ipv4(&ip_hdr, udp_body)?;
udp_hdr.write(&mut cursor)?;
cursor.write_all(udp_body)?;
} else {
cursor.write_all(ip_body)?;
}

Ok(cursor.into_inner())
}
20 changes: 4 additions & 16 deletions src/server.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::io::{Cursor, Write};
use std::error::Error as StdError;
use std::net::Ipv4Addr;
use std::sync::Arc;

Expand All @@ -11,6 +11,7 @@ use tokio::{task, sync::Mutex};
use tokio_util::codec::Framed;
use tun::{AsyncDevice, TunPacket, TunPacketCodec};

use crate::nat;
use crate::config;
use crate::remote;
use crate::ip_iter::SizedIpv4NetworkIterator;
Expand Down Expand Up @@ -117,7 +118,7 @@ impl Server {
}

// mqtt -> tun
async fn handle_remote_message(&self, tun_sink: &mut TunSink, id: &[u8], msg: &[u8]) -> Result<(), etherparse::WriteError> {
async fn handle_remote_message(&self, tun_sink: &mut TunSink, id: &[u8], msg: &[u8]) -> Result<(), Box<dyn StdError>> {
let base64_id = general_purpose::URL_SAFE_NO_PAD.encode(id);
let topic_base = &self.topic;
let topic = format!("{topic_base}/{base64_id}");
Expand All @@ -126,20 +127,7 @@ impl Server {
let ip = ip_pool.get_forward(&topic).into();
ip
};
let pkt = match Ipv4Header::from_slice(msg) {
Err(error) => {
log::debug!("packet parse failed {:?}", error);
msg.to_vec()
}
Ok((mut ipv4_header, rest)) => {
ipv4_header.source = ip.octets();
ipv4_header.destination = self.local_addr.octets();
let mut cursor = Cursor::new(Vec::new());
ipv4_header.write(&mut cursor)?;
cursor.write_all(rest)?;
cursor.into_inner()
}
};
let pkt = nat::do_nat(msg, ip, self.local_addr)?;
tun_sink.send(TunPacket::new(pkt)).await?;
Ok(())
}
Expand Down

0 comments on commit 9e249f6

Please sign in to comment.