-
-
Notifications
You must be signed in to change notification settings - Fork 116
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for DTLS 1.2 Connection IDs #473
Merged
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"log" | ||
"net" | ||
|
||
piondtls "github.com/pion/dtls/v2" | ||
"github.com/plgd-dev/go-coap/v3/dtls" | ||
) | ||
|
||
func main() { | ||
conf := &piondtls.Config{ | ||
PSK: func(hint []byte) ([]byte, error) { | ||
fmt.Printf("Server's hint: %s \n", hint) | ||
return []byte{0xAB, 0xC1, 0x23}, nil | ||
}, | ||
PSKIdentityHint: []byte("Pion DTLS Client"), | ||
CipherSuites: []piondtls.CipherSuiteID{piondtls.TLS_PSK_WITH_AES_128_CCM_8}, | ||
ConnectionIDGenerator: piondtls.OnlySendCIDGenerator(), | ||
} | ||
raddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:5688") | ||
if err != nil { | ||
log.Fatalf("Error resolving UDP address: %v", err) | ||
} | ||
|
||
// Setup first UDP listener. | ||
udpconn, err := net.ListenUDP("udp", nil) | ||
if err != nil { | ||
log.Fatalf("Error establishing UDP listener: %v", err) | ||
} | ||
|
||
// Create DTLS client on UDP listener. | ||
client, err := piondtls.Client(udpconn, raddr, conf) | ||
if err != nil { | ||
log.Fatalf("Error establishing DTLS client: %v", err) | ||
} | ||
co := dtls.Client(client) | ||
resp, err := co.Get(context.Background(), "/a") | ||
if err != nil { | ||
log.Fatalf("Error performing request: %v", err) | ||
} | ||
log.Printf("Response payload: %+v", resp) | ||
resp, err = co.Get(context.Background(), "/b") | ||
if err != nil { | ||
log.Fatalf("Error performing request: %v", err) | ||
} | ||
log.Printf("Response payload: %+v", resp) | ||
|
||
// Export state to resume connection from another address. | ||
state := client.ConnectionState() | ||
|
||
// Setup second UDP listener on a different address. | ||
udpconn, err = net.ListenUDP("udp", nil) | ||
if err != nil { | ||
log.Fatalf("Error establishing UDP listener: %v", err) | ||
} | ||
|
||
// Resume connection on new address with previous state. | ||
client, err = piondtls.Resume(&state, udpconn, raddr, conf) | ||
if err != nil { | ||
log.Fatalf("Error resuming DTLS connection: %v", err) | ||
} | ||
co = dtls.Client(client) | ||
// Requests can be performed without performing a second handshake. | ||
resp, err = co.Get(context.Background(), "/a") | ||
if err != nil { | ||
log.Fatalf("Error performing request: %v", err) | ||
} | ||
log.Printf("Response payload: %+v", resp) | ||
resp, err = co.Get(context.Background(), "/b") | ||
if err != nil { | ||
log.Fatalf("Error performing request: %v", err) | ||
} | ||
log.Printf("Response payload: %+v", resp) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
package main | ||
|
||
import ( | ||
"bytes" | ||
"context" | ||
"fmt" | ||
"log" | ||
"net" | ||
"sync/atomic" | ||
"time" | ||
|
||
piondtls "github.com/pion/dtls/v2" | ||
"github.com/plgd-dev/go-coap/v3/dtls/server" | ||
"github.com/plgd-dev/go-coap/v3/message" | ||
"github.com/plgd-dev/go-coap/v3/message/codes" | ||
"github.com/plgd-dev/go-coap/v3/mux" | ||
"github.com/plgd-dev/go-coap/v3/options" | ||
udpClient "github.com/plgd-dev/go-coap/v3/udp/client" | ||
) | ||
|
||
func handleA(w mux.ResponseWriter, r *mux.Message) { | ||
log.Printf("got message in handleA: %+v from %v\n", r, w.Conn().RemoteAddr()) | ||
err := w.SetResponse(codes.GET, message.TextPlain, bytes.NewReader([]byte("A hello world"))) | ||
if err != nil { | ||
log.Printf("cannot set response: %v", err) | ||
} | ||
} | ||
|
||
func handleB(w mux.ResponseWriter, r *mux.Message) { | ||
log.Printf("got message in handleB: %+v from %v\n", r, w.Conn().RemoteAddr()) | ||
customResp := w.Conn().AcquireMessage(r.Context()) | ||
defer w.Conn().ReleaseMessage(customResp) | ||
customResp.SetCode(codes.Content) | ||
customResp.SetToken(r.Token()) | ||
customResp.SetContentFormat(message.TextPlain) | ||
customResp.SetBody(bytes.NewReader([]byte("B hello world"))) | ||
err := w.Conn().WriteMessage(customResp) | ||
if err != nil { | ||
log.Printf("cannot set response: %v", err) | ||
} | ||
} | ||
|
||
// wrappedListener wraps a net.Listener and implements a go-coap DTLS | ||
// server.Listener. | ||
// NOTE: this utility is for example purposes only. Context should be handled | ||
// properly in meaningful scenarios. | ||
type wrappedListener struct { | ||
l net.Listener | ||
closed atomic.Bool | ||
} | ||
|
||
// AcceptWithContext disregards the passed context and calls the underlying | ||
// net.Listener Accept(). | ||
func (w *wrappedListener) AcceptWithContext(_ context.Context) (net.Conn, error) { | ||
return w.l.Accept() | ||
} | ||
|
||
// Close calls the underlying net.Listener Close(). | ||
func (w *wrappedListener) Close() error { | ||
return w.l.Close() | ||
} | ||
|
||
// wrapListener wraps a net.Listener and returns a DTLS server.Listener. | ||
func wrapListener(l net.Listener) server.Listener { | ||
return &wrappedListener{ | ||
l: l, | ||
} | ||
} | ||
|
||
func main() { | ||
m := mux.NewRouter() | ||
m.Handle("/a", mux.HandlerFunc(handleA)) | ||
m.Handle("/b", mux.HandlerFunc(handleB)) | ||
laddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:5688") | ||
if err != nil { | ||
log.Fatalf("Error dialing: %v", err) | ||
} | ||
l, err := piondtls.Listen("udp", laddr, &piondtls.Config{ | ||
PSK: func(hint []byte) ([]byte, error) { | ||
fmt.Printf("Client's hint: %s \n", hint) | ||
return []byte{0xAB, 0xC1, 0x23}, nil | ||
}, | ||
PSKIdentityHint: []byte("Pion DTLS Server"), | ||
CipherSuites: []piondtls.CipherSuiteID{piondtls.TLS_PSK_WITH_AES_128_CCM_8}, | ||
ConnectionIDGenerator: piondtls.RandomCIDGenerator(8), | ||
}) | ||
if err != nil { | ||
log.Fatalf("Error establishing DTLS listener: %v", err) | ||
} | ||
s := server.New(options.WithMux(m), options.WithInactivityMonitor(10*time.Second, func(cc *udpClient.Conn) {})) | ||
s.Serve(wrapListener(l)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,8 +5,8 @@ go 1.18 | |
require ( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks like linter is stuck on |
||
github.com/dsnet/golib/memfile v1.0.0 | ||
github.com/hashicorp/go-multierror v1.1.1 | ||
github.com/pion/dtls/v2 v2.2.7 | ||
github.com/pion/transport/v2 v2.2.1 | ||
github.com/pion/dtls/v2 v2.2.8-0.20230828143201-609e5bee6eb0 | ||
github.com/pion/transport/v2 v2.2.2-0.20230802201558-f2dffd80896b | ||
github.com/stretchr/testify v1.8.4 | ||
go.uber.org/atomic v1.11.0 | ||
golang.org/x/exp v0.0.0-20230801115018-d63ba01acd4b | ||
|
@@ -19,7 +19,7 @@ require ( | |
github.com/hashicorp/errwrap v1.1.0 // indirect | ||
github.com/pion/logging v0.2.2 // indirect | ||
github.com/pmezard/go-difflib v1.0.0 // indirect | ||
golang.org/x/crypto v0.11.0 // indirect | ||
golang.org/x/sys v0.10.0 // indirect | ||
golang.org/x/crypto v0.12.0 // indirect | ||
golang.org/x/sys v0.11.0 // indirect | ||
gopkg.in/yaml.v3 v3.0.1 // indirect | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jkralik I'm not sure if there is appetite to do so, but I would be interested in
go-coap
defining a commonContextListener
and utility wrappers to allow for the passing ofnet.Listener
. For now, consumers of this functionality will need to use a custom listener as demonstrated in this example.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I see the point. But one thing - Has handshaking been moved to
Conn.Read/Write
fromlistener.Accept
? If not, we need to incorporate it with https://github.com/plgd-dev/go-coap/blob/master/net/dtlslistener.go#L37.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jkralik I'm not sure I'm following your suggestion here. Handshaking has not moved -- from the perspective of the existing
DTLSListener
nothing has changed. In fact, setting theconnectionIDGenerator
on thepion/dtls
config passed toNewDTLSListener
would enable connection ID support. The issue is that the underlyingpion/transport/udp
package being used does not support routing based on Connection ID. A replacement has been introduced in https://github.com/pion/dtls/tree/master/internal/net/udp, which is ininternal
for now so that it can be iterated upon prior to folks taking a direct dependency on its API. It can be consumed by using thepion/dtls.Listen
function.I do think it would be good for the functionality to become the default in
go-coap
, but right now theDTLSListener
is restrictive about the behavior it allows (anecdotally, we use a different implementation of theDTLSListener
internally so introduce additional functionality). This PR maintains the existinggo-coap
functionality, while also demonstrating how a consumer can provide their own listener for custom functionality (including connection IDs).It seems like previously the
pion/dtls.Listener
was used, but then was moved away from in order to introduce parallel handshakes. My understanding of this functionality is that theDTLSListener
essentially just continuously accepts connections so that the handshake can begin and complete, perhaps before the DTLSServer
callsAcceptWithContext()
. It seems the major blocker from using thepion/dtls.Listener
is the [starting of thepion/dtls.Server
in a go pool. My question is whether this could be functionality introduced inpion/dtls
instead (i.e. stop blockingAccept()
on completion of the handshake), which would allowgo-coap
to treat the DTLS listener as just anet.Listener
(with the generic wrapping to support context handling).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Note: this is what I would like to do long term, but the changes in this PR enable folks to implement custom behavior to enable connection ID support, while keeping the previous behavior of
go-coap
unchanged when using the providedDTLSListener
implementation. This feels like a good intermediate step to me as it does not introduce any breaking changes ingo-coap
, but I am open to discussion and happy to explore other avenues as well!)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a discussion (pion/dtls#279) about moving the handshake, as it is in the
golang/crypto
package, to theRead/Write
functions.I agree with you; we can proceed step by step.