Browse Source

Merge branch 'captp-crossed-hellos' into 'master'

Crossed hellos mitigation

See merge request spritely/goblins!37
update-v0.12.0
Christine Lemmer-Webber 2 years ago
parent
commit
467c116e45
  1. 110
      goblins/ocapn/captp.rkt
  2. 4
      goblins/ocapn/netlayer/fake-intarwebs.rkt
  3. 4
      goblins/ocapn/netlayer/onion.rkt

110
goblins/ocapn/captp.rkt

@ -960,6 +960,7 @@
(define core-beh
(methods
[(get-suite) 'prot0]
[(get-our-side-name) our-side-name]
[get-handoff-pubkey get-handoff-pubkey]
;; TODO: Horrible, we need to protect against this
[(get-handoff-privkey) handoff-privkey]
@ -1071,7 +1072,6 @@
;; don't bother to deduplicate while attempting a connection...
;; oops)
;;
;; TODO: Fix crossed hellos problem
;; TODO: Fix simultaneous outgoing connections problem, which
;; is related, but easier to fix. To do so we just need to
;; recognize that we're "in the middle of" establishing a
@ -1205,9 +1205,14 @@
(define open-session-names->sessionmeta
(spawn ^hash))
;; For keeping track of new outbound sessions to detect crossed hellos
(define locations->crossed-hellos-mitigator
(spawn ^hash))
(define (^connection-establisher bcom netlayer netlayer-name)
(lambda (read-message write-message incoming?)
($ self 'new-connection netlayer netlayer-name read-message write-message)))
(lambda (read-message write-message remote-connect-location)
($ self 'new-connection netlayer netlayer-name
read-message write-message remote-connect-location)))
;; Here's why all netlayers currently are in the same vat as the
;; router, at least currently... to make sure that they're all set up
@ -1379,7 +1384,7 @@
;; somewhere...
;; TODO: Should this still be an exposed method? Maybe it's something only
;; the ^connection-establisher should call...
[(new-connection netlayer netlayer-name read-message write-message)
[(new-connection netlayer netlayer-name read-message write-message remote-connect-location)
(define captp-outgoing-ch
(make-async-channel))
(define (send-to-remote msg)
@ -1408,7 +1413,7 @@
;; TODO: Shouldn't the netlayer actually interpret this message
;; before it gets here? Ie, at this stage, we're already
;; "confident" this is from the right location
[(op:start-session remote-captp-version
[(op:start-session remote-captp-version
remote-encoded-pubkey
(? ocapn-node? claimed-remote-location)
remote-location-sig)
@ -1450,35 +1455,52 @@
remote-handoff-pubkey
remote-location)
(define local-bootstrap-obj
;; Handle potential crossed hellos mitigation - incoming connections decide if we
;; should continue or abort.
;; See the comment below for more information about this (above ^crossed-hellos-mitigator).
(define can-continue?
(let* ([chm ($ locations->crossed-hellos-mitigator 'ref remote-location #f)]
[their-side-name ($ coordinator 'get-remote-side-name)]
[outgoing? (ocapn-node? remote-connect-location)]
[must-abort? (and chm (not outgoing?) ($ chm their-side-name))])
;; Clean up the crossed hellos mitigator actor, we won't need it after this.
(unless (null? chm)
($ locations->crossed-hellos-mitigator 'remove remote-location))
;; Send internal shutdown if needed.
(when must-abort?
(<-np incoming-forwarder (internal-shutdown 'abort "Crossed hellos mitigation")))
(not must-abort?)))
(define (make-local-bootstrap-obj)
(if custom-bootstrap
(custom-bootstrap ^bootstrap coordinator)
(spawn ^bootstrap coordinator)))
;; and finally we can actually kick off setting up the rest
;; of the connection
(define-values (captp-incoming-handler remote-bootstrap-vow)
(setup-captp-conn send-to-remote coordinator
local-bootstrap-obj
intra-node-warden intra-node-incanter))
;; Fulfill the meta-bootstrap-promise with the promise that
;; setup-captp-conn gave us
($ meta-bootstrap-resolver 'fulfill remote-bootstrap-vow)
;; And set things up so that the incoming-forwarder now goes
;; to the captp-incoming-handler
(incoming-swap captp-incoming-handler)
;; TODO: Deal with duplicate sessions and also "crossed connections"
;; And now install in the open sessions in the directory
(define session-name
($ coordinator 'get-session-name))
($ locations->open-session-names 'set remote-location session-name)
($ open-session-names->sessionmeta 'set
session-name
(sessionmeta remote-location
local-bootstrap-obj remote-bootstrap-vow
coordinator session-name))
(when can-continue?
(let*-values ([(session-name) ($ coordinator 'get-session-name)]
[(local-bootstrap-obj) (make-local-bootstrap-obj)]
[(captp-incoming-handler remote-bootstrap-vow)
(setup-captp-conn send-to-remote coordinator
local-bootstrap-obj
intra-node-warden intra-node-incanter)])
;; Fulfill the meta-bootstrap-promise with the promise that
;; setup-captp-conn gave us
($ meta-bootstrap-resolver 'fulfill remote-bootstrap-vow)
;; Set things up so that the incoming-forwarder now goes
;; to the captp-incoming-handler
(incoming-swap captp-incoming-handler)
;; Install in the open sessions in the directory
($ locations->open-session-names 'set remote-location session-name)
($ open-session-names->sessionmeta 'set
session-name
(sessionmeta remote-location
local-bootstrap-obj remote-bootstrap-vow
coordinator session-name))))
(void)]
[(internal-shutdown type reason)
;; We're shutting down before we've properly set the connection up,
@ -1511,6 +1533,34 @@
(write-message msg marshallers)
(lp))))
;; The crossed hellos problem is where we try to connect to a location
;; at the same time, they are trying to connect to us. Only one of these
;; connections should be allowed to succeed.
;;
;; In CapTP when each side opens a connection it MUST send its op:start-session
;; message first. When each side has received this, it then should look and
;; detect crossed hellos (we look in the locations->crossed-hellos-mitigator map).
;;
;; If we detect the crossed hellos problem we take our key from our outbound
;; connection and compute the side name (our-side-name) and the remote key
;; from the inbound connection and calculate their name (their-side-name).
;; With both of these, we sort them bytewise and whichever is lower, that
;; session ends, the higher of the two continues.
(define (^crossed-hellos-mitigator bcom our-side-name)
(define voided-beh (lambda _ (void)))
(lambda (remote-side-name)
(let ([sorted-names (sort (list our-side-name remote-side-name) bytes<?)])
(if (equal? (car sorted-names) our-side-name)
(begin
(<-np incoming-forwarder (internal-shutdown 'abort "Crossed Hellos mitigation"))
(bcom voided-beh #f))
(bcom voided-beh #t)))))
(when (ocapn-node? remote-connect-location)
($ locations->crossed-hellos-mitigator 'set
remote-connect-location
(spawn ^crossed-hellos-mitigator ($ coordinator 'get-our-side-name))))
;; Now we'll need to send our side of the start-session and get the
;; other side... which will be handled by the ^setup-completer above
(send-to-remote (op:start-session captp-version

4
goblins/ocapn/netlayer/fake-intarwebs.rkt

@ -56,7 +56,7 @@
(define-values (read-message write-message)
(read-write-procs ip op))
;; TODO
(<- conn-establisher read-message write-message #t)])
(<- conn-establisher read-message write-message #f)])
#:finally listen-loop)))
(define (^netlayer bcom)
@ -89,7 +89,7 @@
[(vector ip op)
(define-values (read-message write-message)
(read-write-procs ip op))
(<- conn-establisher read-message write-message #f)])
(<- conn-establisher read-message write-message remote-node)])
#:promise? #t)])]))
;; TODO: return pre-setup-beh
pre-setup-beh)

4
goblins/ocapn/netlayer/onion.rkt

@ -175,7 +175,7 @@
(unix-socket-accept ocapn-sock-listener))
(define-values (read-message write-message)
(read-write-procs ip op))
(<-np-extern conn-establisher read-message write-message #t))
(<-np-extern conn-establisher read-message write-message #f))
(syscaller-free-thread
(lambda ()
(dynamic-wind
@ -225,7 +225,7 @@
(onion-socks5-setup! ip op (string-append designator ".onion"))
(define-values (read-message write-message)
(read-write-procs ip op))
(<- conn-establisher read-message write-message #f)))
(<- conn-establisher read-message write-message remote-node)))
(define start-conn (connect-vat 'spawn ^start-conn))
(<- start-conn)])]))
pre-setup-beh)

Loading…
Cancel
Save