mirror of
https://github.com/TecharoHQ/anubis.git
synced 2026-04-11 19:18:46 +00:00
133 lines
2.7 KiB
Go
133 lines
2.7 KiB
Go
//go:build linux
|
|
|
|
package fingerprint
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"syscall"
|
|
"unsafe"
|
|
)
|
|
|
|
type tcpInfo struct {
|
|
State uint8
|
|
Ca_state uint8
|
|
Retransmits uint8
|
|
Probes uint8
|
|
Backoff uint8
|
|
Options uint8
|
|
Wnd_scale uint8
|
|
Delivery_rate_app_limited uint8
|
|
|
|
Rto uint32
|
|
Ato uint32
|
|
SndMss uint32
|
|
RcvMss uint32
|
|
|
|
Unacked uint32
|
|
Sacked uint32
|
|
Lost uint32
|
|
Retrans uint32
|
|
Fackets uint32
|
|
|
|
Last_data_sent uint32
|
|
Last_ack_sent uint32
|
|
Last_data_recv uint32
|
|
Last_ack_recv uint32
|
|
PMTU uint32
|
|
Rcv_ssthresh uint32
|
|
RTT uint32
|
|
RTTvar uint32
|
|
Snd_ssthresh uint32
|
|
Snd_cwnd uint32
|
|
Advmss uint32
|
|
Reordering uint32
|
|
Rcv_rtt uint32
|
|
Rcv_space uint32
|
|
Total_retrans uint32
|
|
Pacing_rate uint64
|
|
Max_pacing_rate uint64
|
|
Bytes_acked uint64
|
|
Bytes_received uint64
|
|
Segs_out uint32
|
|
Segs_in uint32
|
|
Notsent_bytes uint32
|
|
Min_rtt uint32
|
|
Data_segs_in uint32
|
|
Data_segs_out uint32
|
|
Delivery_rate uint64
|
|
Busy_time uint64
|
|
Rwnd_limited uint64
|
|
Sndbuf_limited uint64
|
|
Delivered uint32
|
|
Delivered_ce uint32
|
|
Bytes_sent uint64
|
|
Bytes_retrans uint64
|
|
DSACK_dups uint32
|
|
Reord_seen uint32
|
|
Rcv_ooopack uint32
|
|
Snd_wnd uint32
|
|
}
|
|
|
|
// AssignTCPFingerprint extracts TCP fingerprint information from a connection
|
|
func AssignTCPFingerprint(conn net.Conn) (*JA4T, error) {
|
|
tcpConn, ok := conn.(*net.TCPConn)
|
|
if !ok {
|
|
return nil, fmt.Errorf("not a TCPConn")
|
|
}
|
|
|
|
rawConn, err := tcpConn.SyscallConn()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("SyscallConn failed: %w", err)
|
|
}
|
|
|
|
var info tcpInfo
|
|
var sysErr error
|
|
|
|
err = rawConn.Control(func(fd uintptr) {
|
|
size := uint32(unsafe.Sizeof(info))
|
|
_, _, errno := syscall.Syscall6(
|
|
syscall.SYS_GETSOCKOPT,
|
|
fd,
|
|
uintptr(syscall.IPPROTO_TCP),
|
|
uintptr(syscall.TCP_INFO),
|
|
uintptr(unsafe.Pointer(&info)),
|
|
uintptr(unsafe.Pointer(&size)),
|
|
0,
|
|
)
|
|
if errno != 0 {
|
|
sysErr = errno
|
|
}
|
|
})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("SyscallConn.Control: %w", err)
|
|
}
|
|
if sysErr != nil {
|
|
return nil, fmt.Errorf("getsockopt TCP_INFO: %w", sysErr)
|
|
}
|
|
|
|
fp := &JA4T{
|
|
Window: info.Snd_wnd,
|
|
MSS: uint16(info.SndMss),
|
|
}
|
|
|
|
const (
|
|
TCPI_OPT_TIMESTAMPS = 1 << 0
|
|
TCPI_OPT_SACK = 1 << 1
|
|
TCPI_OPT_WSCALE = 1 << 2
|
|
)
|
|
|
|
if info.Options&TCPI_OPT_SACK != 0 {
|
|
fp.Options = append(fp.Options, 4, 1)
|
|
}
|
|
if info.Options&TCPI_OPT_TIMESTAMPS != 0 {
|
|
fp.Options = append(fp.Options, 8, 1)
|
|
}
|
|
if info.Options&TCPI_OPT_WSCALE != 0 {
|
|
fp.Options = append(fp.Options, 3)
|
|
fp.WindowScale = info.Wnd_scale
|
|
}
|
|
|
|
return fp, nil
|
|
}
|