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
}