Skip to content

Commit

Permalink
Add TTL
Browse files Browse the repository at this point in the history
  • Loading branch information
larseggert committed Nov 21, 2023
1 parent 119e912 commit 17d93b0
Show file tree
Hide file tree
Showing 18 changed files with 159 additions and 145 deletions.
5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,7 @@ members = [
]

[patch.crates-io]
nix = { git = "https://github.com/larseggert/nix.git", branch = "feat-tos" }
nix = { path = "./../nix" }
libc = { path = "./../libc" }
#libc = { git = "https://github.com/larseggert/libc.git", branch = "feat-ttl" }
#nix = { git = "https://github.com/larseggert/nix.git", branch = "feat-tos" }
20 changes: 13 additions & 7 deletions neqo-client/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use neqo_crypto::{
constants::{TLS_AES_128_GCM_SHA256, TLS_AES_256_GCM_SHA384, TLS_CHACHA20_POLY1305_SHA256},
init, AuthenticationStatus, Cipher, ResumptionToken,
};
use neqo_helper::{bind, emit_datagram, recv_datagram};
use neqo_http3::{
self, Error, Header, Http3Client, Http3ClientEvent, Http3Parameters, Http3State, Output,
Priority,
Expand All @@ -22,7 +23,6 @@ use neqo_transport::{
CongestionControlAlgorithm, Connection, ConnectionId, ConnectionParameters,
EmptyConnectionIdGenerator, Error as TransportError, StreamId, StreamType, Version,
};
use neqo_helper::{bind, emit_datagram, recv_datagram};

use std::{
cell::RefCell,
Expand All @@ -32,11 +32,12 @@ use std::{
fs::{create_dir_all, File, OpenOptions},
io::{self, ErrorKind, Write},
net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs, UdpSocket},
os::fd::AsRawFd,
path::PathBuf,
process::exit,
rc::Rc,
str::FromStr,
time::{Duration, Instant}, os::fd::AsRawFd,
time::{Duration, Instant},
};

use structopt::StructOpt;
Expand Down Expand Up @@ -415,7 +416,8 @@ fn process_loop(
}

let mut tos = 0;
match recv_datagram(socket.as_raw_fd(), &mut buf[..], &mut tos) {
let mut ttl = 0;
match recv_datagram(socket.as_raw_fd(), &mut buf[..], &mut tos, &mut ttl) {
Err(ref err)
if err.kind() == ErrorKind::WouldBlock || err.kind() == ErrorKind::Interrupted => {}
Err(err) => {
Expand All @@ -428,7 +430,8 @@ fn process_loop(
continue;
}
if sz > 0 {
let d = Datagram::new(remote, *local_addr, tos, &buf[..sz]);
let d =
Datagram::new_with_tos_and_ttl(remote, *local_addr, tos, ttl, &buf[..sz]);
client.process_input(d, Instant::now());
handler.maybe_key_update(client)?;
}
Expand Down Expand Up @@ -864,10 +867,11 @@ mod old {
fs::File,
io::{ErrorKind, Write},
net::{SocketAddr, UdpSocket},
os::fd::AsRawFd,
path::PathBuf,
process::exit,
rc::Rc,
time::Instant, os::fd::AsRawFd,
time::Instant,
};

use neqo_helper::recv_datagram;
Expand Down Expand Up @@ -1108,7 +1112,8 @@ mod old {
}

let mut tos = 0;
match recv_datagram(socket.as_raw_fd(), &mut buf[..], &mut tos) {
let mut ttl = 0;
match recv_datagram(socket.as_raw_fd(), &mut buf[..], &mut tos, &mut ttl) {
Err(err) => {
if err.kind() != ErrorKind::WouldBlock && err.kind() != ErrorKind::Interrupted {
eprintln!("UDP error: {}", err);
Expand All @@ -1121,7 +1126,8 @@ mod old {
continue;
}
if sz > 0 {
let d = Datagram::new(addr, *local_addr, tos, &buf[..sz]);
let d =
Datagram::new_with_tos_and_ttl(addr, *local_addr, tos, ttl, &buf[..sz]);
client.process_input(d, Instant::now());
handler.maybe_key_update(client)?;
}
Expand Down
37 changes: 24 additions & 13 deletions neqo-common/src/datagram.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,6 @@ pub enum IpTosEcn {
EcnCe = 0b11, // CE (Congestion Experienced) [RFC3168]
}

// impl From<IpTosEcn> for u8 {
// fn from(ecn: IpTosEcn) -> Self {
// ecn as u8
// }
// }

// DiffServ Codepoints, mapped to the upper six bits of the TOS field.
// https://www.iana.org/assignments/dscp-registry/dscp-registry.xhtml
// #[derive(Copy, Clone)]
Expand Down Expand Up @@ -55,26 +49,38 @@ pub enum IpTosDscp {
DscpLe = 0b0000_0100, // [RFC8622]
}

// impl From<IpTosDscp> for u8 {
// fn from(dscp: IpTosDscp) -> Self {
// (dscp as u8) << 2
// }
// }

#[derive(PartialEq, Eq, Clone)]
pub struct Datagram {
src: SocketAddr,
dst: SocketAddr,
tos: u8,
ttl: u8,
d: Vec<u8>,
}

impl Datagram {
pub fn new<V: Into<Vec<u8>>>(src: SocketAddr, dst: SocketAddr, tos: u8, d: V) -> Self {
pub fn new<V: Into<Vec<u8>>>(src: SocketAddr, dst: SocketAddr, d: V) -> Self {
Self {
src,
dst,
tos: IpTosEcn::EcnEct0 as u8,
ttl: 128,
d: d.into(),
}
}

pub fn new_with_tos_and_ttl<V: Into<Vec<u8>>>(
src: SocketAddr,
dst: SocketAddr,
tos: u8,
ttl: u8,
d: V,
) -> Self {
Self {
src,
dst,
tos,
ttl,
d: d.into(),
}
}
Expand All @@ -93,6 +99,11 @@ impl Datagram {
pub fn tos(&self) -> u8 {
self.tos
}

#[must_use]
pub fn ttl(&self) -> u8 {
self.ttl
}
}

impl Deref for Datagram {
Expand Down
44 changes: 32 additions & 12 deletions neqo-helper/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,18 @@ use nix::{
errno::Errno::{EAGAIN, EINTR},
sys::socket::{
recvmsg, sendmsg, setsockopt,
sockopt::{IpDontFrag, IpRecvTos, IpTos, Ipv6DontFrag, Ipv6RecvTClass, Ipv6TClass},
sockopt::{
IpDontFrag, IpRecvTos, IpRecvTtl, IpTos, IpTtl, Ipv6DontFrag, Ipv6HopLimit,
Ipv6RecvHopLimit, Ipv6RecvTClass, Ipv6TClass,
},
AddressFamily, ControlMessage, ControlMessageOwned, MsgFlags, SockaddrLike,
SockaddrStorage,
},
};

use neqo_common::{qdebug, Datagram};
use neqo_common::Datagram;

// Bind a UDPO socket and set some default socket options.
// Bind a UDP socket and set some default socket options.
pub fn bind(local_addr: SocketAddr) -> io::Result<UdpSocket> {
let socket = match UdpSocket::bind(local_addr) {
Err(e) => {
Expand All @@ -45,6 +48,13 @@ pub fn bind(local_addr: SocketAddr) -> io::Result<UdpSocket> {
SocketAddr::V6(..) => setsockopt(&s, Ipv6RecvTClass, &true),
};
assert!(res.is_ok());
// Request IPv4 time-to-live (TTL) and IPv6 hop count
// information for all incoming packets.
let res = match local_addr {
SocketAddr::V4(..) => setsockopt(&s, IpRecvTtl, &true),
SocketAddr::V6(..) => setsockopt(&s, Ipv6RecvHopLimit, &true),
};
assert!(res.is_ok());
s
}
};
Expand All @@ -58,22 +68,26 @@ fn to_sockaddr(addr: SocketAddr) -> SockaddrStorage {
pub fn emit_datagram(fd: i32, d: Datagram) -> io::Result<()> {
let iov = [IoSlice::new(&d[..])];
let tos = d.tos() as i32;
let cmsg = match d.destination() {
let ttl = d.ttl() as i32;
let cmsg_tos = match d.destination() {
SocketAddr::V4(..) => ControlMessage::IpTos(&tos),
SocketAddr::V6(..) => ControlMessage::Ipv6TClass(&tos),
};
let cmsg_ttl = match d.destination() {
SocketAddr::V4(..) => ControlMessage::IpTtl(&ttl),
SocketAddr::V6(..) => ControlMessage::Ipv6HopLimit(&ttl),
};
let sent = sendmsg(
fd,
&iov,
&[cmsg],
&[cmsg_tos, cmsg_ttl],
MsgFlags::empty(),
Some(&to_sockaddr(d.destination())),
)
.unwrap();
if sent != d.len() {
eprintln!("Unable to send all {} bytes of datagram", d.len());
}
qdebug!("TX TOS {:#04x}", tos);
Ok(())
}

Expand All @@ -99,9 +113,14 @@ fn to_socket_addr(addr: &SockaddrStorage) -> SocketAddr {
}
}

pub fn recv_datagram(fd: i32, buf: &mut [u8], tos: &mut u8) -> io::Result<(usize, SocketAddr)> {
pub fn recv_datagram(
fd: i32,
buf: &mut [u8],
tos: &mut u8,
ttl: &mut u8,
) -> io::Result<(usize, SocketAddr)> {
let mut iov = [IoSliceMut::new(buf)];
let mut cmsg = cmsg_space!(IpTos, Ipv6TClass);
let mut cmsg = cmsg_space!(IpTos, Ipv6TClass, IpTtl, Ipv6HopLimit);
let flags = MsgFlags::empty();

match recvmsg::<SockaddrStorage>(fd, &mut iov, Some(&mut cmsg), flags) {
Expand All @@ -113,13 +132,14 @@ pub fn recv_datagram(fd: i32, buf: &mut [u8], tos: &mut u8) -> io::Result<(usize
}
Ok(res) => {
for cmsg in res.cmsgs() {
*tos = match cmsg {
ControlMessageOwned::IpTos(t) => t,
ControlMessageOwned::Ipv6TClass(t) => t,
match cmsg {
ControlMessageOwned::IpTos(t) => *tos = t,
ControlMessageOwned::Ipv6TClass(t) => *tos = t,
ControlMessageOwned::IpTtl(t) => *ttl = t,
ControlMessageOwned::Ipv6HopLimit(t) => *ttl = t,
_ => todo!(),
};
}
qdebug!("RX TOS {:#04x}", tos);
Ok((res.bytes, to_socket_addr(&res.address.unwrap())))
}
}
Expand Down
32 changes: 27 additions & 5 deletions neqo-interop/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,9 @@ fn process_loop(
}

let mut tos = 0;
let (sz, _) = match recv_datagram(nctx.socket.as_raw_fd(), &mut buf[..], &mut tos) {
let mut ttl = 0;
let (sz, _) = match recv_datagram(nctx.socket.as_raw_fd(), &mut buf[..], &mut tos, &mut ttl)
{
Ok(sz) => sz,
Err(e) => {
return Err(String::from(match e.kind() {
Expand All @@ -147,7 +149,13 @@ fn process_loop(
continue;
}
if sz > 0 {
let received = Datagram::new(nctx.remote_addr, nctx.local_addr, tos, &buf[..sz]);
let received = Datagram::new_with_tos_and_ttl(
nctx.remote_addr,
nctx.local_addr,
tos,
ttl,
&buf[..sz],
);
client.process_input(received, Instant::now());
}
}
Expand Down Expand Up @@ -294,7 +302,9 @@ fn process_loop_h3(
}

let mut tos = 0;
let (sz, _) = match recv_datagram(nctx.socket.as_raw_fd(), &mut buf[..], &mut tos) {
let mut ttl = 0;
let (sz, _) = match recv_datagram(nctx.socket.as_raw_fd(), &mut buf[..], &mut tos, &mut ttl)
{
Ok(sz) => sz,
Err(e) => {
return Err(String::from(match e.kind() {
Expand All @@ -309,7 +319,13 @@ fn process_loop_h3(
continue;
}
if sz > 0 {
let received = Datagram::new(nctx.remote_addr, nctx.local_addr, tos, &buf[..sz]);
let received = Datagram::new_with_tos_and_ttl(
nctx.remote_addr,
nctx.local_addr,
tos,
ttl,
&buf[..sz],
);
handler.h3.process_input(received, Instant::now());
}
}
Expand Down Expand Up @@ -682,7 +698,13 @@ impl Handler for VnHandler {
fn rewrite_out(&mut self, d: &Datagram) -> Option<Datagram> {
let mut payload = d[..].to_vec();
payload[1] = 0x1a;
Some(Datagram::new(d.source(), d.destination(), d.tos(), payload))
Some(Datagram::new_with_tos_and_ttl(
d.source(),
d.destination(),
d.tos(),
d.ttl(),
payload,
))
}
}

Expand Down
Loading

0 comments on commit 17d93b0

Please sign in to comment.