turn_rs/processor/mod.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416
pub mod allocate;
pub mod binding;
pub mod channel_bind;
pub mod channel_data;
pub mod create_permission;
pub mod indication;
pub mod refresh;
use crate::{router::Router, Observer, StunClass};
use std::{net::SocketAddr, sync::Arc};
use bytes::BytesMut;
use faster_stun::attribute::*;
use faster_stun::*;
pub struct Env {
pub interface: SocketAddr,
pub realm: Arc<String>,
pub router: Arc<Router>,
pub external: Arc<SocketAddr>,
pub externals: Arc<Vec<SocketAddr>>,
pub observer: Arc<dyn Observer>,
}
/// process udp message
/// and return message + address.
pub struct Processor {
env: Arc<Env>,
decoder: Decoder,
buf: BytesMut,
}
impl Processor {
pub(crate) fn new(
interface: SocketAddr,
external: SocketAddr,
externals: Arc<Vec<SocketAddr>>,
realm: String,
router: Arc<Router>,
observer: Arc<dyn Observer>,
) -> Self {
Self {
decoder: Decoder::new(),
buf: BytesMut::with_capacity(4096),
env: Arc::new(Env {
external: Arc::new(external),
realm: Arc::new(realm),
externals,
interface,
observer,
router,
}),
}
}
/// process udp data
///
/// receive STUN encoded Bytes,
/// and return any Bytes that can be responded to and the target address.
/// Note: unknown message is not process.
///
/// In a typical configuration, a TURN client is connected to a private
/// network [RFC1918] and, through one or more NATs, to the public
/// Internet. On the public Internet is a TURN server. Elsewhere in the
/// Internet are one or more peers with which the TURN client wishes to
/// communicate. These peers may or may not be behind one or more NATs.
/// The client uses the server as a relay to send packets to these peers
/// and to receive packets from these peers.
///
/// ```text
/// Peer A
/// Server-Reflexive +---------+
/// Transport Address | |
/// 192.0.2.150:32102 | |
/// | /| |
/// TURN | / ^| Peer A |
/// Client's Server | / || |
/// Host Transport Transport | // || |
/// Address Address | // |+---------+
/// 198.51.100.2:49721 192.0.2.15:3478 |+-+ // Peer A
/// | | ||N| / Host Transport
/// | +-+ | ||A|/ Address
/// | | | | v|T| 203.0.113.2:49582
/// | | | | /+-+
/// +---------+| | | |+---------+ / +---------+
/// | || |N| || | // | |
/// | TURN |v | | v| TURN |/ | |
/// | Client |----|A|-------| Server |------------------| Peer B |
/// | | | |^ | |^ ^| |
/// | | |T|| | || || |
/// +---------+ | || +---------+| |+---------+
/// | || | |
/// | || | |
/// +-+| | |
/// | | |
/// | | |
/// Client's | Peer B
/// Server-Reflexive Relayed Transport
/// Transport Address Transport Address Address
/// 192.0.2.1:7000 192.0.2.15:50000 192.0.2.210:49191
///
/// Figure 1
/// ```
///
/// Figure 1 shows a typical deployment. In this figure, the TURN client
/// and the TURN server are separated by a NAT, with the client on the
/// private side and the server on the public side of the NAT. This NAT
/// is assumed to be a "bad" NAT; for example, it might have a mapping
/// property of "address-and-port-dependent mapping" (see [RFC4787]).
///
/// The client talks to the server from a (IP address, port) combination
/// called the client's "host transport address". (The combination of an
/// IP address and port is called a "transport address".)
///
/// The client sends TURN messages from its host transport address to a
/// transport address on the TURN server that is known as the "TURN
/// server transport address". The client learns the TURN server
/// transport address through some unspecified means (e.g.,
/// configuration), and this address is typically used by many clients
/// simultaneously.
///
/// Since the client is behind a NAT, the server sees packets from the
/// client as coming from a transport address on the NAT itself. This
/// address is known as the client's "server-reflexive transport
/// address"; packets sent by the server to the client's server-reflexive
/// transport address will be forwarded by the NAT to the client's host
/// transport address.
///
/// The client uses TURN commands to create and manipulate an ALLOCATION
/// on the server. An allocation is a data structure on the server.
/// This data structure contains, amongst other things, the relayed
/// transport address for the allocation. The relayed transport address
/// is the transport address on the server that peers can use to have the
/// server relay data to the client. An allocation is uniquely
/// identified by its relayed transport address.
///
/// Once an allocation is created, the client can send application data
/// to the server along with an indication of to which peer the data is
/// to be sent, and the server will relay this data to the intended peer.
/// The client sends the application data to the server inside a TURN
/// message; at the server, the data is extracted from the TURN message
/// and sent to the peer in a UDP datagram. In the reverse direction, a
/// peer can send application data in a UDP datagram to the relayed
/// transport address for the allocation; the server will then
/// encapsulate this data inside a TURN message and send it to the client
/// along with an indication of which peer sent the data. Since the TURN
/// message always contains an indication of which peer the client is
/// communicating with, the client can use a single allocation to
/// communicate with multiple peers.
///
/// When the peer is behind a NAT, the client must identify the peer
/// using its server-reflexive transport address rather than its host
/// transport address. For example, to send application data to Peer A
/// in the example above, the client must specify 192.0.2.150:32102 (Peer
/// A's server-reflexive transport address) rather than 203.0.113.2:49582
/// (Peer A's host transport address).
///
/// Each allocation on the server belongs to a single client and has
/// either one or two relayed transport addresses that are used only by
/// that allocation. Thus, when a packet arrives at a relayed transport
/// address on the server, the server knows for which client the data is
/// intended.
///
/// The client may have multiple allocations on a server at the same
/// time.
pub async fn process<'c, 'a: 'c>(
&'a mut self,
b: &'a [u8],
addr: SocketAddr,
) -> Result<Option<Response<'c>>, StunError> {
let ctx = Context {
env: self.env.clone(),
addr,
};
Ok(match self.decoder.decode(b)? {
Payload::ChannelData(x) => channel_data::process(ctx, x),
Payload::Message(x) => Self::message_process(ctx, x, &mut self.buf).await?,
})
}
/// process stun message
///
/// TURN is an extension to STUN. All TURN messages, with the exception
/// of the ChannelData message, are STUN-formatted messages. All the
/// base processing rules described in [RFC8489] apply to STUN-formatted
/// messages. This means that all the message-forming and message-
/// processing descriptions in this document are implicitly prefixed with
/// the rules of [RFC8489].
///
/// [RFC8489] specifies an authentication mechanism called the "long-term
/// credential mechanism". TURN servers and clients MUST implement this
/// mechanism, and the authentication options are discussed in
/// Section 7.2.
///
/// Note that the long-term credential mechanism applies only to requests
/// and cannot be used to authenticate indications; thus, indications in
/// TURN are never authenticated. If the server requires requests to be
/// authenticated, then the server's administrator MUST choose a realm
/// value that will uniquely identify the username and password
/// combination that the client must use, even if the client uses
/// multiple servers under different administrations. The server's
/// administrator MAY choose to allocate a unique username to each
/// client, or it MAY choose to allocate the same username to more than
/// one client (for example, to all clients from the same department or
/// company). For each Allocate request, the server SHOULD generate a
/// new random nonce when the allocation is first attempted following the
/// randomness recommendations in [RFC4086] and SHOULD expire the nonce
/// at least once every hour during the lifetime of the allocation. The
/// server uses the mechanism described in Section 9.2 of [RFC8489] to
/// indicate that it supports [RFC8489].
///
/// All requests after the initial Allocate must use the same username as
/// that used to create the allocation to prevent attackers from
/// hijacking the client's allocation.
///
/// Specifically, if:
///
/// * the server requires the use of the long-term credential mechanism, and;
///
/// * a non-Allocate request passes authentication under this mechanism, and;
///
/// * the 5-tuple identifies an existing allocation, but;
///
/// * the request does not use the same username as used to create the
/// allocation,
///
/// then the request MUST be rejected with a 441 (Wrong Credentials)
/// error.
///
/// When a TURN message arrives at the server from the client, the server
/// uses the 5-tuple in the message to identify the associated
/// allocation. For all TURN messages (including ChannelData) EXCEPT an
/// Allocate request, if the 5-tuple does not identify an existing
/// allocation, then the message MUST either be rejected with a 437
/// Allocation Mismatch error (if it is a request) or be silently ignored
/// (if it is an indication or a ChannelData message). A client
/// receiving a 437 error response to a request other than Allocate MUST
/// assume the allocation no longer exists.
///
/// [RFC8489] defines a number of attributes, including the SOFTWARE and
/// FINGERPRINT attributes. The client SHOULD include the SOFTWARE
/// attribute in all Allocate and Refresh requests and MAY include it in
/// any other requests or indications. The server SHOULD include the
/// SOFTWARE attribute in all Allocate and Refresh responses (either
/// success or failure) and MAY include it in other responses or
/// indications. The client and the server MAY include the FINGERPRINT
/// attribute in any STUN-formatted messages defined in this document.
///
/// TURN does not use the backwards-compatibility mechanism described in
/// [RFC8489].
///
/// TURN, as defined in this specification, supports both IPv4 and IPv6.
/// IPv6 support in TURN includes IPv4-to-IPv6, IPv6-to-IPv6, and IPv6-
/// to-IPv4 relaying. When only a single address type is desired, the
/// REQUESTED-ADDRESS-FAMILY attribute is used to explicitly request the
/// address type the TURN server will allocate (e.g., an IPv4-only node
/// may request the TURN server to allocate an IPv6 address). If both
/// IPv4 and IPv6 are desired, the single ADDITIONAL-ADDRESS-FAMILY
/// attribute indicates a request to the server to allocate one IPv4 and
/// one IPv6 relay address in a single Allocate request. This saves
/// local ports on the client and reduces the number of messages sent
/// between the client and the TURN server.
///
/// By default, TURN runs on the same ports as STUN: 3478 for TURN over
/// UDP and TCP, and 5349 for TURN over (D)TLS. However, TURN has its
/// own set of Service Record (SRV) names: "turn" for UDP and TCP, and
/// "turns" for (D)TLS. Either the DNS resolution procedures or the
/// ALTERNATE-SERVER procedures, both described in Section 7, can be used
/// to run TURN on a different port.
///
/// To ensure interoperability, a TURN server MUST support the use of UDP
/// transport between the client and the server, and it SHOULD support
/// the use of TCP, TLS-over-TCP, and DTLS-over-UDP transports.
///
/// When UDP or DTLS-over-UDP transport is used between the client and
/// the server, the client will retransmit a request if it does not
/// receive a response within a certain timeout period. Because of this,
/// the server may receive two (or more) requests with the same 5-tuple
/// and same transaction id. STUN requires that the server recognize
/// this case and treat the request as idempotent (see [RFC8489]). Some
/// implementations may choose to meet this requirement by remembering
/// all received requests and the corresponding responses for 40 seconds
/// (Section 6.3.1 of [RFC8489]). Other implementations may choose to
/// reprocess the request and arrange that such reprocessing returns
/// essentially the same response. To aid implementors who choose the
/// latter approach (the so-called "stateless stack approach"), this
/// specification includes some implementation notes on how this might be
/// done. Implementations are free to choose either approach or some
/// other approach that gives the same results.
///
/// To mitigate either intentional or unintentional denial-of-service
/// attacks against the server by clients with valid usernames and
/// passwords, it is RECOMMENDED that the server impose limits on both
/// the number of allocations active at one time for a given username and
/// on the amount of bandwidth those allocations can use. The server
/// should reject new allocations that would exceed the limit on the
/// allowed number of allocations active at one time with a 486
/// (Allocation Quota Exceeded) (see Section 7.2), and since UDP does not
/// include a congestion control mechanism, it should discard application
/// data traffic that exceeds the bandwidth quota.
#[rustfmt::skip]
#[inline(always)]
async fn message_process<'c>(
ctx: Context,
m: MessageReader<'_, '_>,
w: &'c mut BytesMut,
) -> Result<Option<Response<'c>>, StunError> {
match m.method {
Method::Binding(Kind::Request) => binding::process(ctx, m, w),
Method::Allocate(Kind::Request) => allocate::process(ctx, m, w).await,
Method::CreatePermission(Kind::Request) => create_permission::process(ctx, m, w).await,
Method::ChannelBind(Kind::Request) => channel_bind::process(ctx, m, w).await,
Method::Refresh(Kind::Request) => refresh::process(ctx, m, w).await,
Method::SendIndication => indication::process(ctx, m, w).await,
_ => Ok(None),
}
}
}
pub struct Response<'a> {
pub data: &'a [u8],
pub kind: StunClass,
pub relay: Option<SocketAddr>,
pub interface: Option<SocketAddr>,
}
impl<'a> Response<'a> {
#[inline(always)]
pub(crate) fn new(
data: &'a [u8],
kind: StunClass,
relay: Option<SocketAddr>,
interface: Option<SocketAddr>,
) -> Self {
Self {
data,
kind,
relay,
interface,
}
}
}
pub struct Context {
pub env: Arc<Env>,
pub addr: SocketAddr,
}
/// The key for the HMAC depends on whether long-term or short-term
/// credentials are in use. For long-term credentials, the key is 16
/// bytes:
///
/// key = MD5(username ":" realm ":" SASLprep(password))
///
/// That is, the 16-byte key is formed by taking the MD5 hash of the
/// result of concatenating the following five fields: (1) the username,
/// with any quotes and trailing nulls removed, as taken from the
/// USERNAME attribute (in which case SASLprep has already been applied);
/// (2) a single colon; (3) the realm, with any quotes and trailing nulls
/// removed; (4) a single colon; and (5) the password, with any trailing
/// nulls removed and after processing using SASLprep. For example, if
/// the username was 'user', the realm was 'realm', and the password was
/// 'pass', then the 16-byte HMAC key would be the result of performing
/// an MD5 hash on the string 'user:realm:pass', the resulting hash being
/// 0x8493fbc53ba582fb4c044c456bdc40eb.
///
/// For short-term credentials:
///
/// key = SASLprep(password)
///
/// where MD5 is defined in RFC 1321 [RFC1321] and SASLprep() is defined
/// in RFC 4013 [RFC4013].
///
/// The structure of the key when used with long-term credentials
/// facilitates deployment in systems that also utilize SIP. Typically,
/// SIP systems utilizing SIP's digest authentication mechanism do not
/// actually store the password in the database. Rather, they store a
/// value called H(A1), which is equal to the key defined above.
///
/// Based on the rules above, the hash used to construct MESSAGE-
/// INTEGRITY includes the length field from the STUN message header.
/// Prior to performing the hash, the MESSAGE-INTEGRITY attribute MUST be
/// inserted into the message (with dummy content). The length MUST then
/// be set to point to the length of the message up to, and including,
/// the MESSAGE-INTEGRITY attribute itself, but excluding any attributes
/// after it. Once the computation is performed, the value of the
/// MESSAGE-INTEGRITY attribute can be filled in, and the value of the
/// length in the STUN header can be set to its correct value -- the
/// length of the entire message. Similarly, when validating the
/// MESSAGE-INTEGRITY, the length field should be adjusted to point to
/// the end of the MESSAGE-INTEGRITY attribute prior to calculating the
/// HMAC. Such adjustment is necessary when attributes, such as
/// FINGERPRINT, appear after MESSAGE-INTEGRITY.
#[inline(always)]
pub(crate) async fn verify_message<'a>(
ctx: &Context,
reader: &MessageReader<'a, '_>,
) -> Option<(&'a str, Arc<[u8; 16]>)> {
let username = reader.get::<UserName>()?;
let key = ctx
.env
.router
.get_key(&ctx.addr, &ctx.env.interface, &ctx.env.external, username)
.await?;
reader.integrity(&key).ok()?;
Some((username, key))
}
/// Check if the ip address belongs to the current turn server.
#[inline(always)]
pub(crate) fn ip_is_local(ctx: &Context, addr: &SocketAddr) -> bool {
ctx.env.externals.iter().any(|item| item.ip() == addr.ip())
}