DHCP Works now.
git-svn-id: https://spexeah.com:8443/svn/Asuro@1034 6dbc8c32-bb84-406f-8558-d1cf31a0ab0c
This commit is contained in:
@ -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;
|
||||
|
||||
|
Reference in New Issue
Block a user