diff --git a/ugly_hacks/fbx/known_services.py b/ugly_hacks/fbx/known_services.py new file mode 100644 index 000000000..6c2725aeb --- /dev/null +++ b/ugly_hacks/fbx/known_services.py @@ -0,0 +1 @@ +{ "plinth": { "james": [ "http://192.168.0.12:8080" ], }, } diff --git a/ugly_hacks/fbx/serving_to.py b/ugly_hacks/fbx/serving_to.py new file mode 100644 index 000000000..a8130ae57 --- /dev/null +++ b/ugly_hacks/fbx/serving_to.py @@ -0,0 +1,2 @@ +{ "james": { "wiki": "wiki" }, + "ian": { "web": "plinth" }, } diff --git a/ugly_hacks/fbx/serving_what.py b/ugly_hacks/fbx/serving_what.py new file mode 100644 index 000000000..e2b428d3f --- /dev/null +++ b/ugly_hacks/fbx/serving_what.py @@ -0,0 +1,2 @@ +{ "plinth": "http://192.168.0.13:8080", + "wiki": "http://192.168.0.13/wiki", } diff --git a/ugly_hacks/fbx/settings.py b/ugly_hacks/fbx/settings.py new file mode 100644 index 000000000..56491a2d6 --- /dev/null +++ b/ugly_hacks/fbx/settings.py @@ -0,0 +1,5 @@ +{ "me": "nick", + "socket_port": 8080, + "max_hops": 3, + "proxy_list": ("tor") + } diff --git a/ugly_hacks/santiago.html b/ugly_hacks/santiago.html new file mode 100644 index 000000000..e5453692a --- /dev/null +++ b/ugly_hacks/santiago.html @@ -0,0 +1,625 @@ + + + +
+ + +The following is an ugly hack. Beware!
+Santiago manages service discovery between FreedomBoxen, coordinating +connections between arbitrary servers and services. In essence, A requests a +service from B, B replies with the service's location, and A uses that location +for the service.
+In a nutshell, that's the important part. There are additional details to +manage, but they're implied and built on the system above.
+Right now, we're cheating. We start by pairing boxes, exchanging both +box-specific PGP keys and Tor Hidden Service IDs. This allows boxes to trust +and communicate with one another, regardless of any adverserial interference. +Or, rather, any adverserial interference will be obvious and ignorable.
+The Santiago service is running on B, waiting for connections. When it +receives a request message, that message must be signed by a known and trusted +party. If it is acceptably signed (with a known, and valid ID), B will +reply to A's Santiago with an acceptably signed message.
+The contents of the request message are as follows:
+The message is signed by A, and optionally encrypted (if the message is +proxied, it must contain a "To" header). If A includes a location stanza, +B MUST respect that location in its response and update that location for +its Santiago service from A going forward.
+In this document, I elide the Santiago acknowledgements (because they add a lot +of unnecessary noise - we can assume communication failures are failures of +acknolwedgement receipt). But, after each message that needs a response, an +acceptably signed acknowledgement message is returned. Otherwise the sender +preferentially moves on to the recipient's next Santiago address after a +sufficient amount of time has passed. An example of this communication, with +these details specified, follows:
+| B -> A: | I'll gladly serve X for you, at Z, my good fellow. | +
|---|---|
| A -> B: | (No response) | +
| B -> A: | (using a different Santiago address) I'm serving X for A at Z. | +
| A -> B: | (Acknowledgment) | +
How are these data stored, to prevent both A and B from having to dance the +Santiago for each and every request?
+Each node contains two dictionaries/hash-tables listing (1) what they serve and +who they serve it to, and (2) what services they use, who from, and where that +service is located.
+I offer these services to others.
+These data are stored as pair of dictionaries:
+The GPG ID to Service dictionary. This lists which service each user is +authorized for:
++0x0928: [ "proxy": "proxy", "wiki": "wiki", + "drinking buddy": "drinking buddy" ] +0x7747: [ "wiki": "wiki", "proxy": "restricted_proxy" ] ++
The Service to Location dictionary. This lists the locations each service +runs on:
++"wiki": [ 192.168.1.1, "superduperwiki.onion" ] +"proxy": [ 8.8.8.8 ] +"restricted_proxy": [ 4.4.4.4 ] ++
I consume these services, they are offered by others.
+These data are stored as a triple-key dictionary, with the following mappings:
+
+Service X: { GPG ID1: [ location, location, location ],
+ GPG ID2: [ location, location ], }
+Service Y: { GPG ID2: [ location, location, location ],
+ GPG ID3: [ location, location ], }
+
+This allows fast lookup from the service desired to the users that host the +service, to the actual locations that service is offered. This allows the user +to quickly decide which service provider to use and to try all locations +controlled by that service provider very quickly and easily.
+| TODO: | Revise to reduce communication to logical minimum number of connections, +exchanges, and communications. | +
|---|
When A is connecting to B's service, it will attempt to connect to that +service, which B will validate before permitting the connection. If the service +is non-responsive, A will query B for the service. If B is generally +non-responsive, A will move on to C. A will ask C for the service. If +C cannot provide the service, A will ask C to request the service from +B. If C can reach B and B authorizes A, B will respond +affirmatively to A with the service's location.
+| A -> B: | (Connecting to Service!) | +
|---|---|
| B: | (Validating Service and rejecting for some reason, e.x., A hasn't been +reauthorized for this service recently enough, and because it's Wednesday.) | +
| B -> A: | (No response) | +
| A -> B: | Will you serve X? | +
| B -> A: | (No response, A can't reach B's Santiago.) | +
| A -> C: | Will you serve X? | +
| C -> A: | No! | +
| A -> C: | Will B serve X? | +
| C -> B: | Will you serve X for A? | +
| B -> A: | Hey, buddy, here's X! | +
I'm looking for somebody to provide a service, X.
+A sends a request to C, and C doesn't respond. A requests the +service from B and B NBKs. A requests that B proxy my request +to C, in case B can reach C. C replies directly to A, and +we begin communicating on that service:
+| A -> C: | Will you serve X? | +
|---|---|
| C -> A: | (No response) | +
| A -> B: | Will you serve X? | +
| B -> A: | No! | +
| A -> B: | Will C serve X? | +
| B -> C: | Will you serve X for A? | +
| C -> A: | Hey, buddy, here's X! Let's go out for beer later. | +
I know D offers a service, X, but I can't get in touch with it.
+A requests X from D, and D never responds. A requests that B find +D. B doesn't know D and forwards the request to a friend C. C knows +D and sends the message along. D tries to respond directly to A, but +can't, so it sends replies back up the chain.
+| A -> D: | Will you serve X? | +
|---|---|
| D -> A: | (No response) | +
| A -> B: | Will D serve X for me? | +
| B -> C: | Will D serve X for A? | +
| C -> D: | Will you serve X for A? | +
| D -> A: | Hey, buddy, here's X! | +
| A -> D: | (No response) | +
| D -> C: | I'm serving X for A. | +
| C -> B: | D's serving X for A. | +
| B -> A: | D's serving X for you. | +
Each message is signed, but only the first message (A's message) is inviolable. +Each client then passes the message, stripping off intermediary signatures, and +then signing the message for each of its friends.
+A message looks like:
++---- A's Signed Message Starts Here ---- + To: D's GPG key. + ---- D's Encrypted Message Starts Here ---- + Hey *D*, will you serve *X* for me? + Please reply to 5.onion. + ---- D's Encrypted Message Ends Here ---- +---- A's Signed Message Ends Here ---- ++
A forwarded message, from B to C, looks like:
++---- B's Signed Message Starts Here ---- +---- A's Signed Message Starts Here ---- + To: D's GPG key. + ---- D's Encrypted Message Starts Here ---- + Hey *D*, will you serve *X* for me? + Please reply to 5.onion. + ---- D's Encrypted Message Ends Here ---- +---- A's Signed Message Ends Here ---- +---- B's Signed Message Ends Here ---- ++
When forwarded over again, from C to D, it looks like:
++---- C's Signed Message Starts Here ---- +---- A's Signed Message Starts Here ---- + To: D's GPG key. + ---- D's Encrypted Message Starts Here ---- + Hey *D*, will you serve *X* for me? + Please reply to 5.onion. + ---- D's Encrypted Message Ends Here ---- +---- A's Signed Message Ends Here ---- +---- C's Signed Message Ends Here ---- ++
These buggers are neat. We need to fake known and pre-determined communications +to verify the servers and clients are correctly and independently responding +according to the protocol.
+Of course this is vulnerable. It's on the internet, isn't it?
+A discovered box is shut down or compromised. It can lie to its requestors and +not perform its functions. It can also allow connections and expose +connecting clients. If the client is compromisable (within reach), it also can +be compromised. We can try, but every service that isn't run directly over Tor +identifies one user to another.
+This is probably the largest worry, where B fakes A's responses.
+We gain a lot by relying on the WOT, and only direct links in the WOT. We also +gain a lot by requiring every communication to be signed (and maximally +encrypted).
+Once a key is compromised, we're vulnerable, but to what exactly? What attacks +can an adversary who's compromised a secret key perform? As long as you don't +have any publicly identifiable (or public-facing) services in your Santiago, +then not much. If you're identifiable by your Santiago, and you've permitted +the attacker to see an identifiable service (including your Santiago instances), +that service and all co-located services could be shut down. If the service +identifies you (and not just your box), you're vulnerable. An attacker will +shortly identify all the services you've given it access to.
+An attacker can try to identify your friends, though will have trouble if you +send your proxied requests with non-public methods, or you don't proxy at all.
+Nice try, now try again with a request like:
+http://localhost:8080/santiago/(gpgId)/(service)/(server)
+ +This'll get you good results:
+
+ http://localhost:8080/santiago/james/wiki/nick
+
+ See the serving_to, serving_what, and
+ me variables.