enhancement configuration
This commit is contained in:
parent
3befde0128
commit
003c5a5085
8
chain.go
8
chain.go
@ -17,6 +17,7 @@ var (
|
|||||||
// Chain is a proxy chain that holds a list of proxy nodes.
|
// Chain is a proxy chain that holds a list of proxy nodes.
|
||||||
type Chain struct {
|
type Chain struct {
|
||||||
isRoute bool
|
isRoute bool
|
||||||
|
Retries int
|
||||||
nodeGroups []*NodeGroup
|
nodeGroups []*NodeGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,8 +59,8 @@ func (c *Chain) LastNode() Node {
|
|||||||
if c.IsEmpty() {
|
if c.IsEmpty() {
|
||||||
return Node{}
|
return Node{}
|
||||||
}
|
}
|
||||||
last := c.nodeGroups[len(c.nodeGroups)-1]
|
group := c.nodeGroups[len(c.nodeGroups)-1]
|
||||||
return last.nodes[0]
|
return group.nodes[0].Clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
// LastNodeGroup returns the last group of the group list.
|
// LastNodeGroup returns the last group of the group list.
|
||||||
@ -185,6 +186,8 @@ func (c *Chain) selectRoute() (route *Chain, err error) {
|
|||||||
|
|
||||||
buf := bytes.Buffer{}
|
buf := bytes.Buffer{}
|
||||||
route = newRoute()
|
route = newRoute()
|
||||||
|
route.Retries = c.Retries
|
||||||
|
|
||||||
for _, group := range c.nodeGroups {
|
for _, group := range c.nodeGroups {
|
||||||
node, err := group.Next()
|
node, err := group.Next()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -197,6 +200,7 @@ func (c *Chain) selectRoute() (route *Chain, err error) {
|
|||||||
ChainDialOption(route),
|
ChainDialOption(route),
|
||||||
)
|
)
|
||||||
route = newRoute() // cutoff the chain for multiplex.
|
route = newRoute() // cutoff the chain for multiplex.
|
||||||
|
route.Retries = c.Retries
|
||||||
}
|
}
|
||||||
|
|
||||||
route.AddNode(node)
|
route.AddNode(node)
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
{
|
{
|
||||||
|
"Debug": false,
|
||||||
|
"Retries": 1,
|
||||||
"ServeNodes": [
|
"ServeNodes": [
|
||||||
":8080",
|
":8080",
|
||||||
"ss://chacha20:12345678@:8338"
|
"ss://chacha20:12345678@:8338"
|
||||||
@ -6,5 +8,23 @@
|
|||||||
"ChainNodes": [
|
"ChainNodes": [
|
||||||
"http://192.168.1.1:8080",
|
"http://192.168.1.1:8080",
|
||||||
"https://10.0.2.1:443"
|
"https://10.0.2.1:443"
|
||||||
|
],
|
||||||
|
|
||||||
|
"Routes": [
|
||||||
|
{
|
||||||
|
"Retries": 1,
|
||||||
|
"ServeNodes": [
|
||||||
|
"ws://:1443"
|
||||||
|
],
|
||||||
|
"ChainNodes": [
|
||||||
|
"socks://:192.168.1.1:1080"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Retries": 3,
|
||||||
|
"ServeNodes": [
|
||||||
|
"quic://:443"
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
@ -22,10 +22,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
options struct {
|
options route
|
||||||
ChainNodes, ServeNodes stringList
|
routes []route
|
||||||
Debug bool
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -43,12 +41,17 @@ func init() {
|
|||||||
flag.BoolVar(&printVersion, "V", false, "print version")
|
flag.BoolVar(&printVersion, "V", false, "print version")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
|
if len(options.ServeNodes) > 0 {
|
||||||
|
routes = append(routes, options)
|
||||||
|
}
|
||||||
|
gost.Debug = options.Debug
|
||||||
|
|
||||||
if err := loadConfigureFile(configureFile); err != nil {
|
if err := loadConfigureFile(configureFile); err != nil {
|
||||||
log.Log(err)
|
log.Log(err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if flag.NFlag() == 0 {
|
if flag.NFlag() == 0 || len(routes) == 0 {
|
||||||
flag.PrintDefaults()
|
flag.PrintDefaults()
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
@ -58,7 +61,7 @@ func init() {
|
|||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
gost.Debug = options.Debug
|
log.Log("Debug:", gost.Debug)
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@ -72,24 +75,29 @@ func main() {
|
|||||||
Certificates: []tls.Certificate{cert},
|
Certificates: []tls.Certificate{cert},
|
||||||
}
|
}
|
||||||
|
|
||||||
chain, err := initChain()
|
for _, route := range routes {
|
||||||
if err != nil {
|
if err := route.serve(); err != nil {
|
||||||
log.Log(err)
|
log.Log(err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
if err := serve(chain); err != nil {
|
|
||||||
log.Log(err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
select {}
|
select {}
|
||||||
}
|
}
|
||||||
|
|
||||||
func initChain() (*gost.Chain, error) {
|
type route struct {
|
||||||
|
ChainNodes, ServeNodes stringList
|
||||||
|
Retries int
|
||||||
|
Debug bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *route) initChain() (*gost.Chain, error) {
|
||||||
chain := gost.NewChain()
|
chain := gost.NewChain()
|
||||||
|
chain.Retries = r.Retries
|
||||||
|
|
||||||
gid := 1 // group ID
|
gid := 1 // group ID
|
||||||
|
|
||||||
for _, ns := range options.ChainNodes {
|
for _, ns := range r.ChainNodes {
|
||||||
ngroup := gost.NewNodeGroup()
|
ngroup := gost.NewNodeGroup()
|
||||||
ngroup.ID = gid
|
ngroup.ID = gid
|
||||||
gid++
|
gid++
|
||||||
@ -297,8 +305,13 @@ func parseChainNode(ns string) (nodes []gost.Node, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func serve(chain *gost.Chain) error {
|
func (r *route) serve() error {
|
||||||
for _, ns := range options.ServeNodes {
|
chain, err := r.initChain()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ns := range r.ServeNodes {
|
||||||
node, err := gost.ParseNode(ns)
|
node, err := gost.ParseNode(ns)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -507,9 +520,24 @@ func loadConfigureFile(configureFile string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := json.Unmarshal(content, &options); err != nil {
|
var cfg struct {
|
||||||
|
route
|
||||||
|
Routes []route
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(content, &cfg); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(cfg.route.ServeNodes) > 0 {
|
||||||
|
routes = append(routes, cfg.route)
|
||||||
|
}
|
||||||
|
for _, route := range cfg.Routes {
|
||||||
|
if len(cfg.route.ServeNodes) > 0 {
|
||||||
|
routes = append(routes, route)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gost.Debug = cfg.Debug
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,7 +95,8 @@ func (h *autoHandler) Handle(conn net.Conn) {
|
|||||||
cc := &bufferdConn{Conn: conn, br: br}
|
cc := &bufferdConn{Conn: conn, br: br}
|
||||||
switch b[0] {
|
switch b[0] {
|
||||||
case gosocks4.Ver4:
|
case gosocks4.Ver4:
|
||||||
return // SOCKS4(a) does not suppport authentication method, so we ignore it.
|
cc.Close()
|
||||||
|
return // SOCKS4(a) does not suppport authentication method, so we ignore it for security reason.
|
||||||
case gosocks5.Ver5:
|
case gosocks5.Ver5:
|
||||||
SOCKS5Handler(h.options...).Handle(cc)
|
SOCKS5Handler(h.options...).Handle(cc)
|
||||||
default: // http
|
default: // http
|
||||||
|
30
node.go
30
node.go
@ -23,7 +23,7 @@ type Node struct {
|
|||||||
Client *Client
|
Client *Client
|
||||||
group *NodeGroup
|
group *NodeGroup
|
||||||
failCount uint32
|
failCount uint32
|
||||||
failTime time.Time
|
failTime int64
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseNode parses the node info.
|
// ParseNode parses the node info.
|
||||||
@ -89,7 +89,7 @@ func ParseNode(s string) (node Node, err error) {
|
|||||||
// MarkDead marks the node fail status.
|
// MarkDead marks the node fail status.
|
||||||
func (node *Node) MarkDead() {
|
func (node *Node) MarkDead() {
|
||||||
atomic.AddUint32(&node.failCount, 1)
|
atomic.AddUint32(&node.failCount, 1)
|
||||||
node.failTime = time.Now()
|
atomic.StoreInt64(&node.failTime, time.Now().Unix())
|
||||||
|
|
||||||
if node.group == nil {
|
if node.group == nil {
|
||||||
return
|
return
|
||||||
@ -97,7 +97,7 @@ func (node *Node) MarkDead() {
|
|||||||
for i := range node.group.nodes {
|
for i := range node.group.nodes {
|
||||||
if node.group.nodes[i].ID == node.ID {
|
if node.group.nodes[i].ID == node.ID {
|
||||||
atomic.AddUint32(&node.group.nodes[i].failCount, 1)
|
atomic.AddUint32(&node.group.nodes[i].failCount, 1)
|
||||||
node.group.nodes[i].failTime = time.Now()
|
atomic.StoreInt64(&node.group.nodes[i].failTime, time.Now().Unix())
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -106,7 +106,7 @@ func (node *Node) MarkDead() {
|
|||||||
// ResetDead resets the node fail status.
|
// ResetDead resets the node fail status.
|
||||||
func (node *Node) ResetDead() {
|
func (node *Node) ResetDead() {
|
||||||
atomic.StoreUint32(&node.failCount, 0)
|
atomic.StoreUint32(&node.failCount, 0)
|
||||||
node.failTime = time.Time{}
|
atomic.StoreInt64(&node.failTime, 0)
|
||||||
|
|
||||||
if node.group == nil {
|
if node.group == nil {
|
||||||
return
|
return
|
||||||
@ -115,12 +115,32 @@ func (node *Node) ResetDead() {
|
|||||||
for i := range node.group.nodes {
|
for i := range node.group.nodes {
|
||||||
if node.group.nodes[i].ID == node.ID {
|
if node.group.nodes[i].ID == node.ID {
|
||||||
atomic.StoreUint32(&node.group.nodes[i].failCount, 0)
|
atomic.StoreUint32(&node.group.nodes[i].failCount, 0)
|
||||||
node.group.nodes[i].failTime = time.Time{}
|
atomic.StoreInt64(&node.group.nodes[i].failTime, 0)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clone clones the node, it will prevent data race.
|
||||||
|
func (node *Node) Clone() Node {
|
||||||
|
return Node{
|
||||||
|
ID: node.ID,
|
||||||
|
Addr: node.Addr,
|
||||||
|
Host: node.Host,
|
||||||
|
Protocol: node.Protocol,
|
||||||
|
Transport: node.Transport,
|
||||||
|
Remote: node.Remote,
|
||||||
|
User: node.User,
|
||||||
|
Values: node.Values,
|
||||||
|
DialOptions: node.DialOptions,
|
||||||
|
HandshakeOptions: node.HandshakeOptions,
|
||||||
|
Client: node.Client,
|
||||||
|
group: node.group,
|
||||||
|
failCount: atomic.LoadUint32(&node.failCount),
|
||||||
|
failTime: atomic.LoadInt64(&node.failTime),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (node *Node) String() string {
|
func (node *Node) String() string {
|
||||||
return fmt.Sprintf("%d@%s", node.ID, node.Addr)
|
return fmt.Sprintf("%d@%s", node.ID, node.Addr)
|
||||||
}
|
}
|
||||||
|
10
selector.go
10
selector.go
@ -79,7 +79,7 @@ func (s *RoundStrategy) Apply(nodes []Node) Node {
|
|||||||
if len(nodes) == 0 {
|
if len(nodes) == 0 {
|
||||||
return Node{}
|
return Node{}
|
||||||
}
|
}
|
||||||
old := s.count
|
old := atomic.LoadUint64(&s.count)
|
||||||
atomic.AddUint64(&s.count, 1)
|
atomic.AddUint64(&s.count, 1)
|
||||||
return nodes[int(old%uint64(len(nodes)))]
|
return nodes[int(old%uint64(len(nodes)))]
|
||||||
}
|
}
|
||||||
@ -134,10 +134,10 @@ func (f *FailFilter) Filter(nodes []Node) []Node {
|
|||||||
return nodes
|
return nodes
|
||||||
}
|
}
|
||||||
nl := []Node{}
|
nl := []Node{}
|
||||||
for _, node := range nodes {
|
for i := range nodes {
|
||||||
if node.failCount < uint32(f.MaxFails) ||
|
if atomic.LoadUint32(&nodes[i].failCount) < uint32(f.MaxFails) ||
|
||||||
time.Since(node.failTime) >= f.FailTimeout {
|
time.Since(time.Unix(atomic.LoadInt64(&nodes[i].failTime), 0)) >= f.FailTimeout {
|
||||||
nl = append(nl, node)
|
nl = append(nl, nodes[i].Clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nl
|
return nl
|
||||||
|
Loading…
Reference in New Issue
Block a user