mirror of
https://github.com/outbackdingo/firezone.git
synced 2026-01-27 10:18:54 +00:00
feat(relay): add SOFTWARE attribute (#8076)
Adding a `SOFTWARE` attribute is recommended by the spec and will allow us to identify from client logs, which version of the relay we are talking to.
This commit is contained in:
@@ -16,13 +16,24 @@ pub use server::{
|
||||
CreatePermission, Refresh, Server,
|
||||
};
|
||||
pub use sleep::Sleep;
|
||||
use stun_codec::rfc5389::attributes::Software;
|
||||
pub use stun_codec::rfc8656::attributes::AddressFamily;
|
||||
|
||||
use std::{
|
||||
fmt,
|
||||
net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},
|
||||
sync::LazyLock,
|
||||
};
|
||||
|
||||
pub const VERSION: Option<&str> = option_env!("GITHUB_SHA");
|
||||
pub static SOFTWARE: LazyLock<Software> = LazyLock::new(|| {
|
||||
Software::new(format!(
|
||||
"firezone-relay; rev={}",
|
||||
VERSION.map(|rev| &rev[..8]).unwrap_or("xxxx")
|
||||
))
|
||||
.expect("less than 128 chars")
|
||||
});
|
||||
|
||||
/// Describes the IP stack of a relay server.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum IpStack {
|
||||
|
||||
@@ -8,7 +8,7 @@ use firezone_logging::{err_with_src, sentry_layer};
|
||||
use firezone_relay::sockets::Sockets;
|
||||
use firezone_relay::{
|
||||
sockets, AddressFamily, AllocationPort, ChannelData, ClientSocket, Command, IpStack,
|
||||
PeerSocket, Server, Sleep,
|
||||
PeerSocket, Server, Sleep, VERSION,
|
||||
};
|
||||
use firezone_telemetry::{Telemetry, RELAY_DSN};
|
||||
use futures::{future, FutureExt};
|
||||
@@ -106,7 +106,7 @@ fn main() {
|
||||
if args.telemetry {
|
||||
telemetry.start(
|
||||
args.api_url.as_str(),
|
||||
option_env!("GITHUB_SHA").unwrap_or("unknown"),
|
||||
VERSION.unwrap_or("unknown"),
|
||||
RELAY_DSN,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ pub use crate::server::client_message::{
|
||||
|
||||
use crate::auth::{self, AuthenticatedMessage, MessageIntegrityExt, Nonces, FIREZONE};
|
||||
use crate::net_ext::IpAddrExt;
|
||||
use crate::{ClientSocket, IpStack, PeerSocket};
|
||||
use crate::{ClientSocket, IpStack, PeerSocket, SOFTWARE};
|
||||
use anyhow::Result;
|
||||
use bytecodec::EncodeExt;
|
||||
use core::fmt;
|
||||
@@ -453,11 +453,7 @@ where
|
||||
|
||||
#[tracing::instrument(level = "info", skip_all, fields(software = request.software().map(|s| field::display(s.description())), tid = %format_args!("{:X}", request.transaction_id().as_bytes().hex()), %sender))]
|
||||
fn handle_binding_request(&mut self, request: &Binding, sender: ClientSocket) {
|
||||
let mut message = Message::new(
|
||||
MessageClass::SuccessResponse,
|
||||
BINDING,
|
||||
request.transaction_id(),
|
||||
);
|
||||
let mut message = success_response(BINDING, request.transaction_id());
|
||||
message.add_attribute(XorMappedAddress::new(sender.0));
|
||||
|
||||
tracing::info!("Handled BINDING request");
|
||||
@@ -530,11 +526,7 @@ where
|
||||
maybe_second_relay_addr,
|
||||
);
|
||||
|
||||
let mut message = Message::new(
|
||||
MessageClass::SuccessResponse,
|
||||
ALLOCATE,
|
||||
request.transaction_id(),
|
||||
);
|
||||
let mut message = success_response(ALLOCATE, request.transaction_id());
|
||||
|
||||
let port = allocation.port;
|
||||
|
||||
@@ -959,6 +951,8 @@ where
|
||||
}
|
||||
|
||||
fn send_message(&mut self, message: AuthenticatedMessage, recipient: ClientSocket) {
|
||||
debug_assert!(message.get_attribute::<Software>().is_some());
|
||||
|
||||
let method = message.method();
|
||||
let class = message.class();
|
||||
let error_code = message.get_attribute::<ErrorCode>().map(|e| e.code());
|
||||
@@ -1098,39 +1092,31 @@ fn make_error_response(
|
||||
) -> (Message<Attribute>, String) {
|
||||
let method = request.method();
|
||||
|
||||
let mut message = Message::new(
|
||||
MessageClass::ErrorResponse,
|
||||
method,
|
||||
request.transaction_id(),
|
||||
);
|
||||
let attribute = error_code.into();
|
||||
let reason = attribute.reason_phrase();
|
||||
let msg = format!("{method} failed with {reason}");
|
||||
|
||||
message.add_attribute(attribute);
|
||||
|
||||
(message, msg)
|
||||
(
|
||||
error_response(method, request.transaction_id(), attribute),
|
||||
msg,
|
||||
)
|
||||
}
|
||||
|
||||
fn refresh_success_response(
|
||||
effective_lifetime: Lifetime,
|
||||
transaction_id: TransactionId,
|
||||
) -> Message<Attribute> {
|
||||
let mut message = Message::new(MessageClass::SuccessResponse, REFRESH, transaction_id);
|
||||
let mut message = success_response(REFRESH, transaction_id);
|
||||
message.add_attribute(effective_lifetime);
|
||||
message
|
||||
}
|
||||
|
||||
fn channel_bind_success_response(transaction_id: TransactionId) -> Message<Attribute> {
|
||||
Message::new(MessageClass::SuccessResponse, CHANNEL_BIND, transaction_id)
|
||||
success_response(CHANNEL_BIND, transaction_id)
|
||||
}
|
||||
|
||||
fn create_permission_success_response(transaction_id: TransactionId) -> Message<Attribute> {
|
||||
Message::new(
|
||||
MessageClass::SuccessResponse,
|
||||
CREATE_PERMISSION,
|
||||
transaction_id,
|
||||
)
|
||||
success_response(CREATE_PERMISSION, transaction_id)
|
||||
}
|
||||
|
||||
/// Represents an allocation of a client.
|
||||
@@ -1356,6 +1342,25 @@ stun_codec::define_attribute_enums!(
|
||||
]
|
||||
);
|
||||
|
||||
fn success_response(method: Method, id: TransactionId) -> Message<Attribute> {
|
||||
let mut message = Message::new(MessageClass::SuccessResponse, method, id);
|
||||
message.add_attribute(SOFTWARE.clone());
|
||||
|
||||
message
|
||||
}
|
||||
|
||||
fn error_response(
|
||||
method: Method,
|
||||
transaction_id: TransactionId,
|
||||
error_code: ErrorCode,
|
||||
) -> Message<Attribute> {
|
||||
let mut message = Message::new(MessageClass::ErrorResponse, method, transaction_id);
|
||||
message.add_attribute(SOFTWARE.clone());
|
||||
message.add_attribute(error_code);
|
||||
|
||||
message
|
||||
}
|
||||
|
||||
fn earliest(left: Option<Instant>, right: Option<Instant>) -> Option<Instant> {
|
||||
match (left, right) {
|
||||
(None, None) => None,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::auth::{generate_password, split_username, systemtime_from_unix, FIREZONE};
|
||||
use crate::server::channel_data::ChannelData;
|
||||
use crate::server::UDP_TRANSPORT;
|
||||
use crate::server::{error_response, UDP_TRANSPORT};
|
||||
use crate::Attribute;
|
||||
use anyhow::{Context, Result};
|
||||
use bytecodec::DecodeExt;
|
||||
@@ -17,7 +17,7 @@ use stun_codec::rfc5766::methods::{ALLOCATE, CHANNEL_BIND, CREATE_PERMISSION, RE
|
||||
use stun_codec::rfc8656::attributes::{
|
||||
AdditionalAddressFamily, AddressFamily, RequestedAddressFamily,
|
||||
};
|
||||
use stun_codec::{Message, MessageClass, Method, TransactionId};
|
||||
use stun_codec::{Message, MessageClass, TransactionId};
|
||||
use uuid::Uuid;
|
||||
|
||||
/// The maximum lifetime of an allocation.
|
||||
@@ -615,17 +615,6 @@ fn bad_request(message: &Message<Attribute>) -> Message<Attribute> {
|
||||
)
|
||||
}
|
||||
|
||||
fn error_response(
|
||||
method: Method,
|
||||
transaction_id: TransactionId,
|
||||
error_code: ErrorCode,
|
||||
) -> Message<Attribute> {
|
||||
let mut message = Message::new(MessageClass::ErrorResponse, method, transaction_id);
|
||||
message.add_attribute(error_code);
|
||||
|
||||
message
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
BadChannelData(io::Error),
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
use bytecodec::{DecodeExt, EncodeExt};
|
||||
use firezone_relay::{
|
||||
AddressFamily, Allocate, AllocationPort, Attribute, Binding, ChannelBind, ChannelData,
|
||||
ClientMessage, ClientSocket, Command, IpStack, PeerSocket, Refresh, Server,
|
||||
ClientMessage, ClientSocket, Command, IpStack, PeerSocket, Refresh, Server, SOFTWARE,
|
||||
};
|
||||
use rand::rngs::mock::StepRng;
|
||||
use secrecy::SecretString;
|
||||
@@ -835,6 +835,7 @@ fn binding_response(
|
||||
) -> Message<Attribute> {
|
||||
let mut message =
|
||||
Message::<Attribute>::new(MessageClass::SuccessResponse, BINDING, transaction_id);
|
||||
message.add_attribute(SOFTWARE.clone());
|
||||
message.add_attribute(XorMappedAddress::new(address.into()));
|
||||
|
||||
message
|
||||
@@ -849,6 +850,7 @@ fn allocate_response(
|
||||
) -> Message<Attribute> {
|
||||
let mut message =
|
||||
Message::<Attribute>::new(MessageClass::SuccessResponse, ALLOCATE, transaction_id);
|
||||
message.add_attribute(SOFTWARE.clone());
|
||||
message.add_attribute(XorRelayAddress::new(SocketAddr::new(
|
||||
public_relay_addr.into(),
|
||||
port,
|
||||
@@ -865,6 +867,7 @@ fn unauthorized_allocate_response(
|
||||
) -> Message<Attribute> {
|
||||
let mut message =
|
||||
Message::<Attribute>::new(MessageClass::ErrorResponse, ALLOCATE, transaction_id);
|
||||
message.add_attribute(SOFTWARE.clone());
|
||||
message.add_attribute(ErrorCode::from(Unauthorized));
|
||||
message.add_attribute(Realm::new("firezone".to_owned()).unwrap());
|
||||
message.add_attribute(Nonce::new(nonce.as_hyphenated().to_string()).unwrap());
|
||||
@@ -875,13 +878,18 @@ fn unauthorized_allocate_response(
|
||||
fn refresh_response(transaction_id: TransactionId, lifetime: Lifetime) -> Message<Attribute> {
|
||||
let mut message =
|
||||
Message::<Attribute>::new(MessageClass::SuccessResponse, REFRESH, transaction_id);
|
||||
message.add_attribute(SOFTWARE.clone());
|
||||
message.add_attribute(lifetime);
|
||||
|
||||
message
|
||||
}
|
||||
|
||||
fn channel_bind_response(transaction_id: TransactionId) -> Message<Attribute> {
|
||||
Message::<Attribute>::new(MessageClass::SuccessResponse, CHANNEL_BIND, transaction_id)
|
||||
let mut message =
|
||||
Message::<Attribute>::new(MessageClass::SuccessResponse, CHANNEL_BIND, transaction_id);
|
||||
message.add_attribute(SOFTWARE.clone());
|
||||
|
||||
message
|
||||
}
|
||||
|
||||
fn parse_message(message: &[u8]) -> Message<Attribute> {
|
||||
|
||||
Reference in New Issue
Block a user