Skip to content

Commit 40bb47e

Browse files
committed
feat(x): adopt modern PacketRelay natively in outline-cli
1 parent b6c7e2c commit 40bb47e

3 files changed

Lines changed: 86 additions & 3 deletions

File tree

x/examples/outline-cli/outline_device.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ const (
3636
type OutlineDevice struct {
3737
network.IPDevice
3838
sd transport.StreamDialer
39-
pp *outlinePacketProxy
39+
pp *outlinePacketRelay
4040
svrIP net.IP
4141
}
4242

@@ -54,10 +54,10 @@ func NewOutlineDevice(transportConfig string) (od *OutlineDevice, err error) {
5454
if od.sd, err = configModule.NewStreamDialer(context.TODO(), transportConfig); err != nil {
5555
return nil, fmt.Errorf("failed to create TCP dialer: %w", err)
5656
}
57-
if od.pp, err = newOutlinePacketProxy(transportConfig); err != nil {
57+
if od.pp, err = newOutlinePacketRelay(transportConfig); err != nil {
5858
return nil, fmt.Errorf("failed to create delegate UDP proxy: %w", err)
5959
}
60-
if od.IPDevice, err = lwip2transport.ConfigureDevice(od.sd, od.pp); err != nil {
60+
if od.IPDevice, err = lwip2transport.ConfigureDeviceWithRelay(od.sd, od.pp); err != nil {
6161
return nil, fmt.Errorf("failed to configure lwIP: %w", err)
6262
}
6363

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// Copyright 2026 The Outline Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package main
16+
17+
import (
18+
"context"
19+
"fmt"
20+
"time"
21+
22+
"golang.getoutline.org/sdk/dns"
23+
"golang.getoutline.org/sdk/network/dnstruncate"
24+
"golang.getoutline.org/sdk/network/packetrelay"
25+
"golang.getoutline.org/sdk/transport"
26+
"golang.getoutline.org/sdk/x/configurl"
27+
"golang.getoutline.org/sdk/x/connectivity"
28+
)
29+
30+
type outlinePacketRelay struct {
31+
packetrelay.DelegatePacketRelay
32+
33+
remote, fallback packetrelay.PacketRelay
34+
remotePl transport.PacketListener
35+
}
36+
37+
func newOutlinePacketRelay(transportConfig string) (opp *outlinePacketRelay, err error) {
38+
opp = &outlinePacketRelay{}
39+
40+
if opp.remotePl, err = configurl.NewDefaultProviders().NewPacketListener(context.TODO(), transportConfig); err != nil {
41+
return nil, fmt.Errorf("failed to create UDP packet listener: %w", err)
42+
}
43+
44+
// Create the underlying base relay
45+
baseRemote, err := packetrelay.NewPacketRelayFromPacketListener(opp.remotePl)
46+
if err != nil {
47+
return nil, fmt.Errorf("failed to create UDP packet relay: %w", err)
48+
}
49+
50+
// Layer the 30s timeout explicitly
51+
opp.remote, err = packetrelay.NewTimeoutPacketRelay(baseRemote, 30*time.Second)
52+
if err != nil {
53+
return nil, fmt.Errorf("failed to layer timeout on remote UDP relay: %w", err)
54+
}
55+
56+
if opp.fallback, err = dnstruncate.NewPacketRelay(); err != nil {
57+
return nil, fmt.Errorf("failed to create DNS truncate packet relay: %w", err)
58+
}
59+
if opp.DelegatePacketRelay, err = packetrelay.NewDelegatePacketRelay(opp.fallback); err != nil {
60+
return nil, fmt.Errorf("failed to create delegate UDP relay: %w", err)
61+
}
62+
63+
return
64+
}
65+
66+
func (proxy *outlinePacketRelay) testConnectivityAndRefresh(resolverAddr, domain string) error {
67+
dialer := transport.PacketListenerDialer{Listener: proxy.remotePl}
68+
dnsResolver := dns.NewUDPResolver(dialer, resolverAddr)
69+
result, err := connectivity.TestConnectivityWithResolver(context.Background(), dnsResolver, domain)
70+
if err != nil {
71+
logging.Info.Printf("connectivity test failed. Refresh skipped. Error: %v\n", err)
72+
return err
73+
}
74+
if result != nil {
75+
logging.Info.Println("remote server cannot handle UDP traffic, switch to DNS truncate mode.")
76+
return proxy.SetRelay(proxy.fallback)
77+
} else {
78+
logging.Info.Println("remote server supports UDP, we will delegate all UDP packets to it")
79+
return proxy.SetRelay(proxy.remote)
80+
}
81+
}

x/go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,3 +138,5 @@ require (
138138
)
139139

140140
tool honnef.co/go/tools/cmd/staticcheck
141+
142+
replace golang.getoutline.org/sdk => ../

0 commit comments

Comments
 (0)