1

Publish radio linking rfc

This commit is contained in:
Evan Pratten 2021-11-17 13:36:13 -05:00
parent 1261194a49
commit 455035ccb8
6 changed files with 184 additions and 2 deletions

10
content/rfc/_index.md Normal file
View File

@ -0,0 +1,10 @@
---
title: Proposals
extra:
inject_rfcs: true
---
# Proposals & RFCs
This section contains project proposals that I either lack the time or resources to complete. This is a bit of a public TODO list.

View File

@ -0,0 +1,150 @@
---
title: "RFC: A fast system for repeater linking using modern web technology"
date: 2021-11-17
extra:
is_rfc: true
uses_graphviz: true
---
The three common standards for amateur radio repeater linking are all built on old and cumbersome technology. In the world of repeater linking, the most predominant standards for interconnection are:
- [Echolink](https://secure.echolink.org/)
- Closed-source
- Strict governance
- A strong lack of APIs
- Does not allow cross-system linking
- ex: cannot link Echolink conferences to Allstar nodes
- [AllStarLink](https://allstarlink.org/)
- Absolute overkill
- Most node configurations require special hardware to set up
- Built on the Asterisk PBX
- Uses phone networks to link repeaters
- [IRLP](http://www.irlp.net/)
- Requires specialized hardware
- Uses old connection standards
- Closed-source
In my ideal world, there would be a small, lightweight, and configurable linking backend that developers could extend in any way they wished. This proposal is not the end-all-be-all solution, but a step in the direction of this vision.
## Node discovery
In a linking system like Echolink, *all* clients announce themselves to a central directory server. This server then decides if a client is "worthy" (verified license, not banned from the service, ...) then lists the client on [a somewhat parsable webpage](https://secure.echolink.org/logins.jsp). The topology for such a setup is as follows:
<div class="mermaid">
flowchart LR
You(You) --- D1((Directory Server))
D1 --- NA(Node A) & NB(Node B) & P1(Proxy) & ND(Node D)
P1 --- NC(Node C)
</div>
In most cases, this works just fine. However, there are two off the top of my head that raise an issue:
- `Node A` and `Node B` are owned by a club that wants to keep the nodes private for member use only.
- `Node C` is behind a restrictive firewall, or does not want to expose a host to the public internet.
The second of the two scenarios is solved already in the above graph using a proxy. Echolink proxies have become extremely common due to the fact very few people have access to a network where their host can be exposed publicly for other nodes to directly connect to when making a link.
Echolink's solution to the first issue is fairly lacking in my opinion. Nodes only have the option to restrict connections based on a REGEX on their callsign. This means maintaining a list of allowed users, and updating *every* club-owned node when that changes.
### Decentralizing directory services
While I like Echolink a lot, I think some improvements could be made to both the node directory system, and how nodes link to each other. Ideally, I see a setup as follows:
<div class="mermaid">
flowchart TD
D1((Directory A))
D1 --- NA(Node A) & NB(Node B) & NC(Node C)
D2((Directory B))
D2 --- NC & ND(Node D)
D3((Private Directory))
D3 --- NE(Node E) & NF(Node F)
NE --> D2
</div>
In this world, anyone could host a directory server, and either open it up to the public, or restrict it by means of their choosing (callsign rules, password, key-based access, ...). Nodes can then connect to one or many directories of their choosing. This could allow situations where a node could sit on the edge between two private intranets and have access to other nodes on *both* sides of the boundary without requiring either side to expose some part of itself to the public internet.
### Routing
I also envision a routing system where nodes attached to more than one directory service would periodically propagate information about their first-hop directories to other first-hop directories. An example of such interaction from the perspective of `Node C` would be:
```text
Node C -> Directory A: You can find Directory B at <address>
Node C -> Directory B: You can find Directory A at <address>
```
`Node E` would have a different interaction. Since `Private Directory` is *private*, its announcement would *exclude* that directory:
```text
Node E -> Private Directory: You can find Directory B at <address>
```
At this point, the directory servers should then be able to directly query eachother about their "routing tables". Over time, each directory server would build a list of which directory servers it can reach for information about nodes.
The rable for `Private Directory` would look like this:
| Server | Address | Hops |
|-------------|-------------|------|
| Directory B | `<address>` | 1 |
| Directory A | `<address>` | 2 |
If `Node F` were to try connecting to `Node A`, the order of messages would be:
```text
Node F -> Private Directory: Do you know Node A?
# Private Directory queries the first table entry
Private Directory -> Directory B: Do you know Node A?
Directory B -> Private Directory: No
# Private Directory queries the second table entry
Private Directory -> Directory A: Do you know Node A?
Directory A -> Private Directory: Node A is at <address>
# Node F is informed of the address of Node A
Private Directory -> Node F: Node A is at <address>
```
Of course, since `Node F` is *only* connected to a *private* directory service, if `Node A` were to try connecting to `Node F`, the order of messages would be:
```text
Node A -> Directory A: Do you know Node F?
# Directory A queries the first table entry
Directory A -> Directory B: Do you know Node F?
Directory B -> Directory A: No
# Directory A was never informed that Private Directory exists, since it is private
# Thus, there is no route to Node F
Directory A -> Node A: No
```
Like every other piece of amateur radio backbone software, this routing system relies on trust. I am not an expert in identity verification, and I will not attempt to devise a system for stopping bad actors from poisoning the routing tables in this document.
## Audio transport using modern tech
So far in this document, node addresses have been used extensively, yet nodes are not expected to expose any ports to the internet. In the real-world, it has become very common to see peer-to-peer real-time media links in the form of video conferencing services. These services largely rely on WebRTC, a standardized, strong, and reliable protocol for peer-to-peer content streams.
While WebRTC still struggles to deliver perfect quality audio and video simultaneously, it is more than capable of *just* streaming audio, with the added benefit that basically every browser supports it natively. Most programming languages also have one or many strong WebRTC libraries to work with.
This means that a full implementation of this document would result in something similar to the following:
- Directory server
- Handles incoming clients
- Handles routing tables
- Handles access rules
- Performs client lookups when requested
- Possibly provides telemetry information
- Client library
- Establishes connections with one or more directories
- Periodically propagates information about connected directories
- Can request to create or destroy a link
- When a link is created, it exposes a direct WebRTC connection to the remote node
- Hands off responsibility for the connection to whatever software wraps the library
The wrapping software could be one of:
- A website
- A smartphone app
- A headless application running on a Raspberry Pi that connects straight to a radio for a simplex node
- An application running on a repeater controller
- Anything else

View File

@ -132,3 +132,8 @@ ul {
}
}
}
.mermaid {
width: fit-content;
margin: auto;
}

View File

@ -78,7 +78,8 @@
<p>
<a href="/">Home</a> |
<a href="/blog">Blog</a> |
<a href="/hobbies">Hobbies</a>
<a href="/hobbies">Hobbies</a> |
<a href="/rfc">RFC</a>
</p>
<hr>
</div>

View File

@ -67,7 +67,7 @@ MathJax.Hub.Config({tex2jax: {inlineMath: [['$','$'], ['\\(','\\)']], displayMat
</div>
{# Comments only on blog posts #}
{% if page.description and page.date %}
{% if page.extra.is_rfc or page.description and page.date %}
<br>
<hr>
<script src="https://utteranc.es/client.js" repo="ewpratten/va3zza.com" issue-term="title" label="comment"
@ -80,4 +80,7 @@ MathJax.Hub.Config({tex2jax: {inlineMath: [['$','$'], ['\\(','\\)']], displayMat
{% if page.extra.uses_twitter %}
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
{% endif %}
{% if page.extra.uses_graphviz %}
<script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
{% endif %}
{% endblock content %}

View File

@ -49,6 +49,7 @@
{% block content %}
{{section.content | safe}}
{# Blog posts #}
{% if section.extra.inject_blog_posts %}
<ul>
{% for page in section.pages %}
@ -59,4 +60,16 @@
{% endfor %}
</ul>
{% endif %}
{# RFCs #}
{% if section.extra.inject_rfcs %}
<ul>
{% for page in section.pages %}
{% if not page.extra.hidden %}
<li class="blog-post-li"><a href="{{page.path}}">{{page.title}}</a> <span style="color:gray;">({{page.date}})</span>
</li>
{% endif %}
{% endfor %}
</ul>
{% endif %}
{% endblock content %}