fakeudp_linux.go 1.7 KB

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