fix udp original destination on windows

This commit is contained in:
Deghy 2025-05-09 18:29:30 +03:30
parent e9b3c53a0d
commit d5c53b1ddd
5 changed files with 95 additions and 4 deletions

View File

@ -1,5 +1,5 @@
//go:build !linux //go:build !linux && !windows
// +build !linux // +build !linux,!windows
package dokodemo package dokodemo

View File

@ -0,0 +1,27 @@
//go:build windows
// +build windows
package dokodemo
import (
"net"
"syscall"
)
func FakeUDP(addr *net.UDPAddr, mark int) (net.PacketConn, error) {
udpConn, err := net.ListenUDP("udp", addr)
if err != nil {
return udpConn, err
}
rawConn, err := udpConn.SyscallConn()
if err != nil {
return nil, err
}
err = rawConn.Control(func(fd uintptr) {
syscall.SetsockoptInt(syscall.Handle(fd), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
})
if err != nil {
return nil, err
}
return udpConn, nil
}

View File

@ -11,6 +11,7 @@ import (
"unsafe" "unsafe"
"github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/errors"
"golang.org/x/sys/windows"
) )
const ( const (
@ -142,6 +143,15 @@ func applyInboundSocketOptions(network string, fd uintptr, config *SocketConfig)
} }
} }
if config.ReceiveOriginalDestAddress && isUDPSocket(network) {
if err := syscall.SetsockoptInt(syscall.Handle(fd), syscall.IPPROTO_IP, windows.IP_PKTINFO, 1); err != nil {
return errors.New("failed to set IP_PKTINFO").Base(err)
}
if err := syscall.SetsockoptInt(syscall.Handle(fd), syscall.IPPROTO_IPV6, windows.IPV6_PKTINFO, 1); err != nil {
return errors.New("failed to set IPV6_PKTINFO").Base(err)
}
}
if len(config.CustomSockopt) > 0 { if len(config.CustomSockopt) > 0 {
for _, custom := range config.CustomSockopt { for _, custom := range config.CustomSockopt {
if custom.System != "" && custom.System != runtime.GOOS { if custom.System != "" && custom.System != runtime.GOOS {

View File

@ -1,5 +1,5 @@
//go:build !linux && !freebsd && !darwin //go:build !linux && !freebsd && !darwin && !windows
// +build !linux,!freebsd,!darwin // +build !linux,!freebsd,!darwin,!windows
package udp package udp

View File

@ -0,0 +1,54 @@
//go:build windows
// +build windows
package udp
import (
"encoding/binary"
"unsafe"
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/net"
"golang.org/x/sys/windows"
)
func RetrieveOriginalDest(oob []byte) net.Destination {
dest := net.Destination{}
port := binary.LittleEndian.Uint16(oob[:2])
buf := buf.FromBytes(oob[2:])
defer buf.Release()
for !buf.IsEmpty() {
cm := &windows.WSACMSGHDR{}
len := make([]byte, unsafe.Sizeof(cm.Len))
nRead, err := buf.Read(len)
if err != nil {
return dest
}
cm.Len = uintptr(binary.LittleEndian.Uint16(len))
binary.Read(buf, binary.LittleEndian, &cm.Level)
binary.Read(buf, binary.LittleEndian, &cm.Type)
nRead += 8 // len cm.Level + cm.Type
if cm.Type == windows.IP_PKTINFO {
if cm.Level == windows.IPPROTO_IP { // IPv4
pktinf := &windows.IN_PKTINFO{}
binary.Read(buf, binary.LittleEndian, pktinf)
return net.UDPDestination(net.IPAddress(pktinf.Addr[:]), net.Port(port))
} else { // IPv6
pktinfv6 := &windows.IN6_PKTINFO{}
binary.Read(buf, binary.LittleEndian, pktinfv6)
return net.UDPDestination(net.IPAddress(pktinfv6.Addr[:]), net.Port(port))
}
}
buf.Advance(int32(cm.Len) - int32(nRead))
}
return dest
}
func ReadUDPMsg(conn *net.UDPConn, payload []byte, oob []byte) (int, int, int, *net.UDPAddr, error) {
udpAddr, _ := net.ResolveUDPAddr(conn.LocalAddr().Network(), conn.LocalAddr().String())
binary.LittleEndian.PutUint16(oob[:2], uint16(udpAddr.Port))
n, oobn, flags, addr, err := conn.ReadMsgUDP(payload, oob[2:])
return n, oobn + 2, flags, addr, err
}