5

我正在制作一个简单的期望脚本,它将监视 tcpdump 的输出以获取多播地址列表。我想知道在期望超时之前是否从列表中的每个多播地址接收到数据包。

我有一个可行的解决方案,但它效率低下,我相信我没有充分利用 expect 和 tcl 的力量。无论如何,这是我当前的脚本:

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

因此,正如您所看到的,脚本将一次查找每个 IP 地址,如果看到该 IP,它会将其添加到找到的地址列表中。如果期望超时,它会将地址添加到 not_found 列表中并搜索下一个地址。

现在回到我的问题:有没有一种方法可以在给定的时间内同时监控所有 IP 地址的 tcpdump。如果要找到该地址,我想将其添加到找到的地址列表中,并且最好不要再期待它(这可能是不可能的,我不确定)。关键是我需要脚本来并行监控列表中的所有 IP。我无法对每个地址进行硬编码,因为它们每次都会有所不同,而且我要查找的地址数量也会有所不同。我真的可以从期待大师那里得到一些帮助,哈哈。

谢谢你!

4

2 回答 2

3

这是一个有趣的问题。最简单的方法可能是运行时生成期望脚本的核心。幸运的是,Tcl非常擅长这种事情。(注意:我假设 IP 地址都是 IPv4 地址,并且仅包含数字和句点;如果插入的是一般字符串,我必须更加小心。)

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

您可能想要puts $expbody前几次,这样您就可以确定它正在做正确的事情。

于 2013-08-22T08:43:34.817 回答
0

这是我完成的脚本。它使用与 Donal 的解决方案相同的代码,但我添加了一些检查来解决一些没有考虑到的问题。

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 "# "
于 2013-08-28T15:24:27.883 回答