pkg/skoop/netstack/netfilter.go (107 lines of code) (raw):
package netstack
import (
"context"
"github.com/alibaba/kubeskoop/pkg/skoop/model"
"github.com/pkg/errors"
"k8s.io/klog/v2"
)
type NFHook uint8
type Verdict uint8
const (
NFHookPreRouting = iota
NFHookInput
NFHookForward
NFHookOutput
NFHookPostRouting
VerdictAccept Verdict = 0
VerdictDrop Verdict = 1
)
type contextKey string
const (
ContextIPSetKey contextKey = "ipset"
ContextRouterKey contextKey = "router"
)
func (h NFHook) String() string {
switch h {
case NFHookPreRouting:
return "PREROUTING"
case NFHookInput:
return "INPUT"
case NFHookForward:
return "FORWARD"
case NFHookOutput:
return "OUTPUT"
case NFHookPostRouting:
return "POSTROUTING"
default:
return "INVALID"
}
}
type Netfilter interface {
Hook(hook NFHook, packet model.Packet, iif string, oif string) (Verdict, model.Packet, error)
}
type SimulateNetfilterContext struct {
IPTables IPTables
IPSet *IPSetManager
Router Router
IPVS *IPVS
}
type SimulateNetfilter struct {
iptables IPTables
ipvs *IPVS
ctx context.Context
handles map[NFHook][]Handle
}
func NewSimulateNetfilter(netfilterContext SimulateNetfilterContext) *SimulateNetfilter {
ctx := context.TODO()
ctx = context.WithValue(ctx, ContextIPSetKey, netfilterContext.IPSet)
ctx = context.WithValue(ctx, ContextRouterKey, netfilterContext.Router)
nf := &SimulateNetfilter{
ctx: ctx,
iptables: netfilterContext.IPTables,
ipvs: netfilterContext.IPVS,
}
nf.initHandles()
return nf
}
type Handle func(hook NFHook, packet *model.Packet, iif, oif string) (Verdict, Trace, error)
var ErrIPTablesUnsupported = errors.New("cannot process iptables")
type IPTableDropError struct {
Trace Trace
}
func (e *IPTableDropError) Error() string {
return e.Trace.String()
}
func (nf *SimulateNetfilter) Hook(hook NFHook, packet model.Packet, iif string, oif string) (Verdict, model.Packet, error) {
if _, ok := nf.iptables.(*emptyIPTables); ok {
return VerdictAccept, packet, ErrIPTablesUnsupported
}
for _, h := range nf.handles[hook] {
verdict, trace, err := h(hook, &packet, iif, oif)
if err != nil {
return verdict, packet, err
}
if verdict == VerdictDrop {
return VerdictDrop, packet, &IPTableDropError{Trace: trace}
}
}
return VerdictAccept, packet, nil
}
func (nf *SimulateNetfilter) doIpt(table string) Handle {
return func(hook NFHook, packet *model.Packet, iif, oif string) (Verdict, Trace, error) {
klog.V(4).Infof("hook %d, table %s, input %s", hook, table, packet)
verdict, trace, err := nf.iptables.TracePacket(nf.ctx, hook, table, packet, iif, oif)
klog.V(4).Infof("hook %d, table %s, out %s, trace: %s", hook, table, packet, trace)
return verdict, trace, err
}
}
func (nf *SimulateNetfilter) initHandles() {
nf.handles = map[NFHook][]Handle{
NFHookPreRouting: {nf.doIpt("raw"), nf.doIpt("mangle"), nf.doIpt("nat")},
NFHookInput: {nf.doIpt("mangle"), nf.doIpt("nat"), nf.doIpt("filter")},
NFHookForward: {nf.doIpt("mangle"), nf.doIpt("filter")},
NFHookOutput: {nf.doIpt("raw"), nf.doIpt("mangle"), nf.doIpt("nat"), nf.doIpt("filter")},
NFHookPostRouting: {nf.doIpt("mangle"), nf.doIpt("nat")},
}
}
var _ Netfilter = &SimulateNetfilter{}