2021-09-20 16:00:55 +03:00
|
|
|
//go:build linux
|
2020-12-31 17:57:15 +02:00
|
|
|
// +build linux
|
|
|
|
|
|
|
|
package dokodemo
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"net"
|
|
|
|
"os"
|
|
|
|
"syscall"
|
2021-01-19 16:50:21 +02:00
|
|
|
|
|
|
|
"golang.org/x/sys/unix"
|
2020-12-31 17:57:15 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
func FakeUDP(addr *net.UDPAddr, mark int) (net.PacketConn, error) {
|
2021-01-21 01:58:59 +02:00
|
|
|
var af int
|
|
|
|
var sockaddr syscall.Sockaddr
|
|
|
|
|
|
|
|
if len(addr.IP) == 4 {
|
|
|
|
af = syscall.AF_INET
|
|
|
|
sockaddr = &syscall.SockaddrInet4{Port: addr.Port}
|
|
|
|
copy(sockaddr.(*syscall.SockaddrInet4).Addr[:], addr.IP)
|
|
|
|
} else {
|
|
|
|
af = syscall.AF_INET6
|
|
|
|
sockaddr = &syscall.SockaddrInet6{Port: addr.Port}
|
|
|
|
copy(sockaddr.(*syscall.SockaddrInet6).Addr[:], addr.IP)
|
2020-12-31 17:57:15 +02:00
|
|
|
}
|
|
|
|
|
2021-01-21 01:58:59 +02:00
|
|
|
var fd int
|
|
|
|
var err error
|
|
|
|
|
|
|
|
if fd, err = syscall.Socket(af, syscall.SOCK_DGRAM, 0); err != nil {
|
2020-12-31 17:57:15 +02:00
|
|
|
return nil, &net.OpError{Op: "fake", Err: fmt.Errorf("socket open: %s", err)}
|
|
|
|
}
|
|
|
|
|
|
|
|
if mark != 0 {
|
2021-01-21 01:58:59 +02:00
|
|
|
if err = syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_MARK, mark); err != nil {
|
|
|
|
syscall.Close(fd)
|
2020-12-31 17:57:15 +02:00
|
|
|
return nil, &net.OpError{Op: "fake", Err: fmt.Errorf("set socket option: SO_MARK: %s", err)}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-21 01:58:59 +02:00
|
|
|
if err = syscall.SetsockoptInt(fd, syscall.SOL_IP, syscall.IP_TRANSPARENT, 1); err != nil {
|
|
|
|
syscall.Close(fd)
|
|
|
|
return nil, &net.OpError{Op: "fake", Err: fmt.Errorf("set socket option: IP_TRANSPARENT: %s", err)}
|
2020-12-31 17:57:15 +02:00
|
|
|
}
|
|
|
|
|
2021-01-21 01:58:59 +02:00
|
|
|
syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
|
2021-01-19 16:50:21 +02:00
|
|
|
|
2021-01-21 01:58:59 +02:00
|
|
|
syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, unix.SO_REUSEPORT, 1)
|
2020-12-31 17:57:15 +02:00
|
|
|
|
2021-01-21 01:58:59 +02:00
|
|
|
if err = syscall.Bind(fd, sockaddr); err != nil {
|
|
|
|
syscall.Close(fd)
|
2020-12-31 17:57:15 +02:00
|
|
|
return nil, &net.OpError{Op: "fake", Err: fmt.Errorf("socket bind: %s", err)}
|
|
|
|
}
|
|
|
|
|
2021-01-21 01:58:59 +02:00
|
|
|
fdFile := os.NewFile(uintptr(fd), fmt.Sprintf("net-udp-fake-%s", addr.String()))
|
2020-12-31 17:57:15 +02:00
|
|
|
defer fdFile.Close()
|
|
|
|
|
|
|
|
packetConn, err := net.FilePacketConn(fdFile)
|
|
|
|
if err != nil {
|
2021-01-21 01:58:59 +02:00
|
|
|
syscall.Close(fd)
|
2020-12-31 17:57:15 +02:00
|
|
|
return nil, &net.OpError{Op: "fake", Err: fmt.Errorf("convert file descriptor to connection: %s", err)}
|
|
|
|
}
|
|
|
|
|
|
|
|
return packetConn, nil
|
|
|
|
}
|