add support for linux network namespace

This commit is contained in:
ginuerzh
2024-06-21 23:38:18 +08:00
parent 15f28c667a
commit 2ae0462822
9 changed files with 127 additions and 8 deletions

View File

@ -487,6 +487,7 @@ type HopConfig struct {
Redis *RedisLoader `yaml:",omitempty" json:"redis,omitempty"`
HTTP *HTTPLoader `yaml:"http,omitempty" json:"http,omitempty"`
Plugin *PluginConfig `yaml:",omitempty" json:"plugin,omitempty"`
Metadata map[string]any `yaml:",omitempty" json:"metadata,omitempty"`
}
type NodeConfig struct {
@ -500,6 +501,7 @@ type NodeConfig struct {
Connector *ConnectorConfig `yaml:",omitempty" json:"connector,omitempty"`
Dialer *DialerConfig `yaml:",omitempty" json:"dialer,omitempty"`
Interface string `yaml:",omitempty" json:"interface,omitempty"`
Netns string `yaml:",omitempty" json:"netns,omitempty"`
SockOpts *SockOptsConfig `yaml:"sockopts,omitempty" json:"sockopts,omitempty"`
Filter *NodeFilterConfig `yaml:",omitempty" json:"filter,omitempty"`
HTTP *HTTPNodeConfig `yaml:",omitempty" json:"http,omitempty"`

View File

@ -8,7 +8,9 @@ import (
"github.com/go-gost/core/chain"
"github.com/go-gost/core/hop"
"github.com/go-gost/core/logger"
mdutil "github.com/go-gost/core/metadata/util"
"github.com/go-gost/x/config"
"github.com/go-gost/x/config/parsing"
bypass_parser "github.com/go-gost/x/config/parsing/bypass"
node_parser "github.com/go-gost/x/config/parsing/node"
selector_parser "github.com/go-gost/x/config/parsing/selector"
@ -16,6 +18,7 @@ import (
hop_plugin "github.com/go-gost/x/hop/plugin"
"github.com/go-gost/x/internal/loader"
"github.com/go-gost/x/internal/plugin"
"github.com/go-gost/x/metadata"
)
func ParseHop(cfg *config.HopConfig, log logger.Logger) (hop.Hop, error) {
@ -47,6 +50,16 @@ func ParseHop(cfg *config.HopConfig, log logger.Logger) (hop.Hop, error) {
}
}
ifce := cfg.Interface
var netns string
if cfg.Metadata != nil {
md := metadata.NewMetadata(cfg.Metadata)
if v := mdutil.GetString(md, parsing.MDKeyInterface); v != "" {
ifce = v
}
netns = mdutil.GetString(md, "netns")
}
var nodes []*chain.Node
for _, v := range cfg.Nodes {
if v == nil {
@ -60,8 +73,12 @@ func ParseHop(cfg *config.HopConfig, log logger.Logger) (hop.Hop, error) {
v.Hosts = cfg.Hosts
}
if v.Interface == "" {
v.Interface = cfg.Interface
v.Interface = ifce
}
if v.Netns == "" {
v.Netns = netns
}
if v.SockOpts == nil {
v.SockOpts = cfg.SockOpts
}

View File

@ -143,6 +143,7 @@ func ParseNode(hop string, cfg *config.NodeConfig, log logger.Logger) (*chain.No
tr := chain.NewTransport(d, cr,
chain.AddrTransportOption(cfg.Addr),
chain.InterfaceTransportOption(cfg.Interface),
chain.NetnsTransportOption(cfg.Netns),
chain.SockOptsTransportOption(sockOpts),
chain.TimeoutTransportOption(10*time.Second),
)

View File

@ -2,6 +2,7 @@ package service
import (
"fmt"
"runtime"
"strings"
"time"
@ -32,6 +33,7 @@ import (
"github.com/go-gost/x/registry"
xservice "github.com/go-gost/x/service"
"github.com/go-gost/x/stats"
"github.com/vishvananda/netns"
)
func ParseService(cfg *config.ServiceConfig) (service.Service, error) {
@ -104,6 +106,7 @@ func ParseService(cfg *config.ServiceConfig) (service.Service, error) {
var ignoreChain bool
var pStats *stats.Stats
var observePeriod time.Duration
var netnsIn, netnsOut string
if cfg.Metadata != nil {
md := metadata.NewMetadata(cfg.Metadata)
ppv = mdutil.GetInt(md, parsing.MDKeyProxyProtocol)
@ -125,6 +128,8 @@ func ParseService(cfg *config.ServiceConfig) (service.Service, error) {
pStats = &stats.Stats{}
}
observePeriod = mdutil.GetDuration(md, "observePeriod")
netnsIn = mdutil.GetString(md, "netns")
netnsOut = mdutil.GetString(md, "netns.out")
}
listenOpts := []listener.Option{
@ -146,6 +151,27 @@ func ParseService(cfg *config.ServiceConfig) (service.Service, error) {
)
}
if netnsIn != "" {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
originNs, err := netns.Get()
if err != nil {
return nil, fmt.Errorf("netns.Get(): %v", err)
}
defer netns.Set(originNs)
ns, err := netns.GetFromName(netnsIn)
if err != nil {
return nil, fmt.Errorf("netns.GetFromName(%s): %v", netnsIn, err)
}
defer ns.Close()
if err := netns.Set(ns); err != nil {
return nil, fmt.Errorf("netns.Set(%s): %v", netnsIn, err)
}
}
var ln listener.Listener
if rf := registry.ListenerRegistry().Get(cfg.Listener.Type); rf != nil {
ln = rf(listenOpts...)
@ -209,6 +235,7 @@ func ParseService(cfg *config.ServiceConfig) (service.Service, error) {
chain.RetriesRouterOption(cfg.Handler.Retries),
// chain.TimeoutRouterOption(10*time.Second),
chain.InterfaceRouterOption(ifce),
chain.NetnsRouterOption(netnsOut),
chain.SockOptsRouterOption(sockOpts),
chain.ResolverRouterOption(registry.ResolverRegistry().Get(cfg.Resolver)),
chain.HostMapperRouterOption(registry.HostsRegistry().Get(cfg.Hosts)),