Add netns support
This commit is contained in:
parent
d0d4ebd8db
commit
994d6ccdbf
7 changed files with 220 additions and 80 deletions
73
netns_linux.go
Normal file
73
netns_linux.go
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
package tun
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing/common/control"
|
||||||
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
func listenNetworkNamespace(ctx context.Context, nameOrPath string, config net.ListenConfig, network, address string) (net.Listener, error) {
|
||||||
|
return execInNetworkNamespace(nameOrPath, func() (net.Listener, error) {
|
||||||
|
return config.Listen(ctx, network, address)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type networkNamespaceInterfaceFinder struct {
|
||||||
|
control.InterfaceFinder
|
||||||
|
options *Options
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *networkNamespaceInterfaceFinder) Update() error {
|
||||||
|
return runInNetworkNamespace(f.options.NetNs, f.InterfaceFinder.Update)
|
||||||
|
}
|
||||||
|
|
||||||
|
func execInNetworkNamespace[T any](nameOrPath string, block func() (T, error)) (T, error) {
|
||||||
|
if nameOrPath == "" {
|
||||||
|
return block()
|
||||||
|
}
|
||||||
|
type blockResult struct {
|
||||||
|
value T
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
resultChannel := make(chan blockResult, 1)
|
||||||
|
go func() {
|
||||||
|
runtime.LockOSThread()
|
||||||
|
value, err := execInNetworkNamespaceThread(nameOrPath, block)
|
||||||
|
resultChannel <- blockResult{value, err}
|
||||||
|
}()
|
||||||
|
result := <-resultChannel
|
||||||
|
return result.value, result.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func execInNetworkNamespaceThread[T any](nameOrPath string, block func() (T, error)) (T, error) {
|
||||||
|
var defaultValue T
|
||||||
|
var path string
|
||||||
|
if strings.HasPrefix(nameOrPath, "/") {
|
||||||
|
path = nameOrPath
|
||||||
|
} else {
|
||||||
|
path = "/run/netns/" + nameOrPath
|
||||||
|
}
|
||||||
|
targetFd, err := unix.Open(path, unix.O_RDONLY|unix.O_CLOEXEC, 0)
|
||||||
|
if err != nil {
|
||||||
|
return defaultValue, E.Cause(err, "open netns ", nameOrPath)
|
||||||
|
}
|
||||||
|
defer unix.Close(targetFd)
|
||||||
|
err = unix.Setns(targetFd, unix.CLONE_NEWNET)
|
||||||
|
if err != nil {
|
||||||
|
return defaultValue, E.Cause(err, "set netns to ", nameOrPath)
|
||||||
|
}
|
||||||
|
return block()
|
||||||
|
}
|
||||||
|
|
||||||
|
func runInNetworkNamespace(nameOrPath string, block func() error) error {
|
||||||
|
_, err := execInNetworkNamespace(nameOrPath, func() (struct{}, error) {
|
||||||
|
return struct{}{}, block()
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
}
|
||||||
12
netns_other.go
Normal file
12
netns_other.go
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
//go:build !linux
|
||||||
|
|
||||||
|
package tun
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
func listenNetworkNamespace(ctx context.Context, nameOrPath string, config net.ListenConfig, network, address string) (net.Listener, error) {
|
||||||
|
return config.Listen(ctx, network, address)
|
||||||
|
}
|
||||||
|
|
@ -26,6 +26,7 @@ type autoRedirect struct {
|
||||||
logger logger.Logger
|
logger logger.Logger
|
||||||
tableName string
|
tableName string
|
||||||
networkMonitor NetworkUpdateMonitor
|
networkMonitor NetworkUpdateMonitor
|
||||||
|
ownedNetworkMonitor bool
|
||||||
networkListener *list.Element[NetworkUpdateCallback]
|
networkListener *list.Element[NetworkUpdateCallback]
|
||||||
interfaceFinder control.InterfaceFinder
|
interfaceFinder control.InterfaceFinder
|
||||||
localAddresses []netip.Prefix
|
localAddresses []netip.Prefix
|
||||||
|
|
@ -51,7 +52,7 @@ type autoRedirect struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAutoRedirect(options AutoRedirectOptions) (AutoRedirect, error) {
|
func NewAutoRedirect(options AutoRedirectOptions) (AutoRedirect, error) {
|
||||||
return &autoRedirect{
|
r := &autoRedirect{
|
||||||
tunOptions: options.TunOptions,
|
tunOptions: options.TunOptions,
|
||||||
ctx: options.Context,
|
ctx: options.Context,
|
||||||
handler: options.Handler,
|
handler: options.Handler,
|
||||||
|
|
@ -63,7 +64,11 @@ func NewAutoRedirect(options AutoRedirectOptions) (AutoRedirect, error) {
|
||||||
customRedirectPortFunc: options.CustomRedirectPort,
|
customRedirectPortFunc: options.CustomRedirectPort,
|
||||||
routeAddressSet: options.RouteAddressSet,
|
routeAddressSet: options.RouteAddressSet,
|
||||||
routeExcludeAddressSet: options.RouteExcludeAddressSet,
|
routeExcludeAddressSet: options.RouteExcludeAddressSet,
|
||||||
}, nil
|
}
|
||||||
|
if options.TunOptions.NetNs != "" {
|
||||||
|
r.interfaceFinder = &networkNamespaceInterfaceFinder{control.NewDefaultInterfaceFinder(), options.TunOptions}
|
||||||
|
}
|
||||||
|
return r, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *autoRedirect) Start() error {
|
func (r *autoRedirect) Start() error {
|
||||||
|
|
@ -89,8 +94,11 @@ func (r *autoRedirect) Start() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if r.tunOptions.NetNs != "" && !r.useNFTables {
|
||||||
|
return E.New("auto_redirect in network namespace requires nftables")
|
||||||
|
}
|
||||||
if r.useNFTables {
|
if r.useNFTables {
|
||||||
err = r.initializeNFTables()
|
err = runInNetworkNamespace(r.tunOptions.NetNs, r.initializeNFTables)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return E.Cause(err, "missing nftables support")
|
return E.Cause(err, "missing nftables support")
|
||||||
}
|
}
|
||||||
|
|
@ -132,7 +140,7 @@ func (r *autoRedirect) Start() error {
|
||||||
listenAddr = netip.IPv4Unspecified()
|
listenAddr = netip.IPv4Unspecified()
|
||||||
}
|
}
|
||||||
server := newRedirectServer(r.ctx, r.handler, r.logger, listenAddr)
|
server := newRedirectServer(r.ctx, r.handler, r.logger, listenAddr)
|
||||||
err = server.Start()
|
err = runInNetworkNamespace(r.tunOptions.NetNs, server.Start)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return E.Cause(err, "start redirect server")
|
return E.Cause(err, "start redirect server")
|
||||||
}
|
}
|
||||||
|
|
@ -151,25 +159,44 @@ func (r *autoRedirect) Start() error {
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.logger.Warn("nfqueue not available, pre-match disabled (missing nfnetlink_queue and nft_queue kernel module?): ", err)
|
r.logger.Warn("nfqueue not available, pre-match disabled (missing nfnetlink_queue and nft_queue kernel module?): ", err)
|
||||||
} else if err = handler.Start(); err != nil {
|
} else if err = runInNetworkNamespace(r.tunOptions.NetNs, handler.Start); err != nil {
|
||||||
r.logger.Warn("nfqueue start failed, pre-match disabled (missing nfnetlink_queue and nft_queue kernel module?): ", err)
|
r.logger.Warn("nfqueue start failed, pre-match disabled (missing nfnetlink_queue and nft_queue kernel module?): ", err)
|
||||||
} else {
|
} else {
|
||||||
r.nfqueueHandler = handler
|
r.nfqueueHandler = handler
|
||||||
r.nfqueueEnabled = true
|
r.nfqueueEnabled = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
r.cleanupNFTables()
|
if r.tunOptions.NetNs != "" {
|
||||||
err = r.setupNFTables()
|
var monitor NetworkUpdateMonitor
|
||||||
|
monitor, err = NewNetworkUpdateMonitor(r.logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return E.Cause(err, "setup nftables")
|
return E.Cause(err, "create netns network monitor")
|
||||||
|
}
|
||||||
|
err = runInNetworkNamespace(r.tunOptions.NetNs, monitor.Start)
|
||||||
|
if err != nil {
|
||||||
|
return E.Cause(err, "start netns network monitor")
|
||||||
|
}
|
||||||
|
r.networkMonitor = monitor
|
||||||
|
r.ownedNetworkMonitor = true
|
||||||
|
}
|
||||||
|
err = runInNetworkNamespace(r.tunOptions.NetNs, func() error {
|
||||||
|
r.cleanupNFTables()
|
||||||
|
setupErr := r.setupNFTables()
|
||||||
|
if setupErr != nil {
|
||||||
|
return E.Cause(setupErr, "setup nftables")
|
||||||
}
|
}
|
||||||
if r.tunOptions.AutoRedirectMarkMode {
|
if r.tunOptions.AutoRedirectMarkMode {
|
||||||
err = r.setupRedirectRoutes()
|
setupErr = r.setupRedirectRoutes()
|
||||||
if err != nil {
|
if setupErr != nil {
|
||||||
r.cleanupNFTables()
|
r.cleanupNFTables()
|
||||||
return E.Cause(err, "setup redirect routes")
|
return E.Cause(setupErr, "setup redirect routes")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
r.cleanupIPTables()
|
r.cleanupIPTables()
|
||||||
err = r.setupIPTables()
|
err = r.setupIPTables()
|
||||||
|
|
@ -185,8 +212,14 @@ func (r *autoRedirect) Close() error {
|
||||||
r.nfqueueHandler.Close()
|
r.nfqueueHandler.Close()
|
||||||
}
|
}
|
||||||
if r.useNFTables {
|
if r.useNFTables {
|
||||||
|
_ = runInNetworkNamespace(r.tunOptions.NetNs, func() error {
|
||||||
r.cleanupNFTables()
|
r.cleanupNFTables()
|
||||||
r.cleanupRedirectRoutes()
|
r.cleanupRedirectRoutes()
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if r.ownedNetworkMonitor {
|
||||||
|
_ = r.networkMonitor.Close()
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
r.cleanupIPTables()
|
r.cleanupIPTables()
|
||||||
}
|
}
|
||||||
|
|
@ -197,7 +230,7 @@ func (r *autoRedirect) Close() error {
|
||||||
|
|
||||||
func (r *autoRedirect) UpdateRouteAddressSet() {
|
func (r *autoRedirect) UpdateRouteAddressSet() {
|
||||||
if r.useNFTables {
|
if r.useNFTables {
|
||||||
err := r.nftablesUpdateRouteAddressSet()
|
err := runInNetworkNamespace(r.tunOptions.NetNs, r.nftablesUpdateRouteAddressSet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.logger.Error("update route address set: ", err)
|
r.logger.Error("update route address set: ", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -299,27 +299,38 @@ func (r *autoRedirect) setupNFTables() error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return E.Cause(err, "flush nftables")
|
return E.Cause(err, "flush nftables")
|
||||||
}
|
}
|
||||||
|
if r.tunOptions.NetNs == "" {
|
||||||
r.startDockerFirewallMonitor()
|
r.startDockerFirewallMonitor()
|
||||||
err = r.configureDockerFirewall(false)
|
err = r.configureDockerFirewall(false)
|
||||||
if err != nil && r.logger != nil {
|
if err != nil && r.logger != nil {
|
||||||
r.logger.Warn("configure docker firewall: ", err)
|
r.logger.Warn("configure docker firewall: ", err)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
r.networkListener = r.networkMonitor.RegisterCallback(func() {
|
r.networkListener = r.networkMonitor.RegisterCallback(func() {
|
||||||
err = r.nftablesUpdateLocalAddressSet()
|
updateErr := runInNetworkNamespace(r.tunOptions.NetNs, r.updateNetworkAddresses)
|
||||||
if err != nil {
|
if updateErr != nil {
|
||||||
r.logger.Error("update local address set: ", err)
|
r.logger.Error(updateErr)
|
||||||
}
|
|
||||||
if r.tunOptions.AutoRedirectMarkMode {
|
|
||||||
err = r.updateRedirectRoutes()
|
|
||||||
if err != nil {
|
|
||||||
r.logger.Error("update redirect routes: ", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *autoRedirect) updateNetworkAddresses() error {
|
||||||
|
err := r.nftablesUpdateLocalAddressSet()
|
||||||
|
if err != nil {
|
||||||
|
err = E.Cause(err, "update local address set")
|
||||||
|
}
|
||||||
|
if r.tunOptions.AutoRedirectMarkMode {
|
||||||
|
routeErr := r.updateRedirectRoutes()
|
||||||
|
if routeErr != nil {
|
||||||
|
routeErr = E.Cause(routeErr, "update redirect routes")
|
||||||
|
}
|
||||||
|
err = E.Errors(err, routeErr)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: test if this works
|
// TODO: test if this works
|
||||||
func (r *autoRedirect) nftablesUpdateLocalAddressSet() error {
|
func (r *autoRedirect) nftablesUpdateLocalAddressSet() error {
|
||||||
err := r.interfaceFinder.Update()
|
err := r.interfaceFinder.Update()
|
||||||
|
|
@ -376,6 +387,7 @@ func (r *autoRedirect) nftablesUpdateRouteAddressSet() error {
|
||||||
func (r *autoRedirect) cleanupNFTables() {
|
func (r *autoRedirect) cleanupNFTables() {
|
||||||
if r.networkListener != nil {
|
if r.networkListener != nil {
|
||||||
r.networkMonitor.UnregisterCallback(r.networkListener)
|
r.networkMonitor.UnregisterCallback(r.networkListener)
|
||||||
|
r.networkListener = nil
|
||||||
}
|
}
|
||||||
r.stopDockerFirewallMonitor()
|
r.stopDockerFirewallMonitor()
|
||||||
nft, err := nftables.New()
|
nft, err := nftables.New()
|
||||||
|
|
@ -389,10 +401,12 @@ func (r *autoRedirect) cleanupNFTables() {
|
||||||
_ = r.configureOpenWRTFirewall4(nft, true)
|
_ = r.configureOpenWRTFirewall4(nft, true)
|
||||||
_ = nft.Flush()
|
_ = nft.Flush()
|
||||||
_ = nft.CloseLasting()
|
_ = nft.CloseLasting()
|
||||||
|
if r.tunOptions.NetNs == "" {
|
||||||
err = r.configureDockerFirewall(true)
|
err = r.configureDockerFirewall(true)
|
||||||
if err != nil && r.logger != nil {
|
if err != nil && r.logger != nil {
|
||||||
r.logger.Warn("cleanup docker firewall: ", err)
|
r.logger.Warn("cleanup docker firewall: ", err)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *autoRedirect) nftablesCreatePreMatchChains(nft *nftables.Conn, table *nftables.Table) error {
|
func (r *autoRedirect) nftablesCreatePreMatchChains(nft *nftables.Conn, table *nftables.Table) error {
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ type System struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
tun Tun
|
tun Tun
|
||||||
tunName string
|
tunName string
|
||||||
|
netNs string
|
||||||
mtu int
|
mtu int
|
||||||
handler Handler
|
handler Handler
|
||||||
logger logger.Logger
|
logger logger.Logger
|
||||||
|
|
@ -68,6 +69,7 @@ func NewSystem(options StackOptions) (Stack, error) {
|
||||||
ctx: options.Context,
|
ctx: options.Context,
|
||||||
tun: options.Tun,
|
tun: options.Tun,
|
||||||
tunName: options.TunOptions.Name,
|
tunName: options.TunOptions.Name,
|
||||||
|
netNs: options.TunOptions.NetNs,
|
||||||
mtu: int(options.TunOptions.MTU),
|
mtu: int(options.TunOptions.MTU),
|
||||||
inet4LoopbackAddress: options.TunOptions.Inet4LoopbackAddress,
|
inet4LoopbackAddress: options.TunOptions.Inet4LoopbackAddress,
|
||||||
inet6LoopbackAddress: options.TunOptions.Inet6LoopbackAddress,
|
inet6LoopbackAddress: options.TunOptions.Inet6LoopbackAddress,
|
||||||
|
|
@ -135,7 +137,7 @@ func (s *System) start() error {
|
||||||
var err error
|
var err error
|
||||||
if s.inet4NextAddress.IsValid() {
|
if s.inet4NextAddress.IsValid() {
|
||||||
for range 3 {
|
for range 3 {
|
||||||
tcpListener, err = listener.Listen(s.ctx, "tcp4", net.JoinHostPort(s.inet4Address.String(), "0"))
|
tcpListener, err = listenNetworkNamespace(s.ctx, s.netNs, listener, "tcp4", net.JoinHostPort(s.inet4Address.String(), "0"))
|
||||||
if !retryableListenError(err) {
|
if !retryableListenError(err) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
@ -150,7 +152,7 @@ func (s *System) start() error {
|
||||||
}
|
}
|
||||||
if s.inet6NextAddress.IsValid() {
|
if s.inet6NextAddress.IsValid() {
|
||||||
for range 3 {
|
for range 3 {
|
||||||
tcpListener, err = listener.Listen(s.ctx, "tcp6", net.JoinHostPort(s.inet6Address.String(), "0"))
|
tcpListener, err = listenNetworkNamespace(s.ctx, s.netNs, listener, "tcp6", net.JoinHostPort(s.inet6Address.String(), "0"))
|
||||||
if !retryableListenError(err) {
|
if !retryableListenError(err) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
|
||||||
1
tun.go
1
tun.go
|
|
@ -66,6 +66,7 @@ const (
|
||||||
|
|
||||||
type Options struct {
|
type Options struct {
|
||||||
Name string
|
Name string
|
||||||
|
NetNs string
|
||||||
Inet4Address []netip.Prefix
|
Inet4Address []netip.Prefix
|
||||||
Inet6Address []netip.Prefix
|
Inet6Address []netip.Prefix
|
||||||
MTU uint32
|
MTU uint32
|
||||||
|
|
|
||||||
25
tun_linux.go
25
tun_linux.go
|
|
@ -51,8 +51,8 @@ type NativeTun struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(options Options) (Tun, error) {
|
func New(options Options) (Tun, error) {
|
||||||
var nativeTun *NativeTun
|
|
||||||
if options.FileDescriptor == 0 {
|
if options.FileDescriptor == 0 {
|
||||||
|
return execInNetworkNamespace(options.NetNs, func() (Tun, error) {
|
||||||
tunFd, err := open(options.Name, options.GSO)
|
tunFd, err := open(options.Name, options.GSO)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, E.Cause(err, "open tun")
|
return nil, E.Cause(err, "open tun")
|
||||||
|
|
@ -61,7 +61,7 @@ func New(options Options) (Tun, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, E.Errors(err, unix.Close(tunFd))
|
return nil, E.Errors(err, unix.Close(tunFd))
|
||||||
}
|
}
|
||||||
nativeTun = &NativeTun{
|
nativeTun := &NativeTun{
|
||||||
tunFd: tunFd,
|
tunFd: tunFd,
|
||||||
tunFile: os.NewFile(uintptr(tunFd), "tun"),
|
tunFile: os.NewFile(uintptr(tunFd), "tun"),
|
||||||
options: options,
|
options: options,
|
||||||
|
|
@ -70,8 +70,10 @@ func New(options Options) (Tun, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, E.Errors(err, unix.Close(tunFd))
|
return nil, E.Errors(err, unix.Close(tunFd))
|
||||||
}
|
}
|
||||||
} else {
|
return nativeTun, nil
|
||||||
nativeTun = &NativeTun{
|
})
|
||||||
|
}
|
||||||
|
nativeTun := &NativeTun{
|
||||||
tunFd: options.FileDescriptor,
|
tunFd: options.FileDescriptor,
|
||||||
tunFile: os.NewFile(uintptr(options.FileDescriptor), "tun"),
|
tunFile: os.NewFile(uintptr(options.FileDescriptor), "tun"),
|
||||||
options: options,
|
options: options,
|
||||||
|
|
@ -84,7 +86,6 @@ func New(options Options) (Tun, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return nativeTun, nil
|
return nativeTun, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -290,10 +291,10 @@ func (t *NativeTun) Name() (string, error) {
|
||||||
|
|
||||||
func (t *NativeTun) Start() error {
|
func (t *NativeTun) Start() error {
|
||||||
if t.options.FileDescriptor == 0 {
|
if t.options.FileDescriptor == 0 {
|
||||||
if !t.options.EXP_ExternalConfiguration {
|
if !t.options.EXP_ExternalConfiguration && t.options.NetNs == "" {
|
||||||
t.options.InterfaceMonitor.RegisterMyInterface(t.options.Name)
|
t.options.InterfaceMonitor.RegisterMyInterface(t.options.Name)
|
||||||
}
|
}
|
||||||
err := t.start()
|
err := runInNetworkNamespace(t.options.NetNs, t.start)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -354,7 +355,7 @@ func (t *NativeTun) start() error {
|
||||||
return E.Cause(err, "set rules")
|
return E.Cause(err, "set rules")
|
||||||
}
|
}
|
||||||
|
|
||||||
if t.options.DNSMode != DNSModeDisabled {
|
if t.options.DNSMode != DNSModeDisabled && t.options.NetNs == "" {
|
||||||
err = t.setSearchDomainForSystemdResolved()
|
err = t.setSearchDomainForSystemdResolved()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return E.Cause(err, "set search domain")
|
return E.Cause(err, "set search domain")
|
||||||
|
|
@ -374,11 +375,13 @@ func (t *NativeTun) Close() error {
|
||||||
if t.options.EXP_ExternalConfiguration {
|
if t.options.EXP_ExternalConfiguration {
|
||||||
return common.Close(common.PtrOrNil(t.tunFile))
|
return common.Close(common.PtrOrNil(t.tunFile))
|
||||||
}
|
}
|
||||||
if t.options.DNSMode != DNSModeDisabled {
|
if t.options.DNSMode != DNSModeDisabled && t.options.NetNs == "" {
|
||||||
t.unsetSearchDomainForSystemdResolved()
|
t.unsetSearchDomainForSystemdResolved()
|
||||||
}
|
}
|
||||||
|
return E.Errors(runInNetworkNamespace(t.options.NetNs, func() error {
|
||||||
t.unsetAddresses()
|
t.unsetAddresses()
|
||||||
return E.Errors(t.unsetRoute(), t.unsetRules(), common.Close(common.PtrOrNil(t.tunFile)))
|
return E.Errors(t.unsetRoute(), t.unsetRules())
|
||||||
|
}), common.Close(common.PtrOrNil(t.tunFile)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *NativeTun) Read(p []byte) (n int, err error) {
|
func (t *NativeTun) Read(p []byte) (n int, err error) {
|
||||||
|
|
@ -625,6 +628,7 @@ func (t *NativeTun) UpdateRouteOptions(tunOptions Options) error {
|
||||||
t.options = tunOptions
|
t.options = tunOptions
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
return runInNetworkNamespace(t.options.NetNs, func() error {
|
||||||
tunLink, err := netlink.LinkByName(t.options.Name)
|
tunLink, err := netlink.LinkByName(t.options.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return E.Cause(err, "find tun interface")
|
return E.Cause(err, "find tun interface")
|
||||||
|
|
@ -635,6 +639,7 @@ func (t *NativeTun) UpdateRouteOptions(tunOptions Options) error {
|
||||||
}
|
}
|
||||||
t.options = tunOptions
|
t.options = tunOptions
|
||||||
return t.setRoute(tunLink)
|
return t.setRoute(tunLink)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *NativeTun) routes(tunLink netlink.Link) ([]netlink.Route, error) {
|
func (t *NativeTun) routes(tunLink netlink.Link) ([]netlink.Route, error) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue