use super::keymethod::{self, ClientKeyMethod2};
use super::packet::{ControlFrame, Opcode};
use super::reliable::{fragment, ReliableReceiver, ReliableSender};
use super::tls_channel;
use crate::server::connection::ConnectionId;
use crate::utils::clock::Instant;
use anyhow::{Context, Result};
use std::collections::HashMap;
use std::io::{Read, Write};
use std::net::SocketAddr;
use std::sync::Arc;
use tokio::sync::Mutex;
const MAX_PLAINTEXT_BUFFER: usize = 64 * 1024;
#[derive(Debug)]
pub enum SessionEvent {
TlsEstablished { version: String, cipher: String },
ClientKeyExchange(Box<ClientKeyMethod2>),
ControlMessage(String),
TlsFailed(String),
}
pub struct ControlSession {
pub connection_id: ConnectionId,
pub client_session_id: u64,
pub server_session_id: u64,
pub key_id: u8,
send: ReliableSender,
recv: ReliableReceiver,
tls: Option<rustls::ServerConnection>,
tls_reported: bool,
tls_dead: bool,
plaintext: Vec<u8>,
key_exchange_seen: bool,
pub answered_key_exchange: bool,
pub bytes_sent: u64,
pub bytes_received: u64,
}
impl ControlSession {
pub fn new(
connection_id: ConnectionId,
client_session_id: u64,
server_session_id: u64,
key_id: u8,
client_reset_packet_id: u32,
tls_config: Arc<rustls::ServerConfig>,
) -> Result<Self> {
let tls = rustls::ServerConnection::new(tls_config)
.context("Failed to create the OpenVPN control-channel TLS session")?;
let mut send = ReliableSender::new();
send.queue(
Opcode::ControlHardResetServerV2,
vec![client_reset_packet_id],
Vec::new(),
);
Ok(ControlSession {
connection_id,
client_session_id,
server_session_id,
key_id,
send,
recv: ReliableReceiver::new(client_reset_packet_id.saturating_add(1)),
tls: Some(tls),
tls_reported: false,
tls_dead: false,
plaintext: Vec::new(),
key_exchange_seen: false,
answered_key_exchange: false,
bytes_sent: 0,
bytes_received: 0,
})
}
pub fn on_client_reset_retransmit(&mut self) {
self.send.mark_all_due();
}
pub fn on_ack_frame(&mut self, frame: &ControlFrame) {
self.send.on_ack(&frame.ack_packet_ids);
}
pub fn on_control_frame(&mut self, frame: ControlFrame) -> Vec<SessionEvent> {
self.send.on_ack(&frame.ack_packet_ids);
self.bytes_received = self
.bytes_received
.saturating_add(frame.payload.len() as u64);
let packet_id = match frame.packet_id {
Some(id) => id,
None => return Vec::new(),
};
let mut events = Vec::new();
for payload in self.recv.accept(packet_id, frame.payload) {
if payload.is_empty() {
continue;
}
events.extend(self.feed_tls(&payload));
}
events
}
fn feed_tls(&mut self, payload: &[u8]) -> Vec<SessionEvent> {
if self.tls_dead {
return Vec::new();
}
let tls = match self.tls.as_mut() {
Some(t) => t,
None => return Vec::new(),
};
let mut cursor = std::io::Cursor::new(payload);
while (cursor.position() as usize) < payload.len() {
match tls.read_tls(&mut cursor) {
Ok(0) => break,
Ok(_) => {}
Err(e) => {
self.tls_dead = true;
return vec![SessionEvent::TlsFailed(format!(
"TLS record could not be buffered: {}",
e
))];
}
}
if let Err(e) = tls.process_new_packets() {
self.tls_dead = true;
return vec![SessionEvent::TlsFailed(e.to_string())];
}
}
let mut events = Vec::new();
if !self.tls_reported && !tls.is_handshaking() {
self.tls_reported = true;
events.push(SessionEvent::TlsEstablished {
version: tls_channel::protocol_version_name(tls),
cipher: tls_channel::cipher_suite_name(tls),
});
}
let mut chunk = [0u8; 4096];
loop {
match tls.reader().read(&mut chunk) {
Ok(0) => break,
Ok(n) => self.plaintext.extend_from_slice(&chunk[..n]),
Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => break,
Err(e) => {
self.tls_dead = true;
events.push(SessionEvent::TlsFailed(format!(
"control-channel plaintext read failed: {}",
e
)));
return events;
}
}
}
events.extend(self.consume_plaintext());
if self.plaintext.len() > MAX_PLAINTEXT_BUFFER {
self.tls_dead = true;
let held = self.plaintext.len();
self.plaintext.clear();
events.push(SessionEvent::TlsFailed(format!(
"peer sent {held} bytes of control-channel data without a complete message (limit {MAX_PLAINTEXT_BUFFER}); dropping the session rather than buffering without bound"
)));
}
events
}
fn consume_plaintext(&mut self) -> Vec<SessionEvent> {
let mut events = Vec::new();
loop {
if !self.key_exchange_seen {
match keymethod::parse_client_key_method_2(&self.plaintext) {
Ok(Some((msg, consumed))) => {
self.plaintext.drain(..consumed);
self.key_exchange_seen = true;
events.push(SessionEvent::ClientKeyExchange(Box::new(msg)));
}
Ok(None) => break,
Err(e) => {
self.tls_dead = true;
self.plaintext.clear();
events.push(SessionEvent::TlsFailed(e.to_string()));
break;
}
}
} else if let Some(pos) = self.plaintext.iter().position(|b| *b == 0) {
let msg = String::from_utf8_lossy(&self.plaintext[..pos]).into_owned();
self.plaintext.drain(..=pos);
events.push(SessionEvent::ControlMessage(msg));
} else {
break;
}
}
events
}
pub fn write_key_method_2_answer(&mut self, client_options: &str) -> Result<String> {
let tls = self
.tls
.as_mut()
.context("no TLS session on this control channel")?;
let random1: [u8; 32] = rand::random();
let random2: [u8; 32] = rand::random();
let options = keymethod::server_options_from_client(client_options);
let message = keymethod::build_server_key_method_2(&random1, &random2, &options);
tls.writer()
.write_all(&message)
.context("Failed to queue the key-method-2 answer on the control channel")?;
self.answered_key_exchange = true;
Ok(options)
}
pub fn drain_datagrams(&mut self, now: Instant) -> Vec<Vec<u8>> {
self.queue_tls_records();
let mut out = Vec::new();
while self.recv.has_pending_acks() {
let acks = self.recv.take_acks();
if acks.is_empty() {
break;
}
out.push(self.serialize(Opcode::AckV1, &acks, None, &[]));
}
for packet in self.send.take_due(now) {
out.push(self.serialize(
packet.opcode,
&packet.acks,
Some(packet.packet_id),
&packet.payload,
));
}
self.bytes_sent = self
.bytes_sent
.saturating_add(out.iter().map(|d| d.len() as u64).sum::<u64>());
out
}
fn queue_tls_records(&mut self) {
let tls = match self.tls.as_mut() {
Some(t) => t,
None => return,
};
if !tls.wants_write() {
return;
}
let mut records = Vec::new();
while tls.wants_write() {
match tls.write_tls(&mut records) {
Ok(0) => break,
Ok(_) => {}
Err(_) => break,
}
}
for chunk in fragment(&records) {
self.send.queue(Opcode::ControlV1, Vec::new(), chunk);
}
}
fn serialize(
&self,
opcode: Opcode,
acks: &[u32],
packet_id: Option<u32>,
payload: &[u8],
) -> Vec<u8> {
ControlFrame {
opcode,
key_id: self.key_id,
session_id: self.server_session_id,
ack_packet_ids: acks.to_vec(),
remote_session_id: if acks.is_empty() {
None
} else {
Some(self.client_session_id)
},
packet_id,
payload: payload.to_vec(),
}
.serialize()
.to_vec()
}
pub fn is_dead(&self) -> bool {
self.send.is_exhausted()
}
}
pub struct SessionManager {
sessions: Mutex<HashMap<SocketAddr, ControlSession>>,
}
impl SessionManager {
pub fn new() -> Self {
SessionManager {
sessions: Mutex::new(HashMap::new()),
}
}
pub async fn insert(&self, addr: SocketAddr, session: ControlSession) {
self.sessions.lock().await.insert(addr, session);
}
pub async fn remove(&self, addr: &SocketAddr) -> bool {
self.sessions.lock().await.remove(addr).is_some()
}
pub async fn with<F, T>(&self, addr: &SocketAddr, f: F) -> Option<T>
where
F: FnOnce(&mut ControlSession) -> T,
{
self.sessions.lock().await.get_mut(addr).map(f)
}
pub async fn drain_all(&self, now: Instant) -> (Vec<(SocketAddr, Vec<u8>)>, Vec<SocketAddr>) {
let mut out = Vec::new();
let mut dead = Vec::new();
let mut guard = self.sessions.lock().await;
for (addr, session) in guard.iter_mut() {
if session.is_dead() {
dead.push(*addr);
continue;
}
for datagram in session.drain_datagrams(now) {
out.push((*addr, datagram));
}
}
(out, dead)
}
}
impl Default for SessionManager {
fn default() -> Self {
Self::new()
}
}