From 88384172039fc75ac72424cf782289e587eda16e Mon Sep 17 00:00:00 2001 From: Teoh Han Hui Date: Fri, 29 Nov 2024 19:58:31 +0800 Subject: [PATCH] Use `const_str::concat_bytes!` for the DHCP request --- Cargo.lock | 226 ++++++++++++++++++++++++++++++++++- crates/muvm/Cargo.toml | 1 + crates/muvm/src/guest/net.rs | 149 ++++++++++++----------- 3 files changed, 306 insertions(+), 70 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a0ff756..e4829d3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -119,7 +119,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn", + "syn 2.0.61", ] [[package]] @@ -189,6 +189,78 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" +[[package]] +name = "const-str" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3618cccc083bb987a415d85c02ca6c9994ea5b44731ec28b9ecf09658655fba9" + +[[package]] +name = "darling" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 1.0.109", +] + +[[package]] +name = "darling_macro" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +dependencies = [ + "darling_core", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_builder" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07adf7be193b71cc36b193d0f5fe60b918a3a9db4dad0449f57bcfd519704a3" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f91d4cfa921f1c05904dc3c57b4a32c38aed3340cce209f3a6fd1478babafc4" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_builder_macro" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f0314b72bed045f3a68671b3c86328386762c93f82d98c65c3cb5e5f573dd68" +dependencies = [ + "derive_builder_core", + "syn 1.0.109", +] + [[package]] name = "either" version = "1.11.0" @@ -233,6 +305,12 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + [[package]] name = "futures-core" version = "0.3.30" @@ -256,6 +334,18 @@ dependencies = [ "wasi", ] +[[package]] +name = "getset" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f636605b743120a8d32ed92fc27b6cde1a769f8f936c065151eb66f88ded513c" +dependencies = [ + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.61", +] + [[package]] name = "gimli" version = "0.29.0" @@ -286,6 +376,12 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "input-linux" version = "0.7.1" @@ -379,6 +475,16 @@ version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + [[package]] name = "log" version = "0.4.21" @@ -433,11 +539,13 @@ dependencies = [ "anyhow", "bpaf", "byteorder", + "const-str", "env_logger", "input-linux", "input-linux-sys", "krun-sys", "log", + "neli", "nix", "procfs", "rustix", @@ -450,6 +558,35 @@ dependencies = [ "uuid", ] +[[package]] +name = "neli" +version = "0.7.0-rc2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4de016d5ec13f40df05f92660c9322325d7e15e3ea6f9b365a6e0ecc7cb0b7f2" +dependencies = [ + "bitflags", + "byteorder", + "derive_builder", + "getset", + "libc", + "log", + "neli-proc-macros", + "parking_lot", +] + +[[package]] +name = "neli-proc-macros" +version = "0.2.0-rc2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce2ca79a37046e8897da8e967f22d7a6c76b9d5ffafbc8d7c57185a63ffe9ff" +dependencies = [ + "either", + "proc-macro2", + "quote", + "serde", + "syn 1.0.109", +] + [[package]] name = "nix" version = "0.29.0" @@ -492,6 +629,29 @@ dependencies = [ "memchr", ] +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.5", +] + [[package]] name = "pin-project-lite" version = "0.2.14" @@ -504,6 +664,28 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn 2.0.61", +] + [[package]] name = "proc-macro2" version = "1.0.82" @@ -544,6 +726,15 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "redox_syscall" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +dependencies = [ + "bitflags", +] + [[package]] name = "regex" version = "1.10.4" @@ -604,6 +795,12 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + [[package]] name = "serde" version = "1.0.203" @@ -621,7 +818,7 @@ checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.61", ] [[package]] @@ -650,6 +847,12 @@ dependencies = [ "libc", ] +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + [[package]] name = "socket2" version = "0.5.7" @@ -660,6 +863,23 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.61" @@ -709,7 +929,7 @@ checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.61", ] [[package]] diff --git a/crates/muvm/Cargo.toml b/crates/muvm/Cargo.toml index 51c10cd..72bd8b1 100644 --- a/crates/muvm/Cargo.toml +++ b/crates/muvm/Cargo.toml @@ -12,6 +12,7 @@ license = "MIT" anyhow = { version = "1.0.82", default-features = false, features = ["std"] } bpaf = { version = "0.9.11", default-features = false, features = [] } byteorder = { version = "1.5.0", default-features = false, features = ["std"] } +const-str = { version = "0.5.7", default-features = false, features = [] } env_logger = { version = "0.11.3", default-features = false, features = ["auto-color", "humantime", "unstable-kv"] } input-linux = { version = "0.7.0", default-features = false, features = [] } input-linux-sys = { version = "0.9.0", default-features = false, features = [] } diff --git a/crates/muvm/src/guest/net.rs b/crates/muvm/src/guest/net.rs index f406dde..c934423 100644 --- a/crates/muvm/src/guest/net.rs +++ b/crates/muvm/src/guest/net.rs @@ -1,32 +1,31 @@ use std::fs; use std::io::Write; -use std::net::{UdpSocket, Ipv4Addr}; +use std::net::{Ipv4Addr, UdpSocket}; use std::time::Duration; use anyhow::{Context, Result}; -use rustix::system::sethostname; - -use neli::{ - consts::{ - nl::NlmF, - rtnl::{Arphrd, Ifa, IfaF, Iff, Rta, RtAddrFamily, Rtm, RtmF, Rtn, - Rtprot, RtScope, RtTable}, - socket::NlFamily, - }, - nl::{NlPayload, Nlmsghdr}, - router::synchronous::{NlRouter, NlRouterReceiverHandle}, - rtnl::{Ifaddrmsg, IfaddrmsgBuilder, Ifinfomsg, IfinfomsgBuilder, - RtattrBuilder, Rtmsg, RtmsgBuilder}, - utils::Groups, - types::RtBuffer, +use neli::consts::nl::NlmF; +use neli::consts::rtnl::{ + Arphrd, Ifa, IfaF, Iff, RtAddrFamily, RtScope, RtTable, Rta, Rtm, RtmF, Rtn, Rtprot, +}; +use neli::consts::socket::NlFamily; +use neli::nl::{NlPayload, Nlmsghdr}; +use neli::router::synchronous::{NlRouter, NlRouterReceiverHandle}; +use neli::rtnl::{ + Ifaddrmsg, IfaddrmsgBuilder, Ifinfomsg, IfinfomsgBuilder, RtattrBuilder, Rtmsg, RtmsgBuilder, }; +use neli::types::RtBuffer; +use neli::utils::Groups; +use rustix::system::sethostname; /// Set interface flags for eth0 (interface index 2) with a given mask fn flags_eth0(rtnl: &NlRouter, mask: Iff, set: Iff) -> Result<()> { let ifinfomsg = IfinfomsgBuilder::default() .ifi_family(RtAddrFamily::Unspecified) - .ifi_type(Arphrd::Ether).ifi_index(2) - .ifi_change(mask).ifi_flags(set) + .ifi_type(Arphrd::Ether) + .ifi_index(2) + .ifi_change(mask) + .ifi_flags(set) .build()?; let _: NlRouterReceiverHandle = @@ -39,9 +38,13 @@ fn flags_eth0(rtnl: &NlRouter, mask: Iff, set: Iff) -> Result<()> { fn route4_eth0(rtnl: &NlRouter, what: Rtm, gw: Ipv4Addr) -> Result<()> { let rtmsg = RtmsgBuilder::default() .rtm_family(RtAddrFamily::Inet) - .rtm_dst_len(0).rtm_src_len(0).rtm_tos(0) - .rtm_table(RtTable::Main).rtm_protocol(Rtprot::Boot) - .rtm_scope(RtScope::Universe).rtm_type(Rtn::Unicast) + .rtm_dst_len(0) + .rtm_src_len(0) + .rtm_tos(0) + .rtm_table(RtTable::Main) + .rtm_protocol(Rtprot::Boot) + .rtm_scope(RtScope::Universe) + .rtm_type(Rtn::Unicast) .rtm_flags(RtmF::empty()) .rtattrs(RtBuffer::from_iter([ RtattrBuilder::default() @@ -55,20 +58,21 @@ fn route4_eth0(rtnl: &NlRouter, what: Rtm, gw: Ipv4Addr) -> Result<()> { RtattrBuilder::default() .rta_type(Rta::Gateway) .rta_payload(gw.octets().to_vec()) - .build()? + .build()?, ])) .build()?; - let _: NlRouterReceiverHandle = - rtnl.send(what, NlmF::CREATE | NlmF::REQUEST, - NlPayload::Payload(rtmsg))?; + let _: NlRouterReceiverHandle = rtnl.send( + what, + NlmF::CREATE | NlmF::REQUEST, + NlPayload::Payload(rtmsg), + )?; Ok(()) } /// Add or delete IPv4 addresses for eth0 (interface index 2) -fn addr4_eth0(rtnl: &NlRouter, what: Rtm, addr: Ipv4Addr, prefix_len: u8) - -> Result<()> { +fn addr4_eth0(rtnl: &NlRouter, what: Rtm, addr: Ipv4Addr, prefix_len: u8) -> Result<()> { let ifaddrmsg = IfaddrmsgBuilder::default() .ifa_family(RtAddrFamily::Inet) .ifa_prefixlen(prefix_len) @@ -86,9 +90,11 @@ fn addr4_eth0(rtnl: &NlRouter, what: Rtm, addr: Ipv4Addr, prefix_len: u8) ])) .build()?; - let _: NlRouterReceiverHandle = - rtnl.send(what, NlmF::CREATE | NlmF::REQUEST, - NlPayload::Payload(ifaddrmsg))?; + let _: NlRouterReceiverHandle = rtnl.send( + what, + NlmF::CREATE | NlmF::REQUEST, + NlPayload::Payload(ifaddrmsg), + )?; Ok(()) } @@ -103,26 +109,30 @@ fn do_dhcp(rtnl: &NlRouter) -> Result<()> { let socket = UdpSocket::bind("0.0.0.0:68").expect("Failed to bind"); let mut buf = [0; 576 /* RFC 2131, Section 2 */ ]; - const REQUEST: [u8; 300 /* From RFC 951: >= 60 B of options */ ] = [ - 1 /* REQUEST */, 0x1 /* Ethernet */, 6 /* hlen */, 0 /* Hops */, - 1, 2, 3, 4 /* XID */, 0, 0 /* Seconds */, 0x80, 0x0 /* Flags */, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* All-zero (four) addresses */ - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 16B HW address: who cares */ - /* 32 bytes per row: 64B 'sname', plus 128B 'file' (RFC 1531) */ - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0x63, 0x82, 0x53, 0x63, /* DHCP (magic) cookie, then options: */ - 53, 1, 1 /* DISCOVER */, 80, 0 /* Rapid commit */, 0xff, // Done - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* 54B paaaadding */ - ]; + const REQUEST: &[u8; 300 /* From RFC 951: >= 60 B of options */ ] = const_str::concat_bytes!( + 1, // REQUEST + 0x1, // Ethernet + 6, // hlen + 0, // Hops + [1, 2, 3, 4], // XID + [0, 0], // Seconds + [0x80, 0x0], // Flags + [0; 16], // All-zero (four) addresses + [0; 16], // 16B HW address: who cares + [0; 64], // 64B 'sname' (RFC 1531) + [0; 128], // 128B 'file' (RFC 1531) + [0x63, 0x82, 0x53, 0x63], // DHCP (magic) cookie + // options + [ + 53, 1, 1, // DISCOVER + 80, 0, // Rapid commit + ], + 0xff, // end + [0; 54], // pad + ); socket.set_broadcast(true)?; - socket.send_to(&REQUEST, "255.255.255.255:67")?; + socket.send_to(REQUEST, "255.255.255.255:67")?; // Keep IPv6-only fast let _ = socket.set_read_timeout(Some(Duration::from_millis(100))); @@ -135,36 +145,40 @@ fn do_dhcp(rtnl: &NlRouter) -> Result<()> { let mut netmask = Ipv4Addr::UNSPECIFIED; let mut router = Ipv4Addr::UNSPECIFIED; let mut p: usize = 240; - let mut resolv = fs::File::options().append(true) - .open("/etc/resolv.conf") - .context("Failed to open /etc/resolv.conf")?; + let mut resolv = fs::File::options() + .append(true) + .open("/etc/resolv.conf") + .context("Failed to open /etc/resolv.conf")?; while p < len { let o = msg[p]; let l: u8 = msg[p + 1]; p += 2; // Length doesn't include code and length field itself - if o == 1 { // Option 1: Subnet Mask - netmask = Ipv4Addr::new(msg[p ], msg[p + 1], - msg[p + 1], msg[p + 3]); - } else if o == 3 { // Option 3: Router - router = Ipv4Addr::new(msg[p ], msg[p + 1], - msg[p + 2], msg[p + 3]); - } else if o == 6 { // Option 6: Domain Name Server + if o == 1 { + // Option 1: Subnet Mask + netmask = Ipv4Addr::new(msg[p], msg[p + 1], msg[p + 1], msg[p + 3]); + } else if o == 3 { + // Option 3: Router + router = Ipv4Addr::new(msg[p], msg[p + 1], msg[p + 2], msg[p + 3]); + } else if o == 6 { + // Option 6: Domain Name Server for dns_p in (p..p + l as usize).step_by(4) { - let dns = Ipv4Addr::new(msg[dns_p ], msg[dns_p + 1], - msg[dns_p + 2], msg[dns_p + 3]); - resolv.write_all(format!("nameserver {}\n", dns).as_bytes()) - .context("Failed to write to resolv.conf")?; + let dns = + Ipv4Addr::new(msg[dns_p], msg[dns_p + 1], msg[dns_p + 2], msg[dns_p + 3]); + resolv + .write_all(format!("nameserver {}\n", dns).as_bytes()) + .context("Failed to write to resolv.conf")?; } - } else if o == 0xff { // Option 255: End (of options) + } else if o == 0xff { + // Option 255: End (of options) break; } p += l as usize; } - let prefix_len : u8 = netmask.to_bits().leading_ones() as u8; + let prefix_len: u8 = netmask.to_bits().leading_ones() as u8; // Drop temporary address and route, configure what we got instead route4_eth0(rtnl, Rtm::Delroute, Ipv4Addr::UNSPECIFIED)?; @@ -192,11 +206,12 @@ fn wait_for_slaac(rtnl: &NlRouter) -> Result<()> { while !ll_seen || (global_wait && !global_seen) { let ifaddrmsg = IfaddrmsgBuilder::default() .ifa_family(RtAddrFamily::Inet6) - .ifa_prefixlen(0).ifa_scope(RtScope::Universe).ifa_index(2) + .ifa_prefixlen(0) + .ifa_scope(RtScope::Universe) + .ifa_index(2) .build()?; - let recv = rtnl.send(Rtm::Getaddr, NlmF::ROOT, - NlPayload::Payload(ifaddrmsg))?; + let recv = rtnl.send(Rtm::Getaddr, NlmF::ROOT, NlPayload::Payload(ifaddrmsg))?; for response in recv { let header: Nlmsghdr = response?;