mirror of
https://github.com/xjasonlyu/tun2socks.git
synced 2025-10-07 01:33:15 +08:00
Feature: add support for multicast (#245)
* add support for multicast (#243) * adjust setup --------- Co-authored-by: xjasonlyu <xjasonlyu@gmail.com>
This commit is contained in:
61
core/nic.go
61
core/nic.go
@@ -2,8 +2,11 @@ package core
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
|
|
||||||
"gvisor.dev/gvisor/pkg/tcpip"
|
"gvisor.dev/gvisor/pkg/tcpip"
|
||||||
|
"gvisor.dev/gvisor/pkg/tcpip/network/ipv4"
|
||||||
|
"gvisor.dev/gvisor/pkg/tcpip/network/ipv6"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||||
|
|
||||||
"github.com/xjasonlyu/tun2socks/v2/core/option"
|
"github.com/xjasonlyu/tun2socks/v2/core/option"
|
||||||
@@ -56,3 +59,61 @@ func withSpoofing(nicID tcpip.NICID, v bool) option.Option {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// withMulticastGroups adds a NIC to the given multicast groups.
|
||||||
|
func withMulticastGroups(nicID tcpip.NICID, multicastGroups []net.IP) option.Option {
|
||||||
|
return func(s *stack.Stack) error {
|
||||||
|
if len(multicastGroups) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// The default NIC of tun2socks is working on Spoofing mode. When the UDP Endpoint
|
||||||
|
// tries to use a non-local address to connect, the network stack will
|
||||||
|
// generate a temporary addressState to build the route, which can be primary
|
||||||
|
// but is ephemeral. Nevertheless, when the UDP Endpoint tries to use a
|
||||||
|
// multicast address to connect, the network stack will select an available
|
||||||
|
// primary addressState to build the route. However, when tun2socks is in the
|
||||||
|
// just-initialized or idle state, there will be no available primary addressState,
|
||||||
|
// and the connect operation will fail. Therefore, we need to add permanent addresses,
|
||||||
|
// e.g. 10.0.0.1/8 and fd00:1/8, to the default NIC, which are only used to build
|
||||||
|
// routes for multicast response and do not affect other connections.
|
||||||
|
//
|
||||||
|
// In fact, for multicast, the sender normally does not expect a response.
|
||||||
|
// So, the ep.net.Connect is unnecessary. If we implement a custom UDP Forwarder
|
||||||
|
// and ForwarderRequest in the future, we can remove these code.
|
||||||
|
s.AddProtocolAddress(
|
||||||
|
nicID,
|
||||||
|
tcpip.ProtocolAddress{
|
||||||
|
Protocol: ipv4.ProtocolNumber,
|
||||||
|
AddressWithPrefix: tcpip.AddressWithPrefix{
|
||||||
|
Address: tcpip.AddrFrom4([4]byte{0x0a, 0, 0, 0x01}),
|
||||||
|
PrefixLen: 8,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
stack.AddressProperties{PEB: stack.CanBePrimaryEndpoint},
|
||||||
|
)
|
||||||
|
s.AddProtocolAddress(
|
||||||
|
nicID,
|
||||||
|
tcpip.ProtocolAddress{
|
||||||
|
Protocol: ipv6.ProtocolNumber,
|
||||||
|
AddressWithPrefix: tcpip.AddressWithPrefix{
|
||||||
|
Address: tcpip.AddrFrom16([16]byte{0xfd, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01}),
|
||||||
|
PrefixLen: 8,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
stack.AddressProperties{PEB: stack.CanBePrimaryEndpoint},
|
||||||
|
)
|
||||||
|
for _, multicastGroup := range multicastGroups {
|
||||||
|
if ip := multicastGroup.To4(); ip != nil {
|
||||||
|
if err := s.JoinGroup(ipv4.ProtocolNumber, nicID, tcpip.AddrFrom4Slice(ip)); err != nil {
|
||||||
|
return fmt.Errorf("join multicast group: %s", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ip := multicastGroup.To16()
|
||||||
|
if err := s.JoinGroup(ipv6.ProtocolNumber, nicID, tcpip.AddrFrom16Slice(ip)); err != nil {
|
||||||
|
return fmt.Errorf("join multicast group: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"net"
|
||||||
|
|
||||||
"gvisor.dev/gvisor/pkg/tcpip"
|
"gvisor.dev/gvisor/pkg/tcpip"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/network/ipv4"
|
"gvisor.dev/gvisor/pkg/tcpip/network/ipv4"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/network/ipv6"
|
"gvisor.dev/gvisor/pkg/tcpip/network/ipv6"
|
||||||
@@ -23,6 +25,10 @@ type Config struct {
|
|||||||
// stack to set transport handlers.
|
// stack to set transport handlers.
|
||||||
TransportHandler adapter.TransportHandler
|
TransportHandler adapter.TransportHandler
|
||||||
|
|
||||||
|
// MulticastGroups is used by internal stack to add
|
||||||
|
// nic to given groups.
|
||||||
|
MulticastGroups []net.IP
|
||||||
|
|
||||||
// Options are supplement options to apply settings
|
// Options are supplement options to apply settings
|
||||||
// for the internal stack.
|
// for the internal stack.
|
||||||
Options []option.Option
|
Options []option.Option
|
||||||
@@ -88,6 +94,9 @@ func CreateStack(cfg *Config) (*stack.Stack, error) {
|
|||||||
// Add default route table for IPv4 and IPv6. This will handle
|
// Add default route table for IPv4 and IPv6. This will handle
|
||||||
// all incoming ICMP packets.
|
// all incoming ICMP packets.
|
||||||
withRouteTable(nicID),
|
withRouteTable(nicID),
|
||||||
|
|
||||||
|
// Add default NIC to the given multicast groups.
|
||||||
|
withMulticastGroups(nicID, cfg.MulticastGroups),
|
||||||
)
|
)
|
||||||
|
|
||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
|
@@ -193,6 +193,11 @@ func netstack(k *Key) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var multicastGroups []net.IP
|
||||||
|
if multicastGroups, err = parseMulticastGroups(k.MulticastGroups); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
var opts []option.Option
|
var opts []option.Option
|
||||||
if k.TCPModerateReceiveBuffer {
|
if k.TCPModerateReceiveBuffer {
|
||||||
opts = append(opts, option.WithTCPModerateReceiveBuffer(true))
|
opts = append(opts, option.WithTCPModerateReceiveBuffer(true))
|
||||||
@@ -217,6 +222,7 @@ func netstack(k *Key) (err error) {
|
|||||||
if _defaultStack, err = core.CreateStack(&core.Config{
|
if _defaultStack, err = core.CreateStack(&core.Config{
|
||||||
LinkEndpoint: _defaultDevice,
|
LinkEndpoint: _defaultDevice,
|
||||||
TransportHandler: &mirror.Tunnel{},
|
TransportHandler: &mirror.Tunnel{},
|
||||||
|
MulticastGroups: multicastGroups,
|
||||||
Options: opts,
|
Options: opts,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return
|
return
|
||||||
|
@@ -13,6 +13,7 @@ type Key struct {
|
|||||||
TCPModerateReceiveBuffer bool `yaml:"tcp-moderate-receive-buffer"`
|
TCPModerateReceiveBuffer bool `yaml:"tcp-moderate-receive-buffer"`
|
||||||
TCPSendBufferSize string `yaml:"tcp-send-buffer-size"`
|
TCPSendBufferSize string `yaml:"tcp-send-buffer-size"`
|
||||||
TCPReceiveBufferSize string `yaml:"tcp-receive-buffer-size"`
|
TCPReceiveBufferSize string `yaml:"tcp-receive-buffer-size"`
|
||||||
|
MulticastGroups string `yaml:"multicast-groups"`
|
||||||
TUNPreUp string `yaml:"tun-pre-up"`
|
TUNPreUp string `yaml:"tun-pre-up"`
|
||||||
TUNPostUp string `yaml:"tun-post-up"`
|
TUNPostUp string `yaml:"tun-post-up"`
|
||||||
UDPTimeout time.Duration `yaml:"udp-timeout"`
|
UDPTimeout time.Duration `yaml:"udp-timeout"`
|
||||||
|
@@ -150,3 +150,21 @@ func parseShadowsocks(u *url.URL) (address, method, password, obfsMode, obfsHost
|
|||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseMulticastGroups(s string) (multicastGroups []net.IP, _ error) {
|
||||||
|
ipStrings := strings.Split(s, ",")
|
||||||
|
for _, ipString := range ipStrings {
|
||||||
|
if strings.TrimSpace(ipString) == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ip := net.ParseIP(ipString)
|
||||||
|
if ip == nil {
|
||||||
|
return nil, fmt.Errorf("invalid IP format: %s", ipString)
|
||||||
|
}
|
||||||
|
if !ip.IsMulticast() {
|
||||||
|
return nil, fmt.Errorf("invalid multicast IP address: %s", ipString)
|
||||||
|
}
|
||||||
|
multicastGroups = append(multicastGroups, ip)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
1
main.go
1
main.go
@@ -36,6 +36,7 @@ func init() {
|
|||||||
flag.StringVar(&key.TCPSendBufferSize, "tcp-sndbuf", "", "Set TCP send buffer size for netstack")
|
flag.StringVar(&key.TCPSendBufferSize, "tcp-sndbuf", "", "Set TCP send buffer size for netstack")
|
||||||
flag.StringVar(&key.TCPReceiveBufferSize, "tcp-rcvbuf", "", "Set TCP receive buffer size for netstack")
|
flag.StringVar(&key.TCPReceiveBufferSize, "tcp-rcvbuf", "", "Set TCP receive buffer size for netstack")
|
||||||
flag.BoolVar(&key.TCPModerateReceiveBuffer, "tcp-auto-tuning", false, "Enable TCP receive buffer auto-tuning")
|
flag.BoolVar(&key.TCPModerateReceiveBuffer, "tcp-auto-tuning", false, "Enable TCP receive buffer auto-tuning")
|
||||||
|
flag.StringVar(&key.MulticastGroups, "multicast-groups", "", "Set multicast groups, separated by commas")
|
||||||
flag.StringVar(&key.TUNPreUp, "tun-pre-up", "", "Execute a command before TUN device setup")
|
flag.StringVar(&key.TUNPreUp, "tun-pre-up", "", "Execute a command before TUN device setup")
|
||||||
flag.StringVar(&key.TUNPostUp, "tun-post-up", "", "Execute a command after TUN device setup")
|
flag.StringVar(&key.TUNPostUp, "tun-post-up", "", "Execute a command after TUN device setup")
|
||||||
flag.BoolVar(&versionFlag, "version", false, "Show version and then quit")
|
flag.BoolVar(&versionFlag, "version", false, "Show version and then quit")
|
||||||
|
Reference in New Issue
Block a user