ZBLOG

10个ebpf uprobe golang的代码案例

这里给你提供10个使用eBPF和uprobes的Golang代码案例:

  1. 监控函数调用次数:
package main

import (
	"fmt"
	"os"

	bpf "github.com/iovisor/gobpf/bcc"
)

const source string = `
#include <uapi/linux/ptrace.h>

BPF_HASH(counts, u64);

int count_calls(struct pt_regs *ctx) {
    u64 key = PT_REGS_IP(ctx);
    u64 *val = counts.lookup(&key);
    if (val) {
        (*val)++;
    } else {
        counts.update(&key, &(u64){1});
    }
    return 0;
}
`

func main() {
	m := bpf.NewModule(source, []string{})
	defer m.Close()

	uprobeFD, err := m.LoadUprobe("count_calls")
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to load uprobe: %v\n", err)
		os.Exit(1)
	}

	err = m.AttachUprobe("/path/to/binary", "function_name", uprobeFD)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to attach uprobe: %v\n", err)
		os.Exit(1)
	}

	table := bpf.NewTable(m.TableId("counts"), m)
	it := table.Iter()
	for it.Next() {
		key := binary.LittleEndian.Uint64(it.Key())
		val := binary.LittleEndian.Uint64(it.Leaf())
		fmt.Printf("Function at address 0x%x was called %d times\n", key, val)
	}
}
  1. 统计函数执行时间:
package main

import (
	"fmt"
	bpf "github.com/iovisor/gobpf/bcc"
)

const source string = `
#include <uapi/linux/ptrace.h>

BPF_HASH(start, u32);
BPF_HISTOGRAM(dist);

int trace_entry(struct pt_regs *ctx) {
    u32 pid = bpf_get_current_pid_tgid();
    u64 ts = bpf_ktime_get_ns();
    start.update(&pid, &ts);
    return 0;
}

int trace_return(struct pt_regs *ctx) {
    u32 pid = bpf_get_current_pid_tgid();
    u64 *tsp, delta;

    tsp = start.lookup(&pid);
    if (tsp != 0) {
        delta = bpf_ktime_get_ns() - *tsp;
        dist.increment(bpf_log2l(delta));
        start.delete(&pid);
    }
    
    return 0;
}
`

func main() {
	m := bpf.NewModule(source, []string{})
	defer m.Close()

	entryFD, err := m.LoadUprobe("trace_entry")
	if err != nil {
		fmt.Println(err)
		return
	}

	returnFD, err := m.LoadUprobe("trace_return")
	if err != nil {
		fmt.Println(err)
		return
	}

	err = m.AttachUprobe("/path/to/binary", "function_name", entryFD)
	if err != nil {
		fmt.Println(err)
		return
	}

	err = m.AttachUretprobe("/path/to/binary", "function_name", returnFD)
	if err != nil {
		fmt.Println(err)
		return
	}

	table := bpf.NewTable(m.TableId("dist"), m)

	buckets := table.HistogramRead()
	for i, count := range buckets {
		if count == 0 {
			continue
		}
		
		lower := 1 << uint32(i)
        upper := lower << 1
        fmt.Printf("[%d-%d] ns: %d\n", lower, upper, count)
    }
}
  1. 监控文件IO调用:
package main

import (
	"fmt"
	bpf "github.com/iovisor/gobpf/bcc"
)

const source string = `
#include <uapi/linux/ptrace.h>

struct data_t {
    u64 ts;
    char name[TASK_COMM_LEN];
};

BPF_HASH(start, u32);
BPF_PERF_OUTPUT(events);

int trace_entry(struct pt_regs *ctx) {
    struct data_t data = {};
    u32 pid = bpf_get_current_pid_tgid();

    if (bpf_get_current_comm(&data.name, sizeof(data.name)) == 0) {
        data.ts = bpf_ktime_get_ns();
        start.update(&pid, &data);
    }

    return 0;
}

int trace_return(struct pt_regs *ctx) {
    struct data_t *datap;
    
	u32 pid = bpf_get_current_pid_tgid();
	datap = start.lookup(&pid);

	if (datap != 0) {
		u64 delta;

		delta = bpf_ktime_get_ns() - datap->ts;
        events.perf_submit(ctx, datap, sizeof(*datap));
        
		start.delete(&pid);
	}

	return 0;
}
`

type eventData struct {
	Timestamp uint64
	Name      [16]byte
}

