Skip to content

Instantly share code, notes, and snippets.

@severnt
Created December 14, 2021 00:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save severnt/2ac993e67edeac7afbfaf618adfa87ac to your computer and use it in GitHub Desktop.
Save severnt/2ac993e67edeac7afbfaf618adfa87ac to your computer and use it in GitHub Desktop.
https web server that can detect when the client is using a proxy by computing request to request delta vs TCP RTT
package main
import (
// "fmt"
// "io"
"context"
"crypto/tls"
"log"
"math"
"net"
"net/http"
"reflect"
"sync"
"time"
"unsafe"
"github.com/brucespang/go-tcpinfo"
)
type HS struct {
mutex sync.Mutex
d map[string]time.Time
}
func (hs *HS) ServeHTTP(w http.ResponseWriter, req *http.Request) {
w.Header().Set("Content-Type", "text/plain")
w.Write([]byte("hello world\n"))
nc, _ := req.Context().Value("conn").(net.Conn)
log.Printf("%s %s %s\n", req.RequestURI, nc.LocalAddr().String(), nc.RemoteAddr().String())
delta := 0 * time.Second
key := req.RequestURI
// key := nc.RemoteAddr().String()
hs.mutex.Lock()
if v, ok := hs.d[key]; ok {
delta = time.Now().Sub(v)
log.Printf("req delta: %d\n", delta.Microseconds())
delete(hs.d, key)
} else {
log.Printf("add req\n")
hs.d[key] = time.Now()
}
hs.mutex.Unlock()
if delta <= 0*time.Second {
return
}
tcpConn := getConnFromTLSConn(nc.(*tls.Conn))
tcpInfo, err := tcpinfo.GetsockoptTCPInfo(tcpConn.(*net.TCPConn))
if err != nil {
log.Println(err)
}
log.Printf("tcpi_rtt: %d\n", tcpInfo.Rtt)
// div3 for keepalive off, b/c 2 more rt required to re-establish tls + .5 rt to get resp + .5 rt to send new http req
if diff(int(delta.Microseconds()/3), int(tcpInfo.Rtt)) < 0.2 {
log.Printf("ok\n")
} else {
log.Printf("warn\n")
}
/*
info, err := netlink.SocketDiagTCPInfo(netlink.FAMILY_V6) // AF_INET = 1, AF_INET6 = 10
if err != nil {
log.Println(err)
}
for _, x := range info {
if nc.RemoteAddr().String() != fmt.Sprintf("%s:%d", x.InetDiagMsg.ID.Destination, x.InetDiagMsg.ID.DestinationPort) {
continue
}
log.Printf("%d %d\n", x.TCPInfo.Rtt, x.TCPInfo.Min_rtt)
if diff(int(delta.Microseconds()), int(x.TCPInfo.Rtt)) < 0.2 || diff(int(delta.Microseconds()), int(x.TCPInfo.Min_rtt)) < 0.2 {
log.Printf("ok\n")
} else {
log.Printf("warn\n")
}
}*/
}
func diff(a, b int) float64 {
return math.Abs(float64(a-b)) / (float64(a+b) / 2)
}
func CState(ctx context.Context, nc net.Conn) context.Context {
log.Printf("%s %s\n", nc.LocalAddr().String(), nc.RemoteAddr().String())
return context.WithValue(ctx, "conn", nc)
}
func main() {
hs := &HS{
d: make(map[string]time.Time),
}
srv := http.Server{
Addr: ":8443",
Handler: hs,
ConnContext: CState,
}
srv.SetKeepAlivesEnabled(false)
// connectionCount := 20
l, err := net.Listen("tcp", ":8443")
if err != nil {
log.Fatalf("Listen: %v", err)
}
defer l.Close()
// l = netutil.LimitListener(l, connectionCount)
log.Fatal(srv.ServeTLS(l, "server.crt", "server.key"))
}
func getConnFromTLSConn(tlsConn *tls.Conn) net.Conn {
// XXX: This is really BAD!!! Only way currently to get the underlying
// connection of the tls.Conn. At least until
// https://github.com/golang/go/issues/29257 is solved.
conn := reflect.ValueOf(tlsConn).Elem().FieldByName("conn")
conn = reflect.NewAt(conn.Type(), unsafe.Pointer(conn.UnsafeAddr())).Elem()
return conn.Interface().(net.Conn)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment