connector should set bind addrs correctly (#696)
Some checks are pending
EasyTier Core / pre_job (push) Waiting to run
EasyTier Core / build (freebsd-13.2-x86_64, 13.2, ubuntu-22.04, x86_64-unknown-freebsd) (push) Blocked by required conditions
EasyTier Core / build (linux-aarch64, ubuntu-22.04, aarch64-unknown-linux-musl) (push) Blocked by required conditions
EasyTier Core / build (linux-arm, ubuntu-22.04, arm-unknown-linux-musleabi) (push) Blocked by required conditions
EasyTier Core / build (linux-armhf, ubuntu-22.04, arm-unknown-linux-musleabihf) (push) Blocked by required conditions
EasyTier Core / build (linux-armv7, ubuntu-22.04, armv7-unknown-linux-musleabi) (push) Blocked by required conditions
EasyTier Core / build (linux-armv7hf, ubuntu-22.04, armv7-unknown-linux-musleabihf) (push) Blocked by required conditions
EasyTier Core / build (linux-mips, ubuntu-22.04, mips-unknown-linux-musl) (push) Blocked by required conditions
EasyTier Core / build (linux-mipsel, ubuntu-22.04, mipsel-unknown-linux-musl) (push) Blocked by required conditions
EasyTier Core / build (linux-x86_64, ubuntu-22.04, x86_64-unknown-linux-musl) (push) Blocked by required conditions
EasyTier Core / build (macos-aarch64, macos-latest, aarch64-apple-darwin) (push) Blocked by required conditions
EasyTier Core / build (macos-x86_64, macos-latest, x86_64-apple-darwin) (push) Blocked by required conditions
EasyTier Core / build (windows-arm64, windows-latest, aarch64-pc-windows-msvc) (push) Blocked by required conditions
EasyTier Core / build (windows-x86_64, windows-latest, x86_64-pc-windows-msvc) (push) Blocked by required conditions
EasyTier Core / core-result (push) Blocked by required conditions
EasyTier GUI / pre_job (push) Waiting to run
EasyTier GUI / build-gui (linux-aarch64, aarch64-unknown-linux-gnu, ubuntu-22.04, aarch64-unknown-linux-musl) (push) Blocked by required conditions
EasyTier GUI / build-gui (linux-x86_64, x86_64-unknown-linux-gnu, ubuntu-22.04, x86_64-unknown-linux-musl) (push) Blocked by required conditions
EasyTier GUI / build-gui (macos-aarch64, aarch64-apple-darwin, macos-latest, aarch64-apple-darwin) (push) Blocked by required conditions
EasyTier GUI / build-gui (macos-x86_64, x86_64-apple-darwin, macos-latest, x86_64-apple-darwin) (push) Blocked by required conditions
EasyTier GUI / build-gui (windows-arm64, aarch64-pc-windows-msvc, windows-latest, aarch64-pc-windows-msvc) (push) Blocked by required conditions
EasyTier GUI / build-gui (windows-x86_64, x86_64-pc-windows-msvc, windows-latest, x86_64-pc-windows-msvc) (push) Blocked by required conditions
EasyTier GUI / gui-result (push) Blocked by required conditions
EasyTier Mobile / pre_job (push) Waiting to run
EasyTier Mobile / build-mobile (android, ubuntu-22.04, android) (push) Blocked by required conditions
EasyTier Mobile / mobile-result (push) Blocked by required conditions
EasyTier Test / pre_job (push) Waiting to run
EasyTier Test / test (push) Blocked by required conditions

This commit is contained in:
Sijie.Sun
2025-03-19 10:47:43 +08:00
committed by GitHub
parent 81490d0662
commit b46a200f8d
14 changed files with 97 additions and 44 deletions

View File

@@ -303,9 +303,9 @@ function showEventLogs() {
<template> <template>
<div class="frontend-lib"> <div class="frontend-lib">
<Dialog v-model:visible="dialogVisible" modal :header="t(dialogHeader)" class="w-2/3 h-auto max-h-full" <Dialog v-model:visible="dialogVisible" modal :header="t(dialogHeader)" class="w-full h-auto max-h-full"
:baseZIndex="2000"> :baseZIndex="2000">
<ScrollPanel v-if="dialogHeader === 'vpn_portal_config'" class="w-2/3"> <ScrollPanel v-if="dialogHeader === 'vpn_portal_config'">
<pre>{{ dialogContent }}</pre> <pre>{{ dialogContent }}</pre>
</ScrollPanel> </ScrollPanel>
<Timeline v-else :value="dialogContent"> <Timeline v-else :value="dialogContent">

View File

@@ -24,6 +24,7 @@ use crate::{
}, },
rpc_types::controller::BaseController, rpc_types::controller::BaseController,
}, },
tunnel::IpVersion,
}; };
use crate::proto::cli::PeerConnInfo; use crate::proto::cli::PeerConnInfo;
@@ -175,7 +176,7 @@ impl DirectConnectorManager {
dst_peer_id: PeerId, dst_peer_id: PeerId,
addr: String, addr: String,
) -> Result<(), Error> { ) -> Result<(), Error> {
let connector = create_connector_by_url(&addr, &data.global_ctx).await?; let connector = create_connector_by_url(&addr, &data.global_ctx, IpVersion::Both).await?;
let (peer_id, conn_id) = timeout( let (peer_id, conn_id) = timeout(
std::time::Duration::from_secs(3), std::time::Duration::from_secs(3),
data.peer_manager.try_direct_connect(connector), data.peer_manager.try_direct_connect(connector),
@@ -271,7 +272,7 @@ impl DirectConnectorManager {
let mut tasks = bounded_join_set::JoinSet::new(2); let mut tasks = bounded_join_set::JoinSet::new(2);
let listener_host = listener.socket_addrs(|| None).unwrap().pop(); let listener_host = listener.socket_addrs(|| None)?.pop();
match listener_host { match listener_host {
Some(SocketAddr::V4(s_addr)) => { Some(SocketAddr::V4(s_addr)) => {
if s_addr.ip().is_unspecified() { if s_addr.ip().is_unspecified() {

View File

@@ -91,8 +91,8 @@ impl DNSTunnelConnector {
) )
})?; })?;
let mut connector = create_connector_by_url(url.as_str(), &self.global_ctx).await?; let connector =
connector.set_ip_version(self.ip_version); create_connector_by_url(url.as_str(), &self.global_ctx, self.ip_version).await?;
Ok(connector) Ok(connector)
} }
@@ -179,8 +179,8 @@ impl DNSTunnelConnector {
) )
})?; })?;
let mut connector = create_connector_by_url(url.as_str(), &self.global_ctx).await?; let connector =
connector.set_ip_version(self.ip_version); create_connector_by_url(url.as_str(), &self.global_ctx, self.ip_version).await?;
Ok(connector) Ok(connector)
} }
} }
@@ -243,8 +243,17 @@ mod tests {
let global_ctx = get_mock_global_ctx(); let global_ctx = get_mock_global_ctx();
let mut connector = DNSTunnelConnector::new(url.parse().unwrap(), global_ctx); let mut connector = DNSTunnelConnector::new(url.parse().unwrap(), global_ctx);
connector.set_ip_version(IpVersion::V4); connector.set_ip_version(IpVersion::V4);
let ret = connector.connect().await.unwrap(); for _ in 0..5 {
match connector.connect().await {
Ok(ret) => {
println!("{:?}", ret.info()); println!("{:?}", ret.info());
return;
}
Err(e) => {
println!("{:?}", e);
}
}
}
} }
#[tokio::test] #[tokio::test]
@@ -253,7 +262,16 @@ mod tests {
let global_ctx = get_mock_global_ctx(); let global_ctx = get_mock_global_ctx();
let mut connector = DNSTunnelConnector::new(url.parse().unwrap(), global_ctx); let mut connector = DNSTunnelConnector::new(url.parse().unwrap(), global_ctx);
connector.set_ip_version(IpVersion::V4); connector.set_ip_version(IpVersion::V4);
let ret = connector.connect().await.unwrap(); for _ in 0..5 {
match connector.connect().await {
Ok(ret) => {
println!("{:?}", ret.info()); println!("{:?}", ret.info());
return;
}
Err(e) => {
println!("{:?}", e);
}
}
}
} }
} }

