简介
之前一直用 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.go
和 server/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 字段设置,不改也无所谓,因为设置也不会生效了
能不能写一个用mysql存储的修改?十分感谢
sqlite3 驱动改成 mysql 驱动
github.com/go-sql-driver/mysql
然后新建数据库链接的代码改成
db, _ = sql.Open("mysql", "root:root@/127.0.0.1")
大体就这样,没测试
你好,能不能再出个编译介绍,网上找了下,没找到。
直接用 docker 编译就可以了,https://github.com/lzxz1234/frp/blob/master/Dockerfile,镜像编译完从里面拷出来就行,里面包含了所有平台的客户端和服务端了