From 666ecc580f55e7f6230a157cfc914b38832ca701 Mon Sep 17 00:00:00 2001 From: Zoltan Papp Date: Mon, 14 Aug 2023 17:22:02 +0200 Subject: [PATCH] Add singleton eBPF loader --- client/internal/dns/forwarder/bpf_bpfeb.go | 123 ------------------ client/internal/dns/forwarder/bpf_bpfeb.o | Bin 6704 -> 0 bytes client/internal/dns/forwarder/bpf_bpfel.go | 123 ------------------ client/internal/dns/forwarder/bpf_bpfel.o | Bin 6704 -> 0 bytes client/internal/dns/forwarder/src/port_fwd.c | 100 -------------- .../dns/forwarder/traffic_forwarder.go | 89 ------------- client/internal/dns/service_listener.go | 11 +- .../internal/{wgproxy => }/ebpf/bpf_bpfeb.go | 15 ++- client/internal/ebpf/bpf_bpfeb.o | Bin 0 -> 15960 bytes .../internal/{wgproxy => }/ebpf/bpf_bpfel.go | 15 ++- client/internal/ebpf/bpf_bpfel.o | Bin 0 -> 15960 bytes client/internal/ebpf/dns_fwd.go | 51 ++++++++ client/internal/ebpf/loader.go | 104 +++++++++++++++ client/internal/ebpf/loader_test.go | 40 ++++++ client/internal/ebpf/src/dns_fwd.c | 64 +++++++++ client/internal/ebpf/src/prog.c | 66 ++++++++++ client/internal/ebpf/src/wg_proxy.c | 54 ++++++++ client/internal/ebpf/wg_proxy.go | 41 ++++++ client/internal/wgproxy/ebpf/bpf_bpfeb.o | Bin 6264 -> 0 bytes client/internal/wgproxy/ebpf/bpf_bpfel.o | Bin 6264 -> 0 bytes client/internal/wgproxy/ebpf/loader.go | 84 ------------ client/internal/wgproxy/ebpf/loader_test.go | 18 --- .../internal/wgproxy/ebpf/src/portreplace.c | 90 ------------- client/internal/wgproxy/proxy_ebpf.go | 11 +- go.mod | 1 - go.sum | 19 ++- 26 files changed, 472 insertions(+), 647 deletions(-) delete mode 100644 client/internal/dns/forwarder/bpf_bpfeb.go delete mode 100644 client/internal/dns/forwarder/bpf_bpfeb.o delete mode 100644 client/internal/dns/forwarder/bpf_bpfel.go delete mode 100644 client/internal/dns/forwarder/bpf_bpfel.o delete mode 100644 client/internal/dns/forwarder/src/port_fwd.c delete mode 100644 client/internal/dns/forwarder/traffic_forwarder.go rename client/internal/{wgproxy => }/ebpf/bpf_bpfeb.go (84%) create mode 100644 client/internal/ebpf/bpf_bpfeb.o rename client/internal/{wgproxy => }/ebpf/bpf_bpfel.go (84%) create mode 100644 client/internal/ebpf/bpf_bpfel.o create mode 100644 client/internal/ebpf/dns_fwd.go create mode 100644 client/internal/ebpf/loader.go create mode 100644 client/internal/ebpf/loader_test.go create mode 100644 client/internal/ebpf/src/dns_fwd.c create mode 100644 client/internal/ebpf/src/prog.c create mode 100644 client/internal/ebpf/src/wg_proxy.c create mode 100644 client/internal/ebpf/wg_proxy.go delete mode 100644 client/internal/wgproxy/ebpf/bpf_bpfeb.o delete mode 100644 client/internal/wgproxy/ebpf/bpf_bpfel.o delete mode 100644 client/internal/wgproxy/ebpf/loader.go delete mode 100644 client/internal/wgproxy/ebpf/loader_test.go delete mode 100644 client/internal/wgproxy/ebpf/src/portreplace.c diff --git a/client/internal/dns/forwarder/bpf_bpfeb.go b/client/internal/dns/forwarder/bpf_bpfeb.go deleted file mode 100644 index 9ab731d9b..000000000 --- a/client/internal/dns/forwarder/bpf_bpfeb.go +++ /dev/null @@ -1,123 +0,0 @@ -// Code generated by bpf2go; DO NOT EDIT. -//go:build arm64be || armbe || mips || mips64 || mips64p32 || ppc64 || s390 || s390x || sparc || sparc64 -// +build arm64be armbe mips mips64 mips64p32 ppc64 s390 s390x sparc sparc64 - -package forwarder - -import ( - "bytes" - _ "embed" - "fmt" - "io" - - "github.com/cilium/ebpf" -) - -// loadBpf returns the embedded CollectionSpec for bpf. -func loadBpf() (*ebpf.CollectionSpec, error) { - reader := bytes.NewReader(_BpfBytes) - spec, err := ebpf.LoadCollectionSpecFromReader(reader) - if err != nil { - return nil, fmt.Errorf("can't load bpf: %w", err) - } - - return spec, err -} - -// loadBpfObjects loads bpf and converts it into a struct. -// -// The following types are suitable as obj argument: -// -// *bpfObjects -// *bpfPrograms -// *bpfMaps -// -// See ebpf.CollectionSpec.LoadAndAssign documentation for details. -func loadBpfObjects(obj interface{}, opts *ebpf.CollectionOptions) error { - spec, err := loadBpf() - if err != nil { - return err - } - - return spec.LoadAndAssign(obj, opts) -} - -// bpfSpecs contains maps and programs before they are loaded into the kernel. -// -// It can be passed ebpf.CollectionSpec.Assign. -type bpfSpecs struct { - bpfProgramSpecs - bpfMapSpecs -} - -// bpfSpecs contains programs before they are loaded into the kernel. -// -// It can be passed ebpf.CollectionSpec.Assign. -type bpfProgramSpecs struct { - XdpDnsPortFwd *ebpf.ProgramSpec `ebpf:"xdp_dns_port_fwd"` -} - -// bpfMapSpecs contains maps before they are loaded into the kernel. -// -// It can be passed ebpf.CollectionSpec.Assign. -type bpfMapSpecs struct { - XdpIpMap *ebpf.MapSpec `ebpf:"xdp_ip_map"` - XdpPortMap *ebpf.MapSpec `ebpf:"xdp_port_map"` -} - -// bpfObjects contains all objects after they have been loaded into the kernel. -// -// It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign. -type bpfObjects struct { - bpfPrograms - bpfMaps -} - -func (o *bpfObjects) Close() error { - return _BpfClose( - &o.bpfPrograms, - &o.bpfMaps, - ) -} - -// bpfMaps contains all maps after they have been loaded into the kernel. -// -// It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign. -type bpfMaps struct { - XdpIpMap *ebpf.Map `ebpf:"xdp_ip_map"` - XdpPortMap *ebpf.Map `ebpf:"xdp_port_map"` -} - -func (m *bpfMaps) Close() error { - return _BpfClose( - m.XdpIpMap, - m.XdpPortMap, - ) -} - -// bpfPrograms contains all programs after they have been loaded into the kernel. -// -// It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign. -type bpfPrograms struct { - XdpDnsPortFwd *ebpf.Program `ebpf:"xdp_dns_port_fwd"` -} - -func (p *bpfPrograms) Close() error { - return _BpfClose( - p.XdpDnsPortFwd, - ) -} - -func _BpfClose(closers ...io.Closer) error { - for _, closer := range closers { - if err := closer.Close(); err != nil { - return err - } - } - return nil -} - -// Do not access this directly. -// -//go:embed bpf_bpfeb.o -var _BpfBytes []byte diff --git a/client/internal/dns/forwarder/bpf_bpfeb.o b/client/internal/dns/forwarder/bpf_bpfeb.o deleted file mode 100644 index f18f85af73610b5b48343a3fda87f8718c2fe490..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6704 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 QxmFMd4vb~<^ZrNrFTxKM>Hq)$ diff --git a/client/internal/dns/forwarder/src/port_fwd.c b/client/internal/dns/forwarder/src/port_fwd.c deleted file mode 100644 index d8edcd830..000000000 --- a/client/internal/dns/forwarder/src/port_fwd.c +++ /dev/null @@ -1,100 +0,0 @@ -#include -#include // ETH_P_IP -#include -#include -#include -#include -#include - -#define bpf_printk(fmt, ...) \ - ({ \ - char ____fmt[] = fmt; \ - bpf_trace_printk(____fmt, sizeof(____fmt), ##__VA_ARGS__); \ - }) - -const __u32 map_key_dns_ip = 0; -const __u32 map_key_dns_port = 1; - -struct bpf_map_def SEC("maps") xdp_ip_map = { - .type = BPF_MAP_TYPE_ARRAY, - .key_size = sizeof(__u32), - .value_size = sizeof(__u32), - .max_entries = 10, -}; - -struct bpf_map_def SEC("maps") xdp_port_map = { - .type = BPF_MAP_TYPE_ARRAY, - .key_size = sizeof(__u32), - .value_size = sizeof(__u16), - .max_entries = 10, -}; - -__be32 dns_ip = 0; -__be16 dns_port = 0; - -// 13568 is 53 in big endian -__be16 GENERAL_DNS_PORT = 13568; - -bool read_settings() { - __u16 *port_value; - __u32 *ip_value; - - // read dns ip - ip_value = bpf_map_lookup_elem(&xdp_ip_map, &map_key_dns_ip); - if(!ip_value) { - return false; - } - dns_ip = htonl(*ip_value); - - // read dns port - port_value = bpf_map_lookup_elem(&xdp_port_map, &map_key_dns_port); - if(!port_value) { - return false; - } - dns_port = htons(*port_value); - return true; -} - -SEC("xdp") -int xdp_dns_port_fwd(struct xdp_md *ctx) { - if(dns_port == 0) { - if(!read_settings()){ - return XDP_PASS; - } - bpf_printk("dns port: %d", ntohs(dns_port)); - bpf_printk("dns ip: %d", ntohl(dns_ip)); - } - - void *data = (void *)(long)ctx->data; - void *data_end = (void *)(long)ctx->data_end; - struct ethhdr *eth = data; - struct iphdr *ip = (data + sizeof(struct ethhdr)); - struct udphdr *udp = (data + sizeof(struct ethhdr) + sizeof(struct iphdr)); - - // return early if not enough data - if (data + sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr) > data_end){ - return XDP_PASS; - } - - // skip non IPv4 packages - if (eth->h_proto != htons(ETH_P_IP)) { - return XDP_PASS; - } - - if (ip->protocol != IPPROTO_UDP) { - return XDP_PASS; - } - - if (ip->daddr != dns_ip) { - return XDP_PASS; - } - - // skip non dns ports - if (udp->dest != GENERAL_DNS_PORT){ - return XDP_PASS; - } - - udp->dest = dns_port; - return XDP_PASS; -} -char _license[] SEC("license") = "GPL"; \ No newline at end of file diff --git a/client/internal/dns/forwarder/traffic_forwarder.go b/client/internal/dns/forwarder/traffic_forwarder.go deleted file mode 100644 index 46f940743..000000000 --- a/client/internal/dns/forwarder/traffic_forwarder.go +++ /dev/null @@ -1,89 +0,0 @@ -package forwarder - -import ( - _ "embed" - "encoding/binary" - "net" - - "github.com/cilium/ebpf/link" - "github.com/cilium/ebpf/rlimit" - log "github.com/sirupsen/logrus" -) - -const ( - mapKeyDNSIP uint32 = 0 - mapKeyDNSPort uint32 = 1 -) - -// libbpf-dev, libc6-dev-i386-amd64-cross -// -//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cc clang-14 bpf src/port_fwd.c -- -I /usr/x86_64-linux-gnu/include -type TrafficForwarder struct { - link link.Link - iFaceName string -} - -func NewTrafficForwarder(iFace string) *TrafficForwarder { - return &TrafficForwarder{ - iFaceName: iFace, - } -} - -func (tf *TrafficForwarder) Start(ip string, dnsPort int) error { - log.Debugf("start DNS port forwarder") - // it required for Docker - err := rlimit.RemoveMemlock() - if err != nil { - return err - } - - iFace, err := net.InterfaceByName(tf.iFaceName) - if err != nil { - return err - } - - // load pre-compiled programs into the kernel. - objs := bpfObjects{} - err = loadBpfObjects(&objs, nil) - if err != nil { - return err - } - defer func() { - _ = objs.Close() - }() - - err = objs.XdpIpMap.Put(mapKeyDNSIP, tf.ip2int(ip)) - if err != nil { - return err - } - - err = objs.XdpPortMap.Put(mapKeyDNSPort, uint16(dnsPort)) - if err != nil { - return err - } - - defer func() { - _ = objs.XdpPortMap.Close() - }() - - tf.link, err = link.AttachXDP(link.XDPOptions{ - Program: objs.XdpDnsPortFwd, - Interface: iFace.Index, - }) - return err -} - -func (tf *TrafficForwarder) Free() error { - if tf.link == nil { - return nil - } - - err := tf.link.Close() - tf.link = nil - return err -} - -func (tf *TrafficForwarder) ip2int(ipString string) uint32 { - ip := net.ParseIP(ipString) - return binary.BigEndian.Uint32(ip.To4()) -} diff --git a/client/internal/dns/service_listener.go b/client/internal/dns/service_listener.go index 21777520f..fde729cb6 100644 --- a/client/internal/dns/service_listener.go +++ b/client/internal/dns/service_listener.go @@ -3,7 +3,6 @@ package dns import ( "context" "fmt" - "github.com/netbirdio/netbird/client/internal/dns/forwarder" "net" "net/netip" "runtime" @@ -12,6 +11,8 @@ import ( "github.com/miekg/dns" log "github.com/sirupsen/logrus" + + "github.com/netbirdio/netbird/client/internal/ebpf" ) const ( @@ -29,7 +30,7 @@ type serviceViaListener struct { runtimePort int listenerIsRunning bool listenerFlagLock sync.Mutex - trafficForwarder *forwarder.TrafficForwarder + ebpfService *ebpf.Manager } func newServiceViaListener(wgIface WGIface, customAddr *netip.AddrPort) *serviceViaListener { @@ -44,7 +45,7 @@ func newServiceViaListener(wgIface WGIface, customAddr *netip.AddrPort) *service Handler: mux, UDPSize: 65535, }, - trafficForwarder: forwarder.NewTrafficForwarder(wgIface.Name()), + ebpfService: ebpf.GetEbpfManagerInstance(), } return s } @@ -77,7 +78,7 @@ func (s *serviceViaListener) Listen() error { }() if s.runtimePort != defaultPort { - err = s.trafficForwarder.Start(s.runtimeIP, s.runtimePort) + err = s.ebpfService.LoadDNSFwd(s.runtimeIP, s.runtimePort) if err != nil { return err } @@ -101,7 +102,7 @@ func (s *serviceViaListener) Stop() { log.Errorf("stopping dns server listener returned an error: %v", err) } - err = s.trafficForwarder.Free() + err = s.ebpfService.FreeDNSFwd() if err != nil { log.Errorf("stopping traffic forwarder returned an error: %v", err) } diff --git a/client/internal/wgproxy/ebpf/bpf_bpfeb.go b/client/internal/ebpf/bpf_bpfeb.go similarity index 84% rename from client/internal/wgproxy/ebpf/bpf_bpfeb.go rename to client/internal/ebpf/bpf_bpfeb.go index c4875c3ae..5d2765862 100644 --- a/client/internal/wgproxy/ebpf/bpf_bpfeb.go +++ b/client/internal/ebpf/bpf_bpfeb.go @@ -54,13 +54,16 @@ type bpfSpecs struct { // // It can be passed ebpf.CollectionSpec.Assign. type bpfProgramSpecs struct { - NbWgProxy *ebpf.ProgramSpec `ebpf:"nb_wg_proxy"` + NbXdpProg *ebpf.ProgramSpec `ebpf:"nb_xdp_prog"` } // bpfMapSpecs contains maps before they are loaded into the kernel. // // It can be passed ebpf.CollectionSpec.Assign. type bpfMapSpecs struct { + NbFeatures *ebpf.MapSpec `ebpf:"nb_features"` + NbMapDnsIp *ebpf.MapSpec `ebpf:"nb_map_dns_ip"` + NbMapDnsPort *ebpf.MapSpec `ebpf:"nb_map_dns_port"` NbWgProxySettingsMap *ebpf.MapSpec `ebpf:"nb_wg_proxy_settings_map"` } @@ -83,11 +86,17 @@ func (o *bpfObjects) Close() error { // // It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign. type bpfMaps struct { + NbFeatures *ebpf.Map `ebpf:"nb_features"` + NbMapDnsIp *ebpf.Map `ebpf:"nb_map_dns_ip"` + NbMapDnsPort *ebpf.Map `ebpf:"nb_map_dns_port"` NbWgProxySettingsMap *ebpf.Map `ebpf:"nb_wg_proxy_settings_map"` } func (m *bpfMaps) Close() error { return _BpfClose( + m.NbFeatures, + m.NbMapDnsIp, + m.NbMapDnsPort, m.NbWgProxySettingsMap, ) } @@ -96,12 +105,12 @@ func (m *bpfMaps) Close() error { // // It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign. type bpfPrograms struct { - NbWgProxy *ebpf.Program `ebpf:"nb_wg_proxy"` + NbXdpProg *ebpf.Program `ebpf:"nb_xdp_prog"` } func (p *bpfPrograms) Close() error { return _BpfClose( - p.NbWgProxy, + p.NbXdpProg, ) } diff --git a/client/internal/ebpf/bpf_bpfeb.o b/client/internal/ebpf/bpf_bpfeb.o new file mode 100644 index 0000000000000000000000000000000000000000..0559da486ebeb13a7f0dbf21ed0d3bf4d40e76c3 GIT binary patch literal 15960 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 literal 0 HcmV?d00001 diff --git a/client/internal/ebpf/dns_fwd.go b/client/internal/ebpf/dns_fwd.go new file mode 100644 index 000000000..c534ab953 --- /dev/null +++ b/client/internal/ebpf/dns_fwd.go @@ -0,0 +1,51 @@ +package ebpf + +import ( + "encoding/binary" + "net" + + log "github.com/sirupsen/logrus" +) + +const ( + mapKeyDNSIP uint32 = 0 + mapKeyDNSPort uint32 = 1 +) + +func (tf *Manager) LoadDNSFwd(ip string, dnsPort int) error { + log.Debugf("load ebpf DNS forwarder: address: %s:%d", ip, dnsPort) + tf.lock.Lock() + defer tf.lock.Unlock() + + err := tf.loadXdp() + if err != nil { + return err + } + + err = tf.bpfObjs.NbMapDnsIp.Put(mapKeyDNSIP, ip2int(ip)) + if err != nil { + return err + } + + err = tf.bpfObjs.NbMapDnsPort.Put(mapKeyDNSPort, uint16(dnsPort)) + if err != nil { + return err + } + + tf.setFeatureFlag(featureFlagDnsForwarder) + err = tf.bpfObjs.NbFeatures.Put(mapKeyFeatures, tf.featureFlags) + if err != nil { + return err + } + return nil +} + +func (tf *Manager) FreeDNSFwd() error { + log.Debugf("free ebpf DNS forwarder") + return tf.unsetFeatureFlag(featureFlagDnsForwarder) +} + +func ip2int(ipString string) uint32 { + ip := net.ParseIP(ipString) + return binary.BigEndian.Uint32(ip.To4()) +} diff --git a/client/internal/ebpf/loader.go b/client/internal/ebpf/loader.go new file mode 100644 index 000000000..d96ae4795 --- /dev/null +++ b/client/internal/ebpf/loader.go @@ -0,0 +1,104 @@ +package ebpf + +import ( + _ "embed" + "net" + "sync" + + "github.com/cilium/ebpf/link" + "github.com/cilium/ebpf/rlimit" + log "github.com/sirupsen/logrus" +) + +const ( + mapKeyFeatures uint32 = 0 + + featureFlagWGProxy = 0b00000001 + featureFlagDnsForwarder = 0b00000010 +) + +var ( + singleton *Manager + singletonLock = &sync.Mutex{} +) + +// libbpf-dev, libc6-dev-i386-amd64-cross + +//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cc clang-14 bpf src/prog.c -- -I /usr/x86_64-linux-gnu/include +type Manager struct { + lock sync.Mutex + link link.Link + featureFlags uint16 + bpfObjs bpfObjects +} + +// GetEbpfManagerInstance return a static eBpf Manager instance +func GetEbpfManagerInstance() *Manager { + singletonLock.Lock() + defer singletonLock.Unlock() + if singleton != nil { + return singleton + } + singleton = &Manager{} + return singleton +} + +func (tf *Manager) setFeatureFlag(feature uint16) { + tf.featureFlags = tf.featureFlags | feature +} + +func (tf *Manager) loadXdp() error { + if tf.link != nil { + return nil + } + // it required for Docker + err := rlimit.RemoveMemlock() + if err != nil { + return err + } + + iFace, err := net.InterfaceByName("lo") + if err != nil { + return err + } + + // load pre-compiled programs into the kernel. + err = loadBpfObjects(&tf.bpfObjs, nil) + if err != nil { + return err + } + + tf.link, err = link.AttachXDP(link.XDPOptions{ + Program: tf.bpfObjs.NbXdpProg, + Interface: iFace.Index, + }) + return err +} + +func (tf *Manager) unsetFeatureFlag(feature uint16) error { + tf.lock.Lock() + defer tf.lock.Unlock() + tf.featureFlags &^= feature + + if tf.link == nil { + return nil + } + + if tf.featureFlags == 0 { + return tf.close() + } + + return tf.bpfObjs.NbFeatures.Put(mapKeyFeatures, tf.featureFlags) +} + +func (tf *Manager) close() error { + log.Debugf("detach ebpf program ") + err := tf.bpfObjs.Close() + if err != nil { + log.Warnf("failed to close eBpf objects: %s", err) + } + + err = tf.link.Close() + tf.link = nil + return err +} diff --git a/client/internal/ebpf/loader_test.go b/client/internal/ebpf/loader_test.go new file mode 100644 index 000000000..b63a9b6f8 --- /dev/null +++ b/client/internal/ebpf/loader_test.go @@ -0,0 +1,40 @@ +package ebpf + +import ( + "testing" +) + +func TestManager_setFeatureFlag(t *testing.T) { + mgr := Manager{} + mgr.setFeatureFlag(featureFlagWGProxy) + if mgr.featureFlags != 1 { + t.Errorf("invalid faeture state") + } + + mgr.setFeatureFlag(featureFlagDnsForwarder) + if mgr.featureFlags != 3 { + t.Errorf("invalid faeture state") + } +} + +func TestManager_unsetFeatureFlag(t *testing.T) { + mgr := Manager{} + mgr.setFeatureFlag(featureFlagWGProxy) + mgr.setFeatureFlag(featureFlagDnsForwarder) + + err := mgr.unsetFeatureFlag(featureFlagWGProxy) + if err != nil { + t.Errorf("unexpected error: %s", err) + } + if mgr.featureFlags != 2 { + t.Errorf("invalid faeture state, expected: %d, got: %d", 2, mgr.featureFlags) + } + + err = mgr.unsetFeatureFlag(featureFlagDnsForwarder) + if err != nil { + t.Errorf("unexpected error: %s", err) + } + if mgr.featureFlags != 0 { + t.Errorf("invalid faeture state, expected: %d, got: %d", 0, mgr.featureFlags) + } +} diff --git a/client/internal/ebpf/src/dns_fwd.c b/client/internal/ebpf/src/dns_fwd.c new file mode 100644 index 000000000..5228c7e75 --- /dev/null +++ b/client/internal/ebpf/src/dns_fwd.c @@ -0,0 +1,64 @@ +const __u32 map_key_dns_ip = 0; +const __u32 map_key_dns_port = 1; + +struct bpf_map_def SEC("maps") nb_map_dns_ip = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(__u32), + .max_entries = 10, +}; + +struct bpf_map_def SEC("maps") nb_map_dns_port = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(__u16), + .max_entries = 10, +}; + +__be32 dns_ip = 0; +__be16 dns_port = 0; + +// 13568 is 53 in big endian +__be16 GENERAL_DNS_PORT = 13568; + +bool read_settings() { + __u16 *port_value; + __u32 *ip_value; + + // read dns ip + ip_value = bpf_map_lookup_elem(&nb_map_dns_ip, &map_key_dns_ip); + if(!ip_value) { + return false; + } + dns_ip = htonl(*ip_value); + + // read dns port + port_value = bpf_map_lookup_elem(&nb_map_dns_port, &map_key_dns_port); + if (!port_value) { + return false; + } + dns_port = htons(*port_value); + return true; +} + +int xdp_dns_fwd(struct iphdr *ip, struct udphdr *udp) { + if (dns_port == 0) { + if(!read_settings()){ + return XDP_PASS; + } + bpf_printk("dns port: %d", ntohs(dns_port)); + bpf_printk("dns ip: %d", ntohl(dns_ip)); + } + + if (udp->dest == GENERAL_DNS_PORT && ip->daddr == dns_ip) { + udp->dest = dns_port; + return XDP_PASS; + } + + if (udp->source == dns_port && ip->saddr == dns_ip) { + udp->source = GENERAL_DNS_PORT; + return XDP_PASS; + } + + return XDP_PASS; +} \ No newline at end of file diff --git a/client/internal/ebpf/src/prog.c b/client/internal/ebpf/src/prog.c new file mode 100644 index 000000000..09b649370 --- /dev/null +++ b/client/internal/ebpf/src/prog.c @@ -0,0 +1,66 @@ +#include +#include // ETH_P_IP +#include +#include +#include +#include +#include +#include "dns_fwd.c" +#include "wg_proxy.c" + +#define bpf_printk(fmt, ...) \ + ({ \ + char ____fmt[] = fmt; \ + bpf_trace_printk(____fmt, sizeof(____fmt), ##__VA_ARGS__); \ + }) + +const __u16 flag_feature_wg_proxy = 0b01; +const __u16 flag_feature_dns_fwd = 0b10; + +const __u32 map_key_features = 0; +struct bpf_map_def SEC("maps") nb_features = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(__u16), + .max_entries = 10, +}; + +SEC("xdp") +int nb_xdp_prog(struct xdp_md *ctx) { + __u16 *features; + features = bpf_map_lookup_elem(&nb_features, &map_key_features); + if (!features) { + return XDP_PASS; + } + + void *data = (void *)(long)ctx->data; + void *data_end = (void *)(long)ctx->data_end; + struct ethhdr *eth = data; + struct iphdr *ip = (data + sizeof(struct ethhdr)); + struct udphdr *udp = (data + sizeof(struct ethhdr) + sizeof(struct iphdr)); + + // return early if not enough data + if (data + sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr) > data_end){ + return XDP_PASS; + } + + // skip non IPv4 packages + if (eth->h_proto != htons(ETH_P_IP)) { + return XDP_PASS; + } + + // skip non UPD packages + if (ip->protocol != IPPROTO_UDP) { + return XDP_PASS; + } + + if (*features & flag_feature_dns_fwd) { + xdp_dns_fwd(ip, udp); + } + + if (*features & flag_feature_wg_proxy) { + xdp_wg_proxy(ip, udp); + } + return XDP_PASS; +} +char _license[] SEC("license") = "GPL"; \ No newline at end of file diff --git a/client/internal/ebpf/src/wg_proxy.c b/client/internal/ebpf/src/wg_proxy.c new file mode 100644 index 000000000..ecfedc6b3 --- /dev/null +++ b/client/internal/ebpf/src/wg_proxy.c @@ -0,0 +1,54 @@ +const __u32 map_key_proxy_port = 0; +const __u32 map_key_wg_port = 1; + +struct bpf_map_def SEC("maps") nb_wg_proxy_settings_map = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(__u16), + .max_entries = 10, +}; + +__u16 proxy_port = 0; +__u16 wg_port = 0; + +bool read_port_settings() { + __u16 *value; + value = bpf_map_lookup_elem(&nb_wg_proxy_settings_map, &map_key_proxy_port); + if (!value) { + return false; + } + + proxy_port = *value; + + value = bpf_map_lookup_elem(&nb_wg_proxy_settings_map, &map_key_wg_port); + if (!value) { + return false; + } + wg_port = htons(*value); + + return true; +} + +int xdp_wg_proxy(struct iphdr *ip, struct udphdr *udp) { + if (proxy_port == 0 || wg_port == 0) { + if (!read_port_settings()){ + return XDP_PASS; + } + bpf_printk("proxy port: %d, wg port: %d", proxy_port, wg_port); + } + + // 2130706433 = 127.0.0.1 + if (ip->daddr != htonl(2130706433)) { + return XDP_PASS; + } + + if (udp->source != wg_port){ + return XDP_PASS; + } + + __be16 new_src_port = udp->dest; + __be16 new_dst_port = htons(proxy_port); + udp->dest = new_dst_port; + udp->source = new_src_port; + return XDP_PASS; +} \ No newline at end of file diff --git a/client/internal/ebpf/wg_proxy.go b/client/internal/ebpf/wg_proxy.go new file mode 100644 index 000000000..242cfa0e7 --- /dev/null +++ b/client/internal/ebpf/wg_proxy.go @@ -0,0 +1,41 @@ +package ebpf + +import log "github.com/sirupsen/logrus" + +const ( + mapKeyProxyPort uint32 = 0 + mapKeyWgPort uint32 = 1 +) + +func (tf *Manager) LoadWgProxy(proxyPort, wgPort int) error { + log.Debugf("load ebpf WG proxy") + tf.lock.Lock() + defer tf.lock.Unlock() + + err := tf.loadXdp() + if err != nil { + return err + } + + err = tf.bpfObjs.NbWgProxySettingsMap.Put(mapKeyProxyPort, uint16(proxyPort)) + if err != nil { + return err + } + + err = tf.bpfObjs.NbWgProxySettingsMap.Put(mapKeyWgPort, uint16(wgPort)) + if err != nil { + return err + } + + tf.setFeatureFlag(featureFlagWGProxy) + err = tf.bpfObjs.NbFeatures.Put(mapKeyFeatures, tf.featureFlags) + if err != nil { + return err + } + return nil +} + +func (tf *Manager) FreeWGProxy() error { + log.Debugf("free ebpf WG proxy") + return tf.unsetFeatureFlag(featureFlagWGProxy) +} diff --git a/client/internal/wgproxy/ebpf/bpf_bpfeb.o b/client/internal/wgproxy/ebpf/bpf_bpfeb.o deleted file mode 100644 index 82d7fc35b4c64f55f312a2f8c963a72e40cec6b7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6264 zcmb_gU2K$D89v{1c42>T3kA1PVonioicmW33RNu5;<8(k8oF#rSjBuyJ6}7KPG^Rh zDGV+fdf_G**95bx>4k}G!Uc&YV%7vMH1xs?61^a1HDsen;}zw@CdPw8v;mKx`i|C@1f&D(dYvbo_YvyKCAb*e&O$l$MGleqq|R9|39*wx|?4=UTLf4@90)(QsH=< z{B*b4y`DUrm&*gj`(^64=U*f0w7K(^4&!}-zk{?W<<_^G+iv-{k#D`Hpr+qjeMAoZ zSL@BMkiIypYj3=_`jO-BDeTvzA=cnObo@)YRwZ4lS6kq(kS-nOTdBLBvHd3aU0q#W zxvdS}Df50Zzt`q5|7ojtH!J#srr&p9NEylbKDC9M^I7#Q`&ldBd~%3LsndgsE3+AT z&l{}Ge%hMvQ=b#O1)KLusZZ@9?zQ$LO)CxC{sYVJ{`Tk9CUV03mW(y#m$mCV*JJ&C zppAX^+&0U^$_D{h8?HN2! zO@AT4hvAIp9J@LFb@XPv4zQ6X&f&M52=MpqcmGd3c6Hj zs_AA6PMXTg6JwI6Jzl2KtS?MAwH=P$2Q!x(WXsRbs26E2@!`*p`DuO*kKr!G`W1-*~?U@DNSjOFxa%GJtjKL&Q-sFNO1o;ss%tnOA` zXK1Xys2ip4B-I%=@1$8Q7V7;UozENFl zRx6Fn@yW4xB0e$E@3KYJQtiM|qc>eGQ}x8e#Ho{$C*#vEO@wNNe4$Wx?#h{=?C{{> z!9y<$53g~EfgL#7s4mo}6Q|qAxa`Up<9I5`9@3TMVq9o6Wf^6Zokfwe;wj^FI%N~4 zkTjY$t$x%|+of4A zB@N?XrkuyU;%)FXmxIDV$sXz)ltvMU)P5_?3{jrge!7^iL;1y1r(S$Le(l6JkH?d* zPaKb96_-oXNu`mffvE=WuX>gHKshF6)llx+s^$LMjUG?x2A+Gu;~mZ_#@(T~&ZF;n zn4c?t3#fx{oM{?wd^cPCJhP%8M#*!TzD5N9SgE&pujf2WKW7C0LaBFYzbF{?OSHc# z_&-YB;Jtm#!_>cJafI*0EsWWWRfET-fq$UXuSwGv@%u_G3*E-7HO8#GJ&&4TH;OO0S36Y~?izH8Nc@a#Fb=#xV%3jE8 zf+v;wGqH>}bw#O1qrg{1PE7yT1h1&*S$vA4TOOwTj>TQiplrhUqGbz7Cc`cy{npHy@fbxLYP z@V}56?2A;+V(f#c5P{yXVMDt*!`JyOfa5b4?FRjH8+3@@fpq+_4qN@E!;gv{{|_C0 zD(CTE#i4L<9eWu>8IzRy&aqkdsomg94cq2(9Q(m%4*f>Ihdq5aUiM$}^j&=R5ys>6 z#8+wp#5>TJQdQV%^%&dby&E*vw2gD1Y3t-?K>Pa4lhnMR>=|c$=k%%T+h>4%`4}*D zoId^g@fU%8`z2ss|0b{>pL^N!Z}zT-&0h8VrI;^b$yRo85?cy)rHSY8 zI55j$r(Xcg@d;M@L33^ne-$)s9p?J@@^b;M1$Z&Q*8+S!z_$Xt9N_x_ehBQ3@6lQu zac-VG>J2dS<;zC`JQmts z=e4;*n%~a6o7i&Z-F`hcBIG&r-FV!0!r7Bo#N);j#CL4-{eW7#IeRjA*KHJ^`;zTC z9>#L_owFzJ=XlzIKzprgLV(kEGUtbwcdxS#)}iZ+81TF6H{bph2%P`WzAQ$*K3Oi0 zq(8*t;t!G0X-R?-GUBdvCd}mp9|X0-wj}YJw4Se_bo7WAZ=Vd=i>MN7mSVPZ~y=R diff --git a/client/internal/wgproxy/ebpf/bpf_bpfel.o b/client/internal/wgproxy/ebpf/bpf_bpfel.o deleted file mode 100644 index 2fc0ff8fca8b8aa1a6bfd2b6f7079195dfd478c6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6264 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 diff --git a/client/internal/wgproxy/ebpf/loader.go b/client/internal/wgproxy/ebpf/loader.go deleted file mode 100644 index e154c0d9e..000000000 --- a/client/internal/wgproxy/ebpf/loader.go +++ /dev/null @@ -1,84 +0,0 @@ -//go:build linux && !android - -package ebpf - -import ( - _ "embed" - "net" - - "github.com/cilium/ebpf/link" - "github.com/cilium/ebpf/rlimit" -) - -const ( - mapKeyProxyPort uint32 = 0 - mapKeyWgPort uint32 = 1 -) - -//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cc clang-14 bpf src/portreplace.c -- - -// EBPF is a wrapper for eBPF program -type EBPF struct { - link link.Link -} - -// NewEBPF create new EBPF instance -func NewEBPF() *EBPF { - return &EBPF{} -} - -// Load load ebpf program -func (l *EBPF) Load(proxyPort, wgPort int) error { - // it required for Docker - err := rlimit.RemoveMemlock() - if err != nil { - return err - } - - ifce, err := net.InterfaceByName("lo") - if err != nil { - return err - } - - // Load pre-compiled programs into the kernel. - objs := bpfObjects{} - err = loadBpfObjects(&objs, nil) - if err != nil { - return err - } - defer func() { - _ = objs.Close() - }() - - err = objs.NbWgProxySettingsMap.Put(mapKeyProxyPort, uint16(proxyPort)) - if err != nil { - return err - } - - err = objs.NbWgProxySettingsMap.Put(mapKeyWgPort, uint16(wgPort)) - if err != nil { - return err - } - - defer func() { - _ = objs.NbWgProxySettingsMap.Close() - }() - - l.link, err = link.AttachXDP(link.XDPOptions{ - Program: objs.NbWgProxy, - Interface: ifce.Index, - }) - if err != nil { - return err - } - - return err -} - -// Free ebpf program -func (l *EBPF) Free() error { - if l.link != nil { - return l.link.Close() - } - return nil -} diff --git a/client/internal/wgproxy/ebpf/loader_test.go b/client/internal/wgproxy/ebpf/loader_test.go deleted file mode 100644 index 6ce323e70..000000000 --- a/client/internal/wgproxy/ebpf/loader_test.go +++ /dev/null @@ -1,18 +0,0 @@ -//go:build linux - -package ebpf - -import ( - "testing" -) - -func Test_newEBPF(t *testing.T) { - ebpf := NewEBPF() - err := ebpf.Load(1234, 51892) - defer func() { - _ = ebpf.Free() - }() - if err != nil { - t.Errorf("%s", err) - } -} diff --git a/client/internal/wgproxy/ebpf/src/portreplace.c b/client/internal/wgproxy/ebpf/src/portreplace.c deleted file mode 100644 index dc95ee53f..000000000 --- a/client/internal/wgproxy/ebpf/src/portreplace.c +++ /dev/null @@ -1,90 +0,0 @@ -#include -#include // ETH_P_IP -#include -#include -#include -#include -#include - -#define bpf_printk(fmt, ...) \ - ({ \ - char ____fmt[] = fmt; \ - bpf_trace_printk(____fmt, sizeof(____fmt), ##__VA_ARGS__); \ - }) - -const __u32 map_key_proxy_port = 0; -const __u32 map_key_wg_port = 1; - -struct bpf_map_def SEC("maps") nb_wg_proxy_settings_map = { - .type = BPF_MAP_TYPE_ARRAY, - .key_size = sizeof(__u32), - .value_size = sizeof(__u16), - .max_entries = 10, -}; - -__u16 proxy_port = 0; -__u16 wg_port = 0; - -bool read_port_settings() { - __u16 *value; - value = bpf_map_lookup_elem(&nb_wg_proxy_settings_map, &map_key_proxy_port); - if(!value) { - return false; - } - - proxy_port = *value; - - value = bpf_map_lookup_elem(&nb_wg_proxy_settings_map, &map_key_wg_port); - if(!value) { - return false; - } - wg_port = *value; - - return true; -} - -SEC("xdp") -int nb_wg_proxy(struct xdp_md *ctx) { - if(proxy_port == 0 || wg_port == 0) { - if(!read_port_settings()){ - return XDP_PASS; - } - bpf_printk("proxy port: %d, wg port: %d", proxy_port, wg_port); - } - - void *data = (void *)(long)ctx->data; - void *data_end = (void *)(long)ctx->data_end; - struct ethhdr *eth = data; - struct iphdr *ip = (data + sizeof(struct ethhdr)); - struct udphdr *udp = (data + sizeof(struct ethhdr) + sizeof(struct iphdr)); - - // return early if not enough data - if (data + sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr) > data_end){ - return XDP_PASS; - } - - // skip non IPv4 packages - if (eth->h_proto != htons(ETH_P_IP)) { - return XDP_PASS; - } - - if (ip->protocol != IPPROTO_UDP) { - return XDP_PASS; - } - - // 2130706433 = 127.0.0.1 - if (ip->daddr != htonl(2130706433)) { - return XDP_PASS; - } - - if (udp->source != htons(wg_port)){ - return XDP_PASS; - } - - __be16 new_src_port = udp->dest; - __be16 new_dst_port = htons(proxy_port); - udp->dest = new_dst_port; - udp->source = new_src_port; - return XDP_PASS; -} -char _license[] SEC("license") = "GPL"; \ No newline at end of file diff --git a/client/internal/wgproxy/proxy_ebpf.go b/client/internal/wgproxy/proxy_ebpf.go index 8be6b0c19..4d3e199de 100644 --- a/client/internal/wgproxy/proxy_ebpf.go +++ b/client/internal/wgproxy/proxy_ebpf.go @@ -12,15 +12,14 @@ import ( "github.com/google/gopacket" "github.com/google/gopacket/layers" - log "github.com/sirupsen/logrus" - ebpf2 "github.com/netbirdio/netbird/client/internal/wgproxy/ebpf" + "github.com/netbirdio/netbird/client/internal/ebpf" ) // WGEBPFProxy definition for proxy with EBPF support type WGEBPFProxy struct { - ebpf *ebpf2.EBPF + ebpfManager *ebpf.Manager lastUsedPort uint16 localWGListenPort int @@ -36,7 +35,7 @@ func NewWGEBPFProxy(wgPort int) *WGEBPFProxy { log.Debugf("instantiate ebpf proxy") wgProxy := &WGEBPFProxy{ localWGListenPort: wgPort, - ebpf: ebpf2.NewEBPF(), + ebpfManager: ebpf.GetEbpfManagerInstance(), lastUsedPort: 0, turnConnStore: make(map[uint16]net.Conn), } @@ -56,7 +55,7 @@ func (p *WGEBPFProxy) Listen() error { return err } - err = p.ebpf.Load(wgPorxyPort, p.localWGListenPort) + err = p.ebpfManager.LoadWgProxy(wgPorxyPort, p.localWGListenPort) if err != nil { return err } @@ -110,7 +109,7 @@ func (p *WGEBPFProxy) Free() error { err1 = p.conn.Close() } - err2 = p.ebpf.Free() + err2 = p.ebpfManager.FreeWGProxy() if p.rawConn != nil { err3 = p.rawConn.Close() } diff --git a/go.mod b/go.mod index 57bf9cf83..7ecf61584 100644 --- a/go.mod +++ b/go.mod @@ -126,7 +126,6 @@ require ( github.com/prometheus/client_model v0.3.0 // indirect github.com/prometheus/common v0.37.0 // indirect github.com/prometheus/procfs v0.8.0 // indirect - github.com/rogpeppe/go-internal v1.9.0 // indirect github.com/spf13/cast v1.5.0 // indirect github.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564 // indirect github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9 // indirect diff --git a/go.sum b/go.sum index 1f19d4721..1eb9d243d 100644 --- a/go.sum +++ b/go.sum @@ -100,7 +100,6 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg= github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= github.com/cilium/ebpf v0.5.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= -github.com/cilium/ebpf v0.7.0 h1:1k/q3ATgxSXRdrmPfH8d7YK0GfqVsEKZAX9dQZvs56k= github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= github.com/cilium/ebpf v0.10.0 h1:nk5HPMeoBXtOzbkZBWym+ZWq1GIiHUsBFXxwewXAHLQ= github.com/cilium/ebpf v0.10.0/go.mod h1:DPiVdY/kT534dgc9ERmvP8mWA+9gvwgKfRvk4nNWnoE= @@ -598,7 +597,8 @@ github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40T github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rs/cors v1.8.0 h1:P2KMzcFwrPoSjkF1WLRPsp3UMLyql8L4v9hQpVeK5so= github.com/rs/cors v1.8.0/go.mod h1:EBwu+T5AvHOcXwvZIkQFjUN6s8Czyqw12GL/Y0tUyRM= github.com/rs/xid v1.3.0 h1:6NjYksEUlhurdVehpc7S7dk6DAmcKv8V9gG0FsVN2U4= github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= @@ -615,6 +615,8 @@ github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0 github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA= github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog= +github.com/smartystreets/assertions v1.13.0 h1:Dx1kYM01xsSqKPno3aqLnrwac2LetPvN23diwyr69Qs= +github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= @@ -631,7 +633,9 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= +github.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564 h1:HunZiaEKNGVdhTRQOVpMmj5MQnGnv+e8uZNu3xFLgyM= github.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564/go.mod h1:afMbS0qvv1m5tfENCwnOdZGOF8RGR/FsZ7bvBxQGZG4= +github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9 h1:m59mIOBO4kfcNCEzJNy71UkeF4XIx2EVmL9KLwDQdmM= github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9/go.mod h1:mvWM0+15UqyrFKqdRjY6LuAVJR0HOVhJlEgZ5JWtSWU= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -647,6 +651,7 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= @@ -672,6 +677,7 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1 github.com/yuin/goldmark v1.3.8/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= @@ -733,6 +739,7 @@ golang.org/x/exp v0.0.0-20220518171630-0b5c67f07fdf/go.mod h1:yh0Ynu2b5ZUe3MQfp2 golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.5.0 h1:5JMiNunQeQw++mMOz48/ISeNu3Iweh/JaZU8ZLqHRrI= golang.org/x/image v0.5.0/go.mod h1:FVC7BI/5Ym8R25iw5OLsgshdUBbT1h5jZTpA+mvAdZ4= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -746,6 +753,7 @@ golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPI golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028 h1:4+4C/Iv2U4fMZBiMCc98MG1In4gJY5YRhtpDNeDeHWs= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= @@ -974,6 +982,7 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs= golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1100,6 +1109,8 @@ google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210722135532-667f2b7c528f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc h1:8DyZCyvI8mE1IdLy/60bS+52xfymkE72wv1asokgtao= +google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc h1:kVKPf/IiYSBWEWtkIn6wZXwWGCnLKcC8oWfZvXjsGnM= google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc h1:XSJ8Vk1SWuNr8S18z1NZSziL0CPIXLCCMDOEFtHBOFc= google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= @@ -1145,6 +1156,7 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= @@ -1156,6 +1168,7 @@ gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24 gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 h1:yiW+nvdHb9LVqSHQBXfZCieqV4fzYhNBql77zY0ykqs= gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637/go.mod h1:BHsqpu/nsuzkT5BpiH1EMZPLyqSMM8JbIavyFACoFNk= @@ -1167,6 +1180,7 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= @@ -1175,6 +1189,7 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= +gvisor.dev/gvisor v0.0.0-20221203005347-703fd9b7fbc0 h1:Wobr37noukisGxpKo5jAsLREcpj61RxrWYzD8uwveOY= gvisor.dev/gvisor v0.0.0-20221203005347-703fd9b7fbc0/go.mod h1:Dn5idtptoW1dIos9U6A2rpebLs/MtTwFacjKb8jLdQA= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=