151 lines
4.8 KiB
C#
151 lines
4.8 KiB
C#
using System;
|
|
using System.Net;
|
|
using ln.types.net;
|
|
using ln.types;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Runtime;
|
|
namespace ln.dhcp
|
|
{
|
|
public enum OP:byte { BOOTREQUEST = 1,BOOTREPLY = 2 }
|
|
[Flags]
|
|
public enum BootPFlags:short
|
|
{
|
|
BROADCAST = 0x0001
|
|
}
|
|
|
|
public class BootPPacket
|
|
{
|
|
public IPEndPoint RemoteEndpoint { get; set; }
|
|
|
|
public OP OP { get; set; }
|
|
public byte HType { get; set; }
|
|
public byte HLen { get; set; }
|
|
public byte Hops { get; set; }
|
|
public uint XID { get; set; }
|
|
public ushort Secs { get; set; }
|
|
public BootPFlags Flags { get; set; }
|
|
public IPv4 CIAddr { get; set; } = IPv4.ANY;
|
|
public IPv4 YIAddr { get; set; } = IPv4.ANY;
|
|
public IPv4 SIAddr { get; set; } = IPv4.ANY;
|
|
public IPv4 GIAddr { get; set; } = IPv4.ANY;
|
|
|
|
public MAC CHAddr { get; set; } = new MAC(new byte[6]);
|
|
|
|
public byte[] SName { get; set; }
|
|
public byte[] File { get; set; }
|
|
public byte[] Vend { get; set; }
|
|
|
|
List<Option> options = new List<Option>();
|
|
public Option[] Options => options.ToArray();
|
|
|
|
static byte[] magicVend = new byte[] { 0x63, 0x82, 0x53, 0x63 };
|
|
|
|
public BootPPacket()
|
|
{
|
|
}
|
|
|
|
public BootPPacket(byte[] bytes,IPEndPoint remoteEndpoint)
|
|
{
|
|
if (bytes.Length < 290)
|
|
throw new ArgumentOutOfRangeException(nameof(bytes), "BootP Packet too small");
|
|
|
|
RemoteEndpoint = remoteEndpoint;
|
|
|
|
OP = (OP)bytes[0];
|
|
HType = bytes[1];
|
|
HLen = bytes[2];
|
|
Hops = bytes[3];
|
|
XID = bytes.GetUInt(4,true);
|
|
Secs = bytes.GetUShort(8, true);
|
|
Flags = (BootPFlags)bytes.GetShort(10, true);
|
|
CIAddr = new IPv4(bytes, 12);
|
|
YIAddr = new IPv4(bytes, 16);
|
|
SIAddr = new IPv4(bytes, 20);
|
|
GIAddr = new IPv4(bytes, 24);
|
|
|
|
if (HLen != 6)
|
|
throw new ArgumentOutOfRangeException(nameof(bytes),"Only 6 byte HW Addresses are supported by this implementation");
|
|
|
|
CHAddr = new MAC(bytes.Slice(28, 6));
|
|
SName = bytes.Slice(44, 64);
|
|
File = bytes.Slice(108, 128);
|
|
Vend = bytes.Slice(236);
|
|
|
|
if ((Vend.Length >= 4) && Vend.Slice(0, 4).AreEqual(magicVend))
|
|
{
|
|
options.AddRange(Option.ParseOptions(Vend, 4));
|
|
}
|
|
|
|
Option overload = GetFirstOption(0x34);
|
|
if (overload != null)
|
|
{
|
|
if ((overload.Bytes[0] & 0x01) != 0)
|
|
options.AddRange(Option.ParseOptions(File, 4));
|
|
if ((overload.Bytes[0] & 0x02) != 0)
|
|
options.AddRange(Option.ParseOptions(SName, 4));
|
|
}
|
|
}
|
|
public byte[] ToBytes()
|
|
{
|
|
MemoryStream memoryStream = new MemoryStream();
|
|
memoryStream.WriteByte((byte)OP);
|
|
memoryStream.WriteByte(HType);
|
|
memoryStream.WriteByte(HLen);
|
|
memoryStream.WriteByte(Hops);
|
|
memoryStream.WriteUInteger(XID);
|
|
memoryStream.WriteUShort(Secs);
|
|
memoryStream.WriteShort((short)Flags);
|
|
memoryStream.WriteBytes(CIAddr.IPBytes);
|
|
memoryStream.WriteBytes(YIAddr.IPBytes);
|
|
memoryStream.WriteBytes(SIAddr.IPBytes);
|
|
memoryStream.WriteBytes(GIAddr.IPBytes);
|
|
memoryStream.WriteBytes(CHAddr.Bytes);
|
|
memoryStream.WriteBytes(new byte[10]);
|
|
memoryStream.WriteBytes(new byte[192]);
|
|
memoryStream.WriteBytes(magicVend);
|
|
|
|
byte[] options = Option.ToBytes(Options);
|
|
memoryStream.WriteBytes(options);
|
|
|
|
return memoryStream.ToArray();
|
|
}
|
|
|
|
|
|
public OT GetFirstOption<OT>() where OT : Option
|
|
{
|
|
foreach (Option option in options)
|
|
{
|
|
if (option is OT)
|
|
return (OT)option;
|
|
}
|
|
return null;
|
|
}
|
|
public Option GetFirstOption(byte tag)
|
|
{
|
|
foreach (Option option in options)
|
|
{
|
|
if (option.Tag == tag)
|
|
return option;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public void RemoveOption(Option option) => options.Remove(option);
|
|
public void AddOption(Option option) => options.Add(option);
|
|
public void SetOption(Option option)
|
|
{
|
|
foreach (Option op in options)
|
|
if (op.Tag == option.Tag)
|
|
RemoveOption(op);
|
|
AddOption(option);
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
return String.Format("[OP={0} Options: {1}]",OP,String.Join(", ", (object[])Options));
|
|
}
|
|
|
|
}
|
|
}
|