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