func createTunnel(host string, udp bool) (net.IP, net.IP, error) { c, err := client.NewClient(host, opts.config) if err != nil { return nil, nil, err } defer c.Close() dst, err := c.GetSrcIP(nil) tunnel := &client.Tunnel{} exists := getTunnel(dst.String()) if exists != nil { glog.Infof("Tunnel already exists: %v, %v", exists.Src, exists.Dst) // tunnel dst and src are reversed from remote tunnel.Reqid = exists.Reqid tunnel.Src = exists.Dst tunnel.Dst = exists.Src tunnel.AuthKey = exists.AuthKey tunnel.EncKey = exists.EncKey tunnel.SrcPort = exists.DstPort tunnel.SrcPort = exists.SrcPort } else { tunnel = &client.Tunnel{} if udp { var err error tunnel.DstPort, err = allocatePort() if err != nil { glog.Errorf("No ports available: %v", dst) return nil, nil, err } glog.Infof("Using %d for encap port", tunnel.DstPort) } tunnel.AuthKey = randomKey() tunnel.EncKey = randomKey() // random number between 1 and 2^32 bigreq, err := rand.Int(rand.Reader, big.NewInt(int64(^uint32(0)))) if err != nil { glog.Errorf("Failed to generate reqid: %v", err) return nil, nil, err } tunnel.Reqid = int(bigreq.Int64()) + 1 } // While tail not created for { if tunnel.Src == nil { // Select random pair of addresses from cidr for { tunnel.Dst, tunnel.Src, err = randomIPPair(opts.cidr) if err != nil { return nil, nil, err } err = reserveIP(tunnel.Dst) if err != nil { glog.Infof("IP in use: %v", tunnel.Dst) continue } err = reserveIP(tunnel.Src) if err != nil { unreserveIP(tunnel.Dst) glog.Infof("IP in use: %v", tunnel.Src) continue } break } } // create tail of tunnel var out *client.Tunnel dst, out, err = c.BuildTunnel(opts.external, tunnel) if err != nil { _, ok := err.(IPInUse) if ok { unreserveIP(tunnel.Dst) unreserveIP(tunnel.Src) tunnel.Src = nil if exists != nil { glog.Warningf("Destroying local tunnel due to remote ip conflict") destroyTunnel(dst) exists = nil } continue } glog.Errorf("Remote BuildTunnel failed: %v", err) // cleanup partial tunnel c.DestroyTunnel(opts.external) return nil, nil, err } if exists != nil && !out.Equal(tunnel) { glog.Warningf("Destroying remote mismatched tunnel") c.DestroyTunnel(opts.external) continue } tunnel = out break } // tunnel dst and src are reversed from remote tunnel.Src, tunnel.Dst = tunnel.Dst, tunnel.Src tunnel.SrcPort, tunnel.DstPort = tunnel.DstPort, tunnel.SrcPort if exists == nil { _, tunnel, err = buildTunnelLocal(dst, tunnel) if err != nil { glog.Errorf("Local buildTunnel failed: %v", err) c.DestroyTunnel(opts.external) destroyTunnel(dst) return nil, nil, err } } return tunnel.Src, tunnel.Dst, nil }
func discoverTunnels() { glog.Infof("Discovering existing tunnels") lo, err := netlink.LinkByName("lo") if err != nil { glog.Errorf("Failed to get loopback device: %v", err) return } addrs, err := netlink.AddrList(lo, netlink.FAMILY_ALL) if err != nil { glog.Errorf("Failed to get addrs: %v", err) return } routes, err := netlink.RouteList(nil, netlink.FAMILY_ALL) if err != nil { glog.Errorf("Failed to get routes: %v", err) return } policies, err := netlink.XfrmPolicyList(netlink.FAMILY_ALL) if err != nil { glog.Errorf("Failed to get xfrm policies: %v", err) return } states, err := netlink.XfrmStateList(netlink.FAMILY_ALL) if err != nil { glog.Errorf("Failed to get xfrm states: %v", err) return } for _, addr := range addrs { if opts.cidr.Contains(addr.IP) { tunnel := client.Tunnel{} tunnel.Src = addr.IP err := reserveIP(tunnel.Src) if err != nil { glog.Warningf("Duplicate tunnel ip detected: %v", tunnel.Src) } tunnel.Dst = nil glog.Infof("Potential tunnel found from %s", tunnel.Src) for _, route := range routes { if route.Src == nil || !route.Src.Equal(tunnel.Src) { continue } tunnel.Dst = route.Dst.IP break } if tunnel.Dst == nil { glog.Warningf("could not find dst for tunnel src %s", tunnel.Src) continue } err = reserveIP(tunnel.Dst) if err != nil { glog.Warningf("Duplicate tunnel ip detected: %v", tunnel.Dst) } var dst net.IP for _, policy := range policies { if !policy.Dst.IP.Equal(tunnel.Dst) { continue } if len(policy.Tmpls) == 0 { glog.Warningf("Tunnel policy has no associated template") continue } dst = policy.Tmpls[0].Dst break } if dst == nil { glog.Warningf("could not find ip for tunnel between %s and %s", tunnel.Src, tunnel.Dst) continue } for _, state := range states { if !state.Dst.Equal(dst) { continue } tunnel.Reqid = state.Reqid if state.Auth == nil { glog.Warningf("Tunnel state has no associated authentication entry") continue } tunnel.AuthKey = state.Auth.Key if state.Crypt == nil { glog.Warningf("Tunnel state has no associated encryption entry") continue } tunnel.EncKey = state.Crypt.Key if state.Encap != nil { tunnel.SrcPort = state.Encap.SrcPort tunnel.SrcPort = state.Encap.DstPort } glog.Infof("Discovered tunnel between %v and %v over %v", tunnel.Src, tunnel.Dst, dst) var socket int if tunnel.SrcPort != 0 { socket, err = createEncapListener(tunnel.Src, tunnel.SrcPort) if err != nil { glog.Warningf("Failed to create udp listener: %v", err) } } addTunnel(dst.String(), &tunnel, socket) break } } } glog.Infof("Finished discovering existing tunnels") }