OpenGFW 源码分析

17 Mar 2024 | net, code

修订历史

  • 2024.03.08 创建笔记

前置知识

expr-lang 是方便与 go 应用集成的表达式引擎:

env := map[string]interface{}{
	"greet":   "Hello, %v!",
	"names":   []string{"world", "you"},
	"sprintf": fmt.Sprintf,
}
code := `sprintf(greet, names[0])`
program, err := expr.Compile(code, expr.Env(env))
output, err := expr.Run(program, env)   // output: Hello, world!

gopacket 提供了一组 API,可以用于捕获、解析、分析和构造各种类型的网络数据包

https://colobu.com/2019/06/01/packet-capture-injection-and-analysis-gopacket/

内核网络通信模块

原理

  1. 内核通过 nfqueue 回调函数,将网络数据传给 opengfw
  2. gopacket 分析网络数据的协议,抽取出所需字段
  3. expr-lang 编译配置文件中的规则,结合协议字段的值,执行规则获得裁决结果
  4. opengfw 通过 go-nfqueue 将数据裁决结果通知给内核

目录结构

核心代码

// engine/engine.go
func (e *engine) Run(ctx context.Context) error {
    ...
    for _, w := range e.workers {
		go w.Run(ioCtx)
	}

	for _, i := range e.ioList {
		ioEntry := i
		err := ioEntry.Register(ioCtx, func(p io.Packet, err error) bool {
            ...
			return e.dispatch(ioEntry, p)
		})
        ...
	}
    ...
}

func (e *engine) dispatch(ioEntry io.PacketIO, p io.Packet) bool {
    ...
    e.workers[index].Feed(&workerPacket{
		StreamID: p.StreamID(),
		Packet:   packet,
		SetVerdict: func(v io.Verdict, b []byte) error {
			return ioEntry.SetVerdict(p, v, b)
		},
	})
}

// engine/worker.go
func (w *worker) Feed(p *workerPacket) {
	w.packetChan <- p
}

func (w *worker) Run(ctx context.Context) {
    ...
	for {
		select {
		case wPkt := <-w.packetChan:
            ...
			v, b := w.handle(wPkt.StreamID, wPkt.Packet)
			_ = wPkt.SetVerdict(v, b)
		}
        ...
	}
}

// engine/tcp.go
func (s *tcpStream) ReassembledSG(sg reassembly.ScatterGather, ac reassembly.AssemblerContext) {
    ...
    // feed 每一个 analyzer,抽取出字段
	for i := len(s.activeEntries) - 1; i >= 0; i-- {
    	entry := s.activeEntries[i]
		update, closeUpdate, done := s.feedEntry(entry, rev, start, end, skip, data)
        ...
    }
    if updated || s.virgin {
        // 字段集合作为输入,执行每一条表达式
		result := s.ruleset.Match(s.info)
        ...
    }
    ...
}

其他


Older · View Archive (37)

Bocker - Docker implemented in around 100 lines of bash

Newer

收集一些 buzzword