mirror of
https://github.com/AR2000AR/openComputers_codes.git
synced 2025-09-04 12:45:58 +02:00
[osinetwork] modernize code with libclass2
This commit is contained in:
@@ -554,7 +554,7 @@ local message = {}
|
||||
---@return DNSMessage
|
||||
function message.parsePacket(packet)
|
||||
if (type(packet) == "table") then
|
||||
packet = packet:getPayload()
|
||||
packet = packet:payload()
|
||||
end
|
||||
---@cast packet string
|
||||
local request = serialization.unserialize(packet)
|
||||
|
@@ -10,14 +10,14 @@ if (args[1] == "a") then
|
||||
local interfaces = networklib.getInterface()
|
||||
for interfaceName, itf in pairs(interfaces) do
|
||||
print(interfaceName:match("(%w+)"))
|
||||
print(string.format("\tMAC : %s MTU : %d", itf.ethernet:getAddr(), itf.ethernet:getMTU()))
|
||||
local ipLayer = itf.ethernet:getLayer(ethernet.TYPE.IPv4) --[[@as IPv4Layer]]
|
||||
print(string.format("\tIP : %s Mask : %s", ipv4.address.tostring(ipLayer:getAddr()), ipv4.address.tostring(ipLayer:getMask())))
|
||||
print(string.format("\tMAC : %s MTU : %d", itf.ethernet:addr(), itf.ethernet:mtu()))
|
||||
local ipLayer = itf.ethernet:higherLayer(ethernet.TYPE.IPv4) --[[@as IPv4Layer]]
|
||||
print(string.format("\tIP : %s Mask : %s", ipv4.address.tostring(ipLayer:addr()), ipv4.address.tostring(ipLayer:mask())))
|
||||
end
|
||||
elseif (args[1] == "r") then
|
||||
local routes = networklib.router:listRoutes()
|
||||
for i, v in ipairs(routes) do
|
||||
---@cast v Route
|
||||
print(string.format("%d : %-15s\t%-15s\t%-15s\tvia %s\t%d", i, ipv4.address.tostring(v.network), ipv4.address.tostring(v.mask), ipv4.address.tostring(v.gateway), ipv4.address.tostring(v.interface:getAddr()), v.metric or 0))
|
||||
print(string.format("%d : %-15s\t%-15s\t%-15s\tvia %s\t%d", i, ipv4.address.tostring(v.network), ipv4.address.tostring(v.mask), ipv4.address.tostring(v.gateway), ipv4.address.tostring(v.interface:addr()), v.metric or 0))
|
||||
end
|
||||
end
|
||||
|
@@ -90,7 +90,7 @@ event.listen("interrupted", function(...)
|
||||
return false
|
||||
end)
|
||||
--Main loop====================================================================
|
||||
print(string.format("Ping %s (%s) from %s with %d bytes of data.", args[1], ipv4Address.tostring(targetIP), ipv4Address.tostring(route.interface:getAddr()), opts.s))
|
||||
print(string.format("Ping %s (%s) from %s with %d bytes of data.", args[1], ipv4Address.tostring(targetIP), ipv4Address.tostring(route.interface:addr()), opts.s))
|
||||
ping()
|
||||
while run do
|
||||
os.sleep(0.1)
|
||||
|
@@ -1,74 +0,0 @@
|
||||
---@meta
|
||||
|
||||
--=============================================================================
|
||||
|
||||
---@class OSILayer
|
||||
---@field layerType number
|
||||
---@field protected _layer OSILayer
|
||||
---@field protected _layers table<number,OSILayer>
|
||||
local OSILayer = {}
|
||||
|
||||
---Get the payload from the previous layer
|
||||
---@param from string|number
|
||||
---@param to string|number
|
||||
---@param payload string
|
||||
function OSILayer:payloadHandler(from, to, payload)
|
||||
end
|
||||
|
||||
---Send the payload
|
||||
---@param to string|number destination.
|
||||
---@param payload Payload
|
||||
---@overload fun(payload)
|
||||
function OSILayer:send(to, payload)
|
||||
end
|
||||
|
||||
---Register higher level OSI layer
|
||||
---@param OSILayer any
|
||||
function OSILayer:setLayer(OSILayer)
|
||||
end
|
||||
|
||||
---Return the maximum payload size
|
||||
---@return number
|
||||
function OSILayer:getMTU()
|
||||
end
|
||||
|
||||
---@return string|number
|
||||
function OSILayer:getAddr()
|
||||
end
|
||||
|
||||
--=============================================================================
|
||||
|
||||
---@class OSIDataLayer : OSILayer
|
||||
|
||||
--=============================================================================
|
||||
|
||||
---@class OSINetworkLayer : OSILayer
|
||||
|
||||
--=============================================================================
|
||||
|
||||
---@class OSITransportLayer : OSILayer
|
||||
|
||||
--=============================================================================
|
||||
|
||||
---@class Payload
|
||||
---@field payloadType number
|
||||
local Payload = {}
|
||||
|
||||
---Prepare the payload for the next layer
|
||||
---@return any ...
|
||||
function Payload:pack()
|
||||
end
|
||||
|
||||
---Get a payload object from the argument
|
||||
---@param ... any
|
||||
---@return Payload
|
||||
function Payload.unpack(...)
|
||||
end
|
||||
|
||||
---@return string
|
||||
function Payload:getPayload()
|
||||
end
|
||||
|
||||
---@param payload string
|
||||
function Payload:setPayload(payload)
|
||||
end
|
@@ -13,10 +13,10 @@ package layers.ethernet {
|
||||
- _etype ethernetType
|
||||
- _payload string
|
||||
+ EthernetFrame(src:string, dst:string, tag802_1Q:number, etype:ethernetType, payload:string)
|
||||
+ string getDst()
|
||||
+ setDst(dst:string)
|
||||
+ string dst()
|
||||
+ dst(dst:string)
|
||||
+ string Src()
|
||||
+ setSrc(src:string)
|
||||
+ src(src:string)
|
||||
+ number 802_1Q()
|
||||
+ set802_1Q(tag:number)
|
||||
+ number getEthernetType()
|
||||
|
@@ -9,12 +9,12 @@ package layers.icmp {
|
||||
- _code icmpCode
|
||||
- _param number
|
||||
- _payload string
|
||||
+ icmpType getType()
|
||||
+ setType(val:icmpType)
|
||||
+ icmpCode getCode()
|
||||
+ setCode(val:icmpCode)
|
||||
+ number getParam()
|
||||
+ setParam(val:number)
|
||||
+ icmpType type()
|
||||
+ type(val:icmpType)
|
||||
+ icmpCode code()
|
||||
+ code(val:icmpCode)
|
||||
+ number param()
|
||||
+ param(val:number)
|
||||
}
|
||||
enum icmpCode {
|
||||
ECHO_REPLY.ECHO_REPLY : 0
|
||||
|
@@ -8,12 +8,12 @@ package layers.udp {
|
||||
- _dstPort number
|
||||
- _payload string
|
||||
+ UDPPacket(srcPort:number,dstPort:number,paylaod:string)
|
||||
+ number getDstPort()
|
||||
+ number getSrcPort()
|
||||
+ string getPayload()
|
||||
+ void setDstPort(port:number)
|
||||
+ void setSrcPort(port:number)
|
||||
+ void setPayload(value:string)
|
||||
+ number dstPort()
|
||||
+ number srcPort()
|
||||
+ string payload()
|
||||
+ void dstPort(port:number)
|
||||
+ void srcPort(port:number)
|
||||
+ void payload(value:string)
|
||||
}
|
||||
|
||||
class UDPSocket {
|
||||
|
@@ -59,11 +59,11 @@ end
|
||||
--init the interfaces during first import. Since the lib is imported in /boot/30_network.lua, it is done during system boot
|
||||
if (not network.internal.icmp) then
|
||||
network.internal.icmp = icmp.ICMPLayer(network.router)
|
||||
network.router:setProtocol(network.internal.icmp)
|
||||
network.router:higherLayer(network.internal.icmp.layerType, network.internal.icmp)
|
||||
end
|
||||
if (not network.interfaces.udp) then
|
||||
network.internal.udp = udp.UDPLayer(network.router)
|
||||
network.router:setProtocol(network.internal.udp)
|
||||
network.router:higherLayer(network.internal.udp.layerType, network.internal.udp)
|
||||
end
|
||||
--=============================================================================
|
||||
---@class iInfo
|
||||
@@ -314,7 +314,7 @@ function ifconfig.ifdown(iName)
|
||||
|
||||
local relatedInterfaces = {}
|
||||
for interfaceName, interface in pairs(network.interfaces) do
|
||||
if (interfaceName == iName or interfaceName == address or interface.ethernet:getAddr() == iName) then
|
||||
if (interfaceName == iName or interfaceName == address or interface.ethernet:addr() == iName) then
|
||||
table.insert(relatedInterfaces, interfaceName)
|
||||
end
|
||||
end
|
||||
|
71
network/lib/network/abstract/NetworkLayer.lua
Normal file
71
network/lib/network/abstract/NetworkLayer.lua
Normal file
@@ -0,0 +1,71 @@
|
||||
local class = require('libClass2')
|
||||
|
||||
---@class NetworkLayer:Object
|
||||
---@field protected _layer NetworkLayer lower layer
|
||||
---@field protected _higherLayer table<number,NetworkLayer> highers layers
|
||||
local NetworkLayer = class()
|
||||
NetworkLayer.layerType = 0
|
||||
|
||||
---Comment
|
||||
---@return NetworkLayer
|
||||
function NetworkLayer:new()
|
||||
local o = self.parent()
|
||||
setmetatable(o, {__index = self})
|
||||
---@cast o NetworkLayer
|
||||
o._higherLayer = {}
|
||||
return o
|
||||
end
|
||||
|
||||
---Get the payload from the previous layer
|
||||
---@param from string|number
|
||||
---@param to string|number
|
||||
---@param payload string
|
||||
function NetworkLayer:payloadHandler(from, to, payload)
|
||||
error("Abstract methods", 2)
|
||||
end
|
||||
|
||||
---Send the payload
|
||||
---@param to string|number destination.
|
||||
---@param payload Payload
|
||||
---@overload fun(payload)
|
||||
function NetworkLayer:send(to, payload)
|
||||
error("Abstract methods", 2)
|
||||
end
|
||||
|
||||
---Return the maximum payload size
|
||||
---@return number
|
||||
function NetworkLayer:mtu()
|
||||
error("Abstract methods", 2)
|
||||
end
|
||||
|
||||
---@return string|number
|
||||
function NetworkLayer:addr()
|
||||
error("Abstract methods", 2)
|
||||
end
|
||||
|
||||
---set or get the lower layer handler
|
||||
---@protected
|
||||
---@param value? NetworkLayer
|
||||
---@return NetworkLayer
|
||||
function NetworkLayer:layer(value)
|
||||
checkArg(1, value, 'table', 'nil')
|
||||
local oldValue = self._layer
|
||||
if (value ~= nil) then
|
||||
assert(value:instanceOf(NetworkLayer))
|
||||
value:higherLayer(self.layerType, self)
|
||||
self._layer = value
|
||||
end
|
||||
return oldValue
|
||||
end
|
||||
|
||||
---@param layerType number
|
||||
---@param value? NetworkLayer
|
||||
---@return NetworkLayer
|
||||
function NetworkLayer:higherLayer(layerType, value)
|
||||
checkArg(1, value, 'table', 'nil')
|
||||
local oldValue = self._higherLayer[layerType]
|
||||
if (value ~= nil) then self._higherLayer[layerType] = value end
|
||||
return oldValue
|
||||
end
|
||||
|
||||
return NetworkLayer
|
31
network/lib/network/abstract/Payload.lua
Normal file
31
network/lib/network/abstract/Payload.lua
Normal file
@@ -0,0 +1,31 @@
|
||||
local class = require("libClass2")
|
||||
|
||||
---@class Payload:Object
|
||||
---@field payloadType number
|
||||
---@field protected payloadFormat string
|
||||
local Payload = class()
|
||||
Payload.payloadFormat = "s"
|
||||
Payload.payloadType = 0
|
||||
|
||||
---Prepare the payload for the next layer
|
||||
---@return any ...
|
||||
function Payload:pack()
|
||||
error("Abstract methods", 2)
|
||||
end
|
||||
|
||||
---Get a payload object from the argument
|
||||
---@param ... any
|
||||
---@return Payload
|
||||
function Payload.unpack(...)
|
||||
error("Abstract methods", 2)
|
||||
end
|
||||
|
||||
--[[ ---@param value? string
|
||||
---@return string
|
||||
function Payload:data(value)
|
||||
checkArg(1, value, 'string', 'nil')
|
||||
local oldValue = self._data
|
||||
if (value ~= nil) then self._data = value end
|
||||
return oldValue
|
||||
end ]]
|
||||
return Payload
|
@@ -1,4 +1,6 @@
|
||||
local ethernet = require("network.ethernet")
|
||||
local Payload = require("network.abstract.Payload")
|
||||
local class = require("libClass2")
|
||||
|
||||
|
||||
---@class ARPFrame:Payload
|
||||
@@ -11,7 +13,7 @@ local ethernet = require("network.ethernet")
|
||||
---@field private _tpa number|string
|
||||
---@operator call:ARPFrame
|
||||
---@overload fun(htype:number,ptype:number,oper:arpOperation,sha:number|string,spa:number|string,tha:number|string,tpa:number|string):ARPFrame
|
||||
local ARPFrame = {}
|
||||
local ARPFrame = class(Payload)
|
||||
ARPFrame.payloadType = ethernet.TYPE.ARP
|
||||
ARPFrame.OPERATION = {
|
||||
REQUEST = 1,
|
||||
@@ -19,123 +21,114 @@ ARPFrame.OPERATION = {
|
||||
}
|
||||
|
||||
|
||||
setmetatable(ARPFrame, {
|
||||
---@param htype number
|
||||
---@param ptype number
|
||||
---@param oper arpOperation
|
||||
---@param sha number|string
|
||||
---@param spa number|string
|
||||
---@param tha number|string
|
||||
---@param tpa number|string
|
||||
---@return ARPFrame
|
||||
__call = function(self, htype, ptype, oper, sha, spa, tha, tpa)
|
||||
checkArg(1, htype, "number")
|
||||
checkArg(2, ptype, "number")
|
||||
checkArg(3, oper, "number")
|
||||
checkArg(4, sha, "string", "number")
|
||||
checkArg(5, spa, "string", "number")
|
||||
checkArg(6, tha, "string", "number")
|
||||
checkArg(7, tpa, "string", "number")
|
||||
---@param htype number
|
||||
---@param ptype number
|
||||
---@param oper arpOperation
|
||||
---@param sha number|string
|
||||
---@param spa number|string
|
||||
---@param tha number|string
|
||||
---@param tpa number|string
|
||||
---@return ARPFrame
|
||||
function ARPFrame:new(htype, ptype, oper, sha, spa, tha, tpa)
|
||||
checkArg(1, htype, "number")
|
||||
checkArg(2, ptype, "number")
|
||||
checkArg(3, oper, "number")
|
||||
checkArg(4, sha, "string", "number")
|
||||
checkArg(5, spa, "string", "number")
|
||||
checkArg(6, tha, "string", "number")
|
||||
checkArg(7, tpa, "string", "number")
|
||||
|
||||
local o = {
|
||||
_htype = htype,
|
||||
_ptype = ptype,
|
||||
_oper = oper,
|
||||
_sha = sha,
|
||||
_spa = spa,
|
||||
_tha = tha,
|
||||
_tpa = tpa,
|
||||
}
|
||||
local o = {
|
||||
_htype = htype,
|
||||
_ptype = ptype,
|
||||
_oper = oper,
|
||||
_sha = sha,
|
||||
_spa = spa,
|
||||
_tha = tha,
|
||||
_tpa = tpa,
|
||||
}
|
||||
|
||||
setmetatable(o, {__index = self})
|
||||
setmetatable(o, {__index = self})
|
||||
|
||||
return o
|
||||
end
|
||||
})
|
||||
return o
|
||||
end
|
||||
|
||||
local PACK_FORMAT = "I2I2xxI2sI4sI4"
|
||||
ARPFrame.payloadFormat = "I2I2xxI2sI4sI4"
|
||||
|
||||
---@return string
|
||||
function ARPFrame:pack()
|
||||
return string.pack(PACK_FORMAT, self:getHtype(), self:getPtype(), self:getOper(), self:getSha(), self:getSpa(), self:getTha(), self:getTpa())
|
||||
return string.pack(self.payloadFormat, self:htype(), self:ptype(), self:oper(), self:sha(), self:spa(), self:tha(), self:tpa())
|
||||
end
|
||||
|
||||
---@param arpString string
|
||||
---@return ARPFrame
|
||||
function ARPFrame.unpack(arpString)
|
||||
return ARPFrame(string.unpack(PACK_FORMAT, arpString))
|
||||
return ARPFrame(string.unpack(ARPFrame.payloadFormat, arpString))
|
||||
end
|
||||
|
||||
--#region getter/setter
|
||||
|
||||
---Get htype
|
||||
---@param value? number
|
||||
---@return number
|
||||
function ARPFrame:getHtype() return self._htype end
|
||||
|
||||
---@param val number
|
||||
function ARPFrame:setHtype(val)
|
||||
checkArg(1, val, "number")
|
||||
self._htype = val
|
||||
function ARPFrame:htype(value)
|
||||
checkArg(1, value, 'number', 'nil')
|
||||
local oldValue = self._htype
|
||||
if (value ~= nil) then self._htype = value end
|
||||
return oldValue
|
||||
end
|
||||
|
||||
---Get ptype
|
||||
---@param value? number
|
||||
---@return number
|
||||
function ARPFrame:getPtype() return self._ptype end
|
||||
|
||||
---@param val number
|
||||
function ARPFrame:setPtype(val)
|
||||
checkArg(1, val, "number")
|
||||
self._ptype = val
|
||||
function ARPFrame:ptype(value)
|
||||
checkArg(1, value, 'number', 'nil')
|
||||
local oldValue = self._ptype
|
||||
if (value ~= nil) then self._ptype = value end
|
||||
return oldValue
|
||||
end
|
||||
|
||||
---Get oper
|
||||
---@param value? number
|
||||
---@return number
|
||||
function ARPFrame:getOper() return self._oper end
|
||||
|
||||
---@param val number
|
||||
function ARPFrame:setOper(val)
|
||||
checkArg(1, val, "number")
|
||||
self._oper = val
|
||||
function ARPFrame:oper(value)
|
||||
checkArg(1, value, 'number', 'nil')
|
||||
local oldValue = self._oper
|
||||
if (value ~= nil) then self._oper = value end
|
||||
return oldValue
|
||||
end
|
||||
|
||||
---Get sha
|
||||
---@param value? number|string
|
||||
---@return number|string
|
||||
function ARPFrame:getSha() return self._sha end
|
||||
|
||||
---@param val number|string
|
||||
function ARPFrame:setSha(val)
|
||||
checkArg(1, val, 'string', 'number')
|
||||
self._sha = val
|
||||
function ARPFrame:sha(value)
|
||||
checkArg(1, value, 'number', 'string', 'nil')
|
||||
local oldValue = self._sha
|
||||
if (value ~= nil) then self._sha = value end
|
||||
return oldValue
|
||||
end
|
||||
|
||||
---Get spa
|
||||
---@param value? number|string
|
||||
---@return number|string
|
||||
function ARPFrame:getSpa() return self._spa end
|
||||
|
||||
---@param val number|string
|
||||
function ARPFrame:setSpa(val)
|
||||
checkArg(1, val, 'string', 'number')
|
||||
self._spa = val
|
||||
function ARPFrame:spa(value)
|
||||
checkArg(1, value, 'number', 'string', 'nil')
|
||||
local oldValue = self._spa
|
||||
if (value ~= nil) then self._spa = value end
|
||||
return oldValue
|
||||
end
|
||||
|
||||
---Get tha
|
||||
---@param value? number|string
|
||||
---@return number|string
|
||||
function ARPFrame:getTha() return self._tha end
|
||||
|
||||
---@param val number|string
|
||||
function ARPFrame:setTha(val)
|
||||
checkArg(1, val, 'string', 'number')
|
||||
self._tha = val
|
||||
function ARPFrame:tha(value)
|
||||
checkArg(1, value, 'number', 'string', 'nil')
|
||||
local oldValue = self._tha
|
||||
if (value ~= nil) then self._tha = value end
|
||||
return oldValue
|
||||
end
|
||||
|
||||
---Get tpa
|
||||
---@param value? number|string
|
||||
---@return number|string
|
||||
function ARPFrame:getTpa() return self._tpa end
|
||||
|
||||
---@param val number|string
|
||||
function ARPFrame:setTpa(val)
|
||||
checkArg(1, val, 'string', 'number')
|
||||
self._tpa = val
|
||||
function ARPFrame:tpa(value)
|
||||
checkArg(1, value, 'number', 'string', 'nil')
|
||||
local oldValue = self._tpa
|
||||
if (value ~= nil) then self._tpa = value end
|
||||
return oldValue
|
||||
end
|
||||
|
||||
return ARPFrame
|
||||
|
@@ -2,31 +2,30 @@ local ethernet = require("network.ethernet")
|
||||
local ARPFrame = require("network.arp.ARPFrame")
|
||||
local arpConst = require("network.arp.constantes")
|
||||
local arpAPI = require("network.arp.api")
|
||||
local NetworkLayer = require('network.abstract.NetworkLayer')
|
||||
local class = require("libClass2")
|
||||
|
||||
|
||||
---@class ARPLayer : OSINetworkLayer
|
||||
local ARPLayer = {}
|
||||
---@class ARPLayer : NetworkLayer
|
||||
local ARPLayer = class(NetworkLayer)
|
||||
---@type ethernetType
|
||||
ARPLayer.layerType = ethernet.TYPE.ARP
|
||||
|
||||
setmetatable(ARPLayer, {
|
||||
---@param osiLayer OSIDataLayer
|
||||
---@return ARPLayer
|
||||
__call = function(self, osiLayer)
|
||||
local o = {
|
||||
_layer = osiLayer
|
||||
}
|
||||
setmetatable(o, {__index = self})
|
||||
osiLayer:setLayer(o)
|
||||
return o
|
||||
end
|
||||
})
|
||||
|
||||
function ARPLayer:getAddr()
|
||||
return self._layer:getAddr()
|
||||
---@param osiLayer NetworkLayer
|
||||
---@return ARPLayer
|
||||
function ARPLayer:new(osiLayer)
|
||||
local o = self.parent()
|
||||
setmetatable(o, {__index = self})
|
||||
---@cast o ARPLayer
|
||||
o:layer(osiLayer)
|
||||
return o
|
||||
end
|
||||
|
||||
function ARPLayer:getMTU()
|
||||
function ARPLayer:addr()
|
||||
return self:layer():addr()
|
||||
end
|
||||
|
||||
function ARPLayer:mtu()
|
||||
return 0
|
||||
end
|
||||
|
||||
@@ -36,13 +35,13 @@ end
|
||||
---@param payload string
|
||||
function ARPLayer:payloadHandler(from, to, payload)
|
||||
local arpFrame = ARPFrame.unpack(payload)
|
||||
if (arpFrame:getOper() == arpConst.OPERATION.REQUEST) then
|
||||
local protocolAddress = arpAPI.getLocalAddress(arpFrame:getHtype(), arpFrame:getPtype(), self._layer:getAddr())
|
||||
if (protocolAddress == arpFrame:getTpa()) then
|
||||
self:send(from, ARPFrame(arpFrame:getHtype(), arpFrame:getPtype(), ARPFrame.OPERATION.REPLY, arpFrame:getSha(), arpFrame:getSpa(), to, arpFrame:getTpa()))
|
||||
if (arpFrame:oper() == arpConst.OPERATION.REQUEST) then
|
||||
local protocolAddress = arpAPI.getLocalAddress(arpFrame:htype(), arpFrame:ptype(), self:layer():addr())
|
||||
if (protocolAddress == arpFrame:tpa()) then
|
||||
self:send(from, ARPFrame(arpFrame:htype(), arpFrame:ptype(), ARPFrame.OPERATION.REPLY, arpFrame:sha(), arpFrame:spa(), to, arpFrame:tpa()))
|
||||
end
|
||||
elseif (arpFrame:getOper() == arpConst.OPERATION.REPLY) then
|
||||
arpAPI.addCached(arpFrame:getHtype(), arpFrame:getPtype(), arpFrame:getTha(), arpFrame:getTpa())
|
||||
elseif (arpFrame:oper() == arpConst.OPERATION.REPLY) then
|
||||
arpAPI.addCached(arpFrame:htype(), arpFrame:ptype(), arpFrame:tha(), arpFrame:tpa())
|
||||
end
|
||||
end
|
||||
|
||||
@@ -50,8 +49,8 @@ end
|
||||
---@param payload ARPFrame
|
||||
function ARPLayer:send(dst, payload)
|
||||
if (dst == ethernet.MAC_NIL) then dst = ethernet.MAC_BROADCAST end
|
||||
local eFrame = ethernet.EthernetFrame(self._layer:getAddr(), dst, nil, self.layerType, payload:pack())
|
||||
self._layer:send(dst, eFrame)
|
||||
local eFrame = ethernet.EthernetFrame(self:layer():addr(), dst, nil, self.layerType, payload:pack())
|
||||
self:layer():send(dst, eFrame)
|
||||
end
|
||||
|
||||
return ARPLayer
|
||||
|
@@ -74,7 +74,7 @@ function arpAPI.getAddress(interface, htype, ptype, pa, spa)
|
||||
return cache[ptype][pa][htype]
|
||||
end
|
||||
-- cache miss
|
||||
local arpMessage = ARPFrame(htype, ptype, ARPFrame.OPERATION.REQUEST, interface:getAddr(), spa, ethernet.MAC_NIL, pa)
|
||||
local arpMessage = ARPFrame(htype, ptype, ARPFrame.OPERATION.REQUEST, interface:addr(), spa, ethernet.MAC_NIL, pa)
|
||||
interface:send(ethernet.MAC_BROADCAST, arpMessage)
|
||||
|
||||
local tpa = select(4, event.pull(1, "arp", htype, ptype, nil, pa))
|
||||
|
@@ -1,7 +1,8 @@
|
||||
local computer = require("computer")
|
||||
local event = require("event")
|
||||
local component = require("component")
|
||||
local os = require("os")
|
||||
local Payload = require("network.abstract.Payload")
|
||||
local NetworkLayer = require('network.abstract.NetworkLayer')
|
||||
local class = require("libClass2")
|
||||
|
||||
local UUID_PATERN = "%x%x%x%x%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%x%x%x%x%x%x%x%x"
|
||||
|
||||
@@ -39,91 +40,83 @@ end
|
||||
---@field private _payload string
|
||||
---@operator call:EthernetFrame
|
||||
---@overload fun(src: string,dst: string,tag802_1Q: number|nil,etype: ethernetType,payload: string):EthernetFrame
|
||||
local EthernetFrame = {}
|
||||
local EthernetFrame = class(Payload)
|
||||
|
||||
setmetatable(EthernetFrame, {
|
||||
---Constructor
|
||||
---@param self EthernetFrame
|
||||
---@param src string
|
||||
---@param dst string
|
||||
---@param tag802_1Q number|nil
|
||||
---@param etype ethernetType
|
||||
---@param payload string
|
||||
---@return EthernetFrame
|
||||
__call = function(self, src, dst, tag802_1Q, etype, payload)
|
||||
checkArg(1, src, "string")
|
||||
checkArg(2, dst, "string")
|
||||
checkArg(3, tag802_1Q, "string", "nil")
|
||||
checkArg(4, etype, "number")
|
||||
checkArg(5, payload, "string")
|
||||
if (not checkUUIDformat(src)) then error("#1 : src. Not a valid uuid") end
|
||||
if (not checkUUIDformat(dst)) then error("#2 : dst. Not a valid uuid") end
|
||||
local o = {
|
||||
_dst = dst,
|
||||
_src = src,
|
||||
_802_1Q = tag802_1Q or nil,
|
||||
_etype = etype,
|
||||
_payload = payload,
|
||||
}
|
||||
setmetatable(o, {__index = self})
|
||||
return o
|
||||
end,
|
||||
})
|
||||
|
||||
---Get the destination mac
|
||||
---@return string uuid
|
||||
function EthernetFrame:getDst() return self._dst end
|
||||
|
||||
---Set the destination mac
|
||||
---@param dst string uuid
|
||||
function EthernetFrame:setDst(dst)
|
||||
checkArg(1, dst, "string")
|
||||
if (not checkUUIDformat(dst)) then error(string.format("%s is not a vailid MAC address (uuid)", dst, 2)) end
|
||||
self._dst = dst
|
||||
---Constructor
|
||||
---@param self EthernetFrame
|
||||
---@param src string
|
||||
---@param dst string
|
||||
---@param tag802_1Q number|nil
|
||||
---@param etype ethernetType
|
||||
---@param payload string
|
||||
---@return EthernetFrame
|
||||
function EthernetFrame:new(src, dst, tag802_1Q, etype, payload)
|
||||
checkArg(1, src, "string")
|
||||
checkArg(2, dst, "string")
|
||||
checkArg(3, tag802_1Q, "string", "nil")
|
||||
checkArg(4, etype, "number")
|
||||
checkArg(5, payload, "string")
|
||||
if (not checkUUIDformat(src)) then error("#1 : src. Not a valid uuid") end
|
||||
if (not checkUUIDformat(dst)) then error("#2 : dst. Not a valid uuid") end
|
||||
local o = self.parent()
|
||||
setmetatable(o, {__index = self})
|
||||
o:dst(dst)
|
||||
o:src(src)
|
||||
o:f802_1Q(tag802_1Q)
|
||||
o:etype(etype)
|
||||
o:payload(payload)
|
||||
return o
|
||||
end
|
||||
|
||||
---Get the source mac
|
||||
---@return string uuid
|
||||
function EthernetFrame:getSrc() return self._src end
|
||||
|
||||
---Set the souce mac
|
||||
---@param src string uuid
|
||||
function EthernetFrame:setSrc(src)
|
||||
if (not checkUUIDformat(src)) then error(string.format("%s is not a vailid MAC address (uuid)", src, 2)) end
|
||||
self._src = src
|
||||
end
|
||||
|
||||
---Get the 802_1Q tag
|
||||
---@return number|nil tag
|
||||
function EthernetFrame:get802_1Q() return self._802_1Q end
|
||||
|
||||
---Set the 802_1Q tag
|
||||
---@param tag number|nil
|
||||
function EthernetFrame:set802_1Q(tag)
|
||||
self._802_1Q = tag
|
||||
end
|
||||
|
||||
---Get the ethernet frame payload's type
|
||||
---@return ethernetType
|
||||
function EthernetFrame:getEthernetType() return self._etype end
|
||||
|
||||
---Set the ethernet frame payload's type
|
||||
---@param type ethernetType
|
||||
function EthernetFrame:setEthernetType(type)
|
||||
checkArg(1, type, "number")
|
||||
for k, v in pairs(ethernet.TYPE) do
|
||||
if (type == v) then
|
||||
self._etype = type
|
||||
return
|
||||
end
|
||||
---@param value? string
|
||||
---@return string
|
||||
function EthernetFrame:dst(value)
|
||||
checkArg(1, value, 'string', 'nil')
|
||||
local oldValue = self._dst
|
||||
if (value ~= nil) then
|
||||
if (not checkUUIDformat(value)) then error(string.format("%s is not a vailid MAC address (uuid)", value, 2)) end
|
||||
self._dst = value
|
||||
end
|
||||
error(string.format("%x is not a valid ethernet type"))
|
||||
return oldValue
|
||||
end
|
||||
|
||||
function EthernetFrame:getPayload() return self._payload end
|
||||
---@param value? string
|
||||
---@return string
|
||||
function EthernetFrame:src(value)
|
||||
checkArg(1, value, 'string', 'nil')
|
||||
local oldValue = self._src
|
||||
if (value ~= nil) then
|
||||
if (not checkUUIDformat(value)) then error(string.format("%s is not a vailid MAC address (uuid)", value, 2)) end
|
||||
self._src = value
|
||||
end
|
||||
return oldValue
|
||||
end
|
||||
|
||||
function EthernetFrame:setPayload(payload)
|
||||
self._payload = payload
|
||||
---@param value? number
|
||||
---@return number
|
||||
function EthernetFrame:f802_1Q(value)
|
||||
checkArg(1, value, 'number', 'nil')
|
||||
local oldValue = self._802_1Q or 0
|
||||
if (value ~= nil) then self._802_1Q = value end
|
||||
return oldValue
|
||||
end
|
||||
|
||||
---@param value? ethernetType
|
||||
---@return ethernetType
|
||||
function EthernetFrame:etype(value)
|
||||
checkArg(1, value, 'number', 'nil')
|
||||
local oldValue = self._etype
|
||||
if (value ~= nil) then self._etype = value end
|
||||
return oldValue
|
||||
end
|
||||
|
||||
---@param value? string
|
||||
---@return string
|
||||
function EthernetFrame:payload(value)
|
||||
checkArg(1, value, 'string', 'nil')
|
||||
local oldValue = self._payload or ""
|
||||
if (value ~= nil) then self._payload = value end
|
||||
return oldValue
|
||||
end
|
||||
|
||||
---Dump the frame info into multiples return values
|
||||
@@ -131,7 +124,7 @@ end
|
||||
---@return ethernetType ethernetType
|
||||
---@return string payload
|
||||
function EthernetFrame:pack()
|
||||
return self:get802_1Q(), self:getEthernetType(), self:getPayload()
|
||||
return self:f802_1Q(), self:etype(), self:payload()
|
||||
end
|
||||
|
||||
function EthernetFrame.unpack(src, dst, tag802_1Q, etype, payload)
|
||||
@@ -142,7 +135,7 @@ end
|
||||
--=============================================================================
|
||||
--#region EthernetInterface
|
||||
|
||||
---@class EthernetInterface : OSIDataLayer
|
||||
---@class EthernetInterface : NetworkLayer
|
||||
---@operator call:EthernetInterface
|
||||
---@field private _modem ComponentModem
|
||||
---@field private _port number
|
||||
@@ -150,39 +143,30 @@ end
|
||||
---@field private _listener number
|
||||
---@field private _mtu number
|
||||
---@overload fun(modem:ComponentModem):EthernetInterface
|
||||
local EthernetInterface = {}
|
||||
local EthernetInterface = class(NetworkLayer)
|
||||
|
||||
|
||||
setmetatable(EthernetInterface, {
|
||||
---Create a EthernetInterface
|
||||
---@param modem ComponentModem
|
||||
---@return EthernetInterface
|
||||
__call = function(self, modem)
|
||||
checkArg(1, modem, "table")
|
||||
if (type(modem) == "table") then
|
||||
if (not modem.type == "modem") then error("#1 is not a modem component", 2) end
|
||||
end
|
||||
|
||||
local o = {
|
||||
_modem = modem,
|
||||
_port = ethernet.RAW_PORT,
|
||||
_layers = {},
|
||||
_listener = 0,
|
||||
_mtu = computer.getDeviceInfo()[modem.address].capacity - 72
|
||||
}
|
||||
|
||||
o._modem.open(o._port)
|
||||
|
||||
setmetatable(o, {__index = self})
|
||||
|
||||
o._listener = event.listen("modem_message", function(...) o:modemMessageHandler(...) end)
|
||||
|
||||
return o
|
||||
---Create a EthernetInterface
|
||||
---@param modem ComponentModem
|
||||
---@return EthernetInterface
|
||||
function EthernetInterface:new(modem)
|
||||
checkArg(1, modem, "table")
|
||||
if (type(modem) == "table") then
|
||||
if (not modem.type == "modem") then error("#1 is not a modem component", 2) end
|
||||
end
|
||||
})
|
||||
|
||||
local o = self.parent()
|
||||
setmetatable(o, {__index = self})
|
||||
o._modem = modem
|
||||
o._mtu = computer.getDeviceInfo()[modem.address].capacity - 72
|
||||
o._modem.open(ethernet.RAW_PORT)
|
||||
o._listener = event.listen("modem_message", function(...) o:modemMessageHandler(...) end)
|
||||
|
||||
return o
|
||||
end
|
||||
|
||||
function EthernetInterface:close()
|
||||
self._modem.close(self._port)
|
||||
self._modem.close(ethernet.RAW_PORT)
|
||||
event.cancel(self._listener)
|
||||
end
|
||||
|
||||
@@ -196,9 +180,9 @@ end
|
||||
---@param etype ethernetType
|
||||
---@param payload string
|
||||
function EthernetInterface:modemMessageHandler(eName, localMac, remoteMac, port, distance, tag802_1Q, etype, payload)
|
||||
if (localMac ~= self:getAddr()) then return end
|
||||
if (port ~= self._port) then return false end
|
||||
local handler = self:getLayer(etype)
|
||||
if (localMac ~= self:addr()) then return end
|
||||
if (port ~= ethernet.RAW_PORT) then return false end
|
||||
local handler = self:higherLayer(etype)
|
||||
if (handler) then
|
||||
handler:payloadHandler(remoteMac, localMac, payload)
|
||||
else
|
||||
@@ -208,11 +192,11 @@ end
|
||||
|
||||
---Get the maximum size a ethernet frame can have
|
||||
---@return number mtu
|
||||
function EthernetInterface:getMTU() return self._mtu end
|
||||
function EthernetInterface:mtu() return self._mtu end
|
||||
|
||||
---Get the interface's mac address
|
||||
---@return string uuid
|
||||
function EthernetInterface:getAddr()
|
||||
function EthernetInterface:addr()
|
||||
return self._modem.address
|
||||
end
|
||||
|
||||
@@ -221,33 +205,15 @@ end
|
||||
---@param eFrame EthernetFrame
|
||||
function EthernetInterface:send(dst, eFrame)
|
||||
checkArg(1, dst, "string", "nil")
|
||||
dst = dst or eFrame:getDst()
|
||||
dst = dst or eFrame:dst()
|
||||
checkArg(2, eFrame, "table")
|
||||
if (dst == ethernet.MAC_BROADCAST) then
|
||||
self._modem.broadcast(self._port, eFrame:pack())
|
||||
self._modem.broadcast(ethernet.RAW_PORT, eFrame:pack())
|
||||
else
|
||||
self._modem.send(dst, self._port, eFrame:pack())
|
||||
self._modem.send(dst, ethernet.RAW_PORT, eFrame:pack())
|
||||
end
|
||||
end
|
||||
|
||||
---Get the registed layer handler object
|
||||
---@param etype ethernetType
|
||||
---@return OSINetworkLayer?
|
||||
function EthernetInterface:getLayer(etype)
|
||||
if self._layers[etype] then
|
||||
return self._layers[etype]
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
---Set the layer handler object
|
||||
---@param layerHandler OSINetworkLayer
|
||||
function EthernetInterface:setLayer(layerHandler)
|
||||
checkArg(1, layerHandler, "table")
|
||||
if (not type(layerHandler.payloadHandler) == "function") then error("#1 : not a OSINetwork") end
|
||||
self._layers[layerHandler.layerType] = layerHandler
|
||||
end
|
||||
|
||||
--#endregion
|
||||
--=============================================================================
|
||||
|
||||
|
@@ -1,33 +1,31 @@
|
||||
local network = require("network")
|
||||
local ipv4 = require("network.ipv4")
|
||||
local ICMPPacket = require("network.icmp.ICMPPacket")
|
||||
local icmpConst = require("network.icmp.constantes")
|
||||
local event = require("event")
|
||||
local network = require("network")
|
||||
local ipv4 = require("network.ipv4")
|
||||
local ICMPPacket = require("network.icmp.ICMPPacket")
|
||||
local icmpConst = require("network.icmp.constantes")
|
||||
local event = require("event")
|
||||
local NetworkLayer = require('network.abstract.NetworkLayer')
|
||||
local class = require("libClass2")
|
||||
|
||||
|
||||
---@class ICMPLayer:OSINetworkLayer
|
||||
---@field private _layer OSINetworkLayer
|
||||
---@class ICMPLayer:NetworkLayer
|
||||
---@operator call:ICMPLayer
|
||||
---@overload fun(layer:IPv4Layer):ICMPLayer
|
||||
local ICMPLayer = {}
|
||||
local ICMPLayer = class(NetworkLayer)
|
||||
ICMPLayer.layerType = ipv4.PROTOCOLS.ICMP
|
||||
|
||||
setmetatable(ICMPLayer, {
|
||||
---@param layer OSINetworkLayer
|
||||
---@return ICMPLayer
|
||||
__call = function(self, layer)
|
||||
local o = {
|
||||
_layer = layer
|
||||
}
|
||||
setmetatable(o, {__index = self})
|
||||
layer:setLayer(o)
|
||||
return o
|
||||
end,
|
||||
})
|
||||
---@param layer NetworkLayer
|
||||
---@return ICMPLayer
|
||||
function ICMPLayer:new(layer)
|
||||
local o = self.parent()
|
||||
setmetatable(o, {__index = self})
|
||||
---@cast o ICMPLayer
|
||||
o:layer(layer)
|
||||
return o
|
||||
end
|
||||
|
||||
---@param payload ICMPPacket
|
||||
function ICMPLayer:send(dst, payload)
|
||||
local localIP = network.router:getRoute(dst).interface:getAddr()
|
||||
local localIP = network.router:getRoute(dst).interface:addr()
|
||||
assert(localIP, "[ICMP] : no local IP. Cannot send packet")
|
||||
local ipDatagram = ipv4.IPv4Packet(localIP, dst, payload)
|
||||
network.router:send(ipDatagram)
|
||||
@@ -36,16 +34,16 @@ end
|
||||
---@param payload string
|
||||
function ICMPLayer:payloadHandler(from, to, payload)
|
||||
local icmpPacket = ICMPPacket.unpack(payload)
|
||||
if (icmpPacket:getType() == icmpConst.TYPE.ECHO_REQUEST) then
|
||||
local reply = ICMPPacket(icmpConst.TYPE.ECHO_REPLY, icmpConst.CODE.ECHO_REPLY.ECHO_REPLY, icmpPacket:getParam(), icmpPacket:getPayload())
|
||||
if (icmpPacket:type() == icmpConst.TYPE.ECHO_REQUEST) then
|
||||
local reply = ICMPPacket(icmpConst.TYPE.ECHO_REPLY, icmpConst.CODE.ECHO_REPLY.ECHO_REPLY, icmpPacket:param(), icmpPacket:payload())
|
||||
self:send(from, reply)
|
||||
elseif (icmpPacket:getType() == icmpConst.TYPE.ECHO_REPLY) then
|
||||
event.push("ICMP", from, to, icmpPacket:getType(), icmpPacket:getCode(), icmpPacket:getParam(), icmpPacket:getPayload())
|
||||
elseif (icmpPacket:type() == icmpConst.TYPE.ECHO_REPLY) then
|
||||
event.push("ICMP", from, to, icmpPacket:type(), icmpPacket:code(), icmpPacket:param(), icmpPacket:payload())
|
||||
end
|
||||
end
|
||||
|
||||
function ICMPLayer:getAddr()
|
||||
return self._layer:getAddr()
|
||||
function ICMPLayer:addr()
|
||||
return self:layer():addr()
|
||||
end
|
||||
|
||||
---Send a timeout icmp message
|
||||
@@ -53,10 +51,10 @@ end
|
||||
---@param code number
|
||||
function ICMPLayer:sendTimeout(packet, code)
|
||||
local icmpPacket = ICMPPacket(icmpConst.TYPE.TIME_EXCEEDED, icmpConst.CODE.TIME_EXCEEDED.TTL_expired_in_transit, nil, string.format("%.2x%.2x%.4x%.4x%.2x%.4x%.2x%.2x%.8x%.8x%s",
|
||||
packet:getDscp(), packet:getEcn(), packet:getLen(), packet:getId(), packet:getFlags(),
|
||||
packet:getFragmentOffset(), packet:getTtl(), packet:getProtocol(),
|
||||
packet:getSrc(), packet:getDst(), packet:getPayload():sub(1, 8)))
|
||||
self:send(packet:getSrc(), icmpPacket)
|
||||
packet:dscp(), packet:ecn(), packet:len(), packet:id(), packet:flags(),
|
||||
packet:fragmentOffset(), packet:ttl(), packet:protocol(),
|
||||
packet:src(), packet:dst(), packet:payload():sub(1, 8)))
|
||||
self:send(packet:src(), icmpPacket)
|
||||
end
|
||||
|
||||
return ICMPLayer
|
||||
|
@@ -1,5 +1,7 @@
|
||||
local ipv4 = require("network.ipv4")
|
||||
local ipv4 = require("network.ipv4")
|
||||
local Payload = require("network.abstract.Payload")
|
||||
|
||||
local class = require("libClass2")
|
||||
|
||||
---@class ICMPPacket:Payload
|
||||
---@field private _type number
|
||||
@@ -10,76 +12,75 @@ local ipv4 = require("network.ipv4")
|
||||
---@overload fun(type:icmpType,code:number,param:number,paylaod:string):ICMPPacket
|
||||
---@overload fun(type:icmpType,code:number,param:number):ICMPPacket
|
||||
---@overload fun(type:icmpType,code:number):ICMPPacket
|
||||
local ICMPPacket = {}
|
||||
local ICMPPacket = class(Payload)
|
||||
ICMPPacket.payloadType = ipv4.PROTOCOLS.ICMP
|
||||
|
||||
setmetatable(ICMPPacket, {
|
||||
---@param type icmpType
|
||||
---@param code number
|
||||
---@param param? number
|
||||
---@param payload? string
|
||||
---@return ICMPPacket
|
||||
__call = function(self, type, code, param, payload)
|
||||
local o = {
|
||||
_type = type,
|
||||
_code = code,
|
||||
_param = param or 0,
|
||||
_payload = payload or ""
|
||||
}
|
||||
setmetatable(o, {__index = self})
|
||||
return o
|
||||
end
|
||||
})
|
||||
|
||||
---@param type icmpType
|
||||
---@param code number
|
||||
---@param param? number
|
||||
---@param payload? string
|
||||
---@return ICMPPacket
|
||||
function ICMPPacket:new(type, code, param, payload)
|
||||
local o = {
|
||||
_type = type,
|
||||
_code = code,
|
||||
_param = param or 0,
|
||||
_payload = payload or ""
|
||||
}
|
||||
setmetatable(o, {__index = self})
|
||||
return o
|
||||
end
|
||||
|
||||
--#region getter/setter
|
||||
|
||||
---@param value? number
|
||||
---@return number
|
||||
function ICMPPacket:getType() return self._type end
|
||||
|
||||
---@param val number
|
||||
function ICMPPacket:setType(val)
|
||||
checkArg(1, val, "number")
|
||||
self._type = val
|
||||
function ICMPPacket:type(value)
|
||||
checkArg(1, value, 'number', 'nil')
|
||||
local oldValue = self._type
|
||||
if (value ~= nil) then self._type = value end
|
||||
return oldValue
|
||||
end
|
||||
|
||||
---@param value? number
|
||||
---@return number
|
||||
function ICMPPacket:getCode() return self._code end
|
||||
|
||||
---@param val number
|
||||
function ICMPPacket:setCode(val)
|
||||
checkArg(1, val, "number")
|
||||
self._code = val
|
||||
function ICMPPacket:code(value)
|
||||
checkArg(1, value, 'number', 'nil')
|
||||
local oldValue = self._code
|
||||
if (value ~= nil) then self._code = value end
|
||||
return oldValue
|
||||
end
|
||||
|
||||
---@param value? number
|
||||
---@return number
|
||||
function ICMPPacket:getParam() return self._param end
|
||||
|
||||
---@param val number
|
||||
function ICMPPacket:setParam(val)
|
||||
checkArg(1, val, "number")
|
||||
self._param = val
|
||||
function ICMPPacket:param(value)
|
||||
checkArg(1, value, 'number', 'nil')
|
||||
local oldValue = self._param
|
||||
if (value ~= nil) then self._param = value end
|
||||
return oldValue
|
||||
end
|
||||
|
||||
---@param value? string
|
||||
---@return string
|
||||
function ICMPPacket:getPayload() return self._payload end
|
||||
|
||||
---@param val string
|
||||
function ICMPPacket:setPayload(val)
|
||||
checkArg(1, val, "string")
|
||||
self._payload = val
|
||||
function ICMPPacket:payload(value)
|
||||
checkArg(1, value, 'string', 'nil')
|
||||
local oldValue = self._payload
|
||||
if (value ~= nil) then self._payload = value end
|
||||
return oldValue
|
||||
end
|
||||
|
||||
--#endregion
|
||||
|
||||
local PACK_FORMAT = "I1I1xxI4s"
|
||||
ICMPPacket.payloadFormat = "I1I1xxI4s"
|
||||
|
||||
function ICMPPacket:pack()
|
||||
return string.pack(PACK_FORMAT, self._type, self._code, self._param, self._payload)
|
||||
return string.pack(self.payloadFormat, self._type, self._code, self._param, self._payload)
|
||||
end
|
||||
|
||||
---@return ICMPPacket
|
||||
function ICMPPacket.unpack(val)
|
||||
return ICMPPacket(string.unpack(PACK_FORMAT, val))
|
||||
return ICMPPacket(string.unpack(ICMPPacket.payloadFormat, val))
|
||||
end
|
||||
|
||||
return ICMPPacket
|
||||
|
@@ -1,5 +1,5 @@
|
||||
local component = require("component")
|
||||
local routing = require("routing")
|
||||
local IPv4Router = require("network.ipv4.IPv4Router")
|
||||
|
||||
---@class InterfaceTypes
|
||||
---@field ethernet EthernetInterface
|
||||
@@ -16,7 +16,7 @@ networklib.internal = {
|
||||
---@type table<string,InterfaceTypes>
|
||||
networklib.interfaces = {}
|
||||
---@type IPv4Router
|
||||
networklib.router = routing.IPv4Router()
|
||||
networklib.router = IPv4Router()
|
||||
|
||||
---Get the configured interfaces
|
||||
---@param filter string
|
||||
|
@@ -1,112 +1,116 @@
|
||||
local ethernet = require("network.ethernet")
|
||||
local arp = require("network.arp")
|
||||
local ipv4Address = require("network.ipv4.address")
|
||||
local IPv4Packet = require("network.ipv4.IPv4Packet")
|
||||
local ipv4Consts = require("network.ipv4.constantes")
|
||||
local bit32 = require("bit32")
|
||||
local ethernet = require("network.ethernet")
|
||||
local arp = require("network.arp")
|
||||
local ipv4Address = require("network.ipv4.address")
|
||||
local IPv4Packet = require("network.ipv4.IPv4Packet")
|
||||
local ipv4Consts = require("network.ipv4.constantes")
|
||||
local IPv4Router = require('network.ipv4.IPv4Router')
|
||||
local NetworkLayer = require('network.abstract.NetworkLayer')
|
||||
local bit32 = require("bit32")
|
||||
local class = require("libClass2")
|
||||
|
||||
|
||||
---@class IPv4Layer : OSINetworkLayer
|
||||
---@class IPv4Layer : NetworkLayer
|
||||
---@field private _addr number
|
||||
---@field private _mask number
|
||||
---@field private _router IPv4Router
|
||||
---@field package _layer OSIDataLayer
|
||||
---@field package _layer NetworkLayer
|
||||
---@field package _arp ARPLayer
|
||||
---@field private _buffer table<number,table<number,table<number,IPv4Packet>>>
|
||||
---@operator call:IPv4Layer
|
||||
---@overload fun(dataLayer:OSIDataLayer,router:IPv4Router,addr:number|string,mask:number|string):IPv4Layer
|
||||
local IPv4Layer = {}
|
||||
---@overload fun(dataLayer:NetworkLayer,router:IPv4Router,addr:number|string,mask:number|string):IPv4Layer
|
||||
local IPv4Layer = class(NetworkLayer)
|
||||
IPv4Layer.layerType = ethernet.TYPE.IPv4
|
||||
|
||||
|
||||
setmetatable(IPv4Layer, {
|
||||
---@param dataLayer OSIDataLayer
|
||||
---@param router IPv4Router
|
||||
---@param addr number|string
|
||||
---@param mask number|string
|
||||
---@return IPv4Layer
|
||||
__call = function(self, dataLayer, router, addr, mask)
|
||||
checkArg(1, dataLayer, "table")
|
||||
checkArg(2, addr, "number", "string")
|
||||
checkArg(3, mask, "number", "string")
|
||||
local o = {
|
||||
_addr = 0,
|
||||
_mask = 0,
|
||||
_layer = dataLayer,
|
||||
_arp = nil,
|
||||
_router = nil,
|
||||
_buffer = {}
|
||||
}
|
||||
setmetatable(o, {__index = self})
|
||||
o:setAddr(addr)
|
||||
o:setMask(mask)
|
||||
dataLayer:setLayer(o)
|
||||
o:setRouter(router)
|
||||
--arp
|
||||
o._arp = arp.ARPLayer(dataLayer)
|
||||
arp.setLocalAddress(arp.HARDWARE_TYPE.ETHERNET, arp.PROTOCOLE_TYPE.IPv4, dataLayer:getAddr(), o:getAddr())
|
||||
return o
|
||||
end,
|
||||
})
|
||||
---@param dataLayer NetworkLayer
|
||||
---@param router IPv4Router
|
||||
---@param addr number|string
|
||||
---@param mask number
|
||||
---@return IPv4Layer
|
||||
function IPv4Layer:new(dataLayer, router, addr, mask)
|
||||
checkArg(1, dataLayer, "table")
|
||||
checkArg(2, addr, "number", "string")
|
||||
checkArg(3, mask, "number", "string")
|
||||
local o = self.parent()
|
||||
setmetatable(o, {__index = self})
|
||||
---@cast o IPv4Layer
|
||||
o._layer = dataLayer
|
||||
o._arp = nil
|
||||
o._buffer = {}
|
||||
|
||||
---Set the interfaces's address
|
||||
---@param val string|number
|
||||
function IPv4Layer:setAddr(val)
|
||||
if (type(val) == "number" and val > 0 and val < 0xffffffff) then
|
||||
self._addr = val
|
||||
else
|
||||
self._addr = ipv4Address.fromString(val)
|
||||
end
|
||||
o:layer(dataLayer)
|
||||
o:addr(addr)
|
||||
o:mask(mask)
|
||||
o:router(router)
|
||||
--arp
|
||||
o:arp(arp.ARPLayer(dataLayer))
|
||||
arp.setLocalAddress(arp.HARDWARE_TYPE.ETHERNET, arp.PROTOCOLE_TYPE.IPv4, dataLayer:addr(), o:addr())
|
||||
return o
|
||||
end
|
||||
|
||||
---Get the local IPv4
|
||||
---@return number
|
||||
function IPv4Layer:getAddr() return self._addr end
|
||||
---@param value? ARPLayer
|
||||
---@return ARPLayer
|
||||
function IPv4Layer:arp(value)
|
||||
checkArg(1, value, 'table', 'nil')
|
||||
local oldValue = self._arp
|
||||
if (value ~= nil) then
|
||||
assert(value:instanceOf(arp.ARPLayer))
|
||||
self._arp = value
|
||||
end
|
||||
return oldValue
|
||||
end
|
||||
|
||||
---Set the interfaces's address mask
|
||||
---@param val number
|
||||
function IPv4Layer:setMask(val)
|
||||
checkArg(1, val, "number")
|
||||
local found0 = false
|
||||
for i = 31, 0, -1 do
|
||||
if (not found0) then
|
||||
found0 = 0 == bit32.extract(val, i)
|
||||
---@param value? string|number
|
||||
---@return number
|
||||
function IPv4Layer:addr(value)
|
||||
checkArg(1, value, 'string', 'number', 'nil')
|
||||
local oldValue = self._addr
|
||||
if (value ~= nil) then
|
||||
if (type(value) == "number" and value > 0 and value < 0xffffffff) then
|
||||
self._addr = value
|
||||
else
|
||||
if (bit32.extract(val, i) == 1) then
|
||||
error("Invalid mask", 2)
|
||||
end
|
||||
self._addr = ipv4Address.fromString(value)
|
||||
end
|
||||
end
|
||||
if (type(val) == "number" and val > 0 and val < 0xffffffff) then
|
||||
self._mask = val
|
||||
else
|
||||
self._mask = ipv4Address.fromString(val)
|
||||
end
|
||||
return oldValue
|
||||
end
|
||||
|
||||
---Get the local mask
|
||||
---@param value? number
|
||||
---@return number
|
||||
function IPv4Layer:getMask() return self._mask end
|
||||
|
||||
function IPv4Layer:getMTU() return self._layer:getMTU() - 38 end
|
||||
|
||||
---@param layer OSILayer
|
||||
function IPv4Layer:setLayer(layer)
|
||||
self._router:setProtocol(layer)
|
||||
function IPv4Layer:mask(value)
|
||||
checkArg(1, value, 'number', 'nil')
|
||||
local oldValue = self._mask
|
||||
if (value ~= nil) then
|
||||
if (not (value >= 0 and value <= 0xffffffff)) then error("Invalid mask", 2) end
|
||||
local found0 = false
|
||||
for i = 31, 0, -1 do
|
||||
if (not found0) then
|
||||
found0 = (0 == bit32.extract(value, i))
|
||||
else
|
||||
if (bit32.extract(value, i) == 1) then
|
||||
error("Invalid mask", 2)
|
||||
end
|
||||
end
|
||||
end
|
||||
self._mask = value
|
||||
end
|
||||
return oldValue
|
||||
end
|
||||
|
||||
---Set the layer's router. Used for rerouting packets
|
||||
---@param router IPv4Router
|
||||
function IPv4Layer:setRouter(router)
|
||||
self._router = router
|
||||
self._router:setLayer(self)
|
||||
self._router:addRoute({network = bit32.band(self:getAddr(), self:getMask()), mask = self:getMask(), gateway = self:getAddr(), metric = 0, interface = self})
|
||||
end
|
||||
function IPv4Layer:mtu() return self:layer():mtu() - 38 end
|
||||
|
||||
---Get the router.
|
||||
---@param value? IPv4Router
|
||||
---@return IPv4Router
|
||||
function IPv4Layer:getRouter()
|
||||
return self._router
|
||||
function IPv4Layer:router(value)
|
||||
checkArg(1, value, 'table', 'nil')
|
||||
local oldValue = self._router
|
||||
if (value ~= nil) then
|
||||
assert(value:instanceOf(IPv4Router))
|
||||
self._router = value
|
||||
self._router:higherLayer(self.layerType, self)
|
||||
self._router:addRoute({network = bit32.band(self:addr(), self:mask()), mask = self:mask(), gateway = self:addr(), metric = 0, interface = self})
|
||||
end
|
||||
return oldValue
|
||||
end
|
||||
|
||||
---Send a IPv4Packet
|
||||
@@ -118,18 +122,18 @@ function IPv4Layer:send(to, payload)
|
||||
if (not payload) then
|
||||
---@diagnostic disable-next-line: cast-local-type
|
||||
payload = to
|
||||
to = payload:getDst()
|
||||
to = payload:dst()
|
||||
end
|
||||
---@cast payload IPv4Packet
|
||||
if (to == self:getAddr()) then --sent to self
|
||||
local l = self._layer --[[@as EthernetInterface]]
|
||||
self:payloadHandler(l:getAddr(), l:getAddr(), payload:pack())
|
||||
if (to == self:addr()) then --sent to self
|
||||
local l = self:layer() --[[@as EthernetInterface]]
|
||||
self:payloadHandler(l:addr() --[[@as string]], l:addr() --[[@as string]], payload:pack())
|
||||
else
|
||||
local dst = arp.getAddress(self._arp, arp.HARDWARE_TYPE.ETHERNET, self.layerType, to, self:getAddr())
|
||||
local dst = arp.getAddress(self._arp, arp.HARDWARE_TYPE.ETHERNET, self.layerType, to, self:addr())
|
||||
if (not dst) then error("Cannot resolve IP", 2) end
|
||||
for _, payloadFragment in pairs(payload:getFragments(self:getMTU())) do
|
||||
local eFrame = ethernet.EthernetFrame(self._layer:getAddr(), dst, nil, self.layerType, payloadFragment:pack())
|
||||
self._layer:send(dst, eFrame)
|
||||
for _, payloadFragment in pairs(payload:getFragments(self:mtu())) do
|
||||
local eFrame = ethernet.EthernetFrame(self:layer():addr(), dst, nil, self.layerType, payloadFragment:pack())
|
||||
self:layer():send(dst, eFrame)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -142,29 +146,29 @@ function IPv4Layer:payloadHandler(from, to, payload)
|
||||
checkArg(2, to, 'string')
|
||||
checkArg(3, payload, 'string')
|
||||
local pl = IPv4Packet.unpack(payload)
|
||||
if (pl:getDst() == self:getAddr()) then
|
||||
if (pl:getLen() > 1) then --merge framents
|
||||
local bufferID = string.format("%d%d%d%d", from, to, pl:getProtocol(), pl:getId())
|
||||
if (pl:dst() == self:addr()) then
|
||||
if (pl:len() > 1) then --merge framents
|
||||
local bufferID = string.format("%d%d%d%d", from, to, pl:protocol(), pl:id())
|
||||
self._buffer[bufferID] = self._buffer[bufferID] or {}
|
||||
|
||||
--place the packet in a buffer
|
||||
table.insert(self._buffer[bufferID], math.max(#self._buffer[bufferID], pl:getFragmentOffset()), pl)
|
||||
table.insert(self._buffer[bufferID], math.max(#self._buffer[bufferID], pl:fragmentOffset()), pl)
|
||||
|
||||
--if the buffer hold all the packets merge them
|
||||
if (#self._buffer[bufferID] == pl:getLen()) then
|
||||
local fullPayload, proto = {}, pl:getProtocol()
|
||||
for i, fragment in ipairs(self._buffer[pl:getProtocol()][pl:getSrc()]) do
|
||||
table.insert(fullPayload, math.max(#fullPayload, fragment:getFragmentOffset()), fragment:getPayload())
|
||||
if (#self._buffer[bufferID] == pl:len()) then
|
||||
local fullPayload, proto = {}, pl:protocol()
|
||||
for i, fragment in ipairs(self._buffer[pl:protocol()][pl:src()]) do
|
||||
table.insert(fullPayload, math.max(#fullPayload, fragment:fragmentOffset()), fragment:payload())
|
||||
end
|
||||
pl = IPv4Packet(pl:getSrc(), pl:getDst(), table.concat(fullPayload), pl:getProtocol())
|
||||
pl:setProtocol(proto)
|
||||
self._buffer[pl:getProtocol()][pl:getSrc()] = nil
|
||||
pl = IPv4Packet(pl:src(), pl:dst(), table.concat(fullPayload), pl:protocol())
|
||||
pl:protocol(proto)
|
||||
self._buffer[pl:protocol()][pl:src()] = nil
|
||||
end
|
||||
--TODO : handle merge timeout
|
||||
end
|
||||
if (pl:getLen() == 1) then
|
||||
if (pl:len() == 1) then
|
||||
--if the packet is complete, send it to the router to be handed to the destination program
|
||||
self._router:payloadHandler(pl:getSrc(), pl:getDst(), pl:pack())
|
||||
self._router:payloadHandler(pl:src(), pl:dst(), pl:pack())
|
||||
end
|
||||
else
|
||||
--TODO : check if routing is enabled
|
||||
|
@@ -1,5 +1,7 @@
|
||||
local bit32 = require("bit32")
|
||||
local ethernet = require("network.ethernet")
|
||||
local Payload = require("network.abstract.Payload")
|
||||
local class = require("libClass2")
|
||||
|
||||
|
||||
---@class IPv4Header
|
||||
@@ -20,7 +22,6 @@ local ethernet = require("network.ethernet")
|
||||
---@field protocol ipv4Protocol
|
||||
|
||||
--=============================================================================
|
||||
--#region IPv4Packet
|
||||
|
||||
---@class IPv4Packet : Payload
|
||||
---@field private _header IPv4Header
|
||||
@@ -28,179 +29,151 @@ local ethernet = require("network.ethernet")
|
||||
---@operator call:IPv4Packet
|
||||
---@overload fun(src:number,dst:number,paylaod:Payload):IPv4Packet
|
||||
---@overload fun(src:number,dst:number,paylaod:string,protocol:ipv4Protocol):IPv4Packet
|
||||
local IPv4Packet = {}
|
||||
local IPv4Packet = class(Payload)
|
||||
IPv4Packet.payloadType = ethernet.TYPE.IPv6
|
||||
|
||||
setmetatable(IPv4Packet, {
|
||||
---@param src number
|
||||
---@param dst number
|
||||
---@param payload Payload|string
|
||||
---@param protocole? ipv4Protocol
|
||||
---@return IPv4Packet
|
||||
__call = function(self, src, dst, payload, protocole)
|
||||
checkArg(1, src, 'number')
|
||||
checkArg(2, dst, 'number')
|
||||
checkArg(3, payload, 'string', 'table')
|
||||
local o = {
|
||||
---@type IPv4Header
|
||||
_header = {
|
||||
dscp = 0,
|
||||
ecn = 0,
|
||||
len = 1,
|
||||
id = 0,
|
||||
flags = 0,
|
||||
fragmentOffset = 0,
|
||||
ttl = 64,
|
||||
protocol = 1,
|
||||
src = 0,
|
||||
dst = 0,
|
||||
},
|
||||
_payload = ""
|
||||
}
|
||||
---@param src number
|
||||
---@param dst number
|
||||
---@param payload Payload|string
|
||||
---@param protocole? ipv4Protocol
|
||||
---@return IPv4Packet
|
||||
function IPv4Packet:new(src, dst, payload, protocole)
|
||||
checkArg(1, src, 'number')
|
||||
checkArg(2, dst, 'number')
|
||||
checkArg(3, payload, 'string', 'table')
|
||||
local o = {
|
||||
---@type IPv4Header
|
||||
_header = {
|
||||
dscp = 0,
|
||||
ecn = 0,
|
||||
len = 1,
|
||||
id = 0,
|
||||
flags = 0,
|
||||
fragmentOffset = 0,
|
||||
ttl = 64,
|
||||
protocol = 1,
|
||||
src = 0,
|
||||
dst = 0,
|
||||
},
|
||||
_payload = ""
|
||||
}
|
||||
|
||||
setmetatable(o, {__index = self})
|
||||
---@cast o IPv4Packet
|
||||
o:setSrc(src)
|
||||
o:setDst(dst)
|
||||
if (type(payload) == "string") then
|
||||
checkArg(4, protocole, 'number')
|
||||
---@cast protocole - nil
|
||||
o:setProtocol(protocole)
|
||||
o:setPayload(payload)
|
||||
else
|
||||
o:setProtocol(payload.payloadType)
|
||||
o:setPayload(payload:pack())
|
||||
end
|
||||
|
||||
return o
|
||||
setmetatable(o, {__index = self})
|
||||
---@cast o IPv4Packet
|
||||
o:src(src)
|
||||
o:dst(dst)
|
||||
if (type(payload) == "string") then
|
||||
checkArg(4, protocole, 'number')
|
||||
---@cast protocole - nil
|
||||
o:protocol(protocole)
|
||||
o:payload(payload)
|
||||
else
|
||||
o:protocol(payload.payloadType)
|
||||
o:payload(payload:pack())
|
||||
end
|
||||
})
|
||||
|
||||
return o
|
||||
end
|
||||
|
||||
--#region getter/setter
|
||||
|
||||
---Get the packet's payload
|
||||
---@param value? string
|
||||
---@return string
|
||||
function IPv4Packet:getPayload()
|
||||
return self._payload
|
||||
function IPv4Packet:payload(value)
|
||||
checkArg(1, value, 'string', 'nil')
|
||||
local oldValue = self._payload
|
||||
if (value ~= nil) then self._payload = value end
|
||||
return oldValue
|
||||
end
|
||||
|
||||
---Set the packet's payload
|
||||
---@param val string
|
||||
function IPv4Packet:setPayload(val)
|
||||
self._payload = val
|
||||
end
|
||||
|
||||
---Get the header's dscp value
|
||||
---@param value? number
|
||||
---@return number
|
||||
function IPv4Packet:getDscp() return self._header.dscp end
|
||||
|
||||
---Set the header's dscp value
|
||||
---@param val number
|
||||
function IPv4Packet:setDscp(val)
|
||||
checkArg(1, val, "number")
|
||||
self._header.dscp = val
|
||||
function IPv4Packet:dscp(value)
|
||||
checkArg(1, value, 'number', 'nil')
|
||||
local oldValue = self._header.dscp
|
||||
if (value ~= nil) then self._header.dscp = value end
|
||||
return oldValue
|
||||
end
|
||||
|
||||
---Get the header's ecn value
|
||||
---@param value? number
|
||||
---@return number
|
||||
function IPv4Packet:getEcn() return self._header.ecn end
|
||||
|
||||
---Set the header's ecn value
|
||||
---@param val number
|
||||
function IPv4Packet:setEcn(val)
|
||||
checkArg(1, val, "number")
|
||||
self._header.ecn = val
|
||||
function IPv4Packet:ecn(value)
|
||||
checkArg(1, value, 'number', 'nil')
|
||||
local oldValue = self._header.ecn
|
||||
if (value ~= nil) then self._header.ecn = value end
|
||||
return oldValue
|
||||
end
|
||||
|
||||
---Get the header's len value
|
||||
---@param value? number
|
||||
---@return number
|
||||
function IPv4Packet:getLen() return self._header.len end
|
||||
|
||||
---Set the header's len value
|
||||
---@protected
|
||||
---@param val number
|
||||
function IPv4Packet:setLen(val)
|
||||
checkArg(1, val, "number")
|
||||
self._header.len = val
|
||||
function IPv4Packet:len(value)
|
||||
checkArg(1, value, 'number', 'nil')
|
||||
local oldValue = self._header.len
|
||||
if (value ~= nil) then self._header.len = value end
|
||||
return oldValue
|
||||
end
|
||||
|
||||
---Get the header's id value
|
||||
---@param value? number
|
||||
---@return number
|
||||
function IPv4Packet:getId() return self._header.id end
|
||||
|
||||
---Set the header's id value
|
||||
---@protected
|
||||
---@param val number
|
||||
function IPv4Packet:setId(val)
|
||||
checkArg(1, val, "number")
|
||||
self._header.id = val
|
||||
function IPv4Packet:id(value)
|
||||
checkArg(1, value, 'number', 'nil')
|
||||
local oldValue = self._header.id
|
||||
if (value ~= nil) then self._header.id = value end
|
||||
return oldValue
|
||||
end
|
||||
|
||||
---Get the header's flags value
|
||||
---@param value? number
|
||||
---@return number
|
||||
function IPv4Packet:getFlags() return self._header.flags end
|
||||
|
||||
---Set the header's flags value
|
||||
---@param val number
|
||||
function IPv4Packet:setFlags(val)
|
||||
checkArg(1, val, "number")
|
||||
self._header.flags = val
|
||||
function IPv4Packet:flags(value)
|
||||
checkArg(1, value, 'number', 'nil')
|
||||
local oldValue = self._header.flags
|
||||
if (value ~= nil) then self._header.flags = value end
|
||||
return oldValue
|
||||
end
|
||||
|
||||
---Get the header's fragmentOffset value
|
||||
---@param value? number
|
||||
---@return number
|
||||
function IPv4Packet:getFragmentOffset() return self._header.fragmentOffset end
|
||||
|
||||
---Set the header's fragmentOffset value
|
||||
---@protected
|
||||
---@param val number
|
||||
function IPv4Packet:setFragmentOffset(val)
|
||||
checkArg(1, val, "number")
|
||||
self._header.fragmentOffset = val
|
||||
function IPv4Packet:fragmentOffset(value)
|
||||
checkArg(1, value, 'number', 'nil')
|
||||
local oldValue = self._header.fragmentOffset
|
||||
if (value ~= nil) then self._header.fragmentOffset = value end
|
||||
return oldValue
|
||||
end
|
||||
|
||||
---Get the header's ttl value
|
||||
---@param value? number
|
||||
---@return number
|
||||
function IPv4Packet:getTtl() return self._header.ttl end
|
||||
|
||||
---Set the header's ttl value
|
||||
---@param val number
|
||||
function IPv4Packet:setTtl(val)
|
||||
checkArg(1, val, "number")
|
||||
self._header.ttl = val
|
||||
function IPv4Packet:ttl(value)
|
||||
checkArg(1, value, 'number', 'nil')
|
||||
local oldValue = self._header.ttl
|
||||
if (value ~= nil) then self._header.ttl = value end
|
||||
return oldValue
|
||||
end
|
||||
|
||||
---Get the header's protocol value
|
||||
---@return ipv4Protocol
|
||||
function IPv4Packet:getProtocol() return self._header.protocol end
|
||||
|
||||
---Set the header's protocol value
|
||||
---@param val ipv4Protocol
|
||||
function IPv4Packet:setProtocol(val)
|
||||
checkArg(1, val, "number")
|
||||
self._header.protocol = val
|
||||
end
|
||||
|
||||
---Get the header's src value
|
||||
---@param value? number
|
||||
---@return number
|
||||
function IPv4Packet:getSrc() return self._header.src end
|
||||
|
||||
---Set the header's src value
|
||||
---@param val number
|
||||
function IPv4Packet:setSrc(val)
|
||||
checkArg(1, val, "number")
|
||||
self._header.src = val
|
||||
function IPv4Packet:protocol(value)
|
||||
checkArg(1, value, 'number', 'nil')
|
||||
local oldValue = self._header.protocol
|
||||
if (value ~= nil) then self._header.protocol = value end
|
||||
return oldValue
|
||||
end
|
||||
|
||||
---Get the header's dst value
|
||||
---@param value? number
|
||||
---@return number
|
||||
function IPv4Packet:getDst() return self._header.dst end
|
||||
function IPv4Packet:src(value)
|
||||
checkArg(1, value, 'number', 'nil')
|
||||
local oldValue = self._header.src
|
||||
if (value ~= nil) then self._header.src = value end
|
||||
return oldValue
|
||||
end
|
||||
|
||||
---Set the header's dst value
|
||||
---@param val number
|
||||
function IPv4Packet:setDst(val)
|
||||
checkArg(1, val, "number")
|
||||
self._header.dst = val
|
||||
---@param value? number
|
||||
---@return number
|
||||
function IPv4Packet:dst(value)
|
||||
checkArg(1, value, 'number', 'nil')
|
||||
local oldValue = self._header.dst
|
||||
if (value ~= nil) then self._header.dst = value end
|
||||
return oldValue
|
||||
end
|
||||
|
||||
--#endregion
|
||||
@@ -211,36 +184,36 @@ end
|
||||
function IPv4Packet:getFragments(maxFragmentSize)
|
||||
local fragments = {}
|
||||
local fragmentID = 1;
|
||||
local fragmentTotal = math.ceil(#self:getPayload() / maxFragmentSize)
|
||||
local fragmentTotal = math.ceil(#self:payload() / maxFragmentSize)
|
||||
local currentPos = 1
|
||||
if (fragmentTotal > 1) then
|
||||
if (bit32.btest(self:getFlags(), 2)) then
|
||||
if (bit32.btest(self:flags(), 2)) then
|
||||
error("Packet may not be fragmented", 2)
|
||||
end
|
||||
end
|
||||
maxFragmentSize = math.max(1, maxFragmentSize - 1)
|
||||
local currentFragment = self:getPayload():sub(currentPos, currentPos + maxFragmentSize)
|
||||
local currentFragment = self:payload():sub(currentPos, currentPos + maxFragmentSize)
|
||||
while currentFragment ~= "" do
|
||||
local framgentPacket = IPv4Packet(self:getSrc(), self:getDst(), currentFragment, self:getProtocol())
|
||||
local framgentPacket = IPv4Packet(self:src(), self:dst(), currentFragment, self:protocol())
|
||||
table.insert(fragments, framgentPacket)
|
||||
framgentPacket:setId(self:getId())
|
||||
framgentPacket:setFragmentOffset(#fragments)
|
||||
framgentPacket:setLen(fragmentTotal)
|
||||
framgentPacket:id(self:id())
|
||||
framgentPacket:fragmentOffset(#fragments)
|
||||
framgentPacket:len(fragmentTotal)
|
||||
fragmentID = fragmentID + 1
|
||||
currentPos = currentPos + maxFragmentSize + 1
|
||||
if (fragmentID < fragmentTotal) then
|
||||
--Set the MF (more fragment flag)
|
||||
framgentPacket:setFlags(bit32.bor(framgentPacket:getFlags(), 4))
|
||||
framgentPacket:flags(bit32.bor(framgentPacket:flags(), 4))
|
||||
end
|
||||
currentFragment = self:getPayload():sub(currentPos, currentPos + maxFragmentSize)
|
||||
currentFragment = self:payload():sub(currentPos, currentPos + maxFragmentSize)
|
||||
end
|
||||
return fragments
|
||||
end
|
||||
|
||||
local PACK_FORMAT = "xI1I1I2I1I1I2I1I1xxI4I4s"
|
||||
IPv4Packet.payloadFormat = "xI1I1I2I1I1I2I1I1xxI4I4s"
|
||||
|
||||
function IPv4Packet:pack()
|
||||
return string.pack(PACK_FORMAT, self:getDscp(), self:getEcn(), self:getLen(), self:getId(), self:getFlags(), self:getFragmentOffset(), self:getTtl(), self:getProtocol(), self:getSrc(), self:getDst(), self:getPayload())
|
||||
return string.pack(self.payloadFormat, self:dscp(), self:ecn(), self:len(), self:id(), self:flags(), self:fragmentOffset(), self:ttl(), self:protocol(), self:src(), self:dst(), self:payload())
|
||||
end
|
||||
|
||||
---@param val string
|
||||
@@ -248,7 +221,7 @@ end
|
||||
function IPv4Packet.unpack(val)
|
||||
checkArg(1, val, 'string')
|
||||
|
||||
local dscp, ecn, len, id, flags, fragmentOffset, ttl, protocol, src, dst, payload = string.unpack(PACK_FORMAT, val)
|
||||
local dscp, ecn, len, id, flags, fragmentOffset, ttl, protocol, src, dst, payload = string.unpack(IPv4Packet.payloadFormat, val)
|
||||
---@cast dscp number
|
||||
---@cast ecn number
|
||||
---@cast len number
|
||||
@@ -262,13 +235,13 @@ function IPv4Packet.unpack(val)
|
||||
---@cast payload string
|
||||
|
||||
local packet = IPv4Packet(src, dst, payload, protocol)
|
||||
packet:setDscp(dscp)
|
||||
packet:setEcn(ecn)
|
||||
packet:setLen(len)
|
||||
packet:setId(id)
|
||||
packet:setFlags(flags)
|
||||
packet:setFragmentOffset(fragmentOffset)
|
||||
packet:setTtl(ttl)
|
||||
packet:dscp(dscp)
|
||||
packet:ecn(ecn)
|
||||
packet:len(len)
|
||||
packet:id(id)
|
||||
packet:flags(flags)
|
||||
packet:fragmentOffset(fragmentOffset)
|
||||
packet:ttl(ttl)
|
||||
|
||||
return packet
|
||||
end
|
||||
|
@@ -1,8 +1,11 @@
|
||||
local bit32 = require("bit32")
|
||||
local ipv4 = require("network.ipv4")
|
||||
local ipv4Address = require("network.ipv4.address")
|
||||
local IPv4Packet = require("network.ipv4.IPv4Packet")
|
||||
local NetworkLayer = require('network.abstract.NetworkLayer')
|
||||
local class = require("libClass2")
|
||||
|
||||
---@class routingLib
|
||||
local routing = {}
|
||||
local routing = class(NetworkLayer)
|
||||
--=============================================================================
|
||||
|
||||
---@class Route
|
||||
@@ -13,25 +16,23 @@ local routing = {}
|
||||
---@field interface IPv4Layer
|
||||
--=============================================================================
|
||||
|
||||
---@class IPv4Router:OSINetworkLayer
|
||||
---@class IPv4Router:NetworkLayer
|
||||
---@field private _routes table<Route>
|
||||
---@field private _protocols table<ipv4Protocol,OSILayer>
|
||||
---@field private _protocols table<ipv4Protocol,NetworkLayer>
|
||||
---@operator call:IPv4Router
|
||||
---@overload fun():IPv4Router
|
||||
local IPv4Router = {}
|
||||
local IPv4Router = class(NetworkLayer)
|
||||
IPv4Router.layerType = require("network.ethernet").TYPE.IPv4
|
||||
|
||||
---@return IPv4Router
|
||||
setmetatable(IPv4Router, {
|
||||
__call = function(self)
|
||||
local o = {
|
||||
_routes = {},
|
||||
_protocols = {}
|
||||
}
|
||||
setmetatable(o, {__index = self})
|
||||
return o
|
||||
end
|
||||
})
|
||||
function IPv4Router:new()
|
||||
local o = self.parent()
|
||||
setmetatable(o, {__index = self})
|
||||
---@cast o IPv4Router
|
||||
o._routes = {}
|
||||
o._protocols = {}
|
||||
return o
|
||||
end
|
||||
|
||||
---Add a new route
|
||||
---@param route Route
|
||||
@@ -84,7 +85,7 @@ function IPv4Router:getRoute(address)
|
||||
local address2 = bit32.band(route.network, route.mask)
|
||||
if (address1 == address2) then return route end
|
||||
end
|
||||
error(string.format("No route found to %s. This is not normal. Make sure a default route is set", ipv4.address.tostring(address)), 2)
|
||||
error(string.format("No route found to %s. This is not normal. Make sure a default route is set", ipv4Address.tostring(address)), 2)
|
||||
end
|
||||
|
||||
---Remove a route
|
||||
@@ -134,38 +135,25 @@ function IPv4Router:removeByInterface(interface)
|
||||
for v in pairs(rmRoutes) do
|
||||
table.remove(self._routes, v)
|
||||
end
|
||||
self:removeGateway(interface:getAddr())
|
||||
self:removeGateway(interface:addr())
|
||||
end
|
||||
|
||||
---send the IPv4 packet
|
||||
---@param packet IPv4Packet
|
||||
function IPv4Router:send(packet)
|
||||
packet:setTtl(packet:getTtl() - 1)
|
||||
packet:ttl(packet:ttl() - 1)
|
||||
--TODO : icmp error if ttl 0
|
||||
local route = self:getRoute(packet:getDst())
|
||||
if (packet:getSrc() == 0) then
|
||||
packet:setSrc(route.interface:getAddr())
|
||||
local route = self:getRoute(packet:dst())
|
||||
if (packet:src() == 0) then
|
||||
packet:src(route.interface:addr())
|
||||
end
|
||||
if (route.gateway == route.interface:getAddr()) then
|
||||
if (route.gateway == route.interface:addr()) then
|
||||
route.interface:send(packet)
|
||||
else
|
||||
route.interface:send(route.gateway, packet)
|
||||
end
|
||||
end
|
||||
|
||||
---@param protocolHandler OSILayer
|
||||
function IPv4Router:setProtocol(protocolHandler)
|
||||
self._protocols[protocolHandler.layerType] = protocolHandler
|
||||
end
|
||||
|
||||
IPv4Router.setLayer = IPv4Router.setProtocol
|
||||
|
||||
---@param protocolID ipv4Protocol
|
||||
---@return OSILayer
|
||||
function IPv4Router:getProtocol(protocolID)
|
||||
return self._protocols[protocolID]
|
||||
end
|
||||
|
||||
---@param from number
|
||||
---@param to number
|
||||
---@param payload string
|
||||
@@ -173,21 +161,21 @@ function IPv4Router:payloadHandler(from, to, payload)
|
||||
checkArg(1, from, 'number')
|
||||
checkArg(2, to, 'number')
|
||||
checkArg(3, payload, 'string')
|
||||
local packet = ipv4.IPv4Packet.unpack(payload)
|
||||
if (self._protocols[packet:getProtocol()]) then
|
||||
self._protocols[packet:getProtocol()]:payloadHandler(from, to, packet:getPayload())
|
||||
local packet = IPv4Packet.unpack(payload)
|
||||
if (self:higherLayer(packet:protocol())) then
|
||||
self:higherLayer(packet:protocol()):payloadHandler(from, to, packet:payload())
|
||||
end
|
||||
end
|
||||
|
||||
function IPv4Router:getAddr()
|
||||
return self:getRoute().interface
|
||||
---@return number
|
||||
function IPv4Router:addr()
|
||||
return self:getRoute().interface:addr()
|
||||
end
|
||||
|
||||
function IPv4Router:getMTU()
|
||||
return self:getRoute().interface:getMTU()
|
||||
function IPv4Router:mtu()
|
||||
return self:getRoute().interface:mtu()
|
||||
end
|
||||
|
||||
--=============================================================================
|
||||
|
||||
routing.IPv4Router = IPv4Router
|
||||
return routing
|
||||
return IPv4Router
|
@@ -4,6 +4,7 @@ local consts = require("network.ipv4.constantes")
|
||||
local ipv4lib = {
|
||||
IPv4Layer = require("network.ipv4.IPv4Layer"),
|
||||
IPv4Packet = require("network.ipv4.IPv4Packet"),
|
||||
IPv4Router = require("network.ipv4.IPv4Router"),
|
||||
address = require("network.ipv4.address"),
|
||||
PROTOCOLS = consts.PROTOCOLS
|
||||
}
|
||||
|
@@ -1,59 +1,65 @@
|
||||
local Payload = require("network.abstract.Payload")
|
||||
local class = require("libClass2")
|
||||
|
||||
---@class UDPDatagram : Payload
|
||||
---@field private _srcPort number
|
||||
---@field private _dstPort number
|
||||
---@field private _payload string
|
||||
---@operator call:UDPDatagram
|
||||
---@overload fun(srcPort:number,dstPort:number,payload:string):UDPDatagram
|
||||
local UDPDatagram = {}
|
||||
local UDPDatagram = class(Payload)
|
||||
UDPDatagram.payloadType = require("network.ipv4").PROTOCOLS.UDP
|
||||
|
||||
---@param self UDPDatagram
|
||||
---@param srcPort number
|
||||
---@param dstPort number
|
||||
---@param payload string
|
||||
---@return UDPDatagram
|
||||
setmetatable(UDPDatagram, {
|
||||
---@param self UDPDatagram
|
||||
---@param srcPort number
|
||||
---@param dstPort number
|
||||
---@param payload string
|
||||
---@return table
|
||||
__call = function(self, srcPort, dstPort, payload)
|
||||
checkArg(1, srcPort, "number")
|
||||
checkArg(2, dstPort, "number")
|
||||
checkArg(3, payload, "string")
|
||||
local o = {
|
||||
_scrPort = 0,
|
||||
_dstPort = 0,
|
||||
_payload = ""
|
||||
}
|
||||
setmetatable(o, {__index = self})
|
||||
function UDPDatagram:new(srcPort, dstPort, payload)
|
||||
checkArg(1, srcPort, "number")
|
||||
checkArg(2, dstPort, "number")
|
||||
checkArg(3, payload, "string")
|
||||
local o = self.parent()
|
||||
setmetatable(o, {__index = self})
|
||||
|
||||
o:setDstPort(dstPort)
|
||||
o:setSrcPort(srcPort)
|
||||
o:setPayload(payload)
|
||||
o:dstPort(dstPort)
|
||||
o:srcPort(srcPort)
|
||||
o:payload(payload)
|
||||
|
||||
return o
|
||||
return o
|
||||
end
|
||||
|
||||
---@param value? number
|
||||
---@return number
|
||||
function UDPDatagram:dstPort(value)
|
||||
checkArg(1, value, 'number', 'nil')
|
||||
local oldValue = self._dstPort
|
||||
if (value ~= nil) then
|
||||
assert(value >= 0 and value <= 2 ^ 16 - 1, "Port outside valid range")
|
||||
self._dstPort = value
|
||||
end
|
||||
})
|
||||
|
||||
function UDPDatagram:getDstPort() return self._dstPort end
|
||||
|
||||
function UDPDatagram:getSrcPort() return self._srcPort end
|
||||
|
||||
function UDPDatagram:getPayload() return self._payload end
|
||||
|
||||
function UDPDatagram:setDstPort(port)
|
||||
checkArg(1, port, "number")
|
||||
assert(port >= 0 and port <= 2 ^ 16 - 1, "Port outside valid range")
|
||||
self._dstPort = port
|
||||
return oldValue
|
||||
end
|
||||
|
||||
function UDPDatagram:setSrcPort(port)
|
||||
checkArg(1, port, "number")
|
||||
assert(port >= 0 and port <= 2 ^ 16 - 1, "Port outside valid range")
|
||||
self._srcPort = port
|
||||
---@param value? number
|
||||
---@return number
|
||||
function UDPDatagram:srcPort(value)
|
||||
checkArg(1, value, 'number', 'nil')
|
||||
local oldValue = self._srcPort
|
||||
if (value ~= nil) then
|
||||
assert(value >= 0 and value <= 2 ^ 16 - 1, "Port outside valid range")
|
||||
self._srcPort = value
|
||||
end
|
||||
return oldValue
|
||||
end
|
||||
|
||||
function UDPDatagram:setPayload(value)
|
||||
checkArg(1, value, "string")
|
||||
self._payload = value
|
||||
---@param value? string
|
||||
---@return string
|
||||
function UDPDatagram:payload(value)
|
||||
checkArg(1, value, 'string', 'nil')
|
||||
local oldValue = self._payload
|
||||
if (value ~= nil) then self._payload = value end
|
||||
return oldValue
|
||||
end
|
||||
|
||||
local PACK_FORMAT = "I2I2xxxxs"
|
||||
@@ -61,7 +67,7 @@ local PACK_FORMAT = "I2I2xxxxs"
|
||||
---Prepare the packet for the next layer
|
||||
---@return string
|
||||
function UDPDatagram:pack()
|
||||
return string.pack(PACK_FORMAT, self:getSrcPort(), self:getDstPort(), self:getPayload())
|
||||
return string.pack(PACK_FORMAT, self:srcPort(), self:dstPort(), self:payload())
|
||||
end
|
||||
|
||||
---Get a udp packet from the string
|
||||
|
@@ -1,36 +1,34 @@
|
||||
--local UDPSocket = require("network.udp.UDPSocket")
|
||||
local UDPDatagram = require("network.udp.UDPDatagram")
|
||||
local IPv4Packet = require("network.ipv4.IPv4Packet")
|
||||
local ipv4Address = require("network.ipv4.address")
|
||||
local network = require("network")
|
||||
local UDPDatagram = require("network.udp.UDPDatagram")
|
||||
local IPv4Packet = require("network.ipv4.IPv4Packet")
|
||||
local ipv4Address = require("network.ipv4.address")
|
||||
local NetworkLayer = require('network.abstract.NetworkLayer')
|
||||
local network = require("network")
|
||||
local class = require("libClass2")
|
||||
|
||||
|
||||
---@class UDPLayer : OSITransportLayer
|
||||
---@class UDPLayer : NetworkLayer
|
||||
---@field private _sockets table<number,table<number,table<number,table<number,UDPSocket>>>>
|
||||
---@field private _layer OSINetworkLayer
|
||||
---@field private _layer NetworkLayer
|
||||
---@operator call:UDPLayer
|
||||
---@overload fun(layer:IPv4Layer):UDPLayer
|
||||
local UDPLayer = {}
|
||||
local UDPLayer = class(NetworkLayer)
|
||||
UDPLayer.layerType = require("network.ipv4").PROTOCOLS.UDP
|
||||
|
||||
---@param layer IPv4Layer
|
||||
---@return UDPLayer
|
||||
setmetatable(UDPLayer, {
|
||||
---@param layer IPv4Layer
|
||||
---@return UDPLayer
|
||||
__call = function(self, layer)
|
||||
local o = {
|
||||
_sockets = {},
|
||||
_layer = layer
|
||||
}
|
||||
setmetatable(o, {__index = self})
|
||||
layer:setLayer(o) --tell the IPv4Layer that we exists
|
||||
return o
|
||||
end
|
||||
})
|
||||
function UDPLayer:new(layer)
|
||||
local o = self.parent()
|
||||
setmetatable(o, {__index = self})
|
||||
---@cast o UDPLayer
|
||||
o._sockets = {}
|
||||
o:layer(layer) --tell the IPv4Layer that we exists
|
||||
return o
|
||||
end
|
||||
|
||||
function UDPLayer:payloadHandler(from, to, payload)
|
||||
local udpPacket = UDPDatagram.unpack(payload)
|
||||
local socket = self:getSocket(to, udpPacket:getDstPort(), from, udpPacket:getSrcPort())
|
||||
local socket = self:getSocket(to, udpPacket:dstPort(), from, udpPacket:srcPort())
|
||||
if (not socket) then
|
||||
return
|
||||
end
|
||||
@@ -247,9 +245,9 @@ function UDPLayer:send(from, to, payload)
|
||||
network.router:send(IPv4Packet(from, to, payload, self.layerType))
|
||||
end
|
||||
|
||||
function UDPLayer:getAddr() return self._layer:getAddr() end
|
||||
function UDPLayer:addr() return self:layer():addr() end
|
||||
|
||||
function UDPLayer:getMTU() return self._layer:getMTU() - 8 end
|
||||
function UDPLayer:mtu() return self:layer():mtu() - 8 end
|
||||
|
||||
---add a socket to the internal list. Return false if could not be added (addrress / port already in use)
|
||||
---@private
|
||||
|
@@ -168,7 +168,7 @@ end
|
||||
---@param to number
|
||||
---@param udpPacket UDPDatagram
|
||||
function UDPSocket:payloadHandler(from, to, udpPacket)
|
||||
table.insert(self._buffer, {udpPacket:getPayload(), ipv4Address.tostring(from), udpPacket:getSrcPort()})
|
||||
table.insert(self._buffer, {udpPacket:payload(), ipv4Address.tostring(from), udpPacket:srcPort()})
|
||||
end
|
||||
|
||||
---Create and returns an unconnected UDP obeject.
|
||||
|
Binary file not shown.
@@ -255,12 +255,15 @@
|
||||
["osinetwork"] = {
|
||||
["manifestVersion"] = "1.0",
|
||||
["package"] = "osinetwork",
|
||||
["version"] = "1.0.2",
|
||||
["version"] = "2.0.0",
|
||||
["name"] = "OSI Network stack",
|
||||
["repo"] = "tree/master/network",
|
||||
["description"] = "A close to official rfc emulation of the OSI layers for OpenOS. Include Ethernet, ARP, ICMP, UDP. Also provide a luasocket libe librairy",
|
||||
["note"] = "Are provided : ping, ifup, ifdown, arp, nc, netstat. Any one of theses tools may be moved to a separate package at any time",
|
||||
["authors"] = "AR2000AR",
|
||||
["dependencies"] = {
|
||||
["libclass2"] = "oppm"
|
||||
},
|
||||
["configFiles"] = {
|
||||
"/etc/network/interfaces"
|
||||
},
|
||||
|
Binary file not shown.
@@ -269,12 +269,15 @@
|
||||
["master/network/boot/30_network.lua"] = "//boot/",
|
||||
["?master/network/etc/network/interfaces"] ="//etc/network/"
|
||||
},
|
||||
dependencies = {
|
||||
["libclass2"] = "/"
|
||||
}
|
||||
name = "OSI Network stack",
|
||||
description = "A close to official rfc emulation of the OSI layers for OpenOS. Include Ethernet, ARP, ICMP, UDP. Also provide a luasocket libe librairy",
|
||||
note = "Are provided : ping, ifup, ifdown, arp, nc, netstat. Any one of theses tools may be moved to a separate package at any time",
|
||||
authors = "AR2000AR",
|
||||
repo = "tree/master/network",
|
||||
version = "1.0.2"
|
||||
version = "2.0.0"
|
||||
},
|
||||
["dns_common"] = {
|
||||
files = {
|
||||
|
Reference in New Issue
Block a user