diff --git a/router/config.go b/router/config.go index eacba2616..fb8c139e6 100644 --- a/router/config.go +++ b/router/config.go @@ -21,10 +21,10 @@ import ( "fmt" "github.com/michaelquigley/pfxlog" "github.com/openziti/channel" + "github.com/openziti/fabric/config" "github.com/openziti/fabric/pb/ctrl_pb" "github.com/openziti/fabric/router/forwarder" "github.com/openziti/fabric/router/xgress" - "github.com/openziti/fabric/config" "github.com/openziti/foundation/identity/identity" "github.com/openziti/transport" "github.com/pkg/errors" @@ -51,6 +51,9 @@ const ( // CtrlEndpointMapKey is the string key for the ctrl.endpoint section CtrlEndpointMapKey = "endpoint" + + // CtrlEndpointBindMapKey is the string key for the ctrl.bind section + CtrlEndpointBindMapKey = "bind" ) // internalConfigKeys is used to distinguish internally defined configuration vs file configuration @@ -98,6 +101,7 @@ type Config struct { } Ctrl struct { Endpoint *UpdatableAddress + LocalBinding string DefaultRequestTimeout time.Duration Options *channel.Options } @@ -294,6 +298,10 @@ func (c *UpdatableAddress) Dial(name string, i *identity.TokenId, timeout time.D return c.getWrapped().Dial(name, i, timeout, tcfg) } +func (c *UpdatableAddress) DialWithLocalBinding(name string, binding string, i *identity.TokenId, timeout time.Duration, tcfg transport.Configuration) (transport.Connection, error) { + return c.getWrapped().DialWithLocalBinding(name, binding, i, timeout, tcfg) +} + // getWrapped loads the current transport.Address func (c *UpdatableAddress) getWrapped() transport.Address { return c.wrapped.Load().(transport.Address) @@ -399,6 +407,13 @@ func LoadConfig(path string) (*Config, error) { } cfg.Ctrl.Endpoint = NewUpdatableAddress(address) } + if value, found := submap[CtrlEndpointBindMapKey]; found { + _, err := transport.ResolveInterface(value.(string)) + if err != nil { + return nil, fmt.Errorf("cannot parse [ctrl/bind] (%s)", err) + } + cfg.Ctrl.LocalBinding = value.(string) + } if value, found := submap["options"]; found { if optionsMap, ok := value.(map[interface{}]interface{}); ok { options, err := channel.LoadOptions(optionsMap) diff --git a/router/router.go b/router/router.go index db3ea13a9..803a7a2fe 100644 --- a/router/router.go +++ b/router/router.go @@ -414,7 +414,10 @@ func (self *Router) startControlPlane() error { } } - dialer := channel.NewReconnectingDialerWithHandler(self.config.Id, self.config.Ctrl.Endpoint, attributes, reconnectHandler) + if "" != self.config.Ctrl.LocalBinding { + logrus.Debugf("Using local interface %s to dial controller", self.config.Ctrl.LocalBinding) + } + dialer := channel.NewReconnectingDialerWithHandlerAndLocalBinding(self.config.Id, self.config.Ctrl.Endpoint, self.config.Ctrl.LocalBinding, attributes, reconnectHandler) bindHandler := handler_ctrl.NewBindHandler( self.config.Id, diff --git a/router/xlink_transport/config.go b/router/xlink_transport/config.go index 8809ac8cb..130764e91 100644 --- a/router/xlink_transport/config.go +++ b/router/xlink_transport/config.go @@ -21,6 +21,7 @@ import ( "github.com/openziti/channel" "github.com/openziti/transport" "github.com/pkg/errors" + "github.com/sirupsen/logrus" "reflect" ) @@ -103,6 +104,20 @@ func loadDialerConfig(data map[interface{}]interface{}) (*dialerConfig, error) { } } + if value, found := data["bind"]; found { + logrus.Debugf("Parsing dialer bind config") + if addressString, ok := value.(string); ok { + _, err := transport.ResolveInterface(addressString) + if err != nil { + return nil, errors.Errorf("invalid 'bind' address in dialer config (%s)", err) + } + config.localBinding = addressString + logrus.Debugf("Using local bind address %s", config.localBinding) + } else { + return nil, fmt.Errorf("invalid 'bind' address in dialer config (%s)", reflect.TypeOf(value)) + } + } + if value, found := data["options"]; found { if submap, ok := value.(map[interface{}]interface{}); ok { options, err := channel.LoadOptions(submap) @@ -119,6 +134,7 @@ func loadDialerConfig(data map[interface{}]interface{}) (*dialerConfig, error) { } type dialerConfig struct { - split bool - options *channel.Options + split bool + localBinding string + options *channel.Options } diff --git a/router/xlink_transport/dialer.go b/router/xlink_transport/dialer.go index 54bc88552..0884d818c 100644 --- a/router/xlink_transport/dialer.go +++ b/router/xlink_transport/dialer.go @@ -64,7 +64,7 @@ func (self *dialer) Dial(dial xlink.Dial) (xlink.Xlink, error) { func (self *dialer) dialSplit(linkId *identity.TokenId, address transport.Address, connId string, dial xlink.Dial) (xlink.Xlink, error) { logrus.Debugf("dialing link with split payload/ack channels [l/%s]", linkId.Token) - payloadDialer := channel.NewClassicDialer(linkId, address, map[int32][]byte{ + payloadDialer := channel.NewClassicDialerWithBindAddress(linkId, address, self.config.localBinding, map[int32][]byte{ LinkHeaderRouterId: []byte(self.id.Token), LinkHeaderConnId: []byte(connId), LinkHeaderType: {byte(PayloadChannel)}, @@ -89,7 +89,7 @@ func (self *dialer) dialSplit(linkId *identity.TokenId, address transport.Addres logrus.Debugf("dialing ack channel for [l/%s]", linkId.Token) - ackDialer := channel.NewClassicDialer(linkId, address, map[int32][]byte{ + ackDialer := channel.NewClassicDialerWithBindAddress(linkId, address, self.config.localBinding, map[int32][]byte{ LinkHeaderRouterId: []byte(self.id.Token), LinkHeaderConnId: []byte(connId), LinkHeaderType: {byte(AckChannel)}, @@ -108,7 +108,7 @@ func (self *dialer) dialSplit(linkId *identity.TokenId, address transport.Addres func (self *dialer) dialSingle(linkId *identity.TokenId, address transport.Address, connId string, dial xlink.Dial) (xlink.Xlink, error) { logrus.Debugf("dialing link with single channel [l/%s]", linkId.Token) - payloadDialer := channel.NewClassicDialer(linkId, address, map[int32][]byte{ + payloadDialer := channel.NewClassicDialerWithBindAddress(linkId, address, self.config.localBinding, map[int32][]byte{ LinkHeaderRouterId: []byte(self.id.Token), LinkHeaderConnId: []byte(connId), LinkHeaderRouterVersion: []byte(dial.GetRouterVersion()),