Nothing to see here, move along
1#![no_std]
2#![no_main]
3
4use lancer_user::net;
5use lancer_user::syscall;
6
7const STATE_NAMES: [&[u8]; 11] = [
8 b"Closed",
9 b"Listen",
10 b"SynSent",
11 b"SynRecv",
12 b"Established",
13 b"FinWait1",
14 b"FinWait2",
15 b"CloseWait",
16 b"Closing",
17 b"LastAck",
18 b"TimeWait",
19];
20
21#[unsafe(no_mangle)]
22pub extern "C" fn lancer_main() -> ! {
23 let (rx, tx) = match net::init() {
24 Some(pair) => pair,
25 None => {
26 lancer_user::show!(net, error, "netsock init failed");
27 syscall::exit();
28 }
29 };
30
31 if !net::has_relay() {
32 lancer_user::io::write_bytes(b"networking not available (use SSH)\n");
33 syscall::exit();
34 }
35
36 let mut args_buf = [0u8; 64];
37 let _ = net::recv_args(&rx, &mut args_buf);
38
39 lancer_user::io::write_bytes(
40 b"Proto Local Remote State SndQ RcvQ\n",
41 );
42
43 net::send_request(&tx, &[net::MSG_NETSTAT_REQUEST]);
44
45 let mut resp = [0u8; 64];
46 let mut done = false;
47 core::iter::from_fn(|| match done {
48 true => None,
49 false => {
50 let n = net::recv_response_blocking(&rx, &mut resp);
51 match n < 1 {
52 true => None,
53 false => match resp[0] {
54 net::MSG_NETSTAT_DONE => {
55 done = true;
56 None
57 }
58 net::MSG_NETSTAT_ENTRY if n >= 18 => {
59 format_tcp_entry(&resp[1..n]);
60 Some(())
61 }
62 net::MSG_NETSTAT_ENTRY_UDP if n >= 4 => {
63 format_udp_entry(&resp[1..n]);
64 Some(())
65 }
66 _ => Some(()),
67 },
68 }
69 }
70 })
71 .take(32)
72 .count();
73
74 syscall::exit()
75}
76
77fn format_tcp_entry(data: &[u8]) {
78 let state_idx = data[1] as usize;
79 let local_ip = &data[2..6];
80 let local_port = ((data[6] as u16) << 8) | data[7] as u16;
81 let remote_ip = &data[8..12];
82 let remote_port = ((data[12] as u16) << 8) | data[13] as u16;
83 let send_q = ((data[14] as u16) << 8) | data[15] as u16;
84 let recv_q = ((data[16] as u16) << 8) | data[17] as u16;
85
86 let mut out = [b' '; 128];
87 let mut pos = 0usize;
88
89 pos = append(&mut out, pos, b"tcp ");
90
91 let ip_len = net::write_ip_decimal(&mut out[pos..], local_ip);
92 pos += ip_len;
93 out[pos] = b':';
94 pos += 1;
95 let port_len = net::write_u16_decimal(&mut out[pos..], local_port);
96 pos += port_len;
97
98 pad_to(&mut out, &mut pos, 25);
99
100 let has_remote = remote_ip.iter().any(|&b| b != 0) || remote_port != 0;
101 match has_remote {
102 true => {
103 let rip_len = net::write_ip_decimal(&mut out[pos..], remote_ip);
104 pos += rip_len;
105 out[pos] = b':';
106 pos += 1;
107 let rport_len = net::write_u16_decimal(&mut out[pos..], remote_port);
108 pos += rport_len;
109 }
110 false => {
111 out[pos] = b'-';
112 pos += 1;
113 }
114 }
115
116 pad_to(&mut out, &mut pos, 43);
117
118 let state_name = match state_idx < STATE_NAMES.len() {
119 true => STATE_NAMES[state_idx],
120 false => b"?",
121 };
122 pos = append(&mut out, pos, state_name);
123
124 pad_to(&mut out, &mut pos, 57);
125
126 let sq_len = net::write_u16_decimal(&mut out[pos..], send_q);
127 pos += sq_len;
128
129 pad_to(&mut out, &mut pos, 63);
130
131 let rq_len = net::write_u16_decimal(&mut out[pos..], recv_q);
132 pos += rq_len;
133
134 out[pos] = b'\n';
135 pos += 1;
136
137 lancer_user::io::write_bytes(&out[..pos]);
138}
139
140fn format_udp_entry(data: &[u8]) {
141 let local_port = ((data[0] as u16) << 8) | data[1] as u16;
142 let recv_q = ((data[2] as u16) << 8) | data[3] as u16;
143
144 let mut out = [b' '; 128];
145 let mut pos = 0usize;
146
147 pos = append(&mut out, pos, b"udp 0.0.0.0:");
148 let port_len = net::write_u16_decimal(&mut out[pos..], local_port);
149 pos += port_len;
150
151 pad_to(&mut out, &mut pos, 25);
152
153 out[pos] = b'-';
154 pos += 1;
155
156 pad_to(&mut out, &mut pos, 43);
157
158 out[pos] = b'-';
159 pos += 1;
160
161 pad_to(&mut out, &mut pos, 63);
162
163 let rq_len = net::write_u16_decimal(&mut out[pos..], recv_q);
164 pos += rq_len;
165
166 out[pos] = b'\n';
167 pos += 1;
168
169 lancer_user::io::write_bytes(&out[..pos]);
170}
171
172fn append(buf: &mut [u8], pos: usize, data: &[u8]) -> usize {
173 let n = data.len().min(buf.len() - pos);
174 buf[pos..pos + n].copy_from_slice(&data[..n]);
175 pos + n
176}
177
178fn pad_to(buf: &mut [u8], pos: &mut usize, target: usize) {
179 (*pos..target).for_each(|i| {
180 buf[i] = b' ';
181 });
182 *pos = (*pos).max(target);
183}