Skip to content

Commit 3f34e2e

Browse files
authored
turn: Support RFC 6156 REQUESTED_ADDRESS_FAMILY attribute (#495)
1 parent ea04e68 commit 3f34e2e

File tree

5 files changed

+166
-4
lines changed

5 files changed

+166
-4
lines changed

turn/src/allocation/allocation_manager.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ impl Manager {
8787
requested_port: u16,
8888
lifetime: Duration,
8989
username: Username,
90+
use_ipv4: bool,
9091
) -> Result<Arc<Allocation>> {
9192
if lifetime == Duration::from_secs(0) {
9293
return Err(Error::ErrLifetimeZero);
@@ -98,7 +99,7 @@ impl Manager {
9899

99100
let (relay_socket, relay_addr) = self
100101
.relay_addr_generator
101-
.allocate_conn(true, requested_port)
102+
.allocate_conn(use_ipv4, requested_port)
102103
.await?;
103104
let mut a = Allocation::new(
104105
turn_socket,

turn/src/allocation/allocation_manager/allocation_manager_test.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ async fn test_packet_handler() -> Result<()> {
7373
0,
7474
DEFAULT_LIFETIME,
7575
TextAttribute::new(ATTR_USERNAME, "user".into()),
76+
true,
7677
)
7778
.await?;
7879

@@ -178,6 +179,7 @@ async fn test_create_allocation_duplicate_five_tuple() -> Result<()> {
178179
0,
179180
DEFAULT_LIFETIME,
180181
TextAttribute::new(ATTR_USERNAME, "user".into()),
182+
true,
181183
)
182184
.await?;
183185

@@ -188,6 +190,7 @@ async fn test_create_allocation_duplicate_five_tuple() -> Result<()> {
188190
0,
189191
DEFAULT_LIFETIME,
190192
TextAttribute::new(ATTR_USERNAME, "user".into()),
193+
true,
191194
)
192195
.await;
193196
assert!(result.is_err(), "expected error, but got ok");
@@ -213,6 +216,7 @@ async fn test_delete_allocation() -> Result<()> {
213216
0,
214217
DEFAULT_LIFETIME,
215218
TextAttribute::new(ATTR_USERNAME, "user".into()),
219+
true,
216220
)
217221
.await?;
218222

@@ -253,6 +257,7 @@ async fn test_allocation_timeout() -> Result<()> {
253257
0,
254258
lifetime,
255259
TextAttribute::new(ATTR_USERNAME, "user".into()),
260+
true,
256261
)
257262
.await?;
258263

@@ -302,6 +307,7 @@ async fn test_manager_close() -> Result<()> {
302307
0,
303308
Duration::from_millis(100),
304309
TextAttribute::new(ATTR_USERNAME, "user".into()),
310+
true,
305311
)
306312
.await?;
307313
allocations.push(a1);
@@ -313,6 +319,7 @@ async fn test_manager_close() -> Result<()> {
313319
0,
314320
Duration::from_millis(200),
315321
TextAttribute::new(ATTR_USERNAME, "user".into()),
322+
true,
316323
)
317324
.await?;
318325
allocations.push(a2);
@@ -350,6 +357,7 @@ async fn test_delete_allocation_by_username() -> Result<()> {
350357
0,
351358
DEFAULT_LIFETIME,
352359
TextAttribute::new(ATTR_USERNAME, "user".into()),
360+
true,
353361
)
354362
.await?;
355363
let _ = m
@@ -359,6 +367,7 @@ async fn test_delete_allocation_by_username() -> Result<()> {
359367
0,
360368
DEFAULT_LIFETIME,
361369
TextAttribute::new(ATTR_USERNAME, "user".into()),
370+
true,
362371
)
363372
.await?;
364373
let _ = m
@@ -368,6 +377,7 @@ async fn test_delete_allocation_by_username() -> Result<()> {
368377
0,
369378
DEFAULT_LIFETIME,
370379
TextAttribute::new(ATTR_USERNAME, "user2".into()),
380+
true,
371381
)
372382
.await?;
373383

turn/src/error.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ pub enum Error {
6363
ErrUnexpectedEof,
6464
#[error("invalid value for requested family attribute")]
6565
ErrInvalidRequestedFamilyValue,
66+
#[error("error code 443: peer address family mismatch")]
67+
ErrPeerAddressFamilyMismatch,
6668
#[error("fake error")]
6769
ErrFakeErr,
6870
#[error("try again")]
@@ -141,6 +143,8 @@ pub enum Error {
141143
ErrNoDontFragmentSupport,
142144
#[error("Request must not contain RESERVATION-TOKEN and EVEN-PORT")]
143145
ErrRequestWithReservationTokenAndEvenPort,
146+
#[error("Request must not contain RESERVATION-TOKEN and REQUESTED-ADDRESS-FAMILY")]
147+
ErrRequestWithReservationTokenAndReqAddressFamily,
144148
#[error("no allocation found")]
145149
ErrNoAllocationFound,
146150
#[error("unable to handle send-indication, no permission added")]

turn/src/server/request.rs

Lines changed: 149 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ use crate::proto::evenport::EvenPort;
3636
use crate::proto::lifetime::*;
3737
use crate::proto::peeraddr::PeerAddress;
3838
use crate::proto::relayaddr::RelayedAddress;
39+
use crate::proto::reqfamily::{
40+
RequestedAddressFamily, REQUESTED_FAMILY_IPV4, REQUESTED_FAMILY_IPV6,
41+
};
3942
use crate::proto::reqtrans::RequestedTransport;
4043
use crate::proto::rsrvtoken::ReservationToken;
4144
use crate::proto::*;
@@ -299,6 +302,7 @@ impl Request {
299302
};
300303
let mut requested_port = 0;
301304
let mut reservation_token = "".to_owned();
305+
let mut use_ipv4 = true;
302306

303307
// 2. The server checks if the 5-tuple is currently in use by an
304308
// existing allocation. If yes, the server rejects the request with
@@ -397,7 +401,8 @@ impl Request {
397401
// the token is not valid for some reason, the server rejects the
398402
// request with a 508 (Insufficient Capacity) error.
399403
let mut reservation_token_attr = ReservationToken::default();
400-
if reservation_token_attr.get_from(m).is_ok() {
404+
let reservation_token_attr_result = reservation_token_attr.get_from(m);
405+
if reservation_token_attr_result.is_ok() {
401406
let mut even_port = EvenPort::default();
402407
if even_port.get_from(m).is_ok() {
403408
let bad_request_msg = build_msg(
@@ -418,6 +423,65 @@ impl Request {
418423
}
419424
}
420425

426+
// RFC 6156, Section 4.2:
427+
//
428+
// If it contains both a RESERVATION-TOKEN and a
429+
// REQUESTED-ADDRESS-FAMILY, the server replies with a 400
430+
// (Bad Request) Allocate error response.
431+
//
432+
// 4.2.1. Unsupported Address Family
433+
// This document defines the following new error response code:
434+
// 440 (Address Family not Supported): The server does not support the
435+
// address family requested by the client.
436+
let mut req_family = RequestedAddressFamily::default();
437+
match req_family.get_from(m) {
438+
Err(err) => {
439+
// Currently, the RequestedAddressFamily::get_from() function returns
440+
// Err::Other only when it is an unsupported address family.
441+
if let stun::Error::Other(_) = err {
442+
let addr_family_not_supported_msg = build_msg(
443+
m.transaction_id,
444+
MessageType::new(METHOD_ALLOCATE, CLASS_ERROR_RESPONSE),
445+
vec![Box::new(ErrorCodeAttribute {
446+
code: CODE_ADDR_FAMILY_NOT_SUPPORTED,
447+
reason: vec![],
448+
})],
449+
)?;
450+
return build_and_send_err(
451+
&self.conn,
452+
self.src_addr,
453+
addr_family_not_supported_msg,
454+
Error::ErrInvalidRequestedFamilyValue,
455+
)
456+
.await;
457+
}
458+
}
459+
Ok(()) => {
460+
if reservation_token_attr_result.is_ok() {
461+
let bad_request_msg = build_msg(
462+
m.transaction_id,
463+
MessageType::new(METHOD_ALLOCATE, CLASS_ERROR_RESPONSE),
464+
vec![Box::new(ErrorCodeAttribute {
465+
code: CODE_BAD_REQUEST,
466+
reason: vec![],
467+
})],
468+
)?;
469+
470+
return build_and_send_err(
471+
&self.conn,
472+
self.src_addr,
473+
bad_request_msg,
474+
Error::ErrRequestWithReservationTokenAndReqAddressFamily,
475+
)
476+
.await;
477+
}
478+
479+
if req_family == REQUESTED_FAMILY_IPV6 {
480+
use_ipv4 = false;
481+
}
482+
}
483+
}
484+
421485
// 6. The server checks if the request contains an EVEN-PORT attribute.
422486
// If yes, then the server checks that it can satisfy the request
423487
// (i.e., can allocate a relayed transport address as described
@@ -475,6 +539,7 @@ impl Request {
475539
requested_port,
476540
lifetime_duration,
477541
username,
542+
use_ipv4,
478543
)
479544
.await
480545
{
@@ -570,6 +635,31 @@ impl Request {
570635
if lifetime_duration != Duration::from_secs(0) {
571636
let a = self.allocation_manager.get_allocation(&five_tuple).await;
572637
if let Some(a) = a {
638+
// If a server receives a Refresh Request with a REQUESTED-ADDRESS-FAMILY
639+
// attribute, and the attribute's value doesn't match the address
640+
// family of the allocation, the server MUST reply with a 443 (Peer
641+
// Address Family Mismatch) Refresh error response. [RFC 6156, Section 5.2]
642+
let mut req_family = RequestedAddressFamily::default();
643+
if req_family.get_from(m).is_ok()
644+
&& ((req_family == REQUESTED_FAMILY_IPV6 && !a.relay_addr.is_ipv6())
645+
|| (req_family == REQUESTED_FAMILY_IPV4 && !a.relay_addr.is_ipv4()))
646+
{
647+
let peer_address_family_mismatch_msg = build_msg(
648+
m.transaction_id,
649+
MessageType::new(METHOD_REFRESH, CLASS_ERROR_RESPONSE),
650+
vec![Box::new(ErrorCodeAttribute {
651+
code: CODE_PEER_ADDR_FAMILY_MISMATCH,
652+
reason: vec![],
653+
})],
654+
)?;
655+
return build_and_send_err(
656+
&self.conn,
657+
self.src_addr,
658+
peer_address_family_mismatch_msg,
659+
Error::ErrPeerAddressFamilyMismatch,
660+
)
661+
.await;
662+
}
573663
a.refresh(lifetime_duration).await;
574664
} else {
575665
return Err(Error::ErrNoAllocationFound);
@@ -626,6 +716,30 @@ impl Request {
626716
break;
627717
}
628718

719+
// If an XOR-PEER-ADDRESS attribute contains an address of an address
720+
// family different than that of the relayed transport address for the
721+
// allocation, the server MUST generate an error response with the 443
722+
// (Peer Address Family Mismatch) response code. [RFC 6156, Section 6.2]
723+
if (peer_address.ip.is_ipv4() && !a.relay_addr.is_ipv4())
724+
|| (peer_address.ip.is_ipv6() && !a.relay_addr.is_ipv6())
725+
{
726+
let peer_address_family_mismatch_msg = build_msg(
727+
m.transaction_id,
728+
MessageType::new(METHOD_CREATE_PERMISSION, CLASS_ERROR_RESPONSE),
729+
vec![Box::new(ErrorCodeAttribute {
730+
code: CODE_PEER_ADDR_FAMILY_MISMATCH,
731+
reason: vec![],
732+
})],
733+
)?;
734+
return build_and_send_err(
735+
&self.conn,
736+
self.src_addr,
737+
peer_address_family_mismatch_msg,
738+
Error::ErrPeerAddressFamilyMismatch,
739+
)
740+
.await;
741+
}
742+
629743
log::debug!(
630744
"adding permission for {}",
631745
format!("{}:{}", peer_address.ip, peer_address.port)
@@ -734,9 +848,41 @@ impl Request {
734848
}
735849

736850
let mut peer_addr = PeerAddress::default();
737-
if let Err(err) = peer_addr.get_from(m) {
738-
return build_and_send_err(&self.conn, self.src_addr, bad_request_msg, err.into())
851+
match peer_addr.get_from(m) {
852+
Err(err) => {
853+
return build_and_send_err(
854+
&self.conn,
855+
self.src_addr,
856+
bad_request_msg,
857+
err.into(),
858+
)
739859
.await;
860+
}
861+
_ => {
862+
// If the XOR-PEER-ADDRESS attribute contains an address of an address
863+
// family different than that of the relayed transport address for the
864+
// allocation, the server MUST generate an error response with the 443
865+
// (Peer Address Family Mismatch) response code. [RFC 6156, Section 7.2]
866+
if (peer_addr.ip.is_ipv4() && !a.relay_addr.is_ipv4())
867+
|| (peer_addr.ip.is_ipv6() && !a.relay_addr.is_ipv6())
868+
{
869+
let peer_address_family_mismatch_msg = build_msg(
870+
m.transaction_id,
871+
MessageType::new(METHOD_CHANNEL_BIND, CLASS_ERROR_RESPONSE),
872+
vec![Box::new(ErrorCodeAttribute {
873+
code: CODE_PEER_ADDR_FAMILY_MISMATCH,
874+
reason: vec![],
875+
})],
876+
)?;
877+
return build_and_send_err(
878+
&self.conn,
879+
self.src_addr,
880+
peer_address_family_mismatch_msg,
881+
Error::ErrPeerAddressFamilyMismatch,
882+
)
883+
.await;
884+
}
885+
}
740886
}
741887

742888
log::debug!(

turn/src/server/request/request_test.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ async fn test_allocation_lifetime_deletion_zero_lifetime() -> Result<()> {
9292
0,
9393
Duration::from_secs(3600),
9494
TextAttribute::new(ATTR_USERNAME, "user".into()),
95+
true,
9596
)
9697
.await?;
9798
assert!(r

0 commit comments

Comments
 (0)