Improve: using native http request
This commit is contained in:
parent
6e2b9edb45
commit
47e038cf18
12 changed files with 169 additions and 96 deletions
|
@ -12,13 +12,8 @@ type DirectAdapter struct {
|
||||||
conn net.Conn
|
conn net.Conn
|
||||||
}
|
}
|
||||||
|
|
||||||
// Writer is used to output network traffic
|
// ReadWriter is used to handle network traffic
|
||||||
func (d *DirectAdapter) Writer() io.Writer {
|
func (d *DirectAdapter) ReadWriter() io.ReadWriter {
|
||||||
return d.conn
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reader is used to input network traffic
|
|
||||||
func (d *DirectAdapter) Reader() io.Reader {
|
|
||||||
return d.conn
|
return d.conn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,6 +22,11 @@ func (d *DirectAdapter) Close() {
|
||||||
d.conn.Close()
|
d.conn.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Close is used to close connection
|
||||||
|
func (d *DirectAdapter) Conn() net.Conn {
|
||||||
|
return d.conn
|
||||||
|
}
|
||||||
|
|
||||||
type Direct struct {
|
type Direct struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ package adapters
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
|
"net"
|
||||||
|
|
||||||
C "github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
)
|
)
|
||||||
|
@ -10,18 +11,17 @@ import (
|
||||||
type RejectAdapter struct {
|
type RejectAdapter struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Writer is used to output network traffic
|
// ReadWriter is used to handle network traffic
|
||||||
func (r *RejectAdapter) Writer() io.Writer {
|
func (r *RejectAdapter) ReadWriter() io.ReadWriter {
|
||||||
return &NopRW{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reader is used to input network traffic
|
|
||||||
func (r *RejectAdapter) Reader() io.Reader {
|
|
||||||
return &NopRW{}
|
return &NopRW{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close is used to close connection
|
// Close is used to close connection
|
||||||
func (r *RejectAdapter) Close() {
|
func (r *RejectAdapter) Close() {}
|
||||||
|
|
||||||
|
// Close is used to close connection
|
||||||
|
func (r *RejectAdapter) Conn() net.Conn {
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type Reject struct {
|
type Reject struct {
|
||||||
|
|
|
@ -19,13 +19,8 @@ type ShadowsocksAdapter struct {
|
||||||
conn net.Conn
|
conn net.Conn
|
||||||
}
|
}
|
||||||
|
|
||||||
// Writer is used to output network traffic
|
// ReadWriter is used to handle network traffic
|
||||||
func (ss *ShadowsocksAdapter) Writer() io.Writer {
|
func (ss *ShadowsocksAdapter) ReadWriter() io.ReadWriter {
|
||||||
return ss.conn
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reader is used to input network traffic
|
|
||||||
func (ss *ShadowsocksAdapter) Reader() io.Reader {
|
|
||||||
return ss.conn
|
return ss.conn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,6 +29,10 @@ func (ss *ShadowsocksAdapter) Close() {
|
||||||
ss.conn.Close()
|
ss.conn.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ss *ShadowsocksAdapter) Conn() net.Conn {
|
||||||
|
return ss.conn
|
||||||
|
}
|
||||||
|
|
||||||
type ShadowSocks struct {
|
type ShadowSocks struct {
|
||||||
server string
|
server string
|
||||||
cipher string
|
cipher string
|
||||||
|
|
|
@ -2,17 +2,19 @@ package constant
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
|
"net"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ProxyAdapter interface {
|
type ProxyAdapter interface {
|
||||||
Writer() io.Writer
|
ReadWriter() io.ReadWriter
|
||||||
Reader() io.Reader
|
Conn() net.Conn
|
||||||
Close()
|
Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
type ServerAdapter interface {
|
type ServerAdapter interface {
|
||||||
Addr() *Addr
|
Addr() *Addr
|
||||||
ProxyAdapter
|
Connect(ProxyAdapter)
|
||||||
|
Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
type Proxy interface {
|
type Proxy interface {
|
||||||
|
|
|
@ -9,10 +9,23 @@ const (
|
||||||
AtypIPv4 = 1
|
AtypIPv4 = 1
|
||||||
AtypDomainName = 3
|
AtypDomainName = 3
|
||||||
AtypIPv6 = 4
|
AtypIPv6 = 4
|
||||||
|
|
||||||
|
TCP = iota
|
||||||
|
UDP
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type NetWork int
|
||||||
|
|
||||||
|
func (n *NetWork) String() string {
|
||||||
|
if *n == TCP {
|
||||||
|
return "tcp"
|
||||||
|
}
|
||||||
|
return "udp"
|
||||||
|
}
|
||||||
|
|
||||||
// Addr is used to store connection address
|
// Addr is used to store connection address
|
||||||
type Addr struct {
|
type Addr struct {
|
||||||
|
NetWork NetWork
|
||||||
AddrType int
|
AddrType int
|
||||||
Host string
|
Host string
|
||||||
IP *net.IP
|
IP *net.IP
|
||||||
|
|
7
main.go
7
main.go
|
@ -6,7 +6,8 @@ import (
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
C "github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
"github.com/Dreamacro/clash/proxy"
|
"github.com/Dreamacro/clash/proxy/http"
|
||||||
|
"github.com/Dreamacro/clash/proxy/socks"
|
||||||
"github.com/Dreamacro/clash/tunnel"
|
"github.com/Dreamacro/clash/tunnel"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
@ -33,8 +34,8 @@ func main() {
|
||||||
log.Fatalf("Parse config error: %s", err.Error())
|
log.Fatalf("Parse config error: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
go proxy.NewHttpProxy(port)
|
go http.NewHttpProxy(port)
|
||||||
go proxy.NewSocksProxy(socksPort)
|
go socks.NewSocksProxy(socksPort)
|
||||||
|
|
||||||
sigCh := make(chan os.Signal, 1)
|
sigCh := make(chan os.Signal, 1)
|
||||||
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
|
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
|
||||||
|
|
62
proxy/http/http.go
Normal file
62
proxy/http/http.go
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
package http
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
C "github.com/Dreamacro/clash/constant"
|
||||||
|
)
|
||||||
|
|
||||||
|
type HttpAdapter struct {
|
||||||
|
addr *C.Addr
|
||||||
|
r *http.Request
|
||||||
|
w http.ResponseWriter
|
||||||
|
done chan struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *HttpAdapter) Close() {
|
||||||
|
h.done <- struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *HttpAdapter) Addr() *C.Addr {
|
||||||
|
return h.addr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *HttpAdapter) Connect(proxy C.ProxyAdapter) {
|
||||||
|
req := http.Transport{
|
||||||
|
Dial: func(string, string) (net.Conn, error) {
|
||||||
|
return proxy.Conn(), nil
|
||||||
|
},
|
||||||
|
// from http.DefaultTransport
|
||||||
|
MaxIdleConns: 100,
|
||||||
|
IdleConnTimeout: 90 * time.Second,
|
||||||
|
TLSHandshakeTimeout: 10 * time.Second,
|
||||||
|
ExpectContinueTimeout: 1 * time.Second,
|
||||||
|
}
|
||||||
|
resp, err := req.RoundTrip(h.r)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
header := h.w.Header()
|
||||||
|
for k, vv := range resp.Header {
|
||||||
|
for _, v := range vv {
|
||||||
|
header.Add(k, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
h.w.WriteHeader(resp.StatusCode)
|
||||||
|
io.Copy(h.w, resp.Body)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHttp(host string, w http.ResponseWriter, r *http.Request) (*HttpAdapter, chan struct{}) {
|
||||||
|
done := make(chan struct{})
|
||||||
|
return &HttpAdapter{
|
||||||
|
addr: parseHttpAddr(host),
|
||||||
|
r: r,
|
||||||
|
w: w,
|
||||||
|
done: done,
|
||||||
|
}, done
|
||||||
|
}
|
35
proxy/http/https.go
Normal file
35
proxy/http/https.go
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
package http
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
|
||||||
|
C "github.com/Dreamacro/clash/constant"
|
||||||
|
)
|
||||||
|
|
||||||
|
type HttpsAdapter struct {
|
||||||
|
addr *C.Addr
|
||||||
|
conn net.Conn
|
||||||
|
rw *bufio.ReadWriter
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *HttpsAdapter) Close() {
|
||||||
|
h.conn.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *HttpsAdapter) Addr() *C.Addr {
|
||||||
|
return h.addr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *HttpsAdapter) Connect(proxy C.ProxyAdapter) {
|
||||||
|
go io.Copy(h.conn, proxy.ReadWriter())
|
||||||
|
io.Copy(proxy.ReadWriter(), h.conn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHttps(host string, conn net.Conn) *HttpsAdapter {
|
||||||
|
return &HttpsAdapter{
|
||||||
|
addr: parseHttpAddr(host),
|
||||||
|
conn: conn,
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,21 +1,22 @@
|
||||||
package proxy
|
package http
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httputil"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
|
"github.com/Dreamacro/clash/tunnel"
|
||||||
|
|
||||||
"github.com/riobard/go-shadowsocks2/socks"
|
"github.com/riobard/go-shadowsocks2/socks"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
tun = tunnel.GetInstance()
|
||||||
|
)
|
||||||
|
|
||||||
func NewHttpProxy(port string) {
|
func NewHttpProxy(port string) {
|
||||||
server := &http.Server{
|
server := &http.Server{
|
||||||
Addr: fmt.Sprintf(":%s", port),
|
Addr: fmt.Sprintf(":%s", port),
|
||||||
|
@ -32,21 +33,14 @@ func NewHttpProxy(port string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleHTTP(w http.ResponseWriter, r *http.Request) {
|
func handleHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
buf, _ := httputil.DumpRequestOut(r, true)
|
|
||||||
hijacker, ok := w.(http.Hijacker)
|
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
conn, rw, err := hijacker.Hijack()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
addr := r.Host
|
addr := r.Host
|
||||||
// padding default port
|
// padding default port
|
||||||
if !strings.Contains(addr, ":") {
|
if !strings.Contains(addr, ":") {
|
||||||
addr += ":80"
|
addr += ":80"
|
||||||
}
|
}
|
||||||
tun.Add(NewHttp(addr, conn, rw, buf))
|
req, done := NewHttp(addr, w, r)
|
||||||
|
tun.Add(req)
|
||||||
|
<-done
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleTunneling(w http.ResponseWriter, r *http.Request) {
|
func handleTunneling(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -54,38 +48,16 @@ func handleTunneling(w http.ResponseWriter, r *http.Request) {
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
conn, rw, err := hijacker.Hijack()
|
conn, _, err := hijacker.Hijack()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// w.WriteHeader(http.StatusOK) doesn't works in Safari
|
// w.WriteHeader(http.StatusOK) doesn't works in Safari
|
||||||
conn.Write([]byte("HTTP/1.1 200 OK\r\n\r\n"))
|
conn.Write([]byte("HTTP/1.1 200 OK\r\n\r\n"))
|
||||||
tun.Add(NewHttp(r.Host, conn, rw, []byte{}))
|
tun.Add(NewHttps(r.Host, conn))
|
||||||
}
|
}
|
||||||
|
|
||||||
type HttpAdapter struct {
|
func parseHttpAddr(target string) *C.Addr {
|
||||||
addr *constant.Addr
|
|
||||||
conn net.Conn
|
|
||||||
r io.Reader
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *HttpAdapter) Writer() io.Writer {
|
|
||||||
return h.conn
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *HttpAdapter) Reader() io.Reader {
|
|
||||||
return h.r
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *HttpAdapter) Close() {
|
|
||||||
h.conn.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *HttpAdapter) Addr() *constant.Addr {
|
|
||||||
return h.addr
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseHttpAddr(target string) *constant.Addr {
|
|
||||||
host, port, _ := net.SplitHostPort(target)
|
host, port, _ := net.SplitHostPort(target)
|
||||||
ipAddr, _ := net.ResolveIPAddr("ip", host)
|
ipAddr, _ := net.ResolveIPAddr("ip", host)
|
||||||
var addType int
|
var addType int
|
||||||
|
@ -99,19 +71,11 @@ func parseHttpAddr(target string) *constant.Addr {
|
||||||
addType = socks.AtypIPv4
|
addType = socks.AtypIPv4
|
||||||
}
|
}
|
||||||
|
|
||||||
return &constant.Addr{
|
return &C.Addr{
|
||||||
|
NetWork: C.TCP,
|
||||||
AddrType: addType,
|
AddrType: addType,
|
||||||
Host: host,
|
Host: host,
|
||||||
IP: &ipAddr.IP,
|
IP: &ipAddr.IP,
|
||||||
Port: port,
|
Port: port,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHttp(host string, conn net.Conn, rw *bufio.ReadWriter, payload []byte) *HttpAdapter {
|
|
||||||
r := io.MultiReader(bytes.NewReader(payload), rw)
|
|
||||||
return &HttpAdapter{
|
|
||||||
conn: conn,
|
|
||||||
addr: parseHttpAddr(host),
|
|
||||||
r: r,
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
package proxy
|
package socks
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -6,7 +6,7 @@ import (
|
||||||
"net"
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
"github.com/Dreamacro/clash/tunnel"
|
"github.com/Dreamacro/clash/tunnel"
|
||||||
|
|
||||||
"github.com/riobard/go-shadowsocks2/socks"
|
"github.com/riobard/go-shadowsocks2/socks"
|
||||||
|
@ -45,26 +45,23 @@ func handleSocks(conn net.Conn) {
|
||||||
|
|
||||||
type SocksAdapter struct {
|
type SocksAdapter struct {
|
||||||
conn net.Conn
|
conn net.Conn
|
||||||
addr *constant.Addr
|
addr *C.Addr
|
||||||
}
|
|
||||||
|
|
||||||
func (s *SocksAdapter) Writer() io.Writer {
|
|
||||||
return s.conn
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *SocksAdapter) Reader() io.Reader {
|
|
||||||
return s.conn
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SocksAdapter) Close() {
|
func (s *SocksAdapter) Close() {
|
||||||
s.conn.Close()
|
s.conn.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SocksAdapter) Addr() *constant.Addr {
|
func (s *SocksAdapter) Addr() *C.Addr {
|
||||||
return s.addr
|
return s.addr
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseSocksAddr(target socks.Addr) *constant.Addr {
|
func (s *SocksAdapter) Connect(proxy C.ProxyAdapter) {
|
||||||
|
go io.Copy(s.conn, proxy.ReadWriter())
|
||||||
|
io.Copy(proxy.ReadWriter(), s.conn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseSocksAddr(target socks.Addr) *C.Addr {
|
||||||
var host, port string
|
var host, port string
|
||||||
var ip net.IP
|
var ip net.IP
|
||||||
|
|
||||||
|
@ -84,7 +81,8 @@ func parseSocksAddr(target socks.Addr) *constant.Addr {
|
||||||
port = strconv.Itoa((int(target[1+net.IPv6len]) << 8) | int(target[1+net.IPv6len+1]))
|
port = strconv.Itoa((int(target[1+net.IPv6len]) << 8) | int(target[1+net.IPv6len+1]))
|
||||||
}
|
}
|
||||||
|
|
||||||
return &constant.Addr{
|
return &C.Addr{
|
||||||
|
NetWork: C.TCP,
|
||||||
AddrType: int(target[0]),
|
AddrType: int(target[0]),
|
||||||
Host: host,
|
Host: host,
|
||||||
IP: &ip,
|
IP: &ip,
|
1
proxy/socks/udp.go
Normal file
1
proxy/socks/udp.go
Normal file
|
@ -0,0 +1 @@
|
||||||
|
package socks
|
|
@ -2,7 +2,6 @@ package tunnel
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
@ -110,8 +109,7 @@ func (t *Tunnel) handleConn(localConn C.ServerAdapter) {
|
||||||
}
|
}
|
||||||
defer remoConn.Close()
|
defer remoConn.Close()
|
||||||
|
|
||||||
go io.Copy(localConn.Writer(), remoConn.Reader())
|
localConn.Connect(remoConn)
|
||||||
io.Copy(remoConn.Writer(), localConn.Reader())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tunnel) match(addr *C.Addr) C.Proxy {
|
func (t *Tunnel) match(addr *C.Addr) C.Proxy {
|
||||||
|
|
Loading…
Reference in a new issue