Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/http-tracker-core/src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ impl From<ConnectionContext> for LabelSet {
label_name!("server_binding_ip"),
LabelValue::new(&connection_context.server.service_binding.bind_address().ip().to_string()),
),
(
label_name!("server_binding_address_type"),
LabelValue::new(&connection_context.server.service_binding.bind_address_type().to_string()),
),
(
label_name!("server_binding_port"),
LabelValue::new(&connection_context.server.service_binding.bind_address().port().to_string()),
Expand Down
68 changes: 67 additions & 1 deletion packages/primitives/src/service_binding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ use std::net::SocketAddr;
use serde::{Deserialize, Serialize};
use url::Url;

const DUAL_STACK_IP_V4_MAPPED_V6_PREFIX: &str = "::ffff:";

/// Represents the supported network protocols.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
pub enum Protocol {
Expand All @@ -23,6 +25,29 @@ impl fmt::Display for Protocol {
}
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
pub enum AddressType {
/// Represents a plain IPv4 or IPv6 address.
Plain,

/// Represents an IPv6 address that is a mapped IPv4 address.
///
/// This is used for IPv6 addresses that represent an IPv4 address in a dual-stack network.
///
/// For example: `[::ffff:192.0.2.33]`
V4MappedV6,
}

impl fmt::Display for AddressType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let addr_type_str = match self {
Self::Plain => "plain",
Self::V4MappedV6 => "v4_mapped_v6",
};
write!(f, "{addr_type_str}")
}
}

#[derive(thiserror::Error, Debug, Clone)]
pub enum Error {
#[error("The port number cannot be zero. It must be an assigned valid port.")]
Expand Down Expand Up @@ -94,6 +119,15 @@ impl ServiceBinding {
self.bind_address
}

#[must_use]
pub fn bind_address_type(&self) -> AddressType {
if self.is_v4_mapped_v6() {
return AddressType::V4MappedV6;
}

AddressType::Plain
}

/// # Panics
///
/// It never panics because the URL is always valid.
Expand All @@ -102,6 +136,15 @@ impl ServiceBinding {
Url::parse(&format!("{}://{}", self.protocol, self.bind_address))
.expect("Service binding can always be parsed into a URL")
}

fn is_v4_mapped_v6(&self) -> bool {
self.bind_address.ip().is_ipv6()
&& self
.bind_address
.ip()
.to_string()
.starts_with(DUAL_STACK_IP_V4_MAPPED_V6_PREFIX)
}
}

impl From<ServiceBinding> for Url {
Expand All @@ -126,7 +169,7 @@ mod tests {
use rstest::rstest;
use url::Url;

use crate::service_binding::{Error, Protocol, ServiceBinding};
use crate::service_binding::{AddressType, Error, Protocol, ServiceBinding};

#[rstest]
#[case("wildcard_ip", Protocol::UDP, SocketAddr::from_str("0.0.0.0:6969").unwrap())]
Expand Down Expand Up @@ -156,6 +199,29 @@ mod tests {
);
}

#[test]
fn should_return_the_bind_address_plain_type_for_ipv4_ips() {
let service_binding = ServiceBinding::new(Protocol::UDP, SocketAddr::from_str("127.0.0.1:6969").unwrap()).unwrap();

assert_eq!(service_binding.bind_address_type(), AddressType::Plain);
}

#[test]
fn should_return_the_bind_address_plain_type_for_ipv6_ips() {
let service_binding =
ServiceBinding::new(Protocol::UDP, SocketAddr::from_str("[0:0:0:0:0:0:0:1]:6969").unwrap()).unwrap();

assert_eq!(service_binding.bind_address_type(), AddressType::Plain);
}

#[test]
fn should_return_the_bind_address_v4_mapped_v7_type_for_ipv4_ips_mapped_to_ipv6() {
let service_binding =
ServiceBinding::new(Protocol::UDP, SocketAddr::from_str("[::ffff:192.0.2.33]:6969").unwrap()).unwrap();

assert_eq!(service_binding.bind_address_type(), AddressType::V4MappedV6);
}

#[test]
fn should_return_the_corresponding_url() {
let service_binding = ServiceBinding::new(Protocol::UDP, SocketAddr::from_str("127.0.0.1:6969").unwrap()).unwrap();
Expand Down
4 changes: 4 additions & 0 deletions packages/udp-tracker-core/src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ impl From<ConnectionContext> for LabelSet {
label_name!("server_binding_ip"),
LabelValue::new(&connection_context.server_service_binding.bind_address().ip().to_string()),
),
(
label_name!("server_binding_address_type"),
LabelValue::new(&connection_context.server_service_binding.bind_address_type().to_string()),
),
(
label_name!("server_binding_port"),
LabelValue::new(&connection_context.server_service_binding.bind_address().port().to_string()),
Expand Down
4 changes: 4 additions & 0 deletions packages/udp-tracker-server/src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,10 @@ impl From<ConnectionContext> for LabelSet {
label_name!("server_binding_ip"),
LabelValue::new(&connection_context.server_service_binding.bind_address().ip().to_string()),
),
(
label_name!("server_binding_address_type"),
LabelValue::new(&connection_context.server_service_binding.bind_address_type().to_string()),
),
(
label_name!("server_binding_port"),
LabelValue::new(&connection_context.server_service_binding.bind_address().port().to_string()),
Expand Down
Loading