gfwproxyshadowsocksdocker-imagegogolanggvisornatnetworksocks4socks5tcpip-stacktortun-devicetun2sockstunneludpwireguard
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
119 lines
3.9 KiB
119 lines
3.9 KiB
package core
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
|
|
"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"
|
|
|
|
"github.com/xjasonlyu/tun2socks/v2/core/option"
|
|
)
|
|
|
|
const (
|
|
// nicPromiscuousModeEnabled is the value used by stack to enable
|
|
// or disable NIC's promiscuous mode.
|
|
nicPromiscuousModeEnabled = true
|
|
|
|
// nicSpoofingEnabled is the value used by stack to enable or disable
|
|
// NIC's spoofing.
|
|
nicSpoofingEnabled = true
|
|
)
|
|
|
|
// withCreatingNIC creates NIC for stack.
|
|
func withCreatingNIC(nicID tcpip.NICID, ep stack.LinkEndpoint) option.Option {
|
|
return func(s *stack.Stack) error {
|
|
if err := s.CreateNICWithOptions(nicID, ep,
|
|
stack.NICOptions{
|
|
Disabled: false,
|
|
// If no queueing discipline was specified
|
|
// provide a stub implementation that just
|
|
// delegates to the lower link endpoint.
|
|
QDisc: nil,
|
|
}); err != nil {
|
|
return fmt.Errorf("create NIC: %s", err)
|
|
}
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// withPromiscuousMode sets promiscuous mode in the given NICs.
|
|
func withPromiscuousMode(nicID tcpip.NICID, v bool) option.Option {
|
|
return func(s *stack.Stack) error {
|
|
if err := s.SetPromiscuousMode(nicID, v); err != nil {
|
|
return fmt.Errorf("set promiscuous mode: %s", err)
|
|
}
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// withSpoofing sets address spoofing in the given NICs, allowing
|
|
// endpoints to bind to any address in the NIC.
|
|
func withSpoofing(nicID tcpip.NICID, v bool) option.Option {
|
|
return func(s *stack.Stack) error {
|
|
if err := s.SetSpoofing(nicID, v); err != nil {
|
|
return fmt.Errorf("set spoofing: %s", err)
|
|
}
|
|
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
|
|
}
|
|
}
|
|
|