func()

in pkg/skoop/network/aliyun/assertion.go [190:309]


func (a *vpcAssertion) AssertRoute(srcECS, dstECS string, pkt *model.Packet, privateIP string) ([]model.Suspicion, error) {
	var suspicions []model.Suspicion
	var routeEntries []*vpc.DescribeRouteEntryListResponseBodyRouteEntrysRouteEntry
	var srcECSInfo, dstECSInfo *aliyun.ECSInfo
	var err error

	if srcECS == "" && dstECS == "" {
		return nil, nil
	}

	if srcECS != "" {
		srcECSInfo, err = a.cloudManager.GetECSInfo(srcECS)
		if err != nil {
			return nil, err
		}

		routeEntries = srcECSInfo.Network.RouteTableEntries
		if !slices.Contains(srcECSInfo.Network.IP, pkt.Src.String()) {
			routeEntries = srcECSInfo.Network.VpcDefaultRouteTableEntries
		}
		lo.ForEach(srcECSInfo.Network.NetworkInterfaces, func(ni *aliyun.ENIInfo, _ int) {
			lo.ForEach(ni.NetworkInterfaceSet.PrivateIpSets.PrivateIpSet, func(ip *ecs.DescribeNetworkInterfacesResponseBodyNetworkInterfaceSetsNetworkInterfaceSetPrivateIpSetsPrivateIpSet, _ int) {
				if ip.PrivateIpAddress != nil && *ip.PrivateIpAddress == pkt.Src.String() {
					routeEntries = ni.RouteTableEntries
				}
			})
		})
	}

	if dstECS != "" {
		dstECSInfo, err = a.cloudManager.GetECSInfo(dstECS)
		if err != nil {
			return nil, err
		}

		if srcECS == "" {
			routeEntries = dstECSInfo.Network.VpcDefaultRouteTableEntries
		}
	}

	dstRouteEntry, err := routeMatchPacket(pkt.Dst.String(), routeEntries)
	if err != nil {
		return nil, err
	}
	if dstRouteEntry == nil {
		suspicions = append(suspicions, model.Suspicion{
			Level:   model.SuspicionLevelFatal,
			Message: fmt.Sprintf("no route entry for destination ip %q", pkt.Dst),
		})
	}

	if dstECS != "" && dstRouteEntry != nil && !slices.Contains(dstECSInfo.Network.IP, pkt.Dst.String()) {
		// we do not route dst ip in ecs network ips
		// is there any situation that len(NextHop) == 0?
		nextHop := dstRouteEntry.NextHops.NextHop[0]
		if *nextHop.NextHopType != "local" &&
			!(*nextHop.NextHopType == "Instance" && *nextHop.NextHopId == dstECS) {
			suspicions = append(suspicions, model.Suspicion{
				Level: model.SuspicionLevelFatal,
				Message: fmt.Sprintf("error route next hop for destination ip \"%s\", expect: \"Instance-%s\", actually: \"%s-%s\"",
					pkt.Dst.String(), dstECS, *nextHop.NextHopType, *nextHop.NextHopId),
			})
		}
	}

	// reverse path
	if srcECS != "" {
		var srcRouteEntry *vpc.DescribeRouteEntryListResponseBodyRouteEntrysRouteEntry
		if dstECS != "" {
			if !slices.Contains(dstECSInfo.Network.IP, pkt.Dst.String()) {
				routeEntries = dstECSInfo.Network.VpcDefaultRouteTableEntries
				lo.ForEach(dstECSInfo.Network.NetworkInterfaces, func(ni *aliyun.ENIInfo, _ int) {
					lo.ForEach(ni.NetworkInterfaceSet.PrivateIpSets.PrivateIpSet, func(ip *ecs.DescribeNetworkInterfacesResponseBodyNetworkInterfaceSetsNetworkInterfaceSetPrivateIpSetsPrivateIpSet, _ int) {
						if ip.PrivateIpAddress != nil && *ip.PrivateIpAddress == pkt.Dst.String() {
							routeEntries = ni.RouteTableEntries
						}
					})
				})
			} else {
				routeEntries = dstECSInfo.Network.RouteTableEntries
			}
		} else {
			routeEntries = srcECSInfo.Network.VpcDefaultRouteTableEntries
		}

		if privateIP != "" {
			srcRouteEntry, err = routeMatchPacket(privateIP, routeEntries)
			if err != nil {
				return nil, err
			}
		} else {
			srcRouteEntry, err = routeMatchPacket(pkt.Src.String(), routeEntries)
		}
		if err != nil {
			return nil, err
		}

		if srcRouteEntry == nil {
			suspicions = append(suspicions, model.Suspicion{
				Level:   model.SuspicionLevelFatal,
				Message: fmt.Sprintf("no route entry for src ip %q", pkt.Src.String()),
			})
		}

		if srcRouteEntry != nil && !slices.Contains(srcECSInfo.Network.IP, pkt.Src.String()) {
			nextHop := srcRouteEntry.NextHops.NextHop[0]
			if nextHop.NextHopRegionId != nil && *nextHop.NextHopRegionId != "local" &&
				!(*nextHop.NextHopType == "Instance" && *nextHop.NextHopId == srcECS) {
				suspicions = append(suspicions, model.Suspicion{
					Level: model.SuspicionLevelFatal,
					Message: fmt.Sprintf("error route next hop for source ip: %q, expect: \"Instance-%s\", actual: \"%s-%s\"",
						pkt.Src, srcECSInfo.ID, *nextHop.NextHopType, *nextHop.NextHopId),
				})
			}
		}

	}

	return suspicions, nil
}