nat_detect/lib.rs
1use std::collections::HashMap;
2use std::io::{ErrorKind};
3use std::net::{IpAddr, Ipv4Addr, SocketAddr};
4use tokio::net::UdpSocket;
5use std::time::Duration;
6
7
8use log::{debug, info};
9use bytecodec::{DecodeExt, EncodeExt};
10use stun_codec_blazh::{Attribute, Message, MessageClass, MessageDecoder, MessageEncoder, TransactionId};
11use stun_codec_blazh::rfc3489::attributes::ChangedAddress;
12use stun_codec_blazh::rfc5389::attributes::{MappedAddress, UnknownAttributes};
13use stun_codec_blazh::rfc5389::methods;
14use stun_codec_blazh::rfc5780::attributes::ChangeRequest;
15use crate::NatType::{FullCone, OpenInternet, PortRestrictedCone, RestrictedCone, Symmetric, SymmetricUdpFirewall, Unknown};
16
17
18type IoResult<T>= std::io::Result<T>;
19
20// pub(crate) const FAMILY_IPV4: u16 = 0x01;
21// pub(crate) const FAMILY_IPV6: u16 = 0x02;
22// pub(crate) const IPV4LEN: usize = 4;
23// pub(crate) const IPV6LEN: usize = 16;
24
25pub const TIMEOUT: Duration = Duration::from_millis(1000);
26
27pub const STUN_RETRY_COUNT: usize = 2;
28
29#[derive(Debug, Eq, PartialEq, Hash, Clone, Copy)]
30pub enum NatType{
31
32 /// UDP is always blocked.
33 UdpBlocked,
34
35 /// No NAT, public IP, no firewall.
36 OpenInternet,
37
38 /// No NAT, public IP, but symmetric UDP firewall.
39 SymmetricUdpFirewall,
40
41 /// A full cone NAT is one where all requests from the same internal IP address and port are
42 /// mapped to the same external IP address and port. Furthermore, any external host can send
43 /// a packet to the internal host, by sending a packet to the mapped external address.
44 FullCone,
45
46 /// A restricted cone NAT is one where all requests from the same internal IP address and
47 /// port are mapped to the same external IP address and port. Unlike a full cone NAT, an external
48 /// host (with IP address X) can send a packet to the internal host only if the internal host
49 /// had previously sent a packet to IP address X.
50 RestrictedCone,
51
52 /// A port restricted cone NAT is like a restricted cone NAT, but the restriction
53 /// includes port numbers. Specifically, an external host can send a packet, with source IP
54 /// address X and source port P, to the internal host only if the internal host had previously
55 /// sent a packet to IP address X and port P.
56 PortRestrictedCone,
57
58 /// A symmetric NAT is one where all requests from the same internal IP address and port,
59 /// to a specific destination IP address and port, are mapped to the same external IP address and
60 /// port. If the same host sends a packet with the same source address and port, but to
61 /// a different destination, a different mapping is used. Furthermore, only the external host that
62 /// receives a packet can send a UDP packet back to the internal host.
63 Symmetric,
64
65 /// Unknown
66 Unknown
67}
68
69impl NatType{
70 pub fn weight(&self) -> usize{
71 match self {
72 NatType::UdpBlocked => 1,
73 OpenInternet => 7,
74 SymmetricUdpFirewall => 2,
75 FullCone => 6,
76 RestrictedCone => 5,
77 PortRestrictedCone => 4,
78 Symmetric => 3,
79 NatType::Unknown => 0,
80 }
81 }
82}
83
84
85/*
86 In test I, the client sends a STUN Binding Request to a server, without any flags set in the
87 CHANGE-REQUEST attribute, and without the RESPONSE-ADDRESS attribute. This causes the server
88 to send the response back to the address and port that the request came from.
89
90 In test II, the client sends a Binding Request with both the "change IP" and "change port" flags
91 from the CHANGE-REQUEST attribute set.
92
93 In test III, the client sends a Binding Request with only the "change port" flag set.
94
95 +--------+
96 | Test |
97 | I |
98 +--------+
99 |
100 |
101 V
102 /\ /\
103 N / \ Y / \ Y +--------+
104 UDP <-------/Resp\--------->/ IP \------------->| Test |
105 Blocked \ ? / \Same/ | II |
106 \ / \? / +--------+
107 \/ \/ |
108 | N |
109 | V
110 V /\
111 +--------+ Sym. N / \
112 | Test | UDP <---/Resp\
113 | II | Firewall \ ? /
114 +--------+ \ /
115 | \/
116 V |Y
117 /\ /\ |
118 Symmetric N / \ +--------+ N / \ V
119 NAT <--- / IP \<-----| Test |<--- /Resp\ Open
120 \Same/ | I | \ ? / Internet
121 \? / +--------+ \ /
122 \/ \/
123 | |Y
124 | |
125 | V
126 | Full
127 | Cone
128 V /\
129 +--------+ / \ Y
130 | Test |------>/Resp\---->Restricted
131 | III | \ ? /
132 +--------+ \ /
133 \/
134 |N
135 | Port
136 +------>Restricted
137*/
138pub async fn nat_detect_with_servers(stun_server_list: &[&str]) -> IoResult<(NatType, SocketAddr)> {
139
140
141 let mut reduce_map: HashMap<NatType, usize> = HashMap::new();
142 let mut handlers = Vec::new();
143
144 let local_address = local_ip().await?;
145 debug!("local ip: {}", local_address.ip());
146
147 for s in stun_server_list {
148 debug!("{} use", s);
149 let stun_server = s.to_string();
150 let local_address_clone = local_address.clone();
151 handlers.push( tokio::spawn(async move {
152 nat_detect(local_address_clone, &stun_server).await
153 }));
154 }
155
156 let mut public_address = empty_address();
157
158 let empty_address = empty_address();
159
160 for h in handlers {
161 let result = h.await.map_err(|_| std::io::Error::from(ErrorKind::Other))?;
162 if let Result::Ok((a, p,n)) = result {
163 info!("{} -> {:?}", a, n);
164
165 if !empty_address.eq(&p) {
166 public_address = p;
167 }
168
169 reduce_map.entry(n.clone())
170 .and_modify(|e| *e += 1)
171 .or_insert(1);
172 }
173 // else if let Result::Err(e) = result{
174 // error!("{}", e);
175 // }
176 }
177
178 // select maximum count
179 // if let Option::Some((n, _)) = reduce_map.iter().max_by(|v1, v2| v1.1.cmp(v2.1)){
180 // return IoResult::Ok(*n);
181 // }
182
183 // select maximum weight
184 if let Option::Some(n) = reduce_map.keys().max_by(|k1, k2| k1.weight().cmp(&k2.weight())){
185 return IoResult::Ok((*n, public_address));
186 }
187
188 return other_error();
189}
190
191fn empty_address() -> SocketAddr{
192 SocketAddr::new(IpAddr::V4(Ipv4Addr::from(0)), 0)
193}
194
195// #[derive(Debug)]
196// pub struct ChangedAddress {
197// pub ip: IpAddr,
198// pub port: u16,
199// }
200//
201// impl Default for ChangedAddress {
202// fn default() -> Self {
203// ChangedAddress {
204// ip: IpAddr::V4(Ipv4Addr::from(0)),
205// port: 0,
206// }
207// }
208// }
209//
210// impl fmt::Display for ChangedAddress {
211// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
212// let family = match self.ip {
213// IpAddr::V4(_) => FAMILY_IPV4,
214// IpAddr::V6(_) => FAMILY_IPV6,
215// };
216// if family == FAMILY_IPV4 {
217// write!(f, "{}:{}", self.ip, self.port)
218// } else {
219// write!(f, "[{}]:{}", self.ip, self.port)
220// }
221// }
222// }
223
224pub async fn local_ip() -> IoResult<SocketAddr> {
225 let socket = UdpSocket::bind("0.0.0.0:0").await?;
226 let _ = socket.connect("8.8.8.8:80").await?;
227 socket.local_addr()
228}
229
230// impl ChangedAddress {
231// /// get_from_as decodes MAPPED-ADDRESS value in message m as an attribute of type t.
232// pub fn get_from_as(&mut self, m: &Message, t: AttrType) -> std::result::Result<(), Error> {
233// let v = m.get(t)?;
234// if v.len() <= 4 {
235// return Err(Error::ErrUnexpectedEof);
236// }
237//
238// let family = u16::from_be_bytes([v[0], v[1]]);
239// if family != FAMILY_IPV6 && family != FAMILY_IPV4 {
240// return Err(Error::Other(format!("bad value {}", family)));
241// }
242// self.port = u16::from_be_bytes([v[2], v[3]]);
243//
244// if family == FAMILY_IPV6 {
245// let mut ip = [0; IPV6LEN];
246// let l = std::cmp::min(ip.len(), v[4..].len());
247// ip[..l].copy_from_slice(&v[4..4 + l]);
248// self.ip = IpAddr::V6(Ipv6Addr::from(ip));
249// } else {
250// let mut ip = [0; IPV4LEN];
251// let l = std::cmp::min(ip.len(), v[4..].len());
252// ip[..l].copy_from_slice(&v[4..4 + l]);
253// self.ip = IpAddr::V4(Ipv4Addr::from(ip));
254// };
255//
256// Ok(())
257// }
258//
259// /// add_to_as adds MAPPED-ADDRESS value to m as t attribute.
260// pub fn add_to_as(&self, m: &mut Message, t: AttrType) -> std::result::Result<(), Error> {
261// let family = match self.ip {
262// IpAddr::V4(_) => FAMILY_IPV4,
263// IpAddr::V6(_) => FAMILY_IPV6,
264// };
265//
266// let mut value = vec![0u8; 4];
267// //value[0] = 0 // first 8 bits are zeroes
268// value[0..2].copy_from_slice(&family.to_be_bytes());
269// value[2..4].copy_from_slice(&self.port.to_be_bytes());
270//
271// match self.ip {
272// IpAddr::V4(ipv4) => value.extend_from_slice(&ipv4.octets()),
273// IpAddr::V6(ipv6) => value.extend_from_slice(&ipv6.octets()),
274// };
275//
276// m.add(t, &value);
277// Ok(())
278// }
279// }
280
281
282pub async fn nat_detect(local_address: SocketAddr,stun_server: &str) -> IoResult<(String, SocketAddr, NatType)> {
283
284 let transaction_id = TransactionId::new([3; 12]);
285
286 let mut socket = tokio::net::UdpSocket::bind(format!("{}:0", local_address.ip())).await?;
287 let mut_socket_ref = &mut socket;
288
289 let stun_server_string = stun_server.to_string();
290
291 // test1
292 let test1_message: Message<UnknownAttributes> = build_request_bind_message(transaction_id);
293 debug!("[{}] test1 send: {:?}", stun_server, test1_message);
294 let result = single_send(stun_server, test1_message, mut_socket_ref).await;
295 debug!("[{}] test1: {}", stun_server, result.is_ok());
296 if result.is_err() {
297 return IoResult::Ok((stun_server_string, empty_address(),NatType::UdpBlocked));
298 }
299 let test1_response: Message<stun_codec_blazh::rfc5389::Attribute> = result.unwrap();
300 debug!("[{}] test1 recv: {:?}", stun_server, test1_response);
301
302 let test1_mapped_address = {
303 let opt: Option<&MappedAddress> = test1_response.get_attribute();
304 match opt {
305 None => return other_error(),
306 Some(a) => a.address()
307 }
308 };
309 debug!("[{}] test1 mapped_address: {}", stun_server,test1_mapped_address);
310
311 let public_address = SocketAddr::new(test1_mapped_address.ip().clone(), test1_mapped_address.port().clone());
312
313 let test1_changed_address ={
314 let opt: Option<&ChangedAddress> = test1_response.get_attribute();
315 match opt {
316 None => return other_error(),
317 Some(a) => a.address()
318 }
319 };
320 debug!("[{}] test1 changed_address: {}", stun_server,test1_changed_address);
321
322
323 // test2
324 let test2_message = build_request_bind_message_with_attribute(
325 transaction_id, ChangeRequest::new(true, true)
326 );
327
328 let local_ip = mut_socket_ref.local_addr()?.ip();
329 let test1_mapped_address_ip = test1_mapped_address.ip();
330 let test1_is_same_ip = local_ip.eq(&test1_mapped_address_ip);
331 debug!("[{}] test1 is_same_ip: l:{} r:{}", stun_server, local_ip, test1_mapped_address_ip);
332 if test1_is_same_ip {
333 // no nat
334 debug!("[{}] test2 send: {:?}", stun_server, test2_message);
335 let result = single_send::<ChangeRequest, MappedAddress>(stun_server, test2_message, mut_socket_ref).await;
336 debug!("[{}] test2: {}", stun_server, result.is_ok());
337 if result.is_err() {
338 return IoResult::Ok((stun_server_string, public_address,OpenInternet));
339 } else {
340 debug!("[{}] test2 recv: {:?}", stun_server, result.unwrap());
341 return IoResult::Ok((stun_server_string, public_address, SymmetricUdpFirewall));
342 }
343 } else {
344 // nat
345 debug!("[{}] test2 send: {:?}", stun_server, test2_message);
346 let result = single_send::<ChangeRequest, MappedAddress>(stun_server, test2_message, mut_socket_ref).await;
347 debug!("[{}] test2: {}", stun_server,result.is_ok());
348 if result.is_ok() {
349 let test2_message = result.unwrap();
350 debug!("[{}] test2 recv: {:?}", stun_server, test2_message);
351 return IoResult::Ok((stun_server_string, public_address, FullCone));
352 } else {
353 // test1(2)
354 let test1_address = test1_changed_address.to_string();
355
356 let test12_message: Message<UnknownAttributes> = build_request_bind_message(transaction_id);
357 debug!("[{}] test12 send: {:?}", stun_server,test12_message);
358 let result = single_send(
359 test1_address.as_str(),
360 test12_message,
361 mut_socket_ref
362 ).await;
363 debug!("[{}] test12: {}", stun_server,result.is_ok());
364 if result.is_err() {
365 return IoResult::Ok((stun_server_string,public_address, Unknown));
366 } else {
367 // Symmetric NAT
368 let test12_response: Message<stun_codec_blazh::rfc5389::Attribute> = result.unwrap();
369 debug!("[{}] test12 recv: {:?}", stun_server, test12_response);
370
371 let test12_mapped_address ={
372 let opt: Option<&MappedAddress> = test12_response.get_attribute();
373 match opt {
374 None => return other_error(),
375 Some(a) => a.address()
376 }
377 };
378 debug!("[{}] test12 mapped_address: {}", stun_server,test12_mapped_address);
379
380 if !test1_mapped_address.eq(&test12_mapped_address) {
381 return IoResult::Ok((stun_server_string, public_address,Symmetric));
382 } else {
383 // test 3
384 let test3_message = build_request_bind_message_with_attribute(
385 transaction_id, ChangeRequest::new(false, true)
386 );
387 debug!("[{}] test3 send: {:?}", stun_server, test3_message);
388 let result = single_send::<ChangeRequest, stun_codec_blazh::rfc5389::Attribute>(
389 test1_address.as_str(),
390 test3_message,
391 mut_socket_ref
392 ).await;
393 debug!("[{}] test3: {}", stun_server,result.is_ok());
394 if result.is_err() {
395 return IoResult::Ok((stun_server_string,public_address, PortRestrictedCone));
396 } else {
397 debug!("[{}] test3 recv: {:?}", stun_server, result.unwrap());
398 return IoResult::Ok((stun_server_string, public_address,RestrictedCone));
399 }
400 }
401 }
402 }
403 }
404
405
406}
407
408fn other_error<A>() -> IoResult<A> {
409 IoResult::Err(std::io::Error::from(ErrorKind::Other))
410}
411
412fn build_request_bind_message<A: Attribute>(transaction_id: TransactionId) -> Message<A> {
413 return Message::new(
414 MessageClass::Request,
415 methods::BINDING,
416 transaction_id
417 );
418}
419
420fn build_request_bind_message_with_attribute<A: Attribute>(
421 transaction_id: TransactionId, a: A
422) -> Message<A> {
423 let mut message = build_request_bind_message(transaction_id);
424 message.add_attribute(a);
425 message
426}
427
428// pub struct StunResult{
429// request_id: TransactionId,
430// bs: Vec<u8>
431// }
432//
433//
434// impl StunResult {
435// fn decode<T: Attribute>(&self) -> IoResult<Message<T>> {
436// todo!()
437// }
438// }
439
440async fn single_send<A: Attribute, B: Attribute>(
441 stun_server: &str,
442 message: Message<A>,
443 socket: & mut UdpSocket
444)
445 -> IoResult<Message<B>>
446{
447 let mut encoder = MessageEncoder::default();
448 let bytes: Vec<u8> = encoder.encode_into_bytes(message.clone()).map_err(|_e| std::io::Error::from(ErrorKind::Other))?;
449 let mut buf = [0; 1 << 9];
450 for _i in 0..STUN_RETRY_COUNT {
451 match tokio::time::timeout(TIMEOUT, socket.send_to(bytes.as_slice(), stun_server)).await {
452 Ok(Ok(_)) => {}
453 _ => {
454 continue
455 }
456 }
457 let len = {
458 match tokio::time::timeout(TIMEOUT, socket.recv_from(&mut buf)) .await {
459 Ok(Ok((i, _))) => i,
460 _ => {
461 continue
462 }
463 }
464 };
465
466 let mut decoder = MessageDecoder::<B>::new();
467 match decoder.decode_from_bytes(&buf[0..len]) {
468 Ok(Ok(m)) => {
469 if m.class()== MessageClass::ErrorResponse {
470 break
471 }
472 if message.transaction_id().eq(&m.transaction_id()) {
473 return IoResult::Ok(m);
474 }
475 }
476 _ => {
477 continue
478 }
479 };
480 }
481 return IoResult::Err(std::io::Error::from(ErrorKind::Other));
482}
483