///<summary>This sends an ICMP Request to the specified address, we want ///him to respond to us, so we can guarantee that by pretending to be the ///Server (i.e. x.y.z.1). We'll get a response in our main thread.</summary> ///<param name="dest_ip">Destination IP of our request.</summary> protected virtual void SendICMPRequest(MemBlock dest_ip) { if(_dhcp_server == null) { return; } MemBlock ether_addr = null; if(!_ip_to_ether.TryGetValue(dest_ip, out ether_addr)) { ether_addr = EthernetPacket.BroadcastAddress; } ICMPPacket icmp = new ICMPPacket(ICMPPacket.Types.EchoRequest); IPPacket ip = new IPPacket(IPPacket.Protocols.ICMP, _dhcp_server.ServerIP, dest_ip, icmp.Packet); EthernetPacket ether = new EthernetPacket(ether_addr, EthernetPacket.UnicastAddress, EthernetPacket.Types.IP, ip.ICPacket); Ethernet.Send(ether.ICPacket); }
/// <summary>Writes an IPPacket as is to the TAP device.</summary> /// <param name="packet">The IPPacket!</param> protected virtual void WriteIP(ICopyable packet) { MemBlock mp = packet as MemBlock; if(mp == null) { mp = MemBlock.Copy(packet); } IPPacket ipp = new IPPacket(mp); MemBlock dest = null; if(!_ip_to_ether.TryGetValue(ipp.DestinationIP, out dest)) { return; } EthernetPacket res_ep = new EthernetPacket(_ip_to_ether[ipp.DestinationIP], EthernetPacket.UnicastAddress, EthernetPacket.Types.IP, mp); Ethernet.Send(res_ep.ICPacket); }
/// <summary>This is used to process a dhcp packet on the node side, that /// includes placing data such as the local Brunet Address, Ipop Namespace, /// and other optional parameters in our request to the dhcp server. When /// receiving the results, if it is successful, the results are written to /// the TAP device.</summary> /// <param name="ipp"> The IPPacket that contains the DHCP Request</param> /// <param name="dhcp_params"> an object containing any extra parameters for /// the dhcp server</param> /// <returns> true on if dhcp is supported.</returns> protected virtual bool HandleDHCP(IPPacket ipp) { UDPPacket udpp = new UDPPacket(ipp.Payload); DHCPPacket dhcp_packet = new DHCPPacket(udpp.Payload); MemBlock ether_addr = dhcp_packet.chaddr; if(_dhcp_config == null) { return true; } DHCPServer dhcp_server = CheckOutDHCPServer(ether_addr); if(dhcp_server == null) { return true; } MemBlock last_ip = null; _ether_to_ip.TryGetValue(ether_addr, out last_ip); byte[] last_ipb = (last_ip == null) ? null : (byte[]) last_ip; WaitCallback wcb = delegate(object o) { ProtocolLog.WriteIf(IpopLog.DHCPLog, String.Format( "Attemping DHCP for: {0}", Utils.MemBlockToString(ether_addr, '.'))); DHCPPacket rpacket = null; try { rpacket = dhcp_server.ProcessPacket(dhcp_packet, Brunet.Address.ToString(), last_ipb); } catch(Exception e) { ProtocolLog.WriteIf(IpopLog.DHCPLog, e.Message); CheckInDHCPServer(dhcp_server); return; } /* Check our allocation to see if we're getting a new address */ MemBlock new_addr = rpacket.yiaddr; UpdateMapping(ether_addr, new_addr); MemBlock destination_ip = ipp.SourceIP; if(destination_ip.Equals(IPPacket.ZeroAddress)) { destination_ip = IPPacket.BroadcastAddress; } UDPPacket res_udpp = new UDPPacket(_dhcp_server_port, _dhcp_client_port, rpacket.Packet); IPPacket res_ipp = new IPPacket(IPPacket.Protocols.UDP, rpacket.siaddr, destination_ip, res_udpp.ICPacket); EthernetPacket res_ep = new EthernetPacket(ether_addr, EthernetPacket.UnicastAddress, EthernetPacket.Types.IP, res_ipp.ICPacket); Ethernet.Send(res_ep.ICPacket); CheckInDHCPServer(dhcp_server); }; ThreadPool.QueueUserWorkItem(wcb); return true; }
/// <summary>This method handles IPPackets that come from the TAP Device, i.e., /// local system.</summary> /// <remarks>Currently this supports HandleMulticast (ip[0] >= 244 && /// ip[0]<=239), HandleDNS (dport = 53 and ip[3] == 1), dhcp (sport 68 and /// dport 67.</remarks> /// <param name="packet">The packet from the TAP device</param> /// <param name="from"> This should always be the tap device</param> protected virtual void HandleIPOut(EthernetPacket packet, ISender ret) { IPPacket ipp = new IPPacket(packet.Payload); if(IpopLog.PacketLog.Enabled) { ProtocolLog.Write(IpopLog.PacketLog, String.Format( "Outgoing {0} packet::IP src: {1}, IP dst: {2}", ipp.Protocol, ipp.SSourceIP, ipp.SDestinationIP)); } if(!IsLocalIP(ipp.SourceIP)) { HandleNewStaticIP(packet.SourceAddress, ipp.SourceIP); return; } if(ipp.DestinationIP[0] >= 224 && ipp.DestinationIP[0] <= 239) { if(HandleMulticast(ipp)) { return; } } switch(ipp.Protocol) { case IPPacket.Protocols.UDP: UDPPacket udpp = new UDPPacket(ipp.Payload); if(udpp.SourcePort == _dhcp_client_port && udpp.DestinationPort == _dhcp_server_port) { if(HandleDHCP(ipp)) { return; } } else if(udpp.DestinationPort == 53 &&ipp.DestinationIP.Equals(_dhcp_server.ServerIP)) { if(HandleDNS(ipp)) { return; } } break; } if(HandleOther(ipp)) { return; } if(_dhcp_server == null || ipp.DestinationIP.Equals(_dhcp_server.ServerIP)) { return; } AHAddress target = (AHAddress) _address_resolver.Resolve(ipp.DestinationIP); if (target != null) { if(IpopLog.PacketLog.Enabled) { ProtocolLog.Write(IpopLog.PacketLog, String.Format( "Brunet destination ID: {0}", target)); } SendIP(target, packet.Payload); } }
/// <summary>Parses ARP Packets and writes to the Ethernet the translation.</summary> /// <remarks>IpopRouter makes nodes think they are in the same Layer 2 network /// so that two nodes in the same network can communicate directly with each /// other. IpopRouter masquerades for those that are not local.</remarks> /// <param name="ep">The Ethernet packet to translate</param> protected virtual void HandleARP(MemBlock packet) { // Can't do anything until we have network connectivity! if(_dhcp_server == null) { return; } ARPPacket ap = new ARPPacket(packet); // Not in our range! if(!_dhcp_server.IPInRange((byte[]) ap.TargetProtoAddress) && !_dhcp_server.IPInRange((byte[]) ap.SenderProtoAddress)) { ProtocolLog.WriteIf(IpopLog.ARP, String.Format("Bad ARP request from {0} for {1}", Utils.MemBlockToString(ap.SenderProtoAddress, '.'), Utils.MemBlockToString(ap.TargetProtoAddress, '.'))); return; } if(ap.Operation == ARPPacket.Operations.Reply) { // This would be a unsolicited ARP if(ap.TargetProtoAddress.Equals(IPPacket.BroadcastAddress) && !ap.SenderHWAddress.Equals(EthernetPacket.BroadcastAddress)) { HandleNewStaticIP(ap.SenderHWAddress, ap.SenderProtoAddress); } return; } // We only support request operation hereafter if(ap.Operation != ARPPacket.Operations.Request) { return; } // Must return nothing if the node is checking availability of IPs // Or he is looking himself up. if(_ip_to_ether.ContainsKey(ap.TargetProtoAddress) || ap.SenderProtoAddress.Equals(IPPacket.BroadcastAddress) || ap.SenderProtoAddress.Equals(IPPacket.ZeroAddress)) { return; } // We shouldn't be returning these messages if no one exists at that end // point if(!ap.TargetProtoAddress.Equals(MemBlock.Reference(_dhcp_server.ServerIP))) { Address baddr = _address_resolver.Resolve(ap.TargetProtoAddress); if(Brunet.Address.Equals(baddr) || baddr == null) { return; } } ProtocolLog.WriteIf(IpopLog.ARP, String.Format("Sending ARP response for: {0}", Utils.MemBlockToString(ap.TargetProtoAddress, '.'))); ARPPacket response = ap.Respond(EthernetPacket.UnicastAddress); EthernetPacket res_ep = new EthernetPacket(ap.SenderHWAddress, EthernetPacket.UnicastAddress, EthernetPacket.Types.ARP, response.ICPacket); Ethernet.Send(res_ep.ICPacket); }
/// <summary> This method handles all incoming packets into the IpopNode, both /// abroad and local. This is done to reduce unnecessary extra classes and /// circular dependencies. This method probably shouldn't be called /// directly.</summary> /// <param name="b"> The incoming packet</param> /// <param name="ret">An ISender to return data from the original sender.</param> /// <param name="state">always will be null</param> public void HandleData(MemBlock b, ISender ret, object state) { if(ret is Ethernet) { EthernetPacket ep = new EthernetPacket(b); switch (ep.Type) { case EthernetPacket.Types.ARP: HandleARP(ep.Payload); break; case EthernetPacket.Types.IP: HandleIPOut(ep, ret); break; } } else { HandleIPIn(b, ret); } }
/// <summary>Writes an IPPacket as is to the TAP device.</summary> /// <param name="packet">The IPPacket!</param> protected virtual void WriteIP(ICopyable packet) { MemBlock mp = packet as MemBlock; if(mp == null) { mp = MemBlock.Copy(packet); } IPPacket ipp = new IPPacket(mp); MemBlock dest = null; if(!_ip_to_ether.TryGetValue(ipp.DestinationIP, out dest)) { if(ipp.DestinationIP[0] >= 224 && ipp.DestinationIP[0] <= 239) { dest = EthernetPacket.GetMulticastEthernetAddress(ipp.DestinationIP); } else if(ipp.DestinationIP[3] == 255){ dest = EthernetPacket.BroadcastAddress; } else { return; } } EthernetPacket res_ep = new EthernetPacket(dest, EthernetPacket.UnicastAddress, EthernetPacket.Types.IP, mp); Ethernet.Send(res_ep.ICPacket); }
/// <summary>Parses Arp Packets and writes to the Ethernet the translation.</summary> /// <remarks>IpopRouter makes nodes think they are in the same Layer 2 network /// so that two nodes in the same network can communicate directly with each /// other. IpopRouter masquerades for those that are not local.</remarks> /// <param name="ep">The Ethernet packet to translate</param> protected virtual void HandleArp(MemBlock packet) { // Can't do anything until we have network connectivity! if(_dhcp_server == null) { return; } ArpPacket ap = new ArpPacket(packet); // Not in our range! if(!_dhcp_server.IPInRange((byte[]) ap.TargetProtoAddress) && !_dhcp_server.IPInRange((byte[]) ap.SenderProtoAddress)) { ProtocolLog.WriteIf(IpopLog.Arp, String.Format("Bad Arp request from {0} for {1}", Utils.MemBlockToString(ap.SenderProtoAddress, '.'), Utils.MemBlockToString(ap.TargetProtoAddress, '.'))); return; } if(ap.Operation == ArpPacket.Operations.Reply) { // This would be a unsolicited Arp if(ap.TargetProtoAddress.Equals(IPPacket.BroadcastAddress) && !ap.SenderHWAddress.Equals(EthernetPacket.BroadcastAddress)) { HandleNewStaticIP(ap.SenderHWAddress, ap.SenderProtoAddress); } return; } // We only support request operation hereafter if(ap.Operation != ArpPacket.Operations.Request) { return; } // Must return nothing if the node is checking availability of IPs // Or he is looking himself up. if(_ip_to_ether.ContainsKey(ap.TargetProtoAddress) || ap.SenderProtoAddress.Equals(IPPacket.BroadcastAddress) || ap.SenderProtoAddress.Equals(IPPacket.ZeroAddress)) { return; } if(!ap.TargetProtoAddress.Equals(MemBlock.Reference(_dhcp_server.ServerIP))) { // Do not return messages if there is no connection to the remote address Address baddr = null; try { baddr = _address_resolver.Resolve(ap.TargetProtoAddress); } catch(AddressResolutionException ex) { if(ex.Issue != AddressResolutionException.Issues.DoesNotExist) { throw; } // Otherwise nothing to do, mapping doesn't exist... } if(AppNode.Node.Address.Equals(baddr) || baddr == null) { ProtocolLog.WriteIf(IpopLog.Arp, String.Format("No mapping for: {0}", Utils.MemBlockToString(ap.TargetProtoAddress, '.'))); return; } if(!_conn_handler.ContainsAddress(baddr)) { ProtocolLog.WriteIf(IpopLog.Arp, String.Format( "No connection to {0} for {1}", baddr, Utils.MemBlockToString(ap.TargetProtoAddress, '.'))); _conn_handler.ConnectTo(baddr); return; } } ProtocolLog.WriteIf(IpopLog.Arp, String.Format("Sending Arp response for: {0}", Utils.MemBlockToString(ap.TargetProtoAddress, '.'))); ArpPacket response = ap.Respond(EthernetPacket.UnicastAddress); EthernetPacket res_ep = new EthernetPacket(ap.SenderHWAddress, EthernetPacket.UnicastAddress, EthernetPacket.Types.Arp, response.ICPacket); Ethernet.Send(res_ep.ICPacket); }
/// <summary>This method handles IPPackets that come from the TAP Device, i.e., /// local system.</summary> /// <remarks>Currently this supports HandleMulticast (ip[0] >= 244 && /// ip[0]<=239), HandleDns (dport = 53 and ip[3] == 1), dhcp (sport 68 and /// dport 67.</remarks> /// <param name="packet">The packet from the TAP device</param> /// <param name="from"> This should always be the tap device</param> protected virtual void HandleIPOut(EthernetPacket packet, ISender ret) { IPPacket ipp = new IPPacket(packet.Payload); if(IpopLog.PacketLog.Enabled) { ProtocolLog.Write(IpopLog.PacketLog, String.Format( "Outgoing {0} packet::IP src: {1}, IP dst: {2}", ipp.Protocol, ipp.SSourceIP, ipp.SDestinationIP)); } if(!IsLocalIP(ipp.SourceIP)) { // This really ought to have been caught in ARP, but just in case... HandleNewStaticIP(packet.SourceAddress, ipp.SourceIP); return; } UdpPacket udpp = null; switch(ipp.Protocol) { case IPPacket.Protocols.Udp: udpp = new UdpPacket(ipp.Payload); if(udpp.SourcePort == _dhcp_client_port && udpp.DestinationPort == _dhcp_server_port) { if(HandleDhcp(ipp)) { return; } } else if(udpp.DestinationPort == 53 && ipp.DestinationIP.Equals(_dhcp_server.ServerIP)) { if(HandleDns(ipp)) { return; } } break; } if(ipp.DestinationIP[0] >= 224 && ipp.DestinationIP[0] <= 239) { // We don't want to send Brunet multicast packets over IPOP! if(udpp != null && udpp.DestinationPort == IPHandler.mc_port) { return; } else if(HandleMulticast(ipp)) { return; } } if(ipp.DestinationIP.Equals(IPPacket.BroadcastAddress)) { if(HandleBroadcast(ipp)) { return; } } if(_dhcp_server == null || ipp.DestinationIP.Equals(_dhcp_server.ServerIP)) { return; } Address target = null; try { target = _address_resolver.Resolve(ipp.DestinationIP) as AHAddress; } catch(AddressResolutionException ex) { if(ex.Issue != AddressResolutionException.Issues.DoesNotExist) { throw; } // Otherwise nothing to do, mapping doesn't exist... } if(target != null) { SendIP(target, packet.Payload); } }