mirror of
https://github.com/jmcorgan/fips.git
synced 2026-08-09 00:04:54 +00:00
Add rustfmt formatting policy and reformat codebase
Add rustfmt.toml with stable defaults and apply cargo fmt to all source files. This establishes a consistent formatting baseline for CI enforcement.
This commit is contained in:
+45
-49
@@ -12,8 +12,8 @@
|
||||
|
||||
use crate::upper::hosts::{HostMap, HostMapReloader};
|
||||
use crate::{NodeAddr, PeerIdentity};
|
||||
use simple_dns::rdata::{RData, AAAA};
|
||||
use simple_dns::{Packet, Name, ResourceRecord, CLASS, RCODE, PacketFlag, QTYPE, TYPE};
|
||||
use simple_dns::rdata::{AAAA, RData};
|
||||
use simple_dns::{CLASS, Name, Packet, PacketFlag, QTYPE, RCODE, ResourceRecord, TYPE};
|
||||
use std::net::Ipv6Addr;
|
||||
use tracing::{debug, warn};
|
||||
|
||||
@@ -109,16 +109,10 @@ pub fn handle_dns_packet(
|
||||
let mut response = query.into_reply();
|
||||
response.set_flags(PacketFlag::AUTHORITATIVE_ANSWER);
|
||||
|
||||
if is_aaaa
|
||||
&& let Some((ipv6, node_addr, pubkey)) = resolve_fips_query_with_hosts(&qname, hosts)
|
||||
if is_aaaa && let Some((ipv6, node_addr, pubkey)) = resolve_fips_query_with_hosts(&qname, hosts)
|
||||
{
|
||||
let name = Name::new_unchecked(&qname).into_owned();
|
||||
let record = ResourceRecord::new(
|
||||
name,
|
||||
CLASS::IN,
|
||||
ttl,
|
||||
RData::AAAA(AAAA::from(ipv6)),
|
||||
);
|
||||
let record = ResourceRecord::new(name, CLASS::IN, ttl, RData::AAAA(AAAA::from(ipv6)));
|
||||
response.answers.push(record);
|
||||
|
||||
let identity = DnsResolvedIdentity { node_addr, pubkey };
|
||||
@@ -359,7 +353,10 @@ mod tests {
|
||||
assert!(result.is_some(), "should handle hostname AAAA query");
|
||||
|
||||
let (response_bytes, identity_opt) = result.unwrap();
|
||||
assert!(identity_opt.is_some(), "should produce identity for hostname");
|
||||
assert!(
|
||||
identity_opt.is_some(),
|
||||
"should produce identity for hostname"
|
||||
);
|
||||
|
||||
let response = Packet::parse(&response_bytes).unwrap();
|
||||
assert_eq!(response.answers.len(), 1);
|
||||
@@ -380,7 +377,10 @@ mod tests {
|
||||
assert!(result.is_some());
|
||||
|
||||
let (response_bytes, identity_opt) = result.unwrap();
|
||||
assert!(identity_opt.is_none(), "should not produce identity for unknown");
|
||||
assert!(
|
||||
identity_opt.is_none(),
|
||||
"should not produce identity for unknown"
|
||||
);
|
||||
|
||||
let response = Packet::parse(&response_bytes).unwrap();
|
||||
assert_eq!(response.rcode(), RCODE::NameError);
|
||||
@@ -426,12 +426,8 @@ mod tests {
|
||||
let (identity_tx, mut identity_rx) = tokio::sync::mpsc::channel(16);
|
||||
|
||||
// Spawn the responder
|
||||
let responder_handle = tokio::spawn(run_dns_responder(
|
||||
server_socket,
|
||||
identity_tx,
|
||||
300,
|
||||
reloader,
|
||||
));
|
||||
let responder_handle =
|
||||
tokio::spawn(run_dns_responder(server_socket, identity_tx, 300, reloader));
|
||||
|
||||
// Send a query
|
||||
let client_socket = tokio::net::UdpSocket::bind("127.0.0.1:0").await.unwrap();
|
||||
@@ -457,13 +453,10 @@ mod tests {
|
||||
}
|
||||
|
||||
// Verify identity was sent through channel
|
||||
let resolved = tokio::time::timeout(
|
||||
std::time::Duration::from_secs(1),
|
||||
identity_rx.recv(),
|
||||
)
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
let resolved = tokio::time::timeout(std::time::Duration::from_secs(1), identity_rx.recv())
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
assert_eq!(resolved.node_addr, *identity.node_addr());
|
||||
|
||||
responder_handle.abort();
|
||||
@@ -486,12 +479,8 @@ mod tests {
|
||||
|
||||
let (identity_tx, mut identity_rx) = tokio::sync::mpsc::channel(16);
|
||||
|
||||
let responder_handle = tokio::spawn(run_dns_responder(
|
||||
server_socket,
|
||||
identity_tx,
|
||||
300,
|
||||
reloader,
|
||||
));
|
||||
let responder_handle =
|
||||
tokio::spawn(run_dns_responder(server_socket, identity_tx, 300, reloader));
|
||||
|
||||
// Query by hostname instead of npub
|
||||
let client_socket = tokio::net::UdpSocket::bind("127.0.0.1:0").await.unwrap();
|
||||
@@ -516,13 +505,10 @@ mod tests {
|
||||
}
|
||||
|
||||
// Verify identity registration
|
||||
let resolved = tokio::time::timeout(
|
||||
std::time::Duration::from_secs(1),
|
||||
identity_rx.recv(),
|
||||
)
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
let resolved = tokio::time::timeout(std::time::Duration::from_secs(1), identity_rx.recv())
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
assert_eq!(resolved.node_addr, *identity.node_addr());
|
||||
|
||||
responder_handle.abort();
|
||||
@@ -545,12 +531,8 @@ mod tests {
|
||||
let server_addr = server_socket.local_addr().unwrap();
|
||||
let (identity_tx, _identity_rx) = tokio::sync::mpsc::channel(16);
|
||||
|
||||
let responder_handle = tokio::spawn(run_dns_responder(
|
||||
server_socket,
|
||||
identity_tx,
|
||||
300,
|
||||
reloader,
|
||||
));
|
||||
let responder_handle =
|
||||
tokio::spawn(run_dns_responder(server_socket, identity_tx, 300, reloader));
|
||||
|
||||
let client_socket = tokio::net::UdpSocket::bind("127.0.0.1:0").await.unwrap();
|
||||
|
||||
@@ -561,16 +543,23 @@ mod tests {
|
||||
let (len, _) = tokio::time::timeout(
|
||||
std::time::Duration::from_secs(2),
|
||||
client_socket.recv_from(&mut buf),
|
||||
).await.unwrap().unwrap();
|
||||
)
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
let response = Packet::parse(&buf[..len]).unwrap();
|
||||
assert!(response.answers.is_empty(), "server2 should not resolve before reload");
|
||||
assert!(
|
||||
response.answers.is_empty(),
|
||||
"server2 should not resolve before reload"
|
||||
);
|
||||
|
||||
// Update the hosts file to add server2
|
||||
std::thread::sleep(std::time::Duration::from_millis(50));
|
||||
std::fs::write(
|
||||
&hosts_path,
|
||||
format!("gateway {}\nserver2 {}\n", id1.npub(), id2.npub()),
|
||||
).unwrap();
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Next query should trigger reload — query server2 again
|
||||
let query = build_test_query("server2.fips", TYPE::AAAA);
|
||||
@@ -578,9 +567,16 @@ mod tests {
|
||||
let (len, _) = tokio::time::timeout(
|
||||
std::time::Duration::from_secs(2),
|
||||
client_socket.recv_from(&mut buf),
|
||||
).await.unwrap().unwrap();
|
||||
)
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
let response = Packet::parse(&buf[..len]).unwrap();
|
||||
assert_eq!(response.answers.len(), 1, "server2 should resolve after reload");
|
||||
assert_eq!(
|
||||
response.answers.len(),
|
||||
1,
|
||||
"server2 should resolve after reload"
|
||||
);
|
||||
if let RData::AAAA(aaaa) = &response.answers[0].rdata {
|
||||
assert_eq!(Ipv6Addr::from(aaaa.address), expected_ipv6_2);
|
||||
} else {
|
||||
|
||||
+16
-8
@@ -80,7 +80,9 @@ impl HostMap {
|
||||
|
||||
/// Look up the npub for a hostname (case-insensitive).
|
||||
pub fn lookup_npub(&self, hostname: &str) -> Option<&str> {
|
||||
self.by_name.get(&hostname.to_ascii_lowercase()).map(|s| s.as_str())
|
||||
self.by_name
|
||||
.get(&hostname.to_ascii_lowercase())
|
||||
.map(|s| s.as_str())
|
||||
}
|
||||
|
||||
/// Look up the hostname for a NodeAddr (reverse lookup for display).
|
||||
@@ -279,7 +281,9 @@ pub fn validate_hostname(hostname: &str) -> Result<(), HostMapError> {
|
||||
}
|
||||
|
||||
if hostname.to_ascii_lowercase().starts_with("npub1") {
|
||||
return Err(err("must not start with 'npub1' (ambiguous with npub resolution)"));
|
||||
return Err(err(
|
||||
"must not start with 'npub1' (ambiguous with npub resolution)",
|
||||
));
|
||||
}
|
||||
|
||||
if hostname.starts_with('-') {
|
||||
@@ -338,7 +342,10 @@ mod tests {
|
||||
("NPUB1bar", "npub1 prefix case"),
|
||||
];
|
||||
for (h, desc) in cases {
|
||||
assert!(validate_hostname(h).is_err(), "should be invalid ({desc}): {h}");
|
||||
assert!(
|
||||
validate_hostname(h).is_err(),
|
||||
"should be invalid ({desc}): {h}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -574,10 +581,7 @@ mod tests {
|
||||
let mut base = HostMap::new();
|
||||
base.insert("core", &id.npub()).unwrap();
|
||||
|
||||
let reloader = HostMapReloader::new(
|
||||
base,
|
||||
std::path::PathBuf::from("/nonexistent/hosts"),
|
||||
);
|
||||
let reloader = HostMapReloader::new(base, std::path::PathBuf::from("/nonexistent/hosts"));
|
||||
// Only base entries present
|
||||
assert_eq!(reloader.hosts().len(), 1);
|
||||
assert!(reloader.hosts().lookup_npub("core").is_some());
|
||||
@@ -605,7 +609,11 @@ mod tests {
|
||||
// Modify the file — bump mtime by writing new content
|
||||
// Sleep briefly to ensure mtime changes (filesystem granularity)
|
||||
std::thread::sleep(std::time::Duration::from_millis(50));
|
||||
std::fs::write(&path, format!("gateway {}\nnew-host {}\n", id1.npub(), id2.npub())).unwrap();
|
||||
std::fs::write(
|
||||
&path,
|
||||
format!("gateway {}\nnew-host {}\n", id1.npub(), id2.npub()),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert!(reloader.check_reload());
|
||||
assert_eq!(reloader.hosts().len(), 2);
|
||||
|
||||
+2
-1
@@ -543,7 +543,8 @@ mod tests {
|
||||
let short_packet = vec![0u8; 20];
|
||||
let our_addr: Ipv6Addr = "fd00::ffff".parse().unwrap();
|
||||
|
||||
let response = build_dest_unreachable(&short_packet, DestUnreachableCode::NoRoute, our_addr);
|
||||
let response =
|
||||
build_dest_unreachable(&short_packet, DestUnreachableCode::NoRoute, our_addr);
|
||||
assert!(response.is_none());
|
||||
}
|
||||
|
||||
|
||||
@@ -68,9 +68,8 @@ impl IcmpRateLimiter {
|
||||
|
||||
/// Remove entries older than max_age.
|
||||
fn cleanup(&mut self, now: Instant) {
|
||||
self.last_sent.retain(|_, &mut last| {
|
||||
now.duration_since(last) < self.max_age
|
||||
});
|
||||
self.last_sent
|
||||
.retain(|_, &mut last| now.duration_since(last) < self.max_age);
|
||||
}
|
||||
|
||||
/// Get the number of tracked sources.
|
||||
@@ -179,4 +178,4 @@ mod tests {
|
||||
limiter.cleanup(Instant::now());
|
||||
assert_eq!(limiter.len(), 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+16
-8
@@ -156,13 +156,17 @@ mod tests {
|
||||
}
|
||||
|
||||
fn sample_src() -> [u8; 16] {
|
||||
[0xfd, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f]
|
||||
[
|
||||
0xfd, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
|
||||
0x0e, 0x0f,
|
||||
]
|
||||
}
|
||||
|
||||
fn sample_dst() -> [u8; 16] {
|
||||
[0xfd, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f]
|
||||
[
|
||||
0xfd, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
|
||||
0x1e, 0x1f,
|
||||
]
|
||||
}
|
||||
|
||||
// ===== Round-trip fidelity =====
|
||||
@@ -334,10 +338,14 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_addresses_from_context() {
|
||||
let original_src = [0xfd, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
|
||||
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA];
|
||||
let original_dst = [0xfd, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
|
||||
0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB];
|
||||
let original_src = [
|
||||
0xfd, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
|
||||
0xAA, 0xAA,
|
||||
];
|
||||
let original_dst = [
|
||||
0xfd, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
|
||||
0xBB, 0xBB,
|
||||
];
|
||||
let pkt = build_ipv6_packet(0, 0, 17, 64, original_src, original_dst, &[1, 2]);
|
||||
|
||||
let compressed = compress_ipv6(&pkt).unwrap();
|
||||
|
||||
@@ -74,7 +74,7 @@ pub fn clamp_tcp_mss(ipv6_packet: &mut [u8], max_mss: u16) -> bool {
|
||||
// Parse TCP options
|
||||
let options_start = tcp_start + TCP_HEADER_MIN_LEN;
|
||||
let options_end = tcp_start + tcp_header_len;
|
||||
|
||||
|
||||
if options_end > ipv6_packet.len() {
|
||||
return false;
|
||||
}
|
||||
@@ -114,10 +114,10 @@ pub fn clamp_tcp_mss(ipv6_packet: &mut [u8], max_mss: u16) -> bool {
|
||||
// Clamp if needed
|
||||
if current_mss > max_mss {
|
||||
ipv6_packet[i + 2..i + 4].copy_from_slice(&max_mss.to_be_bytes());
|
||||
|
||||
|
||||
// Recalculate TCP checksum
|
||||
recalculate_tcp_checksum(ipv6_packet, tcp_start);
|
||||
|
||||
|
||||
modified = true;
|
||||
}
|
||||
break; // MSS option found, no need to continue
|
||||
@@ -258,7 +258,7 @@ mod tests {
|
||||
let src = [0xfd, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1];
|
||||
let dst = [0xfd, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2];
|
||||
let mut packet = make_tcp_syn_packet(src, dst, 1460);
|
||||
|
||||
|
||||
// Clear SYN flag
|
||||
packet[40 + 13] = 0x10; // ACK only
|
||||
|
||||
@@ -277,4 +277,4 @@ mod tests {
|
||||
|
||||
assert!(!modified);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+14
-4
@@ -6,7 +6,7 @@
|
||||
|
||||
use crate::{FipsAddress, TunConfig};
|
||||
use futures::TryStreamExt;
|
||||
use rtnetlink::{new_connection, Handle, LinkUnspec, RouteMessageBuilder};
|
||||
use rtnetlink::{Handle, LinkUnspec, RouteMessageBuilder, new_connection};
|
||||
use std::fs::File;
|
||||
use std::io::{Read, Write};
|
||||
use std::net::Ipv6Addr;
|
||||
@@ -151,7 +151,9 @@ impl TunDevice {
|
||||
/// Returns the number of bytes read into the buffer, or an error.
|
||||
/// The buffer should be at least MTU + header size (typically 1500+ bytes).
|
||||
pub fn read_packet(&mut self, buf: &mut [u8]) -> Result<usize, TunError> {
|
||||
self.device.read(buf).map_err(|e| TunError::Configure(format!("read failed: {}", e)))
|
||||
self.device
|
||||
.read(buf)
|
||||
.map_err(|e| TunError::Configure(format!("read failed: {}", e)))
|
||||
}
|
||||
|
||||
/// Shutdown and delete the TUN device.
|
||||
@@ -263,7 +265,9 @@ pub fn run_tun_reader(
|
||||
outbound_tx: TunOutboundTx,
|
||||
transport_mtu: u16,
|
||||
) {
|
||||
use super::icmp::{build_dest_unreachable, effective_ipv6_mtu, should_send_icmp_error, DestUnreachableCode};
|
||||
use super::icmp::{
|
||||
DestUnreachableCode, build_dest_unreachable, effective_ipv6_mtu, should_send_icmp_error,
|
||||
};
|
||||
use super::tcp_mss::clamp_tcp_mss;
|
||||
|
||||
let name = device.name().to_string();
|
||||
@@ -470,7 +474,13 @@ async fn configure_interface(name: &str, addr: Ipv6Addr, mtu: u16) -> Result<(),
|
||||
// Add ip6 rule to ensure fd00::/8 uses the main table, preventing other
|
||||
// routing software (e.g. Tailscale) from intercepting FIPS traffic via
|
||||
// catch-all rules in auxiliary routing tables.
|
||||
let mut rule_req = handle.rule().add().v6().destination_prefix(fd_prefix, 8).table_id(254).priority(5265);
|
||||
let mut rule_req = handle
|
||||
.rule()
|
||||
.add()
|
||||
.v6()
|
||||
.destination_prefix(fd_prefix, 8)
|
||||
.table_id(254)
|
||||
.priority(5265);
|
||||
rule_req.message_mut().header.action = 1.into(); // FR_ACT_TO_TBL
|
||||
if let Err(e) = rule_req.execute().await {
|
||||
debug!("ip6 rule for fd00::/8 not added (may already exist): {e}");
|
||||
|
||||
Reference in New Issue
Block a user