Encienda iptables y configúrelo en LOG
para conexiones entrantes. Regla de ejemplo:
-A INPUT --state NEW -p tcp --dport 4711 -j LOG
(donde 4711 es el puerto que desea rastrear).
Luego ejecute el registro resultante a través de cualquier secuencia de comandos que desee que pueda hacer el resumen por usted.
Puede usar tcpdump para registrar todos los paquetes SYN (sin ACK):
tcpdump "dst port 4711 and tcp[tcpflags] & (tcp-syn|tcp-ack) == tcp-syn"
o registrar todos los paquetes SYN+ACK (conexiones establecidas):
tcpdump "src port 4711 and tcp[tcpflags] & (tcp-syn|tcp-ack) == (tcp-syn|tcp-ack)"
Y luego combínalo con un wc -l
para contar todas las líneas
También necesitaría una forma de medir períodos de tiempo fijos (podría hacer que un cron simplemente le envíe un SIGINT a intervalos regulares, tcpdump contará bytes y paquetes pero solo registrará el tiempo)
Actualización:no es necesario decirlo, eche un vistazo a la página de manual de tcpdump y considere usar algunas opciones como:-i
(escucha solo una interfaz), -p
(deshabilitar el modo promiscuo; menos invasivo), o algunas opciones de salida. Tcpdump necesita permisos de root y es posible que a su jefe no le guste porque es una especie de herramienta de hacker. Por otro lado, no necesita tocar nada en su sistema para ejecutarlo (a diferencia del iptables LOG
solución)
Tenga en cuenta también la pequeña diferencia src/dsk en el filtro. Si captura paquetes SYN+ACK y desea contar las conexiones a un servidor en el puerto 4711 necesita src. Si está capturando paquetes SYN+!ACK para obtener el mismo resultado, necesita dst. Si cuentas las conexiones en el propio servidor, siempre tienes que usar el reverso.
Solución SystemTap
Script inspirado en el ejemplo tcp_connections.stp:
#!/usr/bin/env stap
# To monitor another TCP port run:
# stap -G port=80 tcp_connections.stp
# or
# ./tcp_connections.stp -G port=80
global port = 22
global connections
function report() {
foreach (addr in connections) {
printf("%s: %d\n", addr, @count(connections[addr]))
}
}
probe end {
printf("\n=== Summary ===\n")
report()
}
probe kernel.function("tcp_accept").return?,
kernel.function("inet_csk_accept").return? {
sock = $return
if (sock != 0) {
local_port = inet_get_local_port(sock)
if (local_port == port) {
remote_addr = inet_get_ip_source(sock)
connections[remote_addr] <<< 1
printf("%s New connection from %s\n", ctime(gettimeofday_s()), remote_addr)
}
}
}
Salida:
[[email protected] ~]# ./tcp_connections.stp -G port=80
Mon Mar 17 04:13:03 2014 New connection from 192.168.122.1
Mon Mar 17 04:13:04 2014 New connection from 192.168.122.1
Mon Mar 17 04:13:08 2014 New connection from 192.168.122.4
^C
=== Summary ===
192.168.122.1: 2
192.168.122.4: 1
solución de traza
Inicie el programa bajo strace:
strace -r -f -e trace=accept -o /tmp/strace ${PROGRAM} ${ARGS}
o rastrear un programa ya en ejecución:
strace -r -f -e trace=accept -o /tmp/strace -p ${PID_OF_PROGRAM}
-r
imprime una marca de tiempo relativa al ingresar a cada llamada del sistema en caso de que se necesite más tarde para un análisis de rendimiento adicional. -f
rastrea los procesos secundarios y es posible que no sea necesario.
La salida se parece a esto:
999 0.000000 accept(3, {sa_family=AF_INET, sin_port=htons(34702), sin_addr=inet_addr("192.168.122.4")}, [16]) = 5
999 0.008079 --- SIGCHLD (Child exited) @ 0 (0) ---
999 1.029846 accept(3, {sa_family=AF_INET, sin_port=htons(34703), sin_addr=inet_addr("192.168.122.4")}, [16]) = 5
999 0.008276 --- SIGCHLD (Child exited) @ 0 (0) ---
999 3.580122 accept(3, {sa_family=AF_INET, sin_port=htons(50114), sin_addr=inet_addr("192.168.122.1")}, [16]) = 5
y se puede filtrar con:
# gawk 'match($0, /^([0-9]+)[[:space:]]+([0-9.]+)[[:space:]]+accept\(.*htons\(([^)]+)\),.*inet_addr\("([^"]+)"\).*[[:space:]]+=[[:space:]]+([1-9][0-9]*)/, m) {connections[m[4]]++} END {for (addr in connections) printf("%s: %d\n", addr, connections[addr]); }' /tmp/strace
192.168.122.4: 3
192.168.122.1: 2
Breve explicación del one-liner de AKW:m[1]
es el PID, m[2]
es la marca de tiempo, m[3]
es el puerto remoto y m[4]
es la dirección remota.
La ventaja de esta solución es que no se requiere root si el servidor se ejecuta bajo el mismo usuario. La desventaja es que se cuentan todas las conexiones, no hay filtrado, por lo que no funcionará si la aplicación escucha en varios puertos.