Files
v2ray_simple/proxy/proxy.go
e1732a364fed f28f0d0bee 修订代码, 默认loglevel 改为 Log_info.
对一般用户而言,还是需要使用Info等级 来了解一下 一般的 日志情况,等到使用熟练之后,且确认运行没有错误后, 可以自行调为 warning 来提升性能

发现 bubble包 还自己引入了 命令行参数,这十分不可取,所以我们还是直接使用其代码。

将其它包中 的 命令行参数 统一 移动 到 cmd/verysimple 中;tls lazy 特性因为还在 调试阶段,所以 命令行参数 仍然放到 v2ray_simple 包中。
2022-04-26 13:22:18 +08:00

569 lines
14 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package proxy
import (
"errors"
"io"
"net"
"strings"
"time"
"github.com/e1732a364fed/v2ray_simple/advLayer/grpc"
"github.com/e1732a364fed/v2ray_simple/advLayer/quic"
"github.com/e1732a364fed/v2ray_simple/advLayer/ws"
"github.com/e1732a364fed/v2ray_simple/httpLayer"
"github.com/e1732a364fed/v2ray_simple/netLayer"
"github.com/e1732a364fed/v2ray_simple/tlsLayer"
"github.com/e1732a364fed/v2ray_simple/utils"
"github.com/xtaci/smux"
"go.uber.org/zap"
)
//配置文件格式
const (
SimpleMode = iota
StandardMode
V2rayCompatibleMode
)
//规定,如果 proxy的server的handshake如果返回的是具有内层mux的连接该连接要实现 MuxMarker 接口.
type MuxMarker interface {
io.ReadWriteCloser
IsMux()
}
//实现 MuxMarker
type MuxMarkerConn struct {
netLayer.ReadWrapper
}
func (mh *MuxMarkerConn) IsMux() {}
//有的客户端可能建立tcp连接后首先由读服务端的数据虽然比较少见但是确实存在
// 总之 firstpayload是有可能读不到的我们尽量减少这个延迟.
// 也有可能是有人通过 nc 来测试,也会遇到这种读不到 firstpayload的情况
const FirstPayloadTimeout = time.Millisecond * 100
// Client 用于向 服务端 拨号.
//服务端是一种 “泛目标”代理,所以我们客户端的 Handshake 要传入目标地址, 来告诉它 我们 想要到达的 目标地址.
// 一个Client 掌握从最底层的tcp等到最上层的 代理协议间的所有数据;
// 一旦一个 Client 被完整定义,则它的数据的流向就被完整确定了.
//
// 然而, udp的转发则不一样. 一般来说, udp只handshake一次, 建立一个通道, 然后在这个通道上
// 不断申请发送到 各个远程udp地址的连接。客户端也可以选择建立多个udp通道。
type Client interface {
ProxyCommon
//进行 tcp承载数据的传输的握手。firstPayload 用于如 vless/trojan 这种 没有握手包的协议,可为空。
//规定, firstPayload 由 utils.GetMTU或者 GetPacket获取, 所以写入之后可以用 utils.PutBytes 放回
Handshake(underlay net.Conn, firstPayload []byte, target netLayer.Addr) (wrappedConn io.ReadWriteCloser, err error)
//建立一个通道, 然后在这个通道上 不断地申请发送到 各个远程udp地址 的连接。理论上target可为空值。
EstablishUDPChannel(underlay net.Conn, target netLayer.Addr) (netLayer.MsgConn, error)
//udp的拨号是否使用了多信道方式
IsUDP_MultiChannel() bool
//获取/拨号 一个可用的内层mux
GetClientInnerMuxSession(wrc io.ReadWriteCloser) *smux.Session
InnerMuxEstablished() bool
CloseInnerMuxSession()
}
// Server 用于监听 客户端 的连接.
// 服务端是一种 “泛目标”代理所以我们Handshake要返回 客户端请求的目标地址
// 一个 Server 掌握从最底层的tcp等到最上层的 代理协议间的所有机制。
// 一旦一个 Server 被完整定义,则它的数据的流向就被完整确定了.
type Server interface {
ProxyCommon
//ReadWriteCloser 为请求地址为tcp的情况, net.PacketConn 为 请求 建立的udp通道
Handshake(underlay net.Conn) (net.Conn, netLayer.MsgConn, netLayer.Addr, error)
//获取/监听 一个可用的内层mux
GetServerInnerMuxSession(wlc io.ReadWriteCloser) *smux.Session
}
// FullName 可以完整表示 一个 代理的 VSI 层级.
// 这里认为, tcp/udp/kcp/raw_socket 是FirstName具体的协议名称是 LastName, 中间层是 MiddleName。
//
// An Example of a full name: tcp+tls+ws+vless.
// 总之,类似【域名】的规则,只不过分隔符从 点号 变成了加号。
func GetFullName(pc ProxyCommon) string {
if n := pc.Name(); n == "direct" {
return n
} else {
return getFullNameBuilder(pc, n).String()
}
}
func getFullNameBuilder(pc ProxyCommon, n string) *strings.Builder {
var sb strings.Builder
sb.WriteString(pc.Network())
sb.WriteString(pc.MiddleName())
sb.WriteString(n)
if i, innerProxyName := pc.HasInnerMux(); i == 2 {
sb.WriteString("+smux+")
sb.WriteString(innerProxyName)
}
return &sb
}
// return GetFullName(pc) + "://" + pc.AddrStr()
func GetVSI_url(pc ProxyCommon) string {
n := pc.Name()
if n == "direct" {
return "direct://"
}
sb := getFullNameBuilder(pc, n)
sb.WriteString("://")
sb.WriteString(pc.AddrStr())
return sb.String()
}
// 给一个节点 提供 VSI中 第 5-7层 的支持, server和 client通用. 个别方法只能用于某一端.
//
// 一个 ProxyCommon 会内嵌proxy以及上面各层的所有信息;
type ProxyCommon interface {
Name() string //代理协议名称, 如vless
MiddleName() string //其它VSI层 所使用的协议,前后被加了加号,如 +tls+ws+
Stop()
getCommon() *ProxyCommonStruct
/////////////////// 网络层/传输层 ///////////////////
GetSockopt() *netLayer.Sockopt
// 地址,若tcp/udp的话则为 ip:port/host:port的形式, 若是 unix domain socket 则是文件路径
// 在 inServer就是监听地址在 outClient就是拨号地址
AddrStr() string
SetAddrStr(string)
Network() string
CantRoute() bool //for inServer
GetTag() string
//如果 IsHandleInitialLayers 方法返回true, 则监听/拨号从传输层一直到高级层的过程直接由inServer/outClient自己处理, 而我们主过程直接处理它 处理完毕的剩下的 代理层。
//
// quic就属于这种接管底层协议的“超级协议”, 可称之为 SuperProxy。
IsHandleInitialLayers() bool
// 在IsHandleInitialLayers时可用 用于 inServer
HandleInitialLayersFunc() func() (newConnChan chan net.Conn, baseConn any)
/////////////////// TLS层 ///////////////////
SetUseTLS()
IsUseTLS() bool
GetTLS_Server() *tlsLayer.Server
GetTLS_Client() *tlsLayer.Client
/////////////////// http 层 ///////////////////
HasHeader() *httpLayer.HeaderPreset
//默认回落地址.
GetFallback() *netLayer.Addr
CanFallback() bool //如果能fallback则handshake失败后可能会专门返回 FallbackErr,如监测到返回了 FallbackErr, 则main函数会进行 回落处理.
Path() string
/////////////////// 高级层 ///////////////////
AdvancedLayer() string //如果使用了ws或者grpc这个要返回 ws 或 grpc
GetWS_Client() *ws.Client //for outClient
GetWS_Server() *ws.Server //for inServer
initWS_client() error //for outClient
initWS_server() error //for inServer
GetGRPC_Server() *grpc.Server
IsGrpcClientMultiMode() bool
initGRPC_server() error
IsMux() bool //如果用了grpc或者quic, 则此方法返回true。这个是用于判断外层mux的。
GetQuic_Client() *quic.Client //for outClient
/////////////////// 内层mux层 ///////////////////
// 判断是否有内层mux。
//0 为不会有 innermux, 1 为有可能有 innermux, 2 为总是使用 innerMux;
// 规定是,客户端 只能返回0或者2 服务端 只能返回 0或者1除非服务端协议不支持不mux的情况此时可以返回2
// string 为 innermux内部的 代理 协议 名称。一般用simplesocks
HasInnerMux() (int, string)
}
// ProxyCommonStruct 实现 ProxyCommon中除了Name 之外的其他方法.
// 规定所有的proxy都要内嵌本struct. 我们用这种方式实现 "继承".
// 这是verysimple的架构所要求的。
// verysimple规定在加载完配置文件后一个listen和一个dial所使用的全部层级都是确定了的.
// 因为所有使用的层级都是确定的,就可以进行针对性优化
type ProxyCommonStruct struct {
listenConf *ListenConf
dialConf *DialConf
Addr string
TLS bool
Tag string //可用于路由, 见 netLayer.route.go
network string
Sockopt *netLayer.Sockopt
tls_s *tlsLayer.Server
tls_c *tlsLayer.Client
header *httpLayer.HeaderPreset
PATH string
cantRoute bool //for inServer, 若为true则 inServer 读得的数据 不会经过分流一定会通过用户指定的remoteclient发出
AdvancedL string
ws_c *ws.Client
ws_s *ws.Server
grpc_s *grpc.Server
grpc_multi bool
FallbackAddr *netLayer.Addr
quic_c *quic.Client
listenCommonConnFunc func() (newConnChan chan net.Conn, baseConn any)
innermux *smux.Session //用于存储 client的已拨号的mux连接
}
func (pcs *ProxyCommonStruct) getCommon() *ProxyCommonStruct {
return pcs
}
func (pcs *ProxyCommonStruct) setListenCommonConnFunc(f func() (newConnChan chan net.Conn, baseConn any)) {
pcs.listenCommonConnFunc = f
}
func (pcs *ProxyCommonStruct) Network() string {
return pcs.network
}
func (pcs *ProxyCommonStruct) Path() string {
return pcs.PATH
}
func (pcs *ProxyCommonStruct) setPath(a string) {
pcs.PATH = a
}
func (pcs *ProxyCommonStruct) HasHeader() *httpLayer.HeaderPreset {
return pcs.header
}
func (pcs *ProxyCommonStruct) setHeader(h *httpLayer.HeaderPreset) {
pcs.header = h
}
func (pcs *ProxyCommonStruct) GetFallback() *netLayer.Addr {
return pcs.FallbackAddr
}
func (pcs *ProxyCommonStruct) setFallback(a netLayer.Addr) {
pcs.FallbackAddr = &a
}
func (pcs *ProxyCommonStruct) MiddleName() string {
var sb strings.Builder
sb.WriteString("")
if pcs.TLS {
sb.WriteString("+tls")
}
if pcs.header != nil {
if pcs.AdvancedL != "ws" {
sb.WriteString("+http")
}
}
if pcs.AdvancedL != "" {
sb.WriteString("+")
sb.WriteString(pcs.AdvancedL)
}
sb.WriteString("+")
return sb.String()
}
func (pcs *ProxyCommonStruct) CantRoute() bool {
return pcs.cantRoute
}
func (pcs *ProxyCommonStruct) InnerMuxEstablished() bool {
return pcs.innermux != nil && !pcs.innermux.IsClosed()
}
//placeholder
func (pcs *ProxyCommonStruct) HasInnerMux() (int, string) {
return 0, ""
}
func (*ProxyCommonStruct) GetServerInnerMuxSession(wlc io.ReadWriteCloser) *smux.Session {
smuxConfig := smux.DefaultConfig()
smuxSession, err := smux.Server(wlc, smuxConfig)
if err != nil {
if ce := utils.CanLogErr("smux.Server call failed"); ce != nil {
ce.Write(
zap.Error(err),
)
}
}
return smuxSession
}
func (pcs *ProxyCommonStruct) CloseInnerMuxSession() {
if pcs.innermux != nil && !pcs.innermux.IsClosed() {
pcs.innermux.Close()
pcs.innermux = nil
}
}
func (pcs *ProxyCommonStruct) GetClientInnerMuxSession(wrc io.ReadWriteCloser) *smux.Session {
if pcs.innermux != nil && !pcs.innermux.IsClosed() {
return pcs.innermux
} else {
smuxConfig := smux.DefaultConfig()
smuxSession, err := smux.Client(wrc, smuxConfig)
if err != nil {
if ce := utils.CanLogErr("smux.Client call failed"); ce != nil {
ce.Write(
zap.Error(err),
)
}
}
pcs.innermux = smuxSession
return smuxSession
}
}
//return false. As a placeholder.
func (pcs *ProxyCommonStruct) IsUDP_MultiChannel() bool {
return false
}
func (pcs *ProxyCommonStruct) GetTag() string {
return pcs.Tag
}
func (pcs *ProxyCommonStruct) GetSockopt() *netLayer.Sockopt {
return pcs.Sockopt
}
func (pcs *ProxyCommonStruct) setTag(tag string) {
pcs.Tag = tag
}
func (pcs *ProxyCommonStruct) setNetwork(network string) {
if network == "" {
pcs.network = "tcp"
} else {
pcs.network = network
}
}
func (pcs *ProxyCommonStruct) setCantRoute(cr bool) {
pcs.cantRoute = cr
}
func (pcs *ProxyCommonStruct) setAdvancedLayer(adv string) {
pcs.AdvancedL = adv
}
func (pcs *ProxyCommonStruct) AdvancedLayer() string {
return pcs.AdvancedL
}
//try close inner mux
func (s *ProxyCommonStruct) Stop() {
if s.innermux != nil {
s.innermux.Close()
}
}
//return false. As a placeholder.
func (s *ProxyCommonStruct) CanFallback() bool {
return false
}
func (s *ProxyCommonStruct) IsHandleInitialLayers() bool {
return s.AdvancedL == "quic"
}
func (pcs *ProxyCommonStruct) setTLS_Server(s *tlsLayer.Server) {
pcs.tls_s = s
}
func (s *ProxyCommonStruct) setTLS_Client(c *tlsLayer.Client) {
s.tls_c = c
}
func (s *ProxyCommonStruct) GetTLS_Server() *tlsLayer.Server {
return s.tls_s
}
func (s *ProxyCommonStruct) GetTLS_Client() *tlsLayer.Client {
return s.tls_c
}
func (s *ProxyCommonStruct) AddrStr() string {
return s.Addr
}
func (s *ProxyCommonStruct) SetAddrStr(a string) {
s.Addr = a
}
func (s *ProxyCommonStruct) IsUseTLS() bool {
return s.TLS
}
func (s *ProxyCommonStruct) IsGrpcClientMultiMode() bool {
return s.grpc_multi
}
func (s *ProxyCommonStruct) IsMux() bool {
switch s.AdvancedL {
case "grpc", "quic":
return true
}
return false
}
func (s *ProxyCommonStruct) HandleInitialLayersFunc() func() (newConnChan chan net.Conn, baseConn any) {
return s.listenCommonConnFunc
}
func (s *ProxyCommonStruct) SetUseTLS() {
s.TLS = true
}
func (s *ProxyCommonStruct) setListenConf(lc *ListenConf) {
s.listenConf = lc
}
func (s *ProxyCommonStruct) setDialConf(dc *DialConf) {
s.dialConf = dc
}
func (s *ProxyCommonStruct) GetQuic_Client() *quic.Client {
return s.quic_c
}
func (s *ProxyCommonStruct) setQuic_Client(c *quic.Client) {
s.quic_c = c
}
func (s *ProxyCommonStruct) GetWS_Client() *ws.Client {
return s.ws_c
}
func (s *ProxyCommonStruct) GetWS_Server() *ws.Server {
return s.ws_s
}
func (s *ProxyCommonStruct) GetGRPC_Server() *grpc.Server {
return s.grpc_s
}
func (s *ProxyCommonStruct) initWS_client() error {
if s.dialConf == nil {
return errors.New("initWS_client failed when no dialConf assigned")
}
path := s.dialConf.Path
if path == "" { // 至少Path需要为 "/"
path = "/"
}
var useEarlyData bool
if s.dialConf.Extra != nil {
if thing := s.dialConf.Extra["ws_earlydata"]; thing != nil {
if use, ok := thing.(bool); ok && use {
useEarlyData = true
}
}
}
var c *ws.Client
var e error
if s.header != nil {
c, e = ws.NewClient(s.dialConf.GetAddrStr(), path, s.header.Request.Headers)
} else {
c, e = ws.NewClient(s.dialConf.GetAddrStr(), path, nil)
}
if e != nil {
return utils.ErrInErr{ErrDesc: "initWS_client failed", ErrDetail: e}
}
c.UseEarlyData = useEarlyData
s.ws_c = c
return nil
}
func (s *ProxyCommonStruct) initWS_server() error {
if s.listenConf == nil {
return errors.New("initWS_server failed when no listenConf assigned")
}
path := s.listenConf.Path
if path == "" { // 至少Path需要为 "/"
path = "/"
}
var useEarlyData bool
if s.listenConf.Extra != nil {
if thing := s.listenConf.Extra["ws_earlydata"]; thing != nil {
if use, ok := thing.(bool); ok && use {
useEarlyData = true
}
}
}
var wss *ws.Server
if s.header != nil {
wss = ws.NewServer(path, s.header.Response.Headers)
} else {
wss = ws.NewServer(path, nil)
}
wss.UseEarlyData = useEarlyData
s.ws_s = wss
return nil
}
func (s *ProxyCommonStruct) initGRPC_server() error {
if s.listenConf == nil {
return errors.New("initGRPC_server failed when no listenConf assigned")
}
serviceName := s.listenConf.Path
if serviceName == "" { //不能为空
return errors.New("initGRPC_server failed, path must be specified")
}
s.grpc_s = grpc.NewServer(serviceName)
return nil
}