add udp relay support for http handler
This commit is contained in:
@ -90,6 +90,11 @@ func (h *httpHandler) handleRequest(ctx context.Context, conn net.Conn, req *htt
|
||||
req.URL.Scheme = "http"
|
||||
}
|
||||
|
||||
network := req.Header.Get("X-Gost-Protocol")
|
||||
if network != "udp" {
|
||||
network = "tcp"
|
||||
}
|
||||
|
||||
// Try to get the actual host.
|
||||
// Compatible with GOST 2.x.
|
||||
if v := req.Header.Get("Gost-Target"); v != "" {
|
||||
@ -168,6 +173,11 @@ func (h *httpHandler) handleRequest(ctx context.Context, conn net.Conn, req *htt
|
||||
return
|
||||
}
|
||||
|
||||
if network == "udp" {
|
||||
h.handleUDP(ctx, conn, network, req.Host)
|
||||
return
|
||||
}
|
||||
|
||||
if req.Method == "PRI" ||
|
||||
(req.Method != http.MethodConnect && req.URL.Scheme != "http") {
|
||||
resp.StatusCode = http.StatusBadRequest
|
||||
@ -187,7 +197,7 @@ func (h *httpHandler) handleRequest(ctx context.Context, conn net.Conn, req *htt
|
||||
WithChain(h.chain).
|
||||
WithRetry(h.md.retryCount).
|
||||
WithLogger(h.logger)
|
||||
cc, err := r.Dial(ctx, "tcp", addr)
|
||||
cc, err := r.Dial(ctx, network, addr)
|
||||
if err != nil {
|
||||
resp.StatusCode = http.StatusServiceUnavailable
|
||||
resp.Write(conn)
|
||||
@ -209,13 +219,13 @@ func (h *httpHandler) handleRequest(ctx context.Context, conn net.Conn, req *htt
|
||||
h.logger.Debug(string(dump))
|
||||
}
|
||||
if err = resp.Write(conn); err != nil {
|
||||
h.logger.Warn(err)
|
||||
h.logger.Error(err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
req.Header.Del("Proxy-Connection")
|
||||
if err = req.Write(cc); err != nil {
|
||||
h.logger.Warn(err)
|
||||
h.logger.Error(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ type metadata struct {
|
||||
retryCount int
|
||||
probeResist *probeResist
|
||||
sni bool
|
||||
enableUDP bool
|
||||
}
|
||||
|
||||
func (h *httpHandler) parseMetadata(md md.Metadata) error {
|
||||
@ -23,6 +24,7 @@ func (h *httpHandler) parseMetadata(md md.Metadata) error {
|
||||
knock = "knock"
|
||||
retryCount = "retry"
|
||||
sni = "sni"
|
||||
enableUDP = "udp"
|
||||
)
|
||||
|
||||
h.md.proxyAgent = md.GetString(proxyAgent)
|
||||
@ -53,6 +55,7 @@ func (h *httpHandler) parseMetadata(md md.Metadata) error {
|
||||
}
|
||||
h.md.retryCount = md.GetInt(retryCount)
|
||||
h.md.sni = md.GetBool(sni)
|
||||
h.md.enableUDP = md.GetBool(enableUDP)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
83
pkg/handler/http/udp.go
Normal file
83
pkg/handler/http/udp.go
Normal file
@ -0,0 +1,83 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"time"
|
||||
|
||||
"github.com/go-gost/gost/pkg/chain"
|
||||
"github.com/go-gost/gost/pkg/common/util/socks"
|
||||
"github.com/go-gost/gost/pkg/handler"
|
||||
"github.com/go-gost/gost/pkg/logger"
|
||||
)
|
||||
|
||||
func (h *httpHandler) handleUDP(ctx context.Context, conn net.Conn, network, address string) {
|
||||
h.logger = h.logger.WithFields(map[string]interface{}{
|
||||
"cmd": "udp",
|
||||
})
|
||||
|
||||
resp := &http.Response{
|
||||
ProtoMajor: 1,
|
||||
ProtoMinor: 1,
|
||||
Header: http.Header{},
|
||||
}
|
||||
if h.md.proxyAgent != "" {
|
||||
resp.Header.Add("Proxy-Agent", h.md.proxyAgent)
|
||||
}
|
||||
|
||||
if !h.md.enableUDP {
|
||||
resp.StatusCode = http.StatusForbidden
|
||||
resp.Write(conn)
|
||||
|
||||
if h.logger.IsLevelEnabled(logger.DebugLevel) {
|
||||
dump, _ := httputil.DumpResponse(resp, false)
|
||||
h.logger.Debug(string(dump))
|
||||
}
|
||||
h.logger.Error("UDP relay is diabled")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
resp.StatusCode = http.StatusOK
|
||||
if h.logger.IsLevelEnabled(logger.DebugLevel) {
|
||||
dump, _ := httputil.DumpResponse(resp, false)
|
||||
h.logger.Debug(string(dump))
|
||||
}
|
||||
if err := resp.Write(conn); err != nil {
|
||||
h.logger.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
// obtain a udp connection
|
||||
r := (&chain.Router{}).
|
||||
WithChain(h.chain).
|
||||
WithRetry(h.md.retryCount).
|
||||
WithLogger(h.logger)
|
||||
c, err := r.Dial(ctx, "udp", "") // UDP association
|
||||
if err != nil {
|
||||
h.logger.Error(err)
|
||||
return
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
pc, ok := c.(net.PacketConn)
|
||||
if !ok {
|
||||
h.logger.Errorf("wrong connection type")
|
||||
return
|
||||
}
|
||||
|
||||
relay := handler.NewUDPRelay(socks.UDPTunServerConn(conn), pc).
|
||||
WithBypass(h.bypass).
|
||||
WithLogger(h.logger)
|
||||
|
||||
t := time.Now()
|
||||
h.logger.Infof("%s <-> %s", conn.RemoteAddr(), pc.LocalAddr())
|
||||
relay.Run()
|
||||
h.logger.
|
||||
WithFields(map[string]interface{}{
|
||||
"duration": time.Since(t),
|
||||
}).
|
||||
Infof("%s >-< %s", conn.RemoteAddr(), pc.LocalAddr())
|
||||
}
|
Reference in New Issue
Block a user