内网穿透工具【frp】的核心功能底层处理逻辑解析

文章目录


概述

frp(Fast Reverse Proxy)是一个高性能的反向代理应用,专注于内网穿透。本文档详细介绍了frp核心功能的底层处理逻辑,帮助第一次接触该项目的开发者深入理解其技术架构和实现原理。

技术架构

整体架构模式

frp采用典型的客户端-服务器(C/S)架构模式,包含以下核心组件:
外部用户 frps服务端 内网客户端frpc 本地服务 ControlManager ProxyManager PluginManager ProxyManager VisitorManager Control连接

核心组件关系

1. 服务端核心组件

  • Service: 服务端主服务,负责管理所有连接和组件
  • ControlManager: 管理所有客户端控制连接
  • ProxyManager: 管理所有代理实例
  • MessageTransporter: 消息传输层,处理客户端-服务端通信

2. 客户端核心组件

  • Service: 客户端主服务,管理与服务端的连接
  • Control: 控制连接管理器,维护与服务端的控制通道
  • ProxyManager: 管理客户端代理实例
  • VisitorManager: 管理访问者连接(用于P2P)

核心处理流程

1. 连接建立流程

客户端登录过程

frpc客户端 frps服务端 ControlManager 发送Login消息 验证认证信息 创建Control实例 返回LoginResp消息 建立控制连接 发送ReqWorkConn请求 创建工作连接 frpc客户端 frps服务端 ControlManager

核心代码逻辑

  1. 客户端登录

    • 客户端发送Login消息包含版本、主机名、认证信息
    • 服务端验证认证信息(Token或OIDC)
    • 创建唯一的RunID标识客户端会话
  2. 控制连接建立

    go 复制代码
    // 服务端创建Control实例
    ctl, err := NewControl(ctx, rc, pxyManager, pluginManager, 
                          authVerifier, ctlConn, !internal, loginMsg, serverCfg)
    
    // 客户端创建Control实例
    ctl := &Control{
        sessionCtx:     sessionCtx,
        msgDispatcher:  msg.NewDispatcher(conn),
        msgTransporter: transport.NewMessageTransporter(dispatcher.SendChannel()),
    }

2. 消息处理机制

消息分发架构

frp使用了一套完善的消息处理系统,类似于HTTP2的多路复用机制:
网络连接 MessageDispatcher 消息解析 类型路由 Handler处理 MessageTransporter 消息发送 响应等待 响应分发

核心实现

  1. 消息分发器(Dispatcher)

    go 复制代码
    type Dispatcher struct {
        rw io.ReadWriter
        sendCh         chan Message
        msgHandlers    map[reflect.Type]func(Message)
        defaultHandler func(Message)
    }
    
    // 注册消息处理器
    dispatcher.RegisterHandler(&msg.NewProxy{}, handleNewProxy)
    dispatcher.RegisterHandler(&msg.ReqWorkConn{}, handleReqWorkConn)
  2. 消息传输器(MessageTransporter)

    go 复制代码
    type MessageTransporter interface {
        Send(msg.Message) error
        Do(ctx context.Context, req msg.Message, laneKey, recvMsgType string) (msg.Message, error)
        Dispatch(m msg.Message, laneKey string) bool
    }
  3. 消息类型系统

    • 支持多种消息类型:Login、NewProxy、ReqWorkConn、StartWorkConn等
    • 每种消息都有对应的处理逻辑和响应机制

3. 代理创建与管理

代理生命周期管理

发送NewProxy 服务端确认 启动失败 关闭代理 重试 健康检查失败 重新启动 ProxyPhaseNew ProxyPhaseWaitStart ProxyPhaseRunning ProxyPhaseStartErr ProxyPhaseClosed ProxyPhaseCheckFailed

核心处理逻辑

  1. 代理工厂模式

    go 复制代码
    var proxyFactoryRegistry = map[reflect.Type]func(*BaseProxy, v1.ProxyConfigurer) Proxy{}
    
    func RegisterProxyFactory(proxyConfType reflect.Type, factory func(*BaseProxy, v1.ProxyConfigurer) Proxy) {
        proxyFactoryRegistry[proxyConfType] = factory
    }
  2. 代理包装器(Wrapper)

    • 管理代理状态和生命周期
    • 实现健康检查机制
    • 处理重连和错误恢复
  3. 工作连接处理

    go 复制代码
    func (pm *Manager) HandleWorkConn(name string, workConn net.Conn, m *msg.StartWorkConn) {
        pw, ok := pm.proxies[name]
        if ok {
            pw.InWorkConn(workConn, m)  // 将工作连接分发给对应代理
        }
    }

4. 心跳与连接保活

心跳机制

客户端 服务端 Ping消息 Pong响应 检查Pong超时 重连或关闭 alt [超时检测] 检查Ping超时 关闭连接 alt [服务端检测] loop [心跳循环] 客户端 服务端

实现细节

  1. 心跳发送

    go 复制代码
    func (ctl *Control) heartbeatWorker() {
        sendHeartBeat := func() (bool, error) {
            pingMsg := &msg.Ping{}
            ctl.sessionCtx.AuthSetter.SetPing(pingMsg)
            return false, ctl.msgDispatcher.Send(pingMsg)
        }
        
        go wait.BackoffUntil(sendHeartBeat, backoffManager, true, ctl.doneCh)
    }
  2. 超时检测

    • 客户端检测Pong消息超时
    • 服务端检测Ping消息超时
    • 超时后自动重连或关闭连接

