Skip to main content

strate_net_silo/
content.rs

1use alloc::{string::String, vec, vec::Vec};
2use core::fmt::Write;
3
4use smoltcp::socket::tcp;
5use strate_net::syscalls::call;
6
7use crate::state::NetworkStrate;
8
9impl NetworkStrate {
10    pub(crate) fn generate_content(
11        &mut self,
12        _file_id: u64,
13        path: &str,
14    ) -> core::result::Result<Vec<u8>, i32> {
15        match path {
16            "" => Ok(b"ip\naddress\nprefix\nnetmask\nbroadcast\ngateway\nroute\nroutes\ndns\ndhcp\nresolve\nping\ntcp\nudp\nip6\nip6/address\nip6/gateway\n".to_vec()),
17            "ip" => Ok(if let Some(ref cfg) = self.ip_config {
18                alloc::format!("{}\n", cfg.address).into_bytes()
19            } else {
20                b"0.0.0.0/0\n".to_vec()
21            }),
22            "address" => Ok(if let Some(ref cfg) = self.ip_config {
23                alloc::format!("{}\n", cfg.host).into_bytes()
24            } else {
25                b"0.0.0.0\n".to_vec()
26            }),
27            "prefix" => Ok(if let Some(ref cfg) = self.ip_config {
28                alloc::format!("{}\n", cfg.prefix_len).into_bytes()
29            } else {
30                b"0\n".to_vec()
31            }),
32            "netmask" => Ok(if let Some(ref cfg) = self.ip_config {
33                alloc::format!("{}\n", cfg.netmask).into_bytes()
34            } else {
35                b"0.0.0.0\n".to_vec()
36            }),
37            "broadcast" => Ok(if let Some(ref cfg) = self.ip_config {
38                alloc::format!("{}\n", cfg.broadcast).into_bytes()
39            } else {
40                b"0.0.0.0\n".to_vec()
41            }),
42            "gateway" => Ok(if let Some(ref cfg) = self.ip_config {
43                if let Some(gw) = cfg.gateway {
44                    alloc::format!("{}\n", gw).into_bytes()
45                } else {
46                    b"0.0.0.0\n".to_vec()
47                }
48            } else {
49                b"0.0.0.0\n".to_vec()
50            }),
51            "dns" => {
52                let mut out = String::new();
53                let mut wrote = false;
54                for server in self.dns_servers.iter().flatten() {
55                    let _ = writeln!(out, "{}", server);
56                    wrote = true;
57                }
58                if !wrote {
59                    out.push_str("0.0.0.0\n");
60                }
61                Ok(out.into_bytes())
62            }
63            "dhcp" => Ok(if self.dhcp_enabled {
64                b"on\n".to_vec()
65            } else {
66                b"off\n".to_vec()
67            }),
68            "ip6" | "ip6/address" => {
69                let addr = if let Some(ref cfg) = self.ipv6_config {
70                    cfg.address.address()
71                } else {
72                    self.link_local_addr
73                };
74                Ok(alloc::format!("{}\n", addr).into_bytes())
75            }
76            "ip6/gateway" => Ok(if let Some(ref cfg) = self.ipv6_config {
77                if let Some(gw) = cfg.gateway {
78                    alloc::format!("{}\n", gw).into_bytes()
79                } else {
80                    b"::\n".to_vec()
81                }
82            } else {
83                b"::\n".to_vec()
84            }),
85            "route" => Ok(if let Some(ref cfg) = self.ip_config {
86                if let Some(gw) = cfg.gateway {
87                    alloc::format!("default via {}\n", gw).into_bytes()
88                } else if let Some(ref cfg6) = self.ipv6_config {
89                    if let Some(gw) = cfg6.gateway {
90                        alloc::format!("default via {}\n", gw).into_bytes()
91                    } else {
92                        b"none\n".to_vec()
93                    }
94                } else {
95                    b"none\n".to_vec()
96                }
97            } else if let Some(ref cfg6) = self.ipv6_config {
98                if let Some(gw) = cfg6.gateway {
99                    alloc::format!("default via {}\n", gw).into_bytes()
100                } else {
101                    b"none\n".to_vec()
102                }
103            } else {
104                b"none\n".to_vec()
105            }),
106            "routes" => {
107                let mut content = Vec::new();
108                self.interface.routes_mut().update(|table| {
109                    for route in table.iter() {
110                        let line = alloc::format!("{} via {}\n", route.cidr, route.via_router);
111                        content.extend_from_slice(line.as_bytes());
112                    }
113                });
114                if content.is_empty() {
115                    content.extend_from_slice(b"none\n");
116                }
117                Ok(content)
118            }
119            "resolve" => Ok(b"use /net/resolve/<hostname>\n".to_vec()),
120            "tcp" => Ok(b"use /net/tcp/listen/<port>, /net/tcp/listen-once/<port>, /net/tcp/connect/<ip>/<port>[/<local_port>], /net/tcp/listeners, /net/tcp/connections, /net/tcp/stats\n".to_vec()),
121            "tcp/listeners" => {
122                let mut content = Vec::new();
123                if self.tcp_listeners.is_empty() {
124                    content.extend_from_slice(b"none\n");
125                } else {
126                    for (fid, listener) in self.tcp_listeners.iter() {
127                        let socket = self.sockets.get::<tcp::Socket>(listener.socket);
128                        let mode = if listener.auto_relisten { "auto" } else { "once" };
129                        let line = alloc::format!(
130                            "fid={} port={} state={} mode={}\n",
131                            fid,
132                            listener.port,
133                            Self::tcp_state_name(socket.state()),
134                            mode
135                        );
136                        content.extend_from_slice(line.as_bytes());
137                    }
138                }
139                Ok(content)
140            }
141            "tcp/connections" => {
142                let mut content = Vec::new();
143                if self.tcp_connections.is_empty() {
144                    content.extend_from_slice(b"none\n");
145                } else {
146                    for (fid, conn) in self.tcp_connections.iter() {
147                        let socket = self.sockets.get::<tcp::Socket>(conn.socket);
148                        let local = socket.local_endpoint();
149                        let remote = socket.remote_endpoint();
150                        let line = match (local, remote) {
151                            (Some(local), Some(remote)) => alloc::format!(
152                                "fid={} local={} remote={} state={}\n",
153                                fid,
154                                local,
155                                remote,
156                                Self::tcp_state_name(socket.state())
157                            ),
158                            _ => alloc::format!(
159                                "fid={} local_port={} remote={} state={}\n",
160                                fid,
161                                conn.local_port,
162                                conn.remote,
163                                Self::tcp_state_name(socket.state())
164                            ),
165                        };
166                        content.extend_from_slice(line.as_bytes());
167                    }
168                }
169                Ok(content)
170            }
171            "tcp/stats" => {
172                let listeners = self.tcp_listeners.len();
173                let connections = self.tcp_connections.len();
174                let mut established = 0usize;
175                let mut connecting = 0usize;
176                let mut closing = 0usize;
177                for conn in self.tcp_connections.values() {
178                    let socket = self.sockets.get::<tcp::Socket>(conn.socket);
179                    match socket.state() {
180                        tcp::State::Established => established += 1,
181                        tcp::State::SynSent | tcp::State::SynReceived => connecting += 1,
182                        tcp::State::Closed => {}
183                        _ => closing += 1,
184                    }
185                }
186                Ok(alloc::format!(
187                    "listeners={}\nconnections={}\nestablished={}\nconnecting={}\nclosing={}\n",
188                    listeners,
189                    connections,
190                    established,
191                    connecting,
192                    closing
193                )
194                .into_bytes())
195            }
196            "udp" => Ok(b"use /net/udp/bind/<port>, /net/udp/connect/<ip>/<port> or /net/udp/send/<ip>/<port>\n".to_vec()),
197            path if path.starts_with("resolve/") => {
198                let name = &path[8..];
199                self.resolve_hostname_blocking(name)
200                    .map(|addr| alloc::format!("{}\n", addr).into_bytes())
201            }
202            path if path.starts_with("ping/") || path.starts_with("ping6/") => {
203                if let Some((seq, rtt_us)) = self.ping_replies.first().copied() {
204                    self.ping_replies.remove(0);
205                    let _ = call::debug_log(b"[ping] read returning seq=");
206                    let _ = call::debug_log(&[(seq >> 8) as u8, seq as u8]);
207                    let _ = call::debug_log(b" rtt=");
208                    let _ = call::debug_log(&[(rtt_us / 1000) as u8]);
209                    let _ = call::debug_log(b"ms\n");
210                    let mut buf = vec![0u8; 10];
211                    buf[0..2].copy_from_slice(&seq.to_le_bytes());
212                    buf[2..10].copy_from_slice(&rtt_us.to_le_bytes());
213                    Ok(buf)
214                } else {
215                    let _ = call::debug_log(b"[ping] read: no replies waiting\n");
216                    Ok(Vec::new())
217                }
218            }
219            _ => Err(-9),
220        }
221    }
222}