Advertisement
ladyDia

Networked Router

Nov 14th, 2024 (edited)
120
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 12.94 KB | None | 0 0
  1. --Variables
  2. local networkDeviceSide = "left" --Change this to where network device is
  3. deviceType = "router"
  4. ipAddress = {1,1,0}
  5. routerList = {}
  6. DHCP = {}
  7. actionQueue = {}
  8. dataQueue = {}
  9. callbackList = {}
  10. localFunctions = {}
  11. lastMeasuredTime = 0
  12. broadcastInterval = 10 --How many seconds between broadcasts
  13. version = "1.1"
  14.  
  15. --[[
  16.     All data packets have a set structure made of four sections
  17.     First Section - IP Address of target system
  18.     Second Section - IP Address of sending system
  19.     Third Section - Type of packet being sent (what protocol does packet follow)
  20.     Fourth Section - The main data the packet is transporting
  21.  
  22.     For testing, the IP address will be the same as the device ID.
  23.     In the future this will be changed to allow for proper routing and
  24.     security measures.
  25.  
  26.     The protocol the packet follows is a string in all caps
  27.     (CDP,ERP,DRP,UPP,etc) to allow for universal understanding (and style)
  28.  
  29.     An IP address of 0 for the target system means that the packet is for
  30.     the router to work with. Trying to assign a different device this IP will fail
  31.     as the router will intercept all packets with that IP.
  32. --]]
  33.  
  34. --[[
  35.     Devices are found through the Computer Discovery Protocol and are
  36.     stored with three sections of data
  37.     First section - IP address of device
  38.     Second section - ID of the device
  39.     Third Section - Type of device
  40.     The IP address of the device is the index where the device appears
  41.     in the known device array. The ID of the device is the actual ID of the
  42.     device, this is used to route messages to the device. The type is a
  43.     string that defines what kind of device is on the network, this is used
  44.     for the Device Request Protocol to find devices for different kinds of actions.
  45. --]]
  46.  
  47. --[[
  48.     The actionQueue stores a list of actions that will be run while the router
  49.     is waiting for a message. This can be done via parallel waitForAny, with one
  50.     function listening for new messages and the other running the various functions in
  51.     the actionQueue. Any data the method might need to use is held in the dataQueue.
  52.     When a method from the actionQueue is completed, it is removed from
  53.     queue along with the dataQueue entry and the next method is executed.
  54. --]]
  55.  
  56. local function sendPacket (
  57.         targetIP, --Array
  58.         sourceIP, --Array
  59.         protocol, --String
  60.         data --Any
  61. )
  62.     --[[
  63.         This function sends a packet to an IP address in the network.
  64.         Each packet needs to follow the rules of packet construction.
  65.         If the target IP is 0 then the packet will be sent to the default router.
  66.         If the sending IP is -1 then that means the IP hasn't been set yet
  67.         and will need to be to recieve packets from devices other than the router.
  68.     --]]
  69.     --Checking if IP is in subnet
  70.     if not ipAddress[2] == targetIP[2] then goto skip end
  71.     --Checking if DHCP has any data in it
  72.     if not DHCP[targetIP[3]] then goto skip end
  73.     --Checking if packet components have the right data types, otherwise skip all code
  74.     if not (type(targetIP) == "table") or not (type(sourceIP) == "table") or not (type(protocol) == "string") then
  75.         print("Improperly formatted packet")
  76.         goto skip
  77.     end
  78.     --Packet construction
  79.     local packet = {
  80.         targetIP,
  81.         sourceIP,
  82.         protocol,
  83.         data
  84.     }
  85.     --Sending packet
  86.     if targetIP[2] == ipAddress[2] then
  87.         -- if target ip is in subnet then send packet directly
  88.         print(DHCP[targetIP[3]])
  89.         print(targetIP[1].."."..targetIP[2].."."..targetIP[3] .. " " .. sourceIP[1].."."..sourceIP[2].."."..sourceIP[3] .. " " .. protocol .. " " .. type(data))
  90.         rednet.send(DHCP[targetIP[3]][2],packet)
  91.     elseif routerList[targetIP[2]] then
  92.         -- if router with subnet is known then send along known route
  93.         print(routerList[targetIP[2]])
  94.         print(targetIP[1].."."..targetIP[2].."."..targetIP[3] .. " " .. sourceIP[1].."."..sourceIP[2].."."..sourceIP[3] .. " " .. protocol .. " " .. type(data))
  95.         rednet.send(routerList[targetIP[2]][2],packet)
  96.     else
  97.         -- if subnet is unknown
  98.         print("Subnet is not reachable")
  99.     end
  100.     ::skip::
  101. end
  102.  
  103. local function broadcastRDP(packet)
  104.    --Broadcasts RDP packets to all connected devices, trying to find other routers
  105.    --Sends out the router list along with for reference
  106.     rednet.broadcast({{-1,0,0},ipAddress,"RDP",{os.getComputerID(),routerList}})
  107. end
  108.  
  109. local function broadcastCDP(packet)
  110.    --Broadcasts CDP packets to all connected devices, trying to find unassigned devices
  111.     rednet.broadcast({{-1,-1,-1},ipAddress,"CDP",""})
  112. end
  113.  
  114. local function responseCDP (packet)
  115.     --[[
  116.     Computer Discovery Protocol
  117.     Used by a router to discover devices on the network then assign them IP addresses
  118.     and set itself as the device's default router. Devices already with an IP and
  119.     default router do not respond to CDP packets to avoid confusion on the side of
  120.     the router.
  121.     --]]
  122.     --Checks if device is in registry
  123.     for index = 1, #DHCP, 1 do
  124.         if DHCP[index][2] == packet[4] then
  125.             sendPacket({ipAddress[1],ipAddress[2],DHCP[index][1]},ipAddress,"IP",{ipAddress[1],ipAddress[2],DHCP[index][1]})
  126.             goto continue
  127.         end
  128.     end
  129.     --Creates a device registry to be added to DHCP
  130.     local deviceRegistry = {table.getn(DHCP)+1,packet[4],""}
  131.     table.insert(DHCP,deviceRegistry)
  132.     --Sending IP packet to the device with its new IP address
  133.     sendPacket({ipAddress[1],ipAddress[2],deviceRegistry[1]},ipAddress,"IP",{ipAddress[1],ipAddress[2],deviceRegistry[1]})
  134.     ::continue::
  135. end
  136.  
  137.  local function responseRDP (packet)
  138.     --[[
  139.     Router Discovery Protocol
  140.     Used by a router to discover other routers and build up a internetwork routing table.
  141.     After recieving a routing table, start adding it to router routing table
  142.     Routing table info:
  143.     1 - IP of router
  144.     2 - ID of next hop
  145.     3 - IP of next hop? (for future tracert)
  146.     4 - Number of hops to IP (To find shortest route)
  147.    
  148.     Routers will not have themselves on their own routing tables
  149.     --]]
  150.     for index,data in pairs(packet[4][2]) do
  151.         print(index,data)
  152.         --Find all of the subnet IDs and see if we can directly connect or have to route it
  153.         if data[1] == ipAddress then
  154.             --This case prevents routers from having themselves on their routing table
  155.         elseif not(routerList[index]) then
  156.             --Add routing table entry to list with next hop being the router packet was recieved from
  157.             routerList[index] = {data[1],packet[4][1],packet[2],data[4]+1}
  158.         elseif routerList[index][4] < data[4]+1 then
  159.             --If route is shorter then replace routing
  160.             routerList[index] = {data[1],packet[4][1],packet[2],data[4]+1}
  161.         end
  162.     end
  163.     routerList[packet[2][2]] = {packet[2],packet[4][1],packet[2],0}
  164. end
  165.  
  166. local function responseERP (packet)
  167.     --[[
  168.         Echo Request Protocol is used to see if an IP address is responding.
  169.         Sending an ERP packet will cause the device to send a return packet back to the
  170.         source device. The first ERP packet must contain the word
  171.     --]]
  172.     if packet[4] == "ping" then
  173.         sendPacket(packet[2],0,"ERP","pong")
  174.     end
  175. end
  176.  
  177. local function responseDRP (packet)
  178.     --[[
  179.         Device Request Protocol is used by devices to find the IP of another
  180.         device of a specified kind, usually for sending data to that device to
  181.         process. This will send an array with all of the IP addresses of devices that
  182.         match the given type.
  183.     --]]
  184.     local tempDeviceList = {}
  185.     --If data is not string then end
  186.     if type(packet[4]) ~= "string" then goto continue end
  187.     for index = 1, #DHCP, 1 do
  188.         if DHCP[index][3] == packet[4] or packet[4] == "*" then
  189.             table.insert(
  190.                 tempDeviceList,
  191.                 {ipAddress[1].."."..ipAddress[2].."."..DHCP[index][1],DHCP[index][3]}
  192.             )
  193.         end
  194.     end
  195.     sendPacket(packet[2],ipAddress,"DRP",tempDeviceList)
  196.     ::continue::
  197. end
  198.  
  199. local function responseUPP (packet)
  200.     --Unknown Packet Protocol
  201. end
  202.  
  203. local function responseIP (packet)
  204.     --[[
  205.     Internet Protocol
  206.     Used by router to give a device an IP address. Will only be accepted if the
  207.     router is the default router the device knows. If the default router is
  208.     unassigned then the IP packet is dropped. The data on the packet should
  209.     be a number.
  210.     --]]
  211.     --Checks if IP is within range
  212.     if packet[2][3] > table.getn(DHCP) or packet[2][3] < 1 then goto skip end
  213.     --Adds device description to known devices
  214.     DHCP[packet[2][3]][3] = packet[4]
  215.     ::skip::
  216. end
  217.  
  218. local function responseARP (packet)
  219.     --Address Resolution Protocol
  220.     --[[
  221.         The Address Resolution Protocol (most likely used wrong here) is used when
  222.         a packet is to be recieved, routed, or sent to an unknown IP address. Normally
  223.         this is broadcasted to all devices on the network to find the IP and MAC
  224.         address of a device. The router on the network will handle broadcasting
  225.         and searching instead of the device. The router will first look at
  226.         it's DHCP to see if it knows the IP first, then will start broadcasting to try and
  227.         find it.
  228.     --]]
  229.     --Searching DHCP for the IP address
  230.     for i=1,#DHCP,1 do
  231.         --Searching DHCP for the IP address
  232.         if DHCP[i][1] == packet[1][3] then
  233.             --
  234.         end
  235.     end
  236. end
  237.    
  238. local function lookupDHCP (IP)
  239.     --Domain Name System lookup
  240.     --[[
  241.         This is used to find an IP address in the DHCP table. If the item is not
  242.         found then an ARP broadcast is sent out to try and find the device with
  243.         the IP address.
  244.     --]]
  245.     --Searching DHCP for the IP address
  246.     for i=1,#DHCP,1 do
  247.         --Searching DHCP for the IP address
  248.         if DHCP[i][1] == IP then
  249.             return true
  250.         end
  251.     end
  252.     return false
  253. end
  254.  
  255. local function responseDP (packet)
  256.     --Data  Packet
  257. end
  258.  
  259. local function responseAP (packet)
  260.     --Acknowledgement Packet
  261. end
  262.  
  263. local function routePacket (packet)
  264.     --Send packet along to another device
  265.     sendPacket(packet[1],packet[2],packet[3],packet[4])
  266. end
  267.  
  268. local function queueHandler()
  269.     --Execute's functions in the actionQueue
  270.     if table.getn(actionQueue) > 0 then
  271.         --If there are actions in the queue then complete them
  272.         actionQueue[1](dataQueue[1])
  273.         --Remove function and data from queues
  274.         table.remove(actionQueue,1)
  275.         table.remove(dataQueue,1)
  276.     end
  277. end
  278.  
  279. local function messageListener()
  280.     --Listens for messages to add to the actionQueue
  281.     local message = {rednet.receive(1)}
  282.     local packet = message[2]
  283.     --Seeing if packet is a table
  284.     if not(type(packet) == "table") then goto skip end
  285.     --Checking if packet is formatted correctly
  286.     if not (table.getn(packet) == 4) then goto skip end
  287.     --print("Target IP: "..packet[1])
  288.     print("response"..packet[3])
  289.     if not ((packet[1][2] == 0 or packet[1][2] == ipAddress[2]) and packet[1][3] == 0) then
  290.         --Route packet to target device
  291.         print("Routing packet")
  292.         table.insert(actionQueue,routePacket)
  293.         table.insert(dataQueue,packet)
  294.     --Checks if a response protocol exists
  295.     elseif localFunctions["response"..packet[3]] then
  296.         --If protocol exists
  297.         print("Running response "..packet[3])
  298.         table.insert(actionQueue,localFunctions["response"..packet[3]])
  299.         table.insert(dataQueue,packet)
  300.     else  
  301.         --Send UPP packet to source device if protocol is unknown
  302.         print("Unknown")
  303.         sendPacket(packet[1],0,"UPP","Unknown Packet Type: "..packet[3])
  304.     end
  305.     ::skip::
  306. end
  307.  
  308. local function mainLoop()
  309.     --Getting the first time
  310.     lastMeasuredTime = os.clock()
  311.     --Runs a parallel for the responseLoop and whatever other function is needed
  312.     while true do
  313.         --run messageListener
  314.         messageListener()
  315.         --run queueHandler
  316.         queueHandler()
  317.         --Check to see if enough time has elapsed to run broadcastCDP
  318.         if os.clock()-lastMeasuredTime > broadcastInterval then
  319.             --If enough time has passed, then
  320.             lastMeasuredTime = os.clock()
  321.             table.insert(actionQueue,broadcastCDP)
  322.             table.insert(dataQueue,{})
  323.             table.insert(actionQueue,broadcastRDP)
  324.             table.insert(dataQueue,{})
  325.         end
  326.     end
  327. end
  328.  
  329. --Finding all of the local functions and storing them
  330. index = 1
  331. while true do
  332.     key, data = debug.getlocal(1,index)
  333.     if not key then break end
  334.     --print(key)
  335.     if type(data) == "function" then
  336.         if debug.getinfo(data, "S").what == "Lua" then
  337.             localFunctions[key] = data
  338.         end
  339.     end
  340.     index = index + 1
  341. end
  342.  
  343. --Setting subnet (this needs to be done via config file in future)
  344. print("What is the router's subnet")
  345. ipAddress[2] = tonumber(read())
  346.  
  347. --Turning on the network capabilities of the device
  348. peripheralNames = peripheral.getNames()
  349. for i = 1, #peripheralNames, 1 do
  350.     if peripheral.hasType(peripheralNames[i],"modem") then
  351.         rednet.open(peripheralNames[i])
  352.     end
  353. end
  354. --Init mainLoop()
  355. print("Router boot")
  356. print("Version: v"..version)
  357. print("Running mainLoop")
  358. mainLoop()
  359.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement