/// <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; }
/// <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( "Attempting Dhcp for: {0}", Utils.MemBlockToString(ether_addr, '.'))); DhcpPacket rpacket = null; try { rpacket = dhcp_server.ProcessPacket(dhcp_packet, AppNode.Node.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; }