View File

@@ -92,14 +92,24 @@ impl HttpTunnelConnector {
if !query.is_empty() { if !query.is_empty() {
tracing::info!("try to create connector by url: {}", query[0]); tracing::info!("try to create connector by url: {}", query[0]);
self.redirect_type = HttpRedirectType::RedirectToQuery; self.redirect_type = HttpRedirectType::RedirectToQuery;
return create_connector_by_url(&query[0].to_string(), &self.global_ctx).await; return create_connector_by_url(
&query[0].to_string(),
&self.global_ctx,
self.ip_version,
)
.await;
} else if let Some(new_url) = url_str } else if let Some(new_url) = url_str
.strip_prefix(format!("{}://", url.scheme()).as_str()) .strip_prefix(format!("{}://", url.scheme()).as_str())
.and_then(|x| Url::parse(x).ok()) .and_then(|x| Url::parse(x).ok())
{ {
// stripe the scheme and create connector by url // stripe the scheme and create connector by url
self.redirect_type = HttpRedirectType::RedirectToUrl; self.redirect_type = HttpRedirectType::RedirectToUrl;
return create_connector_by_url(new_url.as_str(), &self.global_ctx).await; return create_connector_by_url(
new_url.as_str(),
&self.global_ctx,
self.ip_version,
)
.await;
} }
return Err(Error::InvalidUrl(format!( return Err(Error::InvalidUrl(format!(
"no valid connector url found in url: {}", "no valid connector url found in url: {}",
@@ -107,7 +117,8 @@ impl HttpTunnelConnector {
))); )));
} else { } else {
self.redirect_type = HttpRedirectType::RedirectToUrl; self.redirect_type = HttpRedirectType::RedirectToUrl;
return create_connector_by_url(new_url.as_str(), &self.global_ctx).await; return create_connector_by_url(new_url.as_str(), &self.global_ctx, self.ip_version)
.await;
} }
} }
@@ -137,7 +148,7 @@ impl HttpTunnelConnector {
continue; continue;
} }
self.redirect_type = HttpRedirectType::BodyUrls; self.redirect_type = HttpRedirectType::BodyUrls;
return create_connector_by_url(line, &self.global_ctx).await; return create_connector_by_url(line, &self.global_ctx, self.ip_version).await;
} }
Err(Error::InvalidUrl(format!( Err(Error::InvalidUrl(format!(

View File

@@ -106,7 +106,7 @@ impl ManualConnectorManager {
} }
pub async fn add_connector_by_url(&self, url: &str) -> Result<(), Error> { pub async fn add_connector_by_url(&self, url: &str) -> Result<(), Error> {
self.add_connector(create_connector_by_url(url, &self.global_ctx).await?); self.add_connector(create_connector_by_url(url, &self.global_ctx, IpVersion::Both).await?);
Ok(()) Ok(())
} }

View File

@@ -13,7 +13,7 @@ use crate::{
common::{error::Error, global_ctx::ArcGlobalCtx, network::IPCollector}, common::{error::Error, global_ctx::ArcGlobalCtx, network::IPCollector},
tunnel::{ tunnel::{
check_scheme_and_get_socket_addr, ring::RingTunnelConnector, tcp::TcpTunnelConnector, check_scheme_and_get_socket_addr, ring::RingTunnelConnector, tcp::TcpTunnelConnector,
udp::UdpTunnelConnector, TunnelConnector, udp::UdpTunnelConnector, IpVersion, TunnelConnector,
}, },
}; };
@@ -55,11 +55,12 @@ async fn set_bind_addr_for_peer_connector(
pub async fn create_connector_by_url( pub async fn create_connector_by_url(
url: &str, url: &str,
global_ctx: &ArcGlobalCtx, global_ctx: &ArcGlobalCtx,
ip_version: IpVersion,
) -> Result<Box<dyn TunnelConnector + 'static>, Error> { ) -> Result<Box<dyn TunnelConnector + 'static>, Error> {
let url = url::Url::parse(url).map_err(|_| Error::InvalidUrl(url.to_owned()))?; let url = url::Url::parse(url).map_err(|_| Error::InvalidUrl(url.to_owned()))?;
match url.scheme() { let mut connector: Box<dyn TunnelConnector + 'static> = match url.scheme() {
"tcp" => { "tcp" => {
let dst_addr = check_scheme_and_get_socket_addr::<SocketAddr>(&url, "tcp")?; let dst_addr = check_scheme_and_get_socket_addr::<SocketAddr>(&url, "tcp", ip_version)?;
let mut connector = TcpTunnelConnector::new(url); let mut connector = TcpTunnelConnector::new(url);
if global_ctx.config.get_flags().bind_device { if global_ctx.config.get_flags().bind_device {
set_bind_addr_for_peer_connector( set_bind_addr_for_peer_connector(
@@ -69,10 +70,10 @@ pub async fn create_connector_by_url(
) )
.await; .await;
} }
return Ok(Box::new(connector)); Box::new(connector)
} }
"udp" => { "udp" => {
let dst_addr = check_scheme_and_get_socket_addr::<SocketAddr>(&url, "udp")?; let dst_addr = check_scheme_and_get_socket_addr::<SocketAddr>(&url, "udp", ip_version)?;
let mut connector = UdpTunnelConnector::new(url); let mut connector = UdpTunnelConnector::new(url);
if global_ctx.config.get_flags().bind_device { if global_ctx.config.get_flags().bind_device {
set_bind_addr_for_peer_connector( set_bind_addr_for_peer_connector(
@@ -82,20 +83,20 @@ pub async fn create_connector_by_url(
) )
.await; .await;
} }
return Ok(Box::new(connector)); Box::new(connector)
} }
"http" | "https" => { "http" | "https" => {
let connector = HttpTunnelConnector::new(url, global_ctx.clone()); let connector = HttpTunnelConnector::new(url, global_ctx.clone());
return Ok(Box::new(connector)); Box::new(connector)
} }
"ring" => { "ring" => {
check_scheme_and_get_socket_addr::<uuid::Uuid>(&url, "ring")?; check_scheme_and_get_socket_addr::<uuid::Uuid>(&url, "ring", IpVersion::Both)?;
let connector = RingTunnelConnector::new(url); let connector = RingTunnelConnector::new(url);
return Ok(Box::new(connector)); Box::new(connector)
} }
#[cfg(feature = "quic")] #[cfg(feature = "quic")]
"quic" => { "quic" => {
let dst_addr = check_scheme_and_get_socket_addr::<SocketAddr>(&url, "quic")?; let dst_addr = check_scheme_and_get_socket_addr::<SocketAddr>(&url, "quic", ip_version)?;
let mut connector = QUICTunnelConnector::new(url); let mut connector = QUICTunnelConnector::new(url);
if global_ctx.config.get_flags().bind_device { if global_ctx.config.get_flags().bind_device {
set_bind_addr_for_peer_connector( set_bind_addr_for_peer_connector(
@@ -105,11 +106,11 @@ pub async fn create_connector_by_url(
) )
.await; .await;
} }
return Ok(Box::new(connector)); Box::new(connector)
} }
#[cfg(feature = "wireguard")] #[cfg(feature = "wireguard")]
"wg" => { "wg" => {
let dst_addr = check_scheme_and_get_socket_addr::<SocketAddr>(&url, "wg")?; let dst_addr = check_scheme_and_get_socket_addr::<SocketAddr>(&url, "wg", ip_version)?;
let nid = global_ctx.get_network_identity(); let nid = global_ctx.get_network_identity();
let wg_config = WgConfig::new_from_network_identity( let wg_config = WgConfig::new_from_network_identity(
&nid.network_name, &nid.network_name,
@@ -124,12 +125,12 @@ pub async fn create_connector_by_url(
) )
.await; .await;
} }
return Ok(Box::new(connector)); Box::new(connector)
} }
#[cfg(feature = "websocket")] #[cfg(feature = "websocket")]
"ws" | "wss" => { "ws" | "wss" => {
use crate::tunnel::{FromUrl, IpVersion}; use crate::tunnel::FromUrl;
let dst_addr = SocketAddr::from_url(url.clone(), IpVersion::Both)?; let dst_addr = SocketAddr::from_url(url.clone(), ip_version)?;
let mut connector = crate::tunnel::websocket::WSTunnelConnector::new(url); let mut connector = crate::tunnel::websocket::WSTunnelConnector::new(url);
if global_ctx.config.get_flags().bind_device { if global_ctx.config.get_flags().bind_device {
set_bind_addr_for_peer_connector( set_bind_addr_for_peer_connector(
@@ -139,14 +140,17 @@ pub async fn create_connector_by_url(
) )
.await; .await;
} }
return Ok(Box::new(connector)); Box::new(connector)
} }
"txt" | "srv" => { "txt" | "srv" => {
let connector = dns_connector::DNSTunnelConnector::new(url, global_ctx.clone()); let connector = dns_connector::DNSTunnelConnector::new(url, global_ctx.clone());
return Ok(Box::new(connector)); Box::new(connector)
} }
_ => { _ => {
return Err(Error::InvalidUrl(url.into())); return Err(Error::InvalidUrl(url.into()));
} }
} };
connector.set_ip_version(ip_version);
Ok(connector)
} }

View File

@@ -30,7 +30,7 @@ use easytier::{
self, self,
common::{CompressionAlgoPb, NatType}, common::{CompressionAlgoPb, NatType},
}, },
tunnel::PROTO_PORT_OFFSET, tunnel::{IpVersion, PROTO_PORT_OFFSET},
utils::{init_logger, setup_panic_handler}, utils::{init_logger, setup_panic_handler},
web_client, web_client,
}; };
@@ -870,7 +870,7 @@ async fn run_main(cli: Cli) -> anyhow::Result<()> {
flags.bind_device = false; flags.bind_device = false;
global_ctx.set_flags(flags); global_ctx.set_flags(flags);
let _wc = web_client::WebClient::new( let _wc = web_client::WebClient::new(
create_connector_by_url(c_url.as_str(), &global_ctx).await?, create_connector_by_url(c_url.as_str(), &global_ctx, IpVersion::Both).await?,
token.to_string(), token.to_string(),
); );
tokio::signal::ctrl_c().await.unwrap(); tokio::signal::ctrl_c().await.unwrap();

View File

@@ -1130,6 +1130,7 @@ mod tests {
let connector1 = create_connector_by_url( let connector1 = create_connector_by_url(
format!("{}://127.0.0.1:31013", proto1).as_str(), format!("{}://127.0.0.1:31013", proto1).as_str(),
&peer_mgr_a.get_global_ctx(), &peer_mgr_a.get_global_ctx(),
crate::tunnel::IpVersion::Both,
) )
.await .await
.unwrap(); .unwrap();
@@ -1148,6 +1149,7 @@ mod tests {
let connector2 = create_connector_by_url( let connector2 = create_connector_by_url(
format!("{}://127.0.0.1:31014", proto2).as_str(), format!("{}://127.0.0.1:31014", proto2).as_str(),
&peer_mgr_b.get_global_ctx(), &peer_mgr_b.get_global_ctx(),
crate::tunnel::IpVersion::Both,
) )
.await .await
.unwrap(); .unwrap();

View File

@@ -193,6 +193,7 @@ where
pub(crate) fn check_scheme_and_get_socket_addr<T>( pub(crate) fn check_scheme_and_get_socket_addr<T>(
url: &url::Url, url: &url::Url,
scheme: &str, scheme: &str,
ip_version: IpVersion,
) -> Result<T, TunnelError> ) -> Result<T, TunnelError>
where where
T: FromUrl, T: FromUrl,
@@ -201,7 +202,7 @@ where
return Err(TunnelError::InvalidProtocol(url.scheme().to_string())); return Err(TunnelError::InvalidProtocol(url.scheme().to_string()));
} }
Ok(T::from_url(url.clone(), IpVersion::Both)?) Ok(T::from_url(url.clone(), ip_version)?)
} }
fn default_port(scheme: &str) -> Option<u16> { fn default_port(scheme: &str) -> Option<u16> {

View File

@@ -84,7 +84,8 @@ impl QUICTunnelListener {
#[async_trait::async_trait] #[async_trait::async_trait]
impl TunnelListener for QUICTunnelListener { impl TunnelListener for QUICTunnelListener {
async fn listen(&mut self) -> Result<(), TunnelError> { async fn listen(&mut self) -> Result<(), TunnelError> {
let addr = check_scheme_and_get_socket_addr::<SocketAddr>(&self.addr, "quic")?; let addr =
check_scheme_and_get_socket_addr::<SocketAddr>(&self.addr, "quic", IpVersion::Both)?;
let (endpoint, server_cert) = make_server_endpoint(addr).unwrap(); let (endpoint, server_cert) = make_server_endpoint(addr).unwrap();
self.endpoint = Some(endpoint); self.endpoint = Some(endpoint);
self.server_cert = Some(server_cert); self.server_cert = Some(server_cert);

View File

@@ -231,7 +231,11 @@ fn get_tunnel_for_server(conn: Arc<Connection>) -> impl Tunnel {
impl RingTunnelListener { impl RingTunnelListener {
fn get_addr(&self) -> Result<uuid::Uuid, TunnelError> { fn get_addr(&self) -> Result<uuid::Uuid, TunnelError> {
check_scheme_and_get_socket_addr::<Uuid>(&self.listerner_addr, "ring") check_scheme_and_get_socket_addr::<Uuid>(
&self.listerner_addr,
"ring",
super::IpVersion::Both,
)
} }
} }
@@ -284,7 +288,11 @@ impl RingTunnelConnector {
#[async_trait] #[async_trait]
impl TunnelConnector for RingTunnelConnector { impl TunnelConnector for RingTunnelConnector {
async fn connect(&mut self) -> Result<Box<dyn Tunnel>, super::TunnelError> { async fn connect(&mut self) -> Result<Box<dyn Tunnel>, super::TunnelError> {
let remote_addr = check_scheme_and_get_socket_addr::<Uuid>(&self.remote_addr, "ring")?; let remote_addr = check_scheme_and_get_socket_addr::<Uuid>(
&self.remote_addr,
"ring",
super::IpVersion::Both,
)?;
let entry = CONNECTION_MAP let entry = CONNECTION_MAP
.lock() .lock()
.await .await

View File

@@ -58,7 +58,8 @@ impl TcpTunnelListener {
impl TunnelListener for TcpTunnelListener { impl TunnelListener for TcpTunnelListener {
async fn listen(&mut self) -> Result<(), TunnelError> { async fn listen(&mut self) -> Result<(), TunnelError> {
self.listener = None; self.listener = None;
let addr = check_scheme_and_get_socket_addr::<SocketAddr>(&self.addr, "tcp")?; let addr =
check_scheme_and_get_socket_addr::<SocketAddr>(&self.addr, "tcp", IpVersion::Both)?;
let socket2_socket = socket2::Socket::new( let socket2_socket = socket2::Socket::new(
socket2::Domain::for_address(addr), socket2::Domain::for_address(addr),

View File

@@ -473,7 +473,11 @@ impl UdpTunnelListener {
#[async_trait] #[async_trait]
impl TunnelListener for UdpTunnelListener { impl TunnelListener for UdpTunnelListener {
async fn listen(&mut self) -> Result<(), super::TunnelError> { async fn listen(&mut self) -> Result<(), super::TunnelError> {
let addr = super::check_scheme_and_get_socket_addr::<SocketAddr>(&self.addr, "udp")?; let addr = super::check_scheme_and_get_socket_addr::<SocketAddr>(
&self.addr,
"udp",
IpVersion::Both,
)?;
let socket2_socket = socket2::Socket::new( let socket2_socket = socket2::Socket::new(
socket2::Domain::for_address(addr), socket2::Domain::for_address(addr),
@@ -957,6 +961,7 @@ mod tests {
let addr = check_scheme_and_get_socket_addr::<SocketAddr>( let addr = check_scheme_and_get_socket_addr::<SocketAddr>(
&format!("udp://{}:11111", ip.to_string()).parse().unwrap(), &format!("udp://{}:11111", ip.to_string()).parse().unwrap(),
"udp", "udp",
IpVersion::Both,
) )
.unwrap(); .unwrap();
let socket2_socket = socket2::Socket::new( let socket2_socket = socket2::Socket::new(

View File

@@ -547,7 +547,8 @@ impl WgTunnelListener {
#[async_trait] #[async_trait]
impl TunnelListener for WgTunnelListener { impl TunnelListener for WgTunnelListener {
async fn listen(&mut self) -> Result<(), super::TunnelError> { async fn listen(&mut self) -> Result<(), super::TunnelError> {
let addr = check_scheme_and_get_socket_addr::<SocketAddr>(&self.addr, "wg")?; let addr =
check_scheme_and_get_socket_addr::<SocketAddr>(&self.addr, "wg", IpVersion::Both)?;
let socket2_socket = socket2::Socket::new( let socket2_socket = socket2::Socket::new(
socket2::Domain::for_address(addr), socket2::Domain::for_address(addr),
socket2::Type::DGRAM, socket2::Type::DGRAM,