利用v2ray api实现流量统计以及增删用户

首先要知道v2ray(下面简写“v2”)的配置文件格式为json,形式如下:

{
"log": {},
"api": {},
"dns": {},
"stats": {},
"routing": {},
"policy": {},
"reverse": {},
"inbounds": [],
"outbounds": [],
"transport": {}
}

v2配置很多但总体就上面10类,把握这个有助于你写配置。简单解释下这几个含义:

  • log:日志配置
  • api:配置远程控制api
  • dns:配置内置的dns服务器
  • stats:配置数据统计
  • routing:配置路由
  • policy:配置本地策略
  • reverse:配置反向代理
  • inbounds:配置入站连接
  • outbounds:配置出站连接
  • transport:配置如何与其它服务器建立和使用网络连接

这里我们要说的是api,实现用户流量的统计和用户的动态增删。

配置文件

我们先要配置v2文件。要实现流量统计功能,配置内需要确保存在以下配置:

  • “stats”:{} 对象的存在 “policy” 中的统计开关为 true。
  • 全局统计的开关在 “system”下,用户统计的开关在 “levels” 下
  • 全局统计在相应的入站出站要有 tag
  • 用户统计在 “clients” 里面要有 email

要使用 api 查询流量,配置内需要确保存在以下配置:

  • “api” 配置对象里面有 StatsService
  • 专用的 dokodemo-door协议的入口,tag 为
  • api routing 里面有 inboundTag:api outboundTag:api 的规则

配置示例

{
"stats": {},
"api": {
"tag": "api",
"services": [
"HandlerService",
"StatsService"
]
},
"policy": {
"levels": {
"0": {
"statsUserUplink": true, //开启用户流量上传统计
"statsUserDownlink": true //开启用户流量下载统计
}
},
"system": {
"statsInboundUplink": true, //开启入站方向的流量上传
"statsInboundDownlink": true, //开启入站方向的流量下载
"statsOutboundUplink": true, //开启出站方向的流量上传
"statsOutboundDownlink": true //开启出站方向的流量下载
}
},
"inbounds": [
{
"tag": "tcp",
"port": 3307,
"protocol": "vmess",
"settings": {
"clients": [
{
"email": "auser", //定义一个auser用户
"id": "e731f153-4f31-49d3-9e8f-ff8f396135ef",
"level": 0,
"alterId": 64
},
{
"email": "buser", //定义一个buser用户
"id": "e731f153-4f31-49d3-9e8f-ff8f396135ee",
"level": 0,
"alterId": 64
}
]
}
},
{
"listen": "127.0.0.1",
"port": 10085,
"protocol": "dokodemo-door",
"settings": {
"address": "127.0.0.1"
},
"tag": "api"
}
],
"outbounds": [
{
"tag": "direct",
"protocol": "freedom",
"settings": {}
}
],
"routing": {
"settings": {
"rules": [
{
"inboundTag": [
"api"
],
"outboundTag": "api",
"type": "field"
}
]
},
"strategy": "rules"
}
}

v2ctl工具

v2会附带安装v2ctl工具,v2ctl支持多个参数其中一个参数是api,借此我们可以实现流量统计。server参数端口为dokodemo-door的端口。

v2ctl api --server=127.0.0.1:10085 StatsService.QueryStats 'pattern: "" reset: false'
v2ctl api --server=127.0.0.1:10085 StatsService.GetStats 'name: "inbound>>>statin>>>traffic>>>downlink" reset: false'

虽然有v2ctl这个现成工具,但我们还是需要自己写脚本,因为v2ctl只能流量统计,无法实现用户的动态增删。
v2的api其实是打开了一个 grpc 协议的查询接口,我们只要借助任何一个支持grpc协议的语言就能调用。支持grpc协议的有很多,只要安装中间件,php都可跑。我们这里选择官方支持内存占用小的go语言。

go语言实现

先安装go语言,把go放入系统环境。然后下载v2和grpc的包。

go get -insecure v2ray.com/core
go get google.golang.org/grpc

开始写脚本,下面的代码参考了文章:调用 V2Ray 提供的 API 接口进行用户增删及流量统计查询操作。这里为了适合我的v2和go运行做了一点修改,增加了部分代码实现用户流量查询。

package main
import (
"context"
"fmt"
"log"
"google.golang.org/grpc"
"v2ray.com/core/app/proxyman/command"
statsService "v2ray.com/core/app/stats/command"
"v2ray.com/core/common/protocol"
"v2ray.com/core/common/serial"
"v2ray.com/core/proxy/vmess"
)
const (
API_ADDRESS = "127.0.0.1"
API_PORT = 10085
INBOUND_TAG = "tcp"
LEVEL = 0
EMAIL = "123@gmail.com"
UUID = "2601070b-ab53-4352-a290-1d44414581ee"
ALTERID = 32
)
func addUser(c command.HandlerServiceClient) {
resp, err := c.AlterInbound(context.Background(), &command.AlterInboundRequest{
Tag: INBOUND_TAG,
Operation: serial.ToTypedMessage(&command.AddUserOperation{
User: &protocol.User{
Level: LEVEL,
Email: EMAIL,
Account: serial.ToTypedMessage(&vmess.Account{
Id: UUID,
AlterId: ALTERID,
SecuritySettings: &protocol.SecurityConfig{Type: protocol.SecurityType_AUTO},
}),
},
}),
})
if err != nil {
log.Printf("failed to call grpc command: %v", err)
} else {
log.Printf("ok: %v", resp)
}
}
func removeUser(c command.HandlerServiceClient) {
resp, err := c.AlterInbound(context.Background(), &command.AlterInboundRequest{
Tag: INBOUND_TAG,
Operation: serial.ToTypedMessage(&command.RemoveUserOperation{
Email: EMAIL,
}),
})
if err != nil {
log.Printf("failed to call grpc command: %v", err)
} else {
log.Printf("ok: %v", resp)
}
}
func queryUserTraffic(c statsService.StatsServiceClient) {
resp, err := c.QueryStats(context.Background(), &statsService.QueryStatsRequest{
Pattern: "user>>>123@gmail.com>>>traffic>>>uplink", // 筛选用户表达式
Reset_: false, // 查询完成后是否重置流量
})
if err != nil {
log.Printf("failed to call grpc command: %v", err)
}
// 获取返回值中的流量信息
stat := resp.GetStat()
// 返回的是一个数组,对其进行遍历输出
for _, e := range stat {
fmt.Println(e)
}
}

func main() {
cmdConn, err := grpc.Dial(fmt.Sprintf("%s:%d", API_ADDRESS, API_PORT), grpc.WithInsecure())
if err != nil {
panic(err)
}
//hsClient := command.NewHandlerServiceClient(cmdConn)
hsClient_traffic := statsService.NewStatsServiceClient(cmdConn)
//addUser(hsClient)
//removeUser(hsClient)
queryUserTraffic(hsClient_traffic)
}

其他

动手能力强的就可以参考sspanel、v2board等前端面板提供的网页api实现v2后端接入。sspanel面板可以直接参考官方提供的python版ss后端代码写:sspanel配套ss后端

目前v2后端市面上均收费,价格在60-80刀/年,200-300刀/永久,小机场还是有经济压力的,而免费版不到100个用户又是不够用。上面代码实现了流量统计和用户增删,这两个功能其实可以当做一个简单的后端运行了。上报用户ip、审计、限速等功能如果能再完善,基本就算是个完整功能的后端了。