HTTP/HTTPS proxy library with custom dialer, which receives in the context key proxy.ReqParamsK
a *proxy.ReqParams
instance with the IP that made the request, it's URL and method. It can be served using standard library server or fasthttp server, and has two builtin dialers for dialing with a specific network interface or parent proxy.
With Go 1.13 or superior:
git clone [email protected]:lamg/proxy.git
cd proxy/cmd/proxy && go install
This is a proxy that denies all the connections coming from IP addresses different from 127.0.0.1
.
package main
import (
"crypto/tls"
"fmt"
"net"
h "net/http"
"time"
alg "github.com/lamg/algorithms"
"github.com/lamg/proxy"
)
func main() {
// localhost clients only
ar, e := newAllowedRanges("127.0.0.1/32")
if e == nil {
p := proxy.NewProxy(ar.DialContext)
server := &h.Server{
Addr: ":8080",
Handler: p,
ReadTimeout: 5 * time.Second,
WriteTimeout: 10 * time.Second,
// Disable HTTP/2.
TLSNextProto: make(map[string]func(*h.Server,
*tls.Conn, h.Handler)),
}
e = server.ListenAndServe()
}
if e != nil {
log.Fatal(e)
}
}
type allowedRanges struct {
ranges []*net.IPNet
timeout time.Duration
}
func newAllowedRanges(cidrs ...string) (a *allowedRanges, e error) {
a = &allowedRanges{
ranges: make([]*net.IPNet, len(cidrs)),
timeout: 90 * time.Second,
}
ib := func(i int) (b bool) {
_, a.ranges[i], e = net.ParseCIDR(cidrs[i])
b = e != nil
return
}
alg.BLnSrch(ib, len(cidrs))
return
}
func (r *allowedRanges) DialContext(ctx context.Context, network,
addr string) (c net.Conn, e error) {
rqp := ctx.Value(proxy.ReqParamsK).(*proxy.ReqParams)
ip := net.ParseIP(rqp.IP)
ok, _ := alg.BLnSrch(
func(i int) bool { return r.ranges[i].Contains(ip) },
len(r.ranges),
)
if !ok {
e = fmt.Errorf("Client IP '%s' out of range", rqp.IP)
}
if e == nil {
ifd := &proxy.IfaceDialer{Timeout: r.timeout}
c, e = ifd.Dial(network, addr)
}
return
}