func main() {
	m := bpf.NewModule(source, []string{})
	defer m.Close()

	entryFD, err := m.LoadUprobe("trace_entry")
	if err != nil {
		fmt.Println(err)
		return
	}

	returnFD, err := m.LoadUprobe("trace_return")
	if err != nil {
		fmt.Println(err)
		return
	}

	err = m.AttachUprobe("/path/to/binary", "function_name", entryFD)
	if err != nil {
		fmt.Println(err)
		return
	}

	err = m.AttachUretprobe("/path/to/binary", "function_name", returnFD)
	if err != nil {
		fmt.Println(err)
		return
	}

	table := bpf.NewTable(m.TableId("events"), m)

	channel := make(chan []byte)
	perfMap, err := bpf.InitPerfMap(table, channel)
	if err != nil {
		fmt.Println(err)
		return
	}

	go func() {
        for data := range channel {
            var event eventData
			err = binary.Read(bytes.NewBuffer(data), binary.LittleEndian, &event)
			if err != nil {
				fmt.Println(err)
				continue
			}
			
            fmt.Printf("Process: %s, Timestamp: %d\n", string(event.Name[:]), event.Timestamp)
        }
    }()
	
	select {}
}
  1. 监控系统调用:
package main

import (
    "fmt"
    "os"

    bpf "github.com/iovisor/gobpf/bcc"
)

const source string = `
#include <uapi/linux/ptrace.h>

BPF_HASH(syscall_counts, u32);

int count_syscalls(struct pt_regs *ctx) {
    u32 pid = bpf_get_current_pid_tgid();
    u64 *count = syscall_counts.lookup(&pid);
    if (count) {
        (*count)++;
    } else {
        syscall_counts.update(&pid, &(u64){1});
    }
    
    return 0;
}
`

func main() {
	m := bpf.NewModule(source, []string{})
	defer m.Close()

	syscallFD, err := m.LoadUprobe("count_syscalls")
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to load uprobe: %v\n", err)
		os.Exit(1)
	}

	err = m.AttachUprobe("", "__x64_sys_read", syscallFD)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to attach uprobe: %v\n", err)
		os.Exit(1)
    }

    table := bpf.NewTable(m.TableId("syscall_counts"), m)

	it := table.Iter()
	for it.Next() {
		pid := binary.LittleEndian.Uint32(it.Key())
		count := binary.LittleEndian.Uint64(it.Leaf())
		fmt.Printf("Process with PID %d made %d syscalls\n", pid, count)
    }
}
  1. 拦截网络数据包:
package main

import (
    "fmt"
    "os"
    
    bpf "github.com/iovisor/gobpf/bcc"
)

const source string = `
#include <uapi/linux/ptrace.h>
#include <bcc/proto.h>

BPF_PERF_OUTPUT(events);

int trace_packet(struct __sk_buff *skb) {
    u8 *cursor = 0;
	struct ethernet_t *ethernet = cursor_advance(cursor, sizeof(*ethernet));
	
	if (ethernet->type == ETH_P_IP) {
        struct ip_t *ip = cursor_advance(cursor, sizeof(*ip));

        if (ip->protocol == IPPROTO_TCP) {
            struct tcp_t *tcp = cursor_advance(cursor, sizeof(*tcp));

            if (tcp->dest == bpf_htons(80)) { // HTTP traffic
                events.perf_submit(skb, skb->len);
            }
        }
    }
    
	return 0;
}
`

func main() {
	m := bpf.NewModule(source, []string{})
	defer m.Close()

	uprobeFD, err := m.LoadUprobe("trace_packet")
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to load uprobe: %v\n", err)
		os.Exit(1)
	}

	err = m.AttachUprobe("tcp_sendmsg", uprobeFD)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to attach uprobe: %v\n", err)
		os.Exit(1)
    }

    perfMap, err := bpf.InitPerfMap(m.TableId("events"), printPacketSize)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to initialize perf map: %v\n", err)
		os.Exit(1)
    }
    
    perfMap.Start()

    select {}
}

func printPacketSize(data []byte) {
	fmt.Printf("Received packet of size %d bytes\n", len(data))
}
  1. 拦截文件读写操作:
package main

import (
    "fmt"
    "os"

	bpf "github.com/iovisor/gobpf/bcc"
)

const source string = `
#include <uapi/linux/ptrace.h>
#include <linux/sched.h>

struct key_t {
	int id;
	u64 inode;
	char name[TASK_COMM_LEN];
};

BPF_HASH(open_files, struct key_t);

int trace_open(struct pt_regs *ctx) {
	struct key_t key = {};
	u64 id = bpf_get_current_pid_tgid();
	
	key.id = id >> 32;
	key.inode = PT_REGS_RC(ctx);
	bpf_get_current_comm(&key.name, sizeof(key.name));
	open_files.update(&key, &id);

	return 0;
}

int trace_close(struct pt_regs *ctx) {
	struct key_t key = {};
	u64 id = bpf_get_current_pid_tgid();

	key.id = id >> 32;
	key.inode = PT_REGS_RC(ctx);
	bpf_get_current_comm(&key.name, sizeof(key.name));
	open_files.delete(&key);

	return 0;
}
`

