1
0
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:
2023-05-06 16:42:03 +02:00
parent 80e4b3cfbd
commit 6ab5f687cf
28 changed files with 757 additions and 796 deletions

View File

@@ -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)

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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()

View File

@@ -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

View File

@@ -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 {

View File

@@ -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

View 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

View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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))

View File

@@ -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
--=============================================================================

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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
}

View File

@@ -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

View File

@@ -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

View File

@@ -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.

View File

@@ -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.

View File

@@ -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 = {