Select only ASNs visible in all paths for an IP
[dnsseed-rust] / src / bgp_client.rs
index 8f264c660e49840674137be1192ed75cf1ec1b26..1fa92501c2601ee16ed28c4cec4661e935a44c83 100644 (file)
@@ -46,14 +46,14 @@ impl RoutingTable {
                        ($addrty: ty, $addr: expr, $table: expr, $addr_bits: expr) => { {
                                let mut res = Vec::new();
                                //TODO: Optimize this!
-                               for i in (0..($addr_bits + 1)).rev() {
+                               for i in (0..$addr_bits).rev() {
                                        let mut lookup = $addr.octets();
                                        for b in 0..(i / 8) {
-                                               lookup[lookup.len() - b] = 0;
+                                               lookup[lookup.len() - b - 1] = 0;
                                        }
-                                       lookup[lookup.len() - (i/8)] &= !(((1u16 << (i % 8)) - 1) as u8);
+                                       lookup[lookup.len() - (i/8) - 1] &= !(((1u16 << (i % 8)) - 1) as u8);
                                        let lookup_addr = <$addrty>::from(lookup);
-                                       for attrs in $table.range((Included((lookup_addr, $addr_bits, 0)), Included((lookup_addr, $addr_bits, std::u32::MAX)))) {
+                                       for attrs in $table.range((Included((lookup_addr, $addr_bits - i as u8, 0)), Included((lookup_addr, $addr_bits - i as u8, std::u32::MAX)))) {
                                                res.push(Arc::clone(&attrs.1));
                                        }
                                        if !res.is_empty() { break; }
@@ -176,13 +176,24 @@ pub struct BGPClient {
 impl BGPClient {
        pub fn get_asn(&self, addr: IpAddr) -> u32 {
                let mut path_vecs = self.routes.lock().unwrap().get_route_attrs(addr).clone();
+               if path_vecs.is_empty() { return 0; }
+
                path_vecs.sort_unstable_by(|path_a, path_b| {
                        path_a.pref.cmp(&path_b.pref)
                                .then(path_b.path.len().cmp(&path_a.path.len()))
                                .then(path_b.med.cmp(&path_a.med))
                });
-               // TODO: Find last common ASN among all paths
-               *path_vecs[0].path.last().unwrap_or(&0)
+
+               let primary_route = path_vecs.pop().unwrap();
+               'asn_candidates: for asn in primary_route.path.iter().rev() {
+                       for secondary_route in path_vecs.iter() {
+                               if !secondary_route.path.contains(asn) {
+                                       continue 'asn_candidates;
+                               }
+                       }
+                       return *asn;
+               }
+               *primary_route.path.last().unwrap_or(&0)
        }
 
        pub fn disconnect(&self) {
@@ -257,7 +268,9 @@ impl BGPClient {
                                        }
                                        match bgp_msg {
                                                Message::Open(_) => {
-                                                       printer.add_line("Connected to BGP route provider".to_string(), true);
+                                                       client.routes.lock().unwrap().v4_table.clear();
+                                                       client.routes.lock().unwrap().v6_table.clear();
+                                                       printer.add_line("Connected to BGP route provider".to_string(), false);
                                                },
                                                Message::KeepAlive => {
                                                        let _ = sender.try_send(Message::KeepAlive);