Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: get client IP from the request headers #233

Merged
merged 104 commits into from
Jan 30, 2025
Merged
Changes from 1 commit
Commits
Show all changes
104 commits
Select commit Hold shift + click to select a range
b2aa859
refactor: split UDP serving from handling of packets
sbruens Nov 18, 2024
c0c0e9f
Use a read channel.
sbruens Nov 20, 2024
8d95309
Rename `wrappedPacketConn` to just `packetConn`.
sbruens Nov 20, 2024
51d5c88
Update `shadowsocks_handler`.
sbruens Nov 21, 2024
422542b
Change the `HandlePacket` API to not require the `pkt`.
sbruens Nov 22, 2024
c10176f
Remove the NAT map from the `Handle()` function.
sbruens Nov 25, 2024
004c6c3
Rework the metrics now that the NAT is no longer done by the handler.
sbruens Nov 26, 2024
a91d55b
Move the metrics `AddClosed()` call to after the `timedCopy` returns.
sbruens Nov 26, 2024
1d7200b
Remove the explicit `targetConn.Close()` and let it expire on its own.
sbruens Nov 26, 2024
4b8eeae
Add the NAT metrics back in at the server level.
sbruens Nov 27, 2024
1e89e85
Use buffer pool on `packetHandler` instead of global.
sbruens Nov 27, 2024
b4e7dbb
Revert wrapping the `clientConn` with shadowsocks encryption/decryption.
sbruens Nov 27, 2024
63c2cff
Rename `packet` to `association`.
sbruens Nov 27, 2024
1eeb4d6
Fix tests.
sbruens Nov 28, 2024
08e8bba
Update the docstring for `PacketServe`.
sbruens Nov 28, 2024
34a01d7
Fix comment to refer to "associations".
sbruens Nov 28, 2024
dd5f439
feat: add WebSocket support to the existing `outline-ss-server`
sbruens Nov 28, 2024
e769585
Fix config reloads.
sbruens Dec 3, 2024
033ba9d
Fix metrics test.
sbruens Dec 3, 2024
87a9d23
Use `slicepool`.
sbruens Dec 3, 2024
50feaa2
Let the assocation handler provide the buffer.
sbruens Dec 4, 2024
c0e942b
Merge branch 'sbruens/udp-split-serving' into sbruens/websocket
sbruens Dec 4, 2024
6eb828e
Fix StreamConn wrapper.
sbruens Dec 4, 2024
831371a
Move web server config into its own top-level config structure.
sbruens Dec 10, 2024
db09289
Add a TODO to create a new `ClientConn` struct.
sbruens Dec 10, 2024
b7a4a3c
Remove the `packetConnWrapper` and move the logic into `natconn` inst…
sbruens Dec 10, 2024
f80294c
Fix close while reading of `natconn`.
sbruens Dec 10, 2024
36d4b27
Simplify the natmap a little.
sbruens Dec 10, 2024
f5d9ac3
Refactor `PacketServe` to use events (close and read).
sbruens Dec 13, 2024
e0547f2
Use correct logger.
sbruens Dec 13, 2024
21cae17
Update tests for config validation.
sbruens Dec 10, 2024
e210fb0
Format.
sbruens Dec 13, 2024
3c1277c
Merge branch 'sbruens/udp-split-serving' into sbruens/websocket
sbruens Dec 13, 2024
0c45bad
Close the connection.
sbruens Dec 13, 2024
3dc12d1
Keep `readCh` and `closeCh` unbuffered.
sbruens Dec 16, 2024
afb9cd1
Catch panics in the `ReadFrom` go routine.
sbruens Dec 16, 2024
5d2acc6
Close the `readCh` instead of sending the error on the `readCh`.
sbruens Dec 16, 2024
7cd0f1f
Wrap a logger with the association's client address so we can simplif…
sbruens Dec 16, 2024
078032c
Reference GitHub issue for supporting multiple IPs.
sbruens Dec 16, 2024
2b3f746
Simplify packet handling with a new `association` struct.
sbruens Dec 18, 2024
2f2268b
Add some comments to the `Association` interface.
sbruens Dec 18, 2024
bfe4b35
Consolidate debug logging.
sbruens Dec 18, 2024
f37f23a
Rename some vars.
sbruens Dec 18, 2024
08de4c3
Update doc.
sbruens Dec 18, 2024
418c0e4
Format.
sbruens Dec 19, 2024
98988b0
Do not unpack first packets twice.
sbruens Dec 19, 2024
fffb6a2
Merge branch 'sbruens/udp-split-serving' into sbruens/websocket
sbruens Dec 20, 2024
b9c0286
Move handling into the association.
sbruens Dec 20, 2024
38e2eae
Merge branch 'sbruens/udp-split-serving' into sbruens/websocket
sbruens Dec 20, 2024
d14ea20
Merge branch 'master' into sbruens/udp-split-serving
sbruens Dec 20, 2024
eef630a
Add some comments to the timeout value.
sbruens Dec 20, 2024
3241298
Merge branch 'sbruens/udp-split-serving' into sbruens/websocket
sbruens Dec 20, 2024
1c462b1
Don't set the stream dialer in the old config flow.
sbruens Dec 20, 2024
ed4f4de
Merge branch 'sbruens/udp-split-serving' into sbruens/websocket
sbruens Dec 20, 2024
0918050
Rename `AddAuthentication` and `AddClose`.
sbruens Jan 6, 2025
78af4be
Update comment to reflect it handles packets from both directions.
sbruens Jan 6, 2025
2cf398c
Separate the interfaces for `Handle()` and `HandlePacket()`.
sbruens Jan 6, 2025
1055cb1
Fix typo in `UDPAssocationMetrics`.
sbruens Jan 6, 2025
f8ab81a
Don't pass `conn` to `Handle()`.
sbruens Jan 6, 2025
e6ef2f3
Update comment.
sbruens Jan 6, 2025
2939f8a
Add comments.
sbruens Jan 6, 2025
5b14062
Merge branch 'sbruens/udp-split-serving' into sbruens/websocket
sbruens Jan 6, 2025
ed980ad
Address review comments.
sbruens Jan 7, 2025
23a03e9
Remove ConnAssociation in favor of a `HandleAssociation(Conn, PacketA…
sbruens Jan 8, 2025
aa130f0
Split `Service` interface into outline-ss-server and Caddy interfaces.
sbruens Jan 8, 2025
19fb5f7
Remove unused const.
sbruens Jan 8, 2025
c656b36
Don't require `conn` in `HandleAssociation()`.
sbruens Jan 8, 2025
31cec7c
Exit the loop if the connection is closed.
sbruens Jan 9, 2025
0642698
Re-use global buffer pool.
sbruens Jan 10, 2025
a16c1b3
Remove app-specific interfaces.
sbruens Jan 10, 2025
77983fc
Decouple the association and the packet handling.
sbruens Jan 11, 2025
f3d63ae
Move timedCopy handling to the packet handler.
sbruens Jan 11, 2025
4c4072c
Remove unused property.
sbruens Jan 13, 2025
413a1aa
Decouple shadowsocks from association.
sbruens Jan 13, 2025
db3d0a3
Move authentication into its own function.
sbruens Jan 13, 2025
5f685bb
Remove the `packetMetrics` struct.
sbruens Jan 13, 2025
1dbfa99
Update tests.
sbruens Jan 13, 2025
23050ef
Remove the `Metrics()` method.
sbruens Jan 13, 2025
47222f6
Move variables into the anonymous functions.
sbruens Jan 16, 2025
8e9af05
Rename stream and packet handlers `Handle()` methods.
sbruens Jan 17, 2025
5704718
More `handle` naming clarification.
sbruens Jan 17, 2025
0cbcd61
Refactor to make packet handler an association handler.
sbruens Jan 21, 2025
bcac22b
Only handle the association if it was new.
sbruens Jan 21, 2025
220d1d7
Fix the metric race condition in tests.
sbruens Jan 21, 2025
d81f128
Move `AddNATEntry()` call to new entry only.
sbruens Jan 21, 2025
96de2a6
Format.
sbruens Jan 22, 2025
09e471f
Address review comments.
sbruens Jan 22, 2025
64c48ce
Make `clientConn` an `io.Writer`.
sbruens Jan 22, 2025
589abba
Merge branch 'sbruens/udp-split-serving' into sbruens/websocket
sbruens Jan 23, 2025
b12e0bb
Handle the `EOF` case and stop reading from the connection.
sbruens Jan 23, 2025
354d8a8
Add comment about using localhost listeners for the web config.
sbruens Jan 23, 2025
d37e358
Add comment about support half-closed states.
sbruens Jan 23, 2025
6ee3084
Refactor how we parse the listener configs.
sbruens Jan 29, 2025
f2fda60
Merge branch 'master' into sbruens/websocket
sbruens Jan 29, 2025
8fca003
Add comments.
sbruens Jan 29, 2025
d7e43f7
Align yaml string.
sbruens Jan 29, 2025
775692d
Skip the unnecessary JSON marshalling.
sbruens Jan 29, 2025
c076337
Use reflection and a type map to avoid code duplication.
sbruens Jan 29, 2025
b00ee41
More review comments.
sbruens Jan 29, 2025
cc3eb8c
feat: get client IP from the request headers
sbruens Jan 29, 2025
7ddab63
Fix doc.
sbruens Jan 29, 2025
aeef1f2
More review comments.
sbruens Jan 29, 2025
7b2dfe7
Merge branch 'sbruens/websocket' into sbruens/fwd-address
sbruens Jan 29, 2025
d8a8b08
Merge branch 'master' into sbruens/fwd-address
sbruens Jan 30, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
More review comments.
  • Loading branch information
sbruens committed Jan 29, 2025
commit b00ee412e041d2fcbe77aee6e0b412a9a301c35d
37 changes: 15 additions & 22 deletions cmd/outline-ss-server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ package main
import (
"container/list"
"context"
"errors"
"flag"
"fmt"
"log/slog"
"net"
"net/http"
"os"
"os/signal"
"strings"
"sync"
"syscall"
"time"
Expand Down Expand Up @@ -198,11 +198,6 @@ func (ls *listenerSet) Len() int {
return len(ls.listenerCloseFuncs)
}

type connWithDone struct {
net.Conn
doneCh chan struct{}
}

func (s *OutlineServer) runConfig(config Config) (func() error, error) {
startErrCh := make(chan error)
stopErrCh := make(chan error)
Expand Down Expand Up @@ -234,7 +229,7 @@ func (s *OutlineServer) runConfig(config Config) (func() error, error) {
go func() {
defer server.Shutdown(context.Background())
err := server.Serve(&HTTPStreamListener{ln})
if err != nil && err != http.ErrServerClosed && !isErrClosing(err) {
if err != nil && !errors.Is(http.ErrServerClosed, err) && !errors.Is(net.ErrClosed, err) {
slog.Error("Failed to run web server.", "err", err, "ID", srvConfig.ID)
}
}()
Expand Down Expand Up @@ -342,7 +337,7 @@ func (s *OutlineServer) runConfig(config Config) (func() error, error) {
}, s.serverMetrics)
} else if cfg.WebsocketStream != nil {
if _, exists := webServers[cfg.WebsocketStream.WebServer]; !exists {
return fmt.Errorf("listener references unknown web server `%s`", cfg.WebsocketStream.WebServer)
return fmt.Errorf("websocket-stream listener references unknown web server `%s`", cfg.WebsocketStream.WebServer)
}
mux := webServers[cfg.WebsocketStream.WebServer]
// TODO: Support a "half-closed" state for WebSockets.
Expand All @@ -351,13 +346,14 @@ func (s *OutlineServer) runConfig(config Config) (func() error, error) {
defer wsConn.Close()
ctx, contextCancel := context.WithCancel(context.Background())
defer contextCancel()
raddr, err := net.ResolveTCPAddr("tcp", r.RemoteAddr)
// TODO: Get the forwarded client address.
raddr, err := transport.MakeNetAddr("tcp", r.RemoteAddr)
if err != nil {
slog.Error("failed to upgrade", "err", err)
slog.Error("failed to determine client address", "err", err)
w.WriteHeader(http.StatusBadGateway)
return
}
conn := &streamConn{&wrappedConn{Conn: wsConn, raddr: raddr}}
conn := &streamConn{&replaceAddrConn{Conn: wsConn, raddr: raddr}}
streamHandler.HandleStream(ctx, conn, s.serviceMetrics.AddOpenTCPConnection(conn))
}
websocket.Handler(handler).ServeHTTP(w, r)
Expand All @@ -366,21 +362,21 @@ func (s *OutlineServer) runConfig(config Config) (func() error, error) {
slog.Info("WebSocket stream service started.", "ID", cfg.WebsocketStream.WebServer, "path", cfg.WebsocketStream.Path)
} else if cfg.WebsocketPacket != nil {
if _, exists := webServers[cfg.WebsocketPacket.WebServer]; !exists {
return fmt.Errorf("listener references unknown web server `%s`", cfg.WebsocketPacket.WebServer)
return fmt.Errorf("websocket-packet listener references unknown web server `%s`", cfg.WebsocketPacket.WebServer)
}
mux := webServers[cfg.WebsocketPacket.WebServer]
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
handler := func(wsConn *websocket.Conn) {
defer wsConn.Close()
ctx, contextCancel := context.WithCancel(context.Background())
defer contextCancel()
raddr, err := net.ResolveUDPAddr("udp", r.RemoteAddr)
raddr, err := transport.MakeNetAddr("udp", r.RemoteAddr)
if err != nil {
slog.Error("failed to upgrade", "err", err)
slog.Error("failed to determine client address", "err", err)
w.WriteHeader(http.StatusBadGateway)
return
}
conn := &wrappedConn{Conn: wsConn, raddr: raddr}
conn := &replaceAddrConn{Conn: wsConn, raddr: raddr}
associationHandler.HandleAssociation(ctx, conn, s.serviceMetrics.AddOpenUDPAssociation(conn))
}
websocket.Handler(handler).ServeHTTP(w, r)
Expand Down Expand Up @@ -430,10 +426,6 @@ func (s *OutlineServer) Stop() error {
return nil
}

func isErrClosing(err error) bool {
return strings.Contains(err.Error(), "use of closed network connection")
}

// RunOutlineServer starts an Outline server running, and returns the server or an error.
func RunOutlineServer(filename string, natTimeout time.Duration, serverMetrics *serverMetrics, serviceMetrics service.ServiceMetrics, replayHistory int) (*OutlineServer, error) {
server := &OutlineServer{
Expand Down Expand Up @@ -461,13 +453,13 @@ func RunOutlineServer(filename string, natTimeout time.Duration, serverMetrics *
}

// TODO: Create a dedicated `ClientConn` struct with `ClientAddr` and `Conn`.
// wrappedConn overrides [websocket.Conn]'s remote address handling.
type wrappedConn struct {
// replaceAddrConn overrides [websocket.Conn]'s remote address handling.
type replaceAddrConn struct {
*websocket.Conn
raddr net.Addr
}

func (c wrappedConn) RemoteAddr() net.Addr {
func (c replaceAddrConn) RemoteAddr() net.Addr {
return c.raddr
}

Expand All @@ -477,6 +469,7 @@ type streamConn struct {

var _ transport.StreamConn = (*streamConn)(nil)

// TODO: Support a "half-closed" state.
func (c *streamConn) CloseRead() error {
return c.Close()
}
Expand Down