Skip to content

Commit efbb10b

Browse files
committed
fix: properly parse peer address
After switch to Go's http/server, the peer address comes wrapped, so use a different method to unwrap it. The tests haven't caught that, as they were using gRPC's server, so switch tests to use same approach as production, ans enable HTTP/2 over TLS, as otherwise h2c is a mess, and it doesn't abort connections properly for test purposes. Signed-off-by: Andrey Smirnov <[email protected]>
1 parent cf39974 commit efbb10b

File tree

8 files changed

+219
-70
lines changed

8 files changed

+219
-70
lines changed

go.mod

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,11 @@ require (
1010
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10
1111
github.com/prometheus/client_golang v1.20.4
1212
github.com/siderolabs/discovery-api v0.1.4
13-
github.com/siderolabs/discovery-client v0.1.9
13+
github.com/siderolabs/discovery-client v0.1.10
1414
github.com/siderolabs/gen v0.5.0
1515
github.com/siderolabs/go-debug v0.4.0
1616
github.com/stretchr/testify v1.9.0
1717
go.uber.org/zap v1.27.0
18-
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
1918
golang.org/x/net v0.28.0
2019
golang.org/x/sync v0.8.0
2120
golang.org/x/time v0.6.0

go.sum

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjR
4242
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
4343
github.com/siderolabs/discovery-api v0.1.4 h1:2fMEFSMiWaD1zDiBDY5md8VxItvL1rDQRSOfeXNjYKc=
4444
github.com/siderolabs/discovery-api v0.1.4/go.mod h1:kaBy+G42v2xd/uAF/NIe383sjNTBE2AhxPTyi9SZI0s=
45-
github.com/siderolabs/discovery-client v0.1.9 h1:yDzvts++Nf/2qczdDUfU5GAibkEIgz/eo9RPG/k/rOc=
46-
github.com/siderolabs/discovery-client v0.1.9/go.mod h1:Ew1z07eyJwqNwum84IKYH4S649KEKK5WUmRW49HlXS8=
45+
github.com/siderolabs/discovery-client v0.1.10 h1:bTAvFLiISSzVXyYL1cIgAz8cPYd9ZfvhxwdebgtxARA=
46+
github.com/siderolabs/discovery-client v0.1.10/go.mod h1:Ew1z07eyJwqNwum84IKYH4S649KEKK5WUmRW49HlXS8=
4747
github.com/siderolabs/gen v0.5.0 h1:Afdjx+zuZDf53eH5DB+E+T2JeCwBXGinV66A6osLgQI=
4848
github.com/siderolabs/gen v0.5.0/go.mod h1:1GUMBNliW98Xeq8GPQeVMYqQE09LFItE8enR3wgMh3Q=
4949
github.com/siderolabs/go-debug v0.4.0 h1:pbFt6Rzumm90s3GvbRer7yIxFNc0gQ94I53omkqswHA=
@@ -56,8 +56,6 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
5656
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
5757
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
5858
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
59-
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M=
60-
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
6159
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
6260
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
6361
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=

internal/grpclog/grpclog.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Copyright (c) 2024 Sidero Labs, Inc.
2+
//
3+
// Use of this software is governed by the Business Source License
4+
// included in the LICENSE file.
5+
6+
// Package grpclog provides a logger that logs to a zap logger.
7+
package grpclog
8+
9+
import (
10+
"context"
11+
"fmt"
12+
13+
"github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/logging"
14+
"go.uber.org/zap"
15+
)
16+
17+
// Adapter returns a logging.Logger that logs to the provided zap logger.
18+
func Adapter(l *zap.Logger) logging.Logger {
19+
return logging.LoggerFunc(func(_ context.Context, lvl logging.Level, msg string, fields ...any) {
20+
f := make([]zap.Field, 0, len(fields)/2)
21+
22+
for i := 0; i < len(fields); i += 2 {
23+
key := fields[i].(string) //nolint:forcetypeassert,errcheck
24+
value := fields[i+1]
25+
26+
switch v := value.(type) {
27+
case string:
28+
f = append(f, zap.String(key, v))
29+
case int:
30+
f = append(f, zap.Int(key, v))
31+
case bool:
32+
f = append(f, zap.Bool(key, v))
33+
default:
34+
f = append(f, zap.Any(key, v))
35+
}
36+
}
37+
38+
logger := l.WithOptions(zap.AddCallerSkip(1)).With(f...)
39+
40+
switch lvl {
41+
case logging.LevelDebug:
42+
logger.Debug(msg)
43+
case logging.LevelInfo:
44+
logger.Info(msg)
45+
case logging.LevelWarn:
46+
logger.Warn(msg)
47+
case logging.LevelError:
48+
logger.Error(msg)
49+
default:
50+
panic(fmt.Sprintf("unknown level %v", lvl))
51+
}
52+
})
53+
}

pkg/server/addr.go

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,8 @@ package server
77

88
import (
99
"context"
10-
"net"
1110
"net/netip"
1211

13-
"go4.org/netipx"
1412
"google.golang.org/grpc/metadata"
1513
"google.golang.org/grpc/peer"
1614
)
@@ -38,10 +36,8 @@ func PeerAddress(ctx context.Context) netip.Addr {
3836
}
3937

4038
if peer, ok := peer.FromContext(ctx); ok {
41-
if addr, ok := peer.Addr.(*net.TCPAddr); ok {
42-
if ip, ok := netipx.FromStdIP(addr.IP); ok {
43-
return ip
44-
}
39+
if addrPort, err := netip.ParseAddrPort(peer.Addr.String()); err == nil {
40+
return addrPort.Addr()
4541
}
4642
}
4743

pkg/server/cert_test.go

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
// Copyright (c) 2024 Sidero Labs, Inc.
2+
//
3+
// Use of this software is governed by the Business Source License
4+
// included in the LICENSE file.
5+
6+
package server_test
7+
8+
import (
9+
"crypto/ecdsa"
10+
"crypto/elliptic"
11+
"crypto/rand"
12+
"crypto/tls"
13+
"crypto/x509"
14+
"crypto/x509/pkix"
15+
"math/big"
16+
"net"
17+
"sync"
18+
"testing"
19+
"time"
20+
21+
"github.com/stretchr/testify/require"
22+
)
23+
24+
var onceCert = sync.OnceValues(func() (*tls.Certificate, error) {
25+
priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
26+
if err != nil {
27+
return nil, err
28+
}
29+
30+
keyUsage := x509.KeyUsageDigitalSignature
31+
notBefore := time.Now()
32+
notAfter := notBefore.Add(time.Hour)
33+
34+
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
35+
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
36+
if err != nil {
37+
return nil, err
38+
}
39+
40+
template := x509.Certificate{
41+
SerialNumber: serialNumber,
42+
Subject: pkix.Name{
43+
Organization: []string{"SideroLabs Testing"},
44+
},
45+
NotBefore: notBefore,
46+
NotAfter: notAfter,
47+
48+
KeyUsage: keyUsage,
49+
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
50+
BasicConstraintsValid: true,
51+
IPAddresses: []net.IP{net.IPv4(127, 0, 0, 1), net.IPv6loopback},
52+
}
53+
54+
derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
55+
if err != nil {
56+
return nil, err
57+
}
58+
59+
cert := tls.Certificate{
60+
Certificate: [][]byte{derBytes},
61+
PrivateKey: priv,
62+
}
63+
64+
cert.Leaf, err = x509.ParseCertificate(derBytes)
65+
if err != nil {
66+
return nil, err
67+
}
68+
69+
return &cert, nil
70+
})
71+
72+
func GetServerTLSConfig(t *testing.T) *tls.Config {
73+
t.Helper()
74+
75+
cert, err := onceCert()
76+
require.NoError(t, err)
77+
78+
return &tls.Config{
79+
Certificates: []tls.Certificate{*cert},
80+
MinVersion: tls.VersionTLS12,
81+
}
82+
}
83+
84+
func GetClientTLSConfig(t *testing.T) *tls.Config {
85+
t.Helper()
86+
87+
cert, err := onceCert()
88+
require.NoError(t, err)
89+
90+
certPool := x509.NewCertPool()
91+
certPool.AddCert(cert.Leaf)
92+
93+
return &tls.Config{
94+
RootCAs: certPool,
95+
MinVersion: tls.VersionTLS12,
96+
}
97+
}

pkg/server/client_test.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ func TestClient(t *testing.T) {
6060
ClusterID: clusterID,
6161
AffiliateID: affiliate1,
6262
TTL: time.Minute,
63-
Insecure: true,
63+
TLSConfig: GetClientTLSConfig(t),
6464
})
6565
require.NoError(t, err)
6666

@@ -70,7 +70,7 @@ func TestClient(t *testing.T) {
7070
ClusterID: clusterID,
7171
AffiliateID: affiliate2,
7272
TTL: time.Minute,
73-
Insecure: true,
73+
TLSConfig: GetClientTLSConfig(t),
7474
})
7575
require.NoError(t, err)
7676

