ebpf test

This commit is contained in:
braginini 2021-12-05 18:17:13 +01:00
parent 3dca2d6953
commit b78ec082a3
5 changed files with 308 additions and 1 deletions

36
ebpf/filter.go Normal file
View File

@ -0,0 +1,36 @@
package main
import (
"github.com/cilium/ebpf"
"net"
"syscall"
)
// Filter represents a classic BPF filter program that can be applied to a socket
type Filter struct {
*ebpf.ProgramSpec
}
// ApplyTo applies the current filter onto the provided UDPConn
func (filter Filter) ApplyTo(conn *net.UDPConn) error {
file, err := conn.File()
if err != nil {
return err
}
p, err := ebpf.NewProgramWithOptions(filter.ProgramSpec, ebpf.ProgramOptions{
LogLevel: 6,
})
if err != nil {
return err
}
if err := syscall.SetsockoptInt(int(file.Fd()), syscall.SOL_SOCKET, SO_ATTACH_BPF, p.FD()); err != nil {
return err
}
return nil
}

71
ebpf/main.go Normal file
View File

@ -0,0 +1,71 @@
package main
import (
"encoding/hex"
"fmt"
"github.com/cilium/ebpf"
"github.com/cilium/ebpf/asm"
"net"
)
const (
SO_ATTACH_BPF int = 50
StunMagicCookie uint32 = 0x2112A442
)
func main() {
// open a raw socket
/*fd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, syscall.IPPROTO_UDP)
if err != nil {
panic(err)
}
fmt.Print(fd)*/
addr := net.UDPAddr{
IP: net.IPv4zero,
Port: 12345,
}
conn, err := net.ListenUDP("udp4", &addr)
if err != nil {
return
}
filter := &Filter{
ProgramSpec: &ebpf.ProgramSpec{
Type: ebpf.SocketFilter,
License: "GPL",
Instructions: asm.Instructions{
asm.Mov.Reg(asm.R6, asm.R1), // LDABS requires ctx in R6
asm.LoadAbs(-0x100000+22, asm.Half),
asm.JNE.Imm(asm.R0, int32(addr.Port), "skip"),
/* asm.LoadAbs(-0x100000+32, asm.Word),
asm.JNE.Imm(asm.R0, int32(StunMagicCookie), "skip"),
asm.Mov.Imm(asm.R0, -1).Sym("exit"),*/
/*asm.Return(),*/
asm.Mov.Imm(asm.R0, 0).Sym("skip"),
asm.Return(),
},
},
}
err = filter.ApplyTo(conn)
if err != nil {
panic(err)
}
fmt.Printf("start")
buf := make([]byte, 1024)
for {
n, ra, err := conn.ReadFrom(buf)
if err != nil {
panic(err)
}
fmt.Printf("Bytes read: %d\n", n)
fmt.Printf("Remote Addr: %+v\n", ra)
fmt.Printf("Bytes HEX: %s\n", hex.EncodeToString(buf[:n]))
fmt.Printf("Bytes String: %s\n", string(buf[:n]))
fmt.Println()
}
}

186
ebpf/test/main.go Normal file
View File

