func()

in pkg/skoop/netstack/iptables.go [585:678]


func (xt *xTable) tracePacket(ctx context.Context, hook NFHook, packet *model.Packet, iif, oif string) (verdict Verdict, trace Trace, err error) {
	type stackFrame struct {
		chain *iptChain
		pos   int
	}

	chain := xt.chains[hook.String()]
	stack := utils.NewStack[*stackFrame](&stackFrame{
		chain: chain,
		pos:   0,
	})

	verdict = VerdictDrop

	var frame *stackFrame

	buildTrace := func(frame *stackFrame) {
		if frame == nil {
			return
		}

		if frame.pos >= len(frame.chain.rules) {
			return
		}

		trace = append(trace, fmt.Sprintf("%s %s %s", xt.name, chain.name, frame.chain.rules[frame.pos]))
	}

	defer func() {
		if verdict != VerdictAccept {
			buildTrace(frame)
			for !stack.Empty() {
				buildTrace(stack.Pop())
			}
		}
	}()

	for !stack.Empty() {
		frame = stack.Pop()
	chain:
		for pos := frame.pos; pos < len(frame.chain.rules); {
			rule := frame.chain.rules[pos]
			pos++

			v, err := rule.match(ctx, packet, iif, oif)
			if err != nil {
				return VerdictDrop, trace, &IPTablesRuleError{Rule: rule.String(), Message: err.Error()}
			}

			if v {
				trace = append(trace, fmt.Sprintf("%s %s %s", xt.name, chain.name, rule))
				switch target := rule.target.(type) {
				case *AcceptTarget:
					return VerdictAccept, trace, nil
				case *DropTarget, RejectTarget:
					return VerdictDrop, trace, nil
				case *NopTarget:
					continue
				case *ReturnTarget:
					break chain
				case *CallTarget:
					stack.Push(&stackFrame{chain, pos})
					targetChain := xt.chains[target.Chain]
					stack.Push(&stackFrame{targetChain, 0})
					break chain
				case *GotoTarget:
					targetChain := xt.chains[target.Chain]
					stack.Push(&stackFrame{targetChain, 0})
					break chain
				case ExtensionTarget:
					verdict, err := target.Do(ctx, packet, iif, oif)
					if err != nil {
						return VerdictDrop, trace, err
					}
					switch verdict {
					case XTablesVerdictAccept:
						return VerdictAccept, trace, nil
					case XTablesVerdictDrop, XTablesVerdictReject:
						return VerdictDrop, trace, nil
					case XTablesVerdictContinue:
						continue
					case XTablesVerdictReturn:
						break chain
					default:
						panic(fmt.Sprintf("unknown verdict %v", verdict))
					}
				default:
					return VerdictDrop, trace, &IPTablesRuleError{Rule: rule.String(), Message: fmt.Sprintf("unsupported target (%T)%v", target, target)}
				}
			}
		}
	}
	return chain.policy, trace, nil
}