330 lines
10 KiB
ObjectPascal
330 lines
10 KiB
ObjectPascal
{
|
|
Driver->Net->L3->ARP - Address Resolution Protocol Driver.
|
|
|
|
@author(Kieron Morris <kjm@kieronmorris.me>)
|
|
}
|
|
unit arp;
|
|
|
|
interface
|
|
|
|
uses
|
|
tracer, lmemorymanager,
|
|
util, lists, console, terminal,
|
|
net, nettypes, netutils,
|
|
netlog,
|
|
eth2, ipv4;
|
|
|
|
type
|
|
PARPCacheRecord = ^TARPCacheRecord;
|
|
TARPCacheRecord = record
|
|
MAC : TMACAddress;
|
|
IP : TIPv4Address;
|
|
end;
|
|
|
|
procedure register;
|
|
function IPv4ToMAC(ip : puint8) : puint8;
|
|
function MACToIIPv4(mac : puint8) : puint8;
|
|
procedure sendGratuitous;
|
|
procedure sendRequest(ip : puint8);
|
|
procedure send(hType : uint16; pType : uint16; op : uint16; p_context : PPacketContext);
|
|
function resolveIP(ip : puint8) : puint8;
|
|
|
|
implementation
|
|
|
|
var
|
|
Registered : Boolean = false;
|
|
Cache : PLinkedListBase;
|
|
|
|
function findCacheRecordByMAC(mac : puint8) : PARPCacheRecord;
|
|
var
|
|
i : uint32;
|
|
r : PARPCacheRecord;
|
|
|
|
begin
|
|
push_trace('arp.findCacheRecordByMAC');
|
|
findCacheRecordByMAC:= nil;
|
|
if LL_Size(Cache) > 0 then begin
|
|
for i:=0 to LL_Size(Cache)-1 do begin
|
|
r:= PARPCacheRecord(LL_Get(Cache, i));
|
|
if MACEqual(mac, @r^.MAC[0]) then begin
|
|
findCacheRecordByMAC:= r;
|
|
break;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function findCacheRecordByIP(ip : puint8) : PARPCacheRecord;
|
|
var
|
|
i : uint32;
|
|
r : PARPCacheRecord;
|
|
|
|
begin
|
|
push_trace('arp.findCacheRecordByIP');
|
|
findCacheRecordByIP:= nil;
|
|
if LL_Size(Cache) > 0 then begin
|
|
for i:=0 to LL_Size(Cache)-1 do begin
|
|
r:= PARPCacheRecord(LL_Get(Cache, i));
|
|
if IPEqual(ip, @r^.IP[0]) then begin
|
|
findCacheRecordByIP:= r;
|
|
break;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure send(hType : uint16; pType : uint16; op : uint16; p_context : PPacketContext);
|
|
var
|
|
buf : void;
|
|
hdr : PARPHeader;
|
|
hSize, pSize : uint8;
|
|
|
|
begin
|
|
push_trace('arp.send');
|
|
writeToLogLn(' L3: arp.send');
|
|
if p_context <> nil then begin
|
|
buf:= kalloc(sizeof(TARPHeader));
|
|
hdr:= PARPHeader(buf);
|
|
case hType of
|
|
$1 : hSize:= 6;
|
|
else hSize:= 0;
|
|
end;
|
|
case pType of
|
|
$0800 : pSize:= 4;
|
|
else pSize:= 0;
|
|
end;
|
|
if (hSize > 0) and (pSize > 0) then begin
|
|
hdr^.Hardware_Type_Hi:= hType SHR 8;
|
|
hdr^.Hardware_Type_Lo:= hType AND $FF;
|
|
hdr^.Protocol_Type_Hi:= pType SHR 8;
|
|
hdr^.Protocol_Type_Lo:= pType AND $FF;
|
|
hdr^.Hardware_Address_Length:= hSize;
|
|
hdr^.Protocol_Address_Length:= pSize;
|
|
hdr^.Operation_Hi:= op SHR 8;
|
|
hdr^.Operation_Lo:= op AND $FF;
|
|
copyMAC(@p_context^.MAC.Source[0], @hdr^.Source_Hardware[0]);
|
|
//copyMAC(@FORCE_MAC[0], @hdr^.Source_Hardware[0]);
|
|
copyIPv4(@p_context^.IP.Source[0], @hdr^.Source_Protocol[0]);
|
|
copyMAC(@p_context^.MAC.Destination[0], @hdr^.Destination_Hardware[0]);
|
|
copyIPv4(@p_context^.IP.Destination[0], @hdr^.Destination_Protocol[0]);
|
|
if MACEqual(@p_context^.MAC.Destination[0], @NULL_MAC[0]) then begin
|
|
CopyMAC(@BROADCAST_MAC[0], @p_context^.MAC.Destination[0]);
|
|
end;
|
|
eth2.send(buf, sizeof(TARPHeader), $0806, p_context);
|
|
end;
|
|
kfree(buf);
|
|
end;
|
|
end;
|
|
|
|
procedure sendGratuitous;
|
|
var
|
|
context : PPacketContext;
|
|
|
|
begin
|
|
context:= newPacketContext;
|
|
CopyIPv4(@getIPv4Config^.Address[0], @context^.IP.Destination[0]);
|
|
CopyIPv4(@getIPv4Config^.Address[0], @context^.IP.Source[0]);
|
|
CopyMAC(GetMAC, @context^.MAC.Source[0]);
|
|
CopyMAC(@NULL_MAC[0], @context^.MAC.Destination[0]);
|
|
arp.send($1, $0800, $1, context);
|
|
freePacketContext(context);
|
|
end;
|
|
|
|
procedure sendRequestGateway(ip : puint8);
|
|
var
|
|
context : PPacketContext;
|
|
CacheRecord : PARPCacheRecord;
|
|
|
|
begin
|
|
context:= newPacketContext;
|
|
CacheRecord:= findCacheRecordByIP(@getIPv4Config^.Gateway[0]);
|
|
if CacheRecord <> nil then begin
|
|
CopyMAC(@CacheRecord^.MAC[0], @context^.MAC.Destination[0]);
|
|
CopyIPv4(ip, @context^.IP.Destination[0]);
|
|
CopyIPv4(@getIPv4Config^.Address[0], @context^.IP.Source[0]);
|
|
CopyMAC(GetMAC, @context^.MAC.Source[0]);
|
|
arp.send($1, $0800, $1, context);
|
|
end;
|
|
freePacketContext(context);
|
|
end;
|
|
|
|
procedure sendRequest(ip : puint8);
|
|
var
|
|
context : PPacketContext;
|
|
CacheRecord : PARPCacheRecord;
|
|
|
|
begin
|
|
context:= newPacketContext;
|
|
CopyIPv4(ip, @context^.IP.Destination[0]);
|
|
CopyIPv4(@getIPv4Config^.Address[0], @context^.IP.Source[0]);
|
|
CopyMAC(GetMAC, @context^.MAC.Source[0]);
|
|
CacheRecord:= findCacheRecordByIP(@getIPv4Config^.Gateway[0]);
|
|
CopyMAC(@NULL_MAC[0], @context^.MAC.Destination[0]);
|
|
arp.send($1, $0800, $1, context);
|
|
freePacketContext(context);
|
|
sendRequestGateway(ip);
|
|
end;
|
|
|
|
function resolveIP(ip : puint8) : puint8;
|
|
var
|
|
CacheRecord : PARPCacheRecord;
|
|
|
|
begin
|
|
CacheRecord:= findCacheRecordByIP(ip);
|
|
resolveIP:= nil;
|
|
if CacheRecord = nil then begin
|
|
sendRequest(ip);
|
|
sendRequestGateway(ip);
|
|
end else begin
|
|
resolveIP:= @CacheRecord^.MAC[0];
|
|
end;
|
|
end;
|
|
|
|
procedure recv(p_data : void; p_len : uint16; p_context : PPacketContext);
|
|
var
|
|
Header : PARPHeader;
|
|
AHeader : TARPAbstractHeader;
|
|
CacheElement : PARPCacheRecord;
|
|
Merge : boolean;
|
|
context : PPacketContext;
|
|
|
|
begin
|
|
push_trace('arp.recv');
|
|
writeToLogLn(' L3: arp.recv');
|
|
console.redrawWindows;
|
|
|
|
{ Get our converted Header }
|
|
Header:= PARPHeader(p_data);
|
|
AHeader.Hardware_Type:= (Header^.Hardware_Type_Hi SHL 8) + Header^.Hardware_Type_Lo;
|
|
AHeader.Protocol_Type:= (Header^.Protocol_Type_Hi SHL 8) + Header^.Protocol_Type_Lo;
|
|
AHeader.Hardware_Address_Length:= Header^.Hardware_Address_Length;
|
|
AHeader.Protocol_Address_Length:= Header^.Protocol_Address_Length;
|
|
AHeader.Operation:= (Header^.Operation_Hi SHL 8) + Header^.Operation_Lo;
|
|
copyMAC(@Header^.Source_Hardware[0], @AHeader.Source_Hardware[0]);
|
|
copyIPv4(@Header^.Source_Protocol[0], @AHeader.Source_Protocol[0]);
|
|
copyMAC(@Header^.Destination_Hardware[0], @AHeader.Destination_Hardware[0]);
|
|
copyIPv4(@Header^.Destination_Protocol[0], @AHeader.Destination_Protocol[0]);
|
|
|
|
{ Process ARP Packet }
|
|
CacheElement:= findCacheRecordByIP(@AHeader.Source_Protocol[0]);
|
|
if CacheElement = nil then CacheElement:= findCacheRecordByMAC(@AHeader.Source_Hardware[0]);
|
|
if CacheElement <> nil then begin
|
|
copyMAC(@AHeader.Source_Hardware[0], @CacheElement^.MAC[0]);
|
|
copyIPv4(@AHeader.Source_Protocol[0], @CacheElement^.IP[0]);
|
|
end else begin
|
|
CacheElement:= PARPCacheRecord(LL_Add(Cache));
|
|
CopyMAC(@AHeader.Source_Hardware[0], @CacheElement^.MAC[0]);
|
|
copyIPv4(@AHeader.Source_Protocol[0], @CacheElement^.IP[0]);
|
|
end;
|
|
if IPEqual(@AHeader.Destination_Protocol[0], @getIPv4Config^.Address[0]) then begin
|
|
case AHeader.Operation of
|
|
$1:begin { ARP Request }
|
|
writeToLogLn(' arp.recv.arp.req');
|
|
context:= newPacketContext;
|
|
copyMAC(@AHeader.Source_Hardware[0], @context^.MAC.Destination[0]);
|
|
copyIPv4(@AHeader.Source_Protocol[0], @context^.IP.Destination[0]);
|
|
copyMAC(getMAC, @context^.MAC.Source[0]);
|
|
copyIPv4(@getIPv4Config^.Address[0], @context^.IP.Source[0]);
|
|
send($1, $0800, $2, context);
|
|
freePacketContext(context);
|
|
end;
|
|
$2:begin { ARP Reply }
|
|
writeToLogLn(' arp.recv.arp.rep');
|
|
end;
|
|
$3:begin { RARP Request }
|
|
writeToLogLn(' arp.recv.rarp.req');
|
|
end;
|
|
$4:begin { RARP Reply }
|
|
writeToLogLn(' arp.recv.rarp.rep');
|
|
end;
|
|
$5:begin { DRARP Request }
|
|
writeToLogLn(' arp.recv.drarp.req');
|
|
end;
|
|
$6:begin { DRARP Reply }
|
|
writeToLogLn(' arp.recv.drarp.rep');
|
|
end;
|
|
$7:begin { DRARP Error }
|
|
writeToLogLn(' arp.recv.drarp.err');
|
|
end;
|
|
$8:begin { InARP Request }
|
|
writeToLogLn(' arp.recv.inarp.req');
|
|
end;
|
|
$9:begin { InARP Reply }
|
|
writeToLogLn(' arp.recv.inarp.rep');
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure terminal_command_arp(Params : PParamList);
|
|
var
|
|
i : uint32;
|
|
elm : PARPCacheRecord;
|
|
sIP : pchar;
|
|
_IP : puint8;
|
|
|
|
begin
|
|
if ParamCount(Params) > 0 then begin
|
|
sIP:= getParam(0, Params);
|
|
_IP:= stringToIPv4(sIP);
|
|
sendRequest(_IP);
|
|
writestringlnWND('ARP Request Sent.', getTerminalHWND);
|
|
end else begin
|
|
if LL_Size(Cache) > 0 then begin
|
|
writestringlnWND('MAC IPv4', getTerminalHWND);
|
|
For i:=0 to LL_Size(Cache)-1 do begin
|
|
elm:= PARPCacheRecord(LL_Get(Cache, i));
|
|
writeMACAddressEx(@elm^.MAC[0], getTerminalHWND);
|
|
writestringWND(' ', getTerminalHWND);
|
|
writeIPv4AddressEx(@elm^.IP[0], getTerminalHWND);
|
|
writestringlnWND(' ', getTerminalHWND);
|
|
end;
|
|
end else begin
|
|
writestringlnWND('No entries in ARP table.', getTerminalHWND);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure register;
|
|
begin
|
|
push_trace('arp.register');
|
|
if not Registered then begin
|
|
Cache:= LL_New(sizeof(TARPCacheRecord));
|
|
eth2.registerTypePromisc($0806, @recv);
|
|
terminal.registerCommand('ARP', @terminal_command_arp, 'Get ARP Table.');
|
|
Registered:= true;
|
|
end;
|
|
pop_trace;
|
|
end;
|
|
|
|
function IPv4ToMAC(ip : puint8) : puint8;
|
|
var
|
|
r : PARPCacheRecord;
|
|
|
|
begin
|
|
push_trace('arp.IPv4ToMAC');
|
|
register;
|
|
IPv4ToMAC:= nil;
|
|
r:= findCacheRecordByIP(ip);
|
|
if r <> nil then begin
|
|
IPv4ToMAC:= @r^.MAC[0];
|
|
end;
|
|
pop_trace;
|
|
end;
|
|
|
|
function MACToIIPv4(mac : puint8) : puint8;
|
|
var
|
|
r : PARPCacheRecord;
|
|
|
|
begin
|
|
push_trace('arp.MACToIPv4');
|
|
register;
|
|
MACToIIPv4:= nil;
|
|
r:= findCacheRecordByMAC(mac);
|
|
if r <> nil then begin
|
|
MACToIIPv4:= @r^.IP[0];
|
|
end;
|
|
pop_trace;
|
|
end;
|
|
|
|
end. |