diff --git a/server/file.go b/server/file.go index d64526a..408df1f 100644 --- a/server/file.go +++ b/server/file.go @@ -84,9 +84,9 @@ func (s *Csv) StoreTasksToCsv() { writer.Flush() } -func (s *Csv) LoadTaskFromCsv() { +func (s *Csv) openFile(path string) ([][]string, error) { // 打开文件 - file, err := os.Open(beego.AppPath + "/conf/tasks.csv") + file, err := os.Open(path) if err != nil { panic(err) } @@ -99,28 +99,31 @@ func (s *Csv) LoadTaskFromCsv() { reader.FieldsPerRecord = -1 // 读取文件中所有行保存到slice中 - records, err := reader.ReadAll() + return reader.ReadAll() +} + +func (s *Csv) LoadTaskFromCsv() { + path := beego.AppPath + "/conf/tasks.csv" + records, err := s.openFile(path) if err != nil { - panic(err) + log.Fatal("配置文件打开错误:", path) } var tasks []*ServerConfig // 将每一行数据保存到内存slice中 for _, item := range records { - tcpPort, _ := strconv.Atoi(item[0]) - Start, _ := strconv.Atoi(item[7]) post := &ServerConfig{ - TcpPort: tcpPort, + TcpPort: utils.GetIntNoErrByStr(item[0]), Mode: item[1], Target: item[2], VerifyKey: item[3], U: item[4], P: item[5], Compress: item[6], - Start: Start, + Start: utils.GetIntNoErrByStr(item[7]), Crypt: utils.GetBoolByStr(item[8]), Mux: utils.GetBoolByStr(item[9]), - CompressEncode: utils.GetIntNoerrByStr(item[10]), - CompressDecode: utils.GetIntNoerrByStr(item[11]), + CompressEncode: utils.GetIntNoErrByStr(item[10]), + CompressDecode: utils.GetIntNoErrByStr(item[11]), } tasks = append(tasks, post) } @@ -214,23 +217,10 @@ func (s *Csv) StoreHostToCsv() { } func (s *Csv) LoadHostFromCsv() { - // 打开文件 - file, err := os.Open(beego.AppPath + "/conf/hosts.csv") + path := beego.AppPath + "/conf/hosts.csv" + records, err := s.openFile(path) if err != nil { - panic(err) - } - defer file.Close() - - // 获取csv的reader - reader := csv.NewReader(file) - - // 设置FieldsPerRecord为-1 - reader.FieldsPerRecord = -1 - - // 读取文件中所有行保存到slice中 - records, err := reader.ReadAll() - if err != nil { - panic(err) + log.Fatal("配置文件打开错误:", path) } var hosts []*HostList // 将每一行数据保存到内存slice中 diff --git a/server/process.go b/server/process.go new file mode 100644 index 0000000..639dc55 --- /dev/null +++ b/server/process.go @@ -0,0 +1,99 @@ +package server + +import ( + "bufio" + "github.com/cnlh/easyProxy/utils" + "log" + "net/http" + "net/http/httputil" + "sync" +) + +type process func(c *utils.Conn, s *TunnelModeServer) error + +//tcp隧道模式 +func ProcessTunnel(c *utils.Conn, s *TunnelModeServer) error { + _, _, rb, err, r := c.GetHost() + if err == nil { + if err := s.auth(r, c, s.config.U, s.config.P); err != nil { + return err + } + } + return s.dealClient(c, s.config, s.config.Target, "", rb) +} + +//http代理模式 +func ProcessHttp(c *utils.Conn, s *TunnelModeServer) error { + method, addr, rb, err, r := c.GetHost() + if err != nil { + log.Println(err) + c.Close() + return err + } + if err := s.auth(r, c, s.config.U, s.config.P); err != nil { + return err + } + return s.dealClient(c, s.config, addr, method, rb) +} + +//多客户端域名代理 +func ProcessHost(c *utils.Conn, s *TunnelModeServer) error { + var ( + isConn = true + link *utils.Conn + cnf *ServerConfig + host *HostList + wg sync.WaitGroup + ) + for { + r, err := http.ReadRequest(bufio.NewReader(c)) + if err != nil { + break + } + //首次获取conn + if isConn { + isConn = false + if host, cnf, err = GetKeyByHost(r.Host); err != nil { + log.Printf("the host %s is not found !", r.Host) + break + } + + if err = s.auth(r, c, cnf.U, cnf.P); err != nil { + break + } + + if link, err = s.GetTunnelAndWriteHost(utils.CONN_TCP, cnf, host.Target); err != nil { + log.Println("get bridge tunnel error: ", err) + break + } + + if flag, err := link.ReadFlag(); err != nil || flag == utils.CONN_ERROR { + log.Printf("the host %s connection to %s error", r.Host, host.Target) + break + } else { + wg.Add(1) + go func() { + utils.Relay(c.Conn, link.Conn, cnf.CompressDecode, cnf.Crypt, cnf.Mux) + wg.Done() + }() + } + } + utils.ChangeHostAndHeader(r, host.HostChange, host.HeaderChange, c.Conn.RemoteAddr().String()) + b, err := httputil.DumpRequest(r, true) + if err != nil { + break + } + if _, err := link.WriteTo(b, cnf.CompressEncode, cnf.Crypt); err != nil { + break + } + } + wg.Wait() + if cnf != nil && cnf.Mux && link != nil { + link.WriteTo([]byte(utils.IO_EOF), cnf.CompressEncode, cnf.Crypt) + s.bridge.ReturnTunnel(link, getverifyval(cnf.VerifyKey)) + } else if link != nil { + link.Close() + } + c.Close() + return nil +} diff --git a/server/socks5.go b/server/socks5.go index aea8043..e0cb2df 100755 --- a/server/socks5.go +++ b/server/socks5.go @@ -46,10 +46,9 @@ const ( ) type Sock5ModeServer struct { - bridge *bridge.Tunnel + server isVerify bool listener net.Listener - config *ServerConfig } //req @@ -136,26 +135,24 @@ func (s *Sock5ModeServer) doConnect(c net.Conn, command uint8) (proxyConn *utils binary.Read(c, binary.BigEndian, &port) // connect to host addr := net.JoinHostPort(host, strconv.Itoa(int(port))) - client, err := s.bridge.GetTunnel(getverifyval(s.config.VerifyKey), s.config.CompressEncode, s.config.CompressDecode, s.config.Crypt, s.config.Mux) - if err != nil { - log.Println(err) - return - } - s.sendReply(c, succeeded) var ltype string if command == associateMethod { ltype = utils.CONN_UDP } else { ltype = utils.CONN_TCP } - _, err = client.WriteHost(ltype, addr) + if proxyConn, err = s.GetTunnelAndWriteHost(ltype, s.config, addr); err != nil { + log.Println("get bridge tunnel error: ", err) + return + } + s.sendReply(c, succeeded) var flag string - if flag, err = client.ReadFlag(); err == nil { + if flag, err = proxyConn.ReadFlag(); err == nil { if flag != utils.CONN_SUCCESS { err = errors.New("conn failed") } } - return client, err + return } //conn diff --git a/server/tcp.go b/server/tcp.go index aa9bbf1..ff749ed 100755 --- a/server/tcp.go +++ b/server/tcp.go @@ -1,7 +1,6 @@ package server import ( - "bufio" "errors" "fmt" "github.com/astaxie/beego" @@ -10,17 +9,31 @@ import ( "log" "net" "net/http" - "net/http/httputil" "strings" - "sync" ) -type process func(c *utils.Conn, s *TunnelModeServer) error +//server base struct +type server struct { + bridge *bridge.Tunnel + config *ServerConfig +} + +func (s *server) GetTunnelAndWriteHost(connType string, cnf *ServerConfig, addr string) (*utils.Conn, error) { + var err error + link, err := s.bridge.GetTunnel(getverifyval(cnf.VerifyKey), cnf.CompressEncode, cnf.CompressDecode, cnf.Crypt, cnf.Mux) + if err != nil { + return nil, err + } + if _, err = link.WriteHost(connType, addr); err != nil { + link.Close() + return nil, err + } + return link, nil +} type TunnelModeServer struct { + server process process - bridge *bridge.Tunnel - config *ServerConfig listener *net.TCPListener } @@ -64,10 +77,6 @@ func (s *TunnelModeServer) auth(r *http.Request, c *utils.Conn, u, p string) err return nil } -func (s *TunnelModeServer) dealClient2(c *utils.Conn, cnf *ServerConfig, addr string, method string, rb []byte) error { - return nil -} - //与客户端建立通道 func (s *TunnelModeServer) dealClient(c *utils.Conn, cnf *ServerConfig, addr string, method string, rb []byte) error { var link *utils.Conn @@ -77,7 +86,7 @@ func (s *TunnelModeServer) dealClient(c *utils.Conn, cnf *ServerConfig, addr str s.bridge.ReturnTunnel(link, getverifyval(cnf.VerifyKey)) } }() - if link, err = s.GetTunnelAndWriteHost(c, cnf, addr); err != nil { + if link, err = s.GetTunnelAndWriteHost(utils.CONN_TCP, cnf, addr); err != nil { log.Println("get bridge tunnel error: ", err) return err } @@ -99,109 +108,9 @@ func (s *TunnelModeServer) Close() error { return s.listener.Close() } -func (s *TunnelModeServer) GetTunnelAndWriteHost(c *utils.Conn, cnf *ServerConfig, addr string) (*utils.Conn, error) { - var err error - link, err := s.bridge.GetTunnel(getverifyval(cnf.VerifyKey), cnf.CompressEncode, cnf.CompressDecode, cnf.Crypt, cnf.Mux) - if err != nil { - return nil, err - } - if _, err = link.WriteHost(utils.CONN_TCP, addr); err != nil { - link.Close() - return nil, err - } - return link, nil -} - -//tcp隧道模式 -func ProcessTunnel(c *utils.Conn, s *TunnelModeServer) error { - _, _, rb, err, r := c.GetHost() - if err == nil { - if err := s.auth(r, c, s.config.U, s.config.P); err != nil { - return err - } - } - return s.dealClient(c, s.config, s.config.Target, "", rb) -} - -//http代理模式 -func ProcessHttp(c *utils.Conn, s *TunnelModeServer) error { - method, addr, rb, err, r := c.GetHost() - if err != nil { - log.Println(err) - c.Close() - return err - } - if err := s.auth(r, c, s.config.U, s.config.P); err != nil { - return err - } - return s.dealClient(c, s.config, addr, method, rb) -} - -//多客户端域名代理 -func ProcessHost(c *utils.Conn, s *TunnelModeServer) error { - var ( - isConn = true - link *utils.Conn - cnf *ServerConfig - host *HostList - wg sync.WaitGroup - ) - for { - r, err := http.ReadRequest(bufio.NewReader(c)) - if err != nil { - break - } - //首次获取conn - if isConn { - isConn = false - if host, cnf, err = GetKeyByHost(r.Host); err != nil { - log.Printf("the host %s is not found !", r.Host) - break - } - - if err = s.auth(r, c, cnf.U, cnf.P); err != nil { - break - } - - if link, err = s.GetTunnelAndWriteHost(c, cnf, host.Target); err != nil { - log.Println("get bridge tunnel error: ", err) - break - } - - if flag, err := link.ReadFlag(); err != nil || flag == utils.CONN_ERROR { - log.Printf("the host %s connection to %s error", r.Host, host.Target) - break - } else { - wg.Add(1) - go func() { - utils.Relay(c.Conn, link.Conn, cnf.CompressDecode, cnf.Crypt, cnf.Mux) - wg.Done() - }() - } - } - utils.ChangeHostAndHeader(r, host.HostChange, host.HeaderChange, c.Conn.RemoteAddr().String()) - b, err := httputil.DumpRequest(r, true) - if err != nil { - break - } - if _, err := link.WriteTo(b, cnf.CompressEncode, cnf.Crypt); err != nil { - break - } - } - wg.Wait() - if cnf != nil && cnf.Mux && link != nil { - link.WriteTo([]byte(utils.IO_EOF), cnf.CompressEncode, cnf.Crypt) - s.bridge.ReturnTunnel(link, getverifyval(cnf.VerifyKey)) - } else if link != nil { - link.Close() - } - c.Close() - return nil -} - //web管理方式 type WebServer struct { - bridge *bridge.Tunnel + server } //开始 @@ -222,7 +131,7 @@ func NewWebServer(bridge *bridge.Tunnel) *WebServer { //host type HostServer struct { - config *ServerConfig + server } //开始 diff --git a/utils/util.go b/utils/util.go index 50d0e09..3e27dd2 100755 --- a/utils/util.go +++ b/utils/util.go @@ -76,7 +76,7 @@ func GetCompressType(compress string) (int, int) { } //通过host获取对应的ip地址 -func Gethostbyname(hostname string) string { +func GetHostByName(hostname string) string { if !DomainCheck(hostname) { return hostname } @@ -140,16 +140,17 @@ func GetStrByBool(b bool) string { } //int -func GetIntNoerrByStr(str string) int { +func GetIntNoErrByStr(str string) int { i, _ := strconv.Atoi(str) return i } -// io.copy的优化版,读取buffer长度原为32*1024,与snappy不同,导致读取出的内容存在差异,不利于解密,特此修改 +// io.copy的优化版,读取buffer长度原为32*1024,与snappy不同,导致读取出的内容存在差异,不利于解密 //内存优化 用到pool,快速回收 func copyBuffer(dst io.Writer, src io.Reader) (written int64, err error) { for { + //放在里面是为了加快回收和重利用 buf := bufPoolCopy.Get().([]byte) nr, er := src.Read(buf) if nr > 0 { diff --git a/web/controllers/base.go b/web/controllers/base.go index 9e4fbbc..38342e9 100755 --- a/web/controllers/base.go +++ b/web/controllers/base.go @@ -34,7 +34,7 @@ func (s *BaseController) display(tpl ...string) { } s.Data["menu"] = s.actionName ip := s.Ctx.Request.Host - s.Data["ip"] = utils.Gethostbyname(ip[0:strings.LastIndex(ip, ":")]) + s.Data["ip"] = utils.GetHostByName(ip[0:strings.LastIndex(ip, ":")]) s.Data["p"] = server.Bridge.TunnelPort s.Data["proxyPort"] = beego.AppConfig.String("hostPort") s.Layout = "public/layout.html"