pkg/skoop/plugin/simple.go (149 lines of code) (raw):

package plugin import ( "fmt" "net" "github.com/alibaba/kubeskoop/pkg/skoop/assertions" "github.com/alibaba/kubeskoop/pkg/skoop/k8s" "github.com/alibaba/kubeskoop/pkg/skoop/model" "github.com/alibaba/kubeskoop/pkg/skoop/netstack" "github.com/alibaba/kubeskoop/pkg/skoop/utils" "github.com/samber/lo" ) type simpleVEthPod struct { netNode *model.NetNode podInfo *k8s.Pod net *assertions.NetstackAssertion k8s *assertions.KubernetesAssertion mtu int iface string ipCache *k8s.IPCache } func newSimpleVEthPod(pod *k8s.Pod, ipCache *k8s.IPCache, mtu int, iface string) (*simpleVEthPod, error) { netNode := model.NewNetNode(fmt.Sprintf("%s/%s", pod.Namespace, pod.PodName), model.NetNodeTypePod) return &simpleVEthPod{ netNode: netNode, podInfo: pod, mtu: mtu, iface: iface, net: assertions.NewNetstackAssertion(netNode, &pod.NetNS), k8s: assertions.NewKubernetesAssertion(netNode), ipCache: ipCache, }, nil } func (p *simpleVEthPod) assert() error { pod, err := p.ipCache.GetPodFromName(p.podInfo.Namespace, p.podInfo.PodName) if err != nil { return err } p.k8s.AssertPod(pod) p.net.AssertDefaultRule() p.net.AssertNoPolicyRoute() p.net.AssertNoIPTables() p.net.AssertDefaultAccept() p.net.AssertNetDevice("eth0", netstack.Interface{ MTU: p.mtu, State: netstack.LinkUP, }) p.net.AssertNetDevice("lo", netstack.Interface{ State: netstack.LinkUP, }) return nil } func (p *simpleVEthPod) Send(dst model.Endpoint, protocol model.Protocol) ([]model.Transmission, error) { err := p.assert() if err != nil { return nil, err } pkt := &model.Packet{ Dst: net.ParseIP(dst.IP), Dport: dst.Port, Protocol: protocol, } addr, dstRoute, err := p.podInfo.NetNS.Router.RouteSrc(pkt, "", "") if err != nil { if err == netstack.ErrNoRouteToHost { p.netNode.AddSuspicion(model.SuspicionLevelFatal, fmt.Sprintf("no route to host: %v", dst)) } return nil, &assertions.CannotBuildTransmissionError{ SrcNode: p.netNode, Err: fmt.Errorf("no route to host: %v", err)} } neigh, err := p.podInfo.NetNS.Neighbour.ProbeRouteNeigh(dstRoute, pkt.Dst) if err != nil { return nil, &assertions.CannotBuildTransmissionError{ SrcNode: p.netNode, Err: fmt.Errorf("pod neigh system probe failed: %v", err), } } if neigh != nil && (neigh.State == netstack.NudFailed || neigh.State == netstack.NudIncomplete) { if dstRoute.Gw == nil { p.netNode.AddSuspicion(model.SuspicionLevelCritical, fmt.Sprintf("dst: %v ARP resolve failed.", pkt.Dst.String())) } else { p.netNode.AddSuspicion(model.SuspicionLevelCritical, fmt.Sprintf("dst: %v route's gateway: %v ARP resolve failed.", pkt.Dst.String(), dstRoute.Gw.String())) } } pkt.Src = net.ParseIP(addr) iface, _ := lo.Find(p.podInfo.NetNS.Interfaces, func(i netstack.Interface) bool { return i.Name == "eth0" }) link := &model.Link{ Type: model.LinkVeth, Source: p.netNode, Packet: pkt, SourceAttribute: model.VEthLinkAttribute{ SimpleLinkAttribute: model.SimpleLinkAttribute{ Interface: "eth0", IP: addr, }, PeerIndex: iface.PeerIndex, }, } err = p.net.AssertRoute(assertions.RouteAssertion{Dev: utils.ToPointer("eth0")}, *pkt, "", "") if err != nil { return nil, err } p.netNode.DoAction(model.ActionSend([]*model.Link{link})) return []model.Transmission{ { NextHop: model.Hop{ Type: model.NetNodeTypeNode, ID: p.podInfo.NodeName, }, Link: link, }, }, nil } func (p *simpleVEthPod) Receive(upstream *model.Link) ([]model.Transmission, error) { if upstream.Type != model.LinkVeth { return nil, fmt.Errorf("unexpect upstream type to receive, expect veth, but: %v", upstream.Type) } upstream.Destination = p.netNode upstream.DestinationAttribute = model.SimpleLinkAttribute{ Interface: "eth0", } pkt := upstream.Packet err := p.assert() if err != nil { return nil, err } err = p.net.AssertRoute(assertions.RouteAssertion{Dev: utils.ToPointer("eth0")}, *ack(pkt), "", "") if err != nil { return nil, err } p.net.AssertListen(pkt.Dst, pkt.Dport, pkt.Protocol) p.netNode.DoAction(model.ActionServe(upstream)) return []model.Transmission{}, nil } type GenericNetNode struct { NetNode *model.NetNode } func (n *GenericNetNode) Send(_ model.Endpoint, _ model.Protocol) ([]model.Transmission, error) { n.NetNode.AddSuspicion(model.SuspicionLevelFatal, "non pod/node address as source is not supported") return nil, &assertions.CannotBuildTransmissionError{ SrcNode: n.NetNode, Err: fmt.Errorf("non pod/node address as source is not supported"), } } func (n *GenericNetNode) Receive(upstream *model.Link) ([]model.Transmission, error) { upstream.Destination = n.NetNode n.NetNode.DoAction(model.ActionServe(upstream)) return nil, nil }