Jekyll2022-03-22T17:17:18+00:00https://richardatkin.com/feed.xmlrichardatkin.comRichard AtkinStreaming environmental air quality telemetry from the Cisco Catalyst 9136 Access Point2022-03-22T00:00:00+00:002022-03-22T00:00:00+00:00https://richardatkin.com/post/2022/03/22/Streaming-environmental-air-quality-data-from-the-Cisco-Catalyst-9136-WiFi6e-Access-Point<p>I’ve said this before - the Cisco Catalyst 9136 WiFi-6e Access Point is a big deal. The 9136 brings tonnes of new features to the party, including WiFi-6e, dual-mGig, PoE resiliency, and an <strong>Environmental Air Quality Sensor</strong>.</p>
<p>Regardless of your views about the COVID pandemic, the need for better ventilation and good quality air has become a key talking point, and as the saying goes, <em>if you can’t monitor something, you can’t manage it.</em> Cisco’s Catalyst 9136 WiFi-6e Access Point lets you do just that - monitor the air - because for the first time ever, this is a Cisco WiFi Access Point that includes an Environmental Air Quality Sensor. The AP’s Sensor reports on Temperature, Humidity, Total Volatile Organic Compounds and provides a calculated Indoor Air Quality index.</p>
<p>If you’re new to Air Quality monitoring (like I was!), you can learn more about it here <a href="https://www.renesas.com/us/en/document/whp/overview-tvoc-and-indoor-air-quality">https://www.renesas.com/us/en/document/whp/overview-tvoc-and-indoor-air-quality</a> and here <a href="https://www.worldgbc.org/sites/default/files/bp-resource/BPFP-IEQ-Guidance-Note.pdf">https://www.worldgbc.org/sites/default/files/bp-resource/BPFP-IEQ-Guidance-Note.pdf</a>.</p>
<h1 id="air-quality-monitoring">Air Quality Monitoring</h1>
<p>Let’s get down to it; this is what I’m talking about. The ability to record and track various aspects of the quality of the air in your buildings. The Environmental Air Quality sensors in the 9136 provide you with the ability to monitor several aspects relating to Air Quality, including;</p>
<ul>
<li>Calculated Air Quality Metric (“IAQ”)</li>
<li>Temperature (Deg C)</li>
<li>Humidity (%)</li>
<li>ECO2 (estimated CO2 - calculated based on TVOC)</li>
<li>ETOH (estimated Ethanol)</li>
<li>Total Volatile Compounds (“TVOC”, PPB)</li>
<li>And <em>thirteeen</em> different RMOX values</li>
</ul>
<p>All of this comes from the Catalyst 9136’s Environmental Sensor.</p>
<p><a href="/assets/images/9136-ports-small-annotated.jpg"><figure class="">
<img src="/assets/images/9136-ports-small-annotated.jpg" alt="" /></figure>
</a></p>
<p>And what can you do with all of this data? <em>Here’s one I made earlier…</em></p>
<p><a href="/assets/images/AirQualityMonitoring.jpg"><figure class="">
<img src="/assets/images/AirQualityMonitoring.jpg" alt="" /></figure>
</a></p>
<h1 id="tech-overview">Tech overview</h1>
<p>The key components in implementing this functionality are;</p>
<ul>
<li>Cisco Catalyst 9800 WLC running 17.8 or newer code (currently in Beta)</li>
<li>Cisco Catalyst 9136 WiFi-6e Access Point with embedded Environmental Air Quality Sensor</li>
<li>A TIG stack (Telegraf, InfluxDB & Grafana)</li>
</ul>
<p>The Access Points’ sensors are only enabled from IOS-XE v17.8 so this is our minimum starting point in terms of software.</p>
<p>We’ll use the 9800 WLC to configure the WiFi Access Point so it sends its Sensor data to our TIG stack, and the TIG stack will store our data over time and allow us to produce some graphs, charts, and so on.</p>
<p><a href="/assets/images/SensorFlowDiagram.png"><figure class="">
<img src="/assets/images/SensorFlowDiagram.png" alt="" /></figure>
</a></p>
<h1 id="the-tig-stack">The TIG stack</h1>
<p>“TIG” is a term for three products commonly used together to deliver dashboard-type services; Telegraf, InfluxDB and Grafana. This is how we’ll consume the data the Access Points generate.</p>
<p>Telegraf is a small, popular piece of software that we use to receive our streaming data and which pushes that data in to the database, InfluxDB.</p>
<p>InfluxDB is a popular time-series database. A time-series database is one that timestamps everything and allows you to run time-based queries on the data it holds.</p>
<p>Grafana is a popular dashboarding software that allows you to query a time series database and to draw various graphs and charts based on the data returned.</p>
<h1 id="implementation">Implementation</h1>
<p>Caution! This process is aimed it providing functionality, not security. Do not use these configs in production without hardening them first.</p>
<p>We’ll build out the “TI” parts of our stack first so we can receive and store data; InfluxDB first and Telegraf second. Once these are in place, we’ll build up the WLC config that actually allow us to send the Telemetry. We’ll verify this is all working ok before moving to the last step, building Grafana so we can visualise our data.</p>
<p>For the purposes of this install, the TIG stack is built on an M1 Mac Mini running Monterey 12.3. All software installs are managed through <code class="highlighter-rouge">brew</code>.</p>
<p>The instructions in this article are relevant to the following versions of software;</p>
<ul>
<li>Cisco 9800 IOS-XE v17.8 (Any kind of 9800 is ok; physical or virtual.)</li>
<li>Grafana v8.4</li>
<li>Telegraf v1.21.4</li>
<li>InfluxDB v2.1.1</li>
</ul>
<p>The gist of the process is the same for Windows and Linux, but the specific commands may differ slightly.</p>
<p>In my configs, the following addresses are used:</p>
<ul>
<li>Catalyst 9800 WLC - 192.168.1.70</li>
<li>DNA Spaces Connector - 192.168.1.69</li>
<li>Catalyst 9136 AP - 192.168.1.100</li>
<li>Telegraf & InfluxDB - 192.168.1.224</li>
</ul>
<h2 id="influxdb"><strong>InfluxDB</strong></h2>
<p>The first thing to install and setup is the database, InfluxDB. This is where we’ll store all of the Environmental Sensor data from all of the Access Points. Storing the data in a timeseries database gives you the ability to interact with the data and to see how it changes over time.</p>
<p><strong>Install</strong></p>
<p>The installation process is very easy:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>brew update
brew install influxdb
</code></pre></div></div>
<p><strong>Run</strong></p>
<p>Once you’ve installed InfluxDB, run it:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>influxd
</code></pre></div></div>
<p><strong>Access</strong></p>
<p>By default, InfluxDB will operate on local TCP port 8086 and it can be accessed using HTTP.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>http://localhost:8086
</code></pre></div></div>
<p><strong>Configure</strong></p>
<p>Using the GUI, you’ll need to create an ‘organization’, a ‘bucket’ (the database where your data will be stored) and an API key so external things (like Telegraf and Grafana) can interact with your database.</p>
<p>The organization and bucker are both created in the install wizard when you first open the InfluxDB web page. API keys are created through <code class="highlighter-rouge">Data > API Tokens > 'Generate API Token'</code>.</p>
<p>Be sure to safely note down the values for all of these; you’ll need them later.</p>
<h2 id="telegraf"><strong>Telegraf</strong></h2>
<p>Telegraf is the second part of the installation process. Telegraph is a small piece of software that receives the telemetry data from the Access Point and inserts it in to the InfluxDB. There are two parts to this activity, installing Telegraf, and configuring Telegraf so it understands what we need it to do.</p>
<p><strong>Install</strong></p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>brew update
brew install telegraf
</code></pre></div></div>
<p><strong>Configure</strong></p>
<p>Telegraf is small but mighty. We just need to tell it what sort of data to accept, and where to send it. We do this through a <code class="highlighter-rouge">telegraf.conf</code> file.</p>
<p>Create an empty file called <code class="highlighter-rouge">telegraf.conf</code> and fill it as shown below.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Configuration for sending metrics to InfluxDB 2.0
[[outputs.influxdb_v2]]
## The URLs of the InfluxDB cluster node(s).
## Assuming you installed Telegraf on the same node as InfluxDB
urls = ["http://127.0.0.1:8086"]
## Token for authentication.
token = "Your_InfluxDB_API_Key_Goes_Here"
## Organization is the name of the organization you wish to write to.
organization = "Your_InfluxDB_Organisation_Name_Goes_Here"
## Destination bucket to write into.
bucket = "Your_InfluxDB_Bucket_Name_Goes_Here"
[[inputs.cisco_telemetry_mdt]]
transport = "grpc"
service_address = ":57000"
</code></pre></div></div>
<p><strong>Run</strong></p>
<p>Run telegraf and point it at the <code class="highlighter-rouge">telegraf.conf</code> file you just made.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>telegraf --config ./telegraf.conf
</code></pre></div></div>
<h2 id="9800-wireless-lan-controller"><strong>9800 Wireless LAN Controller</strong></h2>
<p>Running software v17.8 or newer with a Catalyst 9136 WiFi-6e Access Point, we need to do a few things;</p>
<ul>
<li>Enable netconf-yang</li>
<li>Setup aaa for netconf-yang</li>
<li>Create a telemetry subscription that will instruct the Access Point on what data to send, when, where and how.</li>
</ul>
<p><strong>Configure</strong></p>
<p>SSH/Console to the 9800 WLC and create the config shown below. I assume the WLC already has an IP address, network connectivity, an enable secret and a local Priv 15 user defined.</p>
<p><em>Enable netconf-yang</em></p>
<p>Enable netconf-yang on the WLC. This uses TCP 830.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>conf t
netconf-yang
</code></pre></div></div>
<p><em>Setup aaa for netconf-yang</em></p>
<p>netconf-yang provides a way for things to interact with your WLC and it is just as powerful (or vulnerable) as SSH or HTTPS is. With this in mind, we need to provide the WLC with some information about how to authenticate netconf-yang connections. In this example, we’re going to assume that we’re just using local credentials on the WLC for everything.</p>
<p>Netconf on the 9800 only ever uses the default method.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>conf t
aaa new-model
aaa authorization exec default local
aaa authentication login default local
</code></pre></div></div>
<p><em>Enable the sensors</em></p>
<p>Sensors are enabled within the Access Point Join Profile. For the purposes of this exercise, I’m using the ‘default-ap-profile’ Join Profile.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>9800# conf t
9800(config)# ap profile default-ap-profile
9800(config-ap-profile)# sensor environment air-quality
9800(config-ap-profile)# sensor environment temperature
</code></pre></div></div>
<p><em>Enable telemetry</em></p>
<p>Create ietf telemetry subscriptions in the WLC that will send the telemetry data to Telegraf.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>conf t
telemetry ietf subscription 20
encoding encode-kvgpb
filter xpath /wireless-access-point-oper:access-point-oper-data/ap-temp
source-address 192.168.1.70
stream yang-push
update-policy periodic 5000
receiver ip address 192.168.1.224 57000 protocol grpc-tcp
telemetry ietf subscription 21
encoding encode-kvgpb
filter xpath /wireless-access-point-oper:access-point-oper-data/ap-air-quality
source-address 192.168.1.70
stream yang-push
update-policy periodic 5000
receiver ip address 192.168.1.224 57000 protocol grpc-tcp
</code></pre></div></div>
<p>Here’s a breakdown of what these commands are doing:</p>
<p><code class="highlighter-rouge">telemetry ietf subscription 20</code>: this is the subscription ID that groups together all the config to stream one set of data</p>
<p><code class="highlighter-rouge">encoding encode-kvgpb</code>: this matches the encoding specified inside “cisco_telemetry_mdt”, that is used by telegraf. “KVGPB” stands for Key Value Google Protocol Buffer.</p>
<p><code class="highlighter-rouge">filter xpath /wireless-access-point-oper:access-point-oper-data/ap-air-quality</code>: this is the data we want to send</p>
<p><code class="highlighter-rouge">source-address 192.168.1.70</code>: this is where we want to send the data from (ie, the WLC’s Management Interface)</p>
<p><code class="highlighter-rouge">stream yang-push</code>: stream the data using yang</p>
<p><code class="highlighter-rouge">update-policy periodic 5000</code>: send new data every 5 seconds</p>
<p><code class="highlighter-rouge">receiver ip address 192.168.1.224 57000 protocol grpc-tcp</code>: send the data to the DNA Spaces Connector (192.168.1.69) on the port that telegraf is listening on (TCP 57000) using grpc-tcp (which is reliable, but insecure).</p>
<p><strong>Validation</strong></p>
<p>Validate your 9800 config with the commands shown below. Each output includes a corresponding expected / good output.</p>
<p>Take a high level view of your configs and if the WLC thinks they’re valid or not</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>9800# show telemetry ietf subscription summary
Subscription Summary
====================
Maximum supported: 128
Subscription Total Valid Invalid
-----------------------------------------------
All 2 2 0
Dynamic 0 0 0
Configured 2 2 0
Permanent 0 0 0
</code></pre></div></div>
<p>Take a slightly closer look at your configs and if the WLC thinks they’re valid or not</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>9800# show telemetry ietf subscription all
ID Type State State Description
20 Configured Valid Subscription validated
21 Configured Valid Subscription validated
</code></pre></div></div>
<p>Take a detailed look at subscription 20. Anything other than “Connected” as the State is an error of some kind.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>9800# show telemetry ietf subscription 20 detail
Telemetry subscription detail:
Subscription ID: 20
Type: Configured
State: Valid
Stream: yang-push
Filter:
Filter type: xpath
XPath: /wireless-access-point-oper:access-point-oper-data/ap-temp
Update policy:
Update Trigger: periodic
Period: 5000
Encoding: encode-kvgpb
Source VRF:
Source Address: 192.168.1.70
Notes: Subscription validated
Named Receivers:
Name Last State Change State Explanation
-------------------------------------------------------------------------------------------------------------------------------------------------------
grpc-tcp://192.168.1.224:57000 03/21/22 17:04:23 Connected
</code></pre></div></div>
<p>Take a detailed look at subscription 21. Anything other than “Connected” as the State is an error of some kind.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>9800# show telemetry ietf subscription 21 detail
Telemetry subscription detail:
Subscription ID: 21
Type: Configured
State: Valid
Stream: yang-push
Filter:
Filter type: xpath
XPath: /wireless-access-point-oper:access-point-oper-data/ap-air-quality
Update policy:
Update Trigger: periodic
Period: 5000
Encoding: encode-kvgpb
Source VRF:
Source Address: 192.168.1.70
Notes: Subscription validated
Named Receivers:
Name Last State Change State Explanation
-------------------------------------------------------------------------------------------------------------------------------------------------------
grpc-tcp://192.168.1.224:57000 03/21/22 17:06:04 Connected
</code></pre></div></div>
<p>Check the WLC actually has some air quality data from the AP. If the tables are empty, there’s something wrong.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>9800# show platform software process database odm chassis active r0 details EWLC_OPERATIONAL_DB "table tbl_ap_air_quality" content
Database: EWLC_OPERATIONAL_DB - Table: table tbl_ap_air_quality - Num Recs: 1
Records
-------------------------------------------------------------------------------------------------------
791 record@tbl_ap_air_quality: {
st_ap_air_quality@st_ap_air_quality: {
ap_mac@tdl_mac_addr: {
mac[0]@U8:104
mac[1]@U8:125
mac[2]@U8:180
mac[3]@U8:95
mac[4]@U8:220
mac[5]@U8:160
}
last_update@calendar_time: {
second@I64:1647884273
microsec@U32:816370
}
rmox_0@LF:1018991936.000000
rmox_1@LF:90387552.000000
rmox_2@LF:14352000.000000
rmox_3@LF:3086827.500000
rmox_4@LF:846708.500000
rmox_5@LF:266985.437500
rmox_6@LF:102353.226500
rmox_7@LF:283437.281200
rmox_8@LF:907912.437500
rmox_9@LF:3295409.000000
rmox_10@LF:15411923.000000
rmox_11@LF:97635200.000000
rmox_12@LF:1111646592.000000
iaq@LF:3.051500
etoh@LF:0.633100
eco2@LF:405.124300
tvoc@LF:1.190300
}
}
</code></pre></div></div>
<p>Check the WLC actually has some AP temperature data from the AP. If the tables are empty, there’s something wrong.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>9800# show platform software process database odm chassis active r0 details EWLC_OPERATIONAL_DB "table tbl_ap_temperature" content
Database: EWLC_OPERATIONAL_DB - Table: table tbl_ap_temperature - Num Recs: 1
Records
-------------------------------------------------------------------------------------------------------
369 record@tbl_ap_temperature: {
st_ap_temperature@st_ap_temperature: {
ap_mac@tdl_mac_addr: {
mac[0]@U8:104
mac[1]@U8:125
mac[2]@U8:180
mac[3]@U8:95
mac[4]@U8:220
mac[5]@U8:160
}
last_update@calendar_time: {
second@I64:1647884323
microsec@U32:836096
}
temp@LF:28.743200
humidity@LF:39.496500
}
}
</code></pre></div></div>
<p>Lastly, if all of those outputs look ok, check InfluxDB to ensure you are receiving data.</p>
<p>Go to the influxDb webpage navigate to the <code class="highlighter-rouge">data explorer</code>. You should be able to select and visualise your data, like this.</p>
<p><a href="/assets/images/influxDbData.jpg"><figure class="">
<img src="/assets/images/influxDbData.jpg" alt="" /></figure>
</a></p>
<p>If you’ve got this far - great. Time to setup some proper graphs in Grafana.</p>
<h2 id="grafana"><strong>Grafana</strong></h2>
<p><strong>Install</strong></p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>brew update
brew install grafana
</code></pre></div></div>
<p><strong>configure</strong></p>
<p>Log in to the Grafana GUI using your web browser; it will default to using TCP 3000.</p>
<p>Navigate to <code class="highlighter-rouge">Configuration > Data Sources > Add data source > InfluxDB</code> to define how Grafana will interact with InfluxDB.</p>
<p>In my environment, Grafana and InfluxDB are on the same host, so I can use <code class="highlighter-rouge">localhost:8086</code> as the location of InfluxDB. Change this as necessary to suit your environment.</p>
<p>Leave all of the Auth settings alone / off.</p>
<p>Configure the InfluxDB details with the settings you noted down when you first configured InfluxDB. Note that <code class="highlighter-rouge">Token</code> is where your API key should be used.</p>
<p><a href="/assets/images/grafanaInfluxDb.jpg"><figure class="">
<img src="/assets/images/grafanaInfluxDb.jpg" alt="" /></figure>
</a></p>
<p>Now you have the database relationship in place, we can build some charts.</p>
<p>To build a chart, you first need to be able to query the database for some specific data. To do this, we use Influx Query Language. You don’t really need to learn Influx Query Language though because InfluxDB gives us a nice GUI and it’ll produce the script for us.</p>
<p>Go back to the Data Explorer in the InfluxDB GUI and build out a data series that you’re interested in. Once you have a set of data you’re happy with, click the <code class="highlighter-rouge">Script Editor</code> button on the right hand side of the screen and the query is presented on screen for you to copy / paste. Note that after you click the <code class="highlighter-rouge">Script Editor</code> button, it changes to say <code class="highlighter-rouge">Query Builder</code>.</p>
<p><a href="/assets/images/FluxQL.jpg"><figure class="">
<img src="/assets/images/FluxQL.jpg" alt="" /></figure>
</a></p>
<p>Copy the Query and go back to the Grafana GUI.</p>
<p>Create a new dashboard for yourself; this is where we’ll store all of your charts.</p>
<p><a href="/assets/images/grafanaNewDashboard.jpg"><figure class="">
<img src="/assets/images/grafanaNewDashboard.jpg" alt="" /></figure>
</a></p>
<p>Grafana will then load an empty Dashboard. Click the <code class="highlighter-rouge">add a new panel</code> icon and in the following page, insert your query in to the empty box at the bottom of the page and then click the circular refresh button towards the top left to see your data.</p>
<p><a href="/assets/images/grafanaNewPanel.jpg"><figure class="">
<img src="/assets/images/grafanaNewPanel.jpg" alt="" /></figure>
</a></p>
<p>You can use the menu on the right hand side to to tailor how your chart looks, and you can use the time selector at the top right to control the timespan your data covers. Once you’re happy, click the blue <code class="highlighter-rouge">Apply</code> button at the top right. The page will reload, showing your new Panel in your new Dashboard.</p>
<p><a href="/assets/images/grafanaPanel.jpg"><figure class="">
<img src="/assets/images/grafanaPanel.jpg" alt="" /></figure>
</a></p>
<p>Rinse and repeat this process a few times and you can build out lots of panels in your dashboard.</p>
<p><a href="/assets/images/grafanaAirQualityDashboard.jpg"><figure class="">
<img src="/assets/images/grafanaAirQualityDashboard.jpg" alt="" /></figure>
</a></p>
<p>And that’s it! You’ve now got data streaming in and you can build all sorts of charts / graphs / tables to help you make sense of the data and to draw value from it.</p>
<h1 id="limitations">Limitations</h1>
<p>Implementing environmental sensors in this way is new and there are bound to be drawbacks.</p>
<p>Firstly there’s the sensor itself. It’s possible to spend a small fortune on finitely accurate Sensors and clearly Cisco haven’t embedded a $5k sensor in to each Access Point. This will inevitably lead to variations in the relative and absolute quality of the data compared to high end equipment, though I have to say from what I’ve seen in my own testing, the accuracy of the data is more than good enough for normal IoT use cases.</p>
<p>Second is the position of the Sensor. We’re interested in Air Quality monitoring because it impacts human beings, but the Sensor being embedded in a WiFi Access Point which means the Sensor’s view of the world won’t be the same as a persons’. Access Points are typically ceiling mounted some distance higher than the people in the room which means there will be some difference between the air the sensor monitors and the air the people are breathing. The scale of these differences will depend on how still or turbulent the air is, the height difference between the people and where the Access Point is mounted. For normal IoT use cases though, this is probably not an issue.</p>
<p>Third is the position of the Sensor (again). The sensor its self is hidden away near the Access Point’s dual-mGig Ethernet sockets, which means it is less likely to be immediately influenced by moving air (like a breeze through a window), and as the sensor may succumb to ‘out of sight, out of mind’ thinking, there’s a chance the sensor’s ports could get clogged with dust and other obstacles that could skew its readings. Even the orientation of the Access Point (face up, face down or wall mounted) or its install location (above a radiator, below an air con unit, in the sun, near/far from a door or window, in an enclosure, etc etc) will impact the data it produces. Appreciating these factors will be a key consideration come Survey and Installation time.</p>
<p>I don’t see any of these factors from significantly detracting from the usefulness of the data the sensor produces.</p>
<h1 id="whats-next">What’s next?</h1>
<p>In a subsequent blog post I’ll take a look at a much easier way of doing all of this via DNA Spaces. I’ll also look at how you can build systems that automatically react to changes in the data and discuss how this kind of automation can benefit you, your Users, your Energy bills and your Estate overall.</p>
<h1 id="thank-you">Thank you</h1>
<p>A lot of this wouldn’t have been possible without some fantastic support from all sorts of people inside Cisco, as well as from some awesome <a href="https://blogs.cisco.com/tag/cisco-champions">Cisco Champions</a>, including <a href="https://twitter.com/mrTeigen">@mrTeign</a> and <a href="https://www.wifireference.com/2020/01/14/viewing-network-telemetry-from-the-catalyst-9800-with-grafana/">this article</a> from <a href="https://twitter.com/baldwifiguy">@baldwifiguy</a>.</p>Richard AtkinUse the Cisco Catalyst 9136 Access Point to understand the air around you like never before.Latest on Cisco WiFi EoL schedules - March 20222022-03-20T00:00:00+00:002022-03-20T00:00:00+00:00https://richardatkin.com/post/2022/03/20/Cisco-WiFi-Product-EoL-Schedule-Changes<p>The world is facing a lot of challenges at the moment and this has caused issues for everybody. Cisco is reacting to these challenges by changing some of their previously published EoL Schedules to extend the life of some devices. This will help customers to run their existing equipment for longer, without losing support from the manufacturer.</p>
<p>The tables below describes the EoL schedules for the most common things I come across in my day job. Perhaps the most important date to track is the End of Sec Vuln date; this is the point at which Cisco will no longer provide security vulnerability fixes and running equipment past this date carries increased risk.</p>
<p>All dates are in yyyy-mm-dd format, and are correct as of 2022-03-20.</p>
<h1 id="eol-schedule-wireless-lan-controllers">EoL Schedule: Wireless LAN Controllers</h1>
<table>
<thead>
<tr>
<th style="text-align: left">Product</th>
<th style="text-align: center">EoL Announced</th>
<th style="text-align: center">End of Sale</th>
<th style="text-align: center">End of SW Maint</th>
<th style="text-align: center">End of Sec Vuln</th>
<th style="text-align: center">Last date of Support</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left">WiSM2 WLC</td>
<td style="text-align: center">2016-10-10</td>
<td style="text-align: center">2017-04-10</td>
<td style="text-align: center">-</td>
<td style="text-align: center">-</td>
<td style="text-align: center">2022-04-30</td>
</tr>
<tr>
<td style="text-align: left">5508 WLC</td>
<td style="text-align: center">2018-01-31</td>
<td style="text-align: center">2018-05-04</td>
<td style="text-align: center">2019-08-01</td>
<td style="text-align: center">2021-07-31</td>
<td style="text-align: center">2023-07-31</td>
</tr>
<tr>
<td style="text-align: left">8510 WLC</td>
<td style="text-align: center">2018-03-05</td>
<td style="text-align: center">2018-07-04</td>
<td style="text-align: center">2019-09-03</td>
<td style="text-align: center">2021-09-02</td>
<td style="text-align: center">2023-09-30</td>
</tr>
<tr>
<td style="text-align: left">3504 WLC</td>
<td style="text-align: center">2021-01-11</td>
<td style="text-align: center">2021-01-31</td>
<td style="text-align: center">2023-01-31</td>
<td style="text-align: center">2025-01-30</td>
<td style="text-align: center">2027-01-31</td>
</tr>
<tr>
<td style="text-align: left">5520 WLC</td>
<td style="text-align: center">2021-01-31</td>
<td style="text-align: center">2021-12-10</td>
<td style="text-align: center">2023-01-31</td>
<td style="text-align: center">2025-01-30</td>
<td style="text-align: center">2027-01-31</td>
</tr>
<tr>
<td style="text-align: left">8540 WLC</td>
<td style="text-align: center">2021-01-31</td>
<td style="text-align: center">2022-01-31</td>
<td style="text-align: center">2023-01-31</td>
<td style="text-align: center">2025-01-30</td>
<td style="text-align: center">2027-01-31</td>
</tr>
</tbody>
</table>
<h1 id="eol-schedule-wireless-access-points">EoL Schedule: Wireless Access Points</h1>
<table>
<thead>
<tr>
<th style="text-align: left">Product</th>
<th style="text-align: center">EoL Announced</th>
<th style="text-align: center">End of Sale</th>
<th style="text-align: center">End of SW Maint</th>
<th style="text-align: center">End of Sec Vuln</th>
<th style="text-align: center">Last date of Support</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left">1700 / 2700 / 3700 AP</td>
<td style="text-align: center">2018-04-30</td>
<td style="text-align: center">2019-04-30</td>
<td style="text-align: center">2020-04-29</td>
<td style="text-align: center">2024-01-26</td>
<td style="text-align: center">2024-04-30</td>
</tr>
<tr>
<td style="text-align: left">1800 AP</td>
<td style="text-align: center">2020-10-31</td>
<td style="text-align: center">2021-05-01</td>
<td style="text-align: center">2022-05-01</td>
<td style="text-align: center">2024-04-30</td>
<td style="text-align: center">2026-04-30</td>
</tr>
<tr>
<td style="text-align: left">1815 / 1830 / 1840 / 1850 AP</td>
<td style="text-align: center">2021-10-31</td>
<td style="text-align: center">2022-05-01</td>
<td style="text-align: center">2023-05-01</td>
<td style="text-align: center">2025-04-30</td>
<td style="text-align: center">2027-04-30</td>
</tr>
<tr>
<td style="text-align: left">2800 / 3800 / 4800 AP</td>
<td style="text-align: center">2021-10-31</td>
<td style="text-align: center">2022-05-01</td>
<td style="text-align: center">2024-05-01</td>
<td style="text-align: center">2026-04-30</td>
<td style="text-align: center">2027-04-30</td>
</tr>
</tbody>
</table>
<h1 id="eol-schedule-aireos">EoL Schedule: AireOS</h1>
<table>
<thead>
<tr>
<th style="text-align: center">Version</th>
<th style="text-align: center">EoL</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center">8.0</td>
<td style="text-align: center">2018-04-30</td>
</tr>
<tr>
<td style="text-align: center">8.1</td>
<td style="text-align: center">2017-11-14</td>
</tr>
<tr>
<td style="text-align: center">8.3</td>
<td style="text-align: center">2019-11-15</td>
</tr>
<tr>
<td style="text-align: center">8.4</td>
<td style="text-align: center">2018-04-03</td>
</tr>
<tr>
<td style="text-align: center">8.5</td>
<td style="text-align: center">2021-12-30</td>
</tr>
<tr>
<td style="text-align: center">8.7</td>
<td style="text-align: center">2021-11-15</td>
</tr>
<tr>
<td style="text-align: center">8.8</td>
<td style="text-align: center">2020-11-29</td>
</tr>
<tr>
<td style="text-align: center">8.9</td>
<td style="text-align: center">2020-06-01</td>
</tr>
</tbody>
</table>
<h1 id="eol-schedule-ios-xe">EoL Schedule: IOS-XE</h1>
<table>
<thead>
<tr>
<th style="text-align: left">Product</th>
<th style="text-align: center">EoL Announced</th>
<th style="text-align: center">End of SW Maint</th>
<th style="text-align: center">End of Sec Vuln</th>
<th style="text-align: center">Last date of Support</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left">16.12.x</td>
<td style="text-align: center">2020-08-19</td>
<td style="text-align: center">2022-02-17</td>
<td style="text-align: center">2022-08-18</td>
<td style="text-align: center">2026-02-28</td>
</tr>
<tr>
<td style="text-align: left">17.1.x</td>
<td style="text-align: center">2020-03-31</td>
<td style="text-align: center">2020-12-30</td>
<td style="text-align: center">2020-12-30</td>
<td style="text-align: center">2025-06-30</td>
</tr>
<tr>
<td style="text-align: left">17.2.x</td>
<td style="text-align: center">2020-10-13</td>
<td style="text-align: center">2021-07-15</td>
<td style="text-align: center">2021-07-15</td>
<td style="text-align: center">2026-01-31</td>
</tr>
<tr>
<td style="text-align: left">17.3.x</td>
<td style="text-align: center">2021-09-30</td>
<td style="text-align: center">2023-03-31</td>
<td style="text-align: center">2023-09-30</td>
<td style="text-align: center">2027-03-31</td>
</tr>
<tr>
<td style="text-align: left">17.5.x</td>
<td style="text-align: center">2021-08-30</td>
<td style="text-align: center">2022-05-30</td>
<td style="text-align: center">2022-05-30</td>
<td style="text-align: center">2026-11-30</td>
</tr>
</tbody>
</table>
<h1 id="issues">Issues</h1>
<p>There is some contradiction in these dates at the time of writing. The issue is with how the x700 series APs’ EoL schedule compares to the 17.3 EoL schedule. Take Security Vulnerability cover for example. The x700 EoL schedule says we can expect cover up to January 2024, but the latest code those APs can run is v17.3. The v17.3 EoL schedule currently has a Security Vulnerability end date of September 2023. It’s only four months difference, but those four months might matter to somebody, somewhere. I hope we’ll see more updates from Cisco in the coming weeks to address this (presumably through a revised 17.3 EoL schedule), but until that happens, this ambiguity remains.</p>
<h1 id="planning-for-the-future">Planning for the future</h1>
<p>These extended EoL schedules provide a welcome reprive, but the pressure is still on for those running older equipment. Leadtimes for new equipment remaining lengthy and subject to variation based on the various situations relating to Shipping, Brexit, COVID Lockdowns, Wars, etc. Planning ahead and getting orders in much earlier than we’re used to will be key to success here.</p>
<p>The next big things that will drive change are the adoption of the WiFi-6e via <a href="https://richardatkin.com/post/2022/02/03/Cisco-9136-WiFi-6e-product-launch.html">Cisco’s Catalyst 9136 WiFi-6e Access Point</a> (which is only supported on the 9800-Series WLCs), and the End of Software Maintenance dates in January 2023 for the final AireOS Wireless LAN Controllers.</p>
<p>If you need to refresh your infrastructure, the current suggested equipment is:</p>
<h2 id="cisco-catalyst-9800-series-wireless-lan-controllers">Cisco Catalyst 9800 Series Wireless LAN Controllers</h2>
<p>Available as Virtualised (ESXi, Hyper-V, KVM, AWS, GCP or Azure) or Physical Appliances, the 9800 comes in a range of sizes:</p>
<table>
<thead>
<tr>
<th style="text-align: left">WLC Model</th>
<th style="text-align: left">AP Limit</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left">9800-L</td>
<td style="text-align: left">250 APs</td>
</tr>
<tr>
<td style="text-align: left">9800-L with Performance License</td>
<td style="text-align: left">500 APs</td>
</tr>
<tr>
<td style="text-align: left">9800-CL (Virtualised, small)</td>
<td style="text-align: left">1000 APs</td>
</tr>
<tr>
<td style="text-align: left">9800-40</td>
<td style="text-align: left">1500 APs</td>
</tr>
<tr>
<td style="text-align: left">9800-CL (Virtualised, medium)</td>
<td style="text-align: left">3000 APs</td>
</tr>
<tr>
<td style="text-align: left">9800-CL (Virtualised, large)</td>
<td style="text-align: left">6000 APs</td>
</tr>
<tr>
<td style="text-align: left">9800-80</td>
<td style="text-align: left">6000 APs</td>
</tr>
</tbody>
</table>
<p>You can read more about Cisco’s Catalyst 9800 Wireless LAN Controllers at <a href="https://www.cisco.com/c/en/us/products/wireless/catalyst-9800-series-wireless-controllers/index.html">https://www.cisco.com/c/en/us/products/wireless/catalyst-9800-series-wireless-controllers/index.html</a></p>
<h2 id="cisco-catalyst-9100-series-wireless-access-points">Cisco Catalyst 9100 Series Wireless Access Points</h2>
<p>The entire Catalyst 9100 AP range supports WiFi-6, with types of Access Point to suit every kind of environment.</p>
<table>
<thead>
<tr>
<th style="text-align: left">Model</th>
<th style="text-align: left">2.4GHz</th>
<th style="text-align: left">5GHz</th>
<th style="text-align: left">6GHz</th>
<th style="text-align: left">PoE</th>
<th style="text-align: left">Versions</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left">9105</td>
<td style="text-align: left">2x2</td>
<td style="text-align: left">2x2</td>
<td style="text-align: left">NA</td>
<td style="text-align: left">802.3af/.3at</td>
<td style="text-align: left">Small form factor, Teleworker, Wallplate</td>
</tr>
<tr>
<td style="text-align: left">9115</td>
<td style="text-align: left">4x4</td>
<td style="text-align: left">4x4</td>
<td style="text-align: left">NA</td>
<td style="text-align: left">802.3at (or .3af with reduced performance)</td>
<td style="text-align: left">mGig, Int. or Ext. Antenna Versions</td>
</tr>
<tr>
<td style="text-align: left">9120</td>
<td style="text-align: left">4x4</td>
<td style="text-align: left">4x4</td>
<td style="text-align: left">NA</td>
<td style="text-align: left">802.3at (or .3af with reduced performance)</td>
<td style="text-align: left">mGig, Supports dual-5GHz, Int. or Ext. Antenna Versions</td>
</tr>
<tr>
<td style="text-align: left">9124</td>
<td style="text-align: left">4x4</td>
<td style="text-align: left">4x4</td>
<td style="text-align: left">NA</td>
<td style="text-align: left">802.3bt (or .3at / .3af with reduced performance)</td>
<td style="text-align: left">Outdoor, SFP, mGig, Int., Ext. or Directional Antenna Versions</td>
</tr>
<tr>
<td style="text-align: left">9130</td>
<td style="text-align: left">4x4</td>
<td style="text-align: left">8x8</td>
<td style="text-align: left">NA</td>
<td style="text-align: left">802.3at (or .3af with reduced performance)</td>
<td style="text-align: left">mGig, dual or tri-radio modes, Int. or Ext. Antenna Versions</td>
</tr>
<tr>
<td style="text-align: left">9136</td>
<td style="text-align: left">4x4</td>
<td style="text-align: left">8x8</td>
<td style="text-align: left">4x4</td>
<td style="text-align: left">802.3bt (or .3at with reduced performance)</td>
<td style="text-align: left">WiFi-6e, Dual mGig, tri or quad-radio modes, Environmental Sensors</td>
</tr>
</tbody>
</table>
<p>You can read more about Cisco Catalyst 9100 WiFi-6 Access Points at <a href="https://www.cisco.com/c/en/us/products/wireless/catalyst-9100ax-access-points/index.html">https://www.cisco.com/c/en/us/products/wireless/catalyst-9100ax-access-points/index.html</a></p>Richard AtkinCisco have announced changes to their Product EoL schedules in light of challenges facing distribution of new products. Here's the latest...Cisco launches the Catalyst 9136 WiFi-6e Access Point2022-02-03T00:00:00+00:002022-02-03T00:00:00+00:00https://richardatkin.com/post/2022/02/03/Cisco-9136-WiFi-6e-product-launch<h1 id="why-wifi-6e">Why WiFi-6e?</h1>
<p>WiFi-6e is the new kid on the block and it’s a game changer for WiFi. The fundamentals of WiFi haven’t changed much in years. Sure, there’s been evolution across 802.11b/g/a/n/ac, and we’ve gone from WEP, to TKIP and AES, but there hasn’t been a proper <strong>revolution</strong> in years. WiFi-6e is here to shake things up.</p>
<p>We’ve had the same 3x 2.4GHz and 19x 5GHz none-overlapping channels for years. Updates to 802.11 since it was released have squeezed more performance from those channels, but as more and more people have adopted WiFi, the demand for reliable performance has outstripped what the protocols can do in these small, congested frequency blocks. WiFi-6e overcomes these challenges by massively expanding the amount of channels we have available.</p>
<p>In the UK and Europe, WiFi-6e gives us an extra 500MHz of channel space, from 5925MHz to 6425MHz. We lose 10 MHz at either end of the range, which leaves us with 480MHz that provides 24 glorious new channels to use. By adding 24 more channels to the existing 21 we have available, WiFi-6e more than doubles the amount of none-overlapping channels we can use. WiFi-6e also provides higher transmit power limits (250mW indoors @ 6GHz in the UK/EU), <em>and</em> we still benefit from WiFi-6’s enhancements around BSS Colouring, OFDMA, and MU-MIMO. The arrival of WiFi-6e means we have more channels and we can squeeze more bandwidth from each of them. The 24-channel-wide block also means we can make full use of WiFi-6e’s channel bonding capabilities, giving us up to three 160MHz channels, six 80MHz channels, or twelve 40MHz channels. The amount of bandwidth we can extract from these channels blocks is phenominal.</p>
<p>It’s not all about channels though, WiFi-6e is also more secure. Gone are the days of Open networks and even WPA2 is out of the door; WiFi-6e is a WPA3-only world.</p>
<p>Anyway… I mentioned there’s a new AP. It’s the Cisco Catalyst 9136 and it’s a beast! Slightly bigger than its Cisco Catalyst 9130 little sister, the 9136 packs in loads of extra features, higher performance and with a revised facia, I think its better looking than it’s siblings too. Here’s the run down:</p>
<h1 id="cisco-catalyst-9136-wifi-6e-access-point">Cisco Catalyst 9136 WiFi-6e Access Point</h1>
<h2 id="wifi">WiFi</h2>
<ul>
<li>WiFi-6e</li>
<li>UL-OFDMA, DL-OFDMA & MU-MIMO</li>
</ul>
<h2 id="transceivers">Transceivers</h2>
<ul>
<li>1x 4x4:4 6GHz Radio</li>
<li>1x 8x8:8 5GHz Radio (*)</li>
<li>1x 4x4:4 2.4GHz Radio</li>
<li>1x IoT/BLE Radio</li>
<li>1x Scanning Radio</li>
</ul>
<h2 id="security">Security</h2>
<ul>
<li>1024 QAM</li>
<li>WPA3-SAE Hash to Element(H2E) and Hunting & Pecking (H&P)</li>
<li>OWE, SAE & 802.1x-SHA256</li>
<li>CCMP128, CCMP256, GCMP128, GCMP256</li>
</ul>
<h2 id="lan">LAN</h2>
<ul>
<li>2x 5Gbps mGig</li>
<li>Dual PoE Power Redundancy</li>
<li>Supports 802.3bt/at/af</li>
</ul>
<h2 id="extras">Extras</h2>
<ul>
<li>Environmental Sensor (**)</li>
<li>USB (9W)</li>
<li>Uses standard Cisco mounting brackets</li>
<li>Improved access to Ethernet interfaces</li>
</ul>
<p>(*) The 8x8:8 radio will be software configurable as two 4x4:4 radios in a future release.</p>
<p>(**) The Sensor is not likely to be enabled until software 17.8 is released.</p>
<h2 id="pictures">Pictures</h2>
<p><a href="/assets/images/9136-front-small.jpg"><figure class="">
<img src="/assets/images/9136-front-small.jpg" alt="" /></figure>
</a></p>
<p><a href="/assets/images/9136-wonky-small.jpg"><figure class="">
<img src="/assets/images/9136-wonky-small.jpg" alt="" /></figure>
</a></p>
<p><a href="/assets/images/9136-ports-small.jpg"><figure class="">
<img src="/assets/images/9136-ports-small.jpg" alt="" /></figure>
</a></p>
<p><a href="/assets/images/9136-ports-small-annotated.jpg"><figure class="">
<img src="/assets/images/9136-ports-small-annotated.jpg" alt="" /></figure>
</a></p>
<p><a href="/assets/images/9100-family-size-comparison.jpg"><figure class="">
<img src="/assets/images/9100-family-size-comparison.jpg" alt="" /></figure>
</a></p>
<h1 id="impact-on-the-lan">Impact on the LAN</h1>
<p>The extra performance and efficiency from WiFi-6 and the extra capacity from WiFi-6e combine in the Cisco Catalyst 9136 Access Point to deliver the best WiFi experience I’ve ever seen. So improved is the performance that even with ‘only’ the limited 500MHz available to us in the UK and EU (compared to an extra 1200MHz in the USA!), it’s still realistic that a single Access Point using a sensible set of channel widths in a busy inner-city area, could pull down more than 1Gbps on its LAN interface. With a fair wind, networks in less busy environments could realistically see over 2Gbps on the LAN. The upshot of this is that 2x 1Gbps or mGig-capable Access Layer switches are going to be required if you’re to get the most from the new Catalyst 9136 WiFi-6e Access Point.</p>
<p>All the extra radios and performance the 9136 delivers also means more power is required. To get the most out of the 9136 you’re going to need 802.3bt (UPoE). The 9136 does run at 802.3at (PoE+) and 802.3af (PoE) too, but with increasingly diminishing capabilities and performance.</p>
<table>
<thead>
<tr>
<th style="text-align: left">PoE</th>
<th style="text-align: center">Spatial Streams</th>
<th style="text-align: center">2.4GHz</th>
<th style="text-align: center">5GHz</th>
<th style="text-align: center">6GHz</th>
<th style="text-align: center">mGig-0</th>
<th style="text-align: center">mGig-1</th>
<th style="text-align: center">USB</th>
<th style="text-align: center">Scanning Radio</th>
<th style="text-align: center">Max Power</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left">PoE 802.3af</td>
<td style="text-align: center">2</td>
<td style="text-align: center">1x1</td>
<td style="text-align: center">1x1</td>
<td style="text-align: center">Disabled</td>
<td style="text-align: center">1Gbps</td>
<td style="text-align: center">Disabled</td>
<td style="text-align: center">Disabled</td>
<td style="text-align: center">On</td>
<td style="text-align: center">14W</td>
</tr>
<tr>
<td style="text-align: left">PoE+ 802.3at</td>
<td style="text-align: center">8</td>
<td style="text-align: center">2x2</td>
<td style="text-align: center">2x2</td>
<td style="text-align: center">4x4</td>
<td style="text-align: center">2.5Gbps</td>
<td style="text-align: center">Disabled</td>
<td style="text-align: center">Disabled</td>
<td style="text-align: center">On</td>
<td style="text-align: center">25.5W</td>
</tr>
<tr>
<td style="text-align: left">UPoE 802.3bt</td>
<td style="text-align: center">16</td>
<td style="text-align: center">4x4</td>
<td style="text-align: center">8x8</td>
<td style="text-align: center">4x4</td>
<td style="text-align: center">5Gbps</td>
<td style="text-align: center">5Gbps</td>
<td style="text-align: center">On (9Watts)</td>
<td style="text-align: center">On</td>
<td style="text-align: center">46.5W</td>
</tr>
</tbody>
</table>
<p>UPoE mGig switches aren’t particularly cheap, or commonplace, so the 9136 also lets you Etherchannel the interfaces together, so the majority of people that ‘only’ have a 1Gbps Access Layer can still get around 2Gbps out of the AP. If you lack UPoE, you can also power the Access Point using a Power Injector. I did my testing using a Meraki MA-INJ-6 (UPoE, 10G mGig) and had no issues at all.</p>
<p>Where Access Points are particularly mission critical, the 9136 also supports PoE redundancy. Either mGig interface can be used to provide PoE and if one interface should fail, the other will take over. Only one interface at a time provides PoE.</p>
<h1 id="performance-testing">Performance Testing</h1>
<p>I’ve had my hands on the 9136 for a little while now. Plenty long enough for me to upgrade my laptops to use Intel’s AX210 NICs and to get my hands on a little mGig switch so I can really put the pressure on the AP to see what it can do. It does not disappoint!</p>
<p>With three different laptops, all upgraded to use Intel AX210 NICs with the latest drivers (22.110.1, at the time of writing) and on the latest release of Windows 11, I subjected the 9136 to as many different permutations as I could.</p>
<p>Each set of tests was run with one Client laptop connected to each radio via a WPA3-SAE (H2E) SSID. I used iPerf3 in TCP mode on all three Clients at the same time to ensure the AP was seeing full load on all of its radios. The AP was connected on a single 2.5Gbps interface in Flex Connect mode, and controlled by a 9800-CL WLC on standard 17.7.1 code.</p>
<blockquote>
<p>iperf3.exe -c x.x.x.x -i5 -t600 -P20</p>
</blockquote>
<p>In the interest of full disclosure, the higher-speed tests exceeded the performance of my 2.5Gbps mGig switch so I couldn’t test all of the radios in parallel at the same time for these.</p>
<h1 id="results">Results</h1>
<table>
<thead>
<tr>
<th style="text-align: center">Frequency</th>
<th style="text-align: center">Bandwidth</th>
<th style="text-align: center">Client</th>
<th style="text-align: center">Individual Mbps</th>
<th style="text-align: center">Total Mbps</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center">2.4GHz</td>
<td style="text-align: center">20MHz</td>
<td style="text-align: center">Intel AX210 @ 2SS</td>
<td style="text-align: center">121</td>
<td style="text-align: center">578</td>
</tr>
<tr>
<td style="text-align: center">5GHz</td>
<td style="text-align: center">20MHz</td>
<td style="text-align: center">Intel AX210 @ 2SS</td>
<td style="text-align: center">225</td>
<td style="text-align: center"> </td>
</tr>
<tr>
<td style="text-align: center">6GHz</td>
<td style="text-align: center">20MHz</td>
<td style="text-align: center">Intel AX210 @ 2SS</td>
<td style="text-align: center">232</td>
<td style="text-align: center"> </td>
</tr>
<tr>
<td style="text-align: center"> </td>
<td style="text-align: center"> </td>
<td style="text-align: center"> </td>
<td style="text-align: center"> </td>
<td style="text-align: center"> </td>
</tr>
<tr>
<td style="text-align: center">2.4GHz</td>
<td style="text-align: center">20MHz</td>
<td style="text-align: center">Intel AX210 @ 2SS</td>
<td style="text-align: center">118</td>
<td style="text-align: center">749</td>
</tr>
<tr>
<td style="text-align: center">5GHz</td>
<td style="text-align: center">20MHz</td>
<td style="text-align: center">Intel AX210 @ 2SS</td>
<td style="text-align: center">218</td>
<td style="text-align: center"> </td>
</tr>
<tr>
<td style="text-align: center">6GHz</td>
<td style="text-align: center">40MHz</td>
<td style="text-align: center">Intel AX210 @ 2SS</td>
<td style="text-align: center">413</td>
<td style="text-align: center"> </td>
</tr>
<tr>
<td style="text-align: center"> </td>
<td style="text-align: center"> </td>
<td style="text-align: center"> </td>
<td style="text-align: center"> </td>
<td style="text-align: center"> </td>
</tr>
<tr>
<td style="text-align: center">2.4GHz</td>
<td style="text-align: center">20MHz</td>
<td style="text-align: center">Intel AX210 @ 2SS</td>
<td style="text-align: center">120</td>
<td style="text-align: center">965</td>
</tr>
<tr>
<td style="text-align: center">5GHz</td>
<td style="text-align: center">40MHz</td>
<td style="text-align: center">Intel AX210 @ 2SS</td>
<td style="text-align: center">427</td>
<td style="text-align: center"> </td>
</tr>
<tr>
<td style="text-align: center">6GHz</td>
<td style="text-align: center">40MHz</td>
<td style="text-align: center">Intel AX210 @ 2SS</td>
<td style="text-align: center">418</td>
<td style="text-align: center"> </td>
</tr>
<tr>
<td style="text-align: center"> </td>
<td style="text-align: center"> </td>
<td style="text-align: center"> </td>
<td style="text-align: center"> </td>
<td style="text-align: center"> </td>
</tr>
<tr>
<td style="text-align: center">2.4GHz</td>
<td style="text-align: center">20MHz</td>
<td style="text-align: center">Intel AX210 @ 2SS</td>
<td style="text-align: center">117</td>
<td style="text-align: center">1215</td>
</tr>
<tr>
<td style="text-align: center">5GHz</td>
<td style="text-align: center">20MHz</td>
<td style="text-align: center">Intel AX210 @ 2SS</td>
<td style="text-align: center">211</td>
<td style="text-align: center"> </td>
</tr>
<tr>
<td style="text-align: center">6GHz</td>
<td style="text-align: center">80MHz</td>
<td style="text-align: center">Intel AX210 @ 2SS</td>
<td style="text-align: center">887</td>
<td style="text-align: center"> </td>
</tr>
<tr>
<td style="text-align: center"> </td>
<td style="text-align: center"> </td>
<td style="text-align: center"> </td>
<td style="text-align: center"> </td>
<td style="text-align: center"> </td>
</tr>
<tr>
<td style="text-align: center">2.4GHz</td>
<td style="text-align: center">20MHz</td>
<td style="text-align: center">Intel AX210 @ 2SS</td>
<td style="text-align: center">121</td>
<td style="text-align: center">1433</td>
</tr>
<tr>
<td style="text-align: center">5GHz</td>
<td style="text-align: center">40MHz</td>
<td style="text-align: center">Intel AX210 @ 2SS</td>
<td style="text-align: center">423</td>
<td style="text-align: center"> </td>
</tr>
<tr>
<td style="text-align: center">6GHz</td>
<td style="text-align: center">80MHz</td>
<td style="text-align: center">Intel AX210 @ 2SS</td>
<td style="text-align: center">889</td>
<td style="text-align: center"> </td>
</tr>
<tr>
<td style="text-align: center"> </td>
<td style="text-align: center"> </td>
<td style="text-align: center"> </td>
<td style="text-align: center"> </td>
<td style="text-align: center"> </td>
</tr>
<tr>
<td style="text-align: center">2.4GHz</td>
<td style="text-align: center">20MHz</td>
<td style="text-align: center">Intel AX210 @ 2SS</td>
<td style="text-align: center">118</td>
<td style="text-align: center">2264</td>
</tr>
<tr>
<td style="text-align: center">5GHz</td>
<td style="text-align: center">40MHz</td>
<td style="text-align: center">Intel AX210 @ 2SS</td>
<td style="text-align: center">426</td>
<td style="text-align: center"> </td>
</tr>
<tr>
<td style="text-align: center">6GHz</td>
<td style="text-align: center">160MHz</td>
<td style="text-align: center">Intel AX210 @ 2SS</td>
<td style="text-align: center">1720</td>
<td style="text-align: center"> </td>
</tr>
<tr>
<td style="text-align: center"> </td>
<td style="text-align: center"> </td>
<td style="text-align: center"> </td>
<td style="text-align: center"> </td>
<td style="text-align: center"> </td>
</tr>
<tr>
<td style="text-align: center">2.4GHz</td>
<td style="text-align: center">20MHz</td>
<td style="text-align: center">Intel AX210 @ 2SS</td>
<td style="text-align: center">118</td>
<td style="text-align: center">2674</td>
</tr>
<tr>
<td style="text-align: center">5GHz</td>
<td style="text-align: center">80MHz</td>
<td style="text-align: center">Intel AX210 @ 2SS</td>
<td style="text-align: center">846</td>
<td style="text-align: center"> </td>
</tr>
<tr>
<td style="text-align: center">6GHz</td>
<td style="text-align: center">160MHz</td>
<td style="text-align: center">Intel AX210 @ 2SS</td>
<td style="text-align: center">1710</td>
<td style="text-align: center"> </td>
</tr>
<tr>
<td style="text-align: center"> </td>
<td style="text-align: center"> </td>
<td style="text-align: center"> </td>
<td style="text-align: center"> </td>
<td style="text-align: center"> </td>
</tr>
<tr>
<td style="text-align: center">2.4GHz</td>
<td style="text-align: center">20MHz</td>
<td style="text-align: center">Intel AX210 @ 2SS</td>
<td style="text-align: center">117</td>
<td style="text-align: center">3527</td>
</tr>
<tr>
<td style="text-align: center">5GHz</td>
<td style="text-align: center">160MHz</td>
<td style="text-align: center">Intel AX210 @ 2SS</td>
<td style="text-align: center">1640</td>
<td style="text-align: center"> </td>
</tr>
<tr>
<td style="text-align: center">6GHz</td>
<td style="text-align: center">160MHz</td>
<td style="text-align: center">Intel AX210 @ 2SS</td>
<td style="text-align: center">1770</td>
<td style="text-align: center"> </td>
</tr>
</tbody>
</table>
<h2 id="analysis">Analysis</h2>
<p>A dose of reality needs applying to any test reults, but nevertheless, I’m super impressed!</p>
<p>In the real-world, using 20MHz for all three radios seems unnecessarily stingy in all but the most extreme of scenarios. Likewise, any tests using 160MHz aren’t particularly realistic in the UK/EU because of the limited extra space we get unless you have a very isolated network. This still leaves a very healthy middle ground of between 750 to 1400Mbps of real data throughput for a single AP. In the real world, mixed-capability Clients will bring these figures down as WiFi-6 isn’t yet ubiquitous. As we look to the future and anticipate the possibility of 3SS devices hitting the market though, these figures could also go up. The total throughput figures are also likely to go up when the 8x8:8 5GHz radio is able to be split in to two separate 4x4:4 radios.</p>
<h1 id="client-support">Client Support</h1>
<p>Support for WiFi-6e and the newer versions of WPA3 is only really available in the latest releases of code and Client hardware. Be prepared to update your things if you want to take full advantage of WiFi-6e.</p>
<blockquote>
<p>Cisco Catalyst 9136 WiFi-6e Access Point is supported on the 9800 WLC only, with 17.7.1 code or higher.</p>
</blockquote>
<blockquote>
<p>Apple iOS (15.3) on iPhone7 or later only seems to support WPA3-SAE with Hunting and Pecking; Hash to Element mode failed in my tests.</p>
</blockquote>
<blockquote>
<p>Apple iPhone 11 (or newer) is required if you want to support the new, even more secure, 192-bit version of WPA3 Enterprise.</p>
</blockquote>
<blockquote>
<p>Windows devices with recent Intel NICs that wish to run WPA3-SAE with Hunting & Pecking enabled (less secure) need to run Windows 10 v1903 or later, with Intel 21.10.X or later.</p>
</blockquote>
<blockquote>
<p>Windows devices with recent Intel NICs that wish to run WPA3-SAE with Hash to Element (H2E) enabled (more secure) need to run Windows 10 v21H2 or later, with Intel 22.100.X or later.</p>
</blockquote>
<h1 id="design-challenges">Design Challenges</h1>
<p>The motives of improved performance and security are compelling reasons to move to WiFi-6e, but there are barriers to adoption that we need to overcome.</p>
<p>WPA3 has been out for years, but adoption has been very slow; I’m not aware of anybody running pure WPA3 networks yet. This presents an adoption barrier for WiFi-6e because WPA2/WPA3 mixed mode across 2.4 / 5 / 6GHz doesn’t work. WiFi-6e is WPA3-only.</p>
<p>WiFi-6 has been out for a while now, and despite a rocky period in 2020 where Intel and Microsoft caused some issues with reliability, it is now very reliable. The 6GHz extensions to WiFi-6 are still obviously very new, with relatively untested drivers. 6GHz has different Transmit Power limits and propagates differently to 5GHz, so AP locations are likely to need re-surveying if seamless 6GHz coverage is required.</p>
<p>We’ve yet to see how things pan out in terms of support offered by Clients drivers for mixed-mode networks, but I suspect we’ll end up creating WPA3-specific SSIDs across all three frequencies and running them alongside existing WPA2 networks for a period while Client devices are upgraded to properly support WPA3. The 6GHz part of WiFi-6e also presents challenges because even well surveyed networks today may not provide seamless 6GHz coverage and Clients may find themselves dropping down to 2.4 or 5GHz as a result.</p>
<h1 id="environmental-sensor">Environmental Sensor</h1>
<p>Perhaps the most unexpected (and welcome!) move from Cisco is the addition of environmental sensors to the Access Point. The COVID-19 pandemic and the public’s interest in Air Quality Monitoring is no doubt what drives this change, but we’re told they won’t be enabled until IOS-XE v17.8 comes out.</p>
<p>The secondary benefits of Cisco getting in to the Sensor market is that it provides another string to the DNA Spaces bow, which is where we expect the Sensor data to be streamed to, and it helps IT keep a handle on IoT-sprawl. Sensors are nothing new and many Estates teams have been deploying them for years. By bringing the Sensor IoT in to IT though, Administrators can sleep more soundly (and pass their Cyber Essentials + audits more easily!) by knowing that their sensors are secure and kept up to date.</p>
<h1 id="site-survey-mode">Site-Survey Mode</h1>
<p>We no longer need to use EWC mode on an AP when doing surveys. A new mode of operation, survey mode, gives access to a nice simple GUI that’s got everything you need to use the AP for survey work. Joy! This makes surveying, and switching APs between modes, much simpler.</p>
<h1 id="improved-cable-routing">Improved cable routing</h1>
<p>It’s very hard to take a picture of this, but there’s a small lip at the outer edge of the 9100-series Access Points, where the Ethernet cables feed in to the Access Point. In the Catalyst 9130, this lip was sometimes in the way a little when inserting thick Cat6A cables. The new Catalyst 9136 has a smaller, less prominent lip, which makes it much easier to insert even the thickest of cables in to the AP. It’s a small change, but anything that makes deployments easier is a welcome development.</p>
<h1 id="summary">Summary</h1>
<p>The Catalyst 9136 is a great piece of technology that genuinely responds to the demands I see from my Customers. With dual 5Gbps mGig interfaces and PoE redundancy, Cisco are clearly stating their intent around supporting the 9136 and WiFi-6e as a mission-critical piece of technology. The performance and reliability provided by WiFi-6e will markedly improve the WiFi experience and will allow people to use WiFi across even more applications. The inclusion of Environmental Sensors in the AP is also a great move - it addresses demand, helps IT move away from Estates-lead IoT sprawl. Sensors can genuinely impact how Estates are managed and how people interact with their physical environment, which is a very welcome move from my perspective.</p>
<h1 id="further-reading">Further Reading</h1>
<h2 id="cisco">Cisco</h2>
<p><a href="https://www.cisco.com/go/wireless">Cisco Wireless Portfolio</a></p>
<p><a href="https://www.cisco.com/c/en/us/products/collateral/wireless/catalyst-9100ax-access-points/wpa3-dep-guide-og.html">Cisco WPA3 Deployment Guide</a></p>
<h2 id="apple">Apple</h2>
<p><a href="https://support.apple.com/en-gb/guide/security/sec8a67fa93d/web">Apple device WiFi Protocol Support</a></p>
<h2 id="intel">Intel</h2>
<p><a href="https://www.intel.co.uk/content/www/uk/en/products/docs/wireless/wi-fi-6e.html">WiFi-6e Overview</a></p>
<p><a href="https://www.intel.co.uk/content/www/uk/en/support/articles/000054783/wireless.html">Support for WPA3</a></p>
<p><a href="https://www.intel.co.uk/content/www/uk/en/support/articles/000057519/network-and-io.html">Support for WPA3-OWE</a></p>
<h2 id="microsoft">Microsoft</h2>
<p><a href="https://support.microsoft.com/en-us/windows/faster-and-more-secure-wi-fi-in-windows-26177a28-38ed-1a8e-7eca-66f24dc63f09#WindowsVersion=Windows_11">Support for WiFi-6 and WPA3</a></p>Richard AtkinCisco have announced the new Catalyst 9136 WiFi-6e Access Point. It's a ground-breaking piece of technology; let's take a look at what it's all about.Identifying and retrieving TLS/SSL Certificates from a PCAP file using Wireshark.2022-01-15T00:00:00+00:002022-01-15T00:00:00+00:00https://richardatkin.com/post/2022/01/15/Identifying-and-retrieving-certificates-from-a-PCAP-file-using-Wireshark<p>If you need to see exactly what Certificates are being exchanged between things over the network, Wireshark has the answers.</p>
<p>Assuming you’ve got a PCAP full of stuff, the first thing you need to do is to find the right ‘Hello’ packet. A hello packet is sent by the Client to the Server to initiate the connection between the two. Once we’ve identified this initial packet, we can then follow the conversation and get the Certificate(s) involved.</p>
<h1 id="finding-the-hello-packet">Finding the Hello Packet</h1>
<p>Depending on what you already know, there are all sorts of ways you could use Wireshark’s Filters to identify the inital packet… You can mix and match conditions as required to help you find what you’re looking for.</p>
<h2 id="client">Client</h2>
<h3 id="find-all-client-tls-hello-packets">Find all Client TLS Hello packets</h3>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssl.handshake.type == 1
</code></pre></div></div>
<h3 id="find-all-tls-client-hello-packets-from-a-particular-ip-address">Find all TLS Client Hello packets from a particular IP address</h3>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssl.handshake.type == 1 && ip.addr == 35.160.54.177
</code></pre></div></div>
<h3 id="find-all-tls-client-hello-packets-from-a-particular-ip-address-and-tcp-port">Find all TLS Client Hello packets from a particular IP address and TCP port</h3>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssl.handshake.type == 1 && ip.addr == 35.160.54.177 && tcp.port == 443
</code></pre></div></div>
<h3 id="find-all-tls-client-hello-packets-that-contain-a-particular-sni">Find all TLS Client Hello packets that contain a particular SNI</h3>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssl.handshake.type == 1 && tls.handshake.extensions_server_name contains "mozilla.com"
</code></pre></div></div>
<h3 id="find-all-tls-client-hello-packets-with-support-for-tls-v13">Find all TLS Client Hello packets with support for TLS v1.3</h3>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssl.handshake.type == 1 && tls.handshake.extensions.supported_version == 0x0304
</code></pre></div></div>
<h3 id="find-all-tls-client-hello-packets-with-support-for-tls-v12">Find all TLS Client Hello packets with support for TLS v1.2</h3>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssl.handshake.type == 1 && tls.handshake.extensions.supported_version == 0x0303
</code></pre></div></div>
<h3 id="find-all-tls-client-hello-packets-with-support-for-tls-v11">Find all TLS Client Hello packets with support for TLS v1.1</h3>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssl.handshake.type == 1 && tls.handshake.extensions.supported_version == 0x0302
</code></pre></div></div>
<h3 id="find-all-tls-client-hello-packets-with-support-for-tls-v10">Find all TLS Client Hello packets with support for TLS v1.0</h3>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssl.handshake.type == 1 && tls.handshake.extensions.supported_version == 0x0301
</code></pre></div></div>
<p>Once you’ve found the Client hello, you can then follow the conversation in Wireshark until you find the corresponding Server Hello.</p>
<p>You could also just search straight for the Server Hello (which is sent as a response to the Client hello), by changing the Wireshark filter’s ssl handshake type, to 2.</p>
<h2 id="find-all-server-tls-hello-packets">Find all Server TLS Hello packets</h2>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssl.handshake.type == 2
</code></pre></div></div>
<h1 id="following-the-conversation">Following the conversation</h1>
<p>Once you’ve identified the Server Hello packet, it’s time to dig a little deeper.</p>
<p>First, ensure that your Wireshark is set to reassemble out-of-order TCP packets. Without this, it can sometimes be very difficult to complete this next step. You can verify that Wireshark is configured to do this by going to this page in the Wireshark GUI and ensuring that any reassembly related options are ticked.</p>
<h2 id="enabling-out-of-order-tcp-reassambly-in-wireshark">Enabling out-of-order TCP reassambly in Wireshark</h2>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Wireshark GUI:
1. Edit > Preferences
(A popup window should appear)
2. In the popup window, go to "Protocols" and then "TCP"
3. Ensure TCP reasembly options are enabled
</code></pre></div></div>
<h2 id="find-the-certificate">Find the Certificate</h2>
<p>In the packet you’ve selected, identify the Transport Layer Security section and expand the contents. You are looking for a section similar to this:</p>
<p><a href="/assets/images/tlsServerHello.png"><figure class="">
<img src="/assets/images/tlsServerHello.png" alt="" /></figure>
</a></p>
<p>Note that, depending on the particular Server / CA / Protocol you’re dealing with, the packet capture may contain multiple Certificates. You may also notice that some of the Certificates are bigger than the others. This is because the server has basically sent everything twice. In this example, the Server’s Certificate chain includes the host its self, an issuing CA, and a Root CA. The smallest Certificate in the capture (Certificate length 1380) contains only the Root CA Public Key. The second smallest Certificate in the capture (Certificate length 1754) contains both the Root CA and issuing CA. The largest certificate in the capture (Certifiate length 2119) contains all three Certificates chained together. If in doubt, extract them all separately and inspect them individually for yourself, but it’s usually a safe bet to just extract the largest Certificate.</p>
<h2 id="extract-the-certificate">Extract the Certificate</h2>
<p>Now you’ve found the Certificate, you can extract it by right clicking on the Certificate and selecting ‘Export packet bytes…’ and ave the file as a *.cer file.</p>
<p><a href="/assets/images/tlsExportPacketBytes.png"><figure class="">
<img src="/assets/images/tlsExportPacketBytes.png" alt="" /></figure>
</a></p>
<p>Once you’ve got the file save, you can then open it in Windows like any normal Certificate.</p>
<p><a href="/assets/images/tlsCiscoCert.png"><figure class="">
<img src="/assets/images/tlsCiscoCert.png" alt="" /></figure>
</a></p>Richard AtkinGathering data from Networks and Clients to help you understand what's going on.Using multi-threaded Python for large scale DNS name resolution2022-01-15T00:00:00+00:002022-01-15T00:00:00+00:00https://richardatkin.com/post/2022/01/15/Using-multithreaded-Python-to-speed-up-DNS-name-resolution<p>I was running a honeypot back in 2020 and an attacker kindly left a BIG list of hostnames behind. I wanted to resolve the hostnames in DNS to get the IP addresses, but there was over half a million names in the list and my initial attempt at resolving them all was too slow, so I had to switch things up a bit.</p>
<h1 id="first-the-worst">First the worst</h1>
<p>My initial attempt looked a bit like this. A single-threaded script that just read the text file and dumped everything to the screen. Unfortunately, network interactions are slow compared to local processing capabilities and it was taking <em>far</em> too long to process.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Single-threaded DNS-to-IP hostname resolver
# Version 1
# Richard Atkin
import socket
import datetime
def resolveDns():
filename = "C:\\Users\\richa\\Documents\\hostnames.txt"
with open(filename) as file:
hostnames = file.readlines()
hostnames = [line.rstrip() for line in hostnames]
start = datetime.datetime.now()
for host in hostnames:
try:
print(f"{host}: {socket.gethostbyname(host)}")
except Exception as e:
print(f"{host}: {e}")
continue
end = datetime.datetime.now()
duration = end - start
print(" ")
print(f"Time taken: {duration}")
print("")
if __name__ == "__main__":
resolveDns()
</code></pre></div></div>
<h1 id="second-the-best">Second the best</h1>
<p>To get around the performance issue, I decided I needed a way of querying multiple DNS requests in parallel, and that the best way to do this was via multi-threading. With a multi-threaded approach, I could divide and conquor. By splitting the list up in to multiple smaller chunks and having one thread dedicated to each chunk, I figured I could get the job done faster. I’ve never used threading in Python before or since, so while it is far from pretty, it gets the job done.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Multi-threaded DNS-to-IP hostname resolver
# Version 2
# Richard Atkin
import threading
import socket
import datetime
def resolveDns(hostnames):
for host in hostnames:
try:
print(f"{host}: {socket.gethostbyname(host)}")
except Exception as e:
print(f"{host}: {e}")
continue
if __name__ == "__main__":
filename = "C:\\Users\\richa\\Documents\\hostnames.txt"
with open(filename) as file:
hostnames = file.readlines()
hostnames = [line.rstrip() for line in hostnames]
start = datetime.datetime.now()
threads = list()
chunksize = 100
chunks = [hostnames[i:i + chunksize] for i in range(0, len(hostnames), chunksize)]
for chunk in chunks:
x = threading.Thread(target=resolveDns, args=(chunk,))
threads.append(x)
x.start()
for chunk, thread in enumerate(threads):
thread.join()
end = datetime.datetime.now()
duration = end - start
print(" ")
print(f"Time taken: {duration}")
print("")
</code></pre></div></div>
<h1 id="the-proof-is-in-the-numbers">The proof is in the numbers</h1>
<p>The single-threaded approach takes <strong>73.21 seconds</strong> to resolve a list of ~1000 hostnames on my current system, but the multi-threaded approach completes the same task in just <strong>3.96 seconds</strong>!</p>
<p>This is obviously a huge performance improvement, but this got me thinking… If I used smaller chunk sizes and more threads, could I get it even lower? Well…</p>
<table>
<thead>
<tr>
<th style="text-align: center">Chunk size</th>
<th style="text-align: center">Completion time (seconds)</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center">200</td>
<td style="text-align: center">4.73s</td>
</tr>
<tr>
<td style="text-align: center">100</td>
<td style="text-align: center">3.96s</td>
</tr>
<tr>
<td style="text-align: center">50</td>
<td style="text-align: center">1.11s</td>
</tr>
<tr>
<td style="text-align: center">25</td>
<td style="text-align: center">0.5761s</td>
</tr>
<tr>
<td style="text-align: center">10</td>
<td style="text-align: center">0.5969s</td>
</tr>
<tr>
<td style="text-align: center">5</td>
<td style="text-align: center">0.5659s</td>
</tr>
<tr>
<td style="text-align: center">2</td>
<td style="text-align: center">0.5951s</td>
</tr>
</tbody>
</table>
<p>Just over <strong>half-a-second</strong> to resolve 1000 hostnames is a huge improvement compared to the original effort of 73 seconds. This is a great example of how spending a little time optimising some code can bring huge benefits in performance.</p>
<h1 id="github">GitHub</h1>
<p>This code is available on GitHub:</p>
<p><a href="https://github.com/RikJonAtk/multiThreadedDNS">RikJonAtk/multiThreadedDNS</a></p>Richard AtkinNetwork-based IO is slow, so I used multi-threading in Python to resolve lots of hostnames at break-neck speedIdentify a randomised (locally administered) MAC Address2022-01-14T00:00:00+00:002022-01-14T00:00:00+00:00https://richardatkin.com/post/2022/01/14/MAC-Address-Randomisation<p>Anonymisation measures introduced by WiFi vendors makes to harder to use MAC Addresses to consistently identify a device. Here’s how you can tell if a device is using a locally administered (aka random) MAC Address.</p>
<p>A MAC address is six-pairs of hex characters, and a normal MAC address looks something like this:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>13:fe:34:dc:56:22
</code></pre></div></div>
<p>Each pair of hex characters is represented by eight bits (one byte) of data.</p>
<h1 id="locally-administered-addresses">Locally Administered Addresses</h1>
<p>Locally administered MAC addresses can be identified by looking at the second hex character in the MAC Address. If the character is a 2, 6, a or e, the address is considered as locally administered.</p>
<p>The rationale behind this is buried in the two least significant bits of the second character of the MAC address.</p>
<p>Consider the below:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>MAC Address
13:fe:34:dc:56:22
First byte of MAC Address (in Hex)
13:
First byte of MAC Address (in Binary)
0001 0011
^^ These two values are what we're interested in
</code></pre></div></div>
<p>The last two binary digits of the first byte control how the MAC address is perceived. The first (left-most) of these two digits is used to show if this is a Locally Administered MAC Address or not. The second (right-most) of these two digits is used to show if this MAC address belongs to an individual device, or a group.</p>
<table>
<thead>
<tr>
<th style="text-align: center">Last two bits of the first byte</th>
<th style="text-align: left">Meaning</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center">00</td>
<td style="text-align: left">Not a locally administered address, assigned to a specific device</td>
</tr>
<tr>
<td style="text-align: center">01</td>
<td style="text-align: left">Not a locally administered address, assigned to a group of devices</td>
</tr>
<tr>
<td style="text-align: center">10</td>
<td style="text-align: left">A locally administered address belonging to a specific device</td>
</tr>
<tr>
<td style="text-align: center">11</td>
<td style="text-align: left">A locally administered address belonging to a group of devices</td>
</tr>
</tbody>
</table>
<p>This means that any MAC Address where the penultimate bit of the first byte is ‘1’, is using a randomised or locally administered, MAC Address. This means we can easily produce a table showing all possible values of a locally administered MAC Address.</p>
<h2 id="all-locally-administered-mac-addresses">All Locally Administered MAC Addresses</h2>
<p>This table shows all possible values of the second MAC Address character where a locally administered MAC Address is being used.</p>
<table>
<thead>
<tr>
<th style="text-align: center">Binary</th>
<th style="text-align: center">Second Hex character of MAC Address</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center">0010</td>
<td style="text-align: center">2</td>
</tr>
<tr>
<td style="text-align: center">0011</td>
<td style="text-align: center">3</td>
</tr>
<tr>
<td style="text-align: center">0110</td>
<td style="text-align: center">6</td>
</tr>
<tr>
<td style="text-align: center">0111</td>
<td style="text-align: center">7</td>
</tr>
<tr>
<td style="text-align: center">1010</td>
<td style="text-align: center">a</td>
</tr>
<tr>
<td style="text-align: center">1011</td>
<td style="text-align: center">b</td>
</tr>
<tr>
<td style="text-align: center">1110</td>
<td style="text-align: center">d</td>
</tr>
<tr>
<td style="text-align: center">1111</td>
<td style="text-align: center">e</td>
</tr>
</tbody>
</table>
<h2 id="locally-administered-mac-addresses-for-wifi-clients">Locally Administered MAC Addresses for WiFi Clients</h2>
<p>Where we are only concerned about identifying WiFi Clients using Locally Administered addresses, then we know our two bits of interest must be “10”. This narrows down the number of possible values for the MAC Address’s second hex character to just four.</p>
<table>
<thead>
<tr>
<th style="text-align: center">Binary</th>
<th style="text-align: center">Hex</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center">00<strong>10</strong></td>
<td style="text-align: center">2</td>
</tr>
<tr>
<td style="text-align: center">01<strong>10</strong></td>
<td style="text-align: center">6</td>
</tr>
<tr>
<td style="text-align: center">10<strong>10</strong></td>
<td style="text-align: center">a</td>
</tr>
<tr>
<td style="text-align: center">11<strong>10</strong></td>
<td style="text-align: center">e</td>
</tr>
</tbody>
</table>
<p>This means that all Locally Administered Addresses will fit in to one of the following address formats:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code> x2:xx:xx:xx:xx:xx
x6:xx:xx:xx:xx:xx
xA:xx:xx:xx:xx:xx
xE:xx:xx:xx:xx:xx
</code></pre></div></div>
<h1 id="regular-expression">Regular Expression</h1>
<p>Now we know what we’re looking for, we can use a Regular Expression to search for Clients using Locally Administered MAC Addresses.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Regex: ^[0-9a-fA-F][26aeAE]
This regex can be read as;
^ Starting at the start of the string
[0-9a-fA-F] The first character can be anything between 0-f (f is a hex number,
which is equivalent to 15 in decimal or 1111 in binary)
[26aeAE] The second character can be 2, 6, a, e, A or E
NOTE: You can see that letters a & e are entered as both
uppercase and lowercase in the regular expression.
a, e, A & E are entered as lowercase and UPPERCASE to
help prevent issues relating to the industry's lack of
standardisation around whether upper or lower case
letters should be used to represent a MAC Address. This
approach ensures that regardless of whether you have upper
or lowercase letters, the regex will match correctly.
Also note, the regex does not evaluate characters in the
rest of the MAC address.
</code></pre></div></div>Richard AtkinAnonymisation measures introduced by WiFi vendors make it harder to use MAC Addresses to consistently identify a device. Here's how you can tell if a device is using a locally administered (aka random) MAC address.Using OpenSSL to create Self Signed Certificates2022-01-14T00:00:00+00:002022-01-14T00:00:00+00:00https://richardatkin.com/post/2022/01/14/OpenSSL<p>Sometimes you just need a quick and dirty TLS Certificate to test something or to help you setup a lab. Here’s a couple
of one-liners that have got me out of trouble more times than I can count…</p>
<h1 id="use-openssl-to-create-a-self-signed-certificate">Use OpenSSL to create a Self Signed Certificate:</h1>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -sha256 -days 365
</code></pre></div></div>
<p>Running this command launches a small wizard that asks you for details about the Certificate. As this is a self-signed
certificate, the details probabaly don’t matter much. The one to get right though, will be the ‘Common Name’. This
should generally match the hostname or identity of the thing you’re going to apply the Certificate to.</p>
<p>This particular examples creates a SHA256/4096bit x509 Certificate that’s valid for 365 days.</p>
<p>The output from the command is two files, one containing the public key and one containing the private key. The public
key in this example is called ‘cert.pem’ and the private key is called ‘key.pem’.</p>
<h1 id="use-openssl-to-merge-separate-public-and-private-keys-in-to-a-single-pkcs12-certificate">Use OpenSSL to merge separate public and private keys in to a single PKCS12 Certificate:</h1>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>openssl pkcs12 -export -out keyStore.p12 -inkey key.pem -in cert.pem
</code></pre></div></div>
<p>Running this command will take key.pem (private key) and cert.pem (public key) as inputs and, after asking you to setup
an export password, will export a single certificate file that contains the public and private keys. The output
file is called keyStore.p12.</p>Richard AtkinSometimes you just need a quick and dirty SSL Certificate... here's how.WiFi Troubleshooting2022-01-10T00:00:00+00:002022-01-10T00:00:00+00:00https://richardatkin.com/post/2022/01/10/Troubleshooting<p>WiFi is complex and it can break in a great many ways, but the approach to troubleshooting anything is basically the same every time. We compare what we see happening, with what we think should be happening in a correctly configured and well optimised environment, and we make changes as necessary to close the gap. Clearly then, possessing knowledge about what good looks like and access to good diagnostic data, are both key to effective troubleshooting. In this post I look at common ways of remotely gathering that diagnostic data across a range of common Clients and Networks, such as Cisco, Meraki, Microsoft Windows, and Apple.</p>
<p>It’ll take me an age to do deep dives on all of these things, so for now this is a post containing links to useful troubleshooting resources. The content within these links is essentially things I just know, or resources I link to frequently to help me do my job.</p>
<hr />
<h1 id="cisco">Cisco</h1>
<h2 id="identity-services-engine">Identity Services Engine</h2>
<p><a href="https://www.cisco.com/c/en/us/support/docs/security/identity-services-engine/212594-debugs-to-troubleshoot-on-ise.html">Debug logging</a></p>
<h2 id="aireos-wireless-lan-controllers---2504-3504-5508-5520-8510-8540">AireOS Wireless LAN Controllers - 2504, 3504, 5508, 5520, 8510, 8540</h2>
<p><a href="https://www.cisco.com/c/en/us/support/docs/wireless/wireless-lan-controller-software/200046-tac-recommended-aireos.html">Recommended AireOS Software</a></p>
<p><a href="https://www.cisco.com/c/en/us/support/docs/wireless-mobility/wireless-lan-wlan/201007-AireOS-feature-list-per-release.html">AireOS Features by Software Version</a></p>
<p><a href="https://www.cisco.com/c/en/us/td/docs/wireless/controller/technotes/8-8/AireOS_Cat_9800_Feature_Comparison_Matrix.html">AireOS / IOS-XE Feature Comparison Matrix</a></p>
<p><a href="https://www.cisco.com/c/en/us/support/docs/wireless/aironet-1200-series/100260-wlc-debug-client.html">Client debugging</a></p>
<p><a href="https://www.cisco.com/c/en/us/support/docs/switches/catalyst-9200-series-switches/216945-outputs-to-collect-in-the-event-of-crash.pdf">WLC Crash Logs</a></p>
<h2 id="ios-xe-wireless-lan-controllers---9800-series">IOS-XE Wireless LAN Controllers - 9800 series</h2>
<p><a href="https://www.cisco.com/c/en/us/support/docs/wireless/catalyst-9800-series-wireless-controllers/214749-tac-recommended-ios-xe-builds-for-wirele.html">Recommended IOS-XE Software</a></p>
<p><a href="https://www.cisco.com/c/en/us/support/docs/wireless/catalyst-9800-series-wireless-controllers/214855-ios-xe-wireless-feature-list-per-release.html">IOS-XE WLC Features by Software Version</a></p>
<p><a href="https://www.cisco.com/c/en/us/support/docs/wireless/catalyst-9800-series-wireless-controllers/215523-quick-start-guide-on-what-logs-and-debug.html">Troubleshooting quick start guide</a></p>
<p><a href="https://www.cisco.com/c/en/us/support/docs/wireless/catalyst-9800-series-wireless-controllers/213949-wireless-debugging-and-log-collection-on.html">Debug logging & WLC packet captures</a></p>
<p><a href="https://www.cisco.com/c/en/us/support/docs/wireless/catalyst-9800-series-wireless-controllers/213970-catalyst-9800-wireless-controllers-commo.html">Common Wireless Client Connectivity Issues</a></p>
<p><a href="https://www.cisco.com/c/en/us/support/docs/switches/catalyst-9200-series-switches/216945-outputs-to-collect-in-the-event-of-crash.pdf">WLC Crash Logs</a></p>
<h2 id="access-points">Access Points</h2>
<p><a href="https://www.cisco.com/c/en/us/support/docs/wireless/5500-series-wireless-controllers/119286-lap-notjoin-wlc-tshoot.html">AP fails to join WLC</a></p>
<p><a href="https://www.cisco.com/c/en/us/support/docs/wireless/aironet-2800-series-access-points/214560-troubleshoot-wave-2-aps.html">Advanced COS AP Troubleshooting</a></p>
<h1 id="microsoft">Microsoft</h1>
<h2 id="wireless-network-troubleshooting">Wireless Network Troubleshooting</h2>
<p><a href="https://docs.microsoft.com/en-us/windows/client-management/advanced-troubleshooting-wireless-network-connectivity">Advanced troubleshooting for Wireless networks</a></p>
<h2 id="8021x-authentication">802.1X Authentication</h2>
<p><a href="https://docs.microsoft.com/en-us/windows/client-management/data-collection-for-802-authentication">Collecting data for 802.1x troubleshooting</a></p>
<p><a href="https://docs.microsoft.com/en-us/windows/client-management/advanced-troubleshooting-802-authentication">Advanced troubleshooting 802.1X authentication</a></p>
<h2 id="windows-client">Windows Client</h2>
<p><a href="https://support.microsoft.com/en-us/windows/analyze-the-wireless-network-report-76da0daa-1db2-6049-d154-7bb679eb03ed">Wireless Network Reporting</a></p>
<p>See also: (from windows command prompt) “Netsh wlan ….” set of commands.</p>
<h1 id="apple">Apple</h1>
<h2 id="ios">iOS</h2>
<p><a href="https://developer.apple.com/bug-reporting/profiles-and-logs/?platform=ios">Debug Profiles and Logging for iOS</a></p>
<h2 id="macos">macOS</h2>
<p><a href="https://developer.apple.com/bug-reporting/profiles-and-logs/?platform=macos">Debug Profiles and Logging for macOS</a></p>Richard AtkinGathering data from Networks, RADIUS Servers and Clients to help you understand what's going on in your WiFi environment.