156 lines
5.4 KiB
C#
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;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|