From b08c897cf8c6e36a04c74e81a22da6391f10db1a Mon Sep 17 00:00:00 2001 From: 20kdc Date: Sat, 2 Sep 2017 14:51:34 +0100 Subject: [PATCH] Change hierarchi char from '<' to '^', fix some issues This is kind of untested. I've asked Izaya to test it... --- oc/hierarchi.lua | 6 +++--- oc/tcpdial.lua | 13 ++++++++++--- protocol.1 | 20 +++++++++++++++----- protocol.2 | 43 +++++++++++++++++++++++++++++++++++++++++++ tcprouter.lua | 38 +++++++++++++++++++++++--------------- 5 files changed, 94 insertions(+), 26 deletions(-) diff --git a/oc/hierarchi.lua b/oc/hierarchi.lua index 9d5291f..b17fe1c 100644 --- a/oc/hierarchi.lua +++ b/oc/hierarchi.lua @@ -71,9 +71,9 @@ processFrom = function (incoming, from) if from:sub(1, netname:len()) == netname then return end - return "<" .. from + return "^" .. from else - if from:sub(1, 1) == "<" then + if from:sub(1, 1) == "^" then return end return netname .. from @@ -86,7 +86,7 @@ processTo = function (incoming, nto) end return nto:sub(netname:len() + 1) else - if nto:sub(1, 1) ~= "<" then + if nto:sub(1, 1) ~= "^" then return end return nto:sub(2) diff --git a/oc/tcpdial.lua b/oc/tcpdial.lua index 591aeff..29d5cad 100644 --- a/oc/tcpdial.lua +++ b/oc/tcpdial.lua @@ -28,8 +28,8 @@ local function verify(d) local hops, src, dst, data = cdlib.decode(d) if not data then return end -- Just a bit of filtering - if dst:sub(1, 1) ~= "<" then return end - if d:len() > 2021 then return end + if dst:sub(1, 1) ~= "^" then return end + if d:len() > 2022 then return end return true end @@ -55,10 +55,17 @@ local function readerRoutine() for i = 1, sz do dat = dat .. readByte() end - md.broadcast(4957, "copper", dat) + if dat ~= "" then + md.broadcast(4957, "copper", dat) + end end end +event.timer(10, function () + tcp:write("\x00\x00") + tcp:flush() +end, math.huge) + local primary = coroutine.create(readerRoutine) while true do local et, _, _, p, _, m, d = event.pull(0.1) diff --git a/protocol.1 b/protocol.1 index fb8db4a..e306e0c 100644 --- a/protocol.1 +++ b/protocol.1 @@ -3,14 +3,17 @@ Copper Protocol :: Hierarchial Gateways "Hierarchial Gateways" are a system for ISP-like bodies to prevent their users from causing havoc. +Note that this is not the only possible system, and implementors can do as they wish regarding addressing. +(However, for this reason, applications should allow specification of a prefix to all "internet"-level addresses.) + They are simply base low-level Copper nodes with two interfaces and the following rules: For the FROM address: If it's on the parent side, reject if it's prefixed with hostname .. "/", - otherwise prefix it with "<". -If it's on the child side, reject if it's prefixed with "<", + otherwise prefix it with "^". +If it's on the child side, reject if it's prefixed with "^", otherwise prefix it with hostname .. "/". For the TO address: @@ -18,11 +21,11 @@ If it's on the child side, reject if it's prefixed with "<", If it's on the parent side, reject unless prefixed with hostname .. "/", otherwise remove that. (Optionally, if the name is "*", bypass this rule completely. - This is not recommended, though, as this allows sending a "complete broadcast packet" via "[some amount of <]*".) + This is not recommended, though, as this allows sending a "complete broadcast packet" via "[some amount of ^]*".) -If it's on the child side, reject unless prefixed with "<", +If it's on the child side, reject unless prefixed with "^", otherwise remove that. - (Optionally, if the name is "<*", reject anyway. + (Optionally, if the name is "^*", reject anyway. This is a measure which you may or may not wish to take - if the above 'complete broadcast' possibility has been implemented, then it is a must.) For the packet's general routing: @@ -54,3 +57,10 @@ Possible uses of hierarchial gateways: following the same protocol as everything else in Copper, unlike certain competitors 2. ISPs within servers, perhaps those using the hubs + + +Errata: + +Previous versions of the spec used "<" - this was not very usable from most shells on most operating systems. +It has been replaced with "^". +It was not explicitly specified that this was not the only way of doing things - this has been corrected. diff --git a/protocol.2 b/protocol.2 index dea8b81..a4e40b5 100644 --- a/protocol.2 +++ b/protocol.2 @@ -37,6 +37,10 @@ Combined with correctly-forgetting packet caches, this should prevent The final header byte is the actual indicator of what is in the packet. +There are two sections of packet types: + +-- Basic Datagrams + 0x00 indicates that this is an unreliable packet. 0x01 indicates that this is a reliable packet, expecting acknowledgement. 0x02 indicates that this is an acknowledgement for a reliable packet. @@ -59,7 +63,46 @@ Bob receives it successfully on the second time, and sends back a Alice receives the response and does not send a third packet. +-- Connections + +0x03 : Request Connection Start +This is similar to an 0x01 reliable packet expecting acknowledgement in how it is to be sent, + including the usual packetID randomization, and multiple attempts. +However, the data must be two bytes, and these first two bytes must be the new port number. +The port numbers that ought to be used for active connections are 0x8000 to 0xFFFF. +The response must be on that port number. + +0x04 : Request Connection Start / Response +This is sent on the port given by a Request Connection Start to accept the connection. +It has the same format as 0x03 (new port number). +This establishes the connection, and data transmission can begin. +Connections die if no packets have been received by either side for at least 60 seconds. +It is recommended the connection "ping" every 15 seconds. + +- The following packets have the current sequence number as their packetID. + This variable is per-connection-side, starts at 0, + and is incremented after a Connection Data packet + sent by that side. + +0x05 : Connection Data +If 0 bytes, this serves as a ping (not a packet) +The sender's sequence number is incremented by 1 before sending. +The reply is a Connection Acknowledgement with the same sequence number (but no data) + +0x06 : Connection Resequencing +Specifies that the next data packet's sequence number is going to be 0. +(The packet has the current sequence number, to put it in context.) +It is this in particular which requires connections keep: + 1. A map of sequence number -> data (flushed when data is read) + 2. A list of sequence numbers to read. +When ready, a connection data acknowledgement should be given with sequence number 0. + +0x07 : Connection Data Acknowledgement +Sent from the target of 0x05/0x06 to the sender. For 0x05, has the sequence number of the associated data. + ERRATA: When this document was originally posted, the relib header was described as 6 bytes despite a total of 7 bytes being specified. Thanks to @skyem123 for finding the issue. + +The "Connections" section is a recent extension (August 28th 2017) diff --git a/tcprouter.lua b/tcprouter.lua index 5248921..c27c8dc 100644 --- a/tcprouter.lua +++ b/tcprouter.lua @@ -35,14 +35,17 @@ local function getpacket(s) local l = getbyte(s) if not l then error("framing bad") end local sz = string.byte(l) + (string.byte(h) * 256) - if sz > 2021 then error("packet too large") end + if sz > 2022 then error("packet too large") end local data = "" for i = 1, sz do local dbt = getbyte(s) if not dbt then error("terminated early") end data = data .. dbt end - return cdlib.decode(data) + if data == "" then + return false + end + return true, cdlib.decode(data) end local function checkLen(name) @@ -52,10 +55,10 @@ local function checkLen(name) end local function translateSend(hops, src, dst, data, srname, tgsock, tgname) - if src:sub(1, 1) == "<" then return end - if dst:sub(1, tgname:len() + 2) ~= "<" .. tgname .. "/" then return end + if src:sub(1, 1) == "^" then return end + if dst:sub(1, tgname:len() + 2) ~= "^" .. tgname .. "/" then return end -- Ok, all rejection rules have been handled - src = "<" .. srname .. "/" .. src + src = "^" .. srname .. "/" .. src dst = dst:sub(tgname:len() + 3) src, dst = checkLen(src), checkLen(dst) if src and dst then @@ -82,19 +85,24 @@ local function messageroutine(tbl) print("confirmed name " .. name) tbl[3] = name while true do - local hops, src, dst, data = getpacket(tbl[2]) - if not data then - error("Bad Copper packet") - end - print("packet", src, dst) - if hops ~= 255 then - for _, v in ipairs(sockets) do - if v[3] then - if v ~= tbl then - translateSend(hops + 1, src, dst, data, name, v[2], v[3]) + local rcv, hops, src, dst, data = getpacket(tbl[2]) + if rcv then + if not data then + error("Bad Copper packet") + end + print("packet", src, dst) + if hops ~= 255 then + for _, v in ipairs(sockets) do + if v[3] then + if v ~= tbl then + translateSend(hops + 1, src, dst, data, name, v[2], v[3]) + end end end end + else + -- Ping response + tbl[2]:send("\x00\x00") end end end