@ -0,0 +1,186 @@
package main
// This code is derived from https://github.com/cloudflare/cloudflare-blog/tree/master/2018-03-ebpf
//
// Copyright (c) 2015-2017 Cloudflare, Inc. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of the Cloudflare, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import (
"fmt"
"net"
"syscall"
"github.com/cilium/ebpf"
"github.com/cilium/ebpf/asm"
)
// ExampleExtractDistance shows how to attach an eBPF socket filter to
// extract the network distance of an IP host.
func main() {
filter, TTLs, err := newDistanceFilter()
if err != nil {
panic(err)
}
defer filter.Close()
defer TTLs.Close()
// Attach filter before the call to connect()
dialer := net.Dialer{
Control: func(network, address string, c syscall.RawConn) (err error) {
const SO_ATTACH_BPF = 50
err = c.Control(func(fd uintptr) {
err = syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, SO_ATTACH_BPF, filter.FD())
})
return err
},
}
conn, err := dialer.Dial("tcp", "1.1.1.1:53")
if err != nil {
panic(err)
}
conn.Close()
minDist, err := minDistance(TTLs)
if err != nil {
panic(err)
}
fmt.Println("1.1.1.1:53 is", minDist, "hops away")
}
func newDistanceFilter() (*ebpf.Program, *ebpf.Map, error) {
const ETH_P_IPV6 uint16 = 0x86DD
ttls, err := ebpf.NewMap(&ebpf.MapSpec{
Type: ebpf.Hash,
KeySize: 4,
ValueSize: 8,
MaxEntries: 4,
})
if err != nil {
return nil, nil, err
}
insns := asm.Instructions{
// r1 has ctx
// r0 = ctx[16] (aka protocol)
asm.LoadMem(asm.R0, asm.R1, 16, asm.Word),
// Perhaps ipv6
asm.LoadImm(asm.R2, int64(ETH_P_IPV6), asm.DWord),
asm.HostTo(asm.BE, asm.R2, asm.Half),
asm.JEq.Reg(asm.R0, asm.R2, "ipv6"),
// otherwise assume ipv4
// 8th byte in IPv4 is TTL
// LDABS requires ctx in R6
asm.Mov.Reg(asm.R6, asm.R1),
asm.LoadAbs(-0x100000+8, asm.Byte),
asm.Ja.Label("store-ttl"),
// 7th byte in IPv6 is Hop count
// LDABS requires ctx in R6
asm.Mov.Reg(asm.R6, asm.R1).Sym("ipv6"),
asm.LoadAbs(-0x100000+7, asm.Byte),
// stash the load result into FP[-4]
asm.StoreMem(asm.RFP, -4, asm.R0, asm.Word).Sym("store-ttl"),
// stash the &FP[-4] into r2
asm.Mov.Reg(asm.R2, asm.RFP),
asm.Add.Imm(asm.R2, -4),
// r1 must point to map
asm.LoadMapPtr(asm.R1, ttls.FD()),
asm.FnMapLookupElem.Call(),
// load ok? inc. Otherwise? jmp to mapupdate
asm.JEq.Imm(asm.R0, 0, "update-map"),
asm.Mov.Imm(asm.R1, 1),
asm.StoreXAdd(asm.R0, asm.R1, asm.DWord),
asm.Ja.Label("exit"),
// MapUpdate
// r1 has map ptr
asm.LoadMapPtr(asm.R1, ttls.FD()).Sym("update-map"),
// r2 has key -> &FP[-4]
asm.Mov.Reg(asm.R2, asm.RFP),
asm.Add.Imm(asm.R2, -4),
// r3 has value -> &FP[-16] , aka 1
asm.StoreImm(asm.RFP, -16, 1, asm.DWord),
asm.Mov.Reg(asm.R3, asm.RFP),
asm.Add.Imm(asm.R3, -16),
// r4 has flags, 0
asm.Mov.Imm(asm.R4, 0),
asm.FnMapUpdateElem.Call(),
// set exit code to -1, don't trunc packet
asm.Mov.Imm(asm.R0, -1).Sym("exit"),
asm.Return(),
}
prog, err := ebpf.NewProgram(&ebpf.ProgramSpec{
Name: "distance_filter",
Type: ebpf.SocketFilter,
License: "GPL",
Instructions: insns,
})
if err != nil {
ttls.Close()
return nil, nil, err
}
return prog, ttls, nil
}
func minDistance(TTLs *ebpf.Map) (int, error) {
var (
entries = TTLs.Iterate()
ttl uint32
minDist uint32 = 255
count uint64
)
for entries.Next(&ttl, &count) {
var dist uint32
switch {
case ttl > 128:
dist = 255 - ttl
case ttl > 64:
dist = 128 - ttl
case ttl > 32:
dist = 64 - ttl
default:
dist = 32 - ttl
}
if minDist > dist {
minDist = dist
}
}
return int(minDist), entries.Err()
}

5
go.mod
View File

@ -4,8 +4,10 @@ go 1.16
require (
github.com/cenkalti/backoff/v4 v4.1.0
github.com/cilium/ebpf v0.7.0
github.com/golang-jwt/jwt v3.2.2+incompatible
github.com/golang/protobuf v1.5.2
github.com/google/gopacket v1.1.19
github.com/google/uuid v1.2.0
github.com/gorilla/mux v1.8.0
github.com/kardianos/service v1.2.1-0.20210728001519-a323c3813bc7
@ -18,7 +20,8 @@ require (
github.com/spf13/pflag v1.0.5
github.com/vishvananda/netlink v1.1.0
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985
golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34
golang.zx2c4.com/wireguard v0.0.0-20210805125648-3957e9b9dd19
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20210803171230-4253848d036c
golang.zx2c4.com/wireguard/windows v0.4.5

11
go.sum
View File

@ -28,6 +28,8 @@ github.com/cenkalti/backoff/v4 v4.1.0 h1:c8LkOFQTzuO0WBM/ae5HdGQuZPfPxp7lqBRwQRm
github.com/cenkalti/backoff/v4 v4.1.0/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
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/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
@ -45,6 +47,7 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
@ -92,6 +95,8 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
@ -154,6 +159,7 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxv
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
@ -320,10 +326,12 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/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/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=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -412,6 +420,8 @@ golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34 h1:GkvMjFtXUmahfDtashnc1mnrCtuBVcwse5QV2lUk/tI=
golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -442,6 +452,7 @@ golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=