Skip to content

Commit b57f777

Browse files
committed
Use the new WS Upgrade() function from the SDK.
1 parent 348b0cc commit b57f777

File tree

3 files changed

+57
-63
lines changed

3 files changed

+57
-63
lines changed

caddy/outline_handler.go

+19-1
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,17 @@ import (
1818
"errors"
1919
"fmt"
2020
"log/slog"
21+
"net"
2122

23+
"github.com/Jigsaw-Code/outline-sdk/transport"
2224
"github.com/caddyserver/caddy/v2"
2325
"github.com/mholt/caddy-l4/layer4"
2426
)
2527

26-
const outlineHandlerModuleName = "layer4.handlers.outline"
28+
const (
29+
outlineHandlerModuleName = "layer4.handlers.outline"
30+
outlineConnectionTypeCtxKey = "layer4.handlers.outline.cxtype"
31+
)
2732

2833
func init() {
2934
caddy.RegisterModule(ModuleRegistration{
@@ -32,6 +37,13 @@ func init() {
3237
})
3338
}
3439

40+
type ConnectionType string
41+
42+
const (
43+
StreamConnectionType = ConnectionType("stream")
44+
PacketConnectionType = ConnectionType("packet")
45+
)
46+
3547
// OutlineHandler implements a Caddy layer4 plugin for Outline connections.
3648
type OutlineHandler struct {
3749
ConnectionHandler string `json:"connection_handler,omitempty"`
@@ -85,5 +97,11 @@ func (h *OutlineHandler) Validate() error {
8597

8698
// Handle implements layer4.NextHandler.
8799
func (h *OutlineHandler) Handle(cx *layer4.Connection, next layer4.Handler) error {
100+
switch cx.Conn.(type) {
101+
case transport.StreamConn:
102+
cx.SetVar(outlineConnectionTypeCtxKey, StreamConnectionType)
103+
case net.Conn:
104+
cx.SetVar(outlineConnectionTypeCtxKey, PacketConnectionType)
105+
}
88106
return h.compiledHandler.Handle(cx, next)
89107
}

caddy/shadowsocks_handler.go

+12-8
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import (
1818
"container/list"
1919
"fmt"
2020
"log/slog"
21-
"net"
2221
"time"
2322

2423
"github.com/Jigsaw-Code/outline-sdk/transport"
@@ -116,13 +115,18 @@ func (h *ShadowsocksHandler) Provision(ctx caddy.Context) error {
116115

117116
// Handle implements layer4.NextHandler.
118117
func (h *ShadowsocksHandler) Handle(cx *layer4.Connection, _ layer4.Handler) error {
119-
switch conn := cx.Conn.(type) {
120-
case transport.StreamConn:
121-
h.streamHandler.HandleStream(cx.Context, conn, h.metrics.AddOpenTCPConnection(conn))
122-
case net.Conn:
123-
h.associationHandler.HandleAssociation(cx.Context, conn, h.metrics.AddOpenUDPAssociation(conn))
124-
default:
125-
return fmt.Errorf("failed to handle unknown connection type: %T", conn)
118+
connType, ok := cx.GetVar(outlineConnectionTypeCtxKey).(ConnectionType)
119+
if !ok {
120+
// Likely if the Shadowsocks handler was used directly instead of through
121+
// the Outline connection handler.
122+
return fmt.Errorf("unknown outline connection type")
123+
}
124+
125+
switch connType {
126+
case StreamConnectionType:
127+
h.streamHandler.HandleStream(cx.Context, cx.Conn.(transport.StreamConn), h.metrics.AddOpenTCPConnection(cx))
128+
case PacketConnectionType:
129+
h.associationHandler.HandleAssociation(cx.Context, cx.Conn, h.metrics.AddOpenUDPAssociation(cx))
126130
}
127131
return nil
128132
}

caddy/ws2outline_handler.go

+26-54
Original file line numberDiff line numberDiff line change
@@ -22,31 +22,24 @@ import (
2222
"net/http"
2323

2424
"github.com/Jigsaw-Code/outline-sdk/transport"
25+
"github.com/Jigsaw-Code/outline-sdk/x/websocket"
2526
"github.com/caddyserver/caddy/v2"
2627
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
2728
"github.com/mholt/caddy-l4/layer4"
2829
"go.uber.org/zap"
29-
"golang.org/x/net/websocket"
30-
)
3130

32-
const (
33-
wsModuleName = "http.handlers.ws2outline"
31+
onet "github.com/Jigsaw-Code/outline-ss-server/net"
3432
)
3533

34+
const wsModuleName = "http.handlers.ws2outline"
35+
3636
func init() {
3737
caddy.RegisterModule(ModuleRegistration{
3838
ID: wsModuleName,
3939
New: func() caddy.Module { return new(WebSocketHandler) },
4040
})
4141
}
4242

43-
type ConnectionType string
44-
45-
const (
46-
connectionTypeStream ConnectionType = "stream"
47-
connectionTypePacket ConnectionType = "packet"
48-
)
49-
5043
// WebSocketHandler implements a middleware Caddy web handler that proxies
5144
// WebSockets Outline connections.
5245
type WebSocketHandler struct {
@@ -75,7 +68,7 @@ func (h *WebSocketHandler) Provision(ctx caddy.Context) error {
7568
h.zlogger = ctx.Logger()
7669
if h.Type == "" {
7770
// The default connection type if not provided is a stream.
78-
h.Type = connectionTypeStream
71+
h.Type = StreamConnectionType
7972
}
8073

8174
mod, err := ctx.AppIfConfigured(outlineModuleName)
@@ -101,7 +94,7 @@ func (h *WebSocketHandler) Provision(ctx caddy.Context) error {
10194

10295
// Validate implements caddy.Validator.
10396
func (h *WebSocketHandler) Validate() error {
104-
if h.Type != "" && h.Type != connectionTypeStream && h.Type != connectionTypePacket {
97+
if h.Type != "" && h.Type != StreamConnectionType && h.Type != PacketConnectionType {
10598
return fmt.Errorf("unsupported `type`: %v", h.Type)
10699
}
107100
if h.ConnectionHandler == "" {
@@ -117,55 +110,35 @@ func (h WebSocketHandler) ServeHTTP(w http.ResponseWriter, r *http.Request, _ ca
117110
slog.String("path", r.URL.Path),
118111
slog.Any("remote_addr", r.RemoteAddr))
119112

113+
conn, err := websocket.Upgrade(w, r, nil)
114+
if err != nil {
115+
h.logger.Error("failed to upgrade", "err", err)
116+
}
117+
defer conn.Close()
118+
clientAddrPort, clientIpErr := onet.ParseAddrPortOrIP(r.RemoteAddr)
120119
switch h.Type {
121-
case connectionTypeStream:
122-
handler := func(wsConn *websocket.Conn) {
123-
raddr, err := net.ResolveTCPAddr("tcp", r.RemoteAddr)
124-
if err != nil {
125-
h.logger.Error("failed to upgrade", "err", err)
126-
w.WriteHeader(http.StatusBadGateway)
127-
return
128-
}
129-
130-
conn := &wsToStreamConn{&wrappedConn{Conn: wsConn, raddr: raddr}}
131-
132-
if err = h.compiledHandler.Handle(layer4.WrapConnection(conn, []byte{}, h.zlogger), nil); err != nil {
133-
h.logger.Error("failed to upgrade", "err", err)
134-
w.WriteHeader(http.StatusBadGateway)
135-
return
136-
}
120+
case StreamConnectionType:
121+
if clientIpErr == nil {
122+
conn = &replaceAddrConn{StreamConn: conn, raddr: net.TCPAddrFromAddrPort(clientAddrPort)}
137123
}
138-
websocket.Handler(handler).ServeHTTP(w, r)
139-
case connectionTypePacket:
140-
handler := func(wsConn *websocket.Conn) {
141-
raddr, err := net.ResolveUDPAddr("udp", r.RemoteAddr)
142-
if err != nil {
143-
h.logger.Error("failed to upgrade", "err", err)
144-
w.WriteHeader(http.StatusBadGateway)
145-
return
146-
}
147-
148-
conn := &wrappedConn{Conn: wsConn, raddr: raddr}
149-
150-
if err = h.compiledHandler.Handle(layer4.WrapConnection(conn, []byte{}, h.zlogger), nil); err != nil {
151-
h.logger.Error("failed to upgrade", "err", err)
152-
w.WriteHeader(http.StatusBadGateway)
153-
return
154-
}
124+
case PacketConnectionType:
125+
if clientIpErr == nil {
126+
conn = &replaceAddrConn{StreamConn: conn, raddr: net.UDPAddrFromAddrPort(clientAddrPort)}
155127
}
156-
websocket.Handler(handler).ServeHTTP(w, r)
157128
}
158-
159-
return nil
129+
cx := layer4.WrapConnection(conn, []byte{}, h.zlogger)
130+
cx.SetVar(outlineConnectionTypeCtxKey, h.Type)
131+
return h.compiledHandler.Handle(cx, nil)
160132
}
161133

162-
// wrappedConn overrides [websocket.Conn]'s remote address handling.
163-
type wrappedConn struct {
164-
*websocket.Conn
134+
// TODO: Create a dedicated `ClientConn` struct with `ClientAddr` and `Conn`.
135+
// replaceAddrConn overrides a [transport.StreamConn]'s remote address handling.
136+
type replaceAddrConn struct {
137+
transport.StreamConn
165138
raddr net.Addr
166139
}
167140

168-
func (c wrappedConn) RemoteAddr() net.Addr {
141+
func (c replaceAddrConn) RemoteAddr() net.Addr {
169142
return c.raddr
170143
}
171144

@@ -184,4 +157,3 @@ func (c *wsToStreamConn) CloseRead() error {
184157
func (c *wsToStreamConn) CloseWrite() error {
185158
return c.Conn.Close()
186159
}
187-

0 commit comments

Comments
 (0)