summaryrefslogtreecommitdiffhomepage
path: root/pkg
diff options
context:
space:
mode:
authorMilan Lenco <milan.lenco@pantheon.tech>2021-01-21 13:53:33 +0100
committerFUJITA Tomonori <fujita.tomonori@gmail.com>2021-02-13 18:54:31 +0900
commit3339f97722e35d5ff351ef500de1e61344cbd33d (patch)
tree600f85f5a0cd1440670c62c3fd881a3a6efb0645 /pkg
parentc89a32ea7bbed1780b93431e2f94482df462206e (diff)
feat: add option to bind listener to a (VRF) device
Signed-off-by: Milan Lenco <milan.lenco@pantheon.tech>
Diffstat (limited to 'pkg')
-rw-r--r--pkg/server/server.go52
-rw-r--r--pkg/server/sockopt.go9
-rw-r--r--pkg/server/sockopt_bsd.go9
-rw-r--r--pkg/server/sockopt_darwin.go9
-rw-r--r--pkg/server/sockopt_linux.go16
-rw-r--r--pkg/server/sockopt_openbsd.go13
-rw-r--r--pkg/server/util.go8
7 files changed, 49 insertions, 67 deletions
diff --git a/pkg/server/server.go b/pkg/server/server.go
index d9a65c0f..c5b2b0ff 100644
--- a/pkg/server/server.go
+++ b/pkg/server/server.go
@@ -23,6 +23,7 @@ import (
"reflect"
"strconv"
"sync"
+ "syscall"
"time"
"github.com/eapache/channels"
@@ -52,35 +53,56 @@ func (l *tcpListener) Close() error {
}
// avoid mapped IPv6 address
-func newTCPListener(address string, port uint32, ch chan *net.TCPConn) (*tcpListener, error) {
+func newTCPListener(address string, port uint32, bindToDev string, ch chan *net.TCPConn) (*tcpListener, error) {
proto := "tcp4"
+ family := syscall.AF_INET
if ip := net.ParseIP(address); ip == nil {
return nil, fmt.Errorf("can't listen on %s", address)
} else if ip.To4() == nil {
proto = "tcp6"
+ family = syscall.AF_INET6
}
- addr, err := net.ResolveTCPAddr(proto, net.JoinHostPort(address, strconv.Itoa(int(port))))
- if err != nil {
- return nil, err
+ addr := net.JoinHostPort(address, strconv.Itoa(int(port)))
+
+ var lc net.ListenConfig
+ lc.Control = func(network, address string, c syscall.RawConn) error {
+ if bindToDev != "" {
+ err := setBindToDevSockopt(c, bindToDev)
+ if err != nil {
+ log.WithFields(log.Fields{
+ "Topic": "Peer",
+ "Key": addr,
+ "BindToDev": bindToDev,
+ }).Warnf("failed to bind Listener to device (%s): %s", bindToDev, err)
+ return err
+ }
+ }
+ // Note: Set TTL=255 for incoming connection listener in order to accept
+ // connection in case for the neighbor has TTL Security settings.
+ err := setsockoptIpTtl(c, family, 255)
+ if err != nil {
+ log.WithFields(log.Fields{
+ "Topic": "Peer",
+ "Key": addr,
+ }).Warnf("cannot set TTL(=%d) for TCPListener: %s", 255, err)
+ }
+ return nil
}
- l, err := net.ListenTCP(proto, addr)
+ l, err := lc.Listen(context.Background(), proto, addr)
if err != nil {
return nil, err
}
- // Note: Set TTL=255 for incoming connection listener in order to accept
- // connection in case for the neighbor has TTL Security settings.
- if err := setListenTCPTTLSockopt(l, 255); err != nil {
- log.WithFields(log.Fields{
- "Topic": "Peer",
- "Key": addr,
- }).Warnf("cannot set TTL(=%d) for TCPListener: %s", 255, err)
+ listener, ok := l.(*net.TCPListener)
+ if !ok {
+ err = fmt.Errorf("unexpected connection listener (not for TCP)")
+ return nil, err
}
closeCh := make(chan struct{})
go func() error {
for {
- conn, err := l.AcceptTCP()
+ conn, err := listener.AcceptTCP()
if err != nil {
close(closeCh)
log.WithFields(log.Fields{
@@ -93,7 +115,7 @@ func newTCPListener(address string, port uint32, ch chan *net.TCPConn) (*tcpList
}
}()
return &tcpListener{
- l: l,
+ l: listener,
ch: closeCh,
}, nil
}
@@ -2101,7 +2123,7 @@ func (s *BgpServer) StartBgp(ctx context.Context, r *api.StartBgpRequest) error
if c.Config.Port > 0 {
acceptCh := make(chan *net.TCPConn, 4096)
for _, addr := range c.Config.LocalAddressList {
- l, err := newTCPListener(addr, uint32(c.Config.Port), acceptCh)
+ l, err := newTCPListener(addr, uint32(c.Config.Port), g.BindToDevice, acceptCh)
if err != nil {
return err
}
diff --git a/pkg/server/sockopt.go b/pkg/server/sockopt.go
index 0aab0ba9..235bbbb9 100644
--- a/pkg/server/sockopt.go
+++ b/pkg/server/sockopt.go
@@ -17,6 +17,7 @@
package server
import (
+ "fmt"
"net"
"syscall"
@@ -27,10 +28,6 @@ func setTCPMD5SigSockopt(l *net.TCPListener, address string, key string) error {
return setTcpMD5SigSockopt(l, address, key)
}
-func setListenTCPTTLSockopt(l *net.TCPListener, ttl int) error {
- return setListenTcpTTLSockopt(l, ttl)
-}
-
func setTCPTTLSockopt(conn *net.TCPConn, ttl int) error {
return setTcpTTLSockopt(conn, ttl)
}
@@ -39,6 +36,10 @@ func setTCPMinTTLSockopt(conn *net.TCPConn, ttl int) error {
return setTcpMinTTLSockopt(conn, ttl)
}
+func setBindToDevSockopt(sc syscall.RawConn, device string) error {
+ return fmt.Errorf("binding connection to a device is not supported")
+}
+
func dialerControl(network, address string, c syscall.RawConn, ttl, ttlMin uint8, password string, bindInterface string) error {
if password != "" {
log.WithFields(log.Fields{
diff --git a/pkg/server/sockopt_bsd.go b/pkg/server/sockopt_bsd.go
index fe7a6134..942e1289 100644
--- a/pkg/server/sockopt_bsd.go
+++ b/pkg/server/sockopt_bsd.go
@@ -35,15 +35,6 @@ func setTcpMD5SigSockopt(l *net.TCPListener, address string, key string) error {
return setsockOptInt(sc, syscall.IPPROTO_TCP, tcpMD5SIG, 1)
}
-func setListenTcpTTLSockopt(l *net.TCPListener, ttl int) error {
- family := extractFamilyFromTCPListener(l)
- sc, err := l.SyscallConn()
- if err != nil {
- return err
- }
- return setsockoptIpTtl(sc, family, ttl)
-}
-
func setTcpTTLSockopt(conn *net.TCPConn, ttl int) error {
family := extractFamilyFromTCPConn(conn)
sc, err := conn.SyscallConn()
diff --git a/pkg/server/sockopt_darwin.go b/pkg/server/sockopt_darwin.go
index abb69d35..30220952 100644
--- a/pkg/server/sockopt_darwin.go
+++ b/pkg/server/sockopt_darwin.go
@@ -27,15 +27,6 @@ func setTcpMD5SigSockopt(l *net.TCPListener, address string, key string) error {
return fmt.Errorf("setting md5 is not supported")
}
-func setListenTcpTTLSockopt(l *net.TCPListener, ttl int) error {
- family := extractFamilyFromTCPListener(l)
- sc, err := l.SyscallConn()
- if err != nil {
- return err
- }
- return setsockoptIpTtl(sc, family, ttl)
-}
-
func setTcpTTLSockopt(conn *net.TCPConn, ttl int) error {
family := syscall.AF_INET
if strings.Contains(conn.RemoteAddr().String(), "[") {
diff --git a/pkg/server/sockopt_linux.go b/pkg/server/sockopt_linux.go
index 203087ab..55d27bd4 100644
--- a/pkg/server/sockopt_linux.go
+++ b/pkg/server/sockopt_linux.go
@@ -70,13 +70,8 @@ func setTCPMD5SigSockopt(l *net.TCPListener, address string, key string) error {
return setsockOptString(sc, syscall.IPPROTO_TCP, tcpMD5SIG, string(b[:]))
}
-func setListenTCPTTLSockopt(l *net.TCPListener, ttl int) error {
- family := extractFamilyFromTCPListener(l)
- sc, err := l.SyscallConn()
- if err != nil {
- return err
- }
- return setsockoptIpTtl(sc, family, ttl)
+func setBindToDevSockopt(sc syscall.RawConn, device string) error {
+ return setsockOptString(sc, syscall.SOL_SOCKET, syscall.SO_BINDTODEVICE, device)
}
func setTCPTTLSockopt(conn *net.TCPConn, ttl int) error {
@@ -162,14 +157,9 @@ func dialerControl(network, address string, c syscall.RawConn, ttl, minTtl uint8
}
}
if bindInterface != "" {
- if err := c.Control(func(fd uintptr) {
- sockerr = os.NewSyscallError("setsockopt", syscall.SetsockoptString(int(fd), syscall.SOL_SOCKET, syscall.SO_BINDTODEVICE, bindInterface))
- }); err != nil {
+ if err := setBindToDevSockopt(c, bindInterface); err != nil {
return err
}
- if sockerr != nil {
- return sockerr
- }
}
return nil
}
diff --git a/pkg/server/sockopt_openbsd.go b/pkg/server/sockopt_openbsd.go
index 3d6825e2..612047ca 100644
--- a/pkg/server/sockopt_openbsd.go
+++ b/pkg/server/sockopt_openbsd.go
@@ -370,15 +370,6 @@ func setTCPMD5SigSockopt(l *net.TCPListener, address string, key string) error {
return setsockoptTcpMD5Sig(sc, address, key)
}
-func setListenTCPTTLSockopt(l *net.TCPListener, ttl int) error {
- family := extractFamilyFromTCPListener(l)
- sc, err := l.SyscallConn()
- if err != nil {
- return err
- }
- return setsockoptIpTtl(sc, family, ttl)
-}
-
func setTCPTTLSockopt(conn *net.TCPConn, ttl int) error {
family := extractFamilyFromTCPConn(conn)
sc, err := conn.SyscallConn()
@@ -403,6 +394,10 @@ func setTCPMinTTLSockopt(conn *net.TCPConn, ttl int) error {
return setsockOptInt(sc, level, name, ttl)
}
+func setBindToDevSockopt(sc syscall.RawConn, device string) error {
+ return fmt.Errorf("binding connection to a device is not supported")
+}
+
func dialerControl(network, address string, c syscall.RawConn, ttl, minTtl uint8, password string, bindInterface string) error {
if password != "" {
log.WithFields(log.Fields{
diff --git a/pkg/server/util.go b/pkg/server/util.go
index c774c6dd..e4abbed0 100644
--- a/pkg/server/util.go
+++ b/pkg/server/util.go
@@ -65,14 +65,6 @@ func decodeAdministrativeCommunication(data []byte) (string, []byte) {
return string(data[1 : communicationLen+1]), data[communicationLen+1:]
}
-func extractFamilyFromTCPListener(l *net.TCPListener) int {
- family := syscall.AF_INET
- if strings.Contains(l.Addr().String(), "[") {
- family = syscall.AF_INET6
- }
- return family
-}
-
func extractFamilyFromTCPConn(conn *net.TCPConn) int {
family := syscall.AF_INET
if strings.Contains(conn.RemoteAddr().String(), "[") {