1289284Srpaulo#!/usr/bin/env python2 2289284Srpaulo# 3289284Srpaulo# eapol_test controller 4289284Srpaulo# Copyright (c) 2015, Jouni Malinen <j@w1.fi> 5289284Srpaulo# 6289284Srpaulo# This software may be distributed under the terms of the BSD license. 7289284Srpaulo# See README for more details. 8289284Srpaulo 9289284Srpauloimport argparse 10289284Srpauloimport logging 11289284Srpauloimport os 12289284Srpauloimport Queue 13289284Srpauloimport sys 14289284Srpauloimport threading 15289284Srpaulo 16289284Srpaulologger = logging.getLogger() 17289284Srpaulodir = os.path.dirname(os.path.realpath(sys.modules[__name__].__file__)) 18289284Srpaulosys.path.append(os.path.join(dir, '..', 'wpaspy')) 19289284Srpauloimport wpaspy 20289284Srpaulowpas_ctrl = '/tmp/eapol_test' 21289284Srpaulo 22289284Srpauloclass eapol_test: 23289284Srpaulo def __init__(self, ifname): 24289284Srpaulo self.ifname = ifname 25289284Srpaulo self.ctrl = wpaspy.Ctrl(os.path.join(wpas_ctrl, ifname)) 26289284Srpaulo if "PONG" not in self.ctrl.request("PING"): 27289284Srpaulo raise Exception("Failed to connect to eapol_test (%s)" % ifname) 28289284Srpaulo self.mon = wpaspy.Ctrl(os.path.join(wpas_ctrl, ifname)) 29289284Srpaulo self.mon.attach() 30289284Srpaulo 31289284Srpaulo def add_network(self): 32289284Srpaulo id = self.request("ADD_NETWORK") 33289284Srpaulo if "FAIL" in id: 34289284Srpaulo raise Exception("ADD_NETWORK failed") 35289284Srpaulo return int(id) 36289284Srpaulo 37289284Srpaulo def remove_network(self, id): 38289284Srpaulo id = self.request("REMOVE_NETWORK " + str(id)) 39289284Srpaulo if "FAIL" in id: 40289284Srpaulo raise Exception("REMOVE_NETWORK failed") 41289284Srpaulo return None 42289284Srpaulo 43289284Srpaulo def set_network(self, id, field, value): 44289284Srpaulo res = self.request("SET_NETWORK " + str(id) + " " + field + " " + value) 45289284Srpaulo if "FAIL" in res: 46289284Srpaulo raise Exception("SET_NETWORK failed") 47289284Srpaulo return None 48289284Srpaulo 49289284Srpaulo def set_network_quoted(self, id, field, value): 50289284Srpaulo res = self.request("SET_NETWORK " + str(id) + " " + field + ' "' + value + '"') 51289284Srpaulo if "FAIL" in res: 52289284Srpaulo raise Exception("SET_NETWORK failed") 53289284Srpaulo return None 54289284Srpaulo 55289284Srpaulo def request(self, cmd, timeout=10): 56289284Srpaulo return self.ctrl.request(cmd, timeout=timeout) 57289284Srpaulo 58289284Srpaulo def wait_event(self, events, timeout=10): 59289284Srpaulo start = os.times()[4] 60289284Srpaulo while True: 61289284Srpaulo while self.mon.pending(): 62289284Srpaulo ev = self.mon.recv() 63289284Srpaulo logger.debug(self.ifname + ": " + ev) 64289284Srpaulo for event in events: 65289284Srpaulo if event in ev: 66289284Srpaulo return ev 67289284Srpaulo now = os.times()[4] 68289284Srpaulo remaining = start + timeout - now 69289284Srpaulo if remaining <= 0: 70289284Srpaulo break 71289284Srpaulo if not self.mon.pending(timeout=remaining): 72289284Srpaulo break 73289284Srpaulo return None 74289284Srpaulo 75289284Srpaulodef run(ifname, count, no_fast_reauth, res): 76289284Srpaulo et = eapol_test(ifname) 77289284Srpaulo 78289284Srpaulo et.request("AP_SCAN 0") 79289284Srpaulo if no_fast_reauth: 80289284Srpaulo et.request("SET fast_reauth 0") 81289284Srpaulo else: 82289284Srpaulo et.request("SET fast_reauth 1") 83289284Srpaulo id = et.add_network() 84289284Srpaulo et.set_network(id, "key_mgmt", "IEEE8021X") 85289284Srpaulo et.set_network(id, "eapol_flags", "0") 86289284Srpaulo et.set_network(id, "eap", "TLS") 87289284Srpaulo et.set_network_quoted(id, "identity", "user") 88289284Srpaulo et.set_network_quoted(id, "ca_cert", 'ca.pem') 89289284Srpaulo et.set_network_quoted(id, "client_cert", 'client.pem') 90289284Srpaulo et.set_network_quoted(id, "private_key", 'client.key') 91289284Srpaulo et.set_network_quoted(id, "private_key_passwd", 'whatever') 92289284Srpaulo et.set_network(id, "disabled", "0") 93289284Srpaulo 94289284Srpaulo fail = False 95289284Srpaulo for i in range(count): 96289284Srpaulo et.request("REASSOCIATE") 97289284Srpaulo ev = et.wait_event(["CTRL-EVENT-CONNECTED", "CTRL-EVENT-EAP-FAILURE"]) 98289284Srpaulo if ev is None or "CTRL-EVENT-CONNECTED" not in ev: 99289284Srpaulo fail = True 100289284Srpaulo break 101289284Srpaulo 102289284Srpaulo et.remove_network(id) 103289284Srpaulo 104289284Srpaulo if fail: 105289284Srpaulo res.put("FAIL (%d OK)" % i) 106289284Srpaulo else: 107289284Srpaulo res.put("PASS %d" % (i + 1)) 108289284Srpaulo 109289284Srpaulodef main(): 110289284Srpaulo parser = argparse.ArgumentParser(description='eapol_test controller') 111289284Srpaulo parser.add_argument('--ctrl', help='control interface directory') 112289284Srpaulo parser.add_argument('--num', help='number of processes') 113289284Srpaulo parser.add_argument('--iter', help='number of iterations') 114289284Srpaulo parser.add_argument('--no-fast-reauth', action='store_true', 115289284Srpaulo dest='no_fast_reauth', 116289284Srpaulo help='disable TLS session resumption') 117289284Srpaulo args = parser.parse_args() 118289284Srpaulo 119289284Srpaulo num = int(args.num) 120289284Srpaulo iter = int(args.iter) 121289284Srpaulo if args.ctrl: 122289284Srpaulo global wpas_ctrl 123289284Srpaulo wpas_ctrl = args.ctrl 124289284Srpaulo 125289284Srpaulo t = {} 126289284Srpaulo res = {} 127289284Srpaulo for i in range(num): 128289284Srpaulo res[i] = Queue.Queue() 129289284Srpaulo t[i] = threading.Thread(target=run, args=(str(i), iter, 130289284Srpaulo args.no_fast_reauth, res[i])) 131289284Srpaulo for i in range(num): 132289284Srpaulo t[i].start() 133289284Srpaulo for i in range(num): 134289284Srpaulo t[i].join() 135289284Srpaulo try: 136289284Srpaulo results = res[i].get(False) 137289284Srpaulo except: 138289284Srpaulo results = "N/A" 139289284Srpaulo print "%d: %s" % (i, results) 140289284Srpaulo 141289284Srpauloif __name__ == "__main__": 142289284Srpaulo main() 143