Пример #1
0
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
}
Пример #2
0
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")
}