Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --Variables
- local networkDeviceSide = "left" --Change this to where network device is
- deviceType = "router"
- ipAddress = {1,1,0}
- routerList = {}
- DHCP = {}
- actionQueue = {}
- dataQueue = {}
- callbackList = {}
- localFunctions = {}
- lastMeasuredTime = 0
- broadcastInterval = 10 --How many seconds between broadcasts
- version = "1.1"
- --[[
- All data packets have a set structure made of four sections
- First Section - IP Address of target system
- Second Section - IP Address of sending system
- Third Section - Type of packet being sent (what protocol does packet follow)
- Fourth Section - The main data the packet is transporting
- For testing, the IP address will be the same as the device ID.
- In the future this will be changed to allow for proper routing and
- security measures.
- The protocol the packet follows is a string in all caps
- (CDP,ERP,DRP,UPP,etc) to allow for universal understanding (and style)
- An IP address of 0 for the target system means that the packet is for
- the router to work with. Trying to assign a different device this IP will fail
- as the router will intercept all packets with that IP.
- --]]
- --[[
- Devices are found through the Computer Discovery Protocol and are
- stored with three sections of data
- First section - IP address of device
- Second section - ID of the device
- Third Section - Type of device
- The IP address of the device is the index where the device appears
- in the known device array. The ID of the device is the actual ID of the
- device, this is used to route messages to the device. The type is a
- string that defines what kind of device is on the network, this is used
- for the Device Request Protocol to find devices for different kinds of actions.
- --]]
- --[[
- The actionQueue stores a list of actions that will be run while the router
- is waiting for a message. This can be done via parallel waitForAny, with one
- function listening for new messages and the other running the various functions in
- the actionQueue. Any data the method might need to use is held in the dataQueue.
- When a method from the actionQueue is completed, it is removed from
- queue along with the dataQueue entry and the next method is executed.
- --]]
- local function sendPacket (
- targetIP, --Array
- sourceIP, --Array
- protocol, --String
- data --Any
- )
- --[[
- This function sends a packet to an IP address in the network.
- Each packet needs to follow the rules of packet construction.
- If the target IP is 0 then the packet will be sent to the default router.
- If the sending IP is -1 then that means the IP hasn't been set yet
- and will need to be to recieve packets from devices other than the router.
- --]]
- --Checking if IP is in subnet
- if not ipAddress[2] == targetIP[2] then goto skip end
- --Checking if DHCP has any data in it
- if not DHCP[targetIP[3]] then goto skip end
- --Checking if packet components have the right data types, otherwise skip all code
- if not (type(targetIP) == "table") or not (type(sourceIP) == "table") or not (type(protocol) == "string") then
- print("Improperly formatted packet")
- goto skip
- end
- --Packet construction
- local packet = {
- targetIP,
- sourceIP,
- protocol,
- data
- }
- --Sending packet
- if targetIP[2] == ipAddress[2] then
- -- if target ip is in subnet then send packet directly
- print(DHCP[targetIP[3]])
- print(targetIP[1].."."..targetIP[2].."."..targetIP[3] .. " " .. sourceIP[1].."."..sourceIP[2].."."..sourceIP[3] .. " " .. protocol .. " " .. type(data))
- rednet.send(DHCP[targetIP[3]][2],packet)
- elseif routerList[targetIP[2]] then
- -- if router with subnet is known then send along known route
- print(routerList[targetIP[2]])
- print(targetIP[1].."."..targetIP[2].."."..targetIP[3] .. " " .. sourceIP[1].."."..sourceIP[2].."."..sourceIP[3] .. " " .. protocol .. " " .. type(data))
- rednet.send(routerList[targetIP[2]][2],packet)
- else
- -- if subnet is unknown
- print("Subnet is not reachable")
- end
- ::skip::
- end
- local function broadcastRDP(packet)
- --Broadcasts RDP packets to all connected devices, trying to find other routers
- --Sends out the router list along with for reference
- rednet.broadcast({{-1,0,0},ipAddress,"RDP",{os.getComputerID(),routerList}})
- end
- local function broadcastCDP(packet)
- --Broadcasts CDP packets to all connected devices, trying to find unassigned devices
- rednet.broadcast({{-1,-1,-1},ipAddress,"CDP",""})
- end
- local function responseCDP (packet)
- --[[
- Computer Discovery Protocol
- Used by a router to discover devices on the network then assign them IP addresses
- and set itself as the device's default router. Devices already with an IP and
- default router do not respond to CDP packets to avoid confusion on the side of
- the router.
- --]]
- --Checks if device is in registry
- for index = 1, #DHCP, 1 do
- if DHCP[index][2] == packet[4] then
- sendPacket({ipAddress[1],ipAddress[2],DHCP[index][1]},ipAddress,"IP",{ipAddress[1],ipAddress[2],DHCP[index][1]})
- goto continue
- end
- end
- --Creates a device registry to be added to DHCP
- local deviceRegistry = {table.getn(DHCP)+1,packet[4],""}
- table.insert(DHCP,deviceRegistry)
- --Sending IP packet to the device with its new IP address
- sendPacket({ipAddress[1],ipAddress[2],deviceRegistry[1]},ipAddress,"IP",{ipAddress[1],ipAddress[2],deviceRegistry[1]})
- ::continue::
- end
- local function responseRDP (packet)
- --[[
- Router Discovery Protocol
- Used by a router to discover other routers and build up a internetwork routing table.
- After recieving a routing table, start adding it to router routing table
- Routing table info:
- 1 - IP of router
- 2 - ID of next hop
- 3 - IP of next hop? (for future tracert)
- 4 - Number of hops to IP (To find shortest route)
- Routers will not have themselves on their own routing tables
- --]]
- for index,data in pairs(packet[4][2]) do
- print(index,data)
- --Find all of the subnet IDs and see if we can directly connect or have to route it
- if data[1] == ipAddress then
- --This case prevents routers from having themselves on their routing table
- elseif not(routerList[index]) then
- --Add routing table entry to list with next hop being the router packet was recieved from
- routerList[index] = {data[1],packet[4][1],packet[2],data[4]+1}
- elseif routerList[index][4] < data[4]+1 then
- --If route is shorter then replace routing
- routerList[index] = {data[1],packet[4][1],packet[2],data[4]+1}
- end
- end
- routerList[packet[2][2]] = {packet[2],packet[4][1],packet[2],0}
- end
- local function responseERP (packet)
- --[[
- Echo Request Protocol is used to see if an IP address is responding.
- Sending an ERP packet will cause the device to send a return packet back to the
- source device. The first ERP packet must contain the word
- --]]
- if packet[4] == "ping" then
- sendPacket(packet[2],0,"ERP","pong")
- end
- end
- local function responseDRP (packet)
- --[[
- Device Request Protocol is used by devices to find the IP of another
- device of a specified kind, usually for sending data to that device to
- process. This will send an array with all of the IP addresses of devices that
- match the given type.
- --]]
- local tempDeviceList = {}
- --If data is not string then end
- if type(packet[4]) ~= "string" then goto continue end
- for index = 1, #DHCP, 1 do
- if DHCP[index][3] == packet[4] or packet[4] == "*" then
- table.insert(
- tempDeviceList,
- {ipAddress[1].."."..ipAddress[2].."."..DHCP[index][1],DHCP[index][3]}
- )
- end
- end
- sendPacket(packet[2],ipAddress,"DRP",tempDeviceList)
- ::continue::
- end
- local function responseUPP (packet)
- --Unknown Packet Protocol
- end
- local function responseIP (packet)
- --[[
- Internet Protocol
- Used by router to give a device an IP address. Will only be accepted if the
- router is the default router the device knows. If the default router is
- unassigned then the IP packet is dropped. The data on the packet should
- be a number.
- --]]
- --Checks if IP is within range
- if packet[2][3] > table.getn(DHCP) or packet[2][3] < 1 then goto skip end
- --Adds device description to known devices
- DHCP[packet[2][3]][3] = packet[4]
- ::skip::
- end
- local function responseARP (packet)
- --Address Resolution Protocol
- --[[
- The Address Resolution Protocol (most likely used wrong here) is used when
- a packet is to be recieved, routed, or sent to an unknown IP address. Normally
- this is broadcasted to all devices on the network to find the IP and MAC
- address of a device. The router on the network will handle broadcasting
- and searching instead of the device. The router will first look at
- it's DHCP to see if it knows the IP first, then will start broadcasting to try and
- find it.
- --]]
- --Searching DHCP for the IP address
- for i=1,#DHCP,1 do
- --Searching DHCP for the IP address
- if DHCP[i][1] == packet[1][3] then
- --
- end
- end
- end
- local function lookupDHCP (IP)
- --Domain Name System lookup
- --[[
- This is used to find an IP address in the DHCP table. If the item is not
- found then an ARP broadcast is sent out to try and find the device with
- the IP address.
- --]]
- --Searching DHCP for the IP address
- for i=1,#DHCP,1 do
- --Searching DHCP for the IP address
- if DHCP[i][1] == IP then
- return true
- end
- end
- return false
- end
- local function responseDP (packet)
- --Data Packet
- end
- local function responseAP (packet)
- --Acknowledgement Packet
- end
- local function routePacket (packet)
- --Send packet along to another device
- sendPacket(packet[1],packet[2],packet[3],packet[4])
- end
- local function queueHandler()
- --Execute's functions in the actionQueue
- if table.getn(actionQueue) > 0 then
- --If there are actions in the queue then complete them
- actionQueue[1](dataQueue[1])
- --Remove function and data from queues
- table.remove(actionQueue,1)
- table.remove(dataQueue,1)
- end
- end
- local function messageListener()
- --Listens for messages to add to the actionQueue
- local message = {rednet.receive(1)}
- local packet = message[2]
- --Seeing if packet is a table
- if not(type(packet) == "table") then goto skip end
- --Checking if packet is formatted correctly
- if not (table.getn(packet) == 4) then goto skip end
- --print("Target IP: "..packet[1])
- print("response"..packet[3])
- if not ((packet[1][2] == 0 or packet[1][2] == ipAddress[2]) and packet[1][3] == 0) then
- --Route packet to target device
- print("Routing packet")
- table.insert(actionQueue,routePacket)
- table.insert(dataQueue,packet)
- --Checks if a response protocol exists
- elseif localFunctions["response"..packet[3]] then
- --If protocol exists
- print("Running response "..packet[3])
- table.insert(actionQueue,localFunctions["response"..packet[3]])
- table.insert(dataQueue,packet)
- else
- --Send UPP packet to source device if protocol is unknown
- print("Unknown")
- sendPacket(packet[1],0,"UPP","Unknown Packet Type: "..packet[3])
- end
- ::skip::
- end
- local function mainLoop()
- --Getting the first time
- lastMeasuredTime = os.clock()
- --Runs a parallel for the responseLoop and whatever other function is needed
- while true do
- --run messageListener
- messageListener()
- --run queueHandler
- queueHandler()
- --Check to see if enough time has elapsed to run broadcastCDP
- if os.clock()-lastMeasuredTime > broadcastInterval then
- --If enough time has passed, then
- lastMeasuredTime = os.clock()
- table.insert(actionQueue,broadcastCDP)
- table.insert(dataQueue,{})
- table.insert(actionQueue,broadcastRDP)
- table.insert(dataQueue,{})
- end
- end
- end
- --Finding all of the local functions and storing them
- index = 1
- while true do
- key, data = debug.getlocal(1,index)
- if not key then break end
- --print(key)
- if type(data) == "function" then
- if debug.getinfo(data, "S").what == "Lua" then
- localFunctions[key] = data
- end
- end
- index = index + 1
- end
- --Setting subnet (this needs to be done via config file in future)
- print("What is the router's subnet")
- ipAddress[2] = tonumber(read())
- --Turning on the network capabilities of the device
- peripheralNames = peripheral.getNames()
- for i = 1, #peripheralNames, 1 do
- if peripheral.hasType(peripheralNames[i],"modem") then
- rednet.open(peripheralNames[i])
- end
- end
- --Init mainLoop()
- print("Router boot")
- print("Version: v"..version)
- print("Running mainLoop")
- mainLoop()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement