Skip to content

Commit fc0b1f9

Browse files
committed
fix: creating start function for windows and other unix implementations
The wireguard-go windows implementation doesn't implement with the same function signature as other OS implementations for the IPC package, this commit is creating a endpoint start function for windows and another for unix implementations with the hope that the IPC stuff is fixed. The windows IPC implementation create and manage pipe, the linux receives one as parameter
1 parent 7392877 commit fc0b1f9

4 files changed

Lines changed: 249 additions & 111 deletions

File tree

transport/amnezia/endpoint.go

Lines changed: 1 addition & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,17 @@ import (
44
"context"
55
"encoding/base64"
66
"encoding/hex"
7-
"errors"
8-
"fmt"
97
"net"
108
"net/netip"
119
"os"
12-
"strings"
1310

1411
"github.com/sagernet/sing-box/transport/wireguard"
15-
"github.com/sagernet/sing/common"
1612
E "github.com/sagernet/sing/common/exceptions"
1713
F "github.com/sagernet/sing/common/format"
1814
M "github.com/sagernet/sing/common/metadata"
1915
"github.com/sagernet/sing/common/x/list"
20-
"github.com/sagernet/sing/service"
2116
"github.com/sagernet/sing/service/pause"
22-
"github.com/sagernet/wireguard-go/conn"
2317
"github.com/sagernet/wireguard-go/device"
24-
"github.com/sagernet/wireguard-go/ipc"
2518

2619
"go4.org/netipx"
2720
)
@@ -152,111 +145,8 @@ func NewEndpoint(options EndpointOptions) (*Endpoint, error) {
152145
tunDevice: tunDevice,
153146
}, nil
154147
}
155-
156148
func (e *Endpoint) Start(resolve bool) error {
157-
if common.Any(e.peers, func(peer peerConfig) bool {
158-
return !peer.endpoint.IsValid() && peer.destination.IsFqdn()
159-
}) {
160-
if !resolve {
161-
return nil
162-
}
163-
for peerIndex, peer := range e.peers {
164-
if peer.endpoint.IsValid() || !peer.destination.IsFqdn() {
165-
continue
166-
}
167-
destinationAddress, err := e.options.ResolvePeer(peer.destination.Fqdn)
168-
if err != nil {
169-
return E.Cause(err, "resolve endpoint domain for peer[", peerIndex, "]: ", peer.destination)
170-
}
171-
e.peers[peerIndex].endpoint = netip.AddrPortFrom(destinationAddress, peer.destination.Port)
172-
}
173-
} else if resolve {
174-
return nil
175-
}
176-
177-
fileUAPI, uapiErr := ipc.UAPIOpen(e.options.Name)
178-
if uapiErr != nil {
179-
return fmt.Errorf("failed to open uapi socket for %s: %w", e.options.Name, uapiErr)
180-
}
181-
182-
var bind conn.Bind
183-
wgListener, isWgListener := e.options.Dialer.(conn.Listener)
184-
if isWgListener {
185-
bind = conn.NewStdNetBind(wgListener)
186-
} else {
187-
var (
188-
isConnect bool
189-
connectAddr netip.AddrPort
190-
reserved [3]uint8
191-
)
192-
if len(e.peers) == 1 {
193-
isConnect = true
194-
connectAddr = e.peers[0].endpoint
195-
reserved = e.peers[0].reserved
196-
}
197-
bind = wireguard.NewClientBind(e.options.Context, e.options.Logger, e.options.Dialer, isConnect, connectAddr, reserved)
198-
}
199-
if isWgListener || len(e.peers) > 1 {
200-
for _, peer := range e.peers {
201-
if peer.reserved != [3]uint8{} {
202-
bind.SetReservedForEndpoint(peer.endpoint, peer.reserved)
203-
}
204-
}
205-
}
206-
err := e.tunDevice.Start()
207-
if err != nil {
208-
return err
209-
}
210-
logger := &device.Logger{
211-
Verbosef: func(format string, args ...interface{}) {
212-
e.options.Logger.Debug(fmt.Sprintf(strings.ToLower(format), args...))
213-
},
214-
Errorf: func(format string, args ...interface{}) {
215-
e.options.Logger.Error(fmt.Sprintf(strings.ToLower(format), args...))
216-
},
217-
}
218-
wgDevice := device.NewDevice(e.options.Context, e.tunDevice, bind, logger, e.options.Workers)
219-
220-
uapi, err := ipc.UAPIListen(e.options.Name, fileUAPI)
221-
if err != nil {
222-
return fmt.Errorf("failed to listen on uapi socket: %v", err)
223-
}
224-
225-
go func() {
226-
for {
227-
select {
228-
case <-e.options.Context.Done():
229-
uapi.Close()
230-
return
231-
default:
232-
conn, err := uapi.Accept()
233-
if err != nil {
234-
if errors.Is(err, net.ErrClosed) {
235-
return
236-
}
237-
e.options.Logger.Error(E.Cause(err, "uapi accept error"))
238-
continue // any other accept error, just continue
239-
}
240-
go wgDevice.IpcHandle(conn)
241-
}
242-
}
243-
}()
244-
245-
e.tunDevice.SetDevice(wgDevice)
246-
ipcConf := e.ipcConf
247-
for _, peer := range e.peers {
248-
ipcConf += peer.GenerateIpcLines()
249-
}
250-
err = wgDevice.IpcSet(ipcConf)
251-
if err != nil {
252-
return E.Cause(err, "setup wireguard: \n", ipcConf)
253-
}
254-
e.device = wgDevice
255-
e.pauseManager = service.FromContext[pause.Manager](e.options.Context)
256-
if e.pauseManager != nil {
257-
e.pauseCallback = e.pauseManager.RegisterCallback(e.onPauseUpdated)
258-
}
259-
return nil
149+
return start(e, resolve)
260150
}
261151

