-
Notifications
You must be signed in to change notification settings - Fork 18
/
multiplexed_dtls_conn.go
127 lines (102 loc) · 2.98 KB
/
multiplexed_dtls_conn.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package meshboi
import (
"net"
"github.com/pion/dtls/v2"
"github.com/pion/dtls/v2/pkg/protocol"
"github.com/pion/dtls/v2/pkg/protocol/recordlayer"
"github.com/samvrlewis/udp"
log "github.com/sirupsen/logrus"
"inet.af/netaddr"
)
// VpnListenerDialer allows for:
// - Dialing connections to other members in the VPN Mesh
// - Accepting connections to other members in the VPN Mesh
// - Dialing connections to non VPN Mesh members
type VpnMeshListenerDialer interface {
// Returns the connection and the VPN IP address on the other side
AcceptMesh() (MeshConn, error)
// Returns the connection and the VPN IP address on the other side
DialMesh(raddr net.Addr) (MeshConn, error)
Dial(raddr net.Addr) (net.Conn, error)
}
type MeshConn interface {
net.Conn
RemoteMeshAddr() netaddr.IP
}
type meshConn struct {
net.Conn
remoteMeshAddr netaddr.IP
}
func (m *meshConn) RemoteMeshAddr() netaddr.IP {
return m.remoteMeshAddr
}
// MultiplexedDTLSConn represents a conn that can be used to listen for new incoming DTLS connections
// and also dial new UDP connections (both DTLS and non-DTLS) from the same udp address
type MultiplexedDTLSConn struct {
listener *udp.Listener
config *dtls.Config
}
func NewMultiplexedDTLSConn(laddr *net.UDPAddr, config *dtls.Config) (*MultiplexedDTLSConn, error) {
// Set a listen config so that we only accept incoming connections that are DTLS connections
lc := udp.ListenConfig{
AcceptFilter: func(packet []byte) bool {
pkts, err := recordlayer.UnpackDatagram(packet)
if err != nil || len(pkts) < 1 {
return false
}
h := &recordlayer.Header{}
if err := h.Unmarshal(pkts[0]); err != nil {
return false
}
return h.ContentType == protocol.ContentTypeHandshake
},
}
listener, err := lc.Listen("udp", laddr)
if err != nil {
return nil, err
}
return &MultiplexedDTLSConn{
listener: listener.(*udp.Listener),
config: config,
}, nil
}
func (mc *MultiplexedDTLSConn) startDtlsConn(conn net.Conn, isServer bool) (MeshConn, error) {
var dtlsConn *dtls.Conn
var err error
if isServer {
dtlsConn, err = dtls.Server(conn, mc.config)
} else {
dtlsConn, err = dtls.Client(conn, mc.config)
}
if err != nil {
log.Warn("Error starting dtls connection: ", err)
conn.Close()
return nil, err
}
peerIpString := string(dtlsConn.ConnectionState().IdentityHint)
peerVpnIP, err := netaddr.ParseIP(peerIpString)
if err != nil {
log.Warn("Couldn't parse peers vpn IP")
return nil, err
}
return &meshConn{Conn: dtlsConn,
remoteMeshAddr: peerVpnIP,
}, nil
}
func (mc *MultiplexedDTLSConn) AcceptMesh() (MeshConn, error) {
conn, err := mc.listener.Accept()
if err != nil {
return nil, err
}
return mc.startDtlsConn(conn, true)
}
func (mc *MultiplexedDTLSConn) DialMesh(raddr net.Addr) (MeshConn, error) {
conn, err := mc.listener.Dial(raddr)
if err != nil {
return nil, err
}
return mc.startDtlsConn(conn, false)
}
func (mc *MultiplexedDTLSConn) Dial(raddr net.Addr) (net.Conn, error) {
return mc.listener.Dial(raddr)
}