123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238 |
- package main
- import (
- "container/list"
- "encoding/json"
- "errors"
- "flag"
- "fmt"
- "io"
- "jycdp"
- "log"
- "net"
- "net/http"
- "strconv"
- "strings"
- "sync"
- "time"
- )
- const (
- tun_status_normal = iota
- tun_status_busy
- tun_status_idle
- )
- type (
- //Springboard 跳板
- Springboard struct {
- TcpServeAddr string `yaml:"address"`
- Cache *list.List
- Proxy *IpItem //代理地址
- }
- //Config
- Config struct {
- MonitorAddress string `yaml:"monitor_address"`
- ConnectTimeout int64 `yaml:"connect_timeout"`
- SpringboardesPortRange [2]int `yaml:"portrange"`
- PublicIpAddr string `yaml:"public_ip_address"`
- }
- //流量监听 ,只监听请求端
- Monitor struct {
- s *Springboard
- }
- //
- MyMux struct{}
- )
- // Write 实现写接口
- func (m *Monitor) Write(b []byte) (int, error) {
- if strings.Contains(string(b), "pleasechangemyip.com") {
- m.s.ChangeIp()
- }
- return len(b), nil
- }
- var (
- configFile = flag.String("c", "./config.yaml", "配置文件")
- config *Config = new(Config)
- status []int
- tunLock = new(sync.RWMutex)
- )
- // forward 流量转发
- func (s *Springboard) forward(src, dest io.ReadWriteCloser) {
- defer func() {
- if src != nil {
- _ = src.Close()
- }
- if dest != nil {
- _ = dest.Close()
- }
- }()
- if src == nil || dest == nil {
- return
- }
- _, _ = io.Copy(io.MultiWriter(&Monitor{s}, src), dest)
- }
- // processClient 处理客户端请求
- func (s *Springboard) ProcessClient(client net.Conn) {
- defer func() {
- if err := recover(); err != nil {
- fmt.Printf("{err %v}", err)
- }
- }()
- var targetConn net.Conn
- var err error
- for {
- //默认复用上一次对可用IP
- targetConn, err = net.DialTimeout("tcp",
- s.Proxy.Raw,
- time.Duration(config.ConnectTimeout)*time.Second)
- if err == nil {
- break
- }
- //TODO 移除有问题的链接
- //roulette.ClearBadProxy(s.Proxy.Index)
- //跳板主动切换IP
- s.Proxy, _ = roulette.Get()
- }
- s.Cache.PushBack([2]net.Conn{client, targetConn})
- go s.forward(client, targetConn)
- go s.forward(targetConn, client)
- }
- // StartServe 开启TCP服务
- func (s *Springboard) StartServe() {
- s.Proxy, _ = roulette.Get()
- log.Println(s.TcpServeAddr, s.Proxy.Raw)
- conn, err := net.Listen("tcp", s.TcpServeAddr)
- if err != nil {
- log.Println(err.Error())
- return
- }
- log.Println("springboard listen:", s.TcpServeAddr)
- for {
- client, err := conn.Accept()
- if err != nil {
- log.Println("Listen failed: %v\n", err)
- continue
- }
- go s.ProcessClient(client)
- }
- }
- // ChangeIp 切换IP
- func (s *Springboard) ChangeIp() {
- s.Proxy, _ = roulette.Get()
- fmt.Print("C")
- //fmt.Printf("(%s)", s.Proxy.Raw)
- for e := s.Cache.Front(); e != nil; e = e.Next() {
- connes, _ := e.Value.([2](net.Conn))
- if connes[0].Close() != nil {
- _ = connes[0].Close()
- }
- if connes[1].Close() != nil {
- _ = connes[0].Close()
- }
- }
- }
- // Apply 批量申请代理端口资源,用于启动docker,传入proxy_server
- func Apply(length int) (ret []string, err error) {
- tunLock.Lock()
- defer tunLock.Unlock()
- ret = make([]string, length, length)
- pos, start := 0, config.SpringboardesPortRange[0]
- tmp := make([]int, length, length)
- for i, v := range status {
- if v == tun_status_idle {
- //status[i] = tun_status_busy
- tmp[pos] = i
- pos += 1
- }
- if pos == length {
- break
- }
- }
- if pos < length-1 {
- return nil, errors.New("没有足够的tun资源")
- }
- //改状态
- for i, v := range tmp {
- status[v] = tun_status_busy
- ret[i] = fmt.Sprintf("%s:%d", config.PublicIpAddr, start+v)
- }
- return
- }
- // Repay 归还释放tun资源
- func Repay(address []string) {
- ports := make([]int, len(address), len(address))
- for i, v := range address {
- ports[i], _ = strconv.Atoi(strings.Split(v, ":")[1])
- }
- tunLock.Lock()
- defer tunLock.Unlock()
- start := config.SpringboardesPortRange[0]
- for _, v := range ports {
- status[v-start] = tun_status_idle
- }
- }
- // monitor
- func monitor() {
- //申请tun端口
- http.HandleFunc("/apply", func(w http.ResponseWriter, r *http.Request) {
- lenStr := r.FormValue("len")
- if lenStr == "" {
- lenStr = "1"
- }
- length, _ := strconv.Atoi(lenStr)
- ret, err := Apply(length)
- if err != nil {
- w.WriteHeader(http.StatusInternalServerError)
- fmt.Fprint(w, "没有足够的tun资源,请减少申请数量")
- } else {
- json.NewEncoder(w).Encode(ret)
- }
- })
- http.HandleFunc("/repay", func(w http.ResponseWriter, r *http.Request) {
- data := struct {
- Data []string `json:"address"`
- }{}
- json.NewDecoder(r.Body).Decode(&data)
- Repay(data.Data)
- fmt.Fprint(w, "ok")
- })
- http.ListenAndServe(config.MonitorAddress, nil)
- }
- // init 初始化
- func init() {
- flag.Parse()
- jycdp.LoadConfig(*configFile, config)
- length := config.SpringboardesPortRange[1] - config.SpringboardesPortRange[0] + 1
- status = make([]int, length, length)
- //全部设置为闲
- for i, _ := range status {
- status[i] = tun_status_idle
- }
- reloadProxies()
- go watch()
- }
- // main
- func main() {
- //
- for i := config.SpringboardesPortRange[0]; i <= config.SpringboardesPortRange[1]; i++ {
- s := &Springboard{
- TcpServeAddr: fmt.Sprintf(":%d", i),
- Cache: list.New(),
- }
- go s.StartServe()
- }
- monitor()
- //
- }
|