高级功能实现

1. P2P模式与NAT穿透

NAT类型分类

frp实现了智能的NAT类型检测和穿透算法:
NAT类型检测 STUN服务器探测 地址映射分析 NAT类型 EasyNAT: 端口固定 HardNAT: 端口变化 行为分析 端口变化规律 BehaviorNoChange BehaviorPortChanged BehaviorIPChanged BehaviorBothChanged

穿透模式选择

go 复制代码
type NatFeature struct {
    NatType            string  // EasyNAT/HardNAT
    Behavior           string  // 端口变化行为
    PortsDifference    int     // 端口差值
    RegularPortsChange bool    // 是否规律变化
    PublicNetwork      bool    // 是否公网
}

穿透算法

  1. 模式0: 双方都是EasyNAT或一方在公网

    • 简单的双向探测
    • 低TTL消息探测
  2. 模式1: HardNAT与EasyNAT,端口变化规律

    • 多端口范围探测
    • 基于端口预测算法
  3. 模式2: HardNAT与EasyNAT,端口变化不规律

    • 随机端口探测
    • 多监听端口策略
  4. 模式3/4: 双HardNAT场景

    • 复合探测策略
    • 适应性算法选择

穿透实现流程

Visitor frps服务端 Client NatHoleVisitor消息 NatHoleClient消息 分析NAT特征 选择穿透策略 NatHoleResp(策略A) NatHoleResp(策略B) UDP探测包 UDP探测包 par [并发穿透] 建立P2P连接 Visitor frps服务端 Client

2. 多协议支持架构

代理类型工厂

go 复制代码
// 通用TCP代理
type GeneralTCPProxy struct {
    *BaseProxy
}

// UDP代理
type SUDPProxy struct {
    *BaseProxy
    cfg *v1.SUDPProxyConfig
    localAddr *net.UDPAddr
}

// HTTP代理(继承TCP)
func init() {
    RegisterProxyFactory(reflect.TypeOf(&v1.TCPProxyConfig{}), NewGeneralTCPProxy)
    RegisterProxyFactory(reflect.TypeOf(&v1.HTTPProxyConfig{}), NewGeneralTCPProxy)
    RegisterProxyFactory(reflect.TypeOf(&v1.SUDPProxyConfig{}), NewSUDPProxy)
}

协议处理差异

  1. TCP类协议 (TCP/HTTP/HTTPS):

    • 使用GeneralTCPProxy统一处理
    • 支持连接池和多路复用
    • HTTP协议额外支持虚拟主机路由
  2. UDP协议 (UDP/SUDP):

    • 无连接状态管理
    • 数据包级别的转发
    • 支持NAT穿透
  3. 特殊协议 (STCP/XTCP):

    • STCP:安全的内网直连
    • XTCP:P2P模式的大数据传输

3. 连接池与多路复用

工作连接池设计

控制连接 工作连接池 WorkConn1 WorkConn2 WorkConn3 用户请求 代理分发

实现机制

go 复制代码
type Control struct {
    workConnCh chan net.Conn  // 工作连接池
    poolCount  int             // 池大小
}

func (ctl *Control) GetWorkConn() (net.Conn, error) {
    select {
    case workConn := <-ctl.workConnCh:
        // 获取到连接后,请求服务端补充新连接
        ctl.msgDispatcher.Send(&msg.ReqWorkConn{})
        return workConn, nil
    case <-time.After(timeout):
        return nil, fmt.Errorf("获取工作连接超时")
    }
}

安全机制

1. 传输安全

  • TLS加密:控制和数据连接加密
  • Token验证:防止未授权访问
  • IP白名单:访问控制

2. 访问控制

  • 用户权限:基于用户的代理访问控制
  • 域名限制:HTTP代理的域名白名单
  • 端口限制:服务端端口使用限制

项目地址

作者:https://afdian.com/a/fatedier

源码:https://github.com/fatedier/frp

在线文档:https://gofrp.org/zh-cn/docs/

相关推荐
上海控安14 分钟前
上海控安:汽车API安全-风险与防护策略解析
网络·安全·汽车
wuyang-ligerj2 小时前
BGP路由协议(一):基本概念
运维·网络·网络协议·智能路由器
陈天cjq2 小时前
WebSocket 技术详解:协议原理、握手到生产落地的一站式实践
网络·websocket·网络协议
btyzadt3 小时前
Xray与XPOC工具对比分析
网络·安全·web安全
蜗牛沐雨3 小时前
HTTP 范围请求:为什么你的下载可以“断点续传”?
网络·网络协议·http
key_Go4 小时前
02.<<设备登录管理:掌握华为网络设备的本地与远程登录技巧>>
运维·服务器·网络·华为
Serverless社区4 小时前
FunctionAI 图像生成:简化从灵感到 API 调用的每一步
go
RokFile5 小时前
Go 高可用 YAML 生成利器:深入解析 yamlc
go
superlls5 小时前
(计算机网络)TCP 三握中第三次 ACK 丢失会发生什么?
网络·网络协议·tcp/ip