262152
func (e *Endpoint) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {

transport/amnezia/endpoint_options.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// Package amnezia implements the amnezia transport endpoint
12
package amnezia
23

34
import (
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
//go:build linux || darwin || freebsd || openbsd
2+
3+
package amnezia
4+
5+
import (
6+
"errors"
7+
"fmt"
8+
"net"
9+
"net/netip"
10+
"strings"
11+
12+
"github.com/sagernet/sing-box/transport/wireguard"
13+
"github.com/sagernet/sing/common"
14+
E "github.com/sagernet/sing/common/exceptions"
15+
"github.com/sagernet/sing/service"
16+
"github.com/sagernet/sing/service/pause"
17+
"github.com/sagernet/wireguard-go/conn"
18+
"github.com/sagernet/wireguard-go/device"
19+
"github.com/sagernet/wireguard-go/ipc"
20+
)
21+
22+
func start(e *Endpoint, resolve bool) error {
23+
if common.Any(e.peers, func(peer peerConfig) bool {
24+
return !peer.endpoint.IsValid() && peer.destination.IsFqdn()
25+
}) {
26+
if !resolve {
27+
return nil
28+
}
29+
for peerIndex, peer := range e.peers {
30+
if peer.endpoint.IsValid() || !peer.destination.IsFqdn() {
31+
continue
32+
}
33+
destinationAddress, err := e.options.ResolvePeer(peer.destination.Fqdn)
34+
if err != nil {
35+
return E.Cause(err, "resolve endpoint domain for peer[", peerIndex, "]: ", peer.destination)
36+
}
37+
e.peers[peerIndex].endpoint = netip.AddrPortFrom(destinationAddress, peer.destination.Port)
38+
}
39+
} else if resolve {
40+
return nil
41+
}
42+
43+
fileUAPI, uapiErr := ipc.UAPIOpen(e.options.Name)
44+
if uapiErr != nil {
45+
return fmt.Errorf("failed to open uapi socket for %s: %w", e.options.Name, uapiErr)
46+
}
47+
48+
var bind conn.Bind
49+
wgListener, isWgListener := e.options.Dialer.(conn.Listener)
50+
if isWgListener {
51+
bind = conn.NewStdNetBind(wgListener)
52+
} else {
53+
var (
54+
isConnect bool
55+
connectAddr netip.AddrPort
56+
reserved [3]uint8
57+
)
58+
if len(e.peers) == 1 {
59+
isConnect = true
60+
connectAddr = e.peers[0].endpoint
61+
reserved = e.peers[0].reserved
62+
}
63+
bind = wireguard.NewClientBind(e.options.Context, e.options.Logger, e.options.Dialer, isConnect, connectAddr, reserved)
64+
}
65+
if isWgListener || len(e.peers) > 1 {
66+
for _, peer := range e.peers {
67+
if peer.reserved != [3]uint8{} {
68+
bind.SetReservedForEndpoint(peer.endpoint, peer.reserved)
69+
}
70+
}
71+
}
72+
err := e.tunDevice.Start()
73+
if err != nil {
74+
return err
75+
}
76+
logger := &device.Logger{
77+
Verbosef: func(format string, args ...interface{}) {
78+
e.options.Logger.Debug(fmt.Sprintf(strings.ToLower(format), args...))
79+
},
80+
Errorf: func(format string, args ...interface{}) {
81+
e.options.Logger.Error(fmt.Sprintf(strings.ToLower(format), args...))
82+
},
83+
}
84+
wgDevice := device.NewDevice(e.options.Context, e.tunDevice, bind, logger, e.options.Workers)
85+
86+
uapi, err := ipc.UAPIListen(e.options.Name, fileUAPI)
87+
if err != nil {
88+
return fmt.Errorf("failed to listen on uapi socket: %v", err)
89+
}
90+
91+
go func() {
92+
for {
93+
select {
94+
case <-e.options.Context.Done():
95+
uapi.Close()
96+
return
97+
default:
98+
conn, err := uapi.Accept()
99+
if err != nil {
100+
if errors.Is(err, net.ErrClosed) {
101+
return
102+
}
103+
e.options.Logger.Error(E.Cause(err, "uapi accept error"))
104+
continue // any other accept error, just continue
105+
}
106+
go wgDevice.IpcHandle(conn)
107+
}
108+
}
109+
}()
110+
111+
e.tunDevice.SetDevice(wgDevice)
112+
ipcConf := e.ipcConf
113+
for _, peer := range e.peers {
114+
ipcConf += peer.GenerateIpcLines()
115+
}
116+
err = wgDevice.IpcSet(ipcConf)
117+
if err != nil {
118+
return E.Cause(err, "setup wireguard: \n", ipcConf)
119+
}
120+
e.device = wgDevice
121+
e.pauseManager = service.FromContext[pause.Manager](e.options.Context)
122+
if e.pauseManager != nil {
123+
e.pauseCallback = e.pauseManager.RegisterCallback(e.onPauseUpdated)
124+
}
125+
return nil
126+
}
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
//go:build windows
2+
3+
package amnezia
4+
5+
import (
6+
"errors"
7+
"fmt"
8+
"net"
9+
"net/netip"
10+
"strings"
11+
12+
"github.com/sagernet/sing-box/transport/wireguard"
13+
"github.com/sagernet/sing/common"
14+
E "github.com/sagernet/sing/common/exceptions"
15+
"github.com/sagernet/sing/service"
16+
"github.com/sagernet/sing/service/pause"
17+
"github.com/sagernet/wireguard-go/conn"
18+
"github.com/sagernet/wireguard-go/device"
19+
"github.com/sagernet/wireguard-go/ipc"
20+
)
21+
22+
func start(e *Endpoint, resolve bool) error {
23+
if common.Any(e.peers, func(peer peerConfig) bool {
24+
return !peer.endpoint.IsValid() && peer.destination.IsFqdn()
25+
}) {
26+
if !resolve {
27+
return nil
28+
}
29+
for peerIndex, peer := range e.peers {
30+
if peer.endpoint.IsValid() || !peer.destination.IsFqdn() {
31+
continue
32+
}
33+
destinationAddress, err := e.options.ResolvePeer(peer.destination.Fqdn)
34+
if err != nil {
35+
return E.Cause(err, "resolve endpoint domain for peer[", peerIndex, "]: ", peer.destination)
36+
}
37+
e.peers[peerIndex].endpoint = netip.AddrPortFrom(destinationAddress, peer.destination.Port)
38+
}
39+
} else if resolve {
40+
return nil
41+
}
42+
43+
var bind conn.Bind
44+
wgListener, isWgListener := e.options.Dialer.(conn.Listener)
45+
if isWgListener {
46+
bind = conn.NewStdNetBind(wgListener)
47+
} else {
48+
var (
49+
isConnect bool
50+
connectAddr netip.AddrPort
51+
reserved [3]uint8
52+
)
53+
if len(e.peers) == 1 {
54+
isConnect = true
55+
connectAddr = e.peers[0].endpoint
56+
reserved = e.peers[0].reserved
57+
}
58+
bind = wireguard.NewClientBind(e.options.Context, e.options.Logger, e.options.Dialer, isConnect, connectAddr, reserved)
59+
}
60+
if isWgListener || len(e.peers) > 1 {
61+
for _, peer := range e.peers {
62+
if peer.reserved != [3]uint8{} {
63+
bind.SetReservedForEndpoint(peer.endpoint, peer.reserved)
64+
}
65+
}
66+
}
67+
err := e.tunDevice.Start()
68+
if err != nil {
69+
return err
70+
}
71+
logger := &device.Logger{
72+
Verbosef: func(format string, args ...interface{}) {
73+
e.options.Logger.Debug(fmt.Sprintf(strings.ToLower(format), args...))
74+
},
75+
Errorf: func(format string, args ...interface{}) {
76+
e.options.Logger.Error(fmt.Sprintf(strings.ToLower(format), args...))
77+
},
78+
}
79+
wgDevice := device.NewDevice(e.options.Context, e.tunDevice, bind, logger, e.options.Workers)
80+
81+
uapi, err := ipc.UAPIListen(e.options.Name)
82+
if err != nil {
83+
return fmt.Errorf("failed to listen on uapi socket: %v", err)
84+
}
85+
86+
go func() {
87+
for {
88+
select {
89+
case <-e.options.Context.Done():
90+
uapi.Close()
91+
return
92+
default:
93+
conn, err := uapi.Accept()
94+
if err != nil {
95+
if errors.Is(err, net.ErrClosed) {
96+
return
97+
}
98+
e.options.Logger.Error(E.Cause(err, "uapi accept error"))
99+
continue // any other accept error, just continue
100+
}
101+
go wgDevice.IpcHandle(conn)
102+
}
103+
}
104+
}()
105+
106+
e.tunDevice.SetDevice(wgDevice)
107+
ipcConf := e.ipcConf
108+
for _, peer := range e.peers {
109+
ipcConf += peer.GenerateIpcLines()
110+
}
111+
err = wgDevice.IpcSet(ipcConf)
112+
if err != nil {
113+
return E.Cause(err, "setup wireguard: \n", ipcConf)
114+
}
115+
e.device = wgDevice
116+
e.pauseManager = service.FromContext[pause.Manager](e.options.Context)
117+
if e.pauseManager != nil {
118+
e.pauseCallback = e.pauseManager.RegisterCallback(e.onPauseUpdated)
119+
}
120+
return nil
121+
}

0 commit comments

Comments
 (0)