Skip to content
Snippets Groups Projects
Unverified Commit f2a77ce0 authored by Annika Wickert's avatar Annika Wickert Committed by GitHub
Browse files

Merge pull request #251 from bio-routing/bgp/ttl

Add support for setting TTL on BGP sessions
parents d25d3e28 35847dfd
No related branches found
No related tags found
No related merge requests found
......@@ -28,6 +28,7 @@ type BGPGroup struct {
Name string `yaml:"name"`
LocalAddress string `yaml:"local_address"`
LocalAddressIP *bnet.IP
TTL uint8 `yaml:"ttl"`
AuthenticationKey string `yaml:"authentication_key"`
PeerAS uint32 `yaml:"peer_as"`
LocalAS uint32 `yaml:"local_as"`
......@@ -72,6 +73,10 @@ func (bg *BGPGroup) load(localAS uint32, policyOptions *PolicyOptions) error {
n.LocalAddress = bg.LocalAddress
}
if n.TTL == 0 {
n.TTL = bg.TTL
}
if n.AuthenticationKey == "" {
n.AuthenticationKey = bg.AuthenticationKey
}
......@@ -115,6 +120,7 @@ type BGPNeighbor struct {
PeerAddressIP *bnet.IP
LocalAddress string `yaml:"local_address"`
LocalAddressIP *bnet.IP
TTL uint8 `yaml:"ttl"`
AuthenticationKey string `yaml:"authentication_key"`
PeerAS uint32 `yaml:"peer_as"`
LocalAS uint32 `yaml:"local_as"`
......
......@@ -189,6 +189,7 @@ func BGPPeerConfig(n *config.BGPNeighbor, vrf *vrf.VRF) *bgpserver.PeerConfig {
PeerAS: n.PeerAS,
PeerAddress: n.PeerAddressIP,
LocalAddress: n.LocalAddressIP,
TTL: n.TTL,
ReconnectInterval: time.Second * 15,
HoldTime: n.HoldTimeDuration,
KeepAlive: n.HoldTimeDuration / 3,
......
......@@ -54,6 +54,12 @@ func (s *activeState) connectRetryTimerExpired() (state, string) {
}
func (s *activeState) connectionSuccess(con net.Conn) (state, string) {
if s.fsm.peer.ttl != 0 {
SetTCPConnTTLSockopt(con, s.fsm.peer.ttl)
} else if s.fsm.peer.isEBGP() {
SetTCPConnTTLSockopt(con, 1)
}
s.fsm.con = con
stopTimer(s.fsm.connectRetryTimer)
err := s.fsm.sendOpen()
......
......@@ -37,6 +37,12 @@ func (s connectState) run() (state, string) {
}
func (s *connectState) connectionSuccess(c net.Conn) (state, string) {
if s.fsm.peer.ttl != 0 {
SetTCPConnTTLSockopt(c, s.fsm.peer.ttl)
} else if s.fsm.peer.isEBGP() {
SetTCPConnTTLSockopt(c, 1)
}
s.fsm.con = c
stopTimer(s.fsm.connectRetryTimer)
err := s.fsm.sendOpen()
......
......@@ -20,6 +20,7 @@ type peer struct {
config *PeerConfig
addr *bnet.IP
localAddr *bnet.IP
ttl uint8
passive bool
peerASN uint32
localASN uint32
......@@ -51,6 +52,7 @@ type PeerConfig struct {
HoldTime time.Duration
LocalAddress *bnet.IP
PeerAddress *bnet.IP
TTL uint8
LocalAS uint32
PeerAS uint32
Passive bool
......@@ -242,6 +244,7 @@ func newPeer(c PeerConfig, server *bgpServer) (*peer, error) {
server: server,
config: &c,
addr: c.PeerAddress,
ttl: c.TTL,
passive: c.Passive,
peerASN: c.PeerAS,
localASN: c.LocalAS,
......@@ -401,3 +404,7 @@ func (p *peer) stop() {
fsm.eventCh <- ManualStop
}
}
func (p *peer) isEBGP() bool {
return p.localASN != p.peerASN
}
......@@ -11,7 +11,8 @@ const (
IPV6_MINHOPCOUNT = 73 // Generalized TTL Security Mechanism (RFC5082)
)
func SetListenTCPTTLSockopt(l *net.TCPListener, ttl int) error {
// SetListenTCPTTLSockopt sets the TTL on a TCP listener
func SetListenTCPTTLSockopt(l *net.TCPListener, ttl uint8) error {
fi, family, err := extractFileAndFamilyFromTCPListener(l)
defer fi.Close()
if err != nil {
......@@ -20,12 +21,30 @@ func SetListenTCPTTLSockopt(l *net.TCPListener, ttl int) error {
return setsockoptIPTTL(int(fi.Fd()), family, ttl)
}
func setsockoptIPTTL(fd int, family int, value int) error {
// SetTCPConnTTLSockopt sets the TTL on a TCP connection
func SetTCPConnTTLSockopt(c net.Conn, ttl uint8) error {
switch c.(type) {
case *net.TCPConn:
default:
return nil
}
fi, family, err := extractFileAndFamilyFromTCPConn(c.(*net.TCPConn))
defer fi.Close()
if err != nil {
return err
}
return setsockoptIPTTL(int(fi.Fd()), family, ttl)
}
func setsockoptIPTTL(fd int, family int, value uint8) error {
level := syscall.IPPROTO_IP
name := syscall.IP_TTL
if family == syscall.AF_INET6 {
level = syscall.IPPROTO_IPV6
name = syscall.IPV6_UNICAST_HOPS
}
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, level, name, value))
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, level, name, int(value)))
}
......@@ -24,10 +24,33 @@ func extractFileAndFamilyFromTCPListener(l *net.TCPListener) (*os.File, int, err
}
fl.Close()
family := syscall.AF_INET
if strings.Contains(l.Addr().String(), "[") {
family = syscall.AF_INET6
return fi, getAFIFromAddr(l.Addr().String()), nil
}
func extractFileAndFamilyFromTCPConn(c *net.TCPConn) (*os.File, int, error) {
// Note #1: TCPListener.File() has the unexpected side-effect of putting
// the original socket into blocking mode. See Note #2.
fi, err := c.File()
if err != nil {
return nil, 0, err
}
// Note #2: Call net.FileListener() to put the original socket back into
// non-blocking mode.
fl, err := net.FileListener(fi)
if err != nil {
fi.Close()
return nil, 0, err
}
fl.Close()
return fi, getAFIFromAddr(c.LocalAddr().String()), nil
}
func getAFIFromAddr(addr string) int {
if strings.Contains(addr, "[") {
return syscall.AF_INET6
}
return fi, family, nil
return syscall.AF_INET
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment