|
| 1 | +// TSI DGRAM Proxy for Windows - integrates with vsock muxer |
| 2 | +// Implements the Proxy trait for UDP connections |
| 3 | + |
| 4 | +use std::collections::HashMap; |
| 5 | +use std::num::Wrapping; |
| 6 | +use std::os::windows::io::{AsRawHandle, RawHandle}; |
| 7 | +use std::sync::{Arc, Mutex}; |
| 8 | + |
| 9 | +use super::super::Queue as VirtQueue; |
| 10 | +use super::defs; |
| 11 | +use super::defs::uapi; |
| 12 | +use super::muxer::{push_packet, MuxerRx}; |
| 13 | +use super::muxer_rxq::MuxerRxQ; |
| 14 | +use super::packet::{ |
| 15 | + TsiAcceptReq, TsiConnectReq, TsiGetnameRsp, TsiListenReq, TsiSendtoAddr, VsockPacket, |
| 16 | +}; |
| 17 | +use super::proxy::{ |
| 18 | + NewProxyType, Proxy, ProxyError, ProxyRemoval, ProxyStatus, ProxyUpdate, RecvPkt, |
| 19 | +}; |
| 20 | +use super::tsi_windows::TsiDgramProxyWindows; |
| 21 | +use utils::epoll::EventSet; |
| 22 | +use vm_memory::GuestMemoryMmap; |
| 23 | + |
| 24 | +/// Windows TSI DGRAM Proxy wrapper |
| 25 | +pub struct TsiDgramProxyWindowsWrapper { |
| 26 | + id: u64, |
| 27 | + cid: u64, |
| 28 | + family: u16, |
| 29 | + local_port: u32, |
| 30 | + peer_port: u32, |
| 31 | + control_port: u32, |
| 32 | + dgram_proxy: TsiDgramProxyWindows, |
| 33 | + pub status: ProxyStatus, |
| 34 | + mem: GuestMemoryMmap, |
| 35 | + queue: Arc<Mutex<VirtQueue>>, |
| 36 | + rxq: Arc<Mutex<MuxerRxQ>>, |
| 37 | + pending_sendto: Option<std::net::SocketAddr>, |
| 38 | +} |
| 39 | + |
| 40 | +impl TsiDgramProxyWindowsWrapper { |
| 41 | + #[allow(clippy::too_many_arguments)] |
| 42 | + pub fn new( |
| 43 | + id: u64, |
| 44 | + cid: u64, |
| 45 | + family: u16, |
| 46 | + local_port: u32, |
| 47 | + peer_port: u32, |
| 48 | + control_port: u32, |
| 49 | + mem: GuestMemoryMmap, |
| 50 | + queue: Arc<Mutex<VirtQueue>>, |
| 51 | + rxq: Arc<Mutex<MuxerRxQ>>, |
| 52 | + ) -> Result<Self, ProxyError> { |
| 53 | + if family != defs::LINUX_AF_INET && family != defs::LINUX_AF_INET6 { |
| 54 | + return Err(ProxyError::InvalidFamily); |
| 55 | + } |
| 56 | + |
| 57 | + Ok(Self { |
| 58 | + id, |
| 59 | + cid, |
| 60 | + family, |
| 61 | + local_port, |
| 62 | + peer_port, |
| 63 | + control_port, |
| 64 | + dgram_proxy: TsiDgramProxyWindows::new(), |
| 65 | + status: ProxyStatus::Idle, |
| 66 | + mem, |
| 67 | + queue, |
| 68 | + rxq, |
| 69 | + pending_sendto: None, |
| 70 | + }) |
| 71 | + } |
| 72 | + |
| 73 | + fn push_packet(&mut self, pkt: VsockPacket) { |
| 74 | + push_packet( |
| 75 | + &self.mem, |
| 76 | + &self.queue, |
| 77 | + &self.rxq, |
| 78 | + pkt, |
| 79 | + self.cid, |
| 80 | + self.local_port, |
| 81 | + self.peer_port, |
| 82 | + ); |
| 83 | + } |
| 84 | + |
| 85 | + fn send_response(&mut self, op: u16, result: i32) { |
| 86 | + let mut pkt = VsockPacket::new_op_response_pkt(self.local_port, self.control_port, op); |
| 87 | + pkt.set_op_result(result); |
| 88 | + self.push_packet(pkt); |
| 89 | + } |
| 90 | + |
| 91 | + fn parse_address(addr_str: &str, family: u16) -> Result<std::net::SocketAddr, ProxyError> { |
| 92 | + use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}; |
| 93 | + |
| 94 | + let parts: Vec<&str> = addr_str.rsplitn(2, ':').collect(); |
| 95 | + if parts.len() != 2 { |
| 96 | + return Err(ProxyError::InvalidFamily); |
| 97 | + } |
| 98 | + |
| 99 | + let port: u16 = parts[0].parse().map_err(|_| ProxyError::InvalidFamily)?; |
| 100 | + let ip_str = parts[1]; |
| 101 | + |
| 102 | + let addr = match family { |
| 103 | + defs::LINUX_AF_INET => { |
| 104 | + let ip: Ipv4Addr = ip_str.parse().map_err(|_| ProxyError::InvalidFamily)?; |
| 105 | + SocketAddr::new(IpAddr::V4(ip), port) |
| 106 | + } |
| 107 | + defs::LINUX_AF_INET6 => { |
| 108 | + let ip: Ipv6Addr = ip_str.parse().map_err(|_| ProxyError::InvalidFamily)?; |
| 109 | + SocketAddr::new(IpAddr::V6(ip), port) |
| 110 | + } |
| 111 | + _ => return Err(ProxyError::InvalidFamily), |
| 112 | + }; |
| 113 | + |
| 114 | + Ok(addr) |
| 115 | + } |
| 116 | +} |
| 117 | + |
| 118 | +impl AsRawHandle for TsiDgramProxyWindowsWrapper { |
| 119 | + fn as_raw_handle(&self) -> RawHandle { |
| 120 | + std::ptr::null_mut() |
| 121 | + } |
| 122 | +} |
| 123 | + |
| 124 | +impl Proxy for TsiDgramProxyWindowsWrapper { |
| 125 | + fn id(&self) -> u64 { |
| 126 | + self.id |
| 127 | + } |
| 128 | + |
| 129 | + fn status(&self) -> ProxyStatus { |
| 130 | + self.status |
| 131 | + } |
| 132 | + |
| 133 | + fn connect(&mut self, pkt: &VsockPacket, req: TsiConnectReq) -> ProxyUpdate { |
| 134 | + // DGRAM sockets don't connect, just bind |
| 135 | + let mut update = ProxyUpdate::default(); |
| 136 | + let addr_str = String::from_utf8_lossy(&req.addr); |
| 137 | + |
| 138 | + match Self::parse_address(&addr_str, self.family) { |
| 139 | + Ok(addr) => { |
| 140 | + match self.dgram_proxy.bind(&addr) { |
| 141 | + Ok(_) => { |
| 142 | + self.status = ProxyStatus::Connected; |
| 143 | + update.signal_queue = true; |
| 144 | + } |
| 145 | + Err(_) => { |
| 146 | + self.status = ProxyStatus::Closed; |
| 147 | + update.remove_proxy = ProxyRemoval::Immediate; |
| 148 | + } |
| 149 | + } |
| 150 | + } |
| 151 | + Err(_) => { |
| 152 | + self.status = ProxyStatus::Closed; |
| 153 | + update.remove_proxy = ProxyRemoval::Immediate; |
| 154 | + } |
| 155 | + } |
| 156 | + |
| 157 | + update |
| 158 | + } |
| 159 | + |
| 160 | + fn confirm_connect(&mut self, _pkt: &VsockPacket) -> Option<ProxyUpdate> { |
| 161 | + None |
| 162 | + } |
| 163 | + |
| 164 | + fn getpeername(&mut self, _pkt: &VsockPacket) { |
| 165 | + let mut rsp = TsiGetnameRsp::default(); |
| 166 | + rsp.result = -1; |
| 167 | + let mut rsp_pkt = VsockPacket::new_op_response_pkt( |
| 168 | + self.local_port, |
| 169 | + self.control_port, |
| 170 | + uapi::VSOCK_OP_GETPEERNAME, |
| 171 | + ); |
| 172 | + rsp_pkt.set_op_payload(&rsp); |
| 173 | + self.push_packet(rsp_pkt); |
| 174 | + } |
| 175 | + |
| 176 | + fn sendmsg(&mut self, _pkt: &VsockPacket) -> ProxyUpdate { |
| 177 | + ProxyUpdate::default() |
| 178 | + } |
| 179 | + |
| 180 | + fn sendto_addr(&mut self, req: TsiSendtoAddr) -> ProxyUpdate { |
| 181 | + let addr_str = String::from_utf8_lossy(&req.addr); |
| 182 | + if let Ok(addr) = Self::parse_address(&addr_str, self.family) { |
| 183 | + self.pending_sendto = Some(addr); |
| 184 | + } |
| 185 | + ProxyUpdate::default() |
| 186 | + } |
| 187 | + |
| 188 | + fn sendto_data(&mut self, pkt: &VsockPacket) { |
| 189 | + if let Some(addr) = self.pending_sendto.take() { |
| 190 | + let payload = pkt.data(); |
| 191 | + let _ = self.dgram_proxy.sendto(payload, &addr); |
| 192 | + } |
| 193 | + } |
| 194 | + |
| 195 | + fn listen( |
| 196 | + &mut self, |
| 197 | + _pkt: &VsockPacket, |
| 198 | + _req: TsiListenReq, |
| 199 | + _host_port_map: &Option<HashMap<u16, u16>>, |
| 200 | + ) -> ProxyUpdate { |
| 201 | + ProxyUpdate::default() |
| 202 | + } |
| 203 | + |
| 204 | + fn accept(&mut self, _req: TsiAcceptReq) -> ProxyUpdate { |
| 205 | + ProxyUpdate::default() |
| 206 | + } |
| 207 | + |
| 208 | + fn update_peer_credit(&mut self, _pkt: &VsockPacket) -> ProxyUpdate { |
| 209 | + ProxyUpdate::default() |
| 210 | + } |
| 211 | + |
| 212 | + fn push_op_request(&self) {} |
| 213 | + |
| 214 | + fn process_op_response(&mut self, _pkt: &VsockPacket) -> ProxyUpdate { |
| 215 | + ProxyUpdate::default() |
| 216 | + } |
| 217 | + |
| 218 | + fn enqueue_accept(&mut self) {} |
| 219 | + |
| 220 | + fn push_accept_rsp(&self, _result: i32) {} |
| 221 | + |
| 222 | + fn shutdown(&mut self, _pkt: &VsockPacket) { |
| 223 | + self.status = ProxyStatus::Closed; |
| 224 | + } |
| 225 | + |
| 226 | + fn release(&mut self) -> ProxyUpdate { |
| 227 | + self.status = ProxyStatus::Closed; |
| 228 | + let mut update = ProxyUpdate::default(); |
| 229 | + update.remove_proxy = ProxyRemoval::Immediate; |
| 230 | + update |
| 231 | + } |
| 232 | + |
| 233 | + fn process_event(&mut self, evset: EventSet) -> ProxyUpdate { |
| 234 | + let mut update = ProxyUpdate::default(); |
| 235 | + |
| 236 | + if evset.contains(EventSet::IN) && self.status == ProxyStatus::Connected { |
| 237 | + let mut buf = vec![0u8; 65536]; |
| 238 | + match self.dgram_proxy.recvfrom(&mut buf) { |
| 239 | + Ok((bytes_read, Some(from_addr))) if bytes_read > 0 => { |
| 240 | + let mut data_pkt = VsockPacket::new_data_pkt( |
| 241 | + self.local_port, |
| 242 | + self.peer_port, |
| 243 | + &buf[..bytes_read], |
| 244 | + ); |
| 245 | + self.push_packet(data_pkt); |
| 246 | + update.signal_queue = true; |
| 247 | + } |
| 248 | + _ => {} |
| 249 | + } |
| 250 | + } |
| 251 | + |
| 252 | + update |
| 253 | + } |
| 254 | +} |
| 255 | + |
| 256 | +#[cfg(target_os = "windows")] |
| 257 | +impl std::os::unix::io::AsRawFd for TsiDgramProxyWindowsWrapper { |
| 258 | + fn as_raw_fd(&self) -> std::os::unix::io::RawFd { |
| 259 | + -1 |
| 260 | + } |
| 261 | +} |
0 commit comments