@@ -239,7 +239,7 @@ func TestClient(t *testing.T) {
239239
ClusterID: clusterID,
240240
AffiliateID: affiliate1,
241241
TTL: time.Second,
242-
Insecure: true,
242+
TLSConfig: GetClientTLSConfig(t),
243243
})
244244
require.NoError(t, err)
245245

@@ -249,7 +249,7 @@ func TestClient(t *testing.T) {
249249
ClusterID: clusterID,
250250
AffiliateID: affiliate2,
251251
TTL: time.Minute,
252-
Insecure: true,
252+
TLSConfig: GetClientTLSConfig(t),
253253
})
254254
require.NoError(t, err)
255255

@@ -392,7 +392,7 @@ func clusterSimulator(t *testing.T, endpoint string, logger *zap.Logger, numAffi
392392
AffiliateID: fmt.Sprintf("affiliate-%d", i),
393393
ClientVersion: "v0.0.1",
394394
TTL: 10 * time.Second,
395-
Insecure: true,
395+
TLSConfig: GetClientTLSConfig(t),
396396
})
397397
require.NoError(t, err)
398398
}
@@ -557,7 +557,7 @@ func TestClientRedirect(t *testing.T) {
557557
ClusterID: clusterID,
558558
AffiliateID: affiliate1,
559559
TTL: time.Minute,
560-
Insecure: true,
560+
TLSConfig: GetClientTLSConfig(t),
561561
})
562562
require.NoError(t, err)
563563

@@ -567,7 +567,7 @@ func TestClientRedirect(t *testing.T) {
567567
ClusterID: clusterID,
568568
AffiliateID: affiliate2,
569569
TTL: time.Minute,
570-
Insecure: true,
570+
TLSConfig: GetClientTLSConfig(t),
571571
})
572572
require.NoError(t, err)
573573

0 commit comments

Comments
 (0)