Attiva iptables e impostalo su LOG
per le connessioni in entrata. Esempio di regola:
-A INPUT --state NEW -p tcp --dport 4711 -j LOG
(dove 4711 è la porta che vuoi tracciare).
Quindi esegui il registro risultante attraverso qualsiasi script che ti piace che possa fare il riepilogo per te.
Puoi utilizzare tcpdump per registrare tutti i pacchetti SYN (senza ACK):
tcpdump "dst port 4711 and tcp[tcpflags] & (tcp-syn|tcp-ack) == tcp-syn"
o registrare tutti i pacchetti SYN+ACK (connessioni stabilite):
tcpdump "src port 4711 and tcp[tcpflags] & (tcp-syn|tcp-ack) == (tcp-syn|tcp-ack)"
E poi combinalo con un wc -l
per contare tutte le righe
Avresti anche bisogno di un modo per misurare periodi di tempo fissi (potresti fare in modo che un cron gli invii semplicemente un SIGINT a intervalli regolari, tcpdump conterà byte e pacchetti ma registrerà solo il tempo)
Aggiornamento:non è necessario dirlo, dai un'occhiata alla pagina man di tcpdump e considera l'utilizzo di alcune opzioni come:-i
(ascolta solo un'interfaccia), -p
(disattiva la modalità promiscua; meno invasiva) o alcune opzioni di output. Tcpdump ha bisogno dei permessi di root e al tuo capo potrebbe non piacere perché è una specie di strumento per hacker. D'altra parte, non hai bisogno di toccare nulla sul tuo sistema per eseguirlo (a differenza del iptables LOG
soluzione)
Si prega di notare anche la piccola differenza src/dsk nel filtro. Se catturi pacchetti SYN+ACK e vuoi contare le connessioni a un server alla porta 4711 è necessario src. Se stai intercettando pacchetti SYN+!ACK per lo stesso risultato, hai bisogno di dst. Se conti le connessioni sul server stesso, devi sempre usare il contrario.
Soluzione SystemTap
Script ispirato all'esempio 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)
}
}
}
Uscita:
[[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
soluzione strace
Avviare il programma sotto strace:
strace -r -f -e trace=accept -o /tmp/strace ${PROGRAM} ${ARGS}
o rintracciare un programma già in esecuzione:
strace -r -f -e trace=accept -o /tmp/strace -p ${PID_OF_PROGRAM}
-r
stampa un timestamp relativo all'ingresso di ogni chiamata di sistema nel caso in cui sia necessario in seguito per un'analisi delle prestazioni extra. -f
traccia i processi figlio e potrebbe non essere necessario.
L'output è simile a questo:
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
e può essere filtrato 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 spiegazione della battuta AKW:m[1]
è il PID, m[2]
è il timestamp, m[3]
è la porta remota e m[4]
è l'indirizzo remoto.
Il vantaggio di questa soluzione è che root non è richiesto se il server viene eseguito con lo stesso utente. Lo svantaggio è che vengono conteggiate tutte le connessioni, non ci sono filtri, quindi non funzionerà se l'applicazione è in ascolto su più porte.