まあ、多分、私のGoogle fuは吸うかもしれない。私はこのスクリプトを作って私のためにやりました。 wpa_supplicant
を使用して接続を試み、ログを解析して、認証失敗または成功を示す特定の文字列を探します。 v2.3でのみテストされます。ログ出力が他のバージョンと異なる場合、正常に動作しない可能性があります。
テストしているワイヤレスインターフェイスでは、一時的に現在の接続が切断されますが、このスクリプトで開始されたwpa_supplicant
が終了するとすぐに戻ります。
#!/usr/bin env ruby
# This script will run WPA to check authentication to a Wifi AP. It will return status 0 for success
# or status 1 for failure, as well as logging some information about what the script is doing.
#
# It has a built in timeout (default 15sec) in case something holds the script up, on a BeagleboneBlack
# this typically took ~10s for a failed auth, and ~2s for a successful auth. In most cases the WPA
# supplicant was killed before DHCP could configure the interface.
#
# In the case where the interface is already connected to an AP and configured via WPA/DHCP, this script
# will cause that connection to drop, regardless of AP auth success or failure. With the latter the
# connection is promptly restored after the script is finished, however with the former the connection
# may be momentarily reconfigured via DHCP to the new APs details, before control is given back to the
# original WPA process. It is unclear if this disconnection can be avoided.
#
# This has only been tested with wpa_supplicant v2.3
require 'logger'
require 'fileutils'
LOG_FILE = "/tmp/wpalog"
PIDFILE = "/tmp/wpapid"
LOG = Logger.new(STDOUT)
ssid = ARGV[0]
pass = ARGV[1]
timeout = 15
dev = "wlan0"
abort "Usage: #{$0} <ssid> <pass>" if ssid.nil? or pass.nil?
File.write(LOG_FILE, "")
# make sure we don't leave wpa running
at_exit do
kill_wpa!
end
# kill the auth process if it's pidfile exists
def kill_wpa!
if File.exist?(PIDFILE)
pid = File.read(PIDFILE).strip
LOG.info "Killing WPA on PID #{pid}"
Process.kill 9, pid.to_i
FileUtils.rm PIDFILE
end
end
# parse the log for indications of auth success/failure
def parse_log
log = File.read(LOG_FILE)
if log.include? "WPA: Key negotiation completed"
return true
end
if log.include?("pre-shared key may be incorrect") || log.include?("auth_failures=1")
return false
end
nil
end
# timeout so we don't keep going forever if theres some issue
Thread.new do
sleep timeout
LOG.fatal "Operation timed out"
exit
end
# run the process to try to auth to the AP
s = Time.now
LOG.info "Starting WPA Supplicant"
system "bash -c 'wpa_supplicant -Dwext -c <(wpa_passphrase \"#{ssid}\" \"#{pass}\") -B -P #{PIDFILE} -f #{LOG_FILE} -i #{dev} 2>/dev/null'"
result = nil
# loop until the parse_log gives us a non nil result indicating auth success or failure
LOG.info "Searching WPA log for authentication state"
loop do
result = parse_log
sleep 0.2 and next if result.nil?
break
end
f = Time.now
duration = (f - s).to_f.round(2)
LOG.info "Found authentication state in #{duration} seconds"
# kill WPA ASAP before DHCP takes over and changes the interface config
kill_wpa!
if result
LOG.info "Authentication successful"
else
LOG.error "Authentication failed"
end
# empty the log in case there are creds in it
File.write(LOG_FILE, "")
# use return values to signal auth failure or success
exit result ? 0 : 1