type fileKey struct {
	ID    int32
	Inode uint64
	Name  [16]byte
}

func main() {
	m := bpf.NewModule(source, []string{})
	defer m.Close()

	openFD, err := m.LoadUprobe("trace_open")
	if err != nil {
		fmt.Println(err)
		return
	}

	closeFD, err := m.LoadUprobe("trace_close")
	if err != nil {
		fmt.Println(err)
		return
	}

	err = m.AttachUprobe("/path/to/binary", "open", openFD)
	if err != nil {
		fmt.Println(err)
		return
	}

	err = m.AttachUretprobe("/path/to/binary", "close", closeFD)
	if err != nil {
		fmt.Println(err)
		return
    }

    table := bpf.NewTable(m.TableId("open_files"), m)

	channel := make(chan []byte)
	perfMap, err := bpf.InitPerfMap(table, channel)
	if err != nil {
		fmt.Println(err)
		return
    }

	go func() {
        for data := range channel {
            var key fileKey
			err = binary.Read(bytes.NewBuffer(data), binary.LittleEndian, &key)
			if err != nil {
				fmt.Println(err)
				continue
			}
			
            fmt.Printf("Process: %s opened file with inode %d\n", string(key.Name[:]), key.Inode)
        }
    }()
	
	select {}
}
  1. 监控TCP连接:
package main

import (
    "fmt"
    "os"

	bpf "github.com/iovisor/gobpf/bcc"
)

const source string = `
#include <uapi/linux/ptrace.h>
#include <linux/sched.h>

struct key_t {
	u64 ip;
	u64 pid;
};

BPF_HASH(tcp_connections, struct key_t);

int trace_connect(struct pt_regs *ctx) {
	struct key_t key = {};
	u64 ip = PT_REGS_RC(ctx);
	u64 pid = bpf_get_current_pid_tgid();

	key.ip = ip;
	key.pid = pid;
	tcp_connections.update(&key, &ip);

	return 0;
}

int trace_accept(struct pt_regs *ctx) {
	struct key_t key = {};
	u64 ip = PT_REGS_RC(ctx);
	u64 pid = bpf_get_current_pid_tgid();

	key.ip = ip;
	key.pid = pid;
	tcp_connections.update(&key, &ip);

	return 0;
}
`

type connectionKey struct {
	IP  uint64
	PID uint64
}

func main() {
	m := bpf.NewModule(source, []string{})
	defer m.Close()

	connectFD, err := m.LoadUprobe("trace_connect")
	if err != nil {
		fmt.Println(err)
		return
	}

	acceptFD, err := m.LoadUprobe("trace_accept")
	if err != nil {
		fmt.Println(err)
		return
    }

    err = m.AttachUprobe("/path/to/binary", "connect", connectFD)
	if err != nil {
		fmt.Println(err)
		return
    }
    
	err = m.AttachUprobe("/path/to/binary", "accept", acceptFD)
	if err != nil {
		fmt.Println(err)
		return
    }

    table := bpf.NewTable(m.TableId("tcp_connections"), m)

	it := table.Iter()
	for it.Next() {
		var key connectionKey
        var ip uint64

        if binary.Read(bytes.NewBuffer(it.Key()), binary.LittleEndian, &key) == nil && 
           binary.Read(bytes.NewBuffer(it.Leaf()), binary.LittleEndian, &ip) == nil {

            fmt.Printf("Process with PID %d connected to IP %d\n", key.PID, ip)
        }
    }
}
  1. 监控内存分配:

”`go package main

import (

"fmt"
"os"

bpf "github.com/iovisor/gobpf/bcc"

)

const source string = ` #include

BPF_HASH(allocations, u64);

int trace


内容由零声教学AI助手提供,问题来源于学员提问

本站部分文章来源于网络,版权归原作者所有,如有侵权请联系站长删除。
转载请注明出处:https://golang.0voice.com/?id=18474

分享:
扫描分享到社交APP
上一篇
下一篇
发表列表
游客 游客
此处应有掌声~
评论列表

还没有评论,快来说点什么吧~

联系我们

在线咨询: 点击这里给我发消息

微信号:3007537140

上班时间: 10:30-22:30

关注我们
x

注册

已经有帐号?