ln.dhcp/Option.cs

317 lines
8.7 KiB
C#

using System;
using ln.types;
using System.Collections.Generic;
using ln.types.net;
using System.Linq;
using System.Text;
using System.IO;
namespace ln.dhcp
{
public delegate Option OptionFactory(byte tag, byte[] bytes);
public class Option
{
public byte Tag { get; }
public virtual byte[] Bytes { get; set; }
public Option(byte tag)
{
Tag = tag;
}
public Option(byte tag, byte[] bytes)
{
Tag = tag;
Bytes = bytes;
}
public override string ToString()
{
return String.Format("[Option TAG={0} Bytes={1}]", Tag, BitConverter.ToString(Bytes));
}
static Dictionary<byte, OptionFactory> factories = new Dictionary<byte, OptionFactory>();
static void AddFactory(byte tag, OptionFactory factory) => factories.Add(tag, factory);
public static Option[] ParseOptions(byte[] bytes, int offset)
{
List<Option> options = new List<Option>();
while ((offset < bytes.Length) && (bytes[offset] != 0xff))
if (bytes[offset] != 0x00)
options.Add(Option.Parse(bytes, ref offset));
else
offset++;
return options.ToArray();
}
public static Option Parse(byte[] bytes, ref int offset)
{
Console.WriteLine("OFFSET: {0}", offset);
switch (bytes[offset])
{
case 0:
case 255:
return new Option(bytes[offset++]);
default:
byte tag = bytes[offset++];
byte len = bytes[offset++];
byte[] slice = bytes.Slice(offset, len);
offset += len;
if (factories.ContainsKey(tag))
return factories[tag](tag, slice);
else
return new Option(tag, slice);
}
}
public static byte[] ToBytes(IEnumerable<Option> options)
{
MemoryStream memoryStream = new MemoryStream();
foreach(Option option in options)
{
byte[] b = option.Bytes;
memoryStream.WriteByte(option.Tag);
memoryStream.WriteByte((byte)(b.Length));
memoryStream.Write(b, 0, b.Length);
}
memoryStream.WriteByte(0xff);
return memoryStream.ToArray();
}
static Option()
{
AddFactory(0x01, (tag, bytes) => new NetmaskOption(bytes)); // Netmask
AddFactory(0x03, (tag, bytes) => new GatewaysOption(bytes)); // Gateways
AddFactory(0x0C, (tag, bytes) => new TextOption(tag, bytes)); // Host Name
AddFactory(0x0F, (tag, bytes) => new TextOption(tag, bytes)); // Domain Name
AddFactory(0x32, (tag, bytes) => new DHCPRequestedIPOption(bytes)); // Requested IP
AddFactory(0x33, (tag, bytes) => new DHCPLeaseTimeOption(bytes));// Lease Time
AddFactory(0x35, (tag, bytes) => new DHCPMessageTypeOption(bytes[0])); // DHCP Message Type
AddFactory(0x36, (tag, bytes) => new DHCPServerIdentifierOption(bytes)); // Server ID
}
}
public class IPv4ListOption : Option
{
public IPv4[] IPs { get; set; }
public override byte[] Bytes
{
get => IPs.SelectMany(ip => ip.IPBytes).ToArray();
set
{
IPs = new IPv4[value.Length / 4];
for (int n = 0; n < value.Length / 4; n++)
IPs[n] = new IPv4(value.Slice(n * 4, 4));
}
}
public IPv4ListOption(byte tag)
:base(tag)
{
IPs = new IPv4[0];
}
public IPv4ListOption(byte tag, IPv4[] ips)
: base(tag)
{
IPs = ips.Slice(0);
}
public IPv4ListOption(byte tag, byte[] bytes)
: base(tag)
{
IPs = new IPv4[] { new IPv4(bytes) };
}
}
public class GatewaysOption : IPv4ListOption
{
public GatewaysOption()
: base(0x03,new byte[0])
{
}
public GatewaysOption(byte[] bytes)
: base(0x03,bytes)
{
}
public GatewaysOption(IEnumerable<IPv4> gateways)
: base(0x03)
{
IPs = gateways.ToArray();
}
}
public class IPv4Option : Option
{
public IPv4 IP { get; set; }
public override byte[] Bytes
{
get => IP.IPBytes;
set => IP = new IPv4(value);
}
public IPv4Option(byte tag)
: base(tag)
{ }
public IPv4Option(byte tag, IPv4 ip)
: base(tag)
{
IP = ip;
}
public IPv4Option(byte tag, byte[] bytes)
: base(tag)
{
Bytes = bytes;
}
}
public class NetmaskOption : IPv4Option
{
public NetmaskOption()
: base(0x01)
{ }
public NetmaskOption(byte[] bytes)
: base(0x01)
{
Bytes = bytes;
}
public NetmaskOption(IPv4 ip)
: base(0x01, ip)
{ }
}
public class DHCPRequestedIPOption : IPv4Option
{
public DHCPRequestedIPOption()
: base(0x32)
{ }
public DHCPRequestedIPOption(byte[] bytes)
: base(0x32)
{
Bytes = bytes;
}
public DHCPRequestedIPOption(IPv4 ip)
: base(0x32, ip)
{ }
public override string ToString()
{
return string.Format("DHCPRequestedIP={0}",IP);
}
}
public class DHCPServerIdentifierOption : IPv4Option
{
public DHCPServerIdentifierOption()
: base(0x36)
{ }
public DHCPServerIdentifierOption(byte[] bytes)
: base(0x36)
{
IP = new IPv4(bytes);
}
public DHCPServerIdentifierOption(IPv4 ip)
: base(0x36, ip)
{ }
public override string ToString()
{
return string.Format("DHCPServerIdentifier={0}",IP);
}
}
public class TextOption : Option
{
public String Text { get; set; }
public override byte[] Bytes
{
get => Encoding.UTF8.GetBytes(Text);
set => Text = Encoding.UTF8.GetString(value);
}
public TextOption(byte tag)
: base(tag)
{ }
public TextOption(byte tag, byte[] bytes)
: base(tag)
{
Bytes = bytes;
}
public TextOption(byte tag, string text)
: this(tag)
{
Text = text;
}
}
public class IntegerOption : Option
{
public int Integer { get; set; }
public override byte[] Bytes
{
get => Integer.GetBytes(true);
set => Integer = value.GetInt(true);
}
public IntegerOption(byte tag)
: base(tag)
{ }
public IntegerOption(byte tag, byte[] bytes)
: base(tag)
{
Bytes = bytes;
}
public IntegerOption(byte tag, int i)
: this(tag)
{
Integer = i;
}
}
public class DHCPLeaseTimeOption : IntegerOption
{
public DHCPLeaseTimeOption(byte[] val)
: base(0x33, val)
{}
public DHCPLeaseTimeOption(int leaseTime)
: base(0x33)
{
Integer = leaseTime;
}
public DHCPLeaseTimeOption(DateTimeOffset validThrough)
:base(0x33)
{
Integer = (int)(validThrough - DateTimeOffset.Now).TotalSeconds;
}
public override string ToString()
{
return String.Format("DHCPLeaseTime={0}s",Integer);
}
}
public class DHCPMessageTypeOption : Option
{
public DHCPMessageType DHCPMessageType { get; set; }
public override byte[] Bytes
{
get => new byte[] { (byte)DHCPMessageType };
set => DHCPMessageType = value.Length > 0 ? (DHCPMessageType)value[0] : DHCPMessageType.DISCOVER;
}
public DHCPMessageTypeOption()
: base(0x35)
{
}
public DHCPMessageTypeOption(DHCPMessageType messageType)
: base(0x35)
{
DHCPMessageType = messageType;
}
public DHCPMessageTypeOption(byte value)
: this()
{
DHCPMessageType = (DHCPMessageType)value;
}
public override string ToString()
{
return string.Format("DHCPMessageType={0}",DHCPMessageType);
}
}
}