test_radius.py 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592
  1. # RADIUS tests
  2. # Copyright (c) 2013-2014, Jouni Malinen <j@w1.fi>
  3. #
  4. # This software may be distributed under the terms of the BSD license.
  5. # See README for more details.
  6. import logging
  7. logger = logging.getLogger()
  8. import subprocess
  9. import time
  10. import hostapd
  11. def connect(dev, ssid, wait_connect=True):
  12. dev.connect(ssid, key_mgmt="WPA-EAP", scan_freq="2412",
  13. eap="PSK", identity="psk.user@example.com",
  14. password_hex="0123456789abcdef0123456789abcdef",
  15. wait_connect=wait_connect)
  16. def test_radius_auth_unreachable(dev, apdev):
  17. """RADIUS Authentication server unreachable"""
  18. params = hostapd.wpa2_eap_params(ssid="radius-auth")
  19. params['auth_server_port'] = "18139"
  20. hostapd.add_ap(apdev[0]['ifname'], params)
  21. hapd = hostapd.Hostapd(apdev[0]['ifname'])
  22. connect(dev[0], "radius-auth", wait_connect=False)
  23. ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"])
  24. if ev is None:
  25. raise Exception("Timeout on EAP start")
  26. logger.info("Checking for RADIUS retries")
  27. time.sleep(4)
  28. mib = hapd.get_mib()
  29. if "radiusAuthClientAccessRequests" not in mib:
  30. raise Exception("Missing MIB fields")
  31. if int(mib["radiusAuthClientAccessRetransmissions"]) < 1:
  32. raise Exception("Missing RADIUS Authentication retransmission")
  33. if int(mib["radiusAuthClientPendingRequests"]) < 1:
  34. raise Exception("Missing pending RADIUS Authentication request")
  35. def test_radius_auth_unreachable2(dev, apdev):
  36. """RADIUS Authentication server unreachable (2)"""
  37. subprocess.call(['sudo', 'ip', 'ro', 'replace', '192.168.213.17', 'dev',
  38. 'lo'])
  39. params = hostapd.wpa2_eap_params(ssid="radius-auth")
  40. params['auth_server_addr'] = "192.168.213.17"
  41. params['auth_server_port'] = "18139"
  42. hostapd.add_ap(apdev[0]['ifname'], params)
  43. hapd = hostapd.Hostapd(apdev[0]['ifname'])
  44. subprocess.call(['sudo', 'ip', 'ro', 'del', '192.168.213.17', 'dev', 'lo'])
  45. connect(dev[0], "radius-auth", wait_connect=False)
  46. ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED"])
  47. if ev is None:
  48. raise Exception("Timeout on EAP start")
  49. logger.info("Checking for RADIUS retries")
  50. time.sleep(4)
  51. mib = hapd.get_mib()
  52. if "radiusAuthClientAccessRequests" not in mib:
  53. raise Exception("Missing MIB fields")
  54. if int(mib["radiusAuthClientAccessRetransmissions"]) < 1:
  55. raise Exception("Missing RADIUS Authentication retransmission")
  56. def test_radius_acct_unreachable(dev, apdev):
  57. """RADIUS Accounting server unreachable"""
  58. params = hostapd.wpa2_eap_params(ssid="radius-acct")
  59. params['acct_server_addr'] = "127.0.0.1"
  60. params['acct_server_port'] = "18139"
  61. params['acct_server_shared_secret'] = "radius"
  62. hostapd.add_ap(apdev[0]['ifname'], params)
  63. hapd = hostapd.Hostapd(apdev[0]['ifname'])
  64. connect(dev[0], "radius-acct")
  65. logger.info("Checking for RADIUS retries")
  66. time.sleep(4)
  67. mib = hapd.get_mib()
  68. if "radiusAccClientRetransmissions" not in mib:
  69. raise Exception("Missing MIB fields")
  70. if int(mib["radiusAccClientRetransmissions"]) < 2:
  71. raise Exception("Missing RADIUS Accounting retransmissions")
  72. if int(mib["radiusAccClientPendingRequests"]) < 2:
  73. raise Exception("Missing pending RADIUS Accounting requests")
  74. def test_radius_acct_unreachable2(dev, apdev):
  75. """RADIUS Accounting server unreachable(2)"""
  76. subprocess.call(['sudo', 'ip', 'ro', 'replace', '192.168.213.17', 'dev',
  77. 'lo'])
  78. params = hostapd.wpa2_eap_params(ssid="radius-acct")
  79. params['acct_server_addr'] = "192.168.213.17"
  80. params['acct_server_port'] = "18139"
  81. params['acct_server_shared_secret'] = "radius"
  82. hostapd.add_ap(apdev[0]['ifname'], params)
  83. hapd = hostapd.Hostapd(apdev[0]['ifname'])
  84. subprocess.call(['sudo', 'ip', 'ro', 'del', '192.168.213.17', 'dev', 'lo'])
  85. connect(dev[0], "radius-acct")
  86. logger.info("Checking for RADIUS retries")
  87. time.sleep(4)
  88. mib = hapd.get_mib()
  89. if "radiusAccClientRetransmissions" not in mib:
  90. raise Exception("Missing MIB fields")
  91. if int(mib["radiusAccClientRetransmissions"]) < 1 and int(mib["radiusAccClientPendingRequests"]) < 1:
  92. raise Exception("Missing pending or retransmitted RADIUS Accounting requests")
  93. def test_radius_acct(dev, apdev):
  94. """RADIUS Accounting"""
  95. as_hapd = hostapd.Hostapd("as")
  96. as_mib_start = as_hapd.get_mib(param="radius_server")
  97. params = hostapd.wpa2_eap_params(ssid="radius-acct")
  98. params['acct_server_addr'] = "127.0.0.1"
  99. params['acct_server_port'] = "1813"
  100. params['acct_server_shared_secret'] = "radius"
  101. params['radius_auth_req_attr'] = [ "126:s:Operator", "77:s:testing" ]
  102. params['radius_acct_req_attr'] = [ "126:s:Operator", "77:s:testing" ]
  103. hostapd.add_ap(apdev[0]['ifname'], params)
  104. hapd = hostapd.Hostapd(apdev[0]['ifname'])
  105. connect(dev[0], "radius-acct")
  106. dev[1].connect("radius-acct", key_mgmt="WPA-EAP", scan_freq="2412",
  107. eap="PAX", identity="test-class",
  108. password_hex="0123456789abcdef0123456789abcdef")
  109. dev[2].connect("radius-acct", key_mgmt="WPA-EAP",
  110. eap="GPSK", identity="gpsk-cui",
  111. password="abcdefghijklmnop0123456789abcdef",
  112. scan_freq="2412")
  113. logger.info("Checking for RADIUS counters")
  114. count = 0
  115. while True:
  116. mib = hapd.get_mib()
  117. if int(mib['radiusAccClientResponses']) >= 3:
  118. break
  119. time.sleep(0.1)
  120. count += 1
  121. if count > 10:
  122. raise Exception("Did not receive Accounting-Response packets")
  123. if int(mib['radiusAccClientRetransmissions']) > 0:
  124. raise Exception("Unexpected Accounting-Request retransmission")
  125. as_mib_end = as_hapd.get_mib(param="radius_server")
  126. req_s = int(as_mib_start['radiusAccServTotalRequests'])
  127. req_e = int(as_mib_end['radiusAccServTotalRequests'])
  128. if req_e < req_s + 2:
  129. raise Exception("Unexpected RADIUS server acct MIB value")
  130. acc_s = int(as_mib_start['radiusAuthServAccessAccepts'])
  131. acc_e = int(as_mib_end['radiusAuthServAccessAccepts'])
  132. if acc_e < acc_s + 1:
  133. raise Exception("Unexpected RADIUS server auth MIB value")
  134. def test_radius_acct_interim(dev, apdev):
  135. """RADIUS Accounting interim update"""
  136. as_hapd = hostapd.Hostapd("as")
  137. params = hostapd.wpa2_eap_params(ssid="radius-acct")
  138. params['acct_server_addr'] = "127.0.0.1"
  139. params['acct_server_port'] = "1813"
  140. params['acct_server_shared_secret'] = "radius"
  141. params['radius_acct_interim_interval'] = "1"
  142. hostapd.add_ap(apdev[0]['ifname'], params)
  143. hapd = hostapd.Hostapd(apdev[0]['ifname'])
  144. connect(dev[0], "radius-acct")
  145. logger.info("Checking for RADIUS counters")
  146. as_mib_start = as_hapd.get_mib(param="radius_server")
  147. time.sleep(3.1)
  148. as_mib_end = as_hapd.get_mib(param="radius_server")
  149. req_s = int(as_mib_start['radiusAccServTotalRequests'])
  150. req_e = int(as_mib_end['radiusAccServTotalRequests'])
  151. if req_e < req_s + 3:
  152. raise Exception("Unexpected RADIUS server acct MIB value")
  153. def test_radius_acct_interim_unreachable(dev, apdev):
  154. """RADIUS Accounting interim update with unreachable server"""
  155. params = hostapd.wpa2_eap_params(ssid="radius-acct")
  156. params['acct_server_addr'] = "127.0.0.1"
  157. params['acct_server_port'] = "18139"
  158. params['acct_server_shared_secret'] = "radius"
  159. params['radius_acct_interim_interval'] = "1"
  160. hapd = hostapd.add_ap(apdev[0]['ifname'], params)
  161. start = hapd.get_mib()
  162. connect(dev[0], "radius-acct")
  163. logger.info("Waiting for interium accounting updates")
  164. time.sleep(3.1)
  165. end = hapd.get_mib()
  166. req_s = int(start['radiusAccClientTimeouts'])
  167. req_e = int(end['radiusAccClientTimeouts'])
  168. if req_e < req_s + 2:
  169. raise Exception("Unexpected RADIUS server acct MIB value")
  170. def test_radius_das_disconnect(dev, apdev):
  171. """RADIUS Dynamic Authorization Extensions - Disconnect"""
  172. try:
  173. import pyrad.client
  174. import pyrad.packet
  175. import pyrad.dictionary
  176. import radius_das
  177. except ImportError:
  178. return "skip"
  179. params = hostapd.wpa2_eap_params(ssid="radius-das")
  180. params['radius_das_port'] = "3799"
  181. params['radius_das_client'] = "127.0.0.1 secret"
  182. params['radius_das_require_event_timestamp'] = "1"
  183. params['own_ip_addr'] = "127.0.0.1"
  184. params['nas_identifier'] = "nas.example.com"
  185. hapd = hostapd.add_ap(apdev[0]['ifname'], params)
  186. connect(dev[0], "radius-das")
  187. addr = dev[0].p2p_interface_addr()
  188. sta = hapd.get_sta(addr)
  189. id = sta['dot1xAuthSessionId']
  190. dict = pyrad.dictionary.Dictionary("dictionary.radius")
  191. srv = pyrad.client.Client(server="127.0.0.1", acctport=3799,
  192. secret="secret", dict=dict)
  193. srv.retries = 1
  194. srv.timeout = 1
  195. logger.info("Disconnect-Request with incorrect secret")
  196. req = radius_das.DisconnectPacket(dict=dict, secret="incorrect",
  197. User_Name="foo",
  198. NAS_Identifier="localhost",
  199. Event_Timestamp=int(time.time()))
  200. logger.debug(req)
  201. try:
  202. reply = srv.SendPacket(req)
  203. raise Exception("Unexpected response to Disconnect-Request")
  204. except pyrad.client.Timeout:
  205. logger.info("Disconnect-Request with incorrect secret properly ignored")
  206. logger.info("Disconnect-Request without Event-Timestamp")
  207. req = radius_das.DisconnectPacket(dict=dict, secret="secret",
  208. User_Name="psk.user@example.com")
  209. logger.debug(req)
  210. try:
  211. reply = srv.SendPacket(req)
  212. raise Exception("Unexpected response to Disconnect-Request")
  213. except pyrad.client.Timeout:
  214. logger.info("Disconnect-Request without Event-Timestamp properly ignored")
  215. logger.info("Disconnect-Request with non-matching Event-Timestamp")
  216. req = radius_das.DisconnectPacket(dict=dict, secret="secret",
  217. User_Name="psk.user@example.com",
  218. Event_Timestamp=123456789)
  219. logger.debug(req)
  220. try:
  221. reply = srv.SendPacket(req)
  222. raise Exception("Unexpected response to Disconnect-Request")
  223. except pyrad.client.Timeout:
  224. logger.info("Disconnect-Request with non-matching Event-Timestamp properly ignored")
  225. logger.info("Disconnect-Request with unsupported attribute")
  226. req = radius_das.DisconnectPacket(dict=dict, secret="secret",
  227. User_Name="foo",
  228. User_Password="foo",
  229. Event_Timestamp=int(time.time()))
  230. reply = srv.SendPacket(req)
  231. logger.debug("RADIUS response from hostapd")
  232. for i in reply.keys():
  233. logger.debug("%s: %s" % (i, reply[i]))
  234. if reply.code != pyrad.packet.DisconnectNAK:
  235. raise Exception("Unexpected response code")
  236. if 'Error-Cause' not in reply:
  237. raise Exception("Missing Error-Cause")
  238. if reply['Error-Cause'][0] != 401:
  239. raise Exception("Unexpected Error-Cause: {}".format(reply['Error-Cause']))
  240. logger.info("Disconnect-Request with invalid Calling-Station-Id")
  241. req = radius_das.DisconnectPacket(dict=dict, secret="secret",
  242. User_Name="foo",
  243. Calling_Station_Id="foo",
  244. Event_Timestamp=int(time.time()))
  245. reply = srv.SendPacket(req)
  246. logger.debug("RADIUS response from hostapd")
  247. for i in reply.keys():
  248. logger.debug("%s: %s" % (i, reply[i]))
  249. if reply.code != pyrad.packet.DisconnectNAK:
  250. raise Exception("Unexpected response code")
  251. if 'Error-Cause' not in reply:
  252. raise Exception("Missing Error-Cause")
  253. if reply['Error-Cause'][0] != 407:
  254. raise Exception("Unexpected Error-Cause: {}".format(reply['Error-Cause']))
  255. logger.info("Disconnect-Request with mismatching User-Name")
  256. req = radius_das.DisconnectPacket(dict=dict, secret="secret",
  257. User_Name="foo",
  258. Event_Timestamp=int(time.time()))
  259. reply = srv.SendPacket(req)
  260. logger.debug("RADIUS response from hostapd")
  261. for i in reply.keys():
  262. logger.debug("%s: %s" % (i, reply[i]))
  263. if reply.code != pyrad.packet.DisconnectNAK:
  264. raise Exception("Unexpected response code")
  265. if 'Error-Cause' not in reply:
  266. raise Exception("Missing Error-Cause")
  267. if reply['Error-Cause'][0] != 503:
  268. raise Exception("Unexpected Error-Cause: {}".format(reply['Error-Cause']))
  269. logger.info("Disconnect-Request with mismatching Calling-Station-Id")
  270. req = radius_das.DisconnectPacket(dict=dict, secret="secret",
  271. Calling_Station_Id="12:34:56:78:90:aa",
  272. Event_Timestamp=int(time.time()))
  273. reply = srv.SendPacket(req)
  274. logger.debug("RADIUS response from hostapd")
  275. for i in reply.keys():
  276. logger.debug("%s: %s" % (i, reply[i]))
  277. if reply.code != pyrad.packet.DisconnectNAK:
  278. raise Exception("Unexpected response code")
  279. if 'Error-Cause' not in reply:
  280. raise Exception("Missing Error-Cause")
  281. if reply['Error-Cause'][0] != 503:
  282. raise Exception("Unexpected Error-Cause: {}".format(reply['Error-Cause']))
  283. logger.info("Disconnect-Request with mismatching Acct-Session-Id")
  284. req = radius_das.DisconnectPacket(dict=dict, secret="secret",
  285. Acct_Session_Id="12345678-87654321",
  286. Event_Timestamp=int(time.time()))
  287. reply = srv.SendPacket(req)
  288. logger.debug("RADIUS response from hostapd")
  289. for i in reply.keys():
  290. logger.debug("%s: %s" % (i, reply[i]))
  291. if reply.code != pyrad.packet.DisconnectNAK:
  292. raise Exception("Unexpected response code")
  293. if 'Error-Cause' not in reply:
  294. raise Exception("Missing Error-Cause")
  295. if reply['Error-Cause'][0] != 503:
  296. raise Exception("Unexpected Error-Cause: {}".format(reply['Error-Cause']))
  297. ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=1)
  298. if ev is not None:
  299. raise Exception("Unexpected disconnection")
  300. logger.info("Disconnect-Request with mismatching NAS-IP-Address")
  301. req = radius_das.DisconnectPacket(dict=dict, secret="secret",
  302. NAS_IP_Address="192.168.3.4",
  303. Acct_Session_Id=id,
  304. Event_Timestamp=int(time.time()))
  305. reply = srv.SendPacket(req)
  306. logger.debug("RADIUS response from hostapd")
  307. for i in reply.keys():
  308. logger.debug("%s: %s" % (i, reply[i]))
  309. if reply.code != pyrad.packet.DisconnectNAK:
  310. raise Exception("Unexpected response code")
  311. if 'Error-Cause' not in reply:
  312. raise Exception("Missing Error-Cause")
  313. if reply['Error-Cause'][0] != 403:
  314. raise Exception("Unexpected Error-Cause: {}".format(reply['Error-Cause']))
  315. logger.info("Disconnect-Request with mismatching NAS-Identifier")
  316. req = radius_das.DisconnectPacket(dict=dict, secret="secret",
  317. NAS_Identifier="unknown.example.com",
  318. Acct_Session_Id=id,
  319. Event_Timestamp=int(time.time()))
  320. reply = srv.SendPacket(req)
  321. logger.debug("RADIUS response from hostapd")
  322. for i in reply.keys():
  323. logger.debug("%s: %s" % (i, reply[i]))
  324. if reply.code != pyrad.packet.DisconnectNAK:
  325. raise Exception("Unexpected response code")
  326. if 'Error-Cause' not in reply:
  327. raise Exception("Missing Error-Cause")
  328. if reply['Error-Cause'][0] != 403:
  329. raise Exception("Unexpected Error-Cause: {}".format(reply['Error-Cause']))
  330. ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=1)
  331. if ev is not None:
  332. raise Exception("Unexpected disconnection")
  333. logger.info("Disconnect-Request with matching Acct-Session-Id")
  334. req = radius_das.DisconnectPacket(dict=dict, secret="secret",
  335. NAS_IP_Address="127.0.0.1",
  336. NAS_Identifier="nas.example.com",
  337. Acct_Session_Id=id,
  338. Event_Timestamp=int(time.time()))
  339. reply = srv.SendPacket(req)
  340. logger.debug("RADIUS response from hostapd")
  341. for i in reply.keys():
  342. logger.debug("%s: %s" % (i, reply[i]))
  343. if reply.code != pyrad.packet.DisconnectACK:
  344. raise Exception("Unexpected response code")
  345. ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"])
  346. if ev is None:
  347. raise Exception("Timeout while waiting for disconnection")
  348. ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"])
  349. if ev is None:
  350. raise Exception("Timeout while waiting for re-connection")
  351. logger.info("Disconnect-Request with matching User-Name")
  352. req = radius_das.DisconnectPacket(dict=dict, secret="secret",
  353. NAS_Identifier="nas.example.com",
  354. User_Name="psk.user@example.com",
  355. Event_Timestamp=int(time.time()))
  356. reply = srv.SendPacket(req)
  357. logger.debug("RADIUS response from hostapd")
  358. for i in reply.keys():
  359. logger.debug("%s: %s" % (i, reply[i]))
  360. if reply.code != pyrad.packet.DisconnectACK:
  361. raise Exception("Unexpected response code")
  362. ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"])
  363. if ev is None:
  364. raise Exception("Timeout while waiting for disconnection")
  365. ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"])
  366. if ev is None:
  367. raise Exception("Timeout while waiting for re-connection")
  368. logger.info("Disconnect-Request with matching Calling-Station-Id")
  369. req = radius_das.DisconnectPacket(dict=dict, secret="secret",
  370. NAS_IP_Address="127.0.0.1",
  371. Calling_Station_Id=addr,
  372. Event_Timestamp=int(time.time()))
  373. reply = srv.SendPacket(req)
  374. logger.debug("RADIUS response from hostapd")
  375. for i in reply.keys():
  376. logger.debug("%s: %s" % (i, reply[i]))
  377. if reply.code != pyrad.packet.DisconnectACK:
  378. raise Exception("Unexpected response code")
  379. ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"])
  380. if ev is None:
  381. raise Exception("Timeout while waiting for disconnection")
  382. ev = dev[0].wait_event(["CTRL-EVENT-EAP-STARTED", "CTRL-EVENT-CONNECTED"])
  383. if ev is None:
  384. raise Exception("Timeout while waiting for re-connection")
  385. if "CTRL-EVENT-EAP-STARTED" not in ev:
  386. raise Exception("Unexpected skipping of EAP authentication in reconnection")
  387. ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"])
  388. if ev is None:
  389. raise Exception("Timeout while waiting for re-connection to complete")
  390. logger.info("Disconnect-Request with matching Calling-Station-Id and non-matching CUI")
  391. req = radius_das.DisconnectPacket(dict=dict, secret="secret",
  392. Calling_Station_Id=addr,
  393. Chargeable_User_Identity="foo@example.com",
  394. Event_Timestamp=int(time.time()))
  395. reply = srv.SendPacket(req)
  396. logger.debug("RADIUS response from hostapd")
  397. for i in reply.keys():
  398. logger.debug("%s: %s" % (i, reply[i]))
  399. if reply.code != pyrad.packet.DisconnectACK:
  400. raise Exception("Unexpected response code")
  401. ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"])
  402. if ev is None:
  403. raise Exception("Timeout while waiting for disconnection")
  404. ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"])
  405. if ev is None:
  406. raise Exception("Timeout while waiting for re-connection")
  407. logger.info("Disconnect-Request with matching CUI")
  408. dev[1].connect("radius-das", key_mgmt="WPA-EAP",
  409. eap="GPSK", identity="gpsk-cui",
  410. password="abcdefghijklmnop0123456789abcdef",
  411. scan_freq="2412")
  412. req = radius_das.DisconnectPacket(dict=dict, secret="secret",
  413. Chargeable_User_Identity="gpsk-chargeable-user-identity",
  414. Event_Timestamp=int(time.time()))
  415. reply = srv.SendPacket(req)
  416. logger.debug("RADIUS response from hostapd")
  417. for i in reply.keys():
  418. logger.debug("%s: %s" % (i, reply[i]))
  419. if reply.code != pyrad.packet.DisconnectACK:
  420. raise Exception("Unexpected response code")
  421. ev = dev[1].wait_event(["CTRL-EVENT-DISCONNECTED"])
  422. if ev is None:
  423. raise Exception("Timeout while waiting for disconnection")
  424. ev = dev[1].wait_event(["CTRL-EVENT-CONNECTED"])
  425. if ev is None:
  426. raise Exception("Timeout while waiting for re-connection")
  427. ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=1)
  428. if ev is not None:
  429. raise Exception("Unexpected disconnection")
  430. def test_radius_das_coa(dev, apdev):
  431. """RADIUS Dynamic Authorization Extensions - CoA"""
  432. try:
  433. import pyrad.client
  434. import pyrad.packet
  435. import pyrad.dictionary
  436. import radius_das
  437. except ImportError:
  438. return "skip"
  439. params = hostapd.wpa2_eap_params(ssid="radius-das")
  440. params['radius_das_port'] = "3799"
  441. params['radius_das_client'] = "127.0.0.1 secret"
  442. params['radius_das_require_event_timestamp'] = "1"
  443. hapd = hostapd.add_ap(apdev[0]['ifname'], params)
  444. connect(dev[0], "radius-das")
  445. addr = dev[0].p2p_interface_addr()
  446. sta = hapd.get_sta(addr)
  447. id = sta['dot1xAuthSessionId']
  448. dict = pyrad.dictionary.Dictionary("dictionary.radius")
  449. srv = pyrad.client.Client(server="127.0.0.1", acctport=3799,
  450. secret="secret", dict=dict)
  451. srv.retries = 1
  452. srv.timeout = 1
  453. # hostapd does not currently support CoA-Request, so NAK is expected
  454. logger.info("CoA-Request with matching Acct-Session-Id")
  455. req = radius_das.CoAPacket(dict=dict, secret="secret",
  456. Acct_Session_Id=id,
  457. Event_Timestamp=int(time.time()))
  458. reply = srv.SendPacket(req)
  459. logger.debug("RADIUS response from hostapd")
  460. for i in reply.keys():
  461. logger.debug("%s: %s" % (i, reply[i]))
  462. if reply.code != pyrad.packet.CoANAK:
  463. raise Exception("Unexpected response code")
  464. if 'Error-Cause' not in reply:
  465. raise Exception("Missing Error-Cause")
  466. if reply['Error-Cause'][0] != 405:
  467. raise Exception("Unexpected Error-Cause: {}".format(reply['Error-Cause']))
  468. def test_radius_ipv6(dev, apdev):
  469. """RADIUS connection over IPv6"""
  470. params = {}
  471. params['ssid'] = 'as'
  472. params['beacon_int'] = '2000'
  473. params['radius_server_clients'] = 'auth_serv/radius_clients_ipv6.conf'
  474. params['radius_server_ipv6'] = '1'
  475. params['radius_server_auth_port'] = '18129'
  476. params['radius_server_acct_port'] = '18139'
  477. params['eap_server'] = '1'
  478. params['eap_user_file'] = 'auth_serv/eap_user.conf'
  479. params['ca_cert'] = 'auth_serv/ca.pem'
  480. params['server_cert'] = 'auth_serv/server.pem'
  481. params['private_key'] = 'auth_serv/server.key'
  482. hostapd.add_ap(apdev[1]['ifname'], params)
  483. params = hostapd.wpa2_eap_params(ssid="radius-ipv6")
  484. params['auth_server_addr'] = "::0"
  485. params['auth_server_port'] = "18129"
  486. params['acct_server_addr'] = "::0"
  487. params['acct_server_port'] = "18139"
  488. params['acct_server_shared_secret'] = "radius"
  489. params['own_ip_addr'] = "::0"
  490. hostapd.add_ap(apdev[0]['ifname'], params)
  491. connect(dev[0], "radius-ipv6")
  492. def test_radius_macacl(dev, apdev):
  493. """RADIUS MAC ACL"""
  494. params = hostapd.radius_params()
  495. params["ssid"] = "radius"
  496. params["macaddr_acl"] = "2"
  497. hostapd.add_ap(apdev[0]['ifname'], params)
  498. dev[0].connect("radius", key_mgmt="NONE", scan_freq="2412")
  499. def test_radius_failover(dev, apdev):
  500. """RADIUS Authentication and Accounting server failover"""
  501. subprocess.call(['sudo', 'ip', 'ro', 'replace', '192.168.213.17', 'dev',
  502. 'lo'])
  503. as_hapd = hostapd.Hostapd("as")
  504. as_mib_start = as_hapd.get_mib(param="radius_server")
  505. params = hostapd.wpa2_eap_params(ssid="radius-failover")
  506. params["auth_server_addr"] = "192.168.213.17"
  507. params["auth_server_port"] = "1812"
  508. params["auth_server_shared_secret"] = "testing"
  509. params['acct_server_addr'] = "192.168.213.17"
  510. params['acct_server_port'] = "1813"
  511. params['acct_server_shared_secret'] = "testing"
  512. hapd = hostapd.add_ap(apdev[0]['ifname'], params, no_enable=True)
  513. hapd.set("auth_server_addr", "127.0.0.1")
  514. hapd.set("auth_server_port", "1812")
  515. hapd.set("auth_server_shared_secret", "radius")
  516. hapd.set('acct_server_addr', "127.0.0.1")
  517. hapd.set('acct_server_port', "1813")
  518. hapd.set('acct_server_shared_secret', "radius")
  519. hapd.enable()
  520. ev = hapd.wait_event(["AP-ENABLED", "AP-DISABLED"], timeout=30)
  521. if ev is None:
  522. raise Exception("AP startup timed out")
  523. if "AP-ENABLED" not in ev:
  524. raise Exception("AP startup failed")
  525. try:
  526. subprocess.call(['sudo', 'ip', 'ro', 'replace', 'prohibit',
  527. '192.168.213.17'])
  528. dev[0].request("SET EAPOL::authPeriod 5")
  529. connect(dev[0], "radius-failover", wait_connect=False)
  530. ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"], timeout=60)
  531. if ev is None:
  532. raise Exception("Connection with the AP timed out")
  533. finally:
  534. dev[0].request("SET EAPOL::authPeriod 30")
  535. subprocess.call(['sudo', 'ip', 'ro', 'del', '192.168.213.17'])
  536. as_mib_end = as_hapd.get_mib(param="radius_server")
  537. req_s = int(as_mib_start['radiusAccServTotalRequests'])
  538. req_e = int(as_mib_end['radiusAccServTotalRequests'])
  539. if req_e <= req_s:
  540. raise Exception("Unexpected RADIUS server acct MIB value")