/// <summary>Parses web data and updates the revoked users hashtable if /// successful</summary> protected void UpdateRl(byte[] data) { // message is length (4) + date (8) + data (variable) + hash (~20) int length = data.Length; if (length < 12) { throw new Exception("No data? Didn't get enough data..."); } length = NumberSerializer.ReadInt(data, 0); Brunet.DateTime date = new Brunet.DateTime(NumberSerializer.ReadLong(data, 4)); // warn the user that this is an old revocation list, maybe there is an attack if (date < Brunet.DateTime.UtcNow.AddHours(-24)) { ProtocolLog.WriteIf(IpopLog.GroupVPN, "Revocation list is over 24 hours old"); } // Weird, data length is longer than the data we got if (length > data.Length - 12) { throw new Exception("Missing data? Didn't get enough data..."); } // hash the data and verify the signature SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider(); byte[] hash = sha1.ComputeHash(data, 4, length); byte[] signature = new byte[data.Length - 4 - length]; Array.Copy(data, 4 + length, signature, 0, signature.Length); if (!_ca_cert.PublicKey.VerifyHash(hash, CryptoConfig.MapNameToOID("SHA1"), signature)) { throw new Exception("Invalid signature!"); } // convert the data to an array list as it was sent to us MemBlock mem = MemBlock.Reference(data, 12, length - 8); ArrayList rl = AdrConverter.Deserialize(mem) as ArrayList; if (rl == null) { throw new Exception("Data wasn't a list..."); } // convert it into a hashtable for O(1) look ups Hashtable ht = new Hashtable(); foreach (string username in rl) { ht[username] = true; } Interlocked.Exchange(ref _revoked_users, ht); }
/// <summary>Tasks that should be performed during startup until completion /// and repetitive tasks are added here. protected void CheckNode(object o, EventArgs ea) { lock (_sync) { if (_dhcp_config == null) { GetDhcpConfig(); if (_dhcp_config == null) { return; } } // The rest doesn't quite work right yet... Brunet.DateTime now = Brunet.DateTime.UtcNow; if ((now - _last_check_node).TotalSeconds < 30) { return; } _last_check_node = now; } ThreadPool.QueueUserWorkItem(CheckNetwork); }
/** <summary>This provides a mechanism for a node to get a lease by using the Dht. This uses Dht.Create which provides an atomic operation on the Dht, where this node is the first to store a value at a specific key. The idea being that, this node being the first to store the IP, all nodes doing a lookup for that IP Address would be directed to this node.</summary> <remarks>Working with the Dht is a little tricky as transient errors could be misrepresented as a failed Create. It is that reason why there is a Renew parameter. If that is set, the algorithm for obtaining an address is slightly changed with more weight on reobtaining the RequestedAddr. </remarks> <param name="RequestedAddr">Optional parameter if the node would like to request a specific address.</param> <param name="Renew">Is the RequestedAddr a renewal?</param> <param name="node_address">The Brunet.Address where the DhtIpopNode resides </param> <param name="para">Optional, position 0 should hold the hostname.</param> */ public override byte[] RequestLease(byte[] RequestedAddr, bool Renew, string node_address, params object[] para) { int max_renew_attempts = 1; int renew_attempts = max_renew_attempts; int attempts = 2; if(Renew) { if(!ValidIP(RequestedAddr)) { throw new Exception("Invalid requested address: " + Utils.BytesToString(RequestedAddr, '.')); } MemBlock request_addr = MemBlock.Reference(RequestedAddr); renew_attempts = 2; attempts = 1; if(request_addr.Equals(_current_ip) && Brunet.DateTime.UtcNow < _current_quarter_lifetime) { return _current_ip; } } else if(RequestedAddr == null || !ValidIP(RequestedAddr)) { RequestedAddr = MemBlock.Reference(RandomIPAddress()); } byte[] hostname = null; if(para.Length > 0 && para[0] is string) { string shostname = para[0] as string; if(!shostname.Equals(string.Empty)) { hostname = Encoding.UTF8.GetBytes(Config.Namespace + "." + shostname + "." + Dns.DomainName); } } byte[] multicast_key = null; if(_multicast) { multicast_key = Encoding.UTF8.GetBytes(Config.Namespace + ".multicast.ipop"); } byte[] node_addr = Encoding.UTF8.GetBytes(node_address); bool res = false; while (attempts-- > 0) { string str_addr = Utils.BytesToString(RequestedAddr, '.'); ProtocolLog.WriteIf(IpopLog.DhcpLog, "Attempting to allocate IP Address:" + str_addr); byte[] dhcp_key = Encoding.UTF8.GetBytes("dhcp:" + Config.Namespace + ":" + str_addr); byte[] ip_addr = Encoding.UTF8.GetBytes(str_addr); while(renew_attempts-- > 0) { try { res = _dht.Create(dhcp_key, node_addr, Config.LeaseTime); if(hostname != null) { _dht.Put(hostname, ip_addr, Config.LeaseTime); } if(_multicast) { _dht.Put(multicast_key, node_addr, Config.LeaseTime); } // _dht.Put(node_addr, dhcp_key, Config.LeaseTime); } catch(Exception e) { ProtocolLog.WriteIf(IpopLog.DhcpLog, "Unable to allocate: " + e.Message); res = false; } } if(res) { _current_ip = MemBlock.Reference(RequestedAddr); _current_quarter_lifetime = Brunet.DateTime.UtcNow.AddSeconds(Config.LeaseTime / 4.0); break; } else { // Failure! Guess a new IP address RequestedAddr = RandomIPAddress(); renew_attempts = max_renew_attempts; } } if(!res) { throw new Exception("Unable to get an IP Address!"); } return RequestedAddr; }
/** * <summary>This provides a mechanism for a node to get a lease by using the * Dht. This uses Dht.Create which provides an atomic operation on the Dht, * where this node is the first to store a value at a specific key. The idea * being that, this node being the first to store the IP, all nodes doing a * lookup for that IP Address would be directed to this node.</summary> * <remarks>Working with the Dht is a little tricky as transient errors could * be misrepresented as a failed Create. It is that reason why there is a * Renew parameter. If that is set, the algorithm for obtaining an address * is slightly changed with more weight on reobtaining the RequestedAddr. * </remarks> * <param name="RequestedAddr">Optional parameter if the node would like to * request a specific address.</param> * <param name="Renew">Is the RequestedAddr a renewal?</param> * <param name="node_address">The Brunet.Address where the DhtIpopNode resides * </param> * <param name="para">Optional, position 0 should hold the hostname.</param> */ public override byte[] RequestLease(byte[] RequestedAddr, bool Renew, string node_address, params object[] para) { int max_renew_attempts = 1; int renew_attempts = max_renew_attempts; int attempts = 2; if (Renew) { if (!ValidIP(RequestedAddr)) { throw new Exception("Invalid requested address: " + Utils.BytesToString(RequestedAddr, '.')); } MemBlock request_addr = MemBlock.Reference(RequestedAddr); renew_attempts = 2; attempts = 1; if (request_addr.Equals(_current_ip) && Brunet.DateTime.UtcNow < _current_quarter_lifetime) { return(_current_ip); } } else if (RequestedAddr == null || !ValidIP(RequestedAddr)) { RequestedAddr = MemBlock.Reference(RandomIPAddress()); } byte[] hostname = null; if (para.Length > 0 && para[0] is string) { string shostname = para[0] as string; if (!shostname.Equals(string.Empty)) { hostname = Encoding.UTF8.GetBytes(Config.Namespace + "." + shostname + "." + Dns.DomainName); } } byte[] multicast_key = null; if (_multicast) { multicast_key = Encoding.UTF8.GetBytes(Config.Namespace + ".multicast.ipop"); } byte[] node_addr = Encoding.UTF8.GetBytes(node_address); bool res = false; while (attempts-- > 0) { string str_addr = Utils.BytesToString(RequestedAddr, '.'); ProtocolLog.WriteIf(IpopLog.DhcpLog, "Attempting to allocate IP Address:" + str_addr); byte[] dhcp_key = Encoding.UTF8.GetBytes("dhcp:" + Config.Namespace + ":" + str_addr); byte[] ip_addr = Encoding.UTF8.GetBytes(str_addr); while (renew_attempts-- > 0) { try { res = _dht.Create(dhcp_key, node_addr, Config.LeaseTime); if (hostname != null) { _dht.Put(hostname, ip_addr, Config.LeaseTime); } if (_multicast) { _dht.Put(multicast_key, node_addr, Config.LeaseTime); } // _dht.Put(node_addr, dhcp_key, Config.LeaseTime); } catch (Exception e) { ProtocolLog.WriteIf(IpopLog.DhcpLog, "Unable to allocate: " + e.Message); res = false; } } if (res) { _current_ip = MemBlock.Reference(RequestedAddr); _current_quarter_lifetime = Brunet.DateTime.UtcNow.AddSeconds(Config.LeaseTime / 4.0); break; } else { // Failure! Guess a new IP address RequestedAddr = RandomIPAddress(); renew_attempts = max_renew_attempts; } } if (!res) { throw new Exception("Unable to get an IP Address!"); } return(RequestedAddr); }
/// <summary>Tasks that should be performed during startup until completion /// and repetitive tasks are added here. protected void CheckNode(object o, EventArgs ea) { lock(_sync) { if(_dhcp_config == null) { GetDhcpConfig(); if(_dhcp_config == null) { return; } } // The rest doesn't quite work right yet... Brunet.DateTime now = Brunet.DateTime.UtcNow; if((now - _last_check_node).TotalSeconds < 30) { return; } _last_check_node = now; } ThreadPool.QueueUserWorkItem(CheckNetwork); }
/// <summary>Creates an IpopNode given a NodeConfig and an IpopConfig. /// Also sets up the Information, Ethernet device, and subscribes /// to Brunet for IP Packets</summary> /// <param name="node_config">The path to a NodeConfig xml file</param> /// <param name="ipop_config">The path to a IpopConfig xml file</param> public IpopNode(NodeConfig node_config, IpopConfig ipop_config, DHCPConfig dhcp_config) : base(node_config) { PublicNode = CreateNode(node_config); PublicNode.Node.DisconnectOnOverload = false; if(PublicNode.PrivateNode == null) { AppNode = PublicNode; } else { AppNode = PublicNode.PrivateNode; AppNode.Node.DisconnectOnOverload = false; } _ondemand = new OnDemandConnectionOverlord(AppNode.Node); AppNode.Node.AddConnectionOverlord(_ondemand); _ipop_config = ipop_config; Ethernet = new Ethernet(_ipop_config.VirtualNetworkDevice); Ethernet.Subscribe(this, null); Info = new Information(AppNode.Node, "IpopNode", AppNode.SecurityOverlord); Info.UserData["IpopNamespace"] = _ipop_config.IpopNamespace; if(PublicNode == AppNode) { PublicInfo = Info; } else { PublicInfo = new Information(PublicNode.Node, "PrivateIpopNode", PublicNode.SecurityOverlord); PublicInfo.UserData["IpopNamespace"] = _ipop_config.IpopNamespace; } if(_ipop_config.EndToEndSecurity && AppNode.SymphonySecurityOverlord != null) { _secure_senders = true; } else { _secure_senders = false; } AppNode.Node.GetTypeSource(PType.Protocol.IP).Subscribe(this, null); _sync = new object(); _lock = 0; _ether_to_ip = new Dictionary<MemBlock, MemBlock>(); _ip_to_ether = new Dictionary<MemBlock, MemBlock>(); _dhcp_server_port = _ipop_config.DHCPPort != 0 ? _ipop_config.DHCPPort : 67; _dhcp_client_port = _dhcp_server_port + 1; ProtocolLog.WriteIf(IpopLog.DhcpLog, String.Format( "Setting Dhcp Ports to: {0},{1}", _dhcp_server_port, _dhcp_client_port)); _ether_to_dhcp_server = new Dictionary<MemBlock, DhcpServer>(); _static_mapping = new Dictionary<MemBlock, SimpleTimer>(); _dhcp_config = dhcp_config; if(_dhcp_config != null) { SetDns(); SetTAAuth(); _dhcp_server = GetDhcpServer(); } _checked_out = new Hashtable(); AppNode.Node.HeartBeatEvent += CheckNode; _last_check_node = Brunet.DateTime.UtcNow; AppNode.Node.Rpc.AddHandler("Ipop", this); }
/// <summary>Parses web data and updates the revoked users hashtable if /// successful</summary> protected void UpdateRl(byte[] data) { // message is length (4) + date (8) + data (variable) + hash (~20) int length = data.Length; if(length < 12) { throw new Exception("No data? Didn't get enough data..."); } length = NumberSerializer.ReadInt(data, 0); Brunet.DateTime date = new Brunet.DateTime(NumberSerializer.ReadLong(data, 4)); // warn the user that this is an old revocation list, maybe there is an attack if(date < Brunet.DateTime.UtcNow.AddHours(-24)) { ProtocolLog.WriteIf(IpopLog.GroupVPN, "Revocation list is over 24 hours old"); } // Weird, data length is longer than the data we got if(length > data.Length - 12) { throw new Exception("Missing data? Didn't get enough data..."); } // hash the data and verify the signature SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider(); byte[] hash = sha1.ComputeHash(data, 4, length); byte[] signature = new byte[data.Length - 4 - length]; Array.Copy(data, 4 + length, signature, 0, signature.Length); if(!_ca_cert.PublicKey.VerifyHash(hash, CryptoConfig.MapNameToOID("SHA1"), signature)) { throw new Exception("Invalid signature!"); } // convert the data to an array list as it was sent to us MemBlock mem = MemBlock.Reference(data, 12, length - 8); ArrayList rl = AdrConverter.Deserialize(mem) as ArrayList; if(rl == null) { throw new Exception("Data wasn't a list..."); } // convert it into a hashtable for O(1) look ups Hashtable ht = new Hashtable(); foreach(string username in rl) { ht[username] = true; } Interlocked.Exchange(ref _revoked_users, ht); }
/// <summary>Creates an IpopNode given a NodeConfig and an IpopConfig. /// Also sets up the Information, Ethernet device, and subscribes /// to Brunet for IP Packets</summary> /// <param name="node_config">The path to a NodeConfig xml file</param> /// <param name="ipop_config">The path to a IpopConfig xml file</param> public IpopNode(NodeConfig node_config, IpopConfig ipop_config, DHCPConfig dhcp_config) : base(node_config) { PublicNode = CreateNode(node_config); PublicNode.Node.DisconnectOnOverload = false; if (PublicNode.PrivateNode == null) { AppNode = PublicNode; } else { AppNode = PublicNode.PrivateNode; AppNode.Node.DisconnectOnOverload = false; } _ondemand = new OnDemandConnectionOverlord(AppNode.Node); AppNode.Node.AddConnectionOverlord(_ondemand); _ipop_config = ipop_config; Ethernet = new Ethernet(_ipop_config.VirtualNetworkDevice); Ethernet.Subscribe(this, null); Info = new Information(AppNode.Node, "IpopNode", AppNode.SecurityOverlord); Info.UserData["IpopNamespace"] = _ipop_config.IpopNamespace; if (PublicNode == AppNode) { PublicInfo = Info; } else { PublicInfo = new Information(PublicNode.Node, "PrivateIpopNode", PublicNode.SecurityOverlord); PublicInfo.UserData["IpopNamespace"] = _ipop_config.IpopNamespace; } if (_ipop_config.EndToEndSecurity && AppNode.SymphonySecurityOverlord != null) { _secure_senders = true; } else { _secure_senders = false; } AppNode.Node.GetTypeSource(PType.Protocol.IP).Subscribe(this, null); _sync = new object(); _lock = 0; _ether_to_ip = new Dictionary <MemBlock, MemBlock>(); _ip_to_ether = new Dictionary <MemBlock, MemBlock>(); _dhcp_server_port = _ipop_config.DHCPPort != 0 ? _ipop_config.DHCPPort : 67; _dhcp_client_port = _dhcp_server_port + 1; ProtocolLog.WriteIf(IpopLog.DhcpLog, String.Format( "Setting Dhcp Ports to: {0},{1}", _dhcp_server_port, _dhcp_client_port)); _ether_to_dhcp_server = new Dictionary <MemBlock, DhcpServer>(); _static_mapping = new Dictionary <MemBlock, SimpleTimer>(); _dhcp_config = dhcp_config; if (_dhcp_config != null) { SetDns(); SetTAAuth(); _dhcp_server = GetDhcpServer(); } _checked_out = new Hashtable(); AppNode.Node.HeartBeatEvent += CheckNode; _last_check_node = Brunet.DateTime.UtcNow; AppNode.Node.Rpc.AddHandler("Ipop", this); }