diff options
Diffstat (limited to 'server')
-rw-r--r-- | server/fsm.go | 46 | ||||
-rw-r--r-- | server/sockopt_linux.go | 24 |
2 files changed, 44 insertions, 26 deletions
diff --git a/server/fsm.go b/server/fsm.go index 94ee588e..168a0387 100644 --- a/server/fsm.go +++ b/server/fsm.go @@ -293,43 +293,41 @@ func (fsm *FSM) connectLoop() error { host := net.JoinHostPort(addr, strconv.Itoa(bgp.BGP_PORT)) // check if LocalAddress has been configured laddr := fsm.pConf.Transport.Config.LocalAddress + var conn net.Conn + var err error if laddr != "" { - lhost := net.JoinHostPort(laddr, "0") - ltcpaddr, err := net.ResolveTCPAddr("tcp", lhost) - if err != nil { - log.WithFields(log.Fields{ - "Topic": "Peer", - "Key": fsm.pConf.Config.NeighborAddress, - }).Warnf("failed to resolve ltcpaddr: %s", err) + if fsm.pConf.Config.AuthPassword != "" { + deadline := (MIN_CONNECT_RETRY - 1) * 1000 // msec + conn, err = DialTCPTimeoutWithMD5Sig(addr, bgp.BGP_PORT, laddr, fsm.pConf.Config.AuthPassword, deadline) } else { - d := net.Dialer{LocalAddr: ltcpaddr, Timeout: time.Duration(MIN_CONNECT_RETRY-1) * time.Second} - if conn, err := d.Dial("tcp", host); err == nil { - fsm.connCh <- conn - } else { + lhost := net.JoinHostPort(laddr, "0") + ltcpaddr, e := net.ResolveTCPAddr("tcp", lhost) + if e != nil { log.WithFields(log.Fields{ "Topic": "Peer", "Key": fsm.pConf.Config.NeighborAddress, - }).Debugf("failed to connect from ltcpaddr", err) + }).Warnf("failed to resolve ltcpaddr: %s", e) + return } + d := net.Dialer{LocalAddr: ltcpaddr, Timeout: time.Duration(MIN_CONNECT_RETRY-1) * time.Second} + conn, err = d.Dial("tcp", host) } - } else { - var conn net.Conn - var err error if fsm.pConf.Config.AuthPassword != "" { deadline := (MIN_CONNECT_RETRY - 1) * 1000 // msec - conn, err = DialTCPTimeoutWithMD5Sig(addr, bgp.BGP_PORT, fsm.pConf.Config.AuthPassword, deadline) + conn, err = DialTCPTimeoutWithMD5Sig(addr, bgp.BGP_PORT, "0.0.0.0", fsm.pConf.Config.AuthPassword, deadline) } else { conn, err = net.DialTimeout("tcp", host, time.Duration(MIN_CONNECT_RETRY-1)*time.Second) } - if err == nil { - fsm.connCh <- conn - } else { - log.WithFields(log.Fields{ - "Topic": "Peer", - "Key": fsm.pConf.Config.NeighborAddress, - }).Debugf("failed to connect: %s", err) - } + } + + if err == nil { + fsm.connCh <- conn + } else { + log.WithFields(log.Fields{ + "Topic": "Peer", + "Key": fsm.pConf.Config.NeighborAddress, + }).Debugf("failed to connect: %s", err) } } } diff --git a/server/sockopt_linux.go b/server/sockopt_linux.go index d238823c..436591e9 100644 --- a/server/sockopt_linux.go +++ b/server/sockopt_linux.go @@ -24,14 +24,21 @@ import ( "unsafe" ) -func DialTCPTimeoutWithMD5Sig(host string, port int, key string, msec int) (*net.TCPConn, error) { +func DialTCPTimeoutWithMD5Sig(host string, port int, localAddr, key string, msec int) (*net.TCPConn, error) { var family int - var ra syscall.Sockaddr + var ra, la syscall.Sockaddr ip := net.ParseIP(host) if ip == nil { return nil, fmt.Errorf("invalid ip: %s", host) } + l := net.ParseIP(localAddr) + if l == nil { + return nil, fmt.Errorf("invalid local ip: %s", localAddr) + } + if (ip.To4() != nil) != (l.To4() != nil) { + return nil, fmt.Errorf("remote and local ip address family is not same") + } switch { case ip.To4() != nil: family = syscall.AF_INET @@ -42,6 +49,11 @@ func DialTCPTimeoutWithMD5Sig(host string, port int, key string, msec int) (*net i.Addr[idx] = ip.To4()[idx] } ra = i + j := &syscall.SockaddrInet4{} + for idx, _ := range j.Addr { + j.Addr[idx] = l.To4()[idx] + } + la = j default: family = syscall.AF_INET6 i := &syscall.SockaddrInet6{ @@ -51,6 +63,11 @@ func DialTCPTimeoutWithMD5Sig(host string, port int, key string, msec int) (*net i.Addr[idx] = ip[idx] } ra = i + j := &syscall.SockaddrInet6{} + for idx, _ := range j.Addr { + j.Addr[idx] = l[idx] + } + la = j } sotype := syscall.SOCK_STREAM | syscall.SOCK_CLOEXEC proto := 0 @@ -73,6 +90,9 @@ func DialTCPTimeoutWithMD5Sig(host string, port int, key string, msec int) (*net if err = syscall.SetsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_NODELAY, 1); err != nil { return nil, os.NewSyscallError("setsockopt", err) } + if err = syscall.Bind(fd, la); err != nil { + return nil, os.NewSyscallError("bind", err) + } tcpconn := func(fd uintptr) (*net.TCPConn, error) { fi := os.NewFile(uintptr(fd), "") |