1 Star 0 Fork 1

azbox / Coproxy-Go

forked from 牧牧枫cc123 / Coproxy-Go 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
http.go 4.03 KB
一键复制 编辑 原始数据 按行查看 历史
fucongcong 提交于 2018-03-07 15:05 . update md
package main
import (
"fmt"
"io"
"log"
"net"
"time"
)
type HTTP struct {
}
func (http *HTTP) OutToTCP(address string, inConn net.Conn, req *HTTPRequest) (err error) {
inAddr := inConn.RemoteAddr().String()
inLocalAddr := inConn.LocalAddr().String()
//防止死循环
if http.IsDeadLoop(inLocalAddr, req.Host) {
inConn.Close()
err = fmt.Errorf("dead loop detected , %s", req.Host)
return
}
var outConn net.Conn
//构造连接
tryCount := 0
maxTryCount := 5
for {
outConn, err = net.DialTimeout("tcp", address, time.Duration(3000)*time.Millisecond)
tryCount++
if err == nil || tryCount > maxTryCount {
break
} else {
log.Printf("err:%s,retrying...", err)
time.Sleep(time.Second * 2)
}
}
if err != nil {
log.Printf("err:%s", err)
inConn.Close()
return
}
outAddr := outConn.RemoteAddr().String()
if req.IsHTTPS() {
//https无上级或者上级非代理,proxy需要响应connect请求,并直连目标
err = req.HTTPSReply()
} else {
//https或者http,上级是代理,proxy需要转发
_, err = outConn.Write(req.HeadBuf)
if err != nil {
log.Printf("write to %s , err:%s", outAddr, err)
inConn.Close()
return
}
}
//开始做数据交换
http.IoBind(inConn, outConn, func(err interface{}) {
log.Printf("conn %s - %s released [%s]", inAddr, outAddr, req.Host)
}) //
log.Printf("conn %s - %s connected [%s]", inAddr, outAddr, req.Host)
return
}
func (http *HTTP) IoBind(dst io.ReadWriteCloser, src io.ReadWriteCloser, callback func(err interface{})) {
go func() {
defer func() {
if err := recover(); err != nil {
log.Printf("bind crashed %s", err)
}
}()
e1 := make(chan interface{}, 1)
e2 := make(chan interface{}, 1)
go func() {
defer func() {
if err := recover(); err != nil {
log.Printf("bind crashed %s", err)
}
}()
//_, err := io.Copy(dst, src)
err := http.ioCopy(dst, src)
e1 <- err
}()
go func() {
defer func() {
if err := recover(); err != nil {
log.Printf("bind crashed %s", err)
}
}()
//_, err := io.Copy(src, dst)
err := http.ioCopy(src, dst)
e2 <- err
}()
var err interface{}
select {
case err = <-e1:
case err = <-e2:
}
src.Close()
dst.Close()
callback(err)
}()
}
func (http *HTTP) ioCopy(dst io.ReadWriter, src io.ReadWriter) (err error) {
buf := make([]byte, 32*1024)
n := 0
for {
n, err = src.Read(buf)
if n > 0 {
if _, e := dst.Write(buf[0:n]); e != nil {
return e
}
}
if err != nil {
return
}
}
}
func (http *HTTP) IsDeadLoop(inLocalAddr string, host string) bool {
inIP, inPort, err := net.SplitHostPort(inLocalAddr)
if err != nil {
return false
}
outDomain, outPort, err := net.SplitHostPort(host)
if err != nil {
return false
}
if inPort == outPort {
var outIPs []net.IP
outIPs, err = net.LookupIP(outDomain)
if err == nil {
for _, ip := range outIPs {
if ip.String() == inIP {
return true
}
}
}
// interfaceIPs, err := http.GetAllInterfaceAddr()
// if err == nil {
// for _, localIP := range interfaceIPs {
// for _, outIP := range outIPs {
// if localIP.Equal(outIP) {
// return true
// }
// }
// }
// }
}
return false
}
func (http *HTTP) GetAllInterfaceAddr() ([]net.IP, error) {
ifaces, err := net.Interfaces()
if err != nil {
return nil, err
}
addresses := []net.IP{}
for _, iface := range ifaces {
if iface.Flags&net.FlagUp == 0 {
continue // interface down
}
// if iface.Flags&net.FlagLoopback != 0 {
// continue // loopback interface
// }
addrs, err := iface.Addrs()
if err != nil {
continue
}
for _, addr := range addrs {
var ip net.IP
switch v := addr.(type) {
case *net.IPNet:
ip = v.IP
case *net.IPAddr:
ip = v.IP
}
// if ip == nil || ip.IsLoopback() {
// continue
// }
ip = ip.To4()
if ip == nil {
continue // not an ipv4 address
}
addresses = append(addresses, ip)
}
}
if len(addresses) == 0 {
return nil, fmt.Errorf("no address Found, net.InterfaceAddrs: %v", addresses)
}
//only need first
return addresses, nil
}
Go
1
https://gitee.com/azbox/Coproxy-Go.git
git@gitee.com:azbox/Coproxy-Go.git
azbox
Coproxy-Go
Coproxy-Go
master

搜索帮助