Skip to main content

raknet_rust/handshake/
open_connection.rs

1use std::net::SocketAddr;
2
3use bytes::Buf;
4
5use crate::error::DecodeError;
6use crate::protocol::codec::RaknetCodec;
7use crate::protocol::constants::Magic;
8
9#[derive(Debug, Clone)]
10pub struct OpenConnectionRequest1 {
11    pub protocol_version: u8,
12    pub mtu: u16,
13    pub magic: Magic,
14}
15
16#[derive(Debug, Clone)]
17pub struct OpenConnectionReply1 {
18    pub server_guid: u64,
19    pub mtu: u16,
20    pub cookie: Option<u32>,
21    pub magic: Magic,
22}
23
24#[derive(Debug, Clone)]
25pub struct OpenConnectionRequest2 {
26    pub server_addr: SocketAddr,
27    pub mtu: u16,
28    pub client_guid: u64,
29    pub cookie: Option<u32>,
30    pub client_proof: bool,
31    pub parse_path: Request2ParsePath,
32    pub magic: Magic,
33}
34
35#[derive(Debug, Clone, Copy, PartialEq, Eq)]
36pub enum Request2ParsePath {
37    StrictNoCookie,
38    StrictWithCookie,
39    AmbiguousPreferredNoCookie,
40    AmbiguousPreferredWithCookie,
41    LegacyHeuristic,
42}
43
44#[derive(Debug, Clone)]
45pub struct OpenConnectionReply2 {
46    pub server_guid: u64,
47    pub server_addr: SocketAddr,
48    pub mtu: u16,
49    pub use_encryption: bool,
50    pub magic: Magic,
51}
52
53pub(super) fn decode_request_1(
54    src: &mut impl Buf,
55    expected_magic: Magic,
56) -> Result<OpenConnectionRequest1, DecodeError> {
57    let magic = super::validate_magic(Magic::decode_raknet(src)?, expected_magic)?;
58    let protocol_version = u8::decode_raknet(src)?;
59    let padding_len = src.remaining();
60    let _ = src.copy_to_bytes(padding_len);
61
62    let mtu = (padding_len + 18) as u16;
63    Ok(OpenConnectionRequest1 {
64        protocol_version,
65        mtu,
66        magic,
67    })
68}
69
70pub(super) fn decode_reply_1(
71    src: &mut impl Buf,
72    expected_magic: Magic,
73) -> Result<OpenConnectionReply1, DecodeError> {
74    let magic = super::validate_magic(Magic::decode_raknet(src)?, expected_magic)?;
75    let server_guid = u64::decode_raknet(src)?;
76    let has_cookie = bool::decode_raknet(src)?;
77    let cookie = if has_cookie {
78        Some(u32::decode_raknet(src)?)
79    } else {
80        None
81    };
82    let mtu = u16::decode_raknet(src)?;
83
84    Ok(OpenConnectionReply1 {
85        server_guid,
86        mtu,
87        cookie,
88        magic,
89    })
90}
91
92pub(super) fn decode_request_2(
93    src: &mut impl Buf,
94    expected_magic: Magic,
95) -> Result<OpenConnectionRequest2, DecodeError> {
96    let magic = super::validate_magic(Magic::decode_raknet(src)?, expected_magic)?;
97    let remaining = src.copy_to_bytes(src.remaining());
98    let body = &remaining[..];
99
100    let strict_no_cookie = parse_request_2_candidate(body, false, true);
101    let strict_with_cookie = parse_request_2_candidate(body, true, true);
102
103    match (strict_no_cookie, strict_with_cookie) {
104        (Ok(candidate), Err(_)) => {
105            Ok(candidate.into_request(magic, Request2ParsePath::StrictNoCookie))
106        }
107        (Err(_), Ok(candidate)) => {
108            Ok(candidate.into_request(magic, Request2ParsePath::StrictWithCookie))
109        }
110        (Ok(no_cookie), Ok(with_cookie)) => {
111            let path = if matches!(body.first().copied(), Some(4 | 6)) {
112                Request2ParsePath::AmbiguousPreferredNoCookie
113            } else {
114                Request2ParsePath::AmbiguousPreferredWithCookie
115            };
116            let chosen = match path {
117                Request2ParsePath::AmbiguousPreferredNoCookie => no_cookie,
118                Request2ParsePath::AmbiguousPreferredWithCookie => with_cookie,
119                _ => unreachable!("ambiguous path must choose one strict candidate"),
120            };
121            Ok(chosen.into_request(magic, path))
122        }
123        (Err(_), Err(_)) => {
124            let legacy = parse_request_2_legacy(body)?;
125            Ok(legacy.into_request(magic, Request2ParsePath::LegacyHeuristic))
126        }
127    }
128}
129
130#[derive(Debug, Clone, Copy)]
131struct Request2Candidate {
132    server_addr: SocketAddr,
133    mtu: u16,
134    client_guid: u64,
135    cookie: Option<u32>,
136    client_proof: bool,
137}
138
139impl Request2Candidate {
140    fn into_request(self, magic: Magic, parse_path: Request2ParsePath) -> OpenConnectionRequest2 {
141        OpenConnectionRequest2 {
142            server_addr: self.server_addr,
143            mtu: self.mtu,
144            client_guid: self.client_guid,
145            cookie: self.cookie,
146            client_proof: self.client_proof,
147            parse_path,
148            magic,
149        }
150    }
151}
152
153fn parse_request_2_candidate(
154    mut body: &[u8],
155    with_cookie: bool,
156    strict_bool: bool,
157) -> Result<Request2Candidate, DecodeError> {
158    let mut cookie = None;
159    let mut client_proof = false;
160
161    if with_cookie {
162        if body.len() < 5 {
163            return Err(DecodeError::UnexpectedEof);
164        }
165        cookie = Some(u32::from_be_bytes([body[0], body[1], body[2], body[3]]));
166        let raw_proof = body[4];
167        if strict_bool && raw_proof > 1 {
168            return Err(DecodeError::InvalidRequest2Layout);
169        }
170        client_proof = raw_proof == 1;
171        body = &body[5..];
172    }
173
174    let server_addr = SocketAddr::decode_raknet(&mut body)?;
175    let mtu = u16::decode_raknet(&mut body)?;
176    let client_guid = u64::decode_raknet(&mut body)?;
177    if !body.is_empty() {
178        return Err(DecodeError::InvalidRequest2Layout);
179    }
180
181    Ok(Request2Candidate {
182        server_addr,
183        mtu,
184        client_guid,
185        cookie,
186        client_proof,
187    })
188}
189
190fn parse_request_2_legacy(body: &[u8]) -> Result<Request2Candidate, DecodeError> {
191    let mut with_cookie = false;
192    if let Some(first) = body.first().copied()
193        && first != 4
194        && first != 6
195    {
196        with_cookie = true;
197    }
198    parse_request_2_candidate(body, with_cookie, false)
199}
200
201pub(super) fn decode_reply_2(
202    src: &mut impl Buf,
203    expected_magic: Magic,
204) -> Result<OpenConnectionReply2, DecodeError> {
205    let magic = super::validate_magic(Magic::decode_raknet(src)?, expected_magic)?;
206    let server_guid = u64::decode_raknet(src)?;
207    let server_addr = SocketAddr::decode_raknet(src)?;
208    let mtu = u16::decode_raknet(src)?;
209    let use_encryption = bool::decode_raknet(src)?;
210
211    Ok(OpenConnectionReply2 {
212        server_guid,
213        server_addr,
214        mtu,
215        use_encryption,
216        magic,
217    })
218}