FRP 更改多 Token 支持

简介

之前一直用 Ngrok,但 Ngrok 有比较严重的内存泄露问题,经常无故退出。所以最近更改到了 frp。

frp 是一个可用于内网穿透的高性能的反向代理应用,支持 tcp, udp, http, https 协议。

由于 frp 默认只支持一个 token,这样当 token 泄露更改时会导致全部客户端不可用,所以就有了本次修改。

过程

先 fork 代码库 https://github.com/fatedier/frp,简单阅读后可知,登录时 token 校验逻辑位于 server/service.go 文件中第 320 行:

if util.GetAuthKey(g.GlbServerCfg.Token, loginMsg) != loginMsg.PrivilegeKey {

所以我们可以新建 server/auth.go 主要处理授权逻辑:

package server

import (
    "database/sql"
    "github.com/fatedier/frp/models/msg"
    "github.com/fatedier/frp/utils/util"
    _ "github.com/mattn/go-sqlite3"
)

var db *sql.DB

type User struct {
    UserName string
    Token string
}

func GetAuthKey(loginMsg *msg.Login) (key string) {

    user := GetUser(loginMsg.User)
    key = util.GetAuthKey(user.Token, loginMsg.Timestamp)
    return
}

func GetToken(loginMsg *msg.Login) (key string) {

    user := GetUser(loginMsg.User)
    key = user.Token
    return
}

func GetUser(userName string) (user User) {

    if db == nil {
        db, _ = sql.Open("sqlite3", "/sqlite3.db")
        db.Exec("create table if not exists user(user_name varchar(128), token varchar(128))")
    }

    stmt, _ := db.Prepare("SELECT user_name, token FROM user where user_name = ?")
    defer stmt.Close()
    rows, _ := stmt.Query(userName)
    defer rows.Close()

    if rows.Next() {
        rows.Scan(&user.UserName, &user.Token)
    }
    return
}

此处将用户信息存储在了 sqlite3 中,同时将用户做成实体,后续可以根据用户限制代理类型个数等。同时由于引用了 github.com/mattn/go-sqlite3 包,所以也需要在 vendor 目录里添加对应包。

其它修改

除了登录时的 token 校验,还有其它地方也需要同步修改,主要是 server/control.goserver/proxy.go,这两个文件的修改主要用于替换 token 的获取逻辑,由全局获取改为数据库获取:

control.go

212 行改为:

encWriter, err := crypto.NewWriter(ctl.conn, []byte(GetToken(ctl.loginMsg)))

242 行改为:

encReader := crypto.NewReader(ctl.conn, []byte(GetToken(ctl.loginMsg)))

proxy.go

311 行改为:

rwc, err = frpIo.WithEncryption(rwc, []byte(GetToken(pxy.ctl.loginMsg)))

669 行改为:

local, err = frpIo.WithEncryption(local, []byte(GetToken(pxy.GetControl().loginMsg)))

All Done!

到此重新编辑部署就可以了,更多还可以删除 cmd\frps 目录里启动命令里的 Token 字段设置,不改也无所谓,因为设置也不会生效了

4 comments

    1. sqlite3 驱动改成 mysql 驱动 github.com/go-sql-driver/mysql
      然后新建数据库链接的代码改成 db, _ = sql.Open("mysql", "root:root@/127.0.0.1")
      大体就这样,没测试

        1. 直接用 docker 编译就可以了,https://github.com/lzxz1234/frp/blob/master/Dockerfile,镜像编译完从里面拷出来就行,里面包含了所有平台的客户端和服务端了

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注