From cfb01291524da1bf3a9d201d99e7c8df3591a716 Mon Sep 17 00:00:00 2001 From: Kleissner Date: Tue, 16 Mar 2021 14:24:37 +0100 Subject: [PATCH] Forking dependency reuseport. Close #8 --- Network IPv4 Broadcast.go | 2 +- Network IPv6 Multicast.go | 2 +- README.md | 1 - reuseport/README.md | 42 +++++++++++++++++++++++ reuseport/addr.go | 20 +++++++++++ reuseport/control_plan9.go | 9 +++++ reuseport/control_unix.go | 25 ++++++++++++++ reuseport/control_wasm.go | 11 +++++++ reuseport/control_windows.go | 13 ++++++++ reuseport/interface.go | 64 ++++++++++++++++++++++++++++++++++++ 10 files changed, 186 insertions(+), 3 deletions(-) create mode 100644 reuseport/README.md create mode 100644 reuseport/addr.go create mode 100644 reuseport/control_plan9.go create mode 100644 reuseport/control_unix.go create mode 100644 reuseport/control_wasm.go create mode 100644 reuseport/control_windows.go create mode 100644 reuseport/interface.go diff --git a/Network IPv4 Broadcast.go b/Network IPv4 Broadcast.go index 3d91d20..74673a6 100644 --- a/Network IPv4 Broadcast.go +++ b/Network IPv4 Broadcast.go @@ -15,8 +15,8 @@ import ( "strconv" "time" + "github.com/PeernetOfficial/core/reuseport" "github.com/btcsuite/btcd/btcec" - "github.com/libp2p/go-reuseport" ) const ipv4BroadcastPort = 12912 diff --git a/Network IPv6 Multicast.go b/Network IPv6 Multicast.go index 69b273f..82f837b 100644 --- a/Network IPv6 Multicast.go +++ b/Network IPv6 Multicast.go @@ -23,8 +23,8 @@ import ( "strconv" "time" + "github.com/PeernetOfficial/core/reuseport" "github.com/btcsuite/btcd/btcec" - "github.com/libp2p/go-reuseport" "golang.org/x/net/ipv6" ) diff --git a/README.md b/README.md index b600677..b764282 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,6 @@ Go 1.16 or higher is required. Before compiling, make sure to download and updat ``` go get -u github.com/btcsuite/btcd/btcec -go get -u github.com/libp2p/go-reuseport go get -u lukechampine.com/blake3 ``` diff --git a/reuseport/README.md b/reuseport/README.md new file mode 100644 index 0000000..8a39eff --- /dev/null +++ b/reuseport/README.md @@ -0,0 +1,42 @@ +# reuseport + +This is a fork from `https://github.com/libp2p/go-reuseport`. Last sync of changes: 16.03.2021 + +**NOTE:** This package REQUIRES go >= 1.11. + +This package enables listening and dialing from _the same_ TCP or UDP port. +This means that the following sockopts may be set: + +``` +SO_REUSEADDR +SO_REUSEPORT +``` + +This is a simple package to help with address reuse. This is particularly +important when attempting to do TCP NAT holepunching, which requires a process +to both Listen and Dial on the same TCP port. This package provides some +utilities around enabling this behaviour on various OS. + +## Examples + + +```Go +// listen on the same port. oh yeah. +l1, _ := reuse.Listen("tcp", "127.0.0.1:1234") +l2, _ := reuse.Listen("tcp", "127.0.0.1:1234") +``` + +```Go +// dial from the same port. oh yeah. +l1, _ := reuse.Listen("tcp", "127.0.0.1:1234") +l2, _ := reuse.Listen("tcp", "127.0.0.1:1235") +c, _ := reuse.Dial("tcp", "127.0.0.1:1234", "127.0.0.1:1235") +``` + +**Note: cant dial self because tcp/ip stacks use 4-tuples to identify connections, and doing so would clash.** + +## Tested + +Tested on `darwin`, `linux`, and `windows`. + + diff --git a/reuseport/addr.go b/reuseport/addr.go new file mode 100644 index 0000000..cfffc7c --- /dev/null +++ b/reuseport/addr.go @@ -0,0 +1,20 @@ +package reuseport + +import ( + "net" +) + +func ResolveAddr(network, address string) (net.Addr, error) { + switch network { + default: + return nil, net.UnknownNetworkError(network) + case "ip", "ip4", "ip6": + return net.ResolveIPAddr(network, address) + case "tcp", "tcp4", "tcp6": + return net.ResolveTCPAddr(network, address) + case "udp", "udp4", "udp6": + return net.ResolveUDPAddr(network, address) + case "unix", "unixgram", "unixpacket": + return net.ResolveUnixAddr(network, address) + } +} diff --git a/reuseport/control_plan9.go b/reuseport/control_plan9.go new file mode 100644 index 0000000..a8f7f34 --- /dev/null +++ b/reuseport/control_plan9.go @@ -0,0 +1,9 @@ +package reuseport + +import ( + "syscall" +) + +func Control(network, address string, c syscall.RawConn) error { + return nil +} diff --git a/reuseport/control_unix.go b/reuseport/control_unix.go new file mode 100644 index 0000000..9f37d2c --- /dev/null +++ b/reuseport/control_unix.go @@ -0,0 +1,25 @@ +// +build !plan9,!windows,!wasm + +package reuseport + +import ( + "syscall" + + "golang.org/x/sys/unix" +) + +func Control(network, address string, c syscall.RawConn) error { + var err error + c.Control(func(fd uintptr) { + err = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEADDR, 1) + if err != nil { + return + } + + err = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEPORT, 1) + if err != nil { + return + } + }) + return err +} diff --git a/reuseport/control_wasm.go b/reuseport/control_wasm.go new file mode 100644 index 0000000..d5d0a52 --- /dev/null +++ b/reuseport/control_wasm.go @@ -0,0 +1,11 @@ +// +build wasm + +package reuseport + +import ( + "syscall" +) + +func Control(network, address string, c syscall.RawConn) error { + return nil +} diff --git a/reuseport/control_windows.go b/reuseport/control_windows.go new file mode 100644 index 0000000..840534c --- /dev/null +++ b/reuseport/control_windows.go @@ -0,0 +1,13 @@ +package reuseport + +import ( + "syscall" + + "golang.org/x/sys/windows" +) + +func Control(network, address string, c syscall.RawConn) (err error) { + return c.Control(func(fd uintptr) { + err = windows.SetsockoptInt(windows.Handle(fd), windows.SOL_SOCKET, windows.SO_REUSEADDR, 1) + }) +} diff --git a/reuseport/interface.go b/reuseport/interface.go new file mode 100644 index 0000000..64b48af --- /dev/null +++ b/reuseport/interface.go @@ -0,0 +1,64 @@ +// Package reuseport provides Listen and Dial functions that set socket +// options in order to be able to reuse ports. You should only use this +// package if you know what SO_REUSEADDR and SO_REUSEPORT are. +// +// For example: +// +// // listen on the same port. oh yeah. +// l1, _ := reuse.Listen("tcp", "127.0.0.1:1234") +// l2, _ := reuse.Listen("tcp", "127.0.0.1:1234") +// +// // dial from the same port. oh yeah. +// l1, _ := reuse.Listen("tcp", "127.0.0.1:1234") +// l2, _ := reuse.Listen("tcp", "127.0.0.1:1235") +// c, _ := reuse.Dial("tcp", "127.0.0.1:1234", "127.0.0.1:1235") +// +// Note: cant dial self because tcp/ip stacks use 4-tuples to identify connections, +// and doing so would clash. +package reuseport + +import ( + "context" + "net" + + "github.com/pkg/errors" +) + +// Available returns whether or not SO_REUSEPORT or equivalent behaviour is +// available in the OS. +func Available() bool { + return true +} + +var listenConfig = net.ListenConfig{ + Control: Control, +} + +// Listen listens at the given network and address. see net.Listen +// Returns a net.Listener created from a file discriptor for a socket +// with SO_REUSEPORT and SO_REUSEADDR option set. +func Listen(network, address string) (net.Listener, error) { + return listenConfig.Listen(context.Background(), network, address) +} + +// ListenPacket listens at the given network and address. see net.ListenPacket +// Returns a net.Listener created from a file discriptor for a socket +// with SO_REUSEPORT and SO_REUSEADDR option set. +func ListenPacket(network, address string) (net.PacketConn, error) { + return listenConfig.ListenPacket(context.Background(), network, address) +} + +// Dial dials the given network and address. see net.Dialer.Dial +// Returns a net.Conn created from a file descriptor for a socket +// with SO_REUSEPORT and SO_REUSEADDR option set. +func Dial(network, laddr, raddr string) (net.Conn, error) { + nla, err := ResolveAddr(network, laddr) + if err != nil { + return nil, errors.Wrap(err, "resolving local addr") + } + d := net.Dialer{ + Control: Control, + LocalAddr: nla, + } + return d.Dial(network, raddr) +}