mirror of
https://github.com/XTLS/Xray-core.git
synced 2026-10-19 07:44: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
|
//go:build !linux && !openbsd
|
||||||
// +build !linux
|
// +build !linux,!openbsd
|
||||||
|
|
||||||
package dokodemo
|
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
|
//go:build js || netbsd || solaris
|
||||||
// +build js netbsd openbsd solaris
|
// +build js netbsd solaris
|
||||||
|
|
||||||
package internet
|
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
|
//go:build !linux && !freebsd && !darwin && !openbsd
|
||||||
// +build !linux,!freebsd,!darwin
|
// +build !linux,!freebsd,!darwin,!openbsd
|
||||||
|
|
||||||
package udp
|
package udp
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user