Skip to content

Commit

Permalink
Reject L3 skb more efficiently
Browse files Browse the repository at this point in the history
Introduced a key word `__pwru_reject_all__` to inject two simple ebpf
insns when pcap filter is an L2 filter such as `arp`

Also deleted a confusing and scary warning.

Signed-off-by: Zhichuan Liang <gray.liang@isovalent.com>
  • Loading branch information
jschwinger233 authored and brb committed Sep 28, 2023
1 parent 7849235 commit 088110f
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 18 deletions.
5 changes: 3 additions & 2 deletions internal/libpcap/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,11 @@ func CompileCbpf(expr string, l3 bool) (insts []bpf.Instruction, err error) {
return
}

pcap := C.pcap_open_dead(C.DLT_EN10MB, MAXIMUM_SNAPLEN)
pcapType := C.DLT_EN10MB
if l3 {
pcap = C.pcap_open_dead(C.DLT_RAW, MAXIMUM_SNAPLEN)
pcapType = C.DLT_RAW
}
pcap := C.pcap_open_dead(C.int(pcapType), MAXIMUM_SNAPLEN)
if pcap == nil {
return nil, fmt.Errorf("failed to pcap_open_dead: %+v\n", C.PCAP_ERROR)
}
Expand Down
38 changes: 22 additions & 16 deletions internal/libpcap/inject.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package libpcap

import (
"errors"
"fmt"

"github.com/cilium/ebpf"
"github.com/cilium/ebpf/asm"
Expand All @@ -17,8 +16,7 @@ func InjectFilters(program *ebpf.ProgramSpec, filterExpr string) (err error) {
// This could happen for l2 only filters such as "arp". In this
// case we don't want to exit with an error, but instead inject
// a deny-all filter to reject all l3 skbs.
fmt.Printf("L3 filter injection failed while L2 filter injection succeeded, injecting a deny-all L3 filter: %+v\n", err)
return injectFilter(program, "src host 0.0.0.0 and dst host 0.0.0.0 and tcp", true)
return injectFilter(program, "__pwru_reject_all__", true)
}
return
}
Expand All @@ -43,19 +41,27 @@ func injectFilter(program *ebpf.ProgramSpec, filterExpr string, l3 bool) (err er
return errors.New("Cannot find the injection position")
}

filterEbpf, err := CompileEbpf(filterExpr, cbpfc.EBPFOpts{
// The rejection position is in the beginning of the `filter_pcap_ebpf` function:
// filter_pcap_ebpf(void *_skb, void *__skb, void *___skb, void *data, void* data_end)
// So we can confidently say, skb->data is at r4, skb->data_end is at r5.
PacketStart: asm.R4,
PacketEnd: asm.R5,
Result: asm.R0,
ResultLabel: "result" + suffix,
// R0-R3 are also safe to use thanks to the placeholder parameters _skb, __skb, ___skb.
Working: [4]asm.Register{asm.R0, asm.R1, asm.R2, asm.R3},
LabelPrefix: "filter" + suffix,
StackOffset: -int(AvailableOffset),
}, l3)
var filterEbpf asm.Instructions
if filterExpr == "__pwru_reject_all__" {
// let data = data_end, so kprobe_pwru.c:filter_pcap_ebpf_l3() always returns false
filterEbpf = asm.Instructions{
asm.Mov.Reg(asm.R4, asm.R5), // r4 = r5 (data = data_end)
}
} else {
filterEbpf, err = CompileEbpf(filterExpr, cbpfc.EBPFOpts{
// The rejection position is in the beginning of the `filter_pcap_ebpf` function:
// filter_pcap_ebpf(void *_skb, void *__skb, void *___skb, void *data, void* data_end)
// So we can confidently say, skb->data is at r4, skb->data_end is at r5.
PacketStart: asm.R4,
PacketEnd: asm.R5,
Result: asm.R0,
ResultLabel: "result" + suffix,
// R0-R3 are also safe to use thanks to the placeholder parameters _skb, __skb, ___skb.
Working: [4]asm.Register{asm.R0, asm.R1, asm.R2, asm.R3},
LabelPrefix: "filter" + suffix,
StackOffset: -int(AvailableOffset),
}, l3)
}
if err != nil {
return
}
Expand Down

0 comments on commit 088110f

Please sign in to comment.