use std::net::Ipv4Addr;
use crafter::prelude::*;
const DOC_SRC: Ipv4Addr = Ipv4Addr::new(192, 0, 2, 10);
const DOC_DST: Ipv4Addr = Ipv4Addr::new(198, 51, 100, 20);
const AH_SPI: u32 = 0x0000_3100;
fn hmac_key() -> Vec<u8> {
vec![0x33u8; 32]
}
fn ah_security_association() -> SecurityAssociation {
SecurityAssociation::new(AH_SPI)
.integrity(IntegrityAlgorithm::HmacSha2_256_128, hmac_key())
.transport()
.extended_sequence(false)
}
fn main() -> Result<()> {
let sa = ah_security_association();
assert!(sa.validate().is_ok(), "documentation AH SA validates");
assert_eq!(sa.mode, IpsecMode::Transport);
let packet: Packet = Ipv4::new()
.src(DOC_SRC)
.dst(DOC_DST)
.protocol(IPPROTO_AH)
.ttl(64)
/ Ah::secured(sa.clone()).spi(AH_SPI).sequence(1)
/ Tcp::new().sport(43000).dport(443)
/ Raw::from("ah-example");
let compiled = packet.compile()?;
println!("example: ipsec_ah");
println!("mode: offline");
println!("documentation address pair: {DOC_SRC} -> {DOC_DST}");
println!("suite: HMAC-SHA-256-128 (integrity-only), transport mode");
println!("summary: {}", packet.summary());
println!("show:\n{}", packet.show());
println!("compiled bytes: {}", compiled.len());
println!("hexdump:\n{}", compiled.hexdump());
let wire = compiled.as_bytes().to_vec();
assert_eq!(wire[9], IPPROTO_AH, "outer IPv4 advertises AH");
assert_eq!(wire[20], IPPROTO_TCP, "AH Next Header is TCP in transport");
let opaque = Packet::decode_from_l3(NetworkLayer::Ipv4, &wire)?;
let opaque_ah = opaque.layer::<Ah>().expect("typed AH header recovered");
println!();
println!("decode (no SA): {}", opaque.summary());
println!(
" spi: {:#010x}",
opaque_ah.spi_value().expect("SPI is exposed")
);
println!(
" icv bytes: {}",
opaque_ah
.icv_value()
.map(<[u8]>::len)
.expect("ICV is captured")
);
println!(
" verification status: {:?} (no SA in the registry)",
opaque_ah.verification_status()
);
let registry = ProtocolRegistry::new().with_security_association(sa);
let decoded = Packet::decode_from_l3_with_registry(®istry, NetworkLayer::Ipv4, &wire)?;
let ah = decoded.layer::<Ah>().expect("typed AH recovered with SA");
println!();
println!("decode (with SA): {}", decoded.summary());
println!(" spi: {:#010x}", ah.spi_value().expect("SPI is exposed"));
println!(
" next header: {}",
ah.next_header_value().expect("Next Header is exposed")
);
let verified = ah.verification_status();
println!(" verification status: {verified:?}");
assert_eq!(verified, Some(true), "matching SA verifies the AH ICV");
let tcp = decoded.layer::<Tcp>().expect("protected TCP in the clear");
println!(
" inner tcp: {} -> {}",
tcp.source_port_value(),
tcp.destination_port_value()
);
Ok(())
}