What is VerliLinkerVerliLinker is a Lua script written for
Verlihub, that allows different hubs to be linked into one consistent network. The work is done using LuaSockets library in non-blocking mode. That means this script will NOT block Verlihub while executing network operations, like listen(), accept(), connect(), etc.
Consider the following image:

Each hub will display all the users on the network in its nicklist and users that are logged on the network via another hub will be shown with a prefix of that hub, before their nick (ie.
[A]nick).
The ideaThe idea behind this is very simple. Each hub can connect to any number of other hubs, via
hublink connections, so it is even possible to join 2 existing networks, linked with VerliLinker, into a bigger network. The only thing that can cause a trouble is a loop in a network (a loop is any closed circuit between two hubs in the network). VerliLinker has got an anti-loop protection, so all admins will be aware of the loop, but you should try to always avoid it by planning your network more carefully.
The implementationEach hub is listening on specific ports in order to establish links with another hubs. Each listening port is used for 1 remote hub only, for security reasons. For each new hub you want to link with your hub, you need to open a new listening port, with
!links command. So, if you want to link your hubs with 3 more hubs, you need to create 3 links, using 3 different listen_ports, with command
!links add.
listen_port is used as a security measure. Each link has a different listen_port assigned. Why? Whenever a remote computer tries to connect to that listen_port, hub only needs to check if the remote ip address is the one that is allowed to connect to that port. dns lookup for the remote "
host" field of that link, should return an IP address, which can be compared to the connecting ip address. That way the remote hub doesn't need to have a static ip address. This way we are certain that there will be no brute force attacks in order to get unauthorized access into the network.
To connect to another hub, in order to establish a hublink, you can use
!links connect. If both you and another hub's admin try to connect to each other's hubs (to establish that hublink), one of those connections will be dropped and another will succeed (no point of having 2 tcp connections for 1 thing).
You can type
!links, after you load the lua script, for more info on the syntax.
AuthenticationAfter a successful tcp connection between 2 hubs, a simple authentication protocol is used, for example:
S | C
> $AuthRequest 89347589376|
< $AuthReply F47E4C117101B42BCCE1A662119157E5|
> $AuthOK|
For the sake of simplicity, the hub that accepted the tcp connection (a server-side hub) will be named "
Server" and another hub, that initiated tcp connection, will be named "
Client",
S and
C respectively.
So, the Server will first send the
$AuthRequest command, followed by a random string parameter (parameter cannot contain spaces). Client replies to this request with
$AuthReply followed by an md5 hash. Hash is created using random string from
$AuthRequest command and the password, associated with this hub link (password can be set when adding new link with
!links add):
hash = md5(link['password'] + authreq_param)
This is used to avoid sending plain passwords over insecure internet.
If authentication fails, Server closes connection with simple error message, otherwise,
$AuthOK is sent as a reply and now hubs continue to negotiate some options that will be used in the linking process.
Negotiating hublink optionsIn order to avoid misconfigurations in the network, before any successful link establishment, there are some things that need to be checked for validity first. One of those things is a hub prefix on the network. Obviously, 2 hubs cannot have the same prefix, so, each of those need to check if their prefixes are unique on the network.
You can set a prefix for your hub by editing the script file "
links.lua", changing the value of "
links_my_prefix" constant. There are some limitations on types of characters used in a prefix. Generally, avoid using: $ (dollar), <space>, <tab>, | (vertical line), & (ampersand). Also, keep in mind that visitors of your hub could be from around the world, so, it would be the best to use only 7-bit printable ASCII characters.
Here is a simple example of the options negotiation:
S | C
< $MyPrefixes [Alfa]$[Gama]$[G]$[T]|
> $MyPrefixes [Beta]|
< $LoginOk|
This shows that Client hub is responsible for all the users prefixed with prefixes:
[Alfa], [Gama], [G] and [T] and Server is responsible for prefix "
[Beta]". If any of the hubs detects that any of those prefixes of remote hub is already in use, by some other hub on the network, it will close the connection with a simple error msg, otherwise, a
$LoginOk is sent and a negotiation process is complete. Hubs are now successfully connected into a network.
Note that Client hub wants to register several prefixes to the Server, that means the Client has already some hubs connected in his network and is now trying to connect to a Server hub to join that hub in the existing network.
Notice: So far
$MyPrefixes is the only thing that is being negotiated during this process. In future versions, more things can be checked for validity, so, it's best to rely on
$LoginOk message before trying to send anything through that link.
It's alive 
If properly authenticated and negotiated, hubs can now broadcast to their established hublink connections whatever they want, main chat messages, pm, search, myinfo and other messages. Most of things that flow over hublinks are regular NMDC messages, but some control messages can be spoted too.
For a start, hubs send their nick list to each other. Also, hubs will inform all the other linked hubs of new hubs/users in the network. If a hub link is broken, hubs don't need to send mass
$Quit to each others, instead they only send
$PrefixDel message, for each broken hub, to save bandwidth. All the other hubs, that receive
$PrefixDel, will remove nicks prefixed with that prefix.
Here is a brief list of some messages that can be seen over a hublink connection:
$ConnectToMe [Omega]nick1 89.216.68.229:6255
$Kick [hub1]burek [hub2]nick3 Because you were bad
$Kicked [hub1]burek [hub2]nick3 Because you were bad
$MainChat [Beta]burek Some text here.
$Join [A]nick1 0 <++ V:0.706,M:A,H:1/0/0,S:5>$ $0$$0$
$PrefixAdd [Omega]
$PrefixDel [Omega]
$Quit [hub2]burek
$Search 89.216.68.229:2516 F?T?0?1?matrix
$To: [Beta]brlja From: [Alpha]burek $<[Alpha]burek> Some text here.
Basically, most of NMDC messages are broadcasted through the hub links unmodified. Main chat messages are broadcasted in a form suitable for faster checks of nicks/prefixes. There are also some new messages introduced, like "
$Kicked", which is sent in a response when an operator kicks a user, so that all other hubs are informed that a particular user has been kicked and why (cross-hub kicks/bans are possible). For the complete list of hub-to-hub messages, using VerliLinker protocol (VLP), take a look
here.
UsageThe script introduces a new command:
!linksUsage:
!links <add/del/edit/list/connect/disconnect> <link_name> <params>
Examples:
!links add gusari host=2.3.4.5 port=1234 password=gusari666 type=nmdc enabled=1 listen_port=33333
!links add gusari host=1.2.3.4 password=gusari1 listen_port=2222
!links del gusari
!links edit gusari name=gusari2 host=5.4.3.2 port=4321 password=gusari456
!links edit gusari2 port=321
!links list
!links connect gusari
!links disconnect gusari
FlagsSince version 1.4, flags are implemented, to allow hub admins to configure what gets broadcasted from/to their hubs. The usage is fairly simple:
!links edit <link_name> flags=<flags>
The list of flags follows (lower case flags are used to allow/forbid messages FROM our hub to be broadcasted to other hubs, and uppercase flags are used to allow/forbid messages from other hubs to get INTO our hub):
m - allow MainChat messages FROM my hub to be broadcasted to other hubs
M - allow MainChat messages from other hubs to be broadcasted INTO my hub
p - allow private chat messages FROM my hub to be broadcasted to other hubs
P - allow private chat messages from other hubs to be broadcasted INTO my hub
s - allow Search messages FROM my hub to be broadcasted to other hubs
S - allow Search messages from other hubs to be broadcasted INTO my hub
c - allow ConnectToMe messages FROM my hub to be broadcasted to other hubs
C - allow ConnectToMe messages from other hubs to be broadcasted INTO my hub
i - allow MyINFO messages FROM my hub to be broadcasted to other hubs
I - allow MyINFO messages from other hubs to be broadcasted INTO my hub
k - allow Kick messages FROM my hub to be broadcasted to other hubs (allow my OPs to kick remote users from the network)
K - allow Kick messages from other hubs to be broadcasted INTO my hub (allow remote OPs to kick users from my hub)
o - show OPs from my hub as OPs on remote hub
O - show OPs from remote hub as OPs on my hub
For example:
!links edit alpha flags=MsScCk
this command will set following options for link named "alpha":
- don't allow MainChat messages from my hub to be broadcasted to other hubs (missing lowercase 'm')
- allow MainChat messages from other hubs INTO my hub (uppercase 'M')
- allow Search messages from/to my hub (both 's' and 'S')
- allow ConnectToMe messages from/to my hub (both 'c' and 'C')
- don't broadcast MyINFO messages from/to my hub (both 'i' and 'I' missing)
- allow my OPs to kick remote users (lowercase 'k')
- don't allow remote OPs to kick my local users (missing uppercase 'K')
- don't show my/remote OPs in remote/my hub (both 'o' and 'O' missing)
ExampleLet's assume we have 5 hubs:
hub1, hub2, hub3, hub4 and hub5. We would like to connect them like on the following diagram:

