Skip to content

Instantly share code, notes, and snippets.

@FeeYo7
Created January 19, 2022 23:03
Show Gist options
  • Save FeeYo7/6140f03e3c24e71ca2fa71b719113703 to your computer and use it in GitHub Desktop.
Save FeeYo7/6140f03e3c24e71ca2fa71b719113703 to your computer and use it in GitHub Desktop.
proxy
package main
import (
"context"
"crypto/tls"
"flag"
"fmt"
"io"
"io/ioutil"
"log"
"net"
"net/http"
"time"
)
var dialer *net.Dialer
func mustResolve(iface string) *net.Dialer {
addr, err := net.ResolveTCPAddr("tcp", iface)
if err != nil {
panic(err)
}
dialer := &net.Dialer{
LocalAddr: addr,
Timeout: 10 * time.Second,
}
return dialer
}
func dial() {
// Select network adapter that using 192.168.0.50
// and it will be connect to port 0 (dynamically generate an unused port number)
addr, err := net.ResolveTCPAddr("tcp", "192.168.0.50:0")
if err != nil {
panic(err)
}
dialer := &net.Dialer{
LocalAddr: addr,
Timeout: 10 * time.Second,
}
dialContext := func(ctx context.Context, network, addr string) (net.Conn, error) {
conn, err := dialer.Dial(network, addr)
return conn, err
}
transport := &http.Transport{DialContext: dialContext}
client := &http.Client{
Transport: transport,
}
// http request
response, err := client.Get("https://api.ipify.org/") // get my IP address
if err != nil {
panic(err)
}
data, err := ioutil.ReadAll(response.Body)
if err != nil {
panic(err)
}
fmt.Println(string(data))
}
func handleTunneling(w http.ResponseWriter, r *http.Request) {
fmt.Println(r.Host)
dest_conn, err := dialer.Dial("tcp", r.Host)
if err != nil {
http.Error(w, err.Error(), http.StatusServiceUnavailable)
return
}
w.WriteHeader(http.StatusOK)
hijacker, ok := w.(http.Hijacker)
if !ok {
http.Error(w, "Hijacking not supported", http.StatusInternalServerError)
return
}
client_conn, _, err := hijacker.Hijack()
if err != nil {
http.Error(w, err.Error(), http.StatusServiceUnavailable)
}
go transfer(dest_conn, client_conn)
go transfer(client_conn, dest_conn)
}
func transfer(destination io.WriteCloser, source io.ReadCloser) {
defer destination.Close()
defer source.Close()
io.Copy(destination, source)
}
func handleHTTP(w http.ResponseWriter, req *http.Request) {
resp, err := http.DefaultTransport.RoundTrip(req)
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)
}
func copyHeader(dst, src http.Header) {
for k, vv := range src {
for _, v := range vv {
dst.Add(k, v)
}
}
}
// Get preferred outbound ip of this machine
func getOutboundIP() string {
conn, err := net.Dial("udp", "8.8.8.8:80")
if err != nil {
log.Fatal(err)
}
defer conn.Close()
localAddr := conn.LocalAddr().(*net.UDPAddr)
return localAddr.IP.String()
}
func main() {
var defaultIP = getOutboundIP()
fmt.Println("conneting on " + defaultIP)
var pemPath string
flag.StringVar(&pemPath, "pem", "server.pem", "path to pem file")
var keyPath string
flag.StringVar(&keyPath, "key", "server.key", "path to key file")
var proto string
flag.StringVar(&proto, "proto", "https", "Proxy protocol (http or https)")
var iface string
flag.StringVar(&iface, "iface", string(defaultIP)+":0", "Interface address to dial with")
dialer = mustResolve(iface)
flag.Parse()
if proto != "http" && proto != "https" {
log.Fatal("Protocol must be either http or https")
}
server := &http.Server{
Addr: ":8888",
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodConnect {
handleTunneling(w, r)
} else {
handleHTTP(w, r)
}
}),
// Disable HTTP/2.
TLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler)),
}
if proto == "http" {
log.Fatal(server.ListenAndServe())
} else {
log.Fatal(server.ListenAndServeTLS(pemPath, keyPath))
}
}
@FeeYo7
Copy link
Author

FeeYo7 commented Jan 20, 2022

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment