Skip to content

Commit

Permalink
feat: support TLS server
Browse files Browse the repository at this point in the history
  • Loading branch information
andyl committed Apr 2, 2024
1 parent f5e5ef9 commit 0be1a63
Show file tree
Hide file tree
Showing 231 changed files with 41,202 additions and 5 deletions.
5 changes: 5 additions & 0 deletions gnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,11 @@ var MaxStreamBufferCap = 64 * 1024 // 64KB
func Run(eventHandler EventHandler, protoAddr string, opts ...Option) (err error) {
options := loadOptions(opts...)

// upgrade to TLS EventHandler
if options.TLSConfig != nil {
eventHandler = &tlsEventHandler{EventHandler: eventHandler, tlsConfig: options.TLSConfig}
}

logger, logFlusher := logging.GetDefaultLogger(), logging.GetDefaultFlusher()
if options.Logger == nil {
if options.LogPath != "" {
Expand Down
67 changes: 64 additions & 3 deletions gnet_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"bufio"
"bytes"
"context"
"crypto/tls"
"encoding/binary"
"errors"
"io"
Expand Down Expand Up @@ -38,6 +39,14 @@ func TestServe(t *testing.T) {
// the engine will echo back the data.
// waits for graceful connection closing.
t.Run("poll", func(t *testing.T) {
t.Run("tls", func(t *testing.T) {
t.Run("1-loop", func(t *testing.T) {
testTLSServe(t, "tcp", ":9991", false, false, false, false, false, 10, RoundRobin)
})
t.Run("N-loop", func(t *testing.T) {
testTLSServe(t, "tcp", ":9992", false, false, true, false, false, 10, LeastConnections)
})
})
t.Run("tcp", func(t *testing.T) {
t.Run("1-loop", func(t *testing.T) {
testServe(t, "tcp", ":9991", false, false, false, false, false, 10, RoundRobin)
Expand Down Expand Up @@ -105,6 +114,14 @@ func TestServe(t *testing.T) {
})

t.Run("poll-reuseport", func(t *testing.T) {
t.Run("tls", func(t *testing.T) {
t.Run("1-loop", func(t *testing.T) {
testTLSServe(t, "tcp", ":9991", true, false, false, false, false, 10, RoundRobin)
})
t.Run("N-loop", func(t *testing.T) {
testTLSServe(t, "tcp", ":9992", true, false, true, false, false, 10, LeastConnections)
})
})
t.Run("tcp", func(t *testing.T) {
t.Run("1-loop", func(t *testing.T) {
testServe(t, "tcp", ":9991", true, false, false, false, false, 10, RoundRobin)
Expand Down Expand Up @@ -172,6 +189,14 @@ func TestServe(t *testing.T) {
})

t.Run("poll-reuseaddr", func(t *testing.T) {
t.Run("tls", func(t *testing.T) {
t.Run("1-loop", func(t *testing.T) {
testTLSServe(t, "tcp", ":9991", false, true, false, false, false, 10, RoundRobin)
})
t.Run("N-loop", func(t *testing.T) {
testTLSServe(t, "tcp", ":9992", false, true, true, false, false, 10, LeastConnections)
})
})
t.Run("tcp", func(t *testing.T) {
t.Run("1-loop", func(t *testing.T) {
testServe(t, "tcp", ":9991", false, true, false, false, false, 10, RoundRobin)
Expand Down Expand Up @@ -238,6 +263,7 @@ type testServer struct {
clientActive int32
disconnected int32
workerPool *goPool.Pool
isTLS bool
}

func (s *testServer) OnBoot(eng Engine) (action Action) {
Expand Down Expand Up @@ -365,7 +391,7 @@ func (s *testServer) OnTick() (delay time.Duration, action Action) {
for i := 0; i < s.nclients; i++ {
atomic.AddInt32(&s.clientActive, 1)
go func() {
startClient(s.tester, s.network, s.addr, s.multicore, s.async)
startClient(s.tester, s.network, s.addr, s.multicore, s.async, s.isTLS)
atomic.AddInt32(&s.clientActive, -1)
}()
}
Expand All @@ -377,6 +403,32 @@ func (s *testServer) OnTick() (delay time.Duration, action Action) {
return
}

func testTLSServe(t *testing.T, network, addr string, reuseport, reuseaddr, multicore, async, writev bool, nclients int, lb LoadBalancing) {
ts := &testServer{
tester: t,
network: network,
addr: addr,
multicore: multicore,
async: async,
writev: writev,
nclients: nclients,
workerPool: goPool.Default(),
isTLS: true,
}
err := Run(ts,
network+"://"+addr,
WithLockOSThread(async),
WithMulticore(multicore),
WithReusePort(reuseport),
WithReuseAddr(reuseaddr),
WithTicker(true),
WithTCPKeepAlive(time.Minute*1),
WithTCPNoDelay(TCPDelay),
WithLoadBalancing(lb),
WithTLSConfig(getServerConfig()))
assert.NoError(t, err)
}

func testServe(t *testing.T, network, addr string, reuseport, reuseaddr, multicore, async, writev bool, nclients int, lb LoadBalancing) {
ts := &testServer{
tester: t,
Expand All @@ -401,9 +453,18 @@ func testServe(t *testing.T, network, addr string, reuseport, reuseaddr, multico
assert.NoError(t, err)
}

func startClient(t *testing.T, network, addr string, multicore, async bool) {
func startClient(t *testing.T, network, addr string, multicore, async bool, isTLS bool) {
rand.Seed(time.Now().UnixNano())
c, err := net.Dial(network, addr)
var (
c net.Conn
err error
)
if isTLS {
// TLS client use golang tls.Dial
c, err = tls.Dial(network, addr, getGoClientTLSConfig())
} else {
c, err = net.Dial(network, addr)
}
require.NoError(t, err)
defer c.Close()
rd := bufio.NewReader(c)
Expand Down
5 changes: 3 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ require (
github.com/valyala/bytebufferpool v1.0.0
go.uber.org/zap v1.21.0 // don't upgrade this one
golang.org/x/sync v0.6.0
golang.org/x/sys v0.16.0
golang.org/x/sys v0.18.0
gopkg.in/natefinch/lumberjack.v2 v2.2.1
)

Expand All @@ -15,7 +15,8 @@ require (
github.com/pmezard/go-difflib v1.0.0 // indirect
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
golang.org/x/crypto v0.21.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

go 1.17
go 1.21
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8=
go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
Expand All @@ -55,6 +57,8 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
Expand Down
11 changes: 11 additions & 0 deletions options.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"time"

"github.com/panjf2000/gnet/v2/pkg/logging"
"github.com/panjf2000/gnet/v2/pkg/tls"
)

// Option is a function that will set up option.
Expand Down Expand Up @@ -122,6 +123,9 @@ type Options struct {
// Logger is the customized logger for logging info, if it is not set,
// then gnet will use the default logger powered by go.uber.org/zap.
Logger logging.Logger

// TLSConfig support TLS
TLSConfig *tls.Config
}

// WithOptions sets up all options.
Expand Down Expand Up @@ -249,3 +253,10 @@ func WithMulticastInterfaceIndex(idx int) Option {
opts.MulticastInterfaceIndex = idx
}
}

// WithTLSConfig sets support TLS
func WithTLSConfig(tlsConfig *tls.Config) Option {
return func(opts *Options) {
opts.TLSConfig = tlsConfig
}
}
109 changes: 109 additions & 0 deletions pkg/tls/alert.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tls

import "strconv"

// An AlertError is a TLS alert.
//
// When using a QUIC transport, QUICConn methods will return an error
// which wraps AlertError rather than sending a TLS alert.
type AlertError uint8

func (e AlertError) Error() string {
return alert(e).String()
}

type alert uint8

const (
// alert level
alertLevelWarning = 1
alertLevelError = 2
)

const (
alertCloseNotify alert = 0
alertUnexpectedMessage alert = 10
alertBadRecordMAC alert = 20
alertDecryptionFailed alert = 21
alertRecordOverflow alert = 22
alertDecompressionFailure alert = 30
alertHandshakeFailure alert = 40
alertBadCertificate alert = 42
alertUnsupportedCertificate alert = 43
alertCertificateRevoked alert = 44
alertCertificateExpired alert = 45
alertCertificateUnknown alert = 46
alertIllegalParameter alert = 47
alertUnknownCA alert = 48
alertAccessDenied alert = 49
alertDecodeError alert = 50
alertDecryptError alert = 51
alertExportRestriction alert = 60
alertProtocolVersion alert = 70
alertInsufficientSecurity alert = 71
alertInternalError alert = 80
alertInappropriateFallback alert = 86
alertUserCanceled alert = 90
alertNoRenegotiation alert = 100
alertMissingExtension alert = 109
alertUnsupportedExtension alert = 110
alertCertificateUnobtainable alert = 111
alertUnrecognizedName alert = 112
alertBadCertificateStatusResponse alert = 113
alertBadCertificateHashValue alert = 114
alertUnknownPSKIdentity alert = 115
alertCertificateRequired alert = 116
alertNoApplicationProtocol alert = 120
)

var alertText = map[alert]string{
alertCloseNotify: "close notify",
alertUnexpectedMessage: "unexpected message",
alertBadRecordMAC: "bad record MAC",
alertDecryptionFailed: "decryption failed",
alertRecordOverflow: "record overflow",
alertDecompressionFailure: "decompression failure",
alertHandshakeFailure: "handshake failure",
alertBadCertificate: "bad certificate",
alertUnsupportedCertificate: "unsupported certificate",
alertCertificateRevoked: "revoked certificate",
alertCertificateExpired: "expired certificate",
alertCertificateUnknown: "unknown certificate",
alertIllegalParameter: "illegal parameter",
alertUnknownCA: "unknown certificate authority",
alertAccessDenied: "access denied",
alertDecodeError: "error decoding message",
alertDecryptError: "error decrypting message",
alertExportRestriction: "export restriction",
alertProtocolVersion: "protocol version not supported",
alertInsufficientSecurity: "insufficient security level",
alertInternalError: "internal error",
alertInappropriateFallback: "inappropriate fallback",
alertUserCanceled: "user canceled",
alertNoRenegotiation: "no renegotiation",
alertMissingExtension: "missing extension",
alertUnsupportedExtension: "unsupported extension",
alertCertificateUnobtainable: "certificate unobtainable",
alertUnrecognizedName: "unrecognized name",
alertBadCertificateStatusResponse: "bad certificate status response",
alertBadCertificateHashValue: "bad certificate hash value",
alertUnknownPSKIdentity: "unknown PSK identity",
alertCertificateRequired: "certificate required",
alertNoApplicationProtocol: "no application protocol",
}

func (e alert) String() string {
s, ok := alertText[e]
if ok {
return "tls: " + s
}
return "tls: alert(" + strconv.Itoa(int(e)) + ")"
}

func (e alert) Error() string {
return e.String()
}
Loading

0 comments on commit 0be1a63

Please sign in to comment.