mirror of https://github.com/ginuerzh/gost
4 changed files with 105 additions and 2 deletions
@ -0,0 +1,101 @@ |
|||||
|
package gost |
||||
|
|
||||
|
import ( |
||||
|
"errors" |
||||
|
"fmt" |
||||
|
"github.com/golang/glog" |
||||
|
"net" |
||||
|
"syscall" |
||||
|
) |
||||
|
|
||||
|
const ( |
||||
|
SO_ORIGINAL_DST = 80 |
||||
|
) |
||||
|
|
||||
|
type RedsocksTCPServer struct { |
||||
|
Base *ProxyServer |
||||
|
} |
||||
|
|
||||
|
func NewRedsocksTCPServer(base *ProxyServer) *RedsocksTCPServer { |
||||
|
return &RedsocksTCPServer{ |
||||
|
Base: base, |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (s *RedsocksTCPServer) ListenAndServe() error { |
||||
|
laddr, err := net.ResolveTCPAddr("tcp", s.Base.Node.Addr) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
ln, err := net.ListenTCP("tcp", laddr) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
defer ln.Close() |
||||
|
for { |
||||
|
conn, err := ln.AcceptTCP() |
||||
|
if err != nil { |
||||
|
glog.V(LWARNING).Infoln(err) |
||||
|
continue |
||||
|
} |
||||
|
go s.handleRedirectTCP(conn) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (s *RedsocksTCPServer) handleRedirectTCP(conn *net.TCPConn) { |
||||
|
srcAddr := conn.RemoteAddr() |
||||
|
dstAddr, conn, err := getOriginalDstAddr(conn) |
||||
|
if err != nil { |
||||
|
glog.V(LWARNING).Infof("[red-tcp] %s -> %s : %s", srcAddr, dstAddr, err) |
||||
|
return |
||||
|
} |
||||
|
defer conn.Close() |
||||
|
|
||||
|
glog.V(LINFO).Infof("[red-tcp] %s -> %s", srcAddr, dstAddr) |
||||
|
|
||||
|
cc, err := s.Base.Chain.Dial(dstAddr.String()) |
||||
|
if err != nil { |
||||
|
glog.V(LWARNING).Infof("[red-tcp] %s -> %s : %s", srcAddr, dstAddr, err) |
||||
|
return |
||||
|
} |
||||
|
defer cc.Close() |
||||
|
|
||||
|
glog.V(LINFO).Infof("[red-tcp] %s <-> %s", srcAddr, dstAddr) |
||||
|
s.Base.transport(conn, cc) |
||||
|
glog.V(LINFO).Infof("[red-tcp] %s >-< %s", srcAddr, dstAddr) |
||||
|
} |
||||
|
|
||||
|
func getOriginalDstAddr(conn *net.TCPConn) (addr net.Addr, c *net.TCPConn, err error) { |
||||
|
defer conn.Close() |
||||
|
|
||||
|
fc, err := conn.File() |
||||
|
if err != nil { |
||||
|
return |
||||
|
} |
||||
|
defer fc.Close() |
||||
|
|
||||
|
mreq, err := syscall.GetsockoptIPv6Mreq(int(fc.Fd()), syscall.IPPROTO_IP, SO_ORIGINAL_DST) |
||||
|
if err != nil { |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
// only ipv4 support
|
||||
|
ip := net.IPv4(mreq.Multiaddr[4], mreq.Multiaddr[5], mreq.Multiaddr[6], mreq.Multiaddr[7]) |
||||
|
port := uint16(mreq.Multiaddr[2])<<8 + uint16(mreq.Multiaddr[3]) |
||||
|
addr, err = net.ResolveTCPAddr("tcp4", fmt.Sprintf("%s:%d", ip.String(), port)) |
||||
|
if err != nil { |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
cc, err := net.FileConn(fc) |
||||
|
if err != nil { |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
c, ok := cc.(*net.TCPConn) |
||||
|
if !ok { |
||||
|
err = errors.New("not a TCP connection") |
||||
|
} |
||||
|
return |
||||
|
} |
||||
Loading…
Reference in new issue