拨开荷叶行,寻梦已然成。仙女莲花里,翩翩白鹭情。
IMG-LOGO
主页 文章列表 尝试通过UDP执行TLS:有关大讯息的wsarecv错误

尝试通过UDP执行TLS:有关大讯息的wsarecv错误

白鹭 - 2022-03-04 2298 0 0

我想基于 udp 获取 tls conn,就像:

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: 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

附录: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-----

服务密钥.pem

-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgmH BleetLN1fK0dy
JpedWG8C2yxtb7gEEAwvdwXf6FihRANCAAQyl1/gWhTxZ3rS/XJOMLHhmkQp64Et
PrEgq9SjKDpWBZQC kNZdM5xzJrv3bLqcyOSJywZfEpTZzW7sxko4maB
-----END PRIVATE KEY-----

我试试set udp conn的buff,没用!证书只有 558 Bytes,但 UDP 的容量为 65536 Bytes。然后,我除错发现:在crypt/tls/conn.go>readRecordOrCCS c.readFromUntil(c.conn, recordHeaderLen)recordHeaderLen是常数5,它加bytes.MinRead;所以读者爱好者的 len 是 517。实际上资料大小约为 700 字节。所以?我该怎么办?

uj5u.com热心网友回复:

您不能明智地期望使事情起作用:TLS(和 SSL)旨在使用另一个协议的应用层来执行。
简而言之,这意味着虽然 TLS 忽略了特定协议传输其字节的方式,但作为应用层的客户端,它期望底层堆栈具有两个属性:传输任意不透明的资料流,确保稳健性和不透明性。订单交付。在 TCP/IP 世界中,这意味着 TCP,因为 UDP 不提供 TLS 所期望的任何属性。

尽管如此,一些解决方案确实成功地在 UDP 上使用了 TLS,OpenVPN就是一个典型的例子——它使用 TLS 进行握手和初始密钥交换,同时将 UDP 作为默认和推荐的传输协议——但它们都有一层通过 UDP 实作,它“武装”了它通常在 TCP 中发现的属性:这些层处理丢弃、重新排序、复制和损坏的 UDP 帧,“汇出”到上层可以用于应用层的协议。

这基本上意味着,如果您在通过 UDP 使用 TLS 之后,您首先需要实作具有界面的自定义型别,该net.Conn界面将使用 UDP 关联来回铲字节并向其客户端“汇出”具有鲁棒性和按顺序交付的特性——就像net.TCPConn这样。

uj5u.com热心网友回复:

我知道了!

只需使 udp conn 成为流 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)
}

标签:

0 评论

发表评论

您的电子邮件地址不会被公开。 必填的字段已做标记 *