Nothing to see here, move along
at main 216 lines 6.3 kB view raw
1#![no_std] 2#![no_main] 3 4use lancer_core::packet_ring::{PacketRingReader, PacketRingWriter}; 5use lancer_user::io::write_bytes; 6use lancer_user::net; 7use lancer_user::syscall; 8 9const MAX_PINGS: u8 = 8; 10const DEFAULT_COUNT: u8 = 4; 11 12enum Target { 13 V4([u8; 4]), 14 V6([u8; 16]), 15} 16 17struct DnsResult { 18 v6: Option<[u8; 16]>, 19 v4: Option<[u8; 4]>, 20} 21 22#[unsafe(no_mangle)] 23pub extern "C" fn lancer_main() -> ! { 24 let (rx, tx) = match net::init() { 25 Some(pair) => pair, 26 None => { 27 lancer_user::show!(net, error, "netsock init failed"); 28 syscall::exit(); 29 } 30 }; 31 32 if !net::has_relay() { 33 write_bytes(b"networking not available (use SSH)\n"); 34 syscall::exit(); 35 } 36 37 let mut args_buf = [0u8; 128]; 38 let args_len = net::recv_args(&rx, &mut args_buf); 39 40 let args = &args_buf[..args_len]; 41 42 let (cmd_tok, rest) = net::next_token(args); 43 let after_cmd = match net::bytes_eq(cmd_tok, b"ping") { 44 true => rest, 45 false => args, 46 }; 47 48 let (host_tok, remainder) = net::next_token(after_cmd); 49 if host_tok.is_empty() { 50 write_bytes(b"usage: ping <host|ip> [count]\n"); 51 syscall::exit(); 52 } 53 54 let (count_tok, _) = net::next_token(remainder); 55 let count = match count_tok.is_empty() { 56 true => DEFAULT_COUNT, 57 false => match net::parse_decimal_u16(count_tok) { 58 Some(n) if n >= 1 && n <= MAX_PINGS as u16 => n as u8, 59 Some(_) => MAX_PINGS, 60 None => DEFAULT_COUNT, 61 }, 62 }; 63 64 let target = match net::parse_ip(host_tok) { 65 Some(ip) => Target::V4(ip), 66 None => match net::parse_ipv6(host_tok) { 67 Some(addr) => Target::V6(addr), 68 None => pick_target(&rx, &tx, host_tok), 69 }, 70 }; 71 72 write_bytes(b"pinging...\n"); 73 send_ping(&tx, &target, count); 74 recv_results(&rx, true); 75 syscall::exit() 76} 77 78fn pick_target(rx: &PacketRingReader, tx: &PacketRingWriter, hostname: &[u8]) -> Target { 79 let dns = resolve_both(rx, tx, hostname); 80 match (dns.v6, dns.v4) { 81 (None, None) => { 82 write_bytes(b"DNS lookup failed\n"); 83 syscall::exit() 84 } 85 (Some(v6), None) => Target::V6(v6), 86 (None, Some(v4)) => Target::V4(v4), 87 (Some(v6), Some(v4)) => { 88 send_ping(tx, &Target::V6(v6), 1); 89 let (received, _) = recv_results(rx, false); 90 match received > 0 { 91 true => Target::V6(v6), 92 false => Target::V4(v4), 93 } 94 } 95 } 96} 97 98fn resolve_both(rx: &PacketRingReader, tx: &PacketRingWriter, hostname: &[u8]) -> DnsResult { 99 let mut msg = [0u8; 62]; 100 let len = hostname.len().min(61); 101 msg[1..1 + len].copy_from_slice(&hostname[..len]); 102 let mut resp_buf = [0u8; 64]; 103 104 msg[0] = net::MSG_DNS_QUERY6; 105 net::send_request(tx, &msg[..1 + len]); 106 let n = net::recv_response_blocking(rx, &mut resp_buf); 107 let v6 = match n >= 18 && resp_buf[0] == net::MSG_DNS_RESULT6 && resp_buf[1] == 0 { 108 true => { 109 let mut addr = [0u8; 16]; 110 addr.copy_from_slice(&resp_buf[2..18]); 111 Some(addr) 112 } 113 false => None, 114 }; 115 116 msg[0] = net::MSG_DNS_QUERY; 117 net::send_request(tx, &msg[..1 + len]); 118 let n = net::recv_response_blocking(rx, &mut resp_buf); 119 let v4 = match n >= 6 && resp_buf[0] == net::MSG_DNS_RESULT && resp_buf[1] == 0 { 120 true => Some([resp_buf[2], resp_buf[3], resp_buf[4], resp_buf[5]]), 121 false => None, 122 }; 123 124 DnsResult { v6, v4 } 125} 126 127fn send_ping(tx: &PacketRingWriter, target: &Target, count: u8) { 128 match target { 129 Target::V6(addr) => { 130 let mut req = [0u8; 18]; 131 req[0] = net::MSG_PING_REQUEST6; 132 req[1..17].copy_from_slice(addr); 133 req[17] = count; 134 net::send_request(tx, &req); 135 } 136 Target::V4(ip) => { 137 let req = [net::MSG_PING_REQUEST, ip[0], ip[1], ip[2], ip[3], count]; 138 net::send_request(tx, &req); 139 } 140 } 141} 142 143fn recv_results(rx: &PacketRingReader, print: bool) -> (u8, u8) { 144 let mut resp_buf = [0u8; 64]; 145 let mut result = (0u8, 0u8); 146 let mut done = false; 147 core::iter::from_fn(|| { 148 if done { 149 return None; 150 } 151 let n = net::recv_response_blocking(rx, &mut resp_buf); 152 if n < 1 { 153 return Some(()); 154 } 155 match resp_buf[0] { 156 net::MSG_PING_RESULT if n >= 4 && print => { 157 print_ping_line(&resp_buf, n); 158 } 159 net::MSG_PING_DONE if n >= 3 => { 160 let (received, total) = (resp_buf[1], resp_buf[2]); 161 if print { 162 print_done_line(received, total); 163 } 164 result = (received, total); 165 done = true; 166 } 167 _ => {} 168 } 169 Some(()) 170 }) 171 .take(64) 172 .count(); 173 result 174} 175 176fn print_ping_line(resp_buf: &[u8], n: usize) { 177 let seq = resp_buf[1]; 178 let status = resp_buf[2]; 179 let mut out = [0u8; 40]; 180 let mut pos = 0usize; 181 let prefix = b"seq="; 182 out[..prefix.len()].copy_from_slice(prefix); 183 pos += prefix.len(); 184 pos += net::write_u8_decimal(&mut out[pos..], seq); 185 match status { 186 0 if n >= 5 => { 187 let rtt = ((resp_buf[3] as u16) << 8) | resp_buf[4] as u16; 188 let mid = b" time="; 189 out[pos..pos + mid.len()].copy_from_slice(mid); 190 pos += mid.len(); 191 pos += net::write_u16_decimal(&mut out[pos..], rtt); 192 let suffix = b"ms\n"; 193 out[pos..pos + suffix.len()].copy_from_slice(suffix); 194 pos += suffix.len(); 195 } 196 _ => { 197 let suffix = b" timeout\n"; 198 out[pos..pos + suffix.len()].copy_from_slice(suffix); 199 pos += suffix.len(); 200 } 201 } 202 write_bytes(&out[..pos]); 203} 204 205fn print_done_line(received: u8, total: u8) { 206 let mut out = [0u8; 24]; 207 let mut pos = 0usize; 208 pos += net::write_u8_decimal(&mut out[pos..], received); 209 out[pos] = b'/'; 210 pos += 1; 211 pos += net::write_u8_decimal(&mut out[pos..], total); 212 let suffix = b" received\n"; 213 out[pos..pos + suffix.len()].copy_from_slice(suffix); 214 pos += suffix.len(); 215 write_bytes(&out[..pos]); 216}