Now, let's assume that addresses of those hubs are:
-for hub1: dchub://
hub1.domain1.org:111
-for hub2: dchub://
hub2.domain2.org:222
-for hub3: dchub://
hub3.domain3.org:333
-for hub4: dchub://
hub4.domain4.org:444
-for hub5: dchub://
hub5.domain5.org:555
Also, let's assume that passwords, used for hublinks, are:
- for link hub1-hub2: "
pass12"
- for link hub2-hub3: "
pass23"
- for link hub3-hub4: "
pass34"
- for link hub3-hub5: "
pass35"
Further more, let's assume that prefixes for each hub are:
-for hub1:
[Alpha]-for hub2:
[Beta]-for hub3:
[Gamma]-for hub4:
[Delta]-for hub5:
[Epsilon]And finally, let's assume that each hub has listen ports for each of their's links:
- hub1's local listen port for link hub1-hub2: "
201"
- hub2's local listen port for link hub1-hub2: "
301"
- hub2's local listen port for link hub2-hub3: "
401"
- hub3's local listen port for link hub2-hub3: "
501"
- hub3's local listen port for link hub3-hub4: "
601"
- hub4's local listen port for link hub3-hub4: "
701"
- hub3's local listen port for link hub3-hub5: "
801"
- hub5's local listen port for link hub3-hub5: "
901"
Now, let's see how the configuration of each hub looks like.
In hub1, an admin would have to type:
!links add hub2 host=hub2.domain2.org port=301 password=pass12 listen_port=201
Note that if admin doesn't provide a
listen_port parameter, hub will not listen for incoming connections, for that link. This is useful if you want to have some kind of "master" hub, that is the only one that can accept connections from other hubs.
In hub2, an admin would have to type:
!links add hub1 host=hub1.domain1.org port=201 password=pass12 listen_port=301
!links add hub3 host=hub3.domain3.org port=501 password=pass23 listen_port=401
In hub3, an admin would have to type:
!links add hub2 host=hub2.domain2.org port=401 password=pass23 listen_port=501
!links add hub4 host=hub4.domain4.org port=701 password=pass34 listen_port=601
!links add hub5 host=hub5.domain5.org port=901 password=pass35 listen_port=801
In hub4, an admin would have to type:
!links add hub3 host=hub3.domain3.org port=601 password=pass34 listen_port=701
In hub5, an admin would have to type:
!links add hub3 host=hub3.domain3.org port=801 password=pass35 listen_port=901
One more thing. Each admin will need to set the prefix of his hub on the network. They will each open their own script file "
links.lua" and edit it, to change the value of "links_my_prefix" constant to what they want to be their prefix ([Alpha], [Beta], [Gamma], [Delta], [Epsilon]).
That's it. After successful configuration, they can connect their links to build a network.
Admin in hub1:
Admin2 doesn't need to do:
!links connect hub1, because the admin from hub1 already established that link.
Admin in hub3:
!links connect hub2
!links connect hub4
!links connect hub5
After successful connections, the network is up and running
Final wordI hope you like this project that makes it able to create better p2p networks, which can act as a single body, like IRC networks. You can send your bug reports, suggestions, etc. to help improve the VerliLinker.
NOTE:
The oldest version of Verlihub which is tested with this script is Verlihub v0.9.8d-RC2 and VH plugin for Lua v1.7rc1