github.com/xtls/xray-core@v1.8.12-0.20240518155711-3168d27b0bdb/proxy/dokodemo/fakeudp_linux.go (about)

     1  //go:build linux
     2  // +build linux
     3  
     4  package dokodemo
     5  
     6  import (
     7  	"fmt"
     8  	"net"
     9  	"os"
    10  	"syscall"
    11  
    12  	"golang.org/x/sys/unix"
    13  )
    14  
    15  func FakeUDP(addr *net.UDPAddr, mark int) (net.PacketConn, error) {
    16  	var af int
    17  	var sockaddr syscall.Sockaddr
    18  
    19  	if len(addr.IP) == 4 {
    20  		af = syscall.AF_INET
    21  		sockaddr = &syscall.SockaddrInet4{Port: addr.Port}
    22  		copy(sockaddr.(*syscall.SockaddrInet4).Addr[:], addr.IP)
    23  	} else {
    24  		af = syscall.AF_INET6
    25  		sockaddr = &syscall.SockaddrInet6{Port: addr.Port}
    26  		copy(sockaddr.(*syscall.SockaddrInet6).Addr[:], addr.IP)
    27  	}
    28  
    29  	var fd int
    30  	var err error
    31  
    32  	if fd, err = syscall.Socket(af, syscall.SOCK_DGRAM, 0); err != nil {
    33  		return nil, &net.OpError{Op: "fake", Err: fmt.Errorf("socket open: %s", err)}
    34  	}
    35  
    36  	if mark != 0 {
    37  		if err = syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_MARK, mark); err != nil {
    38  			syscall.Close(fd)
    39  			return nil, &net.OpError{Op: "fake", Err: fmt.Errorf("set socket option: SO_MARK: %s", err)}
    40  		}
    41  	}
    42  
    43  	if err = syscall.SetsockoptInt(fd, syscall.SOL_IP, syscall.IP_TRANSPARENT, 1); err != nil {
    44  		syscall.Close(fd)
    45  		return nil, &net.OpError{Op: "fake", Err: fmt.Errorf("set socket option: IP_TRANSPARENT: %s", err)}
    46  	}
    47  
    48  	syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
    49  
    50  	syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, unix.SO_REUSEPORT, 1)
    51  
    52  	if err = syscall.Bind(fd, sockaddr); err != nil {
    53  		syscall.Close(fd)
    54  		return nil, &net.OpError{Op: "fake", Err: fmt.Errorf("socket bind: %s", err)}
    55  	}
    56  
    57  	fdFile := os.NewFile(uintptr(fd), fmt.Sprintf("net-udp-fake-%s", addr.String()))
    58  	defer fdFile.Close()
    59  
    60  	packetConn, err := net.FilePacketConn(fdFile)
    61  	if err != nil {
    62  		syscall.Close(fd)
    63  		return nil, &net.OpError{Op: "fake", Err: fmt.Errorf("convert file descriptor to connection: %s", err)}
    64  	}
    65  
    66  	return packetConn, nil
    67  }