v2ray源码阅读
创始人
2024-05-29 05:23:49
0

v2ray 项目学习

我发现自己用go语言写了这个久,没有高级的语言应用,只会用基础的用法进行CRUD。v2ray是一个go语言项目,所以希望借这个项目,来提高自己的go语言编程能力。

Interface定义

  1. common/interfaces.go中,定义了一些interface
Closable
Interruptible
Runnable 含(Closable)
HasType
  1. feature/feature.go 定义了feature interface
type Feature interface {common.HasTypecommon.Runnable
}

启动流程

  1. v2ary.go
  • 定义 Server interface,继承Runnable interface
  • 定义Instance,实现Server的start()和close()方法
type Closable interface {// Close release all resources used by this object, including goroutines.Close() error
}type Runnable interface {// Start starts the runnable object. Upon the method returning nil, the object begins to function properly.Start() errorClosable
}type Server interface {common.Runnable
}// Instance combines all functionalities in V2Ray.
type Instance struct {access             sync.Mutex // 锁features           []features.Feature // instance的功能featureResolutions []resolutionrunning            bool // 运行状态ctx context.Context
}
  1. 初始化Instance:main/main.go:main()->main/main.go:startV2Ray()->v2ary.go:New()方法
// main/main.go
func main() {flag.Parse()printVersion()if *version {return}server, err := startV2Ray()if err != nil {fmt.Println(err)// Configuration error. Exit with a special value to prevent systemd from restarting.os.Exit(23)}if *test {fmt.Println("Configuration OK.")os.Exit(0)}if err := server.Start(); err != nil {fmt.Println("Failed to start", err)os.Exit(-1)}defer server.Close()// Explicitly triggering GC to remove garbage from config loading.runtime.GC(){osSignals := make(chan os.Signal, 1)signal.Notify(osSignals, os.Interrupt, syscall.SIGTERM)<-osSignals}
}func startV2Ray() (core.Server, error) {configFiles, err := getConfigFilePath()if err != nil {return nil, err}config, err := core.LoadConfig(GetConfigFormat(), configFiles[0], configFiles)if err != nil {return nil, newError("failed to read config files: [", configFiles.String(), "]").Base(err)}server, err := core.New(config)if err != nil {return nil, newError("failed to create server").Base(err)}return server, nil
}// v2ray.go
func New(config *Config) (*Instance, error) {var server = &Instance{ctx: context.Background()}err, done := initInstanceWithConfig(config, server)if done {return nil, err}return server, nil
}

配置读取

  1. main/main.go:startV2Ray()方法中,如下行读取配置
	config, err := core.LoadConfig(GetConfigFormat(), configFiles[0], configFiles)
  1. 假设读取的是json格式的配置,main/json/config_json.go中,会读取json,关键看serial.LoadJSONConfig(v)这行,他首先会解析json配置到infra/conf/v2ray.go定义的结构体
type Config struct {Port            uint16                 `json:"port"` // Port of this Point server. Deprecated.LogConfig       *LogConfig             `json:"log"`RouterConfig    *RouterConfig          `json:"routing"`DNSConfig       *DnsConfig             `json:"dns"`InboundConfigs  []InboundDetourConfig  `json:"inbounds"`OutboundConfigs []OutboundDetourConfig `json:"outbounds"`InboundConfig   *InboundDetourConfig   `json:"inbound"`        // Deprecated.OutboundConfig  *OutboundDetourConfig  `json:"outbound"`       // Deprecated.InboundDetours  []InboundDetourConfig  `json:"inboundDetour"`  // Deprecated.OutboundDetours []OutboundDetourConfig `json:"outboundDetour"` // Deprecated.Transport       *TransportConfig       `json:"transport"`Policy          *PolicyConfig          `json:"policy"`Api             *ApiConfig             `json:"api"`Stats           *StatsConfig           `json:"stats"`Reverse         *ReverseConfig         `json:"reverse"`
}

然后会调用jsonConfig.Build(),转化为如下pb格式的结构体。
config.pb.go定义的配置,供V2Ray运行使用。

// Config is the master config of V2Ray. V2Ray takes this config as input and
// functions accordingly.
type Config struct {state         protoimpl.MessageStatesizeCache     protoimpl.SizeCacheunknownFields protoimpl.UnknownFields// Inbound handler configurations. Must have at least one item.Inbound []*InboundHandlerConfig `protobuf:"bytes,1,rep,name=inbound,proto3" json:"inbound,omitempty"`// Outbound handler configurations. Must have at least one item. The first// item is used as default for routing.Outbound []*OutboundHandlerConfig `protobuf:"bytes,2,rep,name=outbound,proto3" json:"outbound,omitempty"`// App is for configurations of all features in V2Ray. A feature must// implement the Feature interface, and its config type must be registered// through common.RegisterConfig.App []*serial.TypedMessage `protobuf:"bytes,4,rep,name=app,proto3" json:"app,omitempty"`// Transport settings.// Deprecated. Each inbound and outbound should choose their own transport// config. Date to remove: 2020-01-13//// Deprecated: Do not use.Transport *transport.Config `protobuf:"bytes,5,opt,name=transport,proto3" json:"transport,omitempty"`// Configuration for extensions. The config may not work if corresponding// extension is not loaded into V2Ray. V2Ray will ignore such config during// initialization.Extension []*serial.TypedMessage `protobuf:"bytes,6,rep,name=extension,proto3" json:"extension,omitempty"`
}

V2Ray Instance运行

  1. Config.App是feature配置,从下面代码中,可看出最重要的四个feature分别是:dns、policy、routing、stats
func initInstanceWithConfig(config *Config, server *Instance) (error, bool) {...essentialFeatures := []struct {Type     interface{}Instance features.Feature}{{dns.ClientType(), localdns.New()},{policy.ManagerType(), policy.DefaultManager{}},{routing.RouterType(), routing.DefaultRouter{}},{stats.ManagerType(), stats.NoopManager{}},}for _, f := range essentialFeatures {if server.GetFeature(f.Type) == nil {if err := server.AddFeature(f.Instance); err != nil {return err, true}}}...
}
  1. Instance的feature中inbound.Manager类型feature,里面存储了inboundHandler(虽染inboundHandler被包含在一个feature中,但其实他也算是一个feature)
  2. server.Start()相当于Instance.Start(),其实就相当于Instance.features.start()
func (s *Instance) Start() error {s.access.Lock()defer s.access.Unlock()s.running = truefor _, f := range s.features {if err := f.Start(); err != nil {return err}}newError("V2Ray ", Version(), " started").AtWarning().WriteToLog()return nil
}

Features

InboundHandlerManager、OutboundHandlerManager接口定义

  1. features/inbound/inbound.go:Manager, 暂称作InboundHandlerManager,
type Handler interface {common.RunnableTag() string
}type Manager interface {features.FeatureGetHandler(ctx context.Context, tag string) (Handler, error)AddHandler(ctx context.Context, handler Handler) errorRemoveHandler(ctx context.Context, tag string) error
}func ManagerType() interface{} {return (*Manager)(nil)
}
  1. features/outbound/outbound.go:Manager, 暂称作OutboundHandlerManager,相比于InboundHandlerManager,OutboundHandlerManager的handler多一个Dispatch方法
type Handler interface {common.RunnableTag() stringDispatch(ctx context.Context, link *transport.Link)
}type HandlerSelector interface {Select([]string) []string
}type Manager interface {features.FeatureGetHandler(tag string) HandlerGetDefaultHandler() HandlerAddHandler(ctx context.Context, handler Handler) errorRemoveHandler(ctx context.Context, tag string) error
}func ManagerType() interface{} {return (*Manager)(nil)
}

InboundHandlerManager、OutboundHandlerManager接口实现

  1. app/proxyman/inbound/inbound.go中,实现了InboundHandlerManager,InboundHandlerManager.Start()相当于start所有的untaggedHandler、taggedHandlers
// Manager is to manage all inbound handlers.
type Manager struct {access          sync.RWMutexuntaggedHandler []inbound.HandlertaggedHandlers  map[string]inbound.Handlerrunning         bool
}...// Start implements common.Runnable.
func (m *Manager) Start() error {m.access.Lock()defer m.access.Unlock()m.running = truefor _, handler := range m.taggedHandlers {if err := handler.Start(); err != nil {return err}}for _, handler := range m.untaggedHandler {if err := handler.Start(); err != nil {return err}}return nil
}

InboundHandler、OutboundHandler接口实现

  1. app/proxyman/inbound/always.go、dynamic.go中,实现了InboundHandler,AlwaysInboundHandler.Start()相当于start所有的worker。todo:dynamic的逻辑不一样
type AlwaysOnInboundHandler struct {proxy   proxy.Inboundworkers []workermux     *mux.Servertag     string
}// Start implements common.Runnable.
func (h *AlwaysOnInboundHandler) Start() error {for _, worker := range h.workers {if err := worker.Start(); err != nil {return err}}return nil
}
  1. app/proxyman/inbound/worker.go中定义了worker interface
type worker interface {Start() errorClose() errorPort() net.PortProxy() proxy.Inbound
}
  1. worker interface有两个实现:tcpWorker、udpWorkder
type tcpWorker struct {address         net.Addressport            net.Portproxy           proxy.Inbound //表示采用的代理协议stream          *internet.MemoryStreamConfigrecvOrigDest    booltag             stringdispatcher      routing.DispatchersniffingConfig  *proxyman.SniffingConfiguplinkCounter   stats.CounterdownlinkCounter stats.Counterhub internet.Listenerctx context.Context
}
  1. proxy.Inbound的定义在proxy/proxy.go,他的底层实现有比如vmess、vless、shadowsocks、trojan
// An Inbound processes inbound connections.
type Inbound interface {// Network returns a list of networks that this inbound supports. Connections with not-supported networks will not be passed into Process().Network() []net.Network// Process processes a connection of given network. If necessary, the Inbound can dispatch the connection to an Outbound.Process(context.Context, net.Network, internet.Connection, routing.Dispatcher) error
}

错误日志

  1. common/errors/errors.go 自定义Error
// Error is an error object with underlying error.
type Error struct {pathObj  interface{}prefix   []interface{}message  []interface{}inner    errorseverity log.Severity
}// New returns a new error object with message formed from given arguments.
func New(msg ...interface{}) *Error {return &Error{message:  msg,severity: log.Severity_Info, // 默认日志级别为info}
}

每个目录下,都有一个newError方法,和一个errPathObjHolder。

func newError(values ...interface{}) *errors.Error {return errors.New(values...).WithPathObj(errPathObjHolder{})
}

相关内容

热门资讯

iPhone手机怎么玩安卓系统... 你有没有想过,你的iPhone手机竟然也能玩安卓系统?没错,就是那个一直以来让你觉得遥不可及的安卓世...
平板删安卓系统更新不了,原因及... 最近是不是你也遇到了这样的烦恼?平板电脑上的安卓系统更新不了,是不是让你头疼得要命?别急,今天就来给...
苹果组装机安卓系统卡,卡顿背后... 你有没有发现,最近用苹果手机的时候,有时候系统有点卡呢?这可真是让人头疼啊!你知道吗,其实这背后还有...
安卓系统原生浏览器,功能与体验... 你有没有发现,每次打开手机,那个小小的浏览器窗口总是默默无闻地在那里,陪你浏览网页、搜索信息、看视频...
安卓机如何上苹果系统,跨平台体... 你是不是也和我一样,对安卓机和苹果系统之间的切换充满了好奇?想象你的安卓手机里装满了各种应用,而苹果...
安卓导入系统证书失败,原因分析... 最近在使用安卓手机的时候,你是不是也遇到了一个让人头疼的问题——导入系统证书失败?别急,今天就来给你...
安卓原生系统有哪些手机,盘点搭... 你有没有想过,为什么有些手机用起来就是那么流畅,那么顺心呢?这背后可大有学问哦!今天,就让我带你一起...
安卓系统关机了怎么定位,安卓系... 手机突然关机了,是不是有点慌张呢?别担心,今天就来教你一招,让你的安卓手机即使关机了,也能轻松定位到...
安卓系统游戏加速器,畅享无延迟... 你有没有发现,手机游戏越来越好玩了?不过,有时候游戏体验可能并不那么顺畅,是不是因为手机性能不够强大...
安卓4系统天气功能,尽在掌握 安卓4系统天气功能大揭秘在当今这个数字化的世界里,手机已经不仅仅是一个通信工具,它更是一个集成了各种...
安卓系统如何玩碧蓝幻想,攻略与... 你有没有想过,在安卓系统上玩《碧蓝幻想》竟然可以这么酷炫?没错,就是那个让你沉迷其中的二次元大作!今...
安卓系统搜不到图朵,图朵生成之... 最近是不是你也遇到了这样的烦恼?手机里明明有那么多美美的图片,但是用安卓系统搜索的时候,却怎么也找不...
魁族8刷安卓系统,系统升级后的... 哇,你知道吗?最近在安卓系统圈子里,有一个话题可是引起了不小的轰动,那就是魁族8刷安卓系统。你是不是...
微信正版安装安卓系统,畅享沟通... 你有没有想过,你的微信是不是正版安装的安卓系统呢?这可不是一个小问题哦,它关系到你的微信使用体验和隐...
电视能刷安卓系统吗,电视也能刷... 电视能刷安卓系统吗?揭秘智能电视的无限可能想象你家的电视不再只是用来观看节目的工具,而是变成了一个功...
安卓系统开通通知功能,畅享智能... 你知道吗?最近安卓系统更新后,新增了一个超级实用的功能——开通通知功能!这可是个大喜事,让咱们的生活...
苹果系统安卓爱思助手,系统兼容... 你有没有发现,手机的世界里,苹果系统和安卓系统就像是一对欢喜冤家,总是各有各的粉丝,各有各的拥趸。而...
安卓系统占用很大内存,揭秘内存... 手机里的安卓系统是不是让你感觉内存不够用,就像你的房间堆满了杂物,总是找不到地方放新东西?别急,今天...
安卓系统p30,安卓系统下的摄... 你有没有发现,最近安卓系统P30在手机圈里可是火得一塌糊涂呢!这不,我就来给你好好扒一扒这款手机的那...
siri被安卓系统进入了,智能... 你知道吗?最近科技圈可是炸开了锅,因为一个大家伙——Siri,竟然悄悄地溜进了安卓系统!这可不是什么...