@@ -22,31 +22,24 @@ import (
22
22
"net/http"
23
23
24
24
"github.com/Jigsaw-Code/outline-sdk/transport"
25
+ "github.com/Jigsaw-Code/outline-sdk/x/websocket"
25
26
"github.com/caddyserver/caddy/v2"
26
27
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
27
28
"github.com/mholt/caddy-l4/layer4"
28
29
"go.uber.org/zap"
29
- "golang.org/x/net/websocket"
30
- )
31
30
32
- const (
33
- wsModuleName = "http.handlers.ws2outline"
31
+ onet "github.com/Jigsaw-Code/outline-ss-server/net"
34
32
)
35
33
34
+ const wsModuleName = "http.handlers.ws2outline"
35
+
36
36
func init () {
37
37
caddy .RegisterModule (ModuleRegistration {
38
38
ID : wsModuleName ,
39
39
New : func () caddy.Module { return new (WebSocketHandler ) },
40
40
})
41
41
}
42
42
43
- type ConnectionType string
44
-
45
- const (
46
- connectionTypeStream ConnectionType = "stream"
47
- connectionTypePacket ConnectionType = "packet"
48
- )
49
-
50
43
// WebSocketHandler implements a middleware Caddy web handler that proxies
51
44
// WebSockets Outline connections.
52
45
type WebSocketHandler struct {
@@ -75,7 +68,7 @@ func (h *WebSocketHandler) Provision(ctx caddy.Context) error {
75
68
h .zlogger = ctx .Logger ()
76
69
if h .Type == "" {
77
70
// The default connection type if not provided is a stream.
78
- h .Type = connectionTypeStream
71
+ h .Type = StreamConnectionType
79
72
}
80
73
81
74
mod , err := ctx .AppIfConfigured (outlineModuleName )
@@ -101,7 +94,7 @@ func (h *WebSocketHandler) Provision(ctx caddy.Context) error {
101
94
102
95
// Validate implements caddy.Validator.
103
96
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 {
105
98
return fmt .Errorf ("unsupported `type`: %v" , h .Type )
106
99
}
107
100
if h .ConnectionHandler == "" {
@@ -117,55 +110,35 @@ func (h WebSocketHandler) ServeHTTP(w http.ResponseWriter, r *http.Request, _ ca
117
110
slog .String ("path" , r .URL .Path ),
118
111
slog .Any ("remote_addr" , r .RemoteAddr ))
119
112
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 )
120
119
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 )}
137
123
}
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 )}
155
127
}
156
- websocket .Handler (handler ).ServeHTTP (w , r )
157
128
}
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 )
160
132
}
161
133
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
165
138
raddr net.Addr
166
139
}
167
140
168
- func (c wrappedConn ) RemoteAddr () net.Addr {
141
+ func (c replaceAddrConn ) RemoteAddr () net.Addr {
169
142
return c .raddr
170
143
}
171
144
@@ -184,4 +157,3 @@ func (c *wsToStreamConn) CloseRead() error {
184
157
func (c * wsToStreamConn ) CloseWrite () error {
185
158
return c .Conn .Close ()
186
159
}
187
-
0 commit comments