0

I am writing a web interface for a hardware device and am currently doing the network configuration wizard. I want to have the user choose the SSID and if it is secured, then enter a password. I want to check then and there that the password is correct without going any further in the wizard.

Is there any easier way to do this than throwing the details at wpa_supplicant and parsing log output?

YakovL
  • 7,557
  • 12
  • 62
  • 102
komatsu
  • 83
  • 2
  • 8

1 Answers1

0

Well, could find much, maybe my Google fu sucks. I ended up making this script to do it for me. It uses wpa_supplicant to try to connect and then parses the logs to look for certain strings that indicate auth failure or success. It is only tested with v2.3, if the log output is different in other versions it may not work properly.

It will always cause a current connection on the wireless interface you are testing from to drop momentarily but will come back as soon as the wpa_supplicant started by this script is killed by the script exiting.

#!/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
komatsu
  • 83
  • 2
  • 8