ln.dhcp/DHCPListener.cs

156 lines
5.4 KiB
C#

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;
}
}
}
}