I want get tls conn base on udp, just like:
package main
import (
"crypto/tls"
"fmt"
"io"
"net"
"time"
)
func handleConn(conn net.Conn) {
defer conn.Close()
var buf []byte = make([]byte, 2000)
for {
if n, err := conn.Read(buf); err != nil && err != io.EOF {
panic(err)
} else {
conn.Write(buf[:n])
}
}
}
func server() {
cert, err := tls.LoadX509KeyPair("./serve.cert.pem", "./serve.key.pem")
if err != nil {
panic(err)
}
config := &tls.Config{Certificates: []tls.Certificate{cert}}
conn, err := net.DialUDP("udp", &net.UDPAddr{Port: 19986}, &net.UDPAddr{Port: 19987})
if err != nil {
panic(err)
}
tconn := tls.Server(conn, config)
defer tconn.Close()
if err = tconn.Handshake(); err != nil {
panic(err)
}
handleConn(tconn)
}
func main() {
go server()
time.Sleep(time.Second)
client()
}
func client() {
conf := &tls.Config{
InsecureSkipVerify: true,
}
conn, err := net.DialUDP("udp", &net.UDPAddr{Port: 19987}, &net.UDPAddr{Port: 19986})
if err != nil {
panic(err)
}
tconn := tls.Client(conn, conf)
defer tconn.Close()
if err = tconn.Handshake(); err != nil {
panic(err)
}
_, err = conn.Write([]byte("hello"))
if err != nil {
panic(err)
}
buf := make([]byte, 100)
n, err := conn.Read(buf)
if err != nil {
panic(err)
}
fmt.Println(string(buf[:n]))
}
panic:
panic: read udp 127.0.0.1:19987->127.0.0.1:19986: wsarecv: A message sent on a datagram socket was larger than the internal message buffer or some other network limit, or the buffer used to receive a datagram into was smaller than the datagram itself.
goroutine 1 [running]:
main.client()
D:/OneDrive/code/go/ctest/main.go:65 0x2d1
main.main()
D:/OneDrive/code/go/ctest/main.go:49 0x34
exit status 2
Appendix: serve.cert.pem
-----BEGIN CERTIFICATE-----
MIIBbjCCARSgAwIBAgIRAI jBYEYS5aBXDUedBt7PKYwCgYIKoZIzj0EAwIwEjEQ
MA4GA1UEChMHQWNtZSBDbzAeFw0yMjAxMDkxNzQxMjBaFw0yMzAxMDkxNzQxMjBa
MBIxEDAOBgNVBAoTB0FjbWUgQ28wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQy
l1/gWhTxZ3rS/XJOMLHhmkQp64EtPrEgq9SjKDpWBZQC kNZdM5xzJrv3bLqcyOS
JywZfEpTZzW7sxko4maBo0swSTAOBgNVHQ8BAf8EBAMCB4AwEwYDVR0lBAwwCgYI
KwYBBQUHAwEwDAYDVR0TAQH/BAIwADAUBgNVHREEDTALgglsb2NhbGhvc3QwCgYI
KoZIzj0EAwIDSAAwRQIhAICxMC8o603GwL3bf42EXrtPP5/LtEIc/hjdJpilqc3b
AiBTEdrE /oCgUjsxV2RFj1 42CTGtcav4sJyCPjme0N/w==
-----END CERTIFICATE-----
serve.key.pem
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgmH BleetLN1fK0dy
JpedWG8C2yxtb7gEEAwvdwXf6FihRANCAAQyl1/gWhTxZ3rS/XJOMLHhmkQp64Et
PrEgq9SjKDpWBZQC kNZdM5xzJrv3bLqcyOSJywZfEpTZzW7sxko4maB
-----END PRIVATE KEY-----
I try set udp conn's buff, useless!
The certificate only 558 Bytes, but the UDP has a capacity of 65536 Bytes. then, I debug found: in crypt/tls/conn.go>readRecordOrCCS c.readFromUntil(c.conn, recordHeaderLen), the recordHeaderLen is constant 5, it add bytes.MinRead; so the reader buff's len is 517. Actually data size about 700 Bytes.
So? What should I do?
CodePudding user response:
You cannot sensibly expect to make the thing work: TLS (and SSL) is designed to be carried out using the application layer of another protocol.
What this means in simpler terms is that while TLS is oblivious to what particular protocol transports its bytes, as a client of the application layer, it expects two properties from the underlying stack: it transports arbitrary opaque streams of data, ensuring robustness and in-order delivery.
In the TCP/IP world, this means TCP because UDP does not provide neither of the properties TLS expects.
Still, some solutions do successfully employ TLS over UDP, with OpenVPN being a prime example of this—it uses TLS for handshake and initial key exchange while having UDP as its default, and recommended, transport protocol,—but all of them have a layer implemented over UDP which "arms" it with the properties typically found in TCP: such layers deal with dropped, reordered, duplicated and corrupted UDP frames, "exporting" to the upper layer a protocol which is OK to use for application layer.
This basically means than if you're after using TLS over UDP, you first need to implemet a custom type having the net.Conn interface which would use a UDP association to shovel the bytes back and forth and "export" to its client a connection which has the properties of robustness and in-order delivery—just as net.TCPConn does.
CodePudding user response:
I GOT IT!
just make udp conn become to stream io.
package main
import (
"bufio"
"crypto/tls"
"fmt"
"io"
"net"
"time"
)
func handleConn(conn net.Conn) {
defer conn.Close()
var buf []byte = make([]byte, 2000)
for {
if n, err := conn.Read(buf); err != nil && err != io.EOF {
panic(err)
} else {
fmt.Println(string(buf[:n]))
conn.Write(append([]byte("got: "), buf[:n]...))
}
}
}
func server() {
cert, err := tls.LoadX509KeyPair("./serve.cert.pem", "./serve.key.pem")
if err != nil {
panic(err)
}
config := &tls.Config{Certificates: []tls.Certificate{cert}}
conn, err := net.DialUDP("udp", &net.UDPAddr{Port: 19986}, &net.UDPAddr{Port: 19987})
if err != nil {
panic(err)
}
sconn := NewSconn(conn)
tconn := tls.Server(sconn, config)
defer tconn.Close()
handleConn(tconn)
}
func main() {
go server()
time.Sleep(time.Second)
client()
}
func client() {
conf := &tls.Config{
InsecureSkipVerify: true,
CipherSuites: []uint16{
tls.TLS_AES_128_GCM_SHA256,
},
}
conn, err := net.DialUDP("udp", &net.UDPAddr{Port: 19987}, &net.UDPAddr{Port: 19986})
if err != nil {
panic(err)
}
sconn := NewSconn(conn)
tconn := tls.Client(sconn, conf)
defer tconn.Close()
_, err = tconn.Write([]byte("hello"))
if err != nil {
panic(err)
}
buf := make([]byte, 100)
n, err := tconn.Read(buf)
if err != nil {
panic(err)
}
fmt.Println(string(buf[:n]))
}
//
//
//
//
// --------------------------------------------------
type sconn struct {
conn net.Conn
reader *bufio.Reader
}
func NewSconn(conn net.Conn) *sconn {
return &sconn{
conn: conn,
reader: bufio.NewReader(conn),
}
}
func (s *sconn) Read(b []byte) (n int, err error) {
return s.reader.Read(b)
}
func (s *sconn) Write(b []byte) (n int, err error) {
return s.conn.Write(b)
}
func (s *sconn) Close() error {
return s.conn.Close()
}
func (s *sconn) LocalAddr() net.Addr {
return s.conn.LocalAddr()
}
func (s *sconn) RemoteAddr() net.Addr {
return s.conn.RemoteAddr()
}
func (s *sconn) SetDeadline(t time.Time) error {
return s.conn.SetDeadline(t)
}
func (s *sconn) SetReadDeadline(t time.Time) error {
return s.conn.SetReadDeadline(t)
}
func (s *sconn) SetWriteDeadline(t time.Time) error {
return s.conn.SetWriteDeadline(t)
}
