mirror of
https://github.com/XTLS/Xray-core.git
synced 2026-09-15 22:10:26 +00:00
Tunnel inbound: Support TPROXY on OpenBSD as well (#6546)
https://github.com/XTLS/Xray-core/pull/6546#issuecomment-5100711574
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
//go:build openbsd
|
||||
// +build openbsd
|
||||
|
||||
package dokodemo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func FakeUDP(addr *net.UDPAddr, mark int) (net.PacketConn, error) {
|
||||
ip4 := addr.IP.To4()
|
||||
if ip4 == nil {
|
||||
return nil, &net.OpError{Op: "fake", Err: fmt.Errorf("IPv6 is not supported by the OpenBSD transparent UDP patch")}
|
||||
}
|
||||
|
||||
fd, err := unix.Socket(unix.AF_INET, unix.SOCK_DGRAM, 0)
|
||||
if err != nil {
|
||||
return nil, &net.OpError{Op: "fake", Err: fmt.Errorf("socket open: %w", err)}
|
||||
}
|
||||
|
||||
closeFD := true
|
||||
defer func() {
|
||||
if closeFD {
|
||||
unix.Close(fd)
|
||||
}
|
||||
}()
|
||||
|
||||
if err = unix.SetsockoptInt(fd, unix.SOL_SOCKET, unix.SO_BINDANY, 1); err != nil {
|
||||
return nil, &net.OpError{Op: "fake", Err: fmt.Errorf("set socket option SO_BINDANY: %w", err)}
|
||||
}
|
||||
if err = unix.SetsockoptInt(fd, unix.SOL_SOCKET, unix.SO_REUSEADDR, 1); err != nil {
|
||||
return nil, &net.OpError{Op: "fake", Err: fmt.Errorf("set socket option SO_REUSEADDR: %w", err)}
|
||||
}
|
||||
|
||||
sockaddr := &unix.SockaddrInet4{Port: addr.Port}
|
||||
copy(sockaddr.Addr[:], ip4)
|
||||
if err = unix.Bind(fd, sockaddr); err != nil {
|
||||
return nil, &net.OpError{Op: "fake", Err: fmt.Errorf("bind %s: %w", addr.String(), err)}
|
||||
}
|
||||
|
||||
fdFile := os.NewFile(uintptr(fd), fmt.Sprintf("net-udp-bindany-%s", addr.String()))
|
||||
if fdFile == nil {
|
||||
return nil, &net.OpError{Op: "fake", Err: fmt.Errorf("convert descriptor to file")}
|
||||
}
|
||||
defer fdFile.Close()
|
||||
|
||||
packetConn, err := net.FilePacketConn(fdFile)
|
||||
if err != nil {
|
||||
return nil, &net.OpError{Op: "fake", Err: fmt.Errorf("convert descriptor to packet connection: %w", err)}
|
||||
}
|
||||
|
||||
closeFD = false
|
||||
return packetConn, nil
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
//go:build !linux
|
||||
// +build !linux
|
||||
//go:build !linux && !openbsd
|
||||
// +build !linux,!openbsd
|
||||
|
||||
package dokodemo
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
//go:build openbsd
|
||||
// +build openbsd
|
||||
|
||||
package internet
|
||||
|
||||
import (
|
||||
"github.com/xtls/xray-core/common/errors"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func applyOutboundSocketOptions(network string, address string, fd uintptr, config *SocketConfig) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func applyInboundSocketOptions(network string, fd uintptr, config *SocketConfig) error {
|
||||
if config.ReceiveOriginalDestAddress && isUDPSocket(network) {
|
||||
if err := unix.SetsockoptInt(int(fd), unix.IPPROTO_IP, unix.IP_RECVDSTADDR, 1); err != nil {
|
||||
return errors.New("failed to set IP_RECVDSTADDR").Base(err)
|
||||
}
|
||||
if err := unix.SetsockoptInt(int(fd), unix.IPPROTO_IP, unix.IP_RECVDSTPORT, 1); err != nil {
|
||||
return errors.New("failed to set IP_RECVDSTPORT").Base(err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func setReuseAddr(fd uintptr) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func setReusePort(fd uintptr) error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
//go:build js || netbsd || openbsd || solaris
|
||||
// +build js netbsd openbsd solaris
|
||||
//go:build js || netbsd || solaris
|
||||
// +build js netbsd solaris
|
||||
|
||||
package internet
|
||||
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
//go:build openbsd
|
||||
// +build openbsd
|
||||
|
||||
package udp
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/xtls/xray-core/common/net"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func retrieveOriginalDestFromControlMessages(msgs []unix.SocketControlMessage) net.Destination {
|
||||
var ip []byte
|
||||
var port uint16
|
||||
var haveAddress bool
|
||||
var havePort bool
|
||||
|
||||
for _, msg := range msgs {
|
||||
if msg.Header.Level != unix.IPPROTO_IP {
|
||||
continue
|
||||
}
|
||||
|
||||
switch msg.Header.Type {
|
||||
case unix.IP_RECVDSTADDR:
|
||||
if len(msg.Data) < 4 {
|
||||
continue
|
||||
}
|
||||
ip = append(ip[:0], msg.Data[:4]...)
|
||||
haveAddress = true
|
||||
case unix.IP_RECVDSTPORT:
|
||||
if len(msg.Data) < 2 {
|
||||
continue
|
||||
}
|
||||
port = binary.BigEndian.Uint16(msg.Data[:2])
|
||||
havePort = true
|
||||
}
|
||||
}
|
||||
|
||||
if !haveAddress || !havePort || port == 0 {
|
||||
return net.Destination{}
|
||||
}
|
||||
|
||||
return net.UDPDestination(net.IPAddress(ip), net.Port(port))
|
||||
}
|
||||
|
||||
func RetrieveOriginalDest(oob []byte) net.Destination {
|
||||
msgs, err := unix.ParseSocketControlMessage(oob)
|
||||
if err != nil {
|
||||
return net.Destination{}
|
||||
}
|
||||
return retrieveOriginalDestFromControlMessages(msgs)
|
||||
}
|
||||
|
||||
func ReadUDPMsg(conn *net.UDPConn, payload []byte, oob []byte) (int, int, int, *net.UDPAddr, error) {
|
||||
return conn.ReadMsgUDP(payload, oob)
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
//go:build openbsd
|
||||
// +build openbsd
|
||||
|
||||
package udp
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func TestRetrieveOriginalDestFromControlMessages(t *testing.T) {
|
||||
msgs := []unix.SocketControlMessage{
|
||||
{
|
||||
Header: unix.Cmsghdr{Level: unix.IPPROTO_IP, Type: unix.IP_RECVDSTPORT},
|
||||
Data: []byte{0x30, 0x39},
|
||||
},
|
||||
{
|
||||
Header: unix.Cmsghdr{Level: unix.IPPROTO_IP, Type: unix.IP_RECVDSTADDR},
|
||||
Data: []byte{203, 0, 113, 7},
|
||||
},
|
||||
}
|
||||
|
||||
dest := retrieveOriginalDestFromControlMessages(msgs)
|
||||
if !dest.IsValid() {
|
||||
t.Fatal("destination is invalid")
|
||||
}
|
||||
if got, want := dest.Address.String(), "203.0.113.7"; got != want {
|
||||
t.Fatalf("address = %q, want %q", got, want)
|
||||
}
|
||||
if got, want := dest.Port.Value(), uint16(12345); got != want {
|
||||
t.Fatalf("port = %d, want %d", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRetrieveOriginalDestRequiresAddressAndPort(t *testing.T) {
|
||||
tests := [][]unix.SocketControlMessage{
|
||||
{
|
||||
{
|
||||
Header: unix.Cmsghdr{Level: unix.IPPROTO_IP, Type: unix.IP_RECVDSTADDR},
|
||||
Data: []byte{203, 0, 113, 7},
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
Header: unix.Cmsghdr{Level: unix.IPPROTO_IP, Type: unix.IP_RECVDSTPORT},
|
||||
Data: []byte{0x30, 0x39},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, msgs := range tests {
|
||||
if dest := retrieveOriginalDestFromControlMessages(msgs); dest.IsValid() {
|
||||
t.Fatalf("unexpected destination: %v", dest)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
//go:build !linux && !freebsd && !darwin
|
||||
// +build !linux,!freebsd,!darwin
|
||||
//go:build !linux && !freebsd && !darwin && !openbsd
|
||||
// +build !linux,!freebsd,!darwin,!openbsd
|
||||
|
||||
package udp
|
||||
|
||||
|
||||
Reference in New Issue
Block a user