fedproxy/main.go

145 lines
3.3 KiB
Go
Raw Normal View History

2018-08-29 05:06:07 -07:00
package main
import (
2019-01-19 05:30:28 -08:00
"crypto/tls"
"fmt"
"github.com/majestrate/fedproxy/internal/socks5"
2018-08-29 05:06:07 -07:00
"golang.org/x/net/proxy"
2019-01-19 05:34:32 -08:00
"io"
2018-08-29 05:06:07 -07:00
"net"
2019-01-19 05:30:28 -08:00
"net/http"
2018-08-29 05:06:07 -07:00
"os"
"strings"
)
2019-01-19 05:30:28 -08:00
type httpProxyHandler struct {
onion proxy.Dialer
i2p proxy.Dialer
2019-01-19 05:30:28 -08:00
}
func transfer(dst io.WriteCloser, src io.ReadCloser) {
defer dst.Close()
defer src.Close()
io.Copy(dst, src)
}
2019-01-19 05:48:35 -08:00
func copyHeader(dst, src http.Header) {
for k, vv := range src {
for _, v := range vv {
dst.Add(k, v)
}
}
}
2019-01-19 05:30:28 -08:00
func (h *httpProxyHandler) dialOut(addr string) (net.Conn, error) {
host, _, err := net.SplitHostPort(addr)
if err != nil {
return nil, err
}
2021-07-27 21:19:11 -07:00
if strings.HasSuffix(host, ".onion") {
return h.onion.Dial("tcp", addr)
2019-01-19 05:30:28 -08:00
}
if strings.HasSuffix(host, ".i2p") {
return h.i2p.Dial("tcp", addr)
}
2021-07-27 21:19:11 -07:00
// fallthrough for clearnet and .loki
return net.Dial("tcp", addr)
2019-01-19 05:30:28 -08:00
}
2019-01-19 05:34:32 -08:00
func (h *httpProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
2019-01-19 05:30:28 -08:00
if r.Method == http.MethodConnect {
outConn, err := h.dialOut(r.Host)
if err != nil {
http.Error(w, err.Error(), http.StatusServiceUnavailable)
return
}
hijacker, ok := w.(http.Hijacker)
if !ok {
2019-01-19 05:36:22 -08:00
outConn.Close()
2019-01-19 05:30:28 -08:00
http.Error(w, "hijack disallowed", http.StatusInternalServerError)
return
}
2019-01-19 05:50:34 -08:00
w.Header().Del("Transfer-Encoding")
2019-01-19 05:43:14 -08:00
w.WriteHeader(http.StatusOK)
2019-01-19 05:30:28 -08:00
conn, _, err := hijacker.Hijack()
if err != nil {
2019-01-19 05:36:22 -08:00
outConn.Close()
2019-01-19 05:30:28 -08:00
http.Error(w, err.Error(), http.StatusServiceUnavailable)
return
}
2019-01-19 05:36:22 -08:00
go transfer(conn, outConn)
go transfer(outConn, conn)
2019-01-19 05:30:28 -08:00
} else {
2019-01-19 05:48:35 -08:00
resp, err := http.DefaultTransport.RoundTrip(r)
if err != nil {
http.Error(w, err.Error(), http.StatusServiceUnavailable)
return
}
defer resp.Body.Close()
copyHeader(w.Header(), resp.Header)
w.WriteHeader(resp.StatusCode)
io.Copy(w, resp.Body)
2019-01-19 05:30:28 -08:00
w.WriteHeader(http.StatusMethodNotAllowed)
}
}
2018-08-29 05:06:07 -07:00
func main() {
args := os.Args[1:]
if len(args) < 4 {
fmt.Printf("usage: %s proto bindaddr onionsocksaddr i2psocksaddr\n", os.Args[0])
2018-08-29 05:06:07 -07:00
return
}
usehttp := args[0] == "http"
onionsock, err := proxy.SOCKS5("tcp", args[2], nil, nil)
2018-08-29 05:06:07 -07:00
if err != nil {
fmt.Printf("failed to create upstream proxy to %s, %s", args[2], err.Error())
2019-01-19 05:30:28 -08:00
return
2018-08-29 05:06:07 -07:00
}
i2psock, err := proxy.SOCKS5("tcp", args[3], nil, nil)
2019-01-19 05:30:28 -08:00
if usehttp {
serv := &http.Server{
Addr: args[1],
2019-01-19 05:34:32 -08:00
Handler: &httpProxyHandler{
onion: onionsock,
i2p: i2psock,
2019-01-19 05:30:28 -08:00
},
TLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler)),
}
fmt.Printf("setting up http proxy at %s\n", serv.Addr)
err = serv.ListenAndServe()
if err != nil {
fmt.Printf("%s\n", err.Error())
}
2019-01-19 05:30:28 -08:00
} else {
serv, err := socks5.New(&socks5.Config{
Dial: func(addr string) (net.Conn, error) {
host, _, err := net.SplitHostPort(addr)
host = strings.TrimSuffix(host, ".")
2019-01-19 05:30:28 -08:00
if err != nil {
return nil, err
}
2021-07-27 21:19:11 -07:00
if strings.HasSuffix(host, ".onion") {
return onionsock.Dial("tcp", addr)
}
if strings.HasSuffix(host, ".i2p") {
return i2psock.Dial("tcp", addr)
2019-01-19 05:30:28 -08:00
}
2021-07-27 21:19:11 -07:00
// fallthrough for clearnet and loki
return net.Dial("tcp", addr)
2019-01-19 05:30:28 -08:00
},
})
2018-08-29 05:06:07 -07:00
2019-01-19 05:30:28 -08:00
if err != nil {
fmt.Printf("failed to create socks proxy %s", err.Error())
return
}
l, err := net.Listen("tcp", args[1])
2019-01-19 05:30:28 -08:00
if err != nil {
fmt.Printf("failed to listen on %s, %s", args[1], err.Error())
2019-01-19 05:30:28 -08:00
return
}
2019-06-15 06:17:15 -07:00
serv.Serve(l)
2018-08-29 05:06:07 -07:00
}
}