Fix Gossip Pushes going to invalid addresses (#1858)
This commit is contained in:
		@@ -189,7 +189,7 @@ impl ClusterInfo {
 | 
				
			|||||||
            .values()
 | 
					            .values()
 | 
				
			||||||
            .filter_map(|x| x.value.contact_info())
 | 
					            .filter_map(|x| x.value.contact_info())
 | 
				
			||||||
            .filter(|x| x.id != me)
 | 
					            .filter(|x| x.id != me)
 | 
				
			||||||
            .filter(|x| ClusterInfo::is_valid_address(&x.rpc))
 | 
					            .filter(|x| ContactInfo::is_valid_address(&x.rpc))
 | 
				
			||||||
            .cloned()
 | 
					            .cloned()
 | 
				
			||||||
            .collect()
 | 
					            .collect()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -202,7 +202,7 @@ impl ClusterInfo {
 | 
				
			|||||||
            .values()
 | 
					            .values()
 | 
				
			||||||
            .filter_map(|x| x.value.contact_info())
 | 
					            .filter_map(|x| x.value.contact_info())
 | 
				
			||||||
            .filter(|x| x.id != me)
 | 
					            .filter(|x| x.id != me)
 | 
				
			||||||
            .filter(|x| ClusterInfo::is_valid_address(&x.ncp))
 | 
					            .filter(|x| ContactInfo::is_valid_address(&x.ncp))
 | 
				
			||||||
            .cloned()
 | 
					            .cloned()
 | 
				
			||||||
            .collect()
 | 
					            .collect()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -216,7 +216,7 @@ impl ClusterInfo {
 | 
				
			|||||||
            .values()
 | 
					            .values()
 | 
				
			||||||
            .filter_map(|x| x.value.contact_info())
 | 
					            .filter_map(|x| x.value.contact_info())
 | 
				
			||||||
            .filter(|x| x.id != me)
 | 
					            .filter(|x| x.id != me)
 | 
				
			||||||
            .filter(|x| ClusterInfo::is_valid_address(&x.tvu))
 | 
					            .filter(|x| ContactInfo::is_valid_address(&x.tvu))
 | 
				
			||||||
            .cloned()
 | 
					            .cloned()
 | 
				
			||||||
            .collect()
 | 
					            .collect()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -230,7 +230,7 @@ impl ClusterInfo {
 | 
				
			|||||||
            .values()
 | 
					            .values()
 | 
				
			||||||
            .filter_map(|x| x.value.contact_info())
 | 
					            .filter_map(|x| x.value.contact_info())
 | 
				
			||||||
            .filter(|x| x.id != me)
 | 
					            .filter(|x| x.id != me)
 | 
				
			||||||
            .filter(|x| ClusterInfo::is_valid_address(&x.tpu))
 | 
					            .filter(|x| ContactInfo::is_valid_address(&x.tpu))
 | 
				
			||||||
            .cloned()
 | 
					            .cloned()
 | 
				
			||||||
            .collect()
 | 
					            .collect()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -898,18 +898,6 @@ impl ClusterInfo {
 | 
				
			|||||||
            }).unwrap()
 | 
					            }).unwrap()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn is_valid_ip(addr: IpAddr) -> bool {
 | 
					 | 
				
			||||||
        !(addr.is_unspecified() || addr.is_multicast())
 | 
					 | 
				
			||||||
        // || (addr.is_loopback() && !cfg_test))
 | 
					 | 
				
			||||||
        // TODO: boot loopback in production networks
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    /// port must not be 0
 | 
					 | 
				
			||||||
    /// ip must be specified and not mulitcast
 | 
					 | 
				
			||||||
    /// loopback ip is only allowed in tests
 | 
					 | 
				
			||||||
    pub fn is_valid_address(addr: &SocketAddr) -> bool {
 | 
					 | 
				
			||||||
        (addr.port() != 0) && Self::is_valid_ip(addr.ip())
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn spy_node() -> (NodeInfo, UdpSocket) {
 | 
					    pub fn spy_node() -> (NodeInfo, UdpSocket) {
 | 
				
			||||||
        let (_, gossip_socket) = bind_in_range(FULLNODE_PORT_RANGE).unwrap();
 | 
					        let (_, gossip_socket) = bind_in_range(FULLNODE_PORT_RANGE).unwrap();
 | 
				
			||||||
        let pubkey = Keypair::new().pubkey();
 | 
					        let pubkey = Keypair::new().pubkey();
 | 
				
			||||||
@@ -1057,6 +1045,29 @@ mod tests {
 | 
				
			|||||||
    use std::sync::{Arc, RwLock};
 | 
					    use std::sync::{Arc, RwLock};
 | 
				
			||||||
    use window::default_window;
 | 
					    use window::default_window;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn test_cluster_spy_gossip() {
 | 
				
			||||||
 | 
					        //check that gossip doesn't try to push to invalid addresses
 | 
				
			||||||
 | 
					        let node = Node::new_localhost();
 | 
				
			||||||
 | 
					        let (spy, _) = ClusterInfo::spy_node();
 | 
				
			||||||
 | 
					        let cluster_info = Arc::new(RwLock::new(
 | 
				
			||||||
 | 
					            ClusterInfo::new(node.info).expect("ClusterInfo::new"),
 | 
				
			||||||
 | 
					        ));
 | 
				
			||||||
 | 
					        cluster_info.write().unwrap().insert_info(spy);
 | 
				
			||||||
 | 
					        cluster_info
 | 
				
			||||||
 | 
					            .write()
 | 
				
			||||||
 | 
					            .unwrap()
 | 
				
			||||||
 | 
					            .gossip
 | 
				
			||||||
 | 
					            .refresh_push_active_set();
 | 
				
			||||||
 | 
					        let reqs = cluster_info.write().unwrap().gossip_request();
 | 
				
			||||||
 | 
					        //assert none of the addrs are invalid.
 | 
				
			||||||
 | 
					        reqs.iter().all(|(addr, _)| {
 | 
				
			||||||
 | 
					            let res = ContactInfo::is_valid_address(addr);
 | 
				
			||||||
 | 
					            assert!(res);
 | 
				
			||||||
 | 
					            res
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    fn test_cluster_info_new() {
 | 
					    fn test_cluster_info_new() {
 | 
				
			||||||
        let d = NodeInfo::new_localhost(Keypair::new().pubkey(), timestamp());
 | 
					        let d = NodeInfo::new_localhost(Keypair::new().pubkey(), timestamp());
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,6 +10,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
use bincode::serialized_size;
 | 
					use bincode::serialized_size;
 | 
				
			||||||
use bloom::Bloom;
 | 
					use bloom::Bloom;
 | 
				
			||||||
 | 
					use contact_info::ContactInfo;
 | 
				
			||||||
use crds::{Crds, VersionedCrdsValue};
 | 
					use crds::{Crds, VersionedCrdsValue};
 | 
				
			||||||
use crds_gossip_error::CrdsGossipError;
 | 
					use crds_gossip_error::CrdsGossipError;
 | 
				
			||||||
use crds_value::{CrdsValue, CrdsValueLabel};
 | 
					use crds_value::{CrdsValue, CrdsValueLabel};
 | 
				
			||||||
@@ -177,6 +178,11 @@ impl CrdsGossipPush {
 | 
				
			|||||||
            if new_items.get(&val.0.pubkey()).is_some() {
 | 
					            if new_items.get(&val.0.pubkey()).is_some() {
 | 
				
			||||||
                continue;
 | 
					                continue;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            if let Some(contact) = val.1.value.contact_info() {
 | 
				
			||||||
 | 
					                if !ContactInfo::is_valid_address(&contact.ncp) {
 | 
				
			||||||
 | 
					                    continue;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            let bloom = Bloom::random(network_size, 0.1, 1024 * 8 * 4);
 | 
					            let bloom = Bloom::random(network_size, 0.1, 1024 * 8 * 4);
 | 
				
			||||||
            new_items.insert(val.0.pubkey(), bloom);
 | 
					            new_items.insert(val.0.pubkey(), bloom);
 | 
				
			||||||
            if new_items.len() == need {
 | 
					            if new_items.len() == need {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,7 @@ extern crate solana_sdk;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
use solana::blob_fetch_stage::BlobFetchStage;
 | 
					use solana::blob_fetch_stage::BlobFetchStage;
 | 
				
			||||||
use solana::cluster_info::{ClusterInfo, Node, NodeInfo};
 | 
					use solana::cluster_info::{ClusterInfo, Node, NodeInfo};
 | 
				
			||||||
 | 
					use solana::contact_info::ContactInfo;
 | 
				
			||||||
use solana::entry::{reconstruct_entries_from_blobs, Entry};
 | 
					use solana::entry::{reconstruct_entries_from_blobs, Entry};
 | 
				
			||||||
use solana::fullnode::{Fullnode, FullnodeReturnType};
 | 
					use solana::fullnode::{Fullnode, FullnodeReturnType};
 | 
				
			||||||
use solana::leader_scheduler::{make_active_set_entries, LeaderScheduler, LeaderSchedulerConfig};
 | 
					use solana::leader_scheduler::{make_active_set_entries, LeaderScheduler, LeaderSchedulerConfig};
 | 
				
			||||||
@@ -1621,7 +1622,7 @@ fn test_broadcast_last_tick() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
fn mk_client(leader: &NodeInfo) -> ThinClient {
 | 
					fn mk_client(leader: &NodeInfo) -> ThinClient {
 | 
				
			||||||
    let transactions_socket = UdpSocket::bind("0.0.0.0:0").unwrap();
 | 
					    let transactions_socket = UdpSocket::bind("0.0.0.0:0").unwrap();
 | 
				
			||||||
    assert!(ClusterInfo::is_valid_address(&leader.tpu));
 | 
					    assert!(ContactInfo::is_valid_address(&leader.tpu));
 | 
				
			||||||
    ThinClient::new(leader.rpc, leader.tpu, transactions_socket)
 | 
					    ThinClient::new(leader.rpc, leader.tpu, transactions_socket)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user