transparent_linux.go 1.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
  1. package process
  2. import (
  3. "ehang.io/nps/lib/enet"
  4. "ehang.io/nps/lib/logger"
  5. "go.uber.org/zap"
  6. "net"
  7. "strconv"
  8. "syscall"
  9. )
  10. const SO_ORIGINAL_DST = 80
  11. type TransparentProcess struct {
  12. DefaultProcess
  13. }
  14. func (tp *TransparentProcess) GetName() string {
  15. return "transparent"
  16. }
  17. func (tp *TransparentProcess) GetZhName() string {
  18. return "透明代理"
  19. }
  20. func (tp *TransparentProcess) ProcessConn(c enet.Conn) (bool, error) {
  21. addr, err := tp.getAddress(c)
  22. if err != nil {
  23. logger.Debug("get syscall error", zap.Error(err))
  24. return false, nil
  25. }
  26. return true, tp.ac.RunConnWithAddr(c, addr)
  27. }
  28. func (tp *TransparentProcess) getAddress(conn net.Conn) (string, error) {
  29. // TODO: IPV6 support
  30. sysrawConn, f := conn.(syscall.Conn)
  31. if !f {
  32. return "", nil
  33. }
  34. rawConn, err := sysrawConn.SyscallConn()
  35. if err != nil {
  36. return "", nil
  37. }
  38. var ip string
  39. var port uint16
  40. err = rawConn.Control(func(fd uintptr) {
  41. addr, err := syscall.GetsockoptIPv6Mreq(int(fd), syscall.IPPROTO_IP, SO_ORIGINAL_DST)
  42. if err != nil {
  43. return
  44. }
  45. ip = net.IP(addr.Multiaddr[4:8]).String()
  46. port = uint16(addr.Multiaddr[2])<<8 + uint16(addr.Multiaddr[3])
  47. })
  48. return net.JoinHostPort(ip, strconv.Itoa(int(port))), nil
  49. }