专栏首页Serverless+使用 BPF 进行 HTTPS 抓包 —— 以 Golang 和 cURL 为例
原创

使用 BPF 进行 HTTPS 抓包 —— 以 Golang 和 cURL 为例

背景

分析某些业务进程的 HTTPS 请求时,类似 tcpdump 和 Fiddler 等工具无法获得请求明文,不方便进行分析。本文探讨使用 BPF 解决 HTTPS 的可观测性问题。

实验环境

  • 内核版本 4.1 及以上的 Linux 机器
  • 未删除符号表的目标二进制

操作步骤

  • 阅读源码,找到要插入探针的函数
  • 编写代码,捕获 HTTPS 请求并打印

Golang 示例

目标程序

一个简单的示例,向第一个命令行参数指定的 URL 发起 HTTP GET 请求,目标进程代码如下:

package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
)

func main() {
	resp, err := http.Get(os.Args[1])
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		panic(err)
	}
	fmt.Println(string(data))
}

探针代码

稍稍阅读一下 Go 标准库的代码就知道,我们要插入的探针的代码位点在:

crypto/tls.(*Conn).writeRecordLocked(typ recordType, data []byte)

第二个参数就是我们所需要的,知道了这个我们就可以插入探针输出这个参数了

探针代码如下:

#include <uapi/linux/ptrace.h>

BPF_PERF_OUTPUT(trace);

inline int crack_https(struct pt_regs *ctx) {
    u8 buf[256] = {0};
    u64* addr = (u64*)ctx->sp;
    u64 val = 0;

    bpf_probe_read(&val, sizeof(val), addr + 2);
    if (val != 23) {
        return 0;
    }

    val = 0;
    bpf_probe_read(&val, sizeof(val), addr + 3);
    addr = (u64*)val;
    bpf_probe_read(buf, sizeof(buf), addr);

    trace.perf_submit(ctx, &buf, sizeof(buf));
    return 0;
}

实验结果

bpf-https-golang.png

cURL 示例

目标程序

以 curl 7.68.0 为例。通常情况下,各 Linux 发行版上实用程序的符号表可能被 strip 掉了,所以需要获取代码重新编译,此过程略去不表。

探针代码

稍稍阅读一下 cURL 的源代码就知道,我们要插入的探针的代码位点在:

CURLcode Curl_add_buffer_send(Curl_send_buffer **inp,
                              struct connectdata *conn,

                              /* add the number of sent bytes to this
                                 counter */
                              curl_off_t *bytes_written,

                              /* how much of the buffer contains body data */
                              size_t included_body_bytes,
                              int socketindex)

Curl_send_buffer 的定义如下:

struct Curl_send_buffer {
  char *buffer;
  size_t size_max;
  size_t size_used;
};

探针代码如下:

#include <uapi/linux/ptrace.h>

BPF_PERF_OUTPUT(trace);

inline int crack_https(struct pt_regs *ctx) {
    u8 buf[256] = {0};
    u64 val = 0;

    // Curl_send_buffer**
    u64* addr = (u64*)ctx->di;

    // Curl_send_buffer*
    bpf_probe_read(&val, sizeof(val), addr);
    addr = (u64*)val;

    // Curl_send_buffer
    bpf_probe_read(&val, sizeof(val), addr);
    addr = (u64*)val;

    // Curl_send_buffer.buffer
    bpf_probe_read(buf, sizeof(buf), addr);

    trace.perf_submit(ctx, &buf, sizeof(buf));
    return 0;
}

实验结果

bpf-https-curl.png

总结

