2013-08-22 10 views
5

Ich mache ein einfaches expect-Skript, das die Ausgabe von tcpdump für eine Liste von Multicast-Adressen überwacht. Ich möchte wissen, ob Pakete von jeder Multicast-Adresse in der Liste empfangen werden oder nicht, bevor das Zeitlimit überschritten wird.So suchen Sie nach mehreren Mustern, die in einer Liste gespeichert sind, bis alle Elemente gefunden wurden oder eine bestimmte Zeit verstrichen ist

Ich habe eine funktionierende Lösung, aber es ist ineffizient, und ich glaube, dass ich nicht die volle Kraft von expect und tcl nutzen. Wie auch immer, hier ist meine aktuelle Skript:

set multicast_list {225.0.0.1 225.0.0.2 225.0.0.3} 

send "tcpdump -i ixp1\r" 
# If tcpdump does not start, unzip it and run it again 
expect { 
    "tcpdump: listening on ixp1" {} 
    "sh: tcpdump: not found" { 
    send "gunzip /usr/sbin/tcpdump.gz\r" 
    expect "# " 
    send "tcpdump -i ixp1\r" 
    exp_continue 
    } 
} 
# Set timeout to the number of seconds expect will check for ip addresses 
set timeout 30 
set found [list] 
set not_found [list] 
foreach ip $multicast_list { 
    expect { 
    "> $ip" { lappend found "$ip" } 
    timeout { lappend not_found "$ip" } 
    } 
} 
set timeout 5 
# Send ^c to stop tcpdump 
send -- "\003" 
expect "# " 

So wie Sie das Skript für jede IP-Adresse aussehen wird einen nach dem anderen, und wenn die ip es es auf die Liste der gefundenen Adressen hinzufügen ist zu sehen, zu sehen. Wenn die Zeit abgelaufen ist, wird die Adresse zur nicht gefundenen Liste hinzugefügt und nach der nächsten Adresse gesucht.

Nun zurück zu meiner Frage: Gibt es eine Möglichkeit, tcpdump für alle IP-Adressen gleichzeitig über einen bestimmten Zeitraum zu überwachen. Wenn die Adresse gefunden werden soll, möchte ich sie zu der Liste der gefundenen Adressen hinzufügen und im Idealfall aufhören, sie zu erwarten (dies ist möglicherweise nicht möglich, da bin ich mir nicht sicher). Der Schlüssel ist, ich brauche das Skript, um für alle IPs in der Liste parallel zu überwachen. Ich kann nicht jede Adresse hart codieren, weil sie jedes Mal unterschiedlich sind und die Menge der Adressen, die ich suche, wird auch variieren. Ich könnte wirklich etwas Hilfe von einem erwarteten Guru lol gebrauchen.

Vielen Dank!

Antwort

0

Hier ist mein fertiges Skript. Es verwendet den gleichen Code von Donals Lösung, aber ich habe ein paar Überprüfungen hinzugefügt, um einige Probleme zu beheben, die nicht berücksichtigt wurden.

set multicast_list {225.0.0.1 225.0.0.2 225.0.0.3} 
set tcpdump_timeout 10 

spawn /bin/bash 
expect "] " 

# Create the runtime-generated expbody to use later 
# Generate the timeout clause as a normal literal 
set expbody { 
timeout { 
    set not_found [array names waiting] 
    unset waiting 
} 
} 
foreach ip $multicast_list { 
    set waiting($ip) "dummy" 
    # Generate the per-ip clause as a multi-line string; beware a few backslashes 
    append expbody "\"> $ip\" { 
    set currentTime \[clock seconds\] 
    if { \$currentTime < \$endTime } { 
     if { \[ info exists waiting($ip) \] } { 
     lappend found $ip 
     unset waiting($ip) 
     } 
     if {\[array size waiting\]} exp_continue 
    } 
}\n" 
} 

# Set expect timeout and create empty lists for tcpdump results 
set timeout $tcpdump_timeout 
set found [list] 
set not_found [list] 

# Start tcpdump 
send "tcpdump -i ixp1\r" 
expect "tcpdump: listening on ixp1" 

# Get the time to stop tcpdump 
set endTime [ expr [clock seconds] + $tcpdump_timeout ] 

# Feed expbody into expect; it's none-the-wiser that it was runtime-generated 
expect $expbody 
set not_found [array names waiting] 
unset waiting 
# Send ^c to stop tcpdump 
send -- "\003" 
expect "# " 
3

Das ist ein interessantes Problem. Der einfachste Weg ist wahrscheinlich die Runtime-Generierung des Kerns des Expect-Skripts. Zum Glück, Tcl sehr gut in dieser Art von Sache. (Anmerkung: Ich gehe davon aus, dass die IP-Adressen sind alle IPv4-Adressen und bestehen aus nur Zahlen und Punkte, wenn es eine allgemeine Zeichenfolge eingefügt wird, würde ich ein wenig vorsichtiger sein müssen.)

set timeout 30 
set found [list] 
set not_found [list] 
# Generate the timeout clause as a normal literal 
set expbody { 
    timeout { 
     set not_found [array names waiting] 
     unset waiting 
    } 
} 
foreach ip $multicast_list { 
    set waiting($ip) "dummy" 
    # Generate the per-ip clause as a multi-line string; beware a few backslashes 
    append expbody "\"> $ip\" { 
     lappend found $ip 
     unset waiting($ip) 
     if {\[array size waiting\]} exp_continue 
    }\n" 
} 
# Feed into expect; it's none-the-wiser that it was runtime-generated 
expect $expbody 
set timeout 5 
# Send ^c to stop tcpdump 
send -- "\003" 
expect "# " 

Vielleicht möchten Sie die ersten Male puts $expbody, nur so können Sie sicher sein, dass es das Richtige tut.

+0

Vielen Dank Donnal! Das hat mich definitiv auf den richtigen Weg gebracht, aber ich habe immer noch Probleme. Mein Hauptproblem ist jetzt, dass tcpdump ständig Multicast-Pakete von den Adressen in multicast_list empfängt. Wenn also einmal ein Paket von 225.0.0.1 erwartet wird, wird es zur gefundenen Liste hinzugefügt, was großartig ist. Aber dann wird es ein weiteres Paket von der gleichen Adresse empfangen und erwartet wird erneut ausgelöst, anstatt es zu ignorieren. Dies bewirkt, dass der Erwartungswert niemals überschritten wird. Auch mit Ihrem Code bekomme ich einen Fehler, da versucht wird, die Adresse aus der Warteliste zu entfernen, obwohl sie bereits entfernt wurde ... –