Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: test

on:
- workflow_dispatch
- push

jobs:
test:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

- name: Set up Go Environment
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version-file: 'go.mod'
cache: true

- name: Run Tests
run: go test -v ./...
3 changes: 3 additions & 0 deletions const.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ const (
// to two weeks. Rotations should happen at roughly half this.
DefaultCertificateLifetime = time.Hour * 24 * 14

// DefaultTlsHandshakeTimeout is the default timeout for TLS handshakes
DefaultTlsHandshakeTimeout = time.Minute

// This is the default time that an server-led activation token is alive
DefaultMaximumServerLedActivationTokenLifetime = time.Hour * 24 * 14

Expand Down
118 changes: 64 additions & 54 deletions net/splitlistener.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,75 +92,85 @@ func (l *SplitListener) Start() error {
l.cancel()
return err
}

protoConn, ok := conn.(*protocol.Conn)
if !ok {
// It'd be nice not to be silent about this, but since we've
// verified that only *protocol.InterceptingListener can be the
// underlying listener, this should never really happen
_ = conn.Close()
if conn == nil {
continue
}
go func(conn net.Conn) {
Comment thread
ddebko marked this conversation as resolved.
protoConn, ok := conn.(*protocol.Conn)
if !ok {
// It'd be nice not to be silent about this, but since we've
// verified that only *protocol.InterceptingListener can be the
// underlying listener, this should never really happen
_ = conn.Close()
return
}

tlsConn := protoConn.Conn
if !tlsConn.ConnectionState().HandshakeComplete {
// Another case where assuming it is in fact the listener we expect,
// it will always have performed a handshake as the protocol
// requires it; so it'd be nice not to be silent about this, but
// this should never really happen
_ = conn.Close()
continue
}
// Handshake should have already been kicked off in a sync.Once, calling it here again
// as it block until handshake is complete before proceeding.
if err := protoConn.Handshake(); err != nil {
_ = conn.Close()
return
Comment thread
ddebko marked this conversation as resolved.
}

negProto := tlsConn.ConnectionState().NegotiatedProtocol
if nodeenrollment.ContainsKnownAlpnProto(negProto) {
if strings.HasPrefix(negProto, nodeenrollment.FetchNodeCredsNextProtoV1Prefix) {
// If it's the fetch proto, the TLS handshake should be all that is
// needed and the connection should be closed already. Close it for
// safety and continue.
if !protoConn.ConnectionState().HandshakeComplete {
// Another case where assuming it is in fact the listener we expect,
// it will always have performed a handshake as the protocol
// requires it; so it'd be nice not to be silent about this, but
// this should never really happen
_ = conn.Close()
continue
return
}

// Get client conns and do a search
clientNextProtos := protoConn.ClientNextProtos()
var foundListener *MultiplexingListener
l.babyListeners.Range(func(k, v any) bool {
for _, proto := range clientNextProtos {
if k.(string) == proto {
foundListener = v.(*MultiplexingListener)
return false
negProto := protoConn.ConnectionState().NegotiatedProtocol
if nodeenrollment.ContainsKnownAlpnProto(negProto) {
if strings.HasPrefix(negProto, nodeenrollment.FetchNodeCredsNextProtoV1Prefix) {
// If it's the fetch proto, the TLS handshake should be all that is
// needed and the connection should be closed already. Close it for
// safety and continue.
_ = conn.Close()
return
}

// Get client conns and do a search
clientNextProtos := protoConn.ClientNextProtos()
var foundListener *MultiplexingListener
l.babyListeners.Range(func(k, v any) bool {
for _, proto := range clientNextProtos {
if k.(string) == proto {
foundListener = v.(*MultiplexingListener)
return false
}
}
return true
})

// If we didn't find something for that proto, look for a
// non-specific authenticated listener
if foundListener == nil {
val, ok := l.babyListeners.Load(AuthenticatedNonSpecificNextProto)
if ok {
foundListener = val.(*MultiplexingListener)
}
}
return true
})

// If we didn't find something for that proto, look for a
// non-specific authenticated listener
if foundListener == nil {
val, ok := l.babyListeners.Load(AuthenticatedNonSpecificNextProto)
if ok {
foundListener = val.(*MultiplexingListener)

// If we found a listener send the conn down, otherwise close the
// conn
if foundListener == nil {
_ = conn.Close()
} else {
foundListener.IngressConn(protoConn, nil)
}
return
}

// If we found a listener send the conn down, otherwise close the
// conn
if foundListener == nil {
// Not authenticated
val, ok := l.babyListeners.Load(UnauthenticatedNextProto)
if !ok {
_ = conn.Close()
} else {
foundListener.IngressConn(protoConn, nil)
val.(*MultiplexingListener).IngressConn(protoConn, nil)
}
continue
}

// Not authenticated
val, ok := l.babyListeners.Load(UnauthenticatedNextProto)
if !ok {
_ = conn.Close()
} else {
val.(*MultiplexingListener).IngressConn(protoConn, nil)
}
}(conn)
}
}

Expand Down
Loading
Loading