本文通过两个简单的例子,演示了如何使用 BPF 解决 HTTPS 的可观测性问题。大多数使用 Golang 编写的应用程序都会使用标准库,故上文的 Golang 示例具有通用性,我们可以很方便地追踪分析所有 Golang 程序的 HTTPS 调用

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 使用 BPF 进行 HTTPS 抓包 —— 以 Golang 和 cURL 为例

    分析某些业务进程的 HTTPS 请求时,类似 tcpdump 和 Fiddler 等工具无法获得请求明文,不方便进行分析。本文探讨使用 BPF 解决 HTTPS...

    啦啦啦
  • 云原生项目实践DevOps(GitOps)+K8S+BPF+SRE,从0到1使用Golang开发生产级麻将游戏服务器—第3篇

    这将是一个完整的,完全践行 DevOps/GitOps 与 Kubernetes 上云流程的 Golang 游戏服务器开发的系列教程。

    为少
  • 性能工具之 Goreplay 安装及入门使用

    只需要在生产服务器上启动一个 gor 进程,它负责所有的工作包括监听、过滤和转发。它的设计遵循 Unix 设计哲学:一切都是由管道组成的,各种输入将数据复用为输...

    高楼Zee
  • 程序员开发效率神器汇总!

    本文作者:neonliu,腾讯 CSIG 开发工程师 neon 是鹅厂的一位资深后台开发工程师,多年工作下来他总结了很多效率神器,今天分享给大家。 一. 开发...

    腾讯大讲堂
  • 程序员开发效率神器汇总!

    ? 本文作者:neonliu,腾讯 CSIG 开发工程师 neon 是鹅厂的一位资深后台开发工程师,多年工作下来他总结了很多效率神器,今天分享给大家。 一. ...

    腾讯技术工程官方号
  • 你的第一个TC BPF 程序

    https://github.com/nevermosby/linux-bpf-learning

    nevermosby
  • 如何使用BPF将SSH会话转换为结构化事件

    Teleport 4.2引入了一个名叫增强型会话记录(Enhanced Session Recording)的新功能,该功能可以接收一个非结构化的SSH会话,并...

    FB客服
  • [译]eBPF 概念和基本原理

    大约一年前,有个朋友想要用 Rust 开发一个 EVM Assembler。在他的一再要求之下,我开始帮忙编写单元测试。那时候我还不大了解操作系统的相关知识,只...

    崔秀龙
  • eBPF技术简介

    “eBPF 是我见过的 Linux 中最神奇的技术,没有之一,已成为 Linux 内核中顶级子模块,从 tcpdump 中用作网络包过滤的经典 cbpf,到成为...

    CNCF
  • 使用 BPF 改变运行中的程序的函数参数

    注意到我们使用 //go:noinline 修饰了 main.greet 函数,防止被编译器内联,方便进行测试验证。

    ritchiechen
  • Cilium使用 (Cilium 3)

    Cilium要求的内核版本比较高,需要对内核进行升级,否则会运行失败。错误日志如minimal supported kernel version is 4.8....

    charlieroro
  • 从零搭建Prometheus监控报警系统

    Prometheus是由SoundCloud开发的开源监控报警系统和时序列数据库(TSDB)。Prometheus使用Go语言开发,是Google BorgMo...

    kubernetes中文社区
  • 使用 BPF 记录 TCP 重传和丢包记录

    在云函数的日常运营中,经常有用户提出要求协助排查网络问题。一般的手段就是使用 tcpdump 抓包,但是部署抓包往往是在问题发生之后,而且抓包后复现的时机也不确...

    ritchiechen
  • 云原生项目实践DevOps(GitOps)+K8S+BPF+SRE,从0到1使用Golang开发生产级麻将游戏服务器—第2篇

    这将是一个完整的,完全践行 DevOps/GitOps 与 Kubernetes 上云流程的 Golang 游戏服务器开发的系列教程。

    为少
  • 实现一个基于XDP_eBPF的学习型网桥

    eBPF技术风靡当下,eBPF字节码正以星火燎原之势被HOOK在Linux内核中越来越多的位置,在这些HOOK点上,我们可以像编写普通应用程序一样编写内核的HO...

    Linux阅码场
  • 使用 BPF 统计网络流量

    本文介绍使用 BPF 统计网络流量。网络流量是云产品的重要计费指标,服务器每秒可以处理上百万的数据包,这也要求有高效的方法来统计流量,而 BPF 最初作为网络包...

    ritchiechen
  • BPF过滤器

    (1)BPF本质上来说是一个设备驱动(devicedriver),能够被应用程序用来读取网络上通过这个网络适配器的包。但是BPF又是一个特殊的驱动,因为它并没有...

    随心助手
  • 调试你的BPF程序

    文章涉及的实验环境和代码可以到这个git repo获取: https://github.com/nevermosby/linux-bpf-learning

    nevermosby
  • Linux 网络分析必备技能:tcpdump 实战详解

    今天要分享的是 tcpdump,它是 Linux 系统中特别有用的网络工具,通常用于故障诊断、网络分析,功能非常的强大。

    KINGYT

扫码关注云+社区

领取腾讯云代金券