using System; using System.Net.Sockets; using ln.types.net; using System.Net; using System.Net.NetworkInformation; using System.Threading; using ln.logging; using System.Text; namespace ln.dhcp { public class DHCPListener { public DHCPServer DHCPServer { get; private set; } public DHCPServerInterface ServerInterface { get; private set; } public IPv4 InterfaceAddress => ServerInterface.InterfaceAddress; public InterfaceConfiguration ListeningInterfaceConfiguration { get; private set; } public IPv4 ListeningAddress { get; private set; } UdpClient udpClient; Thread listenerThread; public DHCPListener(DHCPServer dhcpServer,DHCPServerInterface serverInterface) { DHCPServer = dhcpServer; ServerInterface = serverInterface; ListeningInterfaceConfiguration = FindNetworkInterface(InterfaceAddress); if (Environment.OSVersion.Platform == PlatformID.Win32NT) SetupWindows(); else SetupLinux(); } public void Start() { if (((listenerThread == null) || !listenerThread.IsAlive) && (ListeningInterfaceConfiguration != null)) { listenerThread = new Thread(() => InterfaceListener()); listenerThread.Start(); } } public void Close() { udpClient.Close(); } public InterfaceConfiguration FindNetworkInterface(IPv4 interfaceAddr) { NetworkInterface[] networkInterfaces = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces(); foreach (NetworkInterface networkInterface in networkInterfaces) { foreach (UnicastIPAddressInformation addressInformation in networkInterface.GetIPProperties().UnicastAddresses) { if (interfaceAddr.Equals(addressInformation.Address)) { return new InterfaceConfiguration(networkInterface.Name, addressInformation.Address, addressInformation.IPv4Mask); } } } return null; } private void SetupWindows() { if (ListeningInterfaceConfiguration == null) return; ListeningAddress = ListeningInterfaceConfiguration.BroadcastAddress; } private void SetupLinux() { if (ListeningInterfaceConfiguration == null) return; ListeningAddress = IPAddress.Any; } private void FixupSocket() { if (Environment.OSVersion.Platform != PlatformID.Win32NT) { IntPtr socket = udpClient.Client.Handle; byte[] ifName = Encoding.ASCII.GetBytes(ListeningInterfaceConfiguration.Name); int result = Mono.Unix.Native.Syscall.setsockopt( (int)socket, Mono.Unix.Native.UnixSocketProtocol.SOL_SOCKET, Mono.Unix.Native.UnixSocketOptionName.SO_BINDTODEVICE, ifName, ifName.Length ); } } private void InterfaceListener() { udpClient = new UdpClient(new IPEndPoint(ListeningAddress, 67)); udpClient.EnableBroadcast = true; FixupSocket(); try { Logging.Log(LogLevel.INFO, "InterfaceListener started: {0}", ServerInterface.InterfaceAddress); while (true) { IPEndPoint remoteEndpoint = new IPEndPoint(IPAddress.Any, 0); byte[] rxBytes = udpClient.Receive(ref remoteEndpoint); Logging.Log(LogLevel.INFO, "RX: {0} {1}", ServerInterface.InterfaceAddress,BitConverter.ToString(rxBytes)); BootPPacket bootPPacket = new BootPPacket(rxBytes, remoteEndpoint); Logging.Log(LogLevel.INFO, "RX: {0} {1}", ServerInterface.InterfaceAddress, bootPPacket); DHCPServer.Pool.Enqueue(() => DHCPServer.Received(ServerInterface, bootPPacket)); } } catch (Exception e) { Logging.Log(LogLevel.WARNING, "DHCPServer.InterfaceListener(): Caught exception: {0}", e); } Logging.Log(LogLevel.INFO, "InterfaceListener stopped: {0}", ServerInterface.InterfaceAddress); lock (this) { udpClient.Dispose(); listenerThread = null; } } public void Send(byte[] packet,IPEndPoint remoteEndpoint) { Logging.Log(LogLevel.INFO, "DHCPListener: Send(): {0} {1}", remoteEndpoint, BitConverter.ToString(packet)); udpClient.Send(packet, packet.Length, remoteEndpoint); } public class InterfaceConfiguration { public String Name; public IPv4 Address; public IPv4 Netmask; public Network4 Network => new Network4(Address, Netmask); public IPv4 BroadcastAddress => Network.Last; public InterfaceConfiguration(String name,IPv4 address,IPv4 netmask) { Name = name; Address = address; Netmask = netmask; } } } }