1
1
package internet
2
2
3
3
import (
4
+ "github.com/xtls/xray-core/common/net"
4
5
"golang.org/x/sys/unix"
6
+ "os"
7
+ "syscall"
8
+ "unsafe"
5
9
)
6
10
7
11
const (
@@ -13,6 +17,83 @@ const (
13
17
sysTCP_KEEPINTVL = 0x101 // nolint: revive,stylecheck
14
18
)
15
19
20
+ const (
21
+ PfOut = 2
22
+ IOCOut = 0x40000000
23
+ IOCIn = 0x80000000
24
+ IOCInOut = IOCIn | IOCOut
25
+ IOCPARMMask = 0x1FFF
26
+ LEN = 4 * 16 + 4 * 4 + 4 * 1
27
+ // #define _IOC(inout,group,num,len) (inout | ((len & IOCPARMMask) << 16) | ((group) << 8) | (num))
28
+ // #define _IOWR(g,n,t) _IOC(IOCInOut, (g), (n), sizeof(t))
29
+ // #define DIOCNATLOOK _IOWR('D', 23, struct pfioc_natlook)
30
+ DIOCNATLOOK = IOCInOut | ((LEN & IOCPARMMask ) << 16 ) | ('D' << 8 ) | 23
31
+ )
32
+
33
+ // OriginalDst uses ioctl to read original destination from /dev/pf
34
+ func OriginalDst (la , ra net.Addr ) (net.IP , int , error ) {
35
+ f , err := os .Open ("/dev/pf" )
36
+ if err != nil {
37
+ return net.IP {}, - 1 , newError ("failed to open device /dev/pf" ).Base (err )
38
+ }
39
+ defer f .Close ()
40
+ fd := f .Fd ()
41
+ nl := struct { // struct pfioc_natlook
42
+ saddr , daddr , rsaddr , rdaddr [16 ]byte
43
+ sxport , dxport , rsxport , rdxport [4 ]byte
44
+ af , proto , protoVariant , direction uint8
45
+ }{
46
+ af : syscall .AF_INET ,
47
+ proto : syscall .IPPROTO_TCP ,
48
+ direction : PfOut ,
49
+ }
50
+ var raIP , laIP net.IP
51
+ var raPort , laPort int
52
+ switch la .(type ) {
53
+ case * net.TCPAddr :
54
+ raIP = ra .(* net.TCPAddr ).IP
55
+ laIP = la .(* net.TCPAddr ).IP
56
+ raPort = ra .(* net.TCPAddr ).Port
57
+ laPort = la .(* net.TCPAddr ).Port
58
+ case * net.UDPAddr :
59
+ raIP = ra .(* net.UDPAddr ).IP
60
+ laIP = la .(* net.UDPAddr ).IP
61
+ raPort = ra .(* net.UDPAddr ).Port
62
+ laPort = la .(* net.UDPAddr ).Port
63
+ }
64
+ if raIP .To4 () != nil {
65
+ if laIP .IsUnspecified () {
66
+ laIP = net .ParseIP ("127.0.0.1" )
67
+ }
68
+ copy (nl .saddr [:net .IPv4len ], raIP .To4 ())
69
+ copy (nl .daddr [:net .IPv4len ], laIP .To4 ())
70
+ }
71
+ if raIP .To16 () != nil && raIP .To4 () == nil {
72
+ if laIP .IsUnspecified () {
73
+ laIP = net .ParseIP ("::1" )
74
+ }
75
+ copy (nl .saddr [:], raIP )
76
+ copy (nl .daddr [:], laIP )
77
+ }
78
+ nl .sxport [0 ], nl .sxport [1 ] = byte (raPort >> 8 ), byte (raPort )
79
+ nl .dxport [0 ], nl .dxport [1 ] = byte (laPort >> 8 ), byte (laPort )
80
+ if _ , _ , errno := syscall .Syscall (syscall .SYS_IOCTL , fd , DIOCNATLOOK , uintptr (unsafe .Pointer (& nl ))); errno != 0 {
81
+ return net.IP {}, - 1 , os .NewSyscallError ("ioctl" , err )
82
+ }
83
+
84
+ odPort := nl .rdxport
85
+ var odIP net.IP
86
+ switch nl .af {
87
+ case syscall .AF_INET :
88
+ odIP = make (net.IP , net .IPv4len )
89
+ copy (odIP , nl .rdaddr [:net .IPv4len ])
90
+ case syscall .AF_INET6 :
91
+ odIP = make (net.IP , net .IPv6len )
92
+ copy (odIP , nl .rdaddr [:])
93
+ }
94
+ return odIP , int (net .PortFromBytes (odPort [:2 ])), nil
95
+ }
96
+
16
97
func applyOutboundSocketOptions (network string , address string , fd uintptr , config * SocketConfig ) error {
17
98
if isTCPSocket (network ) {
18
99
tfo := config .ParseTFOValue ()
0 commit comments