├── .gitignore ├── ebpf ├── Makefile ├── common.h └── drop.c ├── go.mod ├── .github └── workflows │ ├── sourcegraph-lsif-indexing.yml │ └── go.yml ├── LICENSE ├── README.md ├── main.go └── go.sum /.gitignore: -------------------------------------------------------------------------------- 1 | tc-skeleton 2 | ebpf/drop 3 | -------------------------------------------------------------------------------- /ebpf/Makefile: -------------------------------------------------------------------------------- 1 | clean: 2 | -$(RM) drop 3 | 4 | drop: 5 | clang -O2 -g -Wall -Werror -emit-llvm -c drop.c -o - | llc -march=bpf -mcpu=probe -filetype=obj -o drop 6 | -------------------------------------------------------------------------------- /ebpf/common.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #define __section(NAME) __attribute__((section(NAME), used)) 7 | 8 | char __license[] __section("license") = "MIT"; 9 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/florianl/tc-skeleton 2 | 3 | go 1.20 4 | 5 | require ( 6 | github.com/cilium/ebpf v0.12.3 7 | github.com/florianl/go-tc v0.4.5 8 | github.com/jsimonetti/rtnetlink v1.3.1 9 | golang.org/x/sys v0.31.0 10 | ) 11 | 12 | require ( 13 | github.com/google/go-cmp v0.6.0 // indirect 14 | github.com/josharian/native v1.1.0 // indirect 15 | github.com/mdlayher/netlink v1.7.2 // indirect 16 | github.com/mdlayher/socket v0.5.1 // indirect 17 | golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2 // indirect 18 | golang.org/x/net v0.38.0 // indirect 19 | golang.org/x/sync v0.3.0 // indirect 20 | ) 21 | -------------------------------------------------------------------------------- /.github/workflows/sourcegraph-lsif-indexing.yml: -------------------------------------------------------------------------------- 1 | name: "sourcegraph LSIF indexing" 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | 7 | # Set default permissions as read only. 8 | permissions: read-all 9 | 10 | jobs: 11 | lsif-go: 12 | runs-on: ubuntu-latest 13 | container: sourcegraph/lsif-go:latest 14 | steps: 15 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 16 | - name: Generate LSIF data 17 | run: lsif-go 18 | - name: Upload LSIF data 19 | # this will upload to Sourcegraph.com, you may need to substitute a different command. 20 | # by default, we ignore failures to avoid disrupting CI pipelines with non-critical errors. 21 | run: src lsif upload -github-token=${{ secrets.GITHUB_TOKEN }} -ignore-upload-failure 22 | -------------------------------------------------------------------------------- /.github/workflows/go.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: [ main ] 4 | pull_request: 5 | branches: [ '**' ] 6 | 7 | # Set default permissions as read only. 8 | permissions: read-all 9 | 10 | name: Go 11 | jobs: 12 | code-check: 13 | strategy: 14 | matrix: 15 | go-version: [1.20.x, 1.23.x, 1.24.x] 16 | runs-on: ubuntu-latest 17 | steps: 18 | - name: Checkout code 19 | uses: actions/checkout@v4 20 | - name: Install Go 21 | uses: actions/setup-go@v4 22 | with: 23 | go-version: ${{ matrix.go-version }} 24 | - name: Download Go dependencies 25 | env: 26 | GOPROXY: "https://proxy.golang.org" 27 | run: go mod download 28 | - name: staticcheck.io 29 | if: startsWith(matrix.go-version, '1.24') 30 | uses: dominikh/staticcheck-action@v1.3.0 31 | with: 32 | version: "2025.1" 33 | install-go: false 34 | cache-key: ${{ matrix.go }} 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | =========== 3 | 4 | Copyright (C) 2019-2020 Florian Lehner 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 7 | 8 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 9 | 10 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 11 | -------------------------------------------------------------------------------- /ebpf/drop.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | __section("classifier_egress_drop") int egress_drop(struct __sk_buff *skb) { 8 | void *data_end = (void *)(unsigned long long)skb->data_end; 9 | void *data = (void *)(unsigned long long)skb->data; 10 | struct ethhdr *eth = data; 11 | 12 | /* Drop mailformated packet */ 13 | if (data + sizeof(struct ethhdr) > data_end) 14 | return TC_ACT_SHOT; 15 | 16 | /* Drop legacy IP traffic */ 17 | if (eth->h_proto == ___constant_swab16(ETH_P_IP)) 18 | return TC_ACT_SHOT; 19 | 20 | return TC_ACT_OK; 21 | } 22 | 23 | __section("classifier_ingress_drop") int ingress_drop(struct __sk_buff *skb) { 24 | void *data_end = (void *)(unsigned long long)skb->data_end; 25 | void *data = (void *)(unsigned long long)skb->data; 26 | struct ethhdr *eth = data; 27 | 28 | /* Drop mailformated packet */ 29 | if (data + sizeof(struct ethhdr) > data_end) 30 | return TC_ACT_SHOT; 31 | 32 | /* Drop legacy IP traffic */ 33 | if (eth->h_proto == ___constant_swab16(ETH_P_IP)) 34 | return TC_ACT_SHOT; 35 | 36 | return TC_ACT_OK; 37 | } 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | tc-skeleton 2 | =========== 3 | 4 | Simple project to demonstrate the loading of eBPF programs via [florianl/go-tc](https://github.com/florianl/go-tc). 5 | 6 | ``` 7 | $ cd ebpf 8 | $ make clean 9 | $ make drop 10 | $ cd .. 11 | $ go run -exec=sudo main.go 12 | ``` 13 | 14 | Overview 15 | -------- 16 | After the eBPF code is loaded from `ebpf/drop` the eBPF program `ingress_drop` is loaded into the kernel. In a next step this PoC creates a dummy interface. So it does not alter existing configurations or network interfaces. Then a [qdisc and filter](https://man7.org/linux/man-pages/man8/tc.8.html) are attached via the [netlink interface](https://man7.org/linux/man-pages/man7/netlink.7.html) of the kernel to this dummy interface. The file descriptor of the eBPF program `ingress_drop` is passed as argument of the filter to the kernel. With attaching the filter to the interface the eBPF program `ingress_drop` will run on every packet on the interface. 17 | 18 | Privileges 19 | ---------- 20 | This PoC uses the [`netlink`](https://man7.org/linux/man-pages/man7/netlink.7.html) and [`eBPF`](https://man7.org/linux/man-pages/man2/bpf.2.html) interface of the kernel and therefore it requires special privileges. You can provide this privileges by adjusting the `CAP_NET_ADMIN` capabilities. 21 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "net" 7 | "os" 8 | "time" 9 | 10 | "github.com/cilium/ebpf" 11 | 12 | "github.com/jsimonetti/rtnetlink" 13 | 14 | "github.com/florianl/go-tc" 15 | helper "github.com/florianl/go-tc/core" 16 | 17 | "golang.org/x/sys/unix" 18 | ) 19 | 20 | // setupDummyInterface installs a temporary dummy interface 21 | func setupDummyInterface(iface string) (*rtnetlink.Conn, error) { 22 | con, err := rtnetlink.Dial(nil) 23 | if err != nil { 24 | return &rtnetlink.Conn{}, err 25 | } 26 | if err := con.Link.New(&rtnetlink.LinkMessage{ 27 | Family: unix.AF_UNSPEC, 28 | Type: unix.ARPHRD_NETROM, 29 | Index: 0, 30 | Flags: unix.IFF_UP, 31 | Change: unix.IFF_UP, 32 | Attributes: &rtnetlink.LinkAttributes{ 33 | Name: iface, 34 | Info: &rtnetlink.LinkInfo{Kind: "dummy"}, 35 | }, 36 | }); err != nil { 37 | return con, err 38 | } 39 | return con, err 40 | } 41 | 42 | func uint32Ptr(v uint32) *uint32 { 43 | return &v 44 | } 45 | 46 | func stringPtr(v string) *string { 47 | return &v 48 | } 49 | 50 | func main() { 51 | 52 | ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) 53 | defer cancel() 54 | 55 | // Load eBPF from an elf file 56 | coll, err := ebpf.LoadCollectionSpec("ebpf/drop") 57 | if err != nil { 58 | fmt.Fprintf(os.Stderr, "could not load collection from file: %v\n", err) 59 | return 60 | } 61 | 62 | // Load the eBPF program ingress_drop 63 | ingressDrop, err := ebpf.NewProgramWithOptions(coll.Programs["ingress_drop"], 64 | ebpf.ProgramOptions{ 65 | LogLevel: 1, 66 | LogSize: 65536, 67 | }) 68 | if err != nil { 69 | fmt.Fprintf(os.Stderr, "could not load program: %v\n", err) 70 | return 71 | } 72 | defer ingressDrop.Close() 73 | 74 | // Print verifier feedback 75 | fmt.Printf("%s", ingressDrop.VerifierLog) 76 | 77 | info, _ := ingressDrop.Info() 78 | 79 | // Setup tc socket for communication with the kernel 80 | tcnl, err := tc.Open(&tc.Config{}) 81 | if err != nil { 82 | fmt.Fprintf(os.Stderr, "could not open rtnetlink socket: %v\n", err) 83 | return 84 | } 85 | defer func() { 86 | if err := tcnl.Close(); err != nil { 87 | fmt.Fprintf(os.Stderr, "could not close rtnetlink socket: %v\n", err) 88 | } 89 | }() 90 | 91 | // Setup dummy interface for testing 92 | var rtnl *rtnetlink.Conn 93 | tcIface := "tcDevTesting" 94 | if rtnl, err = setupDummyInterface(tcIface); err != nil { 95 | fmt.Fprintf(os.Stderr, "could not setup dummy interface: %v\n", err) 96 | return 97 | } 98 | defer rtnl.Close() 99 | devID, err := net.InterfaceByName(tcIface) 100 | if err != nil { 101 | fmt.Fprintf(os.Stderr, "could not get interface ID: %v\n", err) 102 | return 103 | } 104 | defer func(devID uint32, rtnl *rtnetlink.Conn) { 105 | if err := rtnl.Link.Delete(devID); err != nil { 106 | fmt.Fprintf(os.Stderr, "could not delete interface %s: %v\n", tcIface, err) 107 | } 108 | }(uint32(devID.Index), rtnl) 109 | 110 | qdisc := tc.Object{ 111 | Msg: tc.Msg{ 112 | Family: unix.AF_UNSPEC, 113 | Ifindex: uint32(devID.Index), 114 | Handle: helper.BuildHandle(tc.HandleRoot, 0x0000), 115 | Parent: tc.HandleIngress, 116 | }, 117 | Attribute: tc.Attribute{ 118 | Kind: "clsact", 119 | }, 120 | } 121 | 122 | // Install Qdisc on testing interface 123 | if err := tcnl.Qdisc().Add(&qdisc); err != nil { 124 | fmt.Fprintf(os.Stderr, "could not assign clsact to %s: %v\n", tcIface, err) 125 | return 126 | } 127 | // when deleting the qdisc, the applied filter will also be gone 128 | defer tcnl.Qdisc().Delete(&qdisc) 129 | priority := uint16(1) 130 | 131 | filter := tc.Object{ 132 | Msg: tc.Msg{ 133 | Family: unix.AF_UNSPEC, 134 | Ifindex: uint32(devID.Index), 135 | Parent: helper.BuildHandle(tc.HandleRoot, tc.HandleMinIngress), 136 | Info: helper.FilterInfo(priority, unix.ETH_P_ALL), 137 | }, 138 | Attribute: tc.Attribute{ 139 | Kind: "bpf", 140 | BPF: &tc.Bpf{ 141 | FD: uint32Ptr(uint32(ingressDrop.FD())), 142 | Name: stringPtr(info.Name), 143 | Flags: uint32Ptr(0x1), 144 | }, 145 | }, 146 | } 147 | if err := tcnl.Filter().Add(&filter); err != nil { 148 | fmt.Fprintf(os.Stderr, "could not assign eBPF: %v\n", err) 149 | return 150 | } 151 | 152 | <-ctx.Done() 153 | 154 | if err := tcnl.Filter().Delete(&tc.Object{ 155 | Msg: tc.Msg{ 156 | Family: unix.AF_UNSPEC, 157 | Ifindex: uint32(devID.Index), 158 | Parent: helper.BuildHandle(tc.HandleRoot, tc.HandleMinIngress), 159 | Info: helper.FilterInfo(priority, unix.ETH_P_ALL), 160 | }, 161 | Attribute: tc.Attribute{ 162 | Kind: "bpf", 163 | }, 164 | }); err != nil { 165 | fmt.Fprintf(os.Stderr, "could not delete eBPF filter: %v\n", err) 166 | return 167 | } 168 | 169 | } 170 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/cilium/ebpf v0.5.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= 2 | github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= 3 | github.com/cilium/ebpf v0.8.1/go.mod h1:f5zLIM0FSNuAkSyLAN7X+Hy6yznlF1mNiWUMfxMtrgk= 4 | github.com/cilium/ebpf v0.12.3 h1:8ht6F9MquybnY97at+VDZb3eQQr8ev79RueWeVaEcG4= 5 | github.com/cilium/ebpf v0.12.3/go.mod h1:TctK1ivibvI3znr66ljgi4hqOT8EYQjz1KWBfb1UVgM= 6 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 7 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 8 | github.com/florianl/go-tc v0.4.5 h1:8lvecARs3c/vGee46j0ro8kco98ga9XjwWvXGwlzrXA= 9 | github.com/florianl/go-tc v0.4.5/go.mod h1:uvp6pIlOw7Z8hhfnT5M4+V1hHVgZWRZwwMS8Z0JsRxc= 10 | github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= 11 | github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og= 12 | github.com/frankban/quicktest v1.14.5 h1:dfYrrRyLtiqT9GyKXgdh+k4inNeTvmGbuSgZ3lx3GhA= 13 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 14 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 15 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 16 | github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 17 | github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 18 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 19 | github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 20 | github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= 21 | github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= 22 | github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 23 | github.com/josharian/native v0.0.0-20200817173448-b6b71def0850/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= 24 | github.com/josharian/native v1.0.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= 25 | github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= 26 | github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= 27 | github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw= 28 | github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ= 29 | github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqoO/u39cqLeBLebZ8fWdE96O7FxrAsRYhnVOdgHxok= 30 | github.com/jsimonetti/rtnetlink v0.0.0-20201216134343-bde56ed16391/go.mod h1:cR77jAZG3Y3bsb8hF6fHJbFoyFukLFOkQ98S0pQz3xw= 31 | github.com/jsimonetti/rtnetlink v0.0.0-20201220180245-69540ac93943/go.mod h1:z4c53zj6Eex712ROyh8WI0ihysb5j2ROyV42iNogmAs= 32 | github.com/jsimonetti/rtnetlink v0.0.0-20210122163228-8d122574c736/go.mod h1:ZXpIyOK59ZnN7J0BV99cZUPmsqDRZ3eq5X+st7u/oSA= 33 | github.com/jsimonetti/rtnetlink v0.0.0-20210212075122-66c871082f2b/go.mod h1:8w9Rh8m+aHZIG69YPGGem1i5VzoyRC8nw2kA8B+ik5U= 34 | github.com/jsimonetti/rtnetlink v0.0.0-20210525051524-4cc836578190/go.mod h1:NmKSdU4VGSiv1bMsdqNALI4RSvvjtz65tTMCnD05qLo= 35 | github.com/jsimonetti/rtnetlink v0.0.0-20211022192332-93da33804786/go.mod h1:v4hqbTdfQngbVSZJVWUhGE/lbTFf9jb+ygmNUDQMuOs= 36 | github.com/jsimonetti/rtnetlink v1.3.1 h1:Bl3VxrWwi3eNj2pFuG2x3xcIArSAvHf9paz1OXiDT9A= 37 | github.com/jsimonetti/rtnetlink v1.3.1/go.mod h1:Wcc80IISX10gdeQoRzNPcCd1joPy+P0NyPPgOhQAvpk= 38 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 39 | github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 40 | github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= 41 | github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= 42 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 43 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 44 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 45 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 46 | github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43/go.mod h1:+t7E0lkKfbBsebllff1xdTmyJt8lH37niI6kwFk9OTo= 47 | github.com/mdlayher/genetlink v1.0.0/go.mod h1:0rJ0h4itni50A86M2kHcgS85ttZazNt7a8H2a2cw0Gc= 48 | github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA= 49 | github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M= 50 | github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY= 51 | github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZmb2XgV7o= 52 | github.com/mdlayher/netlink v1.2.0/go.mod h1:kwVW1io0AZy9A1E2YYgaD4Cj+C+GPkU6klXCMzIJ9p8= 53 | github.com/mdlayher/netlink v1.2.1/go.mod h1:bacnNlfhqHqqLo4WsYeXSqfyXkInQ9JneWI68v1KwSU= 54 | github.com/mdlayher/netlink v1.2.2-0.20210123213345-5cc92139ae3e/go.mod h1:bacnNlfhqHqqLo4WsYeXSqfyXkInQ9JneWI68v1KwSU= 55 | github.com/mdlayher/netlink v1.3.0/go.mod h1:xK/BssKuwcRXHrtN04UBkwQ6dY9VviGGuriDdoPSWys= 56 | github.com/mdlayher/netlink v1.4.0/go.mod h1:dRJi5IABcZpBD2A3D0Mv/AiX8I9uDEu5oGkAVrekmf8= 57 | github.com/mdlayher/netlink v1.4.1/go.mod h1:e4/KuJ+s8UhfUpO9z00/fDZZmhSrs+oxyqAS9cNgn6Q= 58 | github.com/mdlayher/netlink v1.6.0/go.mod h1:0o3PlBmGst1xve7wQ7j/hwpNaFaH4qCRyWCdcZk8/vA= 59 | github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g= 60 | github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw= 61 | github.com/mdlayher/socket v0.0.0-20210307095302-262dc9984e00/go.mod h1:GAFlyu4/XV68LkQKYzKhIo/WW7j3Zi0YRAz/BOoanUc= 62 | github.com/mdlayher/socket v0.1.1/go.mod h1:mYV5YIZAfHh4dzDVzI8x8tWLWCliuX8Mon5Awbj+qDs= 63 | github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos= 64 | github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ= 65 | github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= 66 | github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= 67 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 68 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 69 | golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2 h1:Jvc7gsqn21cJHCmAWx0LiimpP18LZmUxkT5Mp7EZ1mI= 70 | golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= 71 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 72 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 73 | golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 74 | golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 75 | golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 76 | golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 77 | golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 78 | golang.org/x/net v0.0.0-20201216054612-986b41b23924/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 79 | golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 80 | golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 81 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 82 | golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 83 | golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 84 | golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= 85 | golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= 86 | golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= 87 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 88 | golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= 89 | golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= 90 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 91 | golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 92 | golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 93 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 94 | golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 95 | golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 96 | golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 97 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 98 | golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 99 | golang.org/x/sys v0.0.0-20201118182958-a01c418693c7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 100 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 101 | golang.org/x/sys v0.0.0-20201218084310-7d0127a74742/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 102 | golang.org/x/sys v0.0.0-20210110051926-789bb1bd4061/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 103 | golang.org/x/sys v0.0.0-20210123111255-9b0068b26619/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 104 | golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 105 | golang.org/x/sys v0.0.0-20210216163648-f7da38b97c65/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 106 | golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 107 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 108 | golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 109 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 110 | golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 111 | golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 112 | golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 113 | golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 114 | golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= 115 | golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= 116 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 117 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 118 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 119 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 120 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 121 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 122 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 123 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 124 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 125 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 126 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 127 | --------------------------------------------------------------------------------