mirror of
https://github.com/XTLS/Xray-core.git
synced 2026-09-17 06:50:27 +00:00
79 lines
2.3 KiB
Go
79 lines
2.3 KiB
Go
//go:build openbsd
|
|
// +build openbsd
|
|
|
|
package dokodemo
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"os"
|
|
|
|
"golang.org/x/sys/unix"
|
|
)
|
|
|
|
func FakeUDP(addr *net.UDPAddr, mark int) (net.PacketConn, error) {
|
|
domain := unix.AF_INET6
|
|
var sockaddr unix.Sockaddr
|
|
if ip4 := addr.IP.To4(); ip4 != nil {
|
|
domain = unix.AF_INET
|
|
sa := &unix.SockaddrInet4{Port: addr.Port}
|
|
copy(sa.Addr[:], ip4)
|
|
sockaddr = sa
|
|
} else if ip6 := addr.IP.To16(); ip6 != nil {
|
|
sa := &unix.SockaddrInet6{Port: addr.Port}
|
|
copy(sa.Addr[:], ip6)
|
|
if addr.Zone != "" {
|
|
iface, err := net.InterfaceByName(addr.Zone)
|
|
if err != nil {
|
|
return nil, &net.OpError{Op: "fake", Err: fmt.Errorf("resolve zone %s: %w", addr.Zone, err)}
|
|
}
|
|
sa.ZoneId = uint32(iface.Index)
|
|
}
|
|
sockaddr = sa
|
|
} else {
|
|
return nil, &net.OpError{Op: "fake", Err: fmt.Errorf("unsupported address %v", addr.IP)}
|
|
}
|
|
|
|
fd, err := unix.Socket(domain, unix.SOCK_DGRAM, 0)
|
|
if err != nil {
|
|
return nil, &net.OpError{Op: "fake", Err: fmt.Errorf("socket open: %w", err)}
|
|
}
|
|
|
|
closeFD := true
|
|
defer func() {
|
|
if closeFD {
|
|
unix.Close(fd)
|
|
}
|
|
}()
|
|
|
|
if err = unix.SetsockoptInt(fd, unix.SOL_SOCKET, unix.SO_BINDANY, 1); err != nil {
|
|
return nil, &net.OpError{Op: "fake", Err: fmt.Errorf("set socket option SO_BINDANY: %w", err)}
|
|
}
|
|
if err = unix.SetsockoptInt(fd, unix.SOL_SOCKET, unix.SO_REUSEADDR, 1); err != nil {
|
|
return nil, &net.OpError{Op: "fake", Err: fmt.Errorf("set socket option SO_REUSEADDR: %w", err)}
|
|
}
|
|
// Several client sessions can be answered from the same original
|
|
// destination at the same time, so the address has to be shareable.
|
|
if err = unix.SetsockoptInt(fd, unix.SOL_SOCKET, unix.SO_REUSEPORT, 1); err != nil {
|
|
return nil, &net.OpError{Op: "fake", Err: fmt.Errorf("set socket option SO_REUSEPORT: %w", err)}
|
|
}
|
|
|
|
if err = unix.Bind(fd, sockaddr); err != nil {
|
|
return nil, &net.OpError{Op: "fake", Err: fmt.Errorf("bind %s: %w", addr.String(), err)}
|
|
}
|
|
|
|
fdFile := os.NewFile(uintptr(fd), fmt.Sprintf("net-udp-bindany-%s", addr.String()))
|
|
if fdFile == nil {
|
|
return nil, &net.OpError{Op: "fake", Err: fmt.Errorf("convert descriptor to file")}
|
|
}
|
|
defer fdFile.Close()
|
|
|
|
packetConn, err := net.FilePacketConn(fdFile)
|
|
if err != nil {
|
|
return nil, &net.OpError{Op: "fake", Err: fmt.Errorf("convert descriptor to packet connection: %w", err)}
|
|
}
|
|
|
|
closeFD = false
|
|
return packetConn, nil
|
|
}
|