fakeudp_linux.go 1.8 KB

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