Skip to content

Commit 0387dfb

Browse files
authored
refactor: use the SDK's WebSocket Upgrade() function (#234)
* Use the new WS `Upgrade()` function from the SDK. * Use `r.Context()`. * Make sure the clientIP is not nil when we replace it. * Bump the `outline-sdk` dependency. * Explicitly allow `BSD-2-Clause` license. * Bump the `outline-sdk` dependency.
1 parent b7d1c7a commit 0387dfb

File tree

6 files changed

+96
-282
lines changed

6 files changed

+96
-282
lines changed

.github/workflows/license.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,4 @@ jobs:
4444

4545
- name: Check licenses
4646
# We allow only "notice" type of licenses.
47-
run: go run github.com/google/go-licenses check --ignore=golang.org/x --allowed_licenses=Apache-2.0,Apache-3,BSD-3-Clause,BSD-4-Clause,CC0-1.0,ISC,MIT ./...
47+
run: go run github.com/google/go-licenses check --ignore=golang.org/x --allowed_licenses=Apache-2.0,Apache-3,BSD-2-Clause,BSD-3-Clause,BSD-4-Clause,CC0-1.0,ISC,MIT ./...

cmd/outline-ss-server/main.go

+35-61
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,11 @@ import (
3131

3232
"github.com/Jigsaw-Code/outline-sdk/transport"
3333
"github.com/Jigsaw-Code/outline-sdk/transport/shadowsocks"
34+
"github.com/Jigsaw-Code/outline-sdk/x/websocket"
35+
"github.com/gorilla/handlers"
3436
"github.com/lmittmann/tint"
3537
"github.com/prometheus/client_golang/prometheus"
3638
"github.com/prometheus/client_golang/prometheus/promhttp"
37-
"golang.org/x/net/websocket"
3839
"golang.org/x/term"
3940

4041
"github.com/Jigsaw-Code/outline-ss-server/ipinfo"
@@ -306,18 +307,22 @@ func (s *OutlineServer) runConfig(config Config) (func() error, error) {
306307
if err != nil {
307308
return err
308309
}
310+
logger := slog.Default().With(
311+
slog.Int("access_keys", len(serviceConfig.Keys)),
312+
slog.Any("fwmark", func() any {
313+
if serviceConfig.Dialer.Fwmark == 0 {
314+
return "disabled"
315+
}
316+
return serviceConfig.Dialer.Fwmark
317+
}()),
318+
)
309319
for _, cfg := range serviceConfig.Listeners {
310320
if cfg.TCP != nil {
311321
ln, err := lnSet.ListenStream(cfg.TCP.Address)
312322
if err != nil {
313323
return err
314324
}
315-
slog.Info("TCP service started.", "address", ln.Addr().String(), "fwmark", func() any {
316-
if serviceConfig.Dialer.Fwmark == 0 {
317-
return "disabled"
318-
}
319-
return serviceConfig.Dialer.Fwmark
320-
}())
325+
logger.Info("TCP service started.", "address", ln.Addr().String())
321326
go service.StreamServe(ln.AcceptStream, func(ctx context.Context, conn transport.StreamConn) {
322327
streamHandler.HandleStream(ctx, conn, s.serviceMetrics.AddOpenTCPConnection(conn))
323328
})
@@ -326,12 +331,7 @@ func (s *OutlineServer) runConfig(config Config) (func() error, error) {
326331
if err != nil {
327332
return err
328333
}
329-
slog.Info("UDP service started.", "address", pc.LocalAddr().String(), "fwmark", func() any {
330-
if serviceConfig.Dialer.Fwmark == 0 {
331-
return "disabled"
332-
}
333-
return serviceConfig.Dialer.Fwmark
334-
}())
334+
logger.Info("UDP service started.", "address", pc.LocalAddr().String())
335335
go service.PacketServe(pc, func(ctx context.Context, conn net.Conn) {
336336
associationHandler.HandleAssociation(ctx, conn, s.serviceMetrics.AddOpenUDPAssociation(conn))
337337
}, s.serverMetrics)
@@ -340,48 +340,37 @@ func (s *OutlineServer) runConfig(config Config) (func() error, error) {
340340
return fmt.Errorf("websocket-stream listener references unknown web server `%s`", cfg.WebsocketStream.WebServer)
341341
}
342342
mux := webServers[cfg.WebsocketStream.WebServer]
343-
// TODO: Support a "half-closed" state for WebSockets.
344343
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
345-
handler := func(wsConn *websocket.Conn) {
346-
defer wsConn.Close()
347-
ctx, contextCancel := context.WithCancel(context.Background())
348-
defer contextCancel()
349-
clientIP, err := onet.GetClientIPFromRequest(r)
350-
if err != nil {
351-
slog.Error("failed to determine client address", "err", err)
352-
w.WriteHeader(http.StatusBadGateway)
353-
return
354-
}
355-
conn := &streamConn{&replaceAddrConn{Conn: wsConn, raddr: &net.TCPAddr{IP: clientIP}}}
356-
streamHandler.HandleStream(ctx, conn, s.serviceMetrics.AddOpenTCPConnection(conn))
344+
conn, err := websocket.Upgrade(w, r, nil)
345+
if err != nil {
346+
slog.Error("failed to upgrade", "err", err)
357347
}
358-
websocket.Handler(handler).ServeHTTP(w, r)
348+
defer conn.Close()
349+
if clientIP := net.ParseIP(r.RemoteAddr); clientIP != nil {
350+
conn = &replaceAddrConn{StreamConn: conn, raddr: &net.TCPAddr{IP: clientIP}}
351+
}
352+
streamHandler.HandleStream(r.Context(), conn, s.serviceMetrics.AddOpenTCPConnection(conn))
359353
})
360-
mux.Handle(cfg.WebsocketStream.Path, http.StripPrefix(cfg.WebsocketStream.Path, handler))
361-
slog.Info("WebSocket stream service started.", "ID", cfg.WebsocketStream.WebServer, "path", cfg.WebsocketStream.Path)
354+
mux.Handle(cfg.WebsocketStream.Path, http.StripPrefix(cfg.WebsocketStream.Path, handlers.ProxyHeaders(handler)))
355+
logger.Info("WebSocket stream service started.", "ID", cfg.WebsocketStream.WebServer, "path", cfg.WebsocketStream.Path)
362356
} else if cfg.WebsocketPacket != nil {
363357
if _, exists := webServers[cfg.WebsocketPacket.WebServer]; !exists {
364358
return fmt.Errorf("websocket-packet listener references unknown web server `%s`", cfg.WebsocketPacket.WebServer)
365359
}
366360
mux := webServers[cfg.WebsocketPacket.WebServer]
367361
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
368-
handler := func(wsConn *websocket.Conn) {
369-
defer wsConn.Close()
370-
ctx, contextCancel := context.WithCancel(context.Background())
371-
defer contextCancel()
372-
clientIP, err := onet.GetClientIPFromRequest(r)
373-
if err != nil {
374-
slog.Error("failed to determine client address", "err", err)
375-
w.WriteHeader(http.StatusBadGateway)
376-
return
377-
}
378-
conn := &replaceAddrConn{Conn: wsConn, raddr: &net.UDPAddr{IP: clientIP}}
379-
associationHandler.HandleAssociation(ctx, conn, s.serviceMetrics.AddOpenUDPAssociation(conn))
362+
conn, err := websocket.Upgrade(w, r, nil)
363+
if err != nil {
364+
slog.Error("failed to upgrade", "err", err)
365+
}
366+
defer conn.Close()
367+
if clientIP := net.ParseIP(r.RemoteAddr); clientIP != nil {
368+
conn = &replaceAddrConn{StreamConn: conn, raddr: &net.UDPAddr{IP: clientIP}}
380369
}
381-
websocket.Handler(handler).ServeHTTP(w, r)
370+
associationHandler.HandleAssociation(r.Context(), conn, s.serviceMetrics.AddOpenUDPAssociation(conn))
382371
})
383-
mux.Handle(cfg.WebsocketPacket.Path, http.StripPrefix(cfg.WebsocketPacket.Path, handler))
384-
slog.Info("WebSocket packet service started.", "ID", cfg.WebsocketPacket.WebServer, "path", cfg.WebsocketPacket.Path)
372+
mux.Handle(cfg.WebsocketPacket.Path, http.StripPrefix(cfg.WebsocketPacket.Path, handlers.ProxyHeaders(handler)))
373+
logger.Info("WebSocket packet service started.", "ID", cfg.WebsocketPacket.WebServer, "path", cfg.WebsocketPacket.Path)
385374
} else {
386375
return fmt.Errorf("unknown listener configuration: %v", cfg)
387376
}
@@ -452,31 +441,16 @@ func RunOutlineServer(filename string, natTimeout time.Duration, serverMetrics *
452441
}
453442

454443
// TODO: Create a dedicated `ClientConn` struct with `ClientAddr` and `Conn`.
455-
// replaceAddrConn overrides [websocket.Conn]'s remote address handling.
444+
// replaceAddrConn overrides a [transport.StreamConn]'s remote address handling.
456445
type replaceAddrConn struct {
457-
*websocket.Conn
446+
transport.StreamConn
458447
raddr net.Addr
459448
}
460449

461450
func (c replaceAddrConn) RemoteAddr() net.Addr {
462451
return c.raddr
463452
}
464453

465-
type streamConn struct {
466-
net.Conn
467-
}
468-
469-
var _ transport.StreamConn = (*streamConn)(nil)
470-
471-
// TODO: Support a "half-closed" state.
472-
func (c *streamConn) CloseRead() error {
473-
return c.Close()
474-
}
475-
476-
func (c *streamConn) CloseWrite() error {
477-
return c.Close()
478-
}
479-
480454
func main() {
481455
slog.SetDefault(slog.New(logHandler))
482456

go.mod

+19-17
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,22 @@
11
module github.com/Jigsaw-Code/outline-ss-server
22

33
require (
4-
github.com/Jigsaw-Code/outline-sdk v0.0.14
4+
github.com/Jigsaw-Code/outline-sdk v0.0.18-0.20241106233708-faffebb12629
5+
github.com/Jigsaw-Code/outline-sdk/x v0.0.0-20250130222646-80b6430a1fc8
56
github.com/go-task/task/v3 v3.34.1
7+
github.com/go-viper/mapstructure/v2 v2.2.1
68
github.com/google/addlicense v1.1.1
79
github.com/google/go-licenses v1.6.0
810
github.com/goreleaser/goreleaser v1.18.2
11+
github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33
912
github.com/lmittmann/tint v1.0.5
1013
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
1114
github.com/oschwald/geoip2-golang v1.8.0
1215
github.com/prometheus/client_golang v1.15.0
1316
github.com/shadowsocks/go-shadowsocks2 v0.1.5
14-
github.com/stretchr/testify v1.8.4
15-
golang.org/x/crypto v0.17.0
16-
golang.org/x/term v0.16.0
17+
github.com/stretchr/testify v1.9.0
18+
golang.org/x/crypto v0.26.0
19+
golang.org/x/term v0.23.0
1720
gopkg.in/yaml.v3 v3.0.1
1821
)
1922

@@ -133,7 +136,6 @@ require (
133136
github.com/go-openapi/validate v0.22.1 // indirect
134137
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
135138
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible // indirect
136-
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
137139
github.com/gobwas/glob v0.2.3 // indirect
138140
github.com/gogo/protobuf v1.3.2 // indirect
139141
github.com/golang-jwt/jwt/v4 v4.5.1 // indirect
@@ -154,7 +156,7 @@ require (
154156
github.com/goreleaser/chglog v0.4.2 // indirect
155157
github.com/goreleaser/fileglob v1.3.0 // indirect
156158
github.com/goreleaser/nfpm/v2 v2.28.0 // indirect
157-
github.com/gorilla/websocket v1.5.0 // indirect
159+
github.com/gorilla/websocket v1.5.3 // indirect
158160
github.com/hashicorp/errwrap v1.1.0 // indirect
159161
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
160162
github.com/hashicorp/go-multierror v1.1.1 // indirect
@@ -171,7 +173,7 @@ require (
171173
github.com/joho/godotenv v1.5.1 // indirect
172174
github.com/josharian/intern v1.0.0 // indirect
173175
github.com/kevinburke/ssh_config v1.2.0 // indirect
174-
github.com/klauspost/compress v1.16.3 // indirect
176+
github.com/klauspost/compress v1.16.7 // indirect
175177
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
176178
github.com/klauspost/pgzip v1.2.5 // indirect
177179
github.com/kylelemons/godebug v1.1.0 // indirect
@@ -219,7 +221,7 @@ require (
219221
github.com/sigstore/cosign/v2 v2.0.0 // indirect
220222
github.com/sigstore/rekor v1.1.1 // indirect
221223
github.com/sigstore/sigstore v1.6.3 // indirect
222-
github.com/sirupsen/logrus v1.9.0 // indirect
224+
github.com/sirupsen/logrus v1.9.3 // indirect
223225
github.com/skeema/knownhosts v1.2.1 // indirect
224226
github.com/slack-go/slack v0.12.2 // indirect
225227
github.com/spf13/afero v1.9.3 // indirect
@@ -245,21 +247,21 @@ require (
245247
go.opencensus.io v0.24.0 // indirect
246248
go.uber.org/automaxprocs v1.5.2 // indirect
247249
gocloud.dev v0.29.0 // indirect
248-
golang.org/x/exp v0.0.0-20240110193028-0dcbfd608b1e // indirect
249-
golang.org/x/mod v0.14.0 // indirect
250-
golang.org/x/net v0.19.0 // indirect
250+
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect
251+
golang.org/x/mod v0.17.0 // indirect
252+
golang.org/x/net v0.28.0 // indirect
251253
golang.org/x/oauth2 v0.7.0 // indirect
252-
golang.org/x/sync v0.6.0 // indirect
253-
golang.org/x/sys v0.16.0 // indirect
254-
golang.org/x/text v0.14.0 // indirect
254+
golang.org/x/sync v0.8.0 // indirect
255+
golang.org/x/sys v0.23.0 // indirect
256+
golang.org/x/text v0.17.0 // indirect
255257
golang.org/x/time v0.3.0 // indirect
256-
golang.org/x/tools v0.16.0 // indirect
258+
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
257259
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
258260
google.golang.org/api v0.119.0 // indirect
259261
google.golang.org/appengine v1.6.7 // indirect
260262
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
261263
google.golang.org/grpc v1.56.3 // indirect
262-
google.golang.org/protobuf v1.30.0 // indirect
264+
google.golang.org/protobuf v1.33.0 // indirect
263265
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
264266
gopkg.in/ini.v1 v1.67.0 // indirect
265267
gopkg.in/mail.v2 v2.3.1 // indirect
@@ -274,4 +276,4 @@ require (
274276
sigs.k8s.io/yaml v1.3.0 // indirect
275277
)
276278

277-
go 1.21
279+
go 1.22

0 commit comments

Comments
 (0)