DHCP Works now.

git-svn-id: https://spexeah.com:8443/svn/Asuro@1034 6dbc8c32-bb84-406f-8558-d1cf31a0ab0c
This commit is contained in:
kieron
2020-07-12 17:02:14 +00:00
parent 46cb414b43
commit fbc59a1617
12 changed files with 389 additions and 166 deletions

View File

@ -1,3 +1,8 @@
{
Driver->Net->L5->DHCP - Dynamic Host Configuration Protocol Driver.
@author(Kieron Morris <kjm@kieronmorris.me>)
}
unit dhcp;
interface
@ -5,7 +10,7 @@ interface
uses
lmemorymanager, console,
nettypes, netutils, udp, netlog, net,
util, rand, lists, tracer, ipv4;
util, rand, lists, tracer, ipv4, arp;
type
TDHCPOptions = PLinkedListBase;
@ -26,16 +31,59 @@ implementation
type
TFlipExclude = Array[0..255] of boolean;
PFlipExclude = ^TFlipExclude;
TDHCPConfiguration = record
Transaction : uint32;
Options : array[0..255] of void;
end;
PDHCPConfiguation = ^TDHCPConfiguration;
var
XID : uint32;
Socket : PUDPBindContext;
FlipExclude : PFlipExclude;
Configuration : PDHCPConfiguation;
Socket : PUDPBindContext = nil;
FlipExclude : PFlipExclude;
procedure nullConfiguration;
var
i : uint8;
begin
if configuration <> nil then begin
Configuration^.Transaction:= 0;
for i:=0 to 255 do begin
if Configuration^.Options[i] <> nil then begin
kfree(Configuration^.Options[i]);
end;
Configuration^.Options[i]:= nil;
end;
end;
end;
function createHeader(): PDHCPHeader;
var
result : PDHCPHeader;
MAC : puint8;
function newHeader : PDHCPHeader;
begin
tracer.push_trace('dhcp.newHeader');
newHeader:= PDHCPHeader(kalloc(sizeof(TDHCPHeader)));
result:= PDHCPHeader(kalloc(sizeof(TDHCPHeader)));
result^.Message_Type:= $01;
result^.Hardware_Type:= $01;
result^.Hardware_Address_Length:= $06;
result^.Hops:= $00;
result^.Transaction_ID:= Configuration^.Transaction;
result^.Seconds_Elapsed:= $0000;
result^.Bootp_Flags:= $0000;
CopyIPv4(@NULL_IP[0], @result^.Client_IP[0]);
CopyIPv4(@NULL_IP[0], @result^.Your_IP[0]);
CopyIPv4(@NULL_IP[0], @result^.Server_IP[0]);
CopyIPv4(@NULL_IP[0], @result^.Relay_Agent_IP[0]);
MAC:= getMAC;
CopyMAC(MAC, @result^.Client_MAC[0]);
memset(uint32(@result^.Padding[0]), 0, 10);
memset(uint32(@result^.Server_Hostname[0]), 0, 64);
memset(uint32(@result^.Boot_File[0]), 0, 128);
memcpy(uint32(@DHCP_MAGIC[0]), uint32(@result^.Magic_Cookie[0]), 4);
createHeader:= result;
end;
function newOption(DHCPOptions : PDHCPOptions; Opcode : TDHCPOpCode; Data : void; Length : uint32; SwapEndian : Boolean) : PDHCPOption;
@ -145,6 +193,30 @@ begin
getEndianCorrectValue32:= Value;
end;
function readOption8(Option : PDHCPOption) : uint8;
var
read8 : puint8;
begin
read8:= puint8(Option^.Value);
readOption8:= read8^;
end;
function readOption16(Option : PDHCPOption) : uint16;
var
read16 : puint16;
begin
read16:= puint16(Option^.Value);
readOption16:= read16^;
end;
function readOption32(Option : PDHCPOption) : uint32;
var
read32 : puint32;
begin
read32:= puint32(Option^.Value);
readOption32:= read32^;
end;
function writeOptions(Header : PDHCPHeader; Options : PDHCPOptions; newLength : puint16) : PDHCPHeader;
var
OptionsSize : uint16;
@ -165,7 +237,7 @@ begin
NewBuffer:= kalloc(TotalSize);
//Copy over Header
NewHeader:= PDHCPHeader(buffer);
NewHeader:= PDHCPHeader(NewBuffer);
memcpy(uint32(Header), uint32(NewHeader), sizeof(TDHCPHeader));
//Write all options
@ -221,14 +293,26 @@ var
begin
tracer.push_trace('dhcp.register');
{ Get the beginning & end of the Options buffer }
HeaderSize:= sizeOf(TDHCPHeader);
bufferEnd:= puint8(uint32(p_data) + p_len);
bufferStart:= puint8(uint32(p_data) + headerSize);
{ Buffer is our iterator }
buffer:= bufferStart;
HaveOp:= false;
HaveLen:= false;
while (uint32(buffer) < uint32(bufferEnd)) do begin
{
If we have a length, read the value (bytes[length])
If we have an Opcode read the length (bytes[1])
If we have neither, read the opcode (bytes[1])
}
if HaveLen then begin
{ Get a new option LinkedList 'object' and store everything inside }
Option:= newOption(DHCPOptions, Opcode, void(buffer), Length, not FlipExclude^[ord(Opcode)]);
if Length = 2 then begin
if Option^.Reverse_Endian then begin
@ -263,57 +347,271 @@ begin
end;
end;
procedure processPacket(p_data : void; p_len : uint16; context : PUDPPacketContext);
procedure processHeader(Header : PDHCPHeader);
begin
{ Switch endianness of any network-byte-order values }
Header^.Transaction_ID:= switchendian32(Header^.Transaction_ID);
Header^.Seconds_Elapsed:= switchendian16(Header^.Seconds_Elapsed);
Header^.Bootp_Flags:= switchendian16(Header^.Bootp_Flags);
end;
procedure processPacket_NAK(Header : PDHCPHeader; Options : PDHCPOptions);
begin
console.outputln('DHCP', 'Process NAK.');
nullConfiguration();
end;
procedure processPacket_ACK(Header : PDHCPHeader; Options : PDHCPOptions);
var
Header : PDHCPHeader;
Options : PDHCPOptions;
i : uint16;
Option : PDHCPOption;
read16 : puint16;
read32 : puint32;
cfgopt : void;
begin
tracer.push_trace('dhcp.processPacket');
console.outputln('DHCP', 'Process ACK.');
getIPv4Config^.UP:= false;
//Copy new address
Configuration^.Options[Ord(TDHCPOpCode.REQUESTED_IP_ADDRESS)]:= kalloc(sizeof(TIPv4Address));
copyIPv4(@Header^.Your_IP[0], puint8(Configuration^.Options[Ord(TDHCPOpCode.REQUESTED_IP_ADDRESS)]));
{ Copy any given configuration data }
for i:=0 to getOptionsCount(Options)-1 do begin
Option:= getOption(Options, i);
case Option^.Opcode of
PAD,END_VENDOR_OPTIONS:begin
end;
else begin
cfgopt:= kalloc(Option^.Size);
Configuration^.Options[ord(Option^.Opcode)]:= cfgopt;
memcpy(uint32(Option^.Value), uint32(cfgopt), Option^.Size);
end;
end;
end;
{ Copy into IPv4 Configuration }
if Configuration^.Options[Ord(TDHCPOpCode.REQUESTED_IP_ADDRESS)] <> nil then
copyIPv4(puint8(Configuration^.Options[Ord(TDHCPOpCode.REQUESTED_IP_ADDRESS)]), puint8(@getIPv4Config^.address[0]));
if Configuration^.Options[Ord(TDHCPOpCode.ROUTER)] <> nil then
copyIpv4(puint8(Configuration^.Options[Ord(TDHCPOpCode.ROUTER)]), puint8(@getIPv4Config^.Gateway[0]));
if Configuration^.Options[Ord(TDHCPOpCode.SUBNET_MASK)] <> nil then
copyIPv4(puint8(Configuration^.Options[Ord(TDHCPOpCode.SUBNET_MASK)]), puint8(@getIPv4Config^.Netmask[0]));
arp.sendGratuitous;
arp.sendRequest(@getIPv4Config^.Gateway[0]);
getIPv4Config^.UP:= true;
end;
procedure processPacket_OFFER(Header : PDHCPHeader; Options : PDHCPOptions);
Var
SendHeader : PDHCPHeader;
SendOptions : PDHCPOptions;
SendMsgType : uint8;
NewSendHeader : PDHCPHeader;
NewHeaderSize : uint32;
SendCtx : PUDPSendContext;
PacketCtx : PPacketContext;
MAC : puint8;
begin
console.outputln('DHCP', 'Process OFFER.');
{ Check the Transaction ID matches our stored ID, discard if not. }
if Header^.Transaction_ID = Configuration^.Transaction then begin
console.outputln('DHCP', 'XID Match');
SendHeader:= createHeader();
CopyIPv4(puint8(@Header^.Your_IP[0]), puint8(@SendHeader^.Client_IP[0]));
CopyIPv4(puint8(@Header^.Server_IP[0]), puint8(@SendHeader^.Server_IP[0]));
SendOptions:= newOptions();
SendMsgType:= ord(TDHCPMessageType.REQUEST);
NewOption(SendOptions, TDHCPOpCode.DHCP_MESSAGE_TYPE, void(@SendMsgType), 1, false);
NewOption(SendOptions, TDHCPOpCode.REQUESTED_IP_ADDRESS, void(@SendHeader^.Client_IP[0]), 4, false);
NewOption(SendOptions, TDHCPOpCode.SERVER_IDENTIFIER, void(@SendHeader^.Server_IP[0]), 4, false);
NewOption(SendOptions, TDHCPOpCode.END_VENDOR_OPTIONS, nil, 0, false);
NewSendHeader:= writeOptions(SendHeader, SendOptions, @NewHeaderSize);
{ Setup Packet Context (IPv4 & ETH2) }
MAC:= getMAC();
packetCtx:= PPacketContext(Kalloc(sizeof(TPacketContext)));
packetCtx^.TTL:= 128;
copyMAC(@BROADCAST_MAC[0], @packetCtx^.MAC.Destination[0]);
copyMAC(MAC, @packetCtx^.MAC.Source[0]);
copyIPv4(@NULL_IP[0], @packetCtx^.IP.Source[0]);
copyIPv4(@BROADCAST_IP[0], @packetCtx^.IP.Destination[0]);
{ Setup UDPContext (UDP) }
sendCtx:= PUDPSendContext(Kalloc(sizeof(TUDPSendContext)));
sendCtx^.DstPort:= 67;
sendCtx^.context:= packetCtx;
sendCtx^.socket:= Socket;
{ Send }
udp.send(void(NewSendHeader), NewHeaderSize, sendCtx);
freeOptions(SendOptions);
kfree(void(NewSendHeader));
kfree(void(SendHeader));
kfree(void(packetCtx));
kfree(void(sendCtx));
end else begin
console.outputln('DHCP', 'XID Mismatch');
end;
end;
procedure processPacket(p_data : void; p_len : uint16; context : PUDPPacketContext);
var
Header : PDHCPHeader;
Options : PDHCPOptions;
Option : PDHCPOption;
MAC : puint8;
i : uint32;
MsgType : uint8;
begin
tracer.push_trace('dhcp.processPacket.enter');
Outputln('DHCP','processPacket');
{ Give access to header values & process to correct endianness. }
Header:= PDHCPHeader(p_data);
processHeader(Header);
{ Process Options }
Options:= newOptions;
readOptions(Options, p_data, p_len);
{ Check the frame is for us and then process }
MAC:= getMAC;
if MACEqual(@context^.PacketContext^.MAC.Destination[0], MAC) then begin
Outputln('DHCP','Frame is addressed to us.');
{ Check the message type is client specific }
If Header^.Message_Type = $02 then begin
Outputln('DHCP','Packet is a client packet.');
Outputln('DHCP','Searching for message type in Options');
{ Iterate options to find DHCP_MESSAGE_TYPE }
for i:=0 to getOptionsCount(Options)-1 do begin
Option:= getOption(Options, i);
if Option^.Opcode = DHCP_MESSAGE_TYPE then begin
break;
end else begin
Option:= nil;
end;
end;
Outputln('DHCP','Done searching for message type in Options');
{ Did we successfully get the DHCP_MESSAGE_TYPE option? }
if Option <> nil then begin
Outputln('DHCP','Found message type option.');
{ Read the value of DHCP_MESSAGE_TYPE }
MsgType:= readOption8(Option);
case TDHCPMessageType(MsgType) of
{ Pass to the correct packet processing function }
TDHCPMessageType.OFFER:processPacket_OFFER(Header, Options);
TDHCPMessageType.PACK:processPacket_ACK(Header, Options);
TDHCPMessageType.NAK:processPacket_NAK(Header, Options);
end;
end else begin
{ Could not find the DHCP_MESSAGE_TYPE option }
Outputln('DHCP','Could not find message type option.');
end;
end else begin
{ Packet is intended for a DHCP server }
Outputln('DHCP','Packet is a server packet.');
end;
end;
freeOptions(Options);
tracer.push_trace('dhcp.processPacket.exit');
end;
procedure DHCPDiscover();
var
SendCtx : PUDPSendContext;
PacketCtx : PPacketContext;
Header : PDHCPHeader;
NewHeader : PDHCPHeader;
HeaderSize : Puint32;
HeaderSize : uint32;
Options : PDHCPOptions;
MsgType : uint8;
MAC : puint8;
begin
tracer.push_trace('dhcp.DHCPDiscover');
Header:= newHeader;
Options:= newOptions;
XID:= rand32();
//Setup header
Header^.Message_Type:= $01;
Header^.Hardware_Type:= $01;
Header^.Hardware_Address_Length:= $06;
Header^.Hops:= $00;
Header^.Transaction_ID:= switchendian32(XID);
Header^.Seconds_Elapsed:= $0000;
CopyIPv4(@NULL_IP[0], @Header^.Client_IP[0]);
CopyIPv4(@NULL_IP[0], @Header^.Your_IP[0]);
CopyIPv4(@NULL_IP[0], @Header^.Server_IP[0]);
CopyIPv4(@NULL_IP[0], @Header^.Relay_Agent_IP[0]);
CopyMAC(@getMAC[0], @Header^.Client_MAC[0]);
memset(uint32(@Header^.Padding[0]), 0, 10);
memset(uint32(@Header^.Server_Hostname[0]), 0, 64);
memset(uint32(@Header^.Boot_File[0]), 0, 128);
memcpy(uint32(@DHCP_MAGIC[0]), uint32(@Header^.Magic_Cookie[0]), 4);
tracer.push_trace('dhcp.DHCPDiscover.begin');
{ Ensure we have a socket bound. }
if Socket <> nil then begin
{ Clear any current configuration }
nullConfiguration();
//Setup options
MsgType:= Ord(TDHCPMessageType.DISCOVER);
newOption(Options, DHCP_MESSAGE_TYPE, void(@MsgType), 1, false);
{ Setup our Transaction ID }
Configuration^.Transaction:= rand32();
{ Setup header }
Header:= createHeader();
processHeader(Header);
NewOption(Options, END_VENDOR_OPTIONS, nil, 0, false);
{ Setup options }
Options:= newOptions;
MsgType:= Ord(TDHCPMessageType.DISCOVER);
newOption(Options, DHCP_MESSAGE_TYPE, void(@MsgType), 1, false);
NewOption(Options, END_VENDOR_OPTIONS, nil, 0, false);
getIPv4Config^.UP:= true;
{ Write options to header }
NewHeader:= writeOptions(Header, Options, @HeaderSize);
{ Setup Packet Context (IPv4 & ETH2) }
packetCtx:= PPacketContext(Kalloc(sizeof(TPacketContext)));
packetCtx^.TTL:= 128;
copyMAC(@BROADCAST_MAC[0], @packetCtx^.MAC.Destination[0]);
MAC:= getMAC;
copyMAC(MAC, @packetCtx^.MAC.Source[0]);
copyIPv4(@NULL_IP[0], @packetCtx^.IP.Source[0]);
copyIPv4(@BROADCAST_IP[0], @packetCtx^.IP.Destination[0]);
{ Setup UDPContext (UDP) }
sendCtx:= PUDPSendContext(Kalloc(sizeof(TUDPSendContext)));
sendCtx^.DstPort:= 67;
sendCtx^.context:= packetCtx;
sendCtx^.socket:= Socket;
{ NET UP }
getIPv4Config^.UP:= true;
{ Send }
udp.send(void(NewHeader), HeaderSize, sendCtx);
{ Free }
kfree(void(PacketCtx));
kfree(void(sendCtx));
kfree(void(Header));
kfree(void(NewHeader));
freeOptions(Options);
end;
tracer.push_trace('dhcp.DHCPDiscover.exit');
end;
procedure bind();
begin
{ Bind our socket, free the socket in case of failure }
Socket:= PUDPBindContext(Kalloc(sizeof(TUDPBindContext)));
Socket^.Port:= 68;
Socket^.Callback:= @processPacket;
Socket^.UID:= rand32;
case UDP.bind(Socket) of
tueOK:console.outputln('DHCP', 'Successfully bound port 68.');
else begin
kfree(void(Socket));
Socket:= nil;
console.outputln('DHCP', 'Failed to bind port 68.');
end;
end;
end;
procedure register();
@ -323,10 +621,23 @@ var
begin
tracer.push_trace('dhcp.register');
console.outputln('DHCP', 'Register begin.');
{ Kalloc our Configuration Data }
Configuration:= PDHCPConfiguation(kalloc(sizeof(TDHCPConfiguration)));
{ Null Existing Coniguration }
for i:=0 to 255 do begin
Configuration^.Options[i] := nil;
end;
nullConfiguration();
{ Clear FlipExclude Table }
FlipExclude:= PFlipExclude(kalloc(sizeof(TFlipExclude)));
for i:=0 to 255 do begin
FlipExclude^[i]:= false;
end;
{ Set FlipExclude Table up to exclude certain OPCode from EndianFlips }
FlipExclude^[ord(PAD)]:= true;
FlipExclude^[ord(SUBNET_MASK)]:= true;
FlipExclude^[ord(ROUTER)]:= true;
@ -383,15 +694,10 @@ begin
FlipExclude^[ord(TZ_TIMEZONE)]:= true;
FlipExclude^[ord(DOMAIN_SEARCH)]:= true;
FlipExclude^[ord(CLASSLESS_STATIC_ROUTE)]:= true;
Socket:= PUDPBindContext(Kalloc(sizeof(TUDPBindContext)));
Socket^.Port:= 68;
Socket^.Callback:= @processPacket;
Socket^.UID:= rand32;
case UDP.bind(Socket) of
tueOK:console.outputln('DHCP', 'Successfully bound port 68.');
else console.outputln('DHCP', 'Failed to bind port 68.');
end;
DHCPDiscover;
{ Bind to port 68 }
bind();
console.outputln('DHCP', 'Register end.');
end;