/// <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></summary> public DHCPPacket ProcessPacket(DHCPPacket packet, string unique_id, byte[] last_ip, params object[] dhcp_params) { DHCPPacket.MessageTypes message_type = (DHCPPacket.MessageTypes) packet.Options[DHCPPacket.OptionTypes.MESSAGE_TYPE][0]; byte[] requested_ip = last_ip; bool renew = false; if(message_type == DHCPPacket.MessageTypes.DISCOVER) { message_type = DHCPPacket.MessageTypes.OFFER; } else if(message_type == DHCPPacket.MessageTypes.REQUEST) { if(packet.Options.ContainsKey(DHCPPacket.OptionTypes.REQUESTED_IP)) { requested_ip = packet.Options[DHCPPacket.OptionTypes.REQUESTED_IP]; } else if(!packet.ciaddr.Equals(IPPacket.ZeroAddress)) { requested_ip = packet.ciaddr; } renew = true; message_type = DHCPPacket.MessageTypes.ACK; } else { throw new Exception("Unsupported message type!"); } byte[] reply_ip = RequestLease(requested_ip, renew, unique_id, dhcp_params); Dictionary<DHCPPacket.OptionTypes, MemBlock> options = new Dictionary<DHCPPacket.OptionTypes, MemBlock>(); options[DHCPPacket.OptionTypes.DOMAIN_NAME] = Encoding.UTF8.GetBytes(DNS.DomainName); // The following option is needed for dhcp to "succeed" in Vista, but they break Linux // options[DHCPPacket.OptionTypes.ROUTER] = reply.ip; options[DHCPPacket.OptionTypes.DOMAIN_NAME_SERVER] = MemBlock.Reference(ServerIP); options[DHCPPacket.OptionTypes.SUBNET_MASK] = MemBlock.Reference(Netmask); options[DHCPPacket.OptionTypes.LEASE_TIME] = _lease_time; options[DHCPPacket.OptionTypes.MTU] = _mtu; options[DHCPPacket.OptionTypes.SERVER_ID] = MemBlock.Reference(ServerIP); options[DHCPPacket.OptionTypes.MESSAGE_TYPE] = MemBlock.Reference(new byte[]{(byte) message_type}); DHCPPacket rpacket = new DHCPPacket(2, packet.xid, packet.ciaddr, reply_ip, ServerIP, packet.chaddr, options); return rpacket; }