Created
December 14, 2021 00:19
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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