Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to search for multiple patterns stored in a list until all items are found or a set amount of time has passed

Tags:

expect

tcl

I'm making a simple expect script that will monitor the output of tcpdump for a list of multicast addresses. I want to know if packets are received or not from each multicast address in the list before expect times out.

I have a working solution, but it is inefficient and I believe I'm not utilizing the full power of expect and tcl. Anyway here is my current script:

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 as you can see the script will look for each ip address one at a time and if the ip is seen it will add it to the list of found addresses. If expect times out it will add the address to the not_found list and search for the next address.

Now back to my question: Is there a way in which I can monitor tcpdump for all IP addresses simultaneously over a given amount of time. If the address were to be found I want to add it to the list of found addresses and ideally stop expecting it (this may not be possible, I'm not sure). The key is I need the script to monitor for all IP's in the list in parallel. I can't hard code each address because they will be different each time and the amount of addresses I am looking for will also vary. I could really use some help from an expect guru lol.

Thank You!

like image 694
The CodeWriter Avatar asked Oct 22 '22 02:10

The CodeWriter


1 Answers

That's an interesting problem. The easiest way is probably to do runtime generation of the core of the expect script. Fortunately, Tcl's very good at that sort of thing. (Note: I'm assuming that IP addresses are all IPv4 addresses and consist of just numbers and periods; if it was a general string being inserted, I'd have to be a little more careful.)

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 "# "

You might want to puts $expbody the first few times, just so you can be sure that it is doing the right thing.

like image 129
Donal Fellows Avatar answered Oct 25 '22 18:10

Donal Fellows