experimental quic support

This commit is contained in:
rui.zheng 2016-10-20 15:34:09 +08:00
parent 6ca1f4a984
commit e0b8e54619
5 changed files with 126 additions and 2 deletions

View File

@ -11,7 +11,7 @@ import (
)
const (
Version = "2.2-rc2"
Version = "2.3-dev"
)
// Log level for glog

View File

@ -57,7 +57,7 @@ func ParseProxyNode(s string) (node ProxyNode, err error) {
}
switch node.Transport {
case "ws", "wss", "tls", "http2":
case "ws", "wss", "tls", "http2", "ssu", "quic":
case "https":
node.Protocol = "http"
node.Transport = "tls"

80
quic.go Normal file
View File

@ -0,0 +1,80 @@
package gost
import (
"bufio"
"crypto/tls"
"github.com/golang/glog"
"github.com/lucas-clemente/quic-go/h2quic"
"io"
"net/http"
"net/http/httputil"
)
type QuicServer struct {
Base *ProxyServer
Handler http.Handler
TLSConfig *tls.Config
}
func NewQuicServer(base *ProxyServer) *QuicServer {
return &QuicServer{Base: base}
}
func (s *QuicServer) ListenAndServeTLS(config *tls.Config) error {
server := &h2quic.Server{
Server: &http.Server{
Addr: s.Base.Node.Addr,
Handler: s.Handler,
TLSConfig: config,
},
}
if server.Handler == nil {
server.Handler = http.HandlerFunc(s.HandleRequest)
}
return server.ListenAndServe()
}
func (s *QuicServer) HandleRequest(w http.ResponseWriter, req *http.Request) {
target := req.Host
glog.V(LINFO).Infof("[quic] %s %s - %s %s", req.Method, req.RemoteAddr, target, req.Proto)
if glog.V(LDEBUG) {
dump, _ := httputil.DumpRequest(req, false)
glog.Infoln(string(dump))
}
c, err := s.Base.Chain.Dial(target)
if err != nil {
glog.V(LWARNING).Infof("[quic] %s -> %s : %s", req.RemoteAddr, target, err)
w.WriteHeader(http.StatusServiceUnavailable)
return
}
defer c.Close()
glog.V(LINFO).Infof("[quic] %s <-> %s", req.RemoteAddr, target)
req.Header.Set("Connection", "Keep-Alive")
if err = req.Write(c); err != nil {
glog.V(LWARNING).Infof("[quic] %s -> %s : %s", req.RemoteAddr, target, err)
return
}
resp, err := http.ReadResponse(bufio.NewReader(c), req)
if err != nil {
glog.V(LWARNING).Infoln(err)
return
}
defer resp.Body.Close()
for k, v := range resp.Header {
for _, vv := range v {
w.Header().Add(k, vv)
}
}
w.WriteHeader(resp.StatusCode)
if _, err := io.Copy(flushWriter{w}, resp.Body); err != nil {
glog.V(LWARNING).Infof("[quic] %s <- %s : %s", req.RemoteAddr, target, err)
}
glog.V(LINFO).Infof("[quic] %s >-< %s", req.RemoteAddr, target)
}

View File

@ -80,6 +80,10 @@ func (s *ProxyServer) Serve() error {
return NewRTcpForwardServer(s).Serve()
case "rudp": // Remote UDP port forwarding
return NewRUdpForwardServer(s).Serve()
case "ssu": // shadowsocks udp relay
return NewShadowUdpServer(s).ListenAndServe()
case "quic":
return NewQuicServer(s).ListenAndServeTLS(s.TLSConfig)
default:
ln, err = net.Listen("tcp", node.Addr)
}

40
ss.go
View File

@ -65,6 +65,46 @@ func (s *ShadowServer) Serve() {
glog.V(LINFO).Infof("[ss] %s >-< %s", s.conn.RemoteAddr(), addr)
}
type ShadowUdpServer struct {
Base *ProxyServer
Handler func(conn *net.UDPConn, addr *net.UDPAddr, data []byte)
}
func NewShadowUdpServer(base *ProxyServer) *ShadowUdpServer {
return &ShadowUdpServer{Base: base}
}
func (s *ShadowUdpServer) ListenAndServe() error {
laddr, err := net.ResolveUDPAddr("udp", s.Base.Node.Addr)
if err != nil {
return err
}
lconn, err := net.ListenUDP("udp", laddr)
if err != nil {
return err
}
defer lconn.Close()
if s.Handler == nil {
s.Handler = s.HandleConn
}
for {
b := make([]byte, LargeBufferSize)
n, addr, err := lconn.ReadFromUDP(b)
if err != nil {
glog.V(LWARNING).Infoln(err)
continue
}
go s.Handler(lconn, addr, b[:n])
}
}
func (s *ShadowUdpServer) HandleConn(conn *net.UDPConn, addr *net.UDPAddr, data []byte) {
}
// This function is copied from shadowsocks library with some modification.
func (s *ShadowServer) getRequest() (host string, ota bool, err error) {
// buf size should at least have the same size with the largest possible