重构代码, 修订文档

This commit is contained in:
e1732a364fed
2022-04-26 09:16:12 +08:00
parent 8725dc513a
commit 9d5b553e01
13 changed files with 299 additions and 283 deletions

View File

@@ -8,8 +8,6 @@ import (
"strconv"
"strings"
vs "github.com/e1732a364fed/v2ray_simple"
"github.com/asaskevich/govalidator"
"github.com/e1732a364fed/v2ray_simple/advLayer/quic"
"github.com/e1732a364fed/v2ray_simple/netLayer"
@@ -195,8 +193,8 @@ func generateConfigFileInteractively() {
"将此次生成的配置投入运行(热加载)",
}
confClient := vs.StandardConf{}
confServer := vs.StandardConf{}
confClient := proxy.StandardConf{}
confServer := proxy.StandardConf{}
var clientStr, serverStr string
@@ -222,7 +220,7 @@ func generateConfigFileInteractively() {
Domains: []string{"geosite:cn"},
}}
confClient.App = &vs.AppConf{MyCountryISO_3166: "CN"}
confClient.App = &proxy.AppConf{MyCountryISO_3166: "CN"}
clientStr, err = utils.GetPurgedTomlStr(confClient)
if err != nil {
@@ -249,8 +247,8 @@ func generateConfigFileInteractively() {
fmt.Printf("\n")
case 2: //clear
confClient = vs.StandardConf{}
confServer = vs.StandardConf{}
confClient = proxy.StandardConf{}
confServer = proxy.StandardConf{}
clientStr = ""
serverStr = ""
case 3: //output
@@ -634,10 +632,10 @@ func interactively_hotRemoveServerOrClient() {
printAllState(os.Stdout)
var items []string
if len(vs.AllServers) > 0 {
if len(AllServers) > 0 {
items = append(items, "listen")
}
if len(vs.AllClients) > 0 {
if len(AllClients) > 0 {
items = append(items, "dial")
}
@@ -667,7 +665,7 @@ func interactively_hotRemoveServerOrClient() {
var theInt int64
if (will_delete_dial && len(vs.AllClients) > 1) || (will_delete_listen && len(vs.AllServers) > 1) {
if (will_delete_dial && len(AllClients) > 1) || (will_delete_listen && len(AllServers) > 1) {
validateFunc := func(input string) error {
theInt, err = strconv.ParseInt(input, 10, 64)
@@ -675,11 +673,11 @@ func interactively_hotRemoveServerOrClient() {
return errors.New("Invalid number")
}
if will_delete_dial && int(theInt) >= len(vs.AllClients) {
if will_delete_dial && int(theInt) >= len(AllClients) {
return errors.New("must with in len of dial array")
}
if will_delete_listen && int(theInt) >= len(vs.AllServers) {
if will_delete_listen && int(theInt) >= len(AllServers) {
return errors.New("must with in len of listen array")
}
@@ -707,15 +705,15 @@ func interactively_hotRemoveServerOrClient() {
will_delete_index = int(theInt)
if will_delete_dial {
vs.AllClients[will_delete_index].Stop()
vs.AllClients = utils.TrimSlice(vs.AllClients, will_delete_index)
AllClients[will_delete_index].Stop()
AllClients = utils.TrimSlice(AllClients, will_delete_index)
}
if will_delete_listen {
vs.ListenerArray[will_delete_index].Close()
vs.AllServers[will_delete_index].Stop()
ListenerArray[will_delete_index].Close()
AllServers[will_delete_index].Stop()
vs.AllServers = utils.TrimSlice(vs.AllServers, will_delete_index)
vs.ListenerArray = utils.TrimSlice(vs.ListenerArray, will_delete_index)
AllServers = utils.TrimSlice(AllServers, will_delete_index)
ListenerArray = utils.TrimSlice(ListenerArray, will_delete_index)
}
@@ -757,7 +755,7 @@ func interactively_hotLoadConfigFile() {
fmt.Printf("你输入了 %s\n", fpath)
standardConf, err = vs.LoadTomlConfFile(fpath)
standardConf, err = proxy.LoadTomlConfFile(fpath)
if err != nil {
log.Printf("can not load standard config file: %s\n", err)

View File

@@ -134,12 +134,12 @@ func printAllState(w io.Writer) {
fmt.Fprintln(w, "allDownloadBytesSinceStart", vs.AllDownloadBytesSinceStart)
fmt.Fprintln(w, "allUploadBytesSinceStart", vs.AllUploadBytesSinceStart)
for i, s := range vs.AllServers {
for i, s := range AllServers {
fmt.Fprintln(w, "inServer", i, proxy.GetFullName(s), s.AddrStr())
}
for i, c := range vs.AllClients {
for i, c := range AllClients {
fmt.Fprintln(w, "outClient", i, proxy.GetFullName(c), c.AddrStr())
}
}
@@ -150,8 +150,8 @@ func tryDownloadGeositeSourceFromConfiguredProxy() {
var outClient proxy.Client
if vs.DefaultOutClient != nil {
outClient = vs.DefaultOutClient
if DefaultOutClient != nil {
outClient = DefaultOutClient
fmt.Println("trying to download geosite through your proxy dial")
} else {
fmt.Println("trying to download geosite directly")
@@ -167,7 +167,7 @@ func tryDownloadGeositeSourceFromConfiguredProxy() {
protocol = "http"
`
clientConf, err := vs.LoadTomlConfStr(tempClientConfStr)
clientConf, err := proxy.LoadTomlConfStr(tempClientConfStr)
if err != nil {
fmt.Println("can not create LoadTomlConfStr: ", err)
@@ -182,7 +182,7 @@ protocol = "http"
listenAddrStr := netLayer.GetRandLocalPrivateAddr(true, false)
clientEndInServer.SetAddrStr(listenAddrStr)
listener = vs.ListenSer(clientEndInServer, outClient, false)
listener = vs.ListenSer(clientEndInServer, outClient, nil)
proxyurl = "http://" + listenAddrStr
@@ -202,23 +202,27 @@ func hotLoadDialConfForRuntime(conf []*proxy.DialConf) {
log.Println("can not create outClient: ", err)
return
}
if vs.DefaultOutClient == nil {
vs.DefaultOutClient = outClient
if DefaultOutClient == nil {
DefaultOutClient = outClient
}
vs.AllClients = append(vs.AllClients, outClient)
AllClients = append(AllClients, outClient)
}
}
func hotLoadListenConfForRuntime(conf []*proxy.ListenConf) {
for _, l := range conf {
for i, l := range conf {
inServer, err := proxy.NewServer(l)
if err != nil {
log.Println("can not create inServer: ", err)
log.Println("can not create inServer: ", i, err)
return
}
vs.ListenSer(inServer, vs.DefaultOutClient, true)
vs.AllServers = append(vs.AllServers, inServer)
lis := vs.ListenSer(inServer, DefaultOutClient, &RoutingEnv)
if lis != nil {
ListenerArray = append(ListenerArray, lis)
AllServers = append(AllServers, inServer)
}
}

View File

@@ -4,6 +4,7 @@ import (
"flag"
"fmt"
"log"
"net"
"os"
"os/signal"
"runtime/pprof"
@@ -11,7 +12,9 @@ import (
"syscall"
vs "github.com/e1732a364fed/v2ray_simple"
"github.com/e1732a364fed/v2ray_simple/httpLayer"
"github.com/e1732a364fed/v2ray_simple/netLayer"
"github.com/e1732a364fed/v2ray_simple/netLayer/tproxy"
"github.com/e1732a364fed/v2ray_simple/proxy"
"github.com/e1732a364fed/v2ray_simple/utils"
"github.com/pkg/profile"
@@ -20,16 +23,35 @@ import (
var (
configFileName string
standardConf vs.StandardConf
startPProf bool
startMProf bool
listenURL string //用于命令行模式
dialURL string //用于命令行模式
jsonMode int
startPProf bool
startMProf bool
standardConf proxy.StandardConf
simpleConf proxy.SimpleConf
AllServers = make([]proxy.Server, 0, 8)
AllClients = make([]proxy.Client, 0, 8)
DefaultOutClient proxy.Client
TproxyList []*tproxy.Machine
ListenerArray []net.Listener
RoutingEnv proxy.RoutingEnv
)
func init() {
flag.StringVar(&configFileName, "c", "client.toml", "config file name")
flag.BoolVar(&startPProf, "pp", false, "pprof")
flag.BoolVar(&startMProf, "mp", false, "memory pprof")
flag.IntVar(&jsonMode, "jm", 0, "json mode, 0:verysimple mode; 1: v2ray mode(not implemented yet)")
flag.StringVar(&listenURL, "L", "", "listen URL (i.e. the listen part in config file), only enbled when config file is not provided.")
flag.StringVar(&dialURL, "D", "", "dial URL (i.e. the dial part in config file), only enbled when config file is not provided.")
}
@@ -89,8 +111,14 @@ func mainFunc() (result int) {
utils.Info("Program started")
defer utils.Info("Program exited")
var err error
if standardConf, err = vs.LoadConfig(configFileName); err != nil && !isFlexible() {
var mode int
var mainFallback *httpLayer.ClassicFallback
standardConf, simpleConf, mode, mainFallback, err = proxy.LoadConfig(configFileName, listenURL, dialURL)
if err != nil && !isFlexible() {
log.Printf("no config exist, and no api server or interactive cli enabled, exiting...")
return -1
}
@@ -104,13 +132,18 @@ func mainFunc() (result int) {
runPreCommands()
var defaultInServer proxy.Server
var Default_uuid string
if mainFallback != nil {
RoutingEnv.MainFallback = mainFallback
}
//load inServers and vs.RoutePolicy
switch vs.ConfMode {
case vs.SimpleMode:
switch mode {
case proxy.SimpleMode:
var hase bool
var eie utils.ErrInErr
defaultInServer, hase, eie = proxy.ServerFromURL(vs.SimpleConf.Server_ThatListenPort_Url)
defaultInServer, hase, eie = proxy.ServerFromURL(simpleConf.Server_ThatListenPort_Url)
if hase {
if ce := utils.CanLogErr("can not create local server"); ce != nil {
ce.Write(zap.Error(eie))
@@ -118,20 +151,20 @@ func mainFunc() (result int) {
return -1
}
if !defaultInServer.CantRoute() && vs.SimpleConf.Route != nil {
if !defaultInServer.CantRoute() && simpleConf.Route != nil {
netLayer.LoadMaxmindGeoipFile("")
//极简模式只支持通过 mycountry进行 geoip分流 这一种情况
vs.RoutePolicy = netLayer.NewRoutePolicy()
if vs.SimpleConf.MyCountryISO_3166 != "" {
vs.RoutePolicy.AddRouteSet(netLayer.NewRouteSetForMyCountry(vs.SimpleConf.MyCountryISO_3166))
RoutingEnv.RoutePolicy = netLayer.NewRoutePolicy()
if simpleConf.MyCountryISO_3166 != "" {
RoutingEnv.RoutePolicy.AddRouteSet(netLayer.NewRouteSetForMyCountry(simpleConf.MyCountryISO_3166))
}
}
case vs.StandardMode:
case proxy.StandardMode:
vs.LoadCommonComponentsFromStandardConf(&standardConf)
RoutingEnv, Default_uuid = proxy.LoadEnvFromStandardConf(&standardConf)
//虽然标准模式支持多个Server目前先只考虑一个
//多个Server存在的话则必须要用 tag指定路由; 然后我们需在预先阶段就判断好tag指定的路由
@@ -144,12 +177,15 @@ func mainFunc() (result int) {
for _, serverConf := range standardConf.Listen {
thisConf := serverConf
if thisConf.Protocol == "tproxy" {
vs.ListenTproxy(thisConf.GetAddrStrForListenOrDial())
tm := vs.ListenTproxy(thisConf.GetAddrStrForListenOrDial())
if tm != nil {
TproxyList = append(TproxyList, tm)
}
continue
}
if thisConf.Uuid == "" && vs.Default_uuid != "" {
thisConf.Uuid = vs.Default_uuid
if thisConf.Uuid == "" && Default_uuid != "" {
thisConf.Uuid = Default_uuid
}
thisServer, err := proxy.NewServer(thisConf)
@@ -160,7 +196,7 @@ func mainFunc() (result int) {
continue
}
vs.AllServers = append(vs.AllServers, thisServer)
AllServers = append(AllServers, thisServer)
if tag := thisServer.GetTag(); tag != "" {
vs.ServersTagMap[tag] = thisServer
}
@@ -169,18 +205,18 @@ func mainFunc() (result int) {
}
// load outClients
switch vs.ConfMode {
case vs.SimpleMode:
switch mode {
case proxy.SimpleMode:
var hase bool
var eie utils.ErrInErr
vs.DefaultOutClient, hase, eie = proxy.ClientFromURL(vs.SimpleConf.Client_ThatDialRemote_Url)
DefaultOutClient, hase, eie = proxy.ClientFromURL(simpleConf.Client_ThatDialRemote_Url)
if hase {
if ce := utils.CanLogErr("can not create remote client"); ce != nil {
ce.Write(zap.Error(eie))
}
return -1
}
case vs.StandardMode:
case proxy.StandardMode:
if len(standardConf.Dial) < 1 {
utils.Warn("no dial in config settings")
@@ -188,8 +224,8 @@ func mainFunc() (result int) {
}
for _, thisConf := range standardConf.Dial {
if thisConf.Uuid == "" && vs.Default_uuid != "" {
thisConf.Uuid = vs.Default_uuid
if thisConf.Uuid == "" && Default_uuid != "" {
thisConf.Uuid = Default_uuid
}
thisClient, err := proxy.NewClient(thisConf)
@@ -199,32 +235,39 @@ func mainFunc() (result int) {
}
continue
}
vs.AllClients = append(vs.AllClients, thisClient)
AllClients = append(AllClients, thisClient)
if tag := thisClient.GetTag(); tag != "" {
vs.ClientsTagMap[tag] = thisClient
}
}
if len(vs.AllClients) > 0 {
vs.DefaultOutClient = vs.AllClients[0]
if len(AllClients) > 0 {
DefaultOutClient = AllClients[0]
} else {
vs.DefaultOutClient = vs.DirectClient
DefaultOutClient = vs.DirectClient
}
}
configFileQualifiedToRun := false
if (defaultInServer != nil || len(vs.AllServers) > 0 || len(vs.TproxyList) > 0) && (vs.DefaultOutClient != nil) {
if (defaultInServer != nil || len(AllServers) > 0 || len(TproxyList) > 0) && (DefaultOutClient != nil) {
configFileQualifiedToRun = true
if vs.ConfMode == vs.SimpleMode {
vs.ListenSer(defaultInServer, vs.DefaultOutClient, true)
if mode == proxy.SimpleMode {
lis := vs.ListenSer(defaultInServer, DefaultOutClient, &RoutingEnv)
if lis != nil {
ListenerArray = append(ListenerArray, lis)
}
} else {
for _, inServer := range vs.AllServers {
vs.ListenSer(inServer, vs.DefaultOutClient, true)
for _, inServer := range AllServers {
lis := vs.ListenSer(inServer, DefaultOutClient, &RoutingEnv)
if lis != nil {
ListenerArray = append(ListenerArray, lis)
}
}
}
@@ -254,13 +297,13 @@ func mainFunc() (result int) {
//在程序ctrl+C关闭时, 会主动Close所有的监听端口. 主要是被报告windows有时退出程序之后, 端口还是处于占用状态.
// 用下面代码以试图解决端口占用问题.
for _, listener := range vs.ListenerArray {
for _, listener := range ListenerArray {
if listener != nil {
listener.Close()
}
}
for _, tm := range vs.TproxyList {
for _, tm := range TproxyList {
tm.Stop()
}

View File

@@ -4,11 +4,12 @@ import (
"testing"
"github.com/BurntSushi/toml"
"github.com/e1732a364fed/v2ray_simple/proxy"
)
func TestLoadTomlConf(t *testing.T) {
var conf StandardConf
var conf proxy.StandardConf
_, err := toml.Decode(testTomlConfStr, &conf)
if err != nil {

19
doc.go
View File

@@ -2,26 +2,9 @@
Package v2ray_simple provides a way to set up a proxy.
Config Format 配置格式
一共有三种配置格式,极简模式,标准模式,兼容模式。
“极简模式”(即 verysimple mode)入口和出口仅有一个而且都是使用共享链接的url格式来配置.
标准模式使用toml格式。
兼容模式可以兼容v2ray现有json格式。暂未实现
极简模式的理念是,配置文件的字符尽量少,尽量短小精悍;
还有个命令行模式就是直接把极简模式的url 放到命令行参数中,比如:
verysimple -L socks5://sfdfsaf -D direct://
Structure 本项目结构
utils -> netLayer-> tlsLayer -> httpLayer -> advLayer -> proxy -> v2ray_simple
utils -> netLayer-> tlsLayer -> httpLayer -> advLayer -> proxy -> v2ray_simple -> cmd/verysimple
Chain

70
main.go
View File

@@ -19,7 +19,6 @@ import (
"github.com/e1732a364fed/v2ray_simple/advLayer/ws"
"github.com/e1732a364fed/v2ray_simple/httpLayer"
"github.com/e1732a364fed/v2ray_simple/netLayer"
"github.com/e1732a364fed/v2ray_simple/netLayer/tproxy"
"github.com/e1732a364fed/v2ray_simple/proxy"
"github.com/e1732a364fed/v2ray_simple/tlsLayer"
"github.com/e1732a364fed/v2ray_simple/utils"
@@ -32,12 +31,6 @@ import (
_ "github.com/e1732a364fed/v2ray_simple/proxy/vless"
)
const (
SimpleMode = iota
StandardMode
V2rayCompatibleMode
)
//统计数据
var (
ActiveConnectionCount int32
@@ -46,32 +39,16 @@ var (
)
var (
uniqueTestDomain string //有时需要测试到单一网站的流量,此时为了避免其它干扰,需要在这里声明 一下 该域名,然后程序里会进行过滤
ConfMode int = -1 //0: simple json, 1: standard toml, 2: v2ray compatible json
SimpleConf proxy.SimpleConf
DirectClient, _, _ = proxy.ClientFromURL("direct://")
DefaultOutClient proxy.Client
Default_uuid string
AllServers = make([]proxy.Server, 0, 8)
AllClients = make([]proxy.Client, 0, 8)
ListenerArray []net.Listener
ServersTagMap = make(map[string]proxy.Server)
ClientsTagMap = make(map[string]proxy.Client)
listenURL string //用于命令行模式
dialURL string //用于命令行模式
Tls_lazy_encrypt bool
Tls_lazy_secure bool
RoutePolicy *netLayer.RoutePolicy
mainFallback *httpLayer.ClassicFallback
dnsMachine *netLayer.DNSMachine
TproxyList []tproxy.Machine
//有时需要测试到单一网站的流量,此时为了避免其它干扰,可声明 一下 该域名,然后程序里会进行过滤
uniqueTestDomain string
)
func init() {
@@ -79,16 +56,13 @@ func init() {
flag.BoolVar(&Tls_lazy_encrypt, "lazy", false, "tls lazy encrypt (splice)")
flag.BoolVar(&Tls_lazy_secure, "ls", false, "tls lazy secure, use special techs to ensure the tls lazy encrypt data can't be detected. Only valid at client end.")
flag.StringVar(&listenURL, "L", "", "listen URL (i.e. the listen part in config file), only enbled when config file is not provided.")
flag.StringVar(&dialURL, "D", "", "dial URL (i.e. the dial part in config file), only enbled when config file is not provided.")
flag.StringVar(&uniqueTestDomain, "td", "", "test a single domain, like www.domain.com. Only valid when loglevel=0")
}
//非阻塞. 可以 直接使用 ListenSer 函数 来手动开启新的转发流程。
// 若 not_temporary 为true, 则生成的listener将会被添加到 listenerArray 中
func ListenSer(inServer proxy.Server, defaultOutClientForThis proxy.Client, not_temporary bool) (thisListener net.Listener) {
// 若 not_temporary 为 false, 则不会使用 RoutingEnv进行路由或回落
func ListenSer(inServer proxy.Server, defaultOutClientForThis proxy.Client, env *proxy.RoutingEnv) (thisListener net.Listener) {
var err error
@@ -144,7 +118,7 @@ func ListenSer(inServer proxy.Server, defaultOutClientForThis proxy.Client, not_
}
handleFunc := func(conn net.Conn) {
handleNewIncomeConnection(inServer, defaultOutClientForThis, conn, !not_temporary)
handleNewIncomeConnection(inServer, defaultOutClientForThis, conn, env)
}
network := inServer.Network()
@@ -159,11 +133,6 @@ func ListenSer(inServer proxy.Server, defaultOutClientForThis proxy.Client, not_
)
}
if not_temporary {
ListenerArray = append(ListenerArray, thisListener)
}
} else {
if err != nil {
utils.ZapLogger.Error(
@@ -194,9 +163,6 @@ type incomingInserverConnState struct {
inServerTlsConn *tlsLayer.Conn
inServerTlsRawReadRecorder *tlsLayer.Recorder
//shouldFallback bool
forbidDNS_orRoute bool
theFallbackFirstBuffer *bytes.Buffer
isTlsLazyServerEnd bool
@@ -204,19 +170,21 @@ type incomingInserverConnState struct {
shouldCloseInSerBaseConnWhenFinish bool
routedToDirect bool
RoutingEnv *proxy.RoutingEnv //used in passToOutClient
}
// handleNewIncomeConnection 会处理 网络层至高级层的数据,
// 然后将代理层的处理发往 handshakeInserver_and_passToOutClient 函数。
//
// 在 listenSer 中被调用。
func handleNewIncomeConnection(inServer proxy.Server, defaultClientForThis proxy.Client, thisLocalConnectionInstance net.Conn, forbidDNS_orRoute bool) {
func handleNewIncomeConnection(inServer proxy.Server, defaultClientForThis proxy.Client, thisLocalConnectionInstance net.Conn, env *proxy.RoutingEnv) {
iics := incomingInserverConnState{
baseLocalConn: thisLocalConnectionInstance,
inServer: inServer,
defaultClient: defaultClientForThis,
forbidDNS_orRoute: forbidDNS_orRoute,
baseLocalConn: thisLocalConnectionInstance,
inServer: inServer,
defaultClient: defaultClientForThis,
RoutingEnv: env,
}
iics.isTlsLazyServerEnd = Tls_lazy_encrypt && canLazyEncryptServer(inServer)
@@ -527,7 +495,7 @@ func handshakeInserver(iics *incomingInserverConnState) (wlc net.Conn, udp_wlc n
return
}
// 在调用 passToOutClient前遇到err时调用
// 在调用 passToOutClient前遇到err时调用, 若找出了buf设置iics并返回true
func findoutFirstBuf(err error, iics *incomingInserverConnState) bool {
if ce := utils.CanLogWarn("failed in inServer proxy handshake"); ce != nil {
ce.Write(
@@ -594,7 +562,7 @@ func handshakeInserver_and_passToOutClient(iics incomingInserverConnState) {
func checkfallback(iics incomingInserverConnState) (targetAddr netLayer.Addr, wlc net.Conn) {
//先检查 mainFallback如果mainFallback中各项都不满足 或者根本没有 mainFallback 再检查 defaultFallback
if mainFallback != nil {
if mf := iics.RoutingEnv.MainFallback; mf != nil {
utils.Debug("Fallback check")
@@ -639,7 +607,7 @@ func checkfallback(iics incomingInserverConnState) (targetAddr netLayer.Addr, wl
}
{
fbAddr := mainFallback.GetFallback(thisFallbackType, fallback_params...)
fbAddr := mf.GetFallback(thisFallbackType, fallback_params...)
if ce := utils.CanLogDebug("Fallback check"); ce != nil {
if fbAddr != nil {
@@ -704,13 +672,13 @@ func passToOutClient(iics incomingInserverConnState, isfallback bool, wlc net.Co
// 因为在direct时netLayer.Addr 拨号时会优先选用ip拨号而且我们下面的分流阶段 如果使用ip的话
// 可以利用geoip文件, 可以做到国别分流.
if !iics.forbidDNS_orRoute && dnsMachine != nil && (targetAddr.Name != "" && len(targetAddr.IP) == 0) && targetAddr.Network != "unix" {
if iics.RoutingEnv != nil && iics.RoutingEnv.DnsMachine != nil && (targetAddr.Name != "" && len(targetAddr.IP) == 0) && targetAddr.Network != "unix" {
if ce := utils.CanLogDebug("Dns querying"); ce != nil {
ce.Write(zap.String("domain", targetAddr.Name))
}
ip := dnsMachine.Query(targetAddr.Name)
ip := iics.RoutingEnv.DnsMachine.Query(targetAddr.Name)
if ip != nil {
targetAddr.IP = ip
@@ -729,7 +697,7 @@ func passToOutClient(iics incomingInserverConnState, isfallback bool, wlc net.Co
inServer := iics.inServer
//尝试分流, 获取到真正要发向 的 outClient
if !iics.forbidDNS_orRoute && RoutePolicy != nil && !(inServer != nil && inServer.CantRoute()) {
if iics.RoutingEnv != nil && iics.RoutingEnv.RoutePolicy != nil && !(inServer != nil && inServer.CantRoute()) {
desc := &netLayer.TargetDescription{
Addr: targetAddr,
@@ -742,7 +710,7 @@ func passToOutClient(iics incomingInserverConnState, isfallback bool, wlc net.Co
ce.Write(zap.Any("source", desc))
}
outtag := RoutePolicy.GetOutTag(desc)
outtag := iics.RoutingEnv.RoutePolicy.GetOutTag(desc)
if outtag == "direct" {
client = DirectClient

View File

@@ -1,8 +1,7 @@
package v2ray_simple
package proxy
import (
"errors"
"flag"
"io/ioutil"
"log"
"net/url"
@@ -13,18 +12,9 @@ import (
"github.com/BurntSushi/toml"
"github.com/e1732a364fed/v2ray_simple/httpLayer"
"github.com/e1732a364fed/v2ray_simple/netLayer"
"github.com/e1732a364fed/v2ray_simple/proxy"
"github.com/e1732a364fed/v2ray_simple/utils"
)
var (
jsonMode int
)
func init() {
flag.IntVar(&jsonMode, "jm", 0, "json mode, 0:verysimple mode; 1: v2ray mode(not implemented yet)")
}
type AppConf struct {
LogLevel *int `toml:"loglevel"` //需要为指针, 否则无法判断0到底是未给出的默认值还是 显式声明的0
DefaultUUID string `toml:"default_uuid"`
@@ -32,7 +22,7 @@ type AppConf struct {
NoReadV bool `toml:"noreadv"`
AdminPass string `toml:"admin_pass"`
AdminPass string `toml:"admin_pass"` //用于apiServer等情况
UDP_timeout *int `toml:"udp_timeout"`
}
@@ -44,8 +34,8 @@ type StandardConf struct {
App *AppConf `toml:"app"`
DnsConf *netLayer.DnsConf `toml:"dns"`
Listen []*proxy.ListenConf `toml:"listen"`
Dial []*proxy.DialConf `toml:"dial"`
Listen []*ListenConf `toml:"listen"`
Dial []*DialConf `toml:"dial"`
Route []*netLayer.RuleConf `toml:"route"`
Fallbacks []*httpLayer.FallbackConf `toml:"fallback"`
@@ -69,21 +59,130 @@ func LoadTomlConfFile(fileNamePath string) (StandardConf, error) {
}
//mainfallback, dnsMachine, routePolicy
func LoadCommonComponentsFromStandardConf(standardConf *StandardConf) {
// 先检查configFileName是否存在存在就尝试加载文件到 standardConf 或者 simpleConf否则尝试 -L参数
func LoadConfig(configFileName, listenURL, dialURL string) (standardConf StandardConf, simpleConf SimpleConf, confMode int, mainFallback *httpLayer.ClassicFallback, err error) {
fpath := utils.GetFilePath(configFileName)
if fpath != "" {
ext := filepath.Ext(fpath)
if ext == ".toml" {
standardConf, err = LoadTomlConfFile(fpath)
if err != nil {
log.Printf("can not load standard config file: %s\n", err)
return
}
confMode = StandardMode
//loglevel 和 noreadv这种会被 命令行覆盖的配置,需要直接在 loadConfig函数中先处理一遍
if appConf := standardConf.App; appConf != nil {
if appConf.LogLevel != nil && !utils.IsFlagGiven("ll") {
utils.LogLevel = *appConf.LogLevel
utils.InitLog()
}
if appConf.NoReadV && !utils.IsFlagGiven("readv") {
netLayer.UseReadv = false
}
}
return
} else {
confMode = SimpleMode
simpleConf, mainFallback, err = loadSimpleConf_byFile(fpath)
}
} else {
if listenURL != "" {
log.Printf("No Such Config File:%s,will try using -L,-D parameter \n", configFileName)
confMode = SimpleMode
simpleConf, err = loadSimpleConf_byUrl(listenURL, dialURL)
} else {
log.Printf("no -L listen URL provided \n")
err = errors.New("no -L listen URL provided")
return
}
}
return
}
func loadSimpleConf_byFile(fpath string) (simpleConf SimpleConf, mainFallback *httpLayer.ClassicFallback, err error) {
//默认认为所有其他后缀的都是json格式因为有时会用 server.json.vless 这种写法
// 默认所有json格式的文件都为 极简模式
var hasE bool
simpleConf, hasE, err = LoadSimpleConfigFile(fpath)
if hasE {
log.Printf("can not load simple config file: %s\n", err)
return
}
if simpleConf.Fallbacks != nil {
mainFallback = httpLayer.NewClassicFallbackFromConfList(simpleConf.Fallbacks)
}
//ConfMode = 0
if simpleConf.Client_ThatDialRemote_Url == "" {
simpleConf.Client_ThatDialRemote_Url = "direct://"
}
return
}
func loadSimpleConf_byUrl(listenURL, dialURL string) (simpleConf SimpleConf, err error) {
_, err = url.Parse(listenURL)
if err != nil {
log.Printf("listenURL given but invalid %s %s\n", listenURL, err)
return
}
simpleConf = SimpleConf{
Server_ThatListenPort_Url: listenURL,
}
if dialURL != "" {
_, err = url.Parse(dialURL)
if err != nil {
log.Printf("dialURL given but invalid %s %s\n", dialURL, err)
return
}
simpleConf.Client_ThatDialRemote_Url = dialURL
}
return
}
type RoutingEnv struct {
RoutePolicy *netLayer.RoutePolicy //used in passToOutClient
MainFallback *httpLayer.ClassicFallback //used in checkFallback in passToOutClient
DnsMachine *netLayer.DNSMachine //used in passToOutClient
}
func LoadEnvFromStandardConf(standardConf *StandardConf) (routingEnv RoutingEnv, Default_uuid string) {
if len(standardConf.Fallbacks) != 0 {
mainFallback = httpLayer.NewClassicFallbackFromConfList(standardConf.Fallbacks)
routingEnv.MainFallback = httpLayer.NewClassicFallbackFromConfList(standardConf.Fallbacks)
}
if dnsConf := standardConf.DnsConf; dnsConf != nil {
dnsMachine = netLayer.LoadDnsMachine(dnsConf)
routingEnv.DnsMachine = netLayer.LoadDnsMachine(dnsConf)
}
var hasAppLevelMyCountry bool
if appConf := standardConf.App; appConf != nil {
Default_uuid = appConf.DefaultUUID
hasAppLevelMyCountry = appConf.MyCountryISO_3166 != ""
if appConf.UDP_timeout != nil {
@@ -98,100 +197,14 @@ func LoadCommonComponentsFromStandardConf(standardConf *StandardConf) {
netLayer.LoadMaxmindGeoipFile("")
RoutePolicy = netLayer.NewRoutePolicy()
routingEnv.RoutePolicy = netLayer.NewRoutePolicy()
if hasAppLevelMyCountry {
RoutePolicy.AddRouteSet(netLayer.NewRouteSetForMyCountry(standardConf.App.MyCountryISO_3166))
routingEnv.RoutePolicy.AddRouteSet(netLayer.NewRouteSetForMyCountry(standardConf.App.MyCountryISO_3166))
}
netLayer.LoadRulesForRoutePolicy(standardConf.Route, RoutePolicy)
netLayer.LoadRulesForRoutePolicy(standardConf.Route, routingEnv.RoutePolicy)
}
}
// 先检查configFileName是否存在存在就尝试加载文件到 standardConf 或者 simpleConf否则尝试 -L参数
func LoadConfig(configFileName string) (standardConf StandardConf, err error) {
fpath := utils.GetFilePath(configFileName)
if fpath != "" {
ext := filepath.Ext(fpath)
if ext == ".toml" {
standardConf, err = LoadTomlConfFile(fpath)
if err != nil {
log.Printf("can not load standard config file: %s\n", err)
return
}
ConfMode = 1
//loglevel 和 noreadv这种会被 命令行覆盖的配置,需要直接在 loadConfig函数中先处理一遍
if appConf := standardConf.App; appConf != nil {
Default_uuid = appConf.DefaultUUID
if appConf.LogLevel != nil && !utils.IsFlagGiven("ll") {
utils.LogLevel = *appConf.LogLevel
utils.InitLog()
}
if appConf.NoReadV && !utils.IsFlagGiven("readv") {
netLayer.UseReadv = false
}
}
return
} else {
//默认认为所有其他后缀的都是json格式因为有时会用 server.json.vless 这种写法
// 默认所有json格式的文件都为 极简模式
var hasE bool
SimpleConf, hasE, err = proxy.LoadSimpleConfigFile(fpath)
if hasE {
log.Printf("can not load simple config file: %s\n", err)
return
}
if SimpleConf.Fallbacks != nil {
mainFallback = httpLayer.NewClassicFallbackFromConfList(SimpleConf.Fallbacks)
}
ConfMode = 0
if SimpleConf.Client_ThatDialRemote_Url == "" {
SimpleConf.Client_ThatDialRemote_Url = "direct://"
}
return
}
} else {
log.Printf("No Such Config File:%s,will try using -L parameter \n", configFileName)
if listenURL != "" {
_, err = url.Parse(listenURL)
if err != nil {
log.Printf("listenURL given but invalid %s %s\n", listenURL, err)
return
}
SimpleConf = proxy.SimpleConf{
Server_ThatListenPort_Url: listenURL,
}
if dialURL != "" {
_, err = url.Parse(dialURL)
if err != nil {
log.Printf("dialURL given but invalid %s %s\n", dialURL, err)
return
}
SimpleConf.Client_ThatDialRemote_Url = dialURL
}
} else {
log.Printf("no -L listen URL provided \n")
err = errors.New("no -L listen URL provided")
return
}
}
return
}

View File

@@ -1,5 +1,22 @@
/*Package proxy defines necessary components for proxy.
Config Format 配置格式
一共有三种配置格式,极简模式,标准模式,兼容模式。
“极简模式”(即 verysimple mode)入口和出口仅有一个而且都是使用共享链接的url格式来配置.
标准模式使用toml格式。
兼容模式可以兼容v2ray现有json格式。暂未实现
极简模式的理念是,配置文件的字符尽量少,尽量短小精悍;
还有个命令行模式就是直接把极简模式的url 放到命令行参数中,比如:
verysimple -L socks5://sfdfsaf -D direct://
Layer Definition
目前认为一个传输过程大概由四个部分组成基础连接udp/tcpTLS可选中间层ws、grpc、http等可选具体协议socks5vlesstrojan等.
@@ -36,7 +53,7 @@ New Model - VSI 新的VSI 模型
11 -------------- client real tcp/udp data)
--------------------------------------------------------------------------------
10 -------------- inner proxy layer)
10 (simplesocks) | inner proxy layer)
--------------------------------------------------------------------------------
9 [client real tcp/udp data] or [inner mux Layer]
--------------------------------------------------------------------------------
@@ -51,7 +68,7 @@ New Model - VSI 新的VSI 模型
4 tcp/udp/unix domain socket/kcp transport layer
--------------------------------------------------------------------------------
实际上quic属于一种超级协议横跨传输层一直到高级层不过为了分类方便这里认为它也是一种 高级层。
另外,实际上quic属于一种超级协议横跨传输层一直到高级层不过为了分类方便这里认为它也是一种 高级层。
也就是说,如果遇到横跨多个层的协议,我们认为它属于其中最高的层级。
@@ -93,7 +110,7 @@ New Model - VSI 新的VSI 模型
}
我们项目的文件夹netLayer 第34层tlsLayer文件夹代表第5层; httpLayer第六层
advLayer文件夹 代表第七层, proxy文件夹代表第8层.
advLayer文件夹 代表第七层, proxy文件夹代表第8层或第10层, 同时连带 处理了 第九层.
同级的ws和grpc是独占的可以都放到一个layer里然后比如第八层配置了一个vless一个trojan那么排列组合就是4种vless+ws, vless+ grpc, trojan+ws, trojan+grpc.
@@ -125,7 +142,7 @@ Contents of proxy package - proxy包内容
使用 RegisterClient 和 RegisterServer 来注册新的实现.
还定义了关于udp 转发机制,该部分直接参考 各个UDP开头的 部分即可.
还定义了关于udp 转发机制,该部分直接参考 relay_udp.go 即可.
Server and Client

View File

@@ -18,13 +18,20 @@ import (
"go.uber.org/zap"
)
//配置文件格式
const (
SimpleMode = iota
StandardMode
V2rayCompatibleMode
)
//规定,如果 proxy的server的handshake如果返回的是具有内层mux的连接该连接要实现 MuxMarker 接口.
type MuxMarker interface {
io.ReadWriteCloser
IsMux()
}
//实现 MusMarker
//实现 MuxMarker
type MuxMarkerConn struct {
netLayer.ReadWrapper
}
@@ -206,7 +213,6 @@ type ProxyCommon interface {
// verysimple规定在加载完配置文件后一个listen和一个dial所使用的全部层级都是确定了的.
// 因为所有使用的层级都是确定的,就可以进行针对性优化
type ProxyCommonStruct struct {
//isdial bool
listenConf *ListenConf
dialConf *DialConf
@@ -348,7 +354,7 @@ func (pcs *ProxyCommonStruct) GetClientInnerMuxSession(wrc io.ReadWriteCloser) *
}
}
//return false
//return false. As a placeholder.
func (pcs *ProxyCommonStruct) IsUDP_MultiChannel() bool {
return false
}
@@ -397,7 +403,6 @@ func (s *ProxyCommonStruct) CanFallback() bool {
return false
}
//return false. As a placeholder.
func (s *ProxyCommonStruct) IsHandleInitialLayers() bool {
return s.AdvancedL == "quic"
}
@@ -438,7 +443,6 @@ func (s *ProxyCommonStruct) IsMux() bool {
return false
}
//return nil. As a placeholder.
func (s *ProxyCommonStruct) HandleInitialLayersFunc() func() (newConnChan chan net.Conn, baseConn any) {
return s.listenCommonConnFunc
}
@@ -447,9 +451,6 @@ func (s *ProxyCommonStruct) SetUseTLS() {
s.TLS = true
}
//func (s *ProxyCommonStruct) setIsDial(b bool) {
// s.isdial = b
//}
func (s *ProxyCommonStruct) setListenConf(lc *ListenConf) {
s.listenConf = lc
}
@@ -457,19 +458,6 @@ func (s *ProxyCommonStruct) setDialConf(dc *DialConf) {
s.dialConf = dc
}
/*
//true则为 Dial 端false 则为 Listen 端
func (s *ProxyCommonStruct) IsDial() bool {
return s.isdial
}
func (s *ProxyCommonStruct) GetListenConf() *ListenConf {
return s.listenConf
}
func (s *ProxyCommonStruct) GetDialConf() *DialConf {
return s.dialConf
}
*/
func (s *ProxyCommonStruct) GetQuic_Client() *quic.Client {
return s.quic_c
}
@@ -478,7 +466,6 @@ func (s *ProxyCommonStruct) setQuic_Client(c *quic.Client) {
s.quic_c = c
}
//for outClient
func (s *ProxyCommonStruct) GetWS_Client() *ws.Client {
return s.ws_c
}
@@ -490,7 +477,6 @@ func (s *ProxyCommonStruct) GetGRPC_Server() *grpc.Server {
return s.grpc_s
}
//for outClient
func (s *ProxyCommonStruct) initWS_client() error {
if s.dialConf == nil {
return errors.New("initWS_client failed when no dialConf assigned")

View File

@@ -75,12 +75,12 @@ protocol = "direct"
testServerConfStr := fmt.Sprintf(testServerConfFormatStr, protocol, clientDialPort, version, network)
clientConf, err := LoadTomlConfStr(testClientConfStr)
clientConf, err := proxy.LoadTomlConfStr(testClientConfStr)
if err != nil {
t.Log(err)
t.FailNow()
}
serverConf, err := LoadTomlConfStr(testServerConfStr)
serverConf, err := proxy.LoadTomlConfStr(testServerConfStr)
if err != nil {
t.Log(err)
t.FailNow()
@@ -115,8 +115,8 @@ protocol = "direct"
t.FailNow()
}
ListenSer(clientEndInServer, clientEndOutClient, false)
ListenSer(serverEndInServer, serverEndOutClient, false)
ListenSer(clientEndInServer, clientEndOutClient, nil)
ListenSer(serverEndInServer, serverEndOutClient, nil)
proxyurl := "http://127.0.0.1:" + clientListenPort

View File

@@ -9,7 +9,7 @@ import (
"github.com/e1732a364fed/v2ray_simple/utils"
)
func ListenTproxy(addr string) {
func ListenTproxy(addr string) (tm *tproxy.Machine) {
utils.Info("Start running Tproxy")
ad, err := netLayer.NewAddr(addr)
@@ -26,8 +26,9 @@ func ListenTproxy(addr string) {
}
udpConn := startLoopUDP(ad)
TproxyList = append(TproxyList, tproxy.Machine{Addr: ad, Listener: lis, UDPConn: udpConn})
tm = &tproxy.Machine{Addr: ad, Listener: lis, UDPConn: udpConn})
return
}
//非阻塞

View File

@@ -4,9 +4,11 @@
package v2ray_simple
import (
"github.com/e1732a364fed/v2ray_simple/netLayer/tproxy"
"github.com/e1732a364fed/v2ray_simple/utils"
)
func ListenTproxy(addr string) {
func ListenTproxy(addr string) (tm *tproxy.Machine) {
utils.Warn("Tproxy not possible on non-linux device")
return
}

View File

@@ -136,12 +136,12 @@ protocol = "direct"
testServerConfStr := fmt.Sprintf(testServerConfFormatStr, protocol, clientDialPort, version, network)
clientConf, err := LoadTomlConfStr(testClientConfStr)
clientConf, err := proxy.LoadTomlConfStr(testClientConfStr)
if err != nil {
t.Log(err)
t.FailNow()
}
serverConf, err := LoadTomlConfStr(testServerConfStr)
serverConf, err := proxy.LoadTomlConfStr(testServerConfStr)
if err != nil {
t.Log(err)
t.FailNow()
@@ -190,10 +190,10 @@ protocol = "direct"
t.FailNow()
}
ListenSer(clientEndInServer, clientEndOutClient, false)
ListenSer(clientEndInServer2, clientEndOutClient, false)
ListenSer(clientEndInServer3, clientEndOutClient, false)
ListenSer(serverEndInServer, serverEndOutClient, false)
ListenSer(clientEndInServer, clientEndOutClient, nil)
ListenSer(clientEndInServer2, clientEndOutClient, nil)
ListenSer(clientEndInServer3, clientEndOutClient, nil)
ListenSer(serverEndInServer, serverEndOutClient, nil)
m := new(dns.Msg)
m.SetQuestion(dns.Fqdn("www.qq.com"), dns.TypeA)