refact: remove func alias, comsoliation define to types
Kim committed
Mar 5, 2026 at 10:39 UTC
1a0bc802ec8b00d37ce540e4d798482c3d20b634
20 files changed
+104
-192
cmd/portal-tunnel/main.go
+4
-5
@@ -17,7 +17,6 @@ import (
17
"github.com/rs/zerolog"
18
"github.com/rs/zerolog/log"
19
20
- "gosuda.org/portal/portal/netutil"
20
"gosuda.org/portal/sdk"
21
"gosuda.org/portal/types"
22
)
@@ -64,7 +63,7 @@ func runTunnel() error {
63
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
64
defer stop()
65
67
- relayURLs := netutil.ParseURLs(flagRelayURLs)
66
+ relayURLs := types.ParseURLs(flagRelayURLs)
67
if len(relayURLs) == 0 {
68
return errors.New("no relay URLs provided")
69
}
@@ -87,7 +86,7 @@ func runTunnel() error {
86
listener, err := sdkClient.Listen(
87
flagName,
88
types.WithDescription(flagDesc),
90
- types.WithTags(netutil.ParseURLs(flagTags)),
89
+ types.WithTags(types.ParseURLs(flagTags)),
90
types.WithOwner(flagOwner),
91
types.WithThumbnail(flagThumbnail),
92
types.WithHide(flagHide),
@@ -169,7 +168,7 @@ loop:
168
func normalizeRelayURLsForReverseConnect(relayURLs []string) ([]string, error) {
169
normalized := make([]string, 0, len(relayURLs))
170
for _, relayURL := range relayURLs {
172
- normalizedURL, err := netutil.NormalizeRelayAPIURL(relayURL)
171
+ normalizedURL, err := types.NormalizeRelayAPIURL(relayURL)
172
if err != nil {
173
return nil, fmt.Errorf("invalid relay URL %q: %w", relayURL, err)
174
}
@@ -188,7 +187,7 @@ var bufferPool = sync.Pool{
187
func proxyConnection(ctx context.Context, localAddr string, relayConn net.Conn) error {
188
defer relayConn.Close()
189
191
- targetAddr, err := netutil.NormalizeTargetAddr(localAddr)
190
+ targetAddr, err := types.NormalizeTargetAddr(localAddr)
191
if err != nil {
192
return fmt.Errorf("invalid --host value %q: %w", localAddr, err)
193
}
cmd/relay-server/main.go
+7
-11
@@ -15,9 +15,9 @@ import (
15
"github.com/rs/zerolog/log"
16
17
"gosuda.org/portal/portal"
18
- "gosuda.org/portal/portal/netutil"
18
"gosuda.org/portal/portal/policy"
19
"gosuda.org/portal/portal/sni"
20
+ "gosuda.org/portal/types"
21
)
22
23
const (
@@ -51,9 +51,9 @@ func main() {
51
}
52
bootstrapsCSV := trimmedEnv("BOOTSTRAP_URIS")
53
if bootstrapsCSV == "" {
54
- bootstrapsCSV = netutil.DefaultBootstrapFrom(portalURL)
54
+ bootstrapsCSV = types.DefaultBootstrapFrom(portalURL)
55
}
56
- sniPort := netutil.ParsePortNumber(os.Getenv("SNI_PORT"), defaultSNIPort)
56
+ sniPort := types.ParsePortNumber(os.Getenv("SNI_PORT"), defaultSNIPort)
57
keylessDir := trimmedEnv("KEYLESS_DIR")
58
if keylessDir == "" {
59
keylessDir = defaultKeylessDir
@@ -75,8 +75,8 @@ func main() {
75
flag.StringVar(&cfg.CloudflareToken, "cloudflare-token", cloudflareToken, "Cloudflare DNS API token (Zone:Read + DNS:Edit) (env: CLOUDFLARE_TOKEN)")
76
flag.Parse()
77
78
- cfg.Bootstraps = netutil.ParseURLs(bootstrapsCSV)
79
- parsedTrustedProxyCIDRs, err := parseTrustedProxyCIDRs(cfg.TrustedProxyCIDRs)
78
+ cfg.Bootstraps = types.ParseURLs(bootstrapsCSV)
79
+ parsedTrustedProxyCIDRs, err := policy.ParseTrustedProxyCIDRs(cfg.TrustedProxyCIDRs)
80
if err != nil {
81
log.Fatal().Err(err).Msg("parse trusted proxy CIDRs")
82
}
@@ -98,8 +98,8 @@ func runServer(cfg relayServerConfig) error {
98
Strs("bootstrap_uris", cfg.Bootstraps).
99
Msg("[server] frontend configuration")
100
101
- rootHost := netutil.PortalRootHost(cfg.PortalURL)
102
- apiUpstreamAddr := netutil.LoopbackForwardAddr(fmt.Sprintf(":%d", cfg.AdminPort))
101
+ rootHost := types.PortalRootHost(cfg.PortalURL)
102
+ apiUpstreamAddr := types.LoopbackForwardAddr(fmt.Sprintf(":%d", cfg.AdminPort))
103
serv, err := portal.NewRelayServer(ctx, cfg.Bootstraps, sniListenAddr, rootHost, cfg.KeylessDir, cfg.CloudflareToken)
104
if err != nil {
105
return fmt.Errorf("create relay server: %w", err)
@@ -226,7 +226,3 @@ func parseBoolEnv(name string) bool {
226
raw := trimmedEnv(name)
227
return strings.EqualFold(raw, "true") || raw == "1"
228
}
229
-
230
-func parseTrustedProxyCIDRs(raw string) ([]*net.IPNet, error) {
231
- return policy.ParseTrustedProxyCIDRs(raw)
232
-}
cmd/relay-server/registry.go
+1
-1
@@ -65,7 +65,7 @@ func (r *SDKRegistry) handleConnect(w http.ResponseWriter, req *http.Request, re
65
req,
66
registryService,
67
req.URL.Query().Get("lease_id"),
68
- req.Header.Get(portal.ReverseConnectTokenHeader),
68
+ req.Header.Get(types.ReverseConnectTokenHeader),
69
true,
70
)
71
if !ok {
cmd/relay-server/serve.go
+3
-4
@@ -17,7 +17,6 @@ import (
17
18
"gosuda.org/portal/portal"
19
"gosuda.org/portal/portal/keyless"
20
- "gosuda.org/portal/portal/netutil"
20
"gosuda.org/portal/portal/policy"
21
"gosuda.org/portal/types"
22
)
@@ -99,10 +98,10 @@ func serveAPI(addr string, serv *portal.RelayServer, admin *Admin, frontend *Fro
98
})
99
100
// Create the main handler
102
- appDomain := netutil.DefaultAppPattern(cfg.PortalURL)
101
+ appDomain := types.DefaultAppPattern(cfg.PortalURL)
102
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
103
// Handle subdomain requests
105
- if netutil.IsSubdomain(appDomain, r.Host) {
104
+ if types.IsSubdomain(appDomain, r.Host) {
105
log.Debug().
106
Str("host", r.Host).
107
Str("url", r.URL.String()).
@@ -129,7 +128,7 @@ func serveAPI(addr string, serv *portal.RelayServer, admin *Admin, frontend *Fro
128
TLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler)),
129
}
130
acmeManager := serv.GetACMEManager()
132
- rootHost := netutil.PortalRootHost(cfg.PortalURL)
131
+ rootHost := types.PortalRootHost(cfg.PortalURL)
132
srv.TLSConfig = &tls.Config{
133
ClientAuth: tls.RequestClientCert,
134
GetCertificate: func(hello *tls.ClientHelloInfo) (*tls.Certificate, error) {
cmd/relay-server/utils.go
+4
-5
@@ -12,7 +12,6 @@ import (
12
13
"gosuda.org/portal/portal"
14
"gosuda.org/portal/portal/keyless"
15
- "gosuda.org/portal/portal/netutil"
15
"gosuda.org/portal/portal/policy"
16
"gosuda.org/portal/types"
17
)
@@ -195,15 +194,15 @@ func (r *leaseRow) fromLeaseEntry(entry *types.LeaseEntry, admin *Admin, portalU
194
r.FirstSeenISO = entry.FirstSeen.UTC().Format(time.RFC3339)
195
r.TTL = r.formatDuration(time.Until(entry.Expires))
196
linkLabel := identityID
198
- if normalized, ok := netutil.NormalizeServiceName(lease.Name); ok {
197
+ if normalized, ok := types.NormalizeServiceName(lease.Name); ok {
198
linkLabel = normalized
200
- } else if normalized, ok := netutil.NormalizeServiceName(identityID); ok {
199
+ } else if normalized, ok := types.NormalizeServiceName(identityID); ok {
200
linkLabel = normalized
201
}
202
204
- publicHost := netutil.PortalRootHost(portalURL)
203
+ publicHost := types.PortalRootHost(portalURL)
204
if publicHost == "" {
206
- publicHost = netutil.PortalHostPort(portalURL)
205
+ publicHost = types.PortalHostPort(portalURL)
206
}
207
if linkLabel != "" && publicHost != "" {
208
r.Link = fmt.Sprintf("//%s.%s/", linkLabel, publicHost)
portal/controlplane/registry/service.go
+1
-1
@@ -128,7 +128,7 @@ func (s *Service) Admit(input AdmissionInput) (AdmissionResult, *types.APIError)
128
// Register creates a new lease and associated SNI route.
129
func (s *Service) Register(input RegisterInput) (types.RegisterResponse, *types.APIError) {
130
name := strings.TrimSpace(input.Name)
131
- if !types.IsValidLeaseName(name) {
131
+ if !types.IsValidServiceName(name) {
132
return types.RegisterResponse{}, apiError(httpStatusBadRequest, "invalid_name", "name must be a DNS label (letters, digits, hyphen; no dots or underscores)")
133
}
134
if !input.TLS {
portal/keyless/client.go
+2
-2
@@ -16,7 +16,7 @@ import (
16
17
keylesstls "github.com/gosuda/keyless_tls/keyless"
18
19
- "gosuda.org/portal/portal/netutil"
19
+ "gosuda.org/portal/types"
20
)
21
22
// BuildClientTLSConfig builds a keyless TLS server config for tunnel-side TLS termination.
@@ -185,7 +185,7 @@ func FetchEndpointCertificateChain(ctx context.Context, endpoint string, serverN
185
tlsConn := tls.Client(rawConn, &tls.Config{
186
MinVersion: tls.VersionTLS12,
187
ServerName: serverName,
188
- InsecureSkipVerify: netutil.IsLocalhost(host),
188
+ InsecureSkipVerify: types.IsLocalhost(host),
189
})
190
defer tlsConn.Close()
191
if err := tlsConn.HandshakeContext(ctx); err != nil {
portal/keyless/signer.go
+2
-12
@@ -5,7 +5,6 @@ import (
5
"errors"
6
"fmt"
7
"os"
8
- "strings"
8
"time"
9
10
ksigner "github.com/gosuda/keyless_tls/relay/signer"
@@ -33,17 +32,8 @@ type Signer struct {
32
keyID string
33
}
34
36
-type Config struct {
37
- KeyFile string
38
-}
39
-
40
-func NewSigner(cfg Config) (*Signer, error) {
41
- keyFile := strings.TrimSpace(cfg.KeyFile)
42
- if keyFile == "" {
43
- return nil, nil
44
- }
45
-
46
- keyPEM, err := os.ReadFile(keyFile)
35
+func NewSigner(KeyFile string) (*Signer, error) {
36
+ keyPEM, err := os.ReadFile(KeyFile)
37
if err != nil {
38
if errors.Is(err, os.ErrNotExist) {
39
return nil, nil
portal/netutil/netutil.go
deleted
-59
@@ -1,59 +0,0 @@
1
-package netutil
2
-
3
-import "gosuda.org/portal/types"
4
-
5
-func NormalizeServiceName(name string) (string, bool) {
6
- return types.NormalizeServiceName(name)
7
-}
8
-
9
-func IsSubdomain(domain, host string) bool {
10
- return types.IsSubdomain(domain, host)
11
-}
12
-
13
-func DefaultAppPattern(base string) string {
14
- return types.DefaultAppPattern(base)
15
-}
16
-
17
-func PortalHostPort(portalURL string) string {
18
- return types.PortalHostPort(portalURL)
19
-}
20
-
21
-func PortalRootHost(portalURL string) string {
22
- return types.PortalRootHost(portalURL)
23
-}
24
-
25
-func IsLocalhost(host string) bool {
26
- return types.IsLocalhost(host)
27
-}
28
-
29
-func DefaultBootstrapFrom(base string) string {
30
- return types.DefaultBootstrapFrom(base)
31
-}
32
-
33
-func ParseURLs(raw string) []string {
34
- return types.ParseURLs(raw)
35
-}
36
-
37
-func ParsePortNumber(raw string, fallback int) int {
38
- return types.ParsePortNumber(raw, fallback)
39
-}
40
-
41
-func LoopbackForwardAddr(listenAddr string) string {
42
- return types.LoopbackForwardAddr(listenAddr)
43
-}
44
-
45
-func IsValidLeaseName(name string) bool {
46
- return types.IsValidLeaseName(name)
47
-}
48
-
49
-func NormalizeRelayAPIURLs(bootstrapServers []string) ([]string, error) {
50
- return types.NormalizeRelayAPIURLs(bootstrapServers)
51
-}
52
-
53
-func NormalizeRelayAPIURL(relayURL string) (string, error) {
54
- return types.NormalizeRelayAPIURL(relayURL)
55
-}
56
-
57
-func NormalizeTargetAddr(targetAddr string) (string, error) {
58
- return types.NormalizeTargetAddr(targetAddr)
59
-}
portal/relay.go
+1
-3
@@ -54,9 +54,7 @@ func NewRelayServer(
54
}
55
server.acmeManager = acmeManager
56
57
- signer, err := keyless.NewSigner(keyless.Config{
58
- KeyFile: keyFile,
59
- })
57
+ signer, err := keyless.NewSigner(keyFile)
58
if err != nil {
59
return nil, fmt.Errorf("configure keyless signer: %w", err)
60
}
portal/reverse_hub.go
+3
-10
@@ -10,14 +10,10 @@ import (
10
11
"github.com/rs/zerolog/log"
12
13
- "gosuda.org/portal/portal/sni"
13
+ "gosuda.org/portal/types"
14
)
15
16
const (
17
- // ReverseKeepaliveMarker keeps idle reverse connections alive
18
- // before they are activated for a real client request.
19
- ReverseKeepaliveMarker = byte(0x00)
20
-
17
// QueueSize is the maximum number of pending reverse connections per lease.
18
QueueSize = 64
19
@@ -36,9 +32,6 @@ const (
32
// ReverseIdleKeepaliveInterval sends an idle keepalive byte to reduce
33
// reverse connection disconnections from intermediate idle timeouts.
34
ReverseIdleKeepaliveInterval = 25 * time.Second
39
-
40
- // ReverseConnectTokenHeader carries reverse auth token on /sdk/connect requests.
41
- ReverseConnectTokenHeader = "X-Portal-Reverse-Token"
35
)
36
37
// ReverseConn wraps a net.Conn with lifecycle management for the connection pool.
@@ -265,7 +258,7 @@ func (h *ReverseHub) AcquireForTLS(leaseID string, timeout time.Duration) (*Reve
258
}
259
// Stop idle keepalive and signal tunnel worker to release this connection.
260
conn.Activate()
268
- err := conn.WriteControlByte(sni.TLSStartMarker, controlWriteTimeout)
261
+ err := conn.WriteControlByte(types.TLSStartMarker, controlWriteTimeout)
262
if err == nil {
263
return conn, nil
264
}
@@ -395,7 +388,7 @@ func (h *ReverseHub) keepAliveWhileIdle(conn *ReverseConn, leaseID string) {
388
case <-conn.active:
389
return
390
case <-ticker.C:
398
- if err := conn.WriteControlByte(ReverseKeepaliveMarker, controlWriteTimeout); err != nil {
391
+ if err := conn.WriteControlByte(types.ReverseKeepaliveMarker, controlWriteTimeout); err != nil {
392
log.Debug().
393
Err(err).
394
Str("lease_id", leaseID).
portal/reverse_hub_test.go
+5
-5
@@ -7,7 +7,7 @@ import (
7
"testing"
8
"time"
9
10
- "gosuda.org/portal/portal/sni"
10
+ "gosuda.org/portal/types"
11
)
12
13
func TestReverseHubAuthorization(t *testing.T) {
@@ -115,7 +115,7 @@ func TestHandleConnectTrimsLeaseIDAndToken(t *testing.T) {
115
case err := <-readErr:
116
t.Fatalf("failed to read marker: %v", err)
117
case marker := <-markerRead:
118
- if marker != sni.TLSStartMarker {
118
+ if marker != types.TLSStartMarker {
119
t.Fatalf("unexpected marker: %d", marker)
120
}
121
case <-time.After(500 * time.Millisecond):
@@ -170,7 +170,7 @@ func TestAcquireForTLSSendsStartMarker(t *testing.T) {
170
case err := <-readErr:
171
t.Fatalf("failed to read marker: %v", err)
172
case b := <-markerRead:
173
- if b != sni.TLSStartMarker {
173
+ if b != types.TLSStartMarker {
174
t.Fatalf("unexpected marker: %d", b)
175
}
176
case <-time.After(500 * time.Millisecond):
@@ -228,7 +228,7 @@ func TestAcquireForTLSPollLoopSendsStartMarker(t *testing.T) {
228
case err := <-readErr:
229
t.Fatalf("failed to read marker: %v", err)
230
case b := <-markerRead:
231
- if b != sni.TLSStartMarker {
231
+ if b != types.TLSStartMarker {
232
t.Fatalf("unexpected marker: %d", b)
233
}
234
case <-time.After(500 * time.Millisecond):
@@ -295,7 +295,7 @@ func TestHandleConnectOffersAuthorizedConn(t *testing.T) {
295
case err := <-readErr:
296
t.Fatalf("failed to read start marker: %v", err)
297
case b := <-markerRead:
298
- if b != sni.TLSStartMarker {
298
+ if b != types.TLSStartMarker {
299
t.Fatalf("unexpected marker: %d", b)
300
}
301
case <-time.After(500 * time.Millisecond):
portal/sni/parser.go
+14
-13
@@ -11,10 +11,11 @@ import (
11
)
12
13
const (
14
- // TLSStartMarker activates a reverse TCP connection for TLS passthrough.
15
- TLSStartMarker = byte(0x02)
16
- // NonTLSStartMarker is reserved for non-TLS protocol marker tests.
17
- NonTLSStartMarker = byte(0x01)
14
+ // TLS wire constants for ClientHello/SNI parsing.
15
+ tlsRecordContentTypeHandshake = byte(0x16)
16
+ tlsHandshakeTypeClientHello = byte(0x01)
17
+ tlsExtensionTypeServerName = uint16(0x0000)
18
+ tlsServerNameTypeHostName = byte(0x00)
19
)
20
21
var (
@@ -39,8 +40,8 @@ func ExtractSNI(r io.Reader) (string, error) {
40
return "", fmt.Errorf("reading TLS header: %w", err)
41
}
42
42
- // Check ContentType (0x16 = Handshake)
43
- if header[0] != 0x16 {
43
+ // Check ContentType (handshake)
44
+ if header[0] != tlsRecordContentTypeHandshake {
45
return "", ErrNotClientHello
46
}
47
@@ -73,8 +74,8 @@ func parseHandshake(data []byte) (string, error) {
74
return "", ErrInvalidTLSRecord
75
}
76
76
- // Check if it's a ClientHello (0x01)
77
- if handshakeType != 0x01 {
77
+ // Check if it's a ClientHello.
78
+ if handshakeType != tlsHandshakeTypeClientHello {
79
return "", ErrNotClientHello
80
}
81
@@ -168,8 +169,8 @@ func parseExtensions(data []byte) (string, error) {
169
return "", ErrInvalidTLSRecord
170
}
171
171
- // Extension Type 0x0000 = server_name (SNI)
172
- if extType == 0x0000 {
172
+ // Extension Type server_name (SNI)
173
+ if extType == tlsExtensionTypeServerName {
174
return parseSNIExtension(data[offset : offset+extLen])
175
}
176
@@ -211,8 +212,8 @@ func parseSNIExtension(data []byte) (string, error) {
212
return "", ErrInvalidTLSRecord
213
}
214
214
- // Name Type 0x00 = host_name
215
- if nameType == 0x00 {
215
+ // Name Type host_name
216
+ if nameType == tlsServerNameTypeHostName {
217
if nameLen == 0 {
218
return "", ErrNoSNI
219
}
@@ -285,7 +286,7 @@ func PeekSNI(r io.Reader, bufSize int) (string, io.Reader, error) {
286
if _, err := io.ReadFull(r, header); err != nil {
287
return "", nil, fmt.Errorf("peeking TLS header: %w", err)
288
}
288
- if header[0] != 0x16 {
289
+ if header[0] != tlsRecordContentTypeHandshake {
290
reader := io.MultiReader(bytes.NewReader(header), r)
291
return "", reader, ErrNotClientHello
292
}
sdk/client.go
+4
-5
@@ -23,7 +23,6 @@ import (
23
"github.com/gosuda/keyless_tls/keyless/lifecycle"
24
25
"gosuda.org/portal/portal/keyless"
26
- "gosuda.org/portal/portal/netutil"
26
"gosuda.org/portal/types"
27
)
28
@@ -94,11 +93,11 @@ func (c *Client) Listen(name string, options ...types.MetadataOption) (net.Liste
93
if name == "" {
94
return nil, errors.New("name is required")
95
}
97
- if !netutil.IsValidLeaseName(name) {
96
+ if !types.IsValidServiceName(name) {
97
return nil, ErrInvalidName
98
}
99
101
- relayAddrs, err := netutil.NormalizeRelayAPIURLs(c.config.BootstrapServers)
100
+ relayAddrs, err := types.NormalizeRelayAPIURLs(c.config.BootstrapServers)
101
if err != nil {
102
return nil, ErrNoAvailableRelay
103
}
@@ -210,7 +209,7 @@ func acquireLifecycleIdentity(leaseID string) (tls.Certificate, error) {
209
return tls.Certificate{}, fmt.Errorf("acquire lifecycle identity for lease %s: %w", leaseID, err)
210
}
211
213
- cert, leaf, bundle, err := decodeLifecycleIdentityBundleWithReissue(ctx, manager, leaseID, bundle)
212
+ cert, leaf, _, err := decodeLifecycleIdentityBundleWithReissue(ctx, manager, leaseID, bundle)
213
if err != nil {
214
return tls.Certificate{}, err
215
}
@@ -368,7 +367,7 @@ func (c *Client) buildTLSConfig(relayAddr, leaseName string) (*tls.Config, []fun
367
if keylessServerName == "" {
368
return nil, nil, fmt.Errorf("relay hostname is required: %s", relayAddr)
369
}
371
- baseHost := netutil.PortalRootHost(relayAddr)
370
+ baseHost := types.PortalRootHost(relayAddr)
371
if baseHost == "" {
372
return nil, nil, fmt.Errorf("keyless base host is required for relay %s", relayAddr)
373
}
sdk/listener.go
+7
-10
@@ -18,9 +18,6 @@ import (
18
19
"github.com/rs/zerolog/log"
20
21
- "gosuda.org/portal/portal"
22
- "gosuda.org/portal/portal/netutil"
23
- "gosuda.org/portal/portal/sni"
21
"gosuda.org/portal/types"
22
)
23
@@ -126,16 +123,16 @@ func NewListener(relayAddr string, lease *types.Lease, tlsConfig *tls.Config, co
123
return nil, errors.New("control plane client certificate is required")
124
}
125
129
- apiURL, err := netutil.NormalizeRelayAPIURL(relayAddr)
126
+ apiURL, err := types.NormalizeRelayAPIURL(relayAddr)
127
if err != nil {
128
return nil, err
129
}
133
- host := netutil.PortalRootHost(apiURL)
130
+ host := types.PortalRootHost(apiURL)
131
clientTransport := http.DefaultTransport.(*http.Transport).Clone()
132
clientTransport.TLSClientConfig = &tls.Config{
133
MinVersion: tls.VersionTLS12,
134
ServerName: host,
138
- InsecureSkipVerify: netutil.IsLocalhost(host),
135
+ InsecureSkipVerify: types.IsLocalhost(host),
136
Certificates: []tls.Certificate{controlPlaneCert},
137
}
138
@@ -317,7 +314,7 @@ func (l *Listener) reverseAcceptWorker(workerID int) {
314
continue
315
}
316
320
- err = l.waitForReverseStart(conn, sni.TLSStartMarker)
317
+ err = l.waitForReverseStart(conn, types.TLSStartMarker)
318
if err != nil {
319
if closeErr := conn.Close(); closeErr != nil {
320
log.Debug().Err(closeErr).Msg("[SDK] failed to close reverse connection")
@@ -410,7 +407,7 @@ func (l *Listener) openReverseConnection() (net.Conn, error) {
407
tlsConn := tls.Client(rawConn, &tls.Config{
408
MinVersion: tls.VersionTLS12,
409
ServerName: serverName,
413
- InsecureSkipVerify: netutil.IsLocalhost(serverName),
410
+ InsecureSkipVerify: types.IsLocalhost(serverName),
411
Certificates: []tls.Certificate{l.controlPlaneCert},
412
})
413
err = tlsConn.HandshakeContext(ctx)
@@ -490,7 +487,7 @@ func buildReverseConnectRequest(u *url.URL, reverseToken string) (*http.Request,
487
return nil, fmt.Errorf("build reverse connect request: %w", err)
488
}
489
req.Host = u.Host
493
- req.Header.Set(portal.ReverseConnectTokenHeader, token)
490
+ req.Header.Set(types.ReverseConnectTokenHeader, token)
491
req.Header.Set("Connection", "keep-alive")
492
return req, nil
493
}
@@ -627,7 +624,7 @@ func (l *Listener) waitForReverseStart(conn net.Conn, expectedMarker byte) error
624
_, err := io.ReadFull(conn, marker[:])
625
if err == nil {
626
_ = conn.SetReadDeadline(time.Time{})
630
- if marker[0] == portal.ReverseKeepaliveMarker {
627
+ if marker[0] == types.ReverseKeepaliveMarker {
628
continue
629
}
630
if marker[0] == expectedMarker {
sdk/listener_test.go
+13
-15
@@ -12,8 +12,6 @@ import (
12
"testing"
13
"time"
14
15
- "gosuda.org/portal/portal"
16
- "gosuda.org/portal/portal/sni"
15
"gosuda.org/portal/types"
16
)
17
@@ -161,7 +159,7 @@ func TestBuildReverseConnectRequest(t *testing.T) {
159
if req.URL.Query().Get("token") != "" {
160
t.Fatalf("token must not be present in query: %q", req.URL.RawQuery)
161
}
164
- if got := req.Header.Get(portal.ReverseConnectTokenHeader); got != "token-1" {
162
+ if got := req.Header.Get(types.ReverseConnectTokenHeader); got != "token-1" {
163
t.Fatalf("unexpected reverse token header: got %q want %q", got, "token-1")
164
}
165
}
@@ -482,10 +480,10 @@ func TestWaitForReverseStart_HTTPMode(t *testing.T) {
480
481
done := make(chan error, 1)
482
go func() {
485
- done <- l.waitForReverseStart(local, sni.TLSStartMarker)
483
+ done <- l.waitForReverseStart(local, types.TLSStartMarker)
484
}()
485
488
- _, err := peer.Write([]byte{sni.TLSStartMarker})
486
+ _, err := peer.Write([]byte{types.TLSStartMarker})
487
if err != nil {
488
t.Fatalf("write marker: %v", err)
489
}
@@ -513,10 +511,10 @@ func TestWaitForReverseStart_TLSMode(t *testing.T) {
511
512
done := make(chan error, 1)
513
go func() {
516
- done <- l.waitForReverseStart(local, sni.TLSStartMarker)
514
+ done <- l.waitForReverseStart(local, types.TLSStartMarker)
515
}()
516
519
- _, err := peer.Write([]byte{sni.TLSStartMarker})
517
+ _, err := peer.Write([]byte{types.TLSStartMarker})
518
if err != nil {
519
t.Fatalf("write marker: %v", err)
520
}
@@ -541,14 +539,14 @@ func TestWaitForReverseStart_IgnoresKeepaliveMarker(t *testing.T) {
539
540
done := make(chan error, 1)
541
go func() {
544
- done <- l.waitForReverseStart(local, sni.TLSStartMarker)
542
+ done <- l.waitForReverseStart(local, types.TLSStartMarker)
543
}()
544
547
- _, err := peer.Write([]byte{portal.ReverseKeepaliveMarker})
545
+ _, err := peer.Write([]byte{types.ReverseKeepaliveMarker})
546
if err != nil {
547
t.Fatalf("write keepalive marker: %v", err)
548
}
551
- _, err = peer.Write([]byte{sni.TLSStartMarker})
549
+ _, err = peer.Write([]byte{types.TLSStartMarker})
550
if err != nil {
551
t.Fatalf("write start marker: %v", err)
552
}
@@ -576,10 +574,10 @@ func TestWaitForReverseStart_TLSRejectsHTTPMarker(t *testing.T) {
574
575
done := make(chan error, 1)
576
go func() {
579
- done <- l.waitForReverseStart(local, sni.TLSStartMarker)
577
+ done <- l.waitForReverseStart(local, types.TLSStartMarker)
578
}()
579
582
- _, err := peer.Write([]byte{sni.NonTLSStartMarker})
580
+ _, err := peer.Write([]byte{types.NonTLSStartMarker})
581
if err != nil {
582
t.Fatalf("write marker: %v", err)
583
}
@@ -604,10 +602,10 @@ func TestWaitForReverseStart_HTTPRejectsTLSMarker(t *testing.T) {
602
603
done := make(chan error, 1)
604
go func() {
607
- done <- l.waitForReverseStart(local, sni.NonTLSStartMarker)
605
+ done <- l.waitForReverseStart(local, types.NonTLSStartMarker)
606
}()
607
610
- _, err := peer.Write([]byte{sni.TLSStartMarker})
608
+ _, err := peer.Write([]byte{types.TLSStartMarker})
609
if err != nil {
610
t.Fatalf("write marker: %v", err)
611
}
@@ -631,7 +629,7 @@ func TestWaitForReverseStart_StopCancelsWait(t *testing.T) {
629
630
done := make(chan error, 1)
631
go func() {
634
- done <- l.waitForReverseStart(local, sni.TLSStartMarker)
632
+ done <- l.waitForReverseStart(local, types.TLSStartMarker)
633
}()
634
635
close(l.stopCh)
types/lease.go
deleted
-21
@@ -1,21 +0,0 @@
1
-package types
2
-
3
-import "time"
4
-
5
-// Lease represents a registered service.
6
-type Lease struct {
7
- Expires time.Time `json:"expires"`
8
- ID string `json:"id"`
9
- Name string `json:"name"`
10
- ReverseToken string `json:"-"`
11
- Metadata Metadata `json:"metadata"`
12
- TLS bool `json:"tls"`
13
-}
14
-
15
-// LeaseEntry represents a registered lease with expiration tracking.
16
-type LeaseEntry struct {
17
- Lease *Lease
18
- Expires time.Time
19
- LastSeen time.Time
20
- FirstSeen time.Time
21
-}
types/netutil.go
-5
@@ -290,11 +290,6 @@ func BuildSNIName(leaseName, baseHost string) string {
290
return normalizedLeaseName + "." + normalizedBaseHost
291
}
292
293
-// IsValidLeaseName reports whether a lease/service name is DNS-label-safe.
294
-func IsValidLeaseName(name string) bool {
295
- return IsValidServiceName(name)
296
-}
297
-
293
// ParseURLs splits a comma-separated string into a list of trimmed, non-empty URLs.
294
func ParseURLs(raw string) []string {
295
raw = strings.TrimSpace(raw)
types/netutil_test.go
+5
-5
@@ -203,14 +203,14 @@ func TestNonApexPortalRoundTrip(t *testing.T) {
203
}
204
}
205
206
-func TestIsValidLeaseNameUsesServiceValidation(t *testing.T) {
206
+func TestIsValidServiceName(t *testing.T) {
207
t.Parallel()
208
209
- if !IsValidLeaseName("my-app") {
210
- t.Fatalf("expected valid lease name")
209
+ if !IsValidServiceName("my-app") {
210
+ t.Fatalf("expected valid service name")
211
}
212
- if IsValidLeaseName("my_app") {
213
- t.Fatalf("expected underscore to be invalid for DNS-safe lease names")
212
+ if IsValidServiceName("my_app") {
213
+ t.Fatalf("expected underscore to be invalid for DNS-safe service names")
214
}
215
}
216
types/types.go
renamed
+28
@@ -1,5 +1,33 @@
1
package types
2
3
+import "time"
4
+
5
+const (
6
+ // Reverse-connect protocol markers and headers.
7
+ ReverseKeepaliveMarker = byte(0x00)
8
+ NonTLSStartMarker = byte(0x01)
9
+ TLSStartMarker = byte(0x02)
10
+ ReverseConnectTokenHeader = "X-Portal-Reverse-Token"
11
+)
12
+
13
+// Lease represents a registered service.
14
+type Lease struct {
15
+ Expires time.Time `json:"expires"`
16
+ ID string `json:"id"`
17
+ Name string `json:"name"`
18
+ ReverseToken string `json:"-"`
19
+ Metadata Metadata `json:"metadata"`
20
+ TLS bool `json:"tls"`
21
+}
22
+
23
+// LeaseEntry represents a registered lease with expiration tracking.
24
+type LeaseEntry struct {
25
+ Lease *Lease
26
+ Expires time.Time
27
+ LastSeen time.Time
28
+ FirstSeen time.Time
29
+}
30
+
31
// Metadata holds service metadata for a lease.
32
type Metadata struct {
33
Description string `json:"description,omitempty"`