<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Configuration on 0x2142 | Networking Nonsense</title>
    <link>https://0x2142.com/tags/configuration/</link>
    <description>Recent content in Configuration on 0x2142 | Networking Nonsense</description>
    <image>
      <title>0x2142 | Networking Nonsense</title>
      <url>https://0x2142.com/logo.jpg</url>
      <link>https://0x2142.com/logo.jpg</link>
    </image>
    <generator>Hugo -- 0.143.1</generator>
    <language>en-us</language>
    <lastBuildDate>Tue, 02 Aug 2022 14:50:51 +0000</lastBuildDate>
    <atom:link href="https://0x2142.com/tags/configuration/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>[How to] Set up Wireguard VPN on OPNsense</title>
      <link>https://0x2142.com/how-to-set-up-wireguard-on-opnsense/</link>
      <pubDate>Tue, 02 Aug 2022 14:50:51 +0000</pubDate>
      <guid>https://0x2142.com/how-to-set-up-wireguard-on-opnsense/</guid>
      <description>In this post, we&amp;rsquo;ll walk through a simple WireGuard remote-access VPN configuration on OPNsense - including client setup examples with Windows &amp;amp; Android.</description>
      <content:encoded><![CDATA[<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
      <iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="allowfullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/b58PpuIsQ3A?autoplay=0&amp;controls=1&amp;end=0&amp;loop=0&amp;mute=0&amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"></iframe>
    </div>

<p>So in my <a href="/opnsense-qotom-q750gs/">last post</a>, I picked up a Qotom Mini-PC to run OPNsense on. After a few months, the device has been running well &amp; I&rsquo;m very happy with it.</p>
<p>One of the new things I got to try out with OPNsense was Wireguard VPN. I had previously been using something else for VPN connectivity back to my home network - but I heard good things about Wireguard &amp; wanted to give it a try.</p>
<p>So far my experience has been good! I&rsquo;ve been pleasantly suprised with how easy it is to configure &amp; get running. In addition, the performance &amp; overall experience has been very positive. The VPN connects quicker than anything I&rsquo;ve used in the past, and just simply works without issue.</p>
<p>All that being said - I wanted to put together a quick guide on how to configure Wireguard on OPNsense. Specifically, this configuraion will be for remote-access VPN - where clients will connect to a VPN headend. We&rsquo;ll walk through the OPNsense configuration &amp; a few clients as well. So let&rsquo;s dig in!</p>
<hr>
<h2 id="topology">Topology</h2>
<p>For the purpose of this blog post, we&rsquo;ll be using the lab topology below:</p>
<p><img alt="topology" loading="lazy" src="/content/images/2022/07/topology.png#center"></p>
<p>I will be using the reserved IP range 203.0.113.0/24 for the WAN-side addressing. I&rsquo;ll have one Windows &amp; one Android client that we&rsquo;ll walk through &amp; connect to the VPN.</p>
<h2 id="installing-the-wireguard-plugin">Installing the Wireguard Plugin</h2>
<p>To get started, first thing we will want to do is install the Wireguard plugin for OPNsense. By default, OPNsense will have standard IPSec &amp; OpenVPN already available - but other VPN options can be enabled easily.</p>
<p>So in OPNsense, we&rsquo;ll navigate down to <strong>System &gt; Firmware &gt; Plugins</strong>, then search for <strong>wireguard</strong> and click the plus icon.</p>
<p><img alt="addplugin" loading="lazy" src="/content/images/2022/07/addplugin.png#center"></p>
<p>This should pull down the package &amp; install pretty quickly. No reboot required here!</p>
<p><img alt="plugindownload" loading="lazy" src="/content/images/2022/07/plugindownload.png#center"></p>
<p>Once installed, you may have to refresh the page or navigate to a new page so that the menu bar has a chance to reload. Then we&rsquo;ll have a new option under <strong>VPN</strong>:</p>
<p><img alt="vpnmenu" loading="lazy" src="/content/images/2022/07/vpnmenu.png#center"></p>
<h2 id="wireguard-tunnel-configuration">Wireguard Tunnel Configuration</h2>
<p>Next we&rsquo;ll begin configuring Wireguard on the OPNsense side.</p>
<p>There is a little bit of a chicken &amp; egg scenario here since everything is based on cryptographic keys. We&rsquo;ll need to generate keys on the firewall, which we need to enter on the client - but we also need the client keys to enter on the firewall. A bit of bouncing between the two - but for now we&rsquo;ll try to complete as much as we can on the firewall side.</p>
<p>We&rsquo;ll enable Wireguard by dropping down to <strong>VPN &gt; WireGuard</strong> then clicking <strong>Enable</strong> and <strong>Apply</strong></p>
<p><img alt="enablewg" loading="lazy" src="/content/images/2022/07/enablewg.png#center"></p>
<p>Next we&rsquo;ll set up the Wireguard tunnel interface on OPNsense. This will be a virtual tunnel interface that will be created as interface <code>wg&lt;instance number&gt;</code>.</p>
<p>To do this, we&rsquo;ll navigate to the <strong>Local</strong> tab, and click the plus icon to add a new tunnel.</p>
<p><img alt="localconfig-pt1-1" loading="lazy" src="/content/images/2022/07/localconfig-pt1-1.png#center"></p>
<p>In the above screenshot, I&rsquo;ve filled in just a few details.</p>
<p>For <strong>Name</strong>, I&rsquo;ve entered our virtual interface name <code>wg1</code>. Since OPNsense shows the <strong>Instance</strong> as <code>1</code> - it will create a <code>wg</code> interface with that instance number.</p>
<p>We&rsquo;ll leave <strong>Public Key</strong> &amp; <strong>Private Key</strong> blank for now. OPNsense will auto-generate these keys once we save this config.</p>
<p>For <strong>Listen Port</strong>, I&rsquo;ve set this to 51820 which is the default for Wireguard. It&rsquo;s not stated here, but this is a UDP tunnel.</p>
<p>For <strong>Tunnel Address</strong> - this is where we add the IP address of the virtual tunnel interface. This will be the gateway for our remote clients. In my lab I&rsquo;ll be using 10.50.50.1/24 here.</p>
<p>We have no peers configured yet - so we can&rsquo;t select any here. We&rsquo;ll leave this blank for now, but come back later.</p>
<p>We will leave <strong>Disable Routes</strong> unchecked. By default, OPNsense will add static/connected routes for any client via the tunnel interface. You might not want this behavior if you wanted to do custom routing - for example, in a site-to-site VPN connection - but we&rsquo;ll leave this enabled.</p>
<p>Once we&rsquo;re done, we&rsquo;ll click <strong>Save</strong>.</p>
<p>Like I mentioned before, OPNsense will now auto-generate our crypto keys for the tunnels. So if we edit our tunnel, we&rsquo;ll now see those fields populated:</p>
<p><img alt="localconfig-pt2-1" loading="lazy" src="/content/images/2022/07/localconfig-pt2-1.png#center"></p>
<p>We&rsquo;ll want to copy the <strong>Public Key</strong> &amp; save it for later. This will need to be imported onto our clients, so that they can communicate securely with our firewall.</p>
<h2 id="wireguard-interface-assignment">Wireguard Interface Assignment</h2>
<p>Now that we have our headend tunnel interface defined, we can map our <code>wg1</code> interface to an OPNsense interface. The OPNsense documentation suggests this is optional, but I would recommend it since it will allow us to create firewall rules to permit/deny access to clients.</p>
<p>We&rsquo;ll navigate to <strong>Interfaces &gt; Assignments</strong>, and we should see a <strong>New interface</strong> available: our <code>wg1</code> tunnel.</p>
<p>We can assign this a name, then click the plus icon &amp; <strong>Save</strong>.</p>
<p><img alt="newinterface" loading="lazy" src="/content/images/2022/07/newinterface.png#center"></p>
<p>Next we&rsquo;ll enable the interface by navigating to <strong>Interfaces &gt; WG1</strong>. Here we&rsquo;ll only need to click <strong>Enable</strong> &amp; save the change - nothing else is necessary.</p>
<p><img alt="enableinterface" loading="lazy" src="/content/images/2022/07/enableinterface.png#center"></p>
<p>Of course, we&rsquo;ll be prompted to apply the changes - which we will do:</p>
<p><img alt="applychangeinterface" loading="lazy" src="/content/images/2022/07/applychangeinterface.png#center"></p>
<p>By default, all traffic through our <code>WG1</code> firewall interface will be blocked - so please make sure to configure a firewall rule to permit traffic from the Wireguard clients.</p>
<h2 id="firewall-rules-allow-inbound-wireguard-traffic">Firewall Rules: Allow Inbound Wireguard Traffic</h2>
<p>Next we need to permit the Wireguard traffic into our firewall. By default the WAN interface will block all traffic that isn&rsquo;t explicitly allowed - including our Wireguard traffic.</p>
<p>For this, we&rsquo;ll navigate to <strong>Firewall &gt; Rules &gt; WAN</strong>. Then click the plus icon to add a new rule.</p>
<p><img alt="waninboundfwrule" loading="lazy" src="/content/images/2022/07/waninboundfwrule.png#center"></p>
<p>The screenshot above shows what our firewall rule will look like.</p>
<p>Here&rsquo;s the summary:</p>
<ul>
<li>Action: Pass</li>
<li>Interface: WAN</li>
<li>Direction: In</li>
<li>TCP/IP Version: IPv4
<ul>
<li>You can enable IPv6 as well, if you have IPv6 connectivity (this is a lab box, which does not)</li>
</ul>
</li>
<li>Protocol: UDP</li>
<li>Source: Any
<ul>
<li>This will allow anyone on the internet to reach our VPN. We could restrict source IP addresses, if our clients had permanent, static IPs.</li>
</ul>
</li>
<li>Destination: WAN Address
<ul>
<li>The firewall itself is the destination for this traffic</li>
</ul>
</li>
<li>Destination Port Range: (other) / 51820</li>
</ul>
<p>I also enabled logging &amp; added a quick description. After we have all this configured, we can click <strong>Save</strong> - then <strong>Apply Changes</strong>.</p>
<h2 id="client-setup---windows">Client Setup - Windows</h2>
<p>So first we&rsquo;ll start with an easy configuration on a Windows client. Wireguard client software can be found on the Wireguard site <a href="https://www.wireguard.com/install/">here</a>.</p>
<p>For the sake of the walkthrough, we will manually configure each client. However, this can be a difficult task if there is a large number of clients. Wireguard does support importing configurations, and there are a number of free tools available to help automate generating config files for clients - including some which will generate QR codes for easy import on mobile clients.</p>
<p>So on my lab Windows machine, we&rsquo;ll open up the Wireguard client &amp; click <strong>Add Empty Tunnel:</strong></p>
<p><img alt="windows-addnew" loading="lazy" src="/content/images/2022/07/windows-addnew.png#center"></p>
<p>Then we&rsquo;ll be given a blank config file, with only the devices public &amp; private key pair generated for us.</p>
<p>We&rsquo;re going to fill in details similar to the below screenshot:</p>
<p><img alt="windows-tunnelconfig" loading="lazy" src="/content/images/2022/07/windows-tunnelconfig.png#center"></p>
<p>The configuration under [Interface] is the local, client-side configuration. I&rsquo;ve added the client&rsquo;s tunnel address - which will be 10.50.50.15/32. I&rsquo;ve also configured DNS servers which the client can reach via the VPN.</p>
<p>Then we&rsquo;ll add the [Peer] section, which contains info about our VPN headend. Here&rsquo;s where we&rsquo;ll need the public key from our OPNsense firewall. We&rsquo;ll also specify the <strong>Endpoint</strong> address, which is the IP or hostname of our VPN headend &amp; the port (which by default is 51820).</p>
<p>We&rsquo;ve also configured <strong>AllowedIPs</strong> as <code>0.0.0.0/0</code>. This will force <strong>all</strong> client traffic over the VPN tunnel - including general internet traffic. However, we could limit this to specific subnets. For example, let&rsquo;s say your network only used 172.16.90.0/24 &amp; 10.1.1.0/16 subnets &amp; we only wanted the user to be able to access those. We would configure the following: <code>AllowedIPs = 172.16.90.0/24, 10.1.1.0/16</code>. In this case, only traffic for those subnets would be routed over the VPN - any other traffic would use the devices default internet connection.</p>
<p>Now, we&rsquo;ll save this - and again need to copy the device&rsquo;s <strong>Public Key</strong>, which we&rsquo;ll need to enter on the OPNsense firewall.</p>
<h2 id="client-setup---adding-clients-to-opnsense">Client Setup - Adding Clients to OPNsense</h2>
<p>In order for the Windows machine to connect to OPNsense, we&rsquo;ll also need to configure a client profile on the firewall.</p>
<p>In OPNsense, we&rsquo;ll navigate back to <strong>VPN &gt; WireGuard</strong>, then click on the <strong>Endpoints</strong> tab.</p>
<p><img alt="wg-client-win" loading="lazy" src="/content/images/2022/07/wg-client-win.png#center"></p>
<p>Here we&rsquo;ll configure a name for our client &amp; paste in the client&rsquo;s <strong>Public Key</strong>.</p>
<p>We&rsquo;ll also set <strong>AllowedIPs</strong> to the client&rsquo;s IP address, which we have configured as <code>10.50.50.15/32</code>. This controls what IP addresses are reachable via this endpoint.</p>
<p>We do have some additional fields available, which we will leave blank. For example - <strong>Endpoint Address</strong> &amp; <strong>Endpoint Port</strong> would be used to define a public IP that we expect our client to connect from. Since a remote-access client could connect from any IP, we leave those fields blank to allow this.</p>
<p>Once we&rsquo;re done, we&rsquo;ll click <strong>Save</strong> then <strong>Apply</strong>.</p>
<p>Next we&rsquo;ll jump back to the <strong>Local</strong> tab, and edit our headend tunnel configuration.</p>
<p>We should now see our windows client in the <strong>Peers</strong> dropdown. We&rsquo;ll select that client, so that Wireguard will permit that client to connect via this tunnel interface.</p>
<p><img alt="localconfig-pt3" loading="lazy" src="/content/images/2022/07/localconfig-pt3.png#center"></p>
<p>Then, as always, click <strong>Save</strong> &amp; <strong>Apply</strong></p>
<p>Last but not least - we should restart our Wireguard server on OPNsense. This can be done by either disabling &amp; re-enabling Wireguard - or by navigating back to the OPNsense dashboard &amp; clicking the restart icon next to the <strong>wireguard-go</strong> service.</p>
<h2 id="testing-the-connection">Testing The Connection</h2>
<p>Okay - now that we have all that completed, it&rsquo;s finally time to test connectivity from our client.</p>
<p>On my Windows client, I&rsquo;ll just click the <strong>Activate</strong> button for the tunnel:</p>
<p><img alt="windows-tunnelconnected" loading="lazy" src="/content/images/2022/07/windows-tunnelconnected.png#center"></p>
<p>And we&rsquo;ll see that the <strong>Status</strong> shows <strong>Active</strong>, and we&rsquo;ll start to see updates to the <strong>Last Handshake</strong> &amp; <strong>Transfer</strong> fields - indicating we are connected &amp; sending data.</p>
<p>To further validate, we can check the <strong>Log</strong> tab:</p>
<p><img alt="windows-log" loading="lazy" src="/content/images/2022/07/windows-log.png#center"></p>
<p>The key things to look for here, are the following messages:</p>
<ul>
<li><strong>Receiving handshake response</strong> which indicates our firewall responded to our request to connect</li>
<li><strong>Keypair 1 created</strong> which indicates that our connection is healthy to our peer</li>
<li><strong>Receiving keepalive packet from peer</strong> - we should see these periodically to maintain our connection. If keepalives stop flowing, then we may have a break in connectivity between client &amp; peer.</li>
</ul>
<p>We should also be able to reach out <code>wg1</code> tunnel address from the Windows client:</p>
<p><img alt="windows-ping" loading="lazy" src="/content/images/2022/07/windows-ping.png#center"></p>
<p>On the OPNsense side of things, we can check what client is connected via the <strong>List Configuration</strong> tab, under <strong>VPN &gt; Wireguard</strong>:</p>
<p><img alt="wireguard-listconfig" loading="lazy" src="/content/images/2022/07/wireguard-listconfig.png#center"></p>
<p>On this screen, we can see we have 1 peer connected - which matches the IP &amp; public key of our Windows client. We&rsquo;ll see similar output like the Windows client, where we can see the latest handshake &amp; data transfer.</p>
<p>Additionally, for easier access we can add the Wireguard widget to the OPNsense dashboard.</p>
<p>If we navigate to our dashboard, then click <strong>Add widget</strong> - we can add the <strong>Wireguard</strong> widget.</p>
<p>Here&rsquo;s what that looks like:</p>
<p><img alt="wg-widget" loading="lazy" src="/content/images/2022/07/wg-widget.png#center"></p>
<h2 id="additional-client-setup---android">Additional Client Setup - Android</h2>
<p>Let&rsquo;s also take a quick look at a mobile client. I&rsquo;ll get through this pretty quickly, since the configuration will be very similar to our other client - just a different UI.</p>
<p>On my Android device - if I open up the Wireguard app, I have a few options for creating or importing a tunnel:</p>
<p><img alt="android-create-1" loading="lazy" src="/content/images/2022/07/android-create-1.png#center"></p>
<p>In this case, we&rsquo;ll again walk through creating a tunnel manually. Again, it&rsquo;s worth mentioning that there are 3rd party apps available to auto-generate config imports or QR codes to make this easier.</p>
<p>First we&rsquo;ll have a handful of fields to fill in about the Android-side configuration. This includes a name for the tunnel, an address, and DNS servers.</p>
<p>We can click on the refresh icon in the <strong>Private Key</strong> field to auto-generate our key pairs:</p>
<p><img alt="android-interface-1" loading="lazy" src="/content/images/2022/07/android-interface-1.png#center"></p>
<p>One of the interesting parts of the mobile app is the ability to permit/exclude individual apps from traversing the VPN tunnel.</p>
<p>Here&rsquo;s a quick screenshot, where we can pick either to allow only certain apps to use the VPN - or permit all except a few we choose to exclude:</p>
<p><img alt="android-app-list-1" loading="lazy" src="/content/images/2022/07/android-app-list-1.png#center"></p>
<p>In my case, I&rsquo;ll keep this set to allow all applications.</p>
<p>Next we&rsquo;ll work on the peer config:</p>
<p><img alt="android-peer-1" loading="lazy" src="/content/images/2022/07/android-peer-1.png#center"></p>
<p>After that, all we need to do is save our VPN configuration - then we can toggle the tunnel on or off:</p>
<p><img alt="android-enable-1" loading="lazy" src="/content/images/2022/07/android-enable-1.png#center"></p>
<p>And similar to the Windows client, we can click on the tunnel itself to see current status / data transfer:</p>
<p><img alt="android-stats-1" loading="lazy" src="/content/images/2022/07/android-stats-1.png#center"></p>
<p>So it looks like we should be connected &amp; can try accessing VPN resources!</p>
<p>We can also use the same methods as earlier to check connectivity from the OPNsense side.</p>
<hr>
<p>Okay - that&rsquo;s all I wanted to share today. I&rsquo;ve been quite pleased with how easy to use WireGuard has been  - and how well it performs! I hope this blog post was helpful if you&rsquo;re interested in trying it out.</p>
<p>Thanks!!</p>
]]></content:encoded>
    </item>
    <item>
      <title>OPNsense on Qotom Q750G5 - Hardware Overview &amp; Perf Testing</title>
      <link>https://0x2142.com/opnsense-qotom-q750gs/</link>
      <pubDate>Sat, 18 Jun 2022 18:21:18 +0000</pubDate>
      <guid>https://0x2142.com/opnsense-qotom-q750gs/</guid>
      <description>In this post, we will take a look at the Qotom Q750G5 hardware (with 2.5GbE), install OPNsense, and walk through a few performance tests.</description>
      <content:encoded><![CDATA[<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
      <iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="allowfullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/ppS6IhKSkfY?autoplay=0&amp;controls=1&amp;end=0&amp;loop=0&amp;mute=0&amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"></iframe>
    </div>

<p><sup><em>Note: I may receive commissions for purchases made through links in this post. This is to help support my blog and does not have any impact on my recommendations.</em></sup></p>
<p>One day I would love to have symmetric internet speeds, but for the meantime I have to work with what I have - which is dismal upload speeds that don&rsquo;t come anywhere close to the download speed.</p>
<p>So I&rsquo;m currently at 200Mb/s down &amp; 10Mb/s up - and I would prefer to have higher upload speeds. However, even just 20Mb/s upload requires me to purchase a 500Mb/s download plan. 🙄</p>
<p>I&rsquo;ve been hesitant to upgrade, since my current Meraki MX64 tops out at ~250Mb/s throughput. I would have to upgrade my firewall or half of my new download speed would be unusable.</p>
<p>While Meraki does have faster firewalls, they&rsquo;re a bit expensive &amp; at the moment somewhat difficult to obtain. So instead I searched around for alternatives, and came across the <a href="https://amzn.to/3apFx5R">Qotom Q750G5</a> - which is a barebones mini-PC that I could load pfSense or OPNsense onto.</p>
<p>So in this blog post - I wanted to talk about the device &amp; some of the performance testing I did.</p>
<hr>
<h2 id="qotom-q750g5---hardware">Qotom Q750G5 - Hardware</h2>
<p>First let&rsquo;s take a quick look at the hardware. What got my attention quickly was the five 2.5GbE ports, but this small device offers quite a lot for how inexpensive it was.</p>
<p>A quick look at the specs:</p>
<ul>
<li>Intel Celeron J4125 Quad Core 2.0Ghz (Burst 2.7Ghz)</li>
<li>Five Intel I225-V 2.5Gb Ethernet ports</li>
<li>Optional WiFi slot</li>
<li>Optional 3G Cellular &amp; SIM card slots</li>
<li>1 RAM slot</li>
<li>1 mSATA slot</li>
<li>1 2.5in SATA HDD slot</li>
<li>2x USB 2.0 &amp; 3x USB 3.0 ports</li>
</ul>
<p>By default it seems this is a barebones kit, however I did opt to buy a model that included 16GB RAM &amp; a 256GB mSATA SSD. It arrived with a single 16GB TeamGroup DDR4 3200Mhz module &amp; 256GB Hoodisk mSATA SSD.</p>
<p>Are the specs a bit overkill for an embedded firewall? Yeah definitely. But the whole kit was only around $230 USD - which seemed crazy to me.</p>
<p>The big thing that pulled me toward this model (besides price) was the 2.5GbE ports. Since a lot more places have gigabit residential internet these days, and some lucky places are starting to see 2Gb/s - I was hoping that this little box would offer me a bit of future-proofing.</p>
<p>Of course, I was a little curious about what performance this device could realistically achieve - but more on that later!</p>
<p>I wanted to provide a few photos of the unit as well. The casing itself is pretty minimal, but the box is definitely heavier than you would expect!</p>
<p><strong>Front Photo:</strong></p>
<p><img alt="qotom750g5-front" loading="lazy" src="/content/images/2022/05/qotom750g5-front.jpg#center"></p>
<p>On the front there isn&rsquo;t a whole lot to see. Power button, reset button, status LEDs, and USB ports. Oh - and there is an HDMI port as well, which comes in handy when installing an operating system (or if you&rsquo;re using this as an actual PC).</p>
<p><strong>Back Photo:</strong></p>
<p><img alt="qotom750g5-back" loading="lazy" src="/content/images/2022/05/qotom750g5-back.jpg#center"></p>
<p>The back shows off the five 2.5Gb Ethernet ports, as well as the power plug. While I didn&rsquo;t get a WiFi-enabled unit, the back faceplate still has cutouts for wireless antenna. I could opt to add wireless to this later, but I do wish the faceplate came with plugs or something to cover the holes in the meantine.</p>
<p><strong>Inside Photo:</strong></p>
<p><img alt="qotom750g5-internal-1" loading="lazy" src="/content/images/2022/05/qotom750g5-internal-1.jpg#center"></p>
<p>Now here&rsquo;s where things get interesting! This box surprisingly packs a lot in it&rsquo;s tiny size.</p>
<p>In the upper right, there is a PCI slot for WiFi. There&rsquo;s also a WiFi/3G PCI slot in the lower left.</p>
<p>Just above the 3G slot is the SSD mSATA slot. When a drive is installed, it does cover the SIM card slot - meaning that the SSD would need to be removed to change SIM cards.</p>
<p>Also on the left, mostly out of the photo, is a connector for a 2.5in HDD. While I didn&rsquo;t snap a photo of the bottom of the unit, the drive would screw into the bottom plate.</p>
<p>Interestingly enough, the CPU is on the other side of the motherboard. While you might think that the overall unit kinda looks like a heatsink - I was surprised to see that&rsquo;s exactly what it is. The CPU is located right under the four screws with black washers and has thermal paste pre-applied. It rests up against the top of the case &amp; uses the top as a heatsink.</p>
<p>As a last note about the CPU - it does get <em>quite toasty</em> at times. During one of my performance tests, the CPU reached ~90°C - and the top of the unit was very hot to the touch. It may not act as the world&rsquo;s best heatsink, so I would avoid placing anything on top of the unit - or resting your hand there for too long 🙂.</p>
<h2 id="performance-testing">Performance Testing</h2>
<p>As a quick note before we get to the good stuff: All of my tests were performed using <a href="https://iperf.fr/iperf-download.php">iPerf3</a>. This may not show us the best real-world throughput tests, but I had quite a difficult time getting dpdk drivers to compile correctly for the Intel 2.5GbE ports (so I could use something like <a href="https://trex-tgn.cisco.com/">TRex</a>). I may attempt to go back to this later, but the iPerf data is what I&rsquo;ll provide for now.</p>
<h3 id="the-testbed">The Testbed</h3>
<p>For the performance testing, I used the two <a href="/home-lab-upgrade-intel-nuc11/">Intel NUC11</a> PCs that I purchased recently for my VMware lab. These already come with a 2.5GbE port, which I am currently using for vMotion between the two. I disconnected the vMotion port temporarily, and instead enabled PCI-passthrough to connect the ports directly to a VM.</p>
<p>I built a VM on each NUC with the following specs:</p>
<ul>
<li>Debian 11</li>
<li>8x vCPU</li>
<li>16GB RAM</li>
<li>PCI-passthrough to 2.5GbE adapter</li>
</ul>
<p>iPerf 3.9 was used for all tests. The iPerf server was enabled with the <code>iperf3 -s</code> command, and the client tests were run with <code>iperf3 -c &lt;client ip&gt; -P 8 -t 600</code>. Each test was run for 10 minutes.</p>
<p>The devices were connected &amp; configured with the following topology:</p>
<p><img alt="network-diagram" loading="lazy" src="/content/images/2022/05/network-diagram.png#center"></p>
<blockquote>
<p>Note: In the below paragraphs, I will talk about the configuration I used for each test. If you&rsquo;re interested in more detail, please check out the video at the top of this blog post. In the video, I walk through the configuration &amp; setup for most of the tests below.</p></blockquote>
<h3 id="test-1-no-firewall">Test 1: No Firewall</h3>
<blockquote>
<p>Avg: 2.35Gb/s</p></blockquote>
<p>Okay, so expecting that I likely wouldn&rsquo;t get the full 2.5Gb speeds once I added the firewall - I wanted to perform a baseline test with the VM&rsquo;s directly connected via the 2.5GbE passthrough port.</p>
<p>In each of these tests, I was able to reach an average speed of: 2.35Gb/s</p>
<h3 id="test-2-routing-nat-simple-firewall-rules">Test 2: Routing, NAT, Simple Firewall rules</h3>
<blockquote>
<p>Avg: 2.35Gb/s</p></blockquote>
<p>In this test case, OPNsense was configured to match the diagram above. The iPerf server was located on the LAN segment, with an IP of 10.2.2.1 &amp; a default route toward the LAN interface of the OPNsense box (10.2.2.2). The client is connected via the WAN interface, at 203.0.113.50.</p>
<p>I created a proxy-ARP virtual address for the 203.0.113.25 IP address, then created a NAT rule to forward traffic sent to that address to 10.2.2.1.</p>
<p>Next, there was a single firewall rule created to permit TCP port 5201 inbound from the WAN. This is the default port that iPerf will use.</p>
<p>During these tests, I averaged about 2.35Gb/s and relatively low CPU usage around 10-20%.</p>
<p><em>As an interesting side note to this: Originally I didn&rsquo;t use the default LAN &amp; WAN ports (ports 1 &amp; 2), but instead used ports 3 &amp; 4. During testing between those ports, I could only reach ~1.7Gb/s. Once I switched to ports 1 &amp; 2, I could easily hit 2.35Gb/s. I&rsquo;m curious to dig in later &amp; see if this is a hardware issue, or possibly OPNsense is prioritizing the LAN/WAN traffic differently</em></p>
<h3 id="test-3-large-firewall-ruleset">Test 3: Large Firewall Ruleset</h3>
<blockquote>
<p>Avg: 2.35Gb/s</p></blockquote>
<p>While my home network will likely have a somewhat minimal firewall ruleset, I was curious to see how well the device would perform with a large ruleset.</p>
<p>So I wrote a script to auto-generate ~1,200 firewall rules with random IP addresses, ports, and a mix of permit/block actions. I applied the ruleset inbound on both the LAN &amp; WAN ports.</p>
<p>Under this test, I was still able to reach the 2.35Gb/s speeds - but now the CPU was creeping up to 30-40%.</p>
<p>So what next? Well I decided to see if I could stress the box a little - and increased the auto-generated ruleset to just over ~15,000 rules.</p>
<p>The increased ruleset took about 5-10 minutes to load into the system, and CPU was pegged at 100% the whole time. In fact, the CPU never really came back down. Even after the rules had loaded, the CPU was flat at 100% - and it took anywhere from 2-4 minutes to navigate between pages in the web GUI. (This is the part where my CPU temps went from &lt;50°C to over 90°C 🙃)</p>
<p>I ended up having to re-image the box.</p>
<h3 id="test-4-suricata-ips">Test 4: Suricata IPS</h3>
<blockquote>
<p>Avg: 2.35Gb/s (But sometimes much, much less)</p></blockquote>
<p>Next I loaded up the built-in IDS/IPS, which uses suricata. I downloaded all available free rulesets, and enabled all of them. Ideally, you wouldn&rsquo;t necessarily enable everything - but I wanted to start off with a full load test.</p>
<p>My experience with these tests was highly variable. <em>Most</em> times, I was surprised to see that I could still push 2.35Gb/s through without any issue. During these tests, the CPU usually bounced between 50-80% usage.</p>
<p>Strangely, every so often I would test and get significantly less than that. Most times when this happened, I would instead only see somewhere between 400-700Mb/s - but on one test the box slowed to just over 200Mb/s. Each time this happened, the performance tests would remain degraded until I restarted the suricata service - then I would be able to reach the 2.35Gb/s again.</p>
<p>My best guess is that something is getting stuck. I know some older IPS systems I&rsquo;ve worked with in the past had issues with CPU-pinning, and you might get garbage performance if your traffic hit the wrong CPU core. I didn&rsquo;t spend a lot of time digging into this, but it feels a bit similar.</p>
<h3 id="test-5-wireguard-vpn">Test 5: Wireguard VPN</h3>
<blockquote>
<p>Avg: 800Mb/s, 650-700Mb/s with IPS also enabled</p></blockquote>
<p>I also wanted to try VPN performance. There are a lot of options for VPN services within OPNsense, including standard IPSec and OpenVPN. However, I opted to try out wireguard - since it&rsquo;s really easy to set up &amp; get running.</p>
<p>In this case, I definitely hit a limitation with CPU-pinning. With my initial tests, I could only reach about ~450-500Mb/s - but the Qotom CPU was only spiking up to 70%.</p>
<p>Seems like the wireguard client (at least for same source/destination/port traffic) does pin everything to a single CPU. So my client CPU, between encrypting the traffic &amp; generating it, was actually maxing out long before the Qotom was.</p>
<p>I ended up spinning up a second VM on the client side (which required disabling PCI passthough &amp; adding both VMs to a shared vSwitch). With both of these running, I was able to max out the Qotom CPU at 100% - and hit a fairly consistent 800Mb/s VPN throughput.</p>
<p>As a final test, I enabled the suricata IPS on top of the VPN as well. Now the traffic would need to be decrypted &amp; inspected before reaching the server. With a single client, I averaged ~400-450Mb/s - and with both clients it was around ~650-700Mb/s</p>
<hr>
<p>Overall I&rsquo;m really pleased with how well this thing performs, especially for how relatively inexpensive it was. I also expected OPNsense to have a steep learning curve, but it was surprisingly easy to get up and running very quickly.</p>
<p>Next I&rsquo;ll be working on getting this firewall up &amp; running at home. I may be tempted to write up some more on OPNsense - so if there are any questions or specific configurations you might like to see, please leave a comment!</p>
]]></content:encoded>
    </item>
    <item>
      <title>[How To] Cisco SD-WAN - Onboarding a Catalyst 8000v</title>
      <link>https://0x2142.com/how-to-cisco-sd-wan-onboarding-a-catalyst-8000v/</link>
      <pubDate>Fri, 14 May 2021 16:10:38 +0000</pubDate>
      <guid>https://0x2142.com/how-to-cisco-sd-wan-onboarding-a-catalyst-8000v/</guid>
      <description>Let&amp;rsquo;s look at how to join a Cisco Catalyst 8000v to an SDWAN network</description>
      <content:encoded><![CDATA[<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
      <iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="allowfullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/HyPYLKrPPsk?autoplay=0&amp;controls=1&amp;end=0&amp;loop=0&amp;mute=0&amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"></iframe>
    </div>

<p>I&rsquo;ve been getting a handful of questions lately on the process of bringing a Cisco Catalyst 8000v or CSR 1000v into an SD-WAN environment. So I figured maybe I should put something together to share.</p>
<p>On a related note - I&rsquo;ve been debating for a while doing a blog and/or video on building out a Cisco Viptela SD-WAN lab in EVE-NG. This would (tentatively) include everything from building controllers, bringing up remote sites, and template/policy configs.  If this is something you might get value from, please let me know!! I&rsquo;m looking for some motivation :)</p>
<p>Okay - all that being said, let&rsquo;s go ahead and get started.</p>
<blockquote>
<p>Note: This guide should work with CSR 1000v devices as well. But it will NOT be 100% accurate for physical ISR/IOS-XE routers, as there are some additional steps with certificates &amp; the Plug and Play portal to get those running.</p></blockquote>
<hr>
<h2 id="topology">Topology</h2>
<p>So to start with, figured I would share the topology that I&rsquo;m working from. If you read my <a href="/cisco-sdwan-and-umbrella-sig-integration/">last post</a> you might recognize this, but with an added location. This new location (site id 400) contains our Catalyst 8000v VM, running IOS-XE version 17.04.01a.</p>
<p><img alt="001&mdash;Topology" loading="lazy" src="/content/images/2021/05/001---Topology.PNG#center"></p>
<h2 id="controller-or-autonomous-mode">Controller or Autonomous Mode?</h2>
<p>Back in the earlier days of IOS-XE SD-WAN, there used to be two separate software images to load on your network appliance - one for traditional IOS-XE, and one for SD-WAN code.</p>
<p>With the newer releases of IOS-XE, we&rsquo;re now getting a unified image that contains both software sets. So our options now are two modes: autonomous (traditional IOS-XE) or controller (SD-WAN).</p>
<p>One way we can check this, is by running a <em>show version</em> and looking for <strong>Router operating mode</strong>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Router# show version
</span></span><span class="line"><span class="cl">&lt;-- Output omitted --&gt;
</span></span><span class="line"><span class="cl">cisco C8000V (VXE) processor (revision VXE) with 2035355K/3075K bytes of memory.
</span></span><span class="line"><span class="cl">Processor board ID XXXXXXXXXXX
</span></span><span class="line"><span class="cl">Router operating mode: Autonomous
</span></span><span class="line"><span class="cl">4 Gigabit Ethernet interfaces
</span></span><span class="line"><span class="cl">32768K bytes of non-volatile configuration memory.
</span></span><span class="line"><span class="cl">3965744K bytes of physical memory.
</span></span><span class="line"><span class="cl">5234688K bytes of virtual hard disk at bootflash:.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Configuration register is 0x2102
</span></span></code></pre></div><p>Okay, and looks like the Catalyst 8000v image I&rsquo;m using booted up in autonomous mode. No big deal, we can change modes pretty easily!</p>
<p>So in normal exec-mode, we&rsquo;ll use the command <em>controller-mode enable</em>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Router# controller-mode enable
</span></span><span class="line"><span class="cl">Enabling controller mode will erase the nvram filesystem, remove all configuration files, and reload the box!
</span></span><span class="line"><span class="cl">Ensure the BOOT variable points to a valid image
</span></span><span class="line"><span class="cl">Continue? [confirm]
</span></span></code></pre></div><p>As noted in the snippet above - this command will erase the config! So you will want to take a backup snapshot of your existing configuration, if this is already being used.  In my case, it&rsquo;s a brand new VM - so we&rsquo;ll continue on.</p>
<p>Once the device is back online, we&rsquo;ll log in with the default login of <strong>admin/admin</strong>. Note that you will be forced to change this upon first login.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">User Access Verification
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Username: admin
</span></span><span class="line"><span class="cl">Password:
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Default admin password needs to be changed.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Enter new password:
</span></span><span class="line"><span class="cl">Confirm password:
</span></span><span class="line"><span class="cl">Router#
</span></span></code></pre></div><p>And just for fun, we&rsquo;ll run a <em>show version</em> again to ensure we&rsquo;re in controller mode:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Router# show version 
</span></span><span class="line"><span class="cl">&lt;-- Output omitted --&gt;
</span></span><span class="line"><span class="cl">cisco C8000V (VXE) processor (revision VXE) with 2035355K/3075K bytes of memory.
</span></span><span class="line"><span class="cl">Processor board ID XXXXXXXXXXX
</span></span><span class="line"><span class="cl">Router operating mode: Controller-Managed
</span></span><span class="line"><span class="cl">4 Gigabit Ethernet interfaces
</span></span><span class="line"><span class="cl">32768K bytes of non-volatile configuration memory.
</span></span><span class="line"><span class="cl">3965756K bytes of physical memory.
</span></span><span class="line"><span class="cl">5234688K bytes of virtual hard disk at bootflash:.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Configuration register is 0x2102
</span></span></code></pre></div><h2 id="catalyst-8000v-initial-config">Catalyst 8000v Initial Config</h2>
<p>So since this is a lab environment, and I&rsquo;m not trying to provide any Day0 provisioning files - I&rsquo;ll have to complete some manual configuration to get started.</p>
<p>First, we&rsquo;ll start with some SD-WAN specific config (site id, org name, etc). I&rsquo;ll be using the values that apply to my lab, so be sure to change these in yours!</p>
<blockquote>
<p>Note: If you haven&rsquo;t used IOS-XE SD-WAN previously, be aware that &ldquo;conf t&rdquo; doesn&rsquo;t work! In SD-WAN/controller mode, you&rsquo;ll use &ldquo;config-transaction&rdquo;. In this mode, all changes will need to be committed before they&rsquo;re applied to the device.</p></blockquote>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Router# config-transaction
</span></span><span class="line"><span class="cl"> ! Set hostname
</span></span><span class="line"><span class="cl">Router(config)# hostname Cat8k-Site400
</span></span><span class="line"><span class="cl"> ! Required SD-WAN system configs
</span></span><span class="line"><span class="cl">Router(config)# system
</span></span><span class="line"><span class="cl">Router(config-system)# organization-name &#34;SDWAN-LAB&#34;
</span></span><span class="line"><span class="cl">Router(config-system)# site-id 400
</span></span><span class="line"><span class="cl">Router(config-system)# vbond 192.168.99.241
</span></span><span class="line"><span class="cl">Router(config-system)# system-ip 10.10.10.237
</span></span><span class="line"><span class="cl">Router(config-system)# commit
</span></span><span class="line"><span class="cl">Commit complete.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Cat8k-Site400# 
</span></span></code></pre></div><p>Once we have those basics configured, at a minimum we&rsquo;ll also need to configure our internet-facing tunnel interface. This allows our Catalyst 8000v to communicate with our control plane for bring-up.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Cat8k-Site400#config-transaction
</span></span><span class="line"><span class="cl"> ! Config physical interface (This is a lab, so I&#39;m using a static IP)
</span></span><span class="line"><span class="cl">Cat8k-Site400(config)# interface GigabitEthernet1
</span></span><span class="line"><span class="cl">Cat8k-Site400(config-if)# ip address 192.168.99.237 255.255.255.0
</span></span><span class="line"><span class="cl">Cat8k-Site400(config-if)# no shut
</span></span><span class="line"><span class="cl"> ! Config tunnel interface
</span></span><span class="line"><span class="cl">Cat8k-Site400(config-if)# interface Tunnel1
</span></span><span class="line"><span class="cl">Cat8k-Site400(config-if)# no shut
</span></span><span class="line"><span class="cl">Cat8k-Site400(config-if)# ip unnumbered GigabitEthernet1
</span></span><span class="line"><span class="cl">Cat8k-Site400(config-if)# tunnel source GigabitEthernet1
</span></span><span class="line"><span class="cl">Cat8k-Site400(config-if)# tunnel mode sdwan
</span></span><span class="line"><span class="cl">Cat8k-Site400(config-if)# exit
</span></span><span class="line"><span class="cl"> ! SD-WAN tunnel config
</span></span><span class="line"><span class="cl">Cat8k-Site400(config)# sdwan
</span></span><span class="line"><span class="cl">Cat8k-Site400(config-sdwan)# interface GigabitEthernet1
</span></span><span class="line"><span class="cl">Cat8k-Site400(config-interface-GigabitEthernet1)# tunnel-interface
</span></span><span class="line"><span class="cl">Cat8k-Site400(config-tunnel-interface)# encapsulation ipsec
</span></span><span class="line"><span class="cl">Cat8k-Site400(config-tunnel-interface)# color biz-internet
</span></span><span class="line"><span class="cl">Cat8k-Site400(config-tunnel-interface)# exit
</span></span><span class="line"><span class="cl"> ! Default route to our internet gateway
</span></span><span class="line"><span class="cl">Cat8k-Site400(config)# ip route 0.0.0.0 0.0.0.0 192.168.99.1
</span></span><span class="line"><span class="cl">Cat8k-Site400(config)# commit
</span></span><span class="line"><span class="cl">Commit complete.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Cat8k-Site400#
</span></span></code></pre></div><h2 id="a-note-on-certificates">A Note on Certificates</h2>
<p>Since this is a lab environment, I&rsquo;m using self-signed local certificate authority to provision all of my certificate infrastructure. Because of this, I&rsquo;ll need to install my local CA certificate on the Catalyst 8000v. If you&rsquo;re using the default Cisco-provisioned certificate setup, you won&rsquo;t need to do this.</p>
<p>Since my SD-WAN lab doesn&rsquo;t have direct access to my local TFTP server - I do have an out-of-band management interface connected to my Cat 8000v. We&rsquo;ll start by configuring that interface:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Cat8k-Site400# config-transaction
</span></span><span class="line"><span class="cl">Cat8k-Site400(config)# vrf definition 512
</span></span><span class="line"><span class="cl">Cat8k-Site400(config-vrf)# address-family ipv4
</span></span><span class="line"><span class="cl">Cat8k-Site400(config-vrf)# exit
</span></span><span class="line"><span class="cl">Cat8k-Site400(config)# interface GigabitEthernet 3
</span></span><span class="line"><span class="cl">Cat8k-Site400(config-if)# vrf forwarding 512
</span></span><span class="line"><span class="cl">Cat8k-Site400(config-if)# ip address dhcp
</span></span><span class="line"><span class="cl">Cat8k-Site400(config-if)# exit
</span></span><span class="line"><span class="cl">Cat8k-Site400(config)# ip tftp source-interface GigabitEthernet 3
</span></span><span class="line"><span class="cl">Cat8k-Site400(config)# commit
</span></span></code></pre></div><p>The standard management VRF/VPN for SD-WAN is 512, so I kept that config to match when I configured this management interface. This will all be over-written anyways once we get connected to vManage &amp; configure/push our template configs.</p>
<p>Once that&rsquo;s done, we can go ahead and copy our CA certificate to bootflash.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Cat8k-Site400# copy tftp://10.0.0.2/cacert.pem bootflash:
</span></span><span class="line"><span class="cl">Destination filename [cacert.pem]?
</span></span><span class="line"><span class="cl">Accessing tftp://10.0.0.2/cacert.pem...
</span></span><span class="line"><span class="cl">Loading cacert.pem from 10.0.0.2 (via GigabitEthernet3): !
</span></span><span class="line"><span class="cl">[OK - 1406 bytes]
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">1406 bytes copied in 0.112 secs (12554 bytes/sec)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Cat8k-Site400# dir bootflash: | inc cacert.pem
</span></span><span class="line"><span class="cl">16      -rw-             1406  May 14 2021 14:41:27 +00:00  cacert.pem
</span></span><span class="line"><span class="cl">```text
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Then we&#39;ll use the command below to install the CA certificate:
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">```text
</span></span><span class="line"><span class="cl">Cat8k-Site400# request platform software sdwan root-cert-chain install bootflash:cacert.pem
</span></span><span class="line"><span class="cl">Uploading root-ca-cert-chain via VPN 0
</span></span><span class="line"><span class="cl">Copying ... /bootflash/cacert.pem via VPN 0
</span></span><span class="line"><span class="cl">Updating the root certificate chain..
</span></span><span class="line"><span class="cl">Successfully installed the root certificate chain
</span></span></code></pre></div><p>And we can validate by using the <em>show sdwan certificate root-ca-cert</em> command:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Cat8k-Site400 show sdwan certificate root-ca-cert
</span></span><span class="line"><span class="cl">Certificate:
</span></span><span class="line"><span class="cl">    Data:
</span></span><span class="line"><span class="cl">        Version: 3 (0x2)
</span></span><span class="line"><span class="cl">        Serial Number:
</span></span><span class="line"><span class="cl">            11:3b:0a:12:17:b0:e0:b5:4b:fa:c2:e9:2c:9c:12:84
</span></span><span class="line"><span class="cl">        Signature Algorithm: sha1WithRSAEncryption
</span></span><span class="line"><span class="cl">        Issuer: DC = local, DC = 0x2142, O = SDWAN-LAB, CN = 0x2142-0XWIN1-CA-2
</span></span><span class="line"><span class="cl">        Validity
</span></span><span class="line"><span class="cl">            Not Before: Nov 29 20:00:11 2018 GMT
</span></span><span class="line"><span class="cl">            Not After : Nov 29 20:10:11 2043 GMT
</span></span><span class="line"><span class="cl">        Subject: DC = local, DC = 0x2142, O = SDWAN-LAB, CN = 0x2142-0XWIN1-CA-2
</span></span><span class="line"><span class="cl">        Subject Public Key Info:
</span></span><span class="line"><span class="cl">            Public Key Algorithm: rsaEncryption
</span></span><span class="line"><span class="cl">                RSA Public-Key: (2048 bit)
</span></span><span class="line"><span class="cl">                Modulus:
</span></span><span class="line"><span class="cl">        &lt;-- Output omitted --&gt;
</span></span></code></pre></div><h2 id="activating-the-catalyst-8000v">Activating the Catalyst 8000v</h2>
<p>Almost there! Now that we&rsquo;ve finished our pre-config &amp; added our root CA certificate - we&rsquo;re ready to join the Catalyst 8000v to the SD-WAN fabric.</p>
<p>We&rsquo;ll start over in vManage - by going to <strong>Configuration &gt; Devices</strong>.</p>
<p>Then we&rsquo;ll find our target, unused Catalyst 8000v device. Click the ellipsis on the right side, then select <strong>Generate Bootstrap Configuration</strong></p>
<p><img alt="002&mdash;Generate-bootstap-config" loading="lazy" src="/content/images/2021/05/002---Generate-bootstap-config.png#center"></p>
<p>This will give us a prompt to select which configuration style to generate. We&rsquo;ll leave this on &ldquo;Cloud-init&rdquo;:</p>
<p><img alt="003&mdash;bootstrap" loading="lazy" src="/content/images/2021/05/003---bootstrap.PNG#center"></p>
<p>Once we hit okay - we&rsquo;ll be presented with the info we need. We won&rsquo;t necessarily need all of this information, but we&rsquo;ll want to take note of our <strong>uuid</strong> and <strong>otp</strong>:</p>
<p><img alt="004&mdash;otp" loading="lazy" src="/content/images/2021/05/004---otp.png#center"></p>
<p>We&rsquo;ll drag this info back over to our Catalyst 8000v, and we can now use it to activate the device &amp; join to our SD-WAN fabric.</p>
<p>For the command below, <strong>chassis-number</strong> will be our <strong>uuid</strong> value - and <strong>token</strong> will be our <strong>otp</strong>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Cat8k-Site400# request platform software sdwan vedge_cloud activate chassis-number C8K-178BXXXX-XXXX-XXXX-XXXX-XXXXXXXXBC24 token 421ecxxxxxxxxxxxxxxxxxxxxxbd53b5
</span></span></code></pre></div><h2 id="validation">Validation</h2>
<p>After a few moments, we&rsquo;ll see some log messages start to appear showing our control connections coming up. You might see these on the terminal if you&rsquo;re using the console port, or you can use <em>show log</em>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">*May 14 15:39:06.910: %Cisco-SDWAN-Cat8k-Site400-OMPD-3-ERRO-400002: R0/0: OMPD: vSmart peer 10.10.10.242 state changed to Init
</span></span><span class="line"><span class="cl">*May 14 15:39:07.980: %DMI-5-AUTH_PASSED: R0/0: dmiauthd: User &#39;vmanage-admin&#39; authenticated successfully from 10.10.10.240:48140 and was authorized for netconf over ssh. External groups:
</span></span><span class="line"><span class="cl">*May 14 15:39:08.798: %Cisco-SDWAN-Cat8k-Site400-OMPD-6-INFO-400002: R0/0: OMPD: vSmart peer 10.10.10.242 state changed to Handshake
</span></span><span class="line"><span class="cl">*May 14 15:39:08.804: %Cisco-SDWAN-Cat8k-Site400-OMPD-5-NTCE-400002: R0/0: OMPD: vSmart peer 10.10.10.242 state changed to Up
</span></span><span class="line"><span class="cl">*May 14 15:39:08.808: %Cisco-SDWAN-Cat8k-Site400-OMPD-6-INFO-400005: R0/0: OMPD: Number of vSmarts connected : 1
</span></span><span class="line"><span class="cl">*May 14 15:39:09.827: %Cisco-SDWAN-Cat8k-Site400-OMPD-3-ERRO-400002: R0/0: OMPD: vSmart peer 10.10.10.243 state changed to Init
</span></span><span class="line"><span class="cl">*May 14 15:39:10.584: %CRYPTO-6-ISAKMP_ON_OFF: ISAKMP is ON
</span></span><span class="line"><span class="cl">*May 14 15:39:11.756: %Cisco-SDWAN-Cat8k-Site400-OMPD-6-INFO-400002: R0/0: OMPD: vSmart peer 10.10.10.243 state changed to Handshake
</span></span><span class="line"><span class="cl">*May 14 15:39:11.762: %Cisco-SDWAN-Cat8k-Site400-OMPD-5-NTCE-400002: R0/0: OMPD: vSmart peer 10.10.10.243 state changed to Up
</span></span><span class="line"><span class="cl">*May 14 15:39:11.762: %Cisco-SDWAN-Cat8k-Site400-OMPD-6-INFO-400005: R0/0: OMPD: Number of vSmarts connected : 2
</span></span><span class="line"><span class="cl">*May 14 15:39:12.738: %Cisco-SDWAN-Cat8k-Site400-OMPD-6-INFO-400007: R0/0: OMPD: Using policy from peer 10.10.10.242
</span></span><span class="line"><span class="cl">*May 14 15:39:13.570: %Cisco-SDWAN-Cat8k-Site400-FTMD-6-INFO-1000020: R0/0: FTMD: SLA class added : class &#39;Default&#39; at index &#39;1&#39; loss = 25%, latency = 300ms, jitter = 100ms, app-probe-class = None
</span></span><span class="line"><span class="cl">*May 14 15:39:14.738: %Cisco-SDWAN-Cat8k-Site400-OMPD-6-INFO-400007: R0/0: OMPD: Using policy from peer 10.10.10.242
</span></span></code></pre></div><p>We can also see our control connections using the command <em>show sdwan control connections</em>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Cat8k-Site400# show sdwan control connections
</span></span><span class="line"><span class="cl">                                                                                       PEER                                          PEER                                          CONTROLLER
</span></span><span class="line"><span class="cl">PEER    PEER PEER            SITE       DOMAIN PEER                                    PRIV  PEER                                    PUB                                           GROUP
</span></span><span class="line"><span class="cl">TYPE    PROT SYSTEM IP       ID         ID     PRIVATE IP                              PORT  PUBLIC IP                               PORT  ORGANIZATION            LOCAL COLOR     PROXY STATE UPTIME      ID
</span></span><span class="line"><span class="cl">----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
</span></span><span class="line"><span class="cl">vsmart  dtls 10.10.10.242    100        1      192.168.99.242                          12446 192.168.99.242                          12446 SDWAN-LAB  biz-internet    No    up     0:00:00:51  0
</span></span><span class="line"><span class="cl">vsmart  dtls 10.10.10.243    100        1      192.168.99.243                          12446 192.168.99.243                          12446 SDWAN-LAB  biz-internet    No    up     0:00:00:49  0
</span></span><span class="line"><span class="cl">vmanage dtls 10.10.10.240    100        0      192.168.99.240                          12646 192.168.99.240                          12646 SDWAN-LAB  biz-internet    No    up     0:00:00:52  0
</span></span></code></pre></div><p>Of course, we can also check to see our device status in the vManage dashboard as well.</p>
<p>Over on the <strong>Monitor &gt; Network</strong> page, we can see that our new Catalyst 8000v is now online:</p>
<p><img alt="005&mdash;monitor-network" loading="lazy" src="/content/images/2021/05/005---monitor-network.PNG#center"></p>
<hr>
<h2 id="extra-how-do-i-check-the-routing-table-on-an-ios-xe-sd-wan-device">Extra: How do I check the routing table on an IOS-XE SD-WAN device?</h2>
<p>So - if you&rsquo;ve only used the vEdge software devices, you may be used to using the <strong>show ip route</strong> or <strong>show ip route vpn 10</strong> commands.</p>
<p>In the IOS-XE world, <em>most</em> SD-WAN commands are prefixed with the <strong>sdwan</strong> keyword. For example: <strong>show sdwan bfd sessions</strong> (where on vEdges, it would just be <strong>show bfd sessions</strong>)</p>
<p>This might lead you to believe that you can use <strong>show sdwan ip route</strong> or <strong>show sdwan ip route vrf 10</strong> - but these won&rsquo;t work! In fact, you&rsquo;ll get the following message:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Cat8k-Site400# show sdwan ip route
</span></span><span class="line"><span class="cl">% Error: This command is not supported
</span></span></code></pre></div><p>For the IOS-XE based devices, they actually just use the standard IOS-XE routing table and VRF constructs.</p>
<p>So on a vEdge, you would have VPN 0 as your transport VPN. On IOS-XE, this is just the default global routing table, shown with <strong>show ip route</strong>.</p>
<p>But what about our LAN-side service VPNs? In this case, our routes are being dumped into a VRF on the IOS-XE device.</p>
<p>So for example, I have VPN 10 in my lab which is used for LAN-side clients. We can use the <strong>show vrf</strong> command to see that this exists, and then <strong>show ip route vrf 10</strong> to see the routes from our other SD-WAN locations:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Cat8k-Site400# show vrf
</span></span><span class="line"><span class="cl">  Name                             Default RD            Protocols   Interfaces
</span></span><span class="line"><span class="cl">  10                               &lt;not set&gt;             ipv4        Gi2
</span></span><span class="line"><span class="cl">  512                              &lt;not set&gt;             ipv4        Gi3
</span></span><span class="line"><span class="cl">  65528                            &lt;not set&gt;             ipv4        Lo65528
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Cat8k-Site400# show ip route vrf 10
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Routing Table: 10
</span></span><span class="line"><span class="cl">Codes: L - local, C - connected, S - static, R - RIP, M - mobile, B - BGP
</span></span><span class="line"><span class="cl">       D - EIGRP, EX - EIGRP external, O - OSPF, IA - OSPF inter area
</span></span><span class="line"><span class="cl">       N1 - OSPF NSSA external type 1, N2 - OSPF NSSA external type 2
</span></span><span class="line"><span class="cl">       E1 - OSPF external type 1, E2 - OSPF external type 2, m - OMP
</span></span><span class="line"><span class="cl">       n - NAT, Ni - NAT inside, No - NAT outside, Nd - NAT DIA
</span></span><span class="line"><span class="cl">       i - IS-IS, su - IS-IS summary, L1 - IS-IS level-1, L2 - IS-IS level-2
</span></span><span class="line"><span class="cl">       ia - IS-IS inter area, * - candidate default, U - per-user static route
</span></span><span class="line"><span class="cl">       H - NHRP, G - NHRP registered, g - NHRP registration summary
</span></span><span class="line"><span class="cl">       o - ODR, P - periodic downloaded static route, l - LISP
</span></span><span class="line"><span class="cl">       a - application route
</span></span><span class="line"><span class="cl">       + - replicated route, % - next hop override, p - overrides from PfR
</span></span><span class="line"><span class="cl">       &amp; - replicated local route overrides by connected
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Gateway of last resort is not set
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      10.0.0.0/24 is subnetted, 2 subnets
</span></span><span class="line"><span class="cl">m        10.2.2.0 [251/0] via 10.10.10.235, 00:09:02, Sdwan-system-intf
</span></span><span class="line"><span class="cl">m        10.3.3.0 [251/0] via 10.10.10.236, 00:09:02, Sdwan-system-intf
</span></span></code></pre></div><hr>
<p>Okay, that&rsquo;s it! Pretty quick process overall - and now we can get into applying our device/feature templates.</p>
<p>Hope this was helpful!!</p>
]]></content:encoded>
    </item>
    <item>
      <title>[How To] Connect Cisco SD-WAN to Umbrella SIG/SWG</title>
      <link>https://0x2142.com/cisco-sdwan-and-umbrella-sig-integration/</link>
      <pubDate>Thu, 22 Apr 2021 15:17:50 +0000</pubDate>
      <guid>https://0x2142.com/cisco-sdwan-and-umbrella-sig-integration/</guid>
      <description>A tutorial for configuring Viptela SDWAN with Cisco Umbrella Secure Internet Gateway &amp;amp; Secure Web Gateway</description>
      <content:encoded><![CDATA[<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
      <iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="allowfullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/kJwtIVp0-R4?autoplay=0&amp;controls=1&amp;end=0&amp;loop=0&amp;mute=0&amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"></iframe>
    </div>

<p>In this post, we&rsquo;ll walk through configuring a Cisco Viptela SD-WAN network to integrate with Cisco Umbrella&rsquo;s Secure Internet Gateway (SIG) &amp; Secure Web Gateway (SWG).</p>
<p>If you&rsquo;re interested in reading more about what SIG &amp; SWG are, please check out my <a href="/meraki-mx-and-umbrella-sig-integration/">last post</a> where I walked through this integration with a Meraki MX firewall.</p>
<p>For additional reading, there&rsquo;s also a good Umbrella blog post on all the components of Cisco&rsquo;s SASE architecture, which you can find <a href="https://umbrella.cisco.com/blog/what-goes-into-the-secure-access-service-edge-sase-solution">here</a>.</p>
<p>Okay, with that being said - let&rsquo;s get started!</p>
<hr>
<h2 id="step-1-umbrella-api-keys">Step 1: Umbrella API Keys</h2>
<p>Okay, so we&rsquo;ll start on the Umbrella side. We&rsquo;ll need to generate a set of API keys, which we&rsquo;ll push out to our WAN edge devices. These API keys will allow our remote devices to reach out to Umbrella &amp; auto-configure their SIG tunnels.</p>
<p>We&rsquo;ll log into our Umbrella dashboard at <a href="https://login.umbrella.com/">https://login.umbrella.com/</a></p>
<p>Once we log in, we&rsquo;ll hop over to <strong>Admin &gt; API Keys</strong>. Then up in the upper-right corner, click <strong>Create</strong>.</p>
<p><img alt="001&mdash;umbrella-api-keys-1" loading="lazy" src="/content/images/2021/04/001---umbrella-api-keys-1.png#center"></p>
<p>For this integration, we&rsquo;ll need to select <strong>Umbrella Management</strong> to make sure our API keys have the access they need. Then click <strong>Create.</strong> Easy enough, right?</p>
<p>Once we do that, the Umbrella dashboard will display our API keys - which we&rsquo;ll need to copy over to our Viptela SD-WAN environment.</p>
<p><img alt="002&mdash;umbrella-keys" loading="lazy" src="/content/images/2021/04/002---umbrella-keys.png#center"></p>
<p>We&rsquo;ll also need to collect our Umbrella Organization ID. This is actually just embedded within the Umbrella Dashboard URL, and should be a seven-digit number. For example, if we look at our current URL on the API keys page:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">https://dashboard.umbrella.com/o/&lt;ORG ID&gt;/#/admin/apikeys
</span></span></code></pre></div><p>And that&rsquo;s all we need for now from the Umbrella side. So let&rsquo;s hop over to Viptela.</p>
<h2 id="step-2-viptela-templates--config">Step 2: Viptela Templates &amp; Config</h2>
<p>For this post, I&rsquo;ll be using my SD-WAN lab in EVE-NG. Currently I just upgraded the lab to run Viptela version 20.4.1, though the SIG integration has been supported since 20.1.</p>
<p>Just for reference, here is the lap topology that I&rsquo;m working with:</p>
<p><img alt="003&mdash;eve-topology-1" loading="lazy" src="/content/images/2021/04/003---eve-topology-1.png#center"></p>
<p>This lab includes a bridged connection to allow direct internet access from the lab network.</p>
<p>To configure our SIG automatic tunnels, we&rsquo;ll need to create / update a few templates:</p>
<ul>
<li>Create a <strong>SIG Credentials</strong> feature template</li>
<li>Create a <strong>SIG</strong> feature template</li>
<li>Assign SIG templates to device templates</li>
<li>Edit Service-side VPN Template to inject a service route</li>
</ul>
<h3 id="2a-creating-a-sig-credentials-template">2a: Creating a SIG Credentials Template</h3>
<p>First we&rsquo;ll create a template which will store our Umbrella API credentials.</p>
<p>In the vManage dashboard, we&rsquo;ll go to <strong>Configuration &gt; Templates</strong>, then drop into the <strong>Feature</strong> tab, and click on <strong>Add Template</strong>.</p>
<p><img alt="004&mdash;add-template" loading="lazy" src="/content/images/2021/04/004---add-template.png#center"></p>
<p>Once we get to the next screen, we&rsquo;ll select our device type. In my case, I&rsquo;m using a <strong>vEdge Cloud</strong>.</p>
<p>A list of templates will pop up - we&rsquo;ll drop down to <strong>SIG Credentials</strong>, which will be near the bottom under the <strong>Other Templates</strong> header.</p>
<p><img alt="005&mdash;SIGCREDTEMPLATE" loading="lazy" src="/content/images/2021/04/005---SIGCREDTEMPLATE.png#center"></p>
<p>We&rsquo;ll then be taken to the page where we create our template.</p>
<p>We&rsquo;ll fill in our template name &amp; description, then paste in our Umbrella details (Org ID, API Key, API Secret).</p>
<p><img alt="006&mdash;SIG-Cred-template-page" loading="lazy" src="/content/images/2021/04/006---SIG-Cred-template-page.png#center"></p>
<p>Once we&rsquo;re done - We&rsquo;ll hit <strong>Save</strong>.</p>
<blockquote>
<p>Note: At time of writing, the &ldquo;Get Keys&rdquo; button only functions if you&rsquo;ve purchased your SD-WAN subscription with DNA Premier licensing. This license level includes Umbrella SIG, and allows this 1-click integration that pulls your Umbrella API keys automatically.</p></blockquote>
<h3 id="2b-creating-a-sig-tunnel-template">2b: Creating a SIG Tunnel Template</h3>
<p>Okay, next we&rsquo;ll need to create another feature template to specify our IPSec tunnel configuration.</p>
<p>Just like before, we&rsquo;ll head back over to <strong>Configuration &gt; Templates &gt; Feature &gt; Add Template</strong>.</p>
<p>This time, after selecting our device type, we&rsquo;ll choose <strong>Secure Internet Gateway (SIG) / WAN</strong> - which is located under the <strong>VPN</strong> header.</p>
<p><img alt="007&mdash;SIGWANTEMPLATE" loading="lazy" src="/content/images/2021/04/007---SIGWANTEMPLATE.png#center"></p>
<p>In the template configuration, we&rsquo;ll give the template a name &amp; description as always. Then we&rsquo;ll jump down to the tunnel config.</p>
<p>We&rsquo;ll select <strong>Umbrella</strong> for SIG Provider, then click <strong>Add Tunnel</strong>.</p>
<p><img alt="008&mdash;sig-tunnel-02" loading="lazy" src="/content/images/2021/04/008---sig-tunnel-02.png#center"></p>
<p>Within the tunnel config, we&rsquo;ll specify an interface name - I&rsquo;ll name mine <em>ipsec1</em> (and I&rsquo;ll create an <em>ipsec2</em> shortly). We&rsquo;ll also specify a <em>Tunnel Source</em>, which in my lab is <strong>ge0/0</strong> for the biz-internet VPN 0 interface.</p>
<p><img alt="008&mdash;sig-tunnel-03" loading="lazy" src="/content/images/2021/04/008---sig-tunnel-03.png#center"></p>
<p>We&rsquo;ll keep <strong>Data-Center</strong> as <strong>Primary</strong>, then click <strong>Add</strong>. Then - we&rsquo;ll add a second tunnel configuration, but using <strong>Data-Center</strong> as <strong>Secondary</strong> and the interface name as <em>ipsec2</em>.</p>
<p>When all that is done, we should have the following:</p>
<p><img alt="008&mdash;sig-tunnel-04" loading="lazy" src="/content/images/2021/04/008---sig-tunnel-04.png#center"></p>
<p>If we scroll down to the bottom of the template config, we&rsquo;ll have some settings for <strong>High Availability</strong>. Here, we&rsquo;ll specify what our active &amp; backup IPSec tunnels are, and their weights. I&rsquo;ll specify <em>ipsec1</em> as active &amp; <em>ipsec2</em> as backup. Then click <strong>Save</strong> to finish our template.</p>
<blockquote>
<p>Note: Weight settings are only available starting with 20.4.1 &amp; allow for ECMP routing to SIG. Not shown above, you can create up to four HA tunnel pairs. Depending on weighting, you can equal-cost or unequal-cost load balance between those pairs.</p>
<p>Why would you want to load balance across multiple tunnels? At time of writing, each IPSec tunnel is limited to a maximum 250Mb/s throughput. By creating multiple tunnels &amp; load balancing, we can overcome this limitation if we need higher bandwidth.</p></blockquote>
<h3 id="2c-attaching-sig-to-device-templates">2c: Attaching SIG to Device Templates</h3>
<p>After we&rsquo;ve built out our two SIG templates, we can now attach them to our device templates.</p>
<p>For me, I currently only have a single device template which is applied to all of my remote WAN edge devices.</p>
<p>So we&rsquo;ll go back to <strong>Configuration &gt; Templates</strong> and find whichever device template we want to use - then click the ellipsis on the far right, end select <strong>Edit</strong>.</p>
<p><img alt="009&mdash;edit-device-template" loading="lazy" src="/content/images/2021/04/009---edit-device-template.png#center"></p>
<p>In the device template, we&rsquo;ll scroll down and look for our <strong>VPN 0</strong> configuration under <strong>Transport &amp; Management VPN</strong>. We&rsquo;ll attach our SIG tunnel template to VPN 0, since that&rsquo;s where those IPSec tunnels are being sourced from.</p>
<p>On the right side, under <strong>Additional VPN 0 Templates</strong>, we&rsquo;ll click <strong>Secure Internet Gateway</strong> to add our template. Then from the drop-down, we can select the feature template we just created:</p>
<p><img alt="010&mdash;device-template-vpn0" loading="lazy" src="/content/images/2021/04/010---device-template-vpn0.png#center"></p>
<p>We&rsquo;ll also include our SIG credentials template, which we can find at the bottom of the page, under <strong>Additional Templates</strong>:</p>
<p><img alt="011&mdash;sig-cred-template-attach-1" loading="lazy" src="/content/images/2021/04/011---sig-cred-template-attach-1.png#center"></p>
<p>Once we&rsquo;re done, we can click <strong>Save</strong> at the bottom. This will take us through the process of pushing out these changes to our remote WAN edge devices. When this configuration is deployed, each vEdge will now reach out to Umbrella &amp; auto-configure an IPSec tunnel.</p>
<blockquote>
<p>Note: While the IPSec tunnels will be established when this configuration is pushed - no traffic will flow over them yet. We&rsquo;ll need to add a service route for that, which we&rsquo;ll do next!</p></blockquote>
<h3 id="2d-injecting-a-service-route">2d: Injecting a Service Route</h3>
<p>Now we have our IPSec tunnels deployed - all we need to do is start routing traffic out to Umbrella. We&rsquo;ll accomplish this using a service route on our LAN-side VPN.</p>
<p>So we&rsquo;ll go over to <strong>Configuration &gt; Templates &gt; Feature</strong> - and we&rsquo;ll scroll down &amp; find whichever template we&rsquo;re currently using on our LAN side. For me, I want VPN 10 to route over the tunnels, so I&rsquo;ll be editing my VPN 10 template.</p>
<p>Within the template, we&rsquo;ll scroll down to the <strong>Service Route</strong> section, click <strong>New Service Route</strong>, and we&rsquo;ll enter our desired prefix. This will be what traffic will be routed over the IPSec tunnel to Umbrella. Since this is intended to be an internet gateway, I&rsquo;ll enter 0.0.0.0/0 to inject a default route to Umbrella.</p>
<p>Service should be pre-selected as <strong>SIG</strong>, so we&rsquo;ll click <strong>Add</strong>, then <strong>Update</strong> &amp; deploy our changes to the remote edge devices.</p>
<p><img alt="012&mdash;service-route" loading="lazy" src="/content/images/2021/04/012---service-route.png#center"></p>
<h2 id="step-3-validation--troubleshooting">Step 3: Validation &amp; Troubleshooting</h2>
<p>Awesome! Now we should have everything configured &amp; working. So let&rsquo;s jump through some initial testing and validation we can do.</p>
<p>Within vManage, we can check the status of our IPSec tunnels. We&rsquo;ll go over to <strong>Monitor &gt; Network</strong> then select one of our WAN edge devices.</p>
<p>We&rsquo;ll click on the <strong>Interfaces</strong> tab on the left side - and we should be able to see a list of all interfaces on our device. This should include an ipsec1 &amp; ipsec2 interface.</p>
<p>I&rsquo;ve also selected the <strong>Real Time</strong> monitor on mine, and filtered to just show traffic on the ipsec1 interface:</p>
<p><img alt="013&mdash;monitor" loading="lazy" src="/content/images/2021/04/013---monitor.png#center"></p>
<p>You might recall from my topology above, that I have a linux VM running behind each of the two vEdge Cloud appliances. Using these, I can also test web access &amp; see what my external IP is:</p>
<p><img alt="014&mdash;linuxVM" loading="lazy" src="/content/images/2021/04/014---linuxVM.png#center"></p>
<p>And sure enough, I am getting a 146.112.x.x address - which belongs to the Umbrella datacenter.</p>
<p>If we log into one of our vEdge devices, we can check the routing table with <strong>show ip route vpn 10</strong> (or whichever VPN you&rsquo;re using for the LAN-side). We should see our default 0.0.0.0/0 route via ipsec1, with a next-hop-VPN of VPN0:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">vEdge-01# show ip route vpn 10
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">     ADDRESS               PATH             PROTOCOL          NEXTHOP  NEXTHOP                         NEXTHOP
</span></span><span class="line"><span class="cl">VPN  FAMILY   PREFIX       ID    PROTOCOL   SUB TYPE  METRIC  IFNAME   ADDR     TLOC IP  COLOR  ENCAP  VPN      STATUS
</span></span><span class="line"><span class="cl">------------------------------------------------------------------------------------------------------------------------
</span></span><span class="line"><span class="cl">10   ipv4     0.0.0.0/0    0     std-ipsec  -         0       ipsec1   -        -        -      -      0        F,S
</span></span><span class="line"><span class="cl">10   ipv4     10.2.2.0/24  0     connected  -         0       ge0/2    -        -        -      -      -        F,S
</span></span></code></pre></div><p>We can also check specifically our SIG tunnel status using the command <strong>show secure-internet-gateway tunnels</strong>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">vEdge-01# show secure-internet-gateway tunnels
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">TUNNEL                                                        API   LAST
</span></span><span class="line"><span class="cl">IF                                                            HTTP  SUCCESSFUL     TUNNEL
</span></span><span class="line"><span class="cl">NAME    TUNNEL ID  TUNNEL NAME                     FSM STATE  CODE  REQ            STATE
</span></span><span class="line"><span class="cl">-------------------------------------------------------------------------------------------
</span></span><span class="line"><span class="cl">ipsec1  530233543  SITE200SYS10x10x10x235IFipsec1  st-tun-up  200   create-tunnel  -
</span></span><span class="line"><span class="cl">ipsec2  530233542  SITE200SYS10x10x10x235IFipsec2  st-tun-up  200   create-tunnel  -
</span></span></code></pre></div><p>In that output above, we&rsquo;ll see that we have both ipsec1 &amp; ipsec2 tunnels shown. The last API queries to Umbrella have a HTTP 200, which is good. We&rsquo;ll also see our tunnel names, which we can use to find our device tunnel configuration in the Umbrella dashboard.</p>
<p>The tunnel name might look like a mess at first, but it&rsquo;s a unique identifier to represent each tunnel that was created. So if we break it down for this vEdge:</p>
<ul>
<li>This vEdge is at Site ID 200
<ul>
<li>Shown as &ldquo;SITE200&rdquo;</li>
</ul>
</li>
<li>This vEdge has a system IP of 10.10.10.235
<ul>
<li>Shown as &ldquo;SYS10x10x10x235&rdquo;</li>
</ul>
</li>
<li>This vEdge has two IPSec interfaces, ipsec1 &amp; ipsec2
<ul>
<li>Shown as &ldquo;IFipec1&rdquo; and &ldquo;IFipsec2&rdquo;</li>
</ul>
</li>
</ul>
<p>If we jump over to the Umbrella dashboard, we&rsquo;ll see the same. Within the Umbrella dashboard, we can jump to <strong>Deployments &gt; Network Tunnels</strong>.</p>
<p>On this page, we should see a total of four tunnels listed (two from each vEdge appliance):</p>
<p><img alt="015&mdash;Umbrella-tunnel-status" loading="lazy" src="/content/images/2021/04/015---Umbrella-tunnel-status.png#center"></p>
<p>And with everything configured &amp; validated - now we can move onto configuring firewall and web filtering policies within Umbrella!</p>
<p>If you&rsquo;re interested in seeing how to configure Umbrella&rsquo;s cloud firewall &amp; web filtering policies - please check out my <a href="https://www.youtube.com/watch?v=kJwtIVp0-R4">YouTube Video</a> above!</p>
]]></content:encoded>
    </item>
    <item>
      <title>[How To] Connect Meraki MX to Umbrella SIG/SWG</title>
      <link>https://0x2142.com/meraki-mx-and-umbrella-sig-integration/</link>
      <pubDate>Tue, 23 Mar 2021 16:00:00 +0000</pubDate>
      <guid>https://0x2142.com/meraki-mx-and-umbrella-sig-integration/</guid>
      <description>A tutorial for configuring a Meraki MX with Cisco Umbrella Secure Internet Gateway &amp;amp; Secure Web Gateway</description>
      <content:encoded><![CDATA[<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
      <iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="allowfullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/GfVEQzxT10g?autoplay=0&amp;controls=1&amp;end=0&amp;loop=0&amp;mute=0&amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"></iframe>
    </div>

<p>In today&rsquo;s blog post - we&rsquo;ll be checking out how to integrate a Meraki MX firewall to Cisco&rsquo;s Umbrella Secure Internet Gateway (SIG) &amp; Secure Web Gateway (SWG) services.</p>
<p>Interested in seeing how to do this with Cisco Viptela SD-WAN? Check out <a href="/cisco-sdwan-and-umbrella-sig-integration/">this post</a></p>
<blockquote>
<p>Note: This integration is still rather new - so I anticipate some of the screenshots &amp; steps below may differ as this post ages.</p></blockquote>
<hr>
<h2 id="what-are-sig--swg">What are SIG &amp; SWG?</h2>
<p>Good question! A lot of us are probably familiar with Cisco Umbrella (formerly OpenDNS) for the DNS-layer security products. Using Cisco Umbrella, we can configure our end PCs or DNS forwarders to use the Cisco DNS servers. Then, we apply security policies to allow/deny DNS queries based on our policy.</p>
<p>Now applying security policy at the DNS level is great! Typical web filtering only inspects HTTP/HTTPS traffic, but inspecting DNS traffic allows us to stop threats that might not use those typical ports. While there may be some applications or malware that use hard-coded IP addresses, a good majority use a domain name that requires a DNS lookup.</p>
<p>But what if we wanted to still do web filtering too? Or maybe we want a centralized, cloud-hosted firewall service? That&rsquo;s where Umbrella SIG &amp; SWG come in.</p>
<p>Secure Web Gateway (SWG) is pretty much exactly what it sounds like. It&rsquo;s a cloud-hosted web filter or web proxy, where we can set URL-based policys to permit or deny access. It supports the usual allow-lists, deny-lists, HTTPS inspection, file inspection, and policies based on user/group identities.</p>
<p>Secure Internet Gateway (SIG) is a large, cloud-hosted firewall service. What we can do with SIG is tunnel all of our traffic to one centrallized location to apply firewall policies (permit/deny/etc).</p>
<p>Why would we want either of these functions to be cloud-hosted? Well we might not have the resources at every remote site to perform firewalling &amp; web filtering - or we don&rsquo;t want to invest in beefy hardware in our corporate datacenter, and backhaul all of our remote traffic back for inspection. The cloud-hosted piece also means a central management point, so only one place to make change for all of our remote sites - rather than having to touch dozens or hundreds of remote devices&hellip;..Did someone say SASE? 🙃</p>
<p>With all that said - Let&rsquo;s get into making this work!</p>
<blockquote>
<p>Note: There are many ways to use Umbrella SIG/SWG (IPSec tunnel, PAC file, Anyconnect, etc). This particular post will only cover IPSec via Meraki MX.</p></blockquote>
<h2 id="step-1-getting-our-keys">Step 1: Getting our Keys</h2>
<p>First thing we&rsquo;ll need to do is on the Umbrella side. We&rsquo;ll need to generate tunnel keys for our Meraki MX to use for IPSec negotiation.</p>
<p>We&rsquo;ll log into our Umbrella dashboard at <a href="https://login.umbrella.com/">https://login.umbrella.com/</a></p>
<p>Once we&rsquo;re in, we&rsquo;ll navigate to <strong>Deployments</strong> &gt; <strong>Core Identities</strong> &gt; <strong>Network Tunnels</strong>. Shown below, we currently have no tunnels configured:</p>
<p><img alt="001&mdash;umbrella-keys-1" loading="lazy" src="/content/images/2021/03/001---umbrella-keys-1.PNG#center"></p>
<p>In the upper right corner, let&rsquo;s click the <strong>Add Tunnel</strong> button.</p>
<p>We&rsquo;ll now see the following screen to begin creating our IPSec tunnel:</p>
<p><img alt="002&mdash;Umbrella-tunnel-create-1" loading="lazy" src="/content/images/2021/03/002---Umbrella-tunnel-create-1.png#center"></p>
<p>Here, we&rsquo;ll need to specify a name for our tunnel &amp; which device type. The name can be anything we choose that helps us identify what locations are using this tunnel. I&rsquo;ve specified <em>MX64</em> as my tunnel name, since I only have one MX that I&rsquo;ll be testing this with. We also have <strong>Meraki MX</strong> as an option in the <em>Device Type</em> drop down - so we&rsquo;ll select that as well. Then, we&rsquo;ll click <strong>Next</strong>.</p>
<p>Then we&rsquo;ll need to configure our <strong>Tunnel ID</strong> and <strong>Passphrase</strong>:</p>
<p><img alt="003&mdash;Umbrella-tunnel-create-2" loading="lazy" src="/content/images/2021/03/003---Umbrella-tunnel-create-2.png#center"></p>
<p>The <strong>Tunnel ID</strong> we&rsquo;ll be sending later, as part of our IPSec local ID. The passphrase will be used as our pre-shared key for the tunnel config. Once we&rsquo;re done with that, click <strong>Save</strong>.</p>
<p>As long as our ID &amp; passphrase are all good, we&rsquo;ll be presented with a box to easily copy these parameters into the Meraki config:</p>
<p><img alt="004&mdash;Umbrella-tunnel-create-3" loading="lazy" src="/content/images/2021/03/004---Umbrella-tunnel-create-3.png#center"></p>
<p>Finally, we&rsquo;ll be dropped back to our <em>Network Tunnels</em> page - where we can see that our tunnel is configured, but not yet established. Let&rsquo;s fix that &amp; hop over to the Meraki dashboard!</p>
<p><img alt="005&mdash;Umbrella-tunnel-create-4" loading="lazy" src="/content/images/2021/03/005---Umbrella-tunnel-create-4.png#center"></p>
<h2 id="step-2-meraki-mx-ipsec-configuration">Step 2: Meraki MX IPSec Configuration</h2>
<p>Okay, now onto the fun stuff.</p>
<p>We&rsquo;ll log into our Meraki Dashboard at <a href="https://account.meraki.com/secure/login/dashboard_login">https://account.meraki.com/secure/login/dashboard_login</a></p>
<p>Once we&rsquo;re in, you&rsquo;ll need to select the network with the MX you want to connect. For me, I currently only have a single network, which contains my MX firewall.</p>
<p>Then we&rsquo;ll navigate to <strong>Security &amp; SD-WAN</strong> &gt; <strong>Configure</strong> &gt; <strong>Site-to-site VPN</strong>.</p>
<p><img alt="006&mdash;Meraki-MX-VPN-1" loading="lazy" src="/content/images/2021/03/006---Meraki-MX-VPN-1.png#center"></p>
<p>Assuming we have no other VPNs configured, you&rsquo;ll have to change the VPN <strong>Type</strong> to <strong>Hub (Mesh)</strong> or <strong>Spoke</strong>. In my case, Umbrella SIG will be the only VPN I&rsquo;ll have configured - so I&rsquo;ll go ahead and use <strong>Hub (Mesh)</strong>. Don&rsquo;t mind the error regarding exit hubs, as we&rsquo;ll be configuring a non-Meraki peer below.</p>
<p><img alt="007&mdash;Meraki-MX-VPN-2" loading="lazy" src="/content/images/2021/03/007---Meraki-MX-VPN-2.PNG#center"></p>
<p>Okay, scrolling down the page just a bit - we&rsquo;ll need to specify which VLANs/internal subnets will be routed across the VPN &amp; pushed through Umbrella for SIG/SWG:</p>
<p><img alt="008&mdash;Meraki-MX-VPN-3-1" loading="lazy" src="/content/images/2021/03/008---Meraki-MX-VPN-3-1.PNG#center"></p>
<p>For testing purposes, I have a VM in a subnet labeled <em>DMZ</em> that I&rsquo;ll be using - So that will be the only VLAN that I&rsquo;ll set to <strong>VPN On</strong>.</p>
<p>Next we&rsquo;ll take a look at configuring <strong>Non-Meraki VPN Peers</strong>.</p>
<p>As shown in the screenshot below, we&rsquo;ll need to configure the following settings:</p>
<ul>
<li>Name - This is locally significant, I set mine to <em>Umbrella_SIG</em></li>
<li>IKE Version - Set this to IKEv2</li>
<li>IPSec Policies - Custom - See below</li>
<li>Public IP - This is the peer Umbrella Datacenter
<ul>
<li>Choose the DC closest to you <a href="https://docs.umbrella.com/umbrella-user-guide/docs/cisco-umbrella-data-centers">here</a></li>
<li>For this post, I&rsquo;m using the New York DC</li>
</ul>
</li>
<li>Local ID - Set this to the Tunnel ID we got from Umbrella</li>
<li>Remote ID - Leave blank</li>
<li>Private Subnets - This is what destination IPs will be routed over the tunnel
<ul>
<li>Since this is intended as an <em>Internet</em> gateway, we&rsquo;ll use 0.0.0.0/0</li>
</ul>
</li>
<li>Preshared Secret - Set this to the passphrase we configured in Umbrella</li>
<li>Availability - Set this to which networks this tunnel should apply
<ul>
<li>Since I only have 1 network &amp; 1 MX, I set this to <em>All Networks</em></li>
</ul>
</li>
</ul>
<p><img alt="009&mdash;Meraki-MX-VPN-4" loading="lazy" src="/content/images/2021/03/009---Meraki-MX-VPN-4.png#center"></p>
<p>Okay - I mentioned above we&rsquo;ll need to set some custom IPSec parameters. Here&rsquo;s what we&rsquo;ll configure as a custom policy:</p>
<p><img alt="010&mdash;Meraki-MX-VPN-5" loading="lazy" src="/content/images/2021/03/010---Meraki-MX-VPN-5.PNG#center"></p>
<blockquote>
<p>Note: Turns out in the drop down menu, there is also an option for &ldquo;Umbrella&rdquo;, so you don&rsquo;t have to create a custom policy. That being said, the Umbrella preset uses DH group 5, but Umbrella&rsquo;s docs ask for DH group 14.</p></blockquote>
<p>Lastly, we&rsquo;ll be able to configure whether or not we want firewall logging (I enabled this) and also whether we want to add access-lists to permit/deny any traffic over the VPN. For now I&rsquo;ll be leaving this as permit any.</p>
<p><img alt="011&mdash;Meraki-MX-6" loading="lazy" src="/content/images/2021/03/011---Meraki-MX-6.PNG#center"></p>
<p>Finally - we can click <strong>Save</strong> to push our configuration to the MX appliance!</p>
<h2 id="step-3-validation--testing">Step 3: Validation &amp; Testing</h2>
<p>Hopefully once we get all that configuration done, we&rsquo;ll be able to see our tunnel come up.</p>
<p>We can validate from both sides, but let&rsquo;s start with Meraki. In the Dashboard menu, we&rsquo;ll navigate to <strong>Security &amp; SD-WAN</strong> &gt; <strong>Monitor</strong> &gt; <strong>VPN Status</strong>.</p>
<p><img alt="012&mdash;Meraki-MX-VPN-7" loading="lazy" src="/content/images/2021/03/012---Meraki-MX-VPN-7.png#center"></p>
<p>Then we&rsquo;ll need to click the tab for <strong>Non-Meraki peer</strong>:</p>
<p>With any luck, we should see the little green circle showing that our tunnel is online.</p>
<p><img alt="016&mdash;MX-VPN-Status" loading="lazy" src="/content/images/2021/03/016---MX-VPN-Status.PNG#center"></p>
<blockquote>
<p>If your tunnel doesn&rsquo;t come up immediately, you may have to generate some traffic from your VPN subnet to the internet. This will force the MX to try and connect to Umbrella.</p>
<p>It&rsquo;s also worth noting - sometimes it may take the Meraki dashboard to show a successful connection. A better indicator is by checking the Umbrella dashboard, or checking manually with a device you are expecting to route over the VPN.</p></blockquote>
<p>If for any reason we have trouble, we can also check our VPN negotiation logs by going to <strong>Network-Wide</strong> &gt; <strong>Monitor</strong> &gt; <strong>Event Log</strong>.</p>
<p><img alt="014&mdash;Meraki-MX-VPN-9" loading="lazy" src="/content/images/2021/03/014---Meraki-MX-VPN-9.png#center"></p>
<p>On this screen, make sure you&rsquo;ve selected <strong>for security appliances</strong> at the top. If needed, we can also filter events by <strong>All Non-Meraki VPN / Client VPN</strong>.</p>
<p><img alt="015&mdash;Meraki-MX-VPN-10" loading="lazy" src="/content/images/2021/03/015---Meraki-MX-VPN-10.png#center"></p>
<p>Since my tunnel came up with no issues, the output above shows a successful tunnel negotiation.</p>
<p>Let&rsquo;s jump over to the Umbrella side, and see what the Umbrella dashboard shows.</p>
<p>Back on the <strong>Network Tunnels</strong> page - we should see that our tunnel now shows as <strong>Active</strong>.</p>
<p><img alt="013&mdash;Meraki-MX-VPN-8" loading="lazy" src="/content/images/2021/03/013---Meraki-MX-VPN-8.png#center"></p>
<p>This screen will also so the public IP that our MX is using to connect, as well as which Umbrella datacenter we&rsquo;ve connected to.</p>
<hr>
<p>Okay! That&rsquo;s it for now. To try and keep this blog post from getting too long, I&rsquo;ve decided to split this into two parts.</p>
<p>If you&rsquo;re interested in seeing how to configure Umbrella&rsquo;s cloud firewall &amp; web filtering policies - please check out my <a href="https://www.youtube.com/watch?v=GfVEQzxT10g">YouTube Video</a> above!</p>
]]></content:encoded>
    </item>
    <item>
      <title>Getting Started with IOS-XE Guestshell</title>
      <link>https://0x2142.com/getting-started-with-ios-xe-guestshell/</link>
      <pubDate>Tue, 26 Jan 2021 16:15:41 +0000</pubDate>
      <guid>https://0x2142.com/getting-started-with-ios-xe-guestshell/</guid>
      <description>In this post, we&amp;rsquo;ll explore how to set up Cisco IOX &amp;amp; Guestshell for on-box Python</description>
      <content:encoded><![CDATA[<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
      <iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="allowfullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/KiVbDq0Czdg?autoplay=0&amp;controls=1&amp;end=0&amp;loop=0&amp;mute=0&amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"></iframe>
    </div>

<p>This post has been on my backlog for a while&hellip; I&rsquo;ve been intermittently trying out the IOS-XE guestshell feature for a few different projects, and never feeling like any of them were good enough to write about.</p>
<p>So why not just write about guestshell itself? It&rsquo;s such a nifty tool.</p>
<hr>
<h2 id="what-is-guestshell">What is Guestshell?</h2>
<p>Now that Cisco&rsquo;s Catalyst platform has standardized on IOS-XE, we can take advantage of some of the features of the Linux-based platform. One of which being Linux Containers (LXC).</p>
<p>Most of the latest Catalyst routers, switches, and access points support what Cisco calls Application Hosting - which is a fancy way of just saying it can run containers on-box. Another acronym to be aware of is IOx - which is what Cisco calls their IOS-XE/Linux appliction framework.</p>
<p>Guestshell is a specific feature within IOS-XE, where a dedicated pre-built container is enabled for on-box access to a Linux shell.</p>
<h2 id="what-hardware-supports-guestshell">What Hardware Supports Guestshell?</h2>
<p>Okay - so for this example, I&rsquo;ll be using the new Catalyst 8000V platform (a virtual Catalyst router). I do also have a Catalyst 9200L on hand, but unfortunately it&rsquo;s one of the few Catalyst platforms that <em>does not</em> support Guestshell (due to lower-end HW specs).</p>
<p>You can also use the Catalyst 8000V to test this in a lab, or you could use most of the Catalyst 8000 / 9000 series platforms if you had them available (or the CSRv &amp; some ISR routers!).</p>
<p>You can find a list of supported platforms &amp; other hardware requirements <a href="https://www.cisco.com/c/en/us/td/docs/ios-xml/ios/prog/configuration/166/b_166_programmability_cg/guest_shell.html#id_45838">here</a>.</p>
<p>All that being said - let&rsquo;s get started!</p>
<h2 id="enabling-iox">Enabling IOx</h2>
<p>So before we can actually use the guestshell feature, there is some pre-configuration to be done.</p>
<p>First we&rsquo;ll need to ensure that the IOx application framework is enabled &amp; running. We can check this by using the <strong>show iox</strong> command:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">0x8KV01# show iox
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">IOx Infrastructure Summary:
</span></span><span class="line"><span class="cl">---------------------------
</span></span><span class="line"><span class="cl">IOx service (CAF)              : Not Running
</span></span><span class="line"><span class="cl">IOx service (HA)               : Not Supported
</span></span><span class="line"><span class="cl">IOx service (IOxman)           : Not Running
</span></span><span class="line"><span class="cl">IOx service (Sec storage)      : Not Supported
</span></span><span class="line"><span class="cl">Libvirtd 5.5.0                 : Running
</span></span></code></pre></div><p>And as we see above - most components are listed as &ldquo;Not Running&rdquo; or &ldquo;Not Supported&rdquo;.</p>
<p>So we&rsquo;ll enter config mode, and use the <em>iox</em> command to enable these services:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">0x8KV01# conf t
</span></span><span class="line"><span class="cl">Enter configuration commands, one per line.  End with CNTL/Z.
</span></span><span class="line"><span class="cl">0x8KV01(config)# iox 
</span></span><span class="line"><span class="cl">0x8KV01(config)#
</span></span><span class="line"><span class="cl">0x8KV01(config)# exit
</span></span><span class="line"><span class="cl">0x8KV01# show iox
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">IOx Infrastructure Summary:
</span></span><span class="line"><span class="cl">---------------------------
</span></span><span class="line"><span class="cl">IOx service (CAF)              : Running
</span></span><span class="line"><span class="cl">IOx service (HA)               : Not Supported
</span></span><span class="line"><span class="cl">IOx service (IOxman)           : Running
</span></span><span class="line"><span class="cl">IOx service (Sec storage)      : Not Supported
</span></span><span class="line"><span class="cl">Libvirtd 5.5.0                 : Running
</span></span></code></pre></div><h2 id="configuring-guestshell-networking">Configuring Guestshell Networking</h2>
<p>There&rsquo;s a good chance we&rsquo;ll want our container to have access to the outside world, so let&rsquo;s take a quick look at the network configuration.</p>
<p><strong>Note: The networking config syntax will differ if you are using a Catalyst router or a Catalyst switch. Since I am using a Catalyst 8000V - we will look at the config for a Catalyst router first.</strong></p>
<p>In order to allow external access to our container, we&rsquo;ll need to configure a gateway interface and NAT translations. Then we can provide a full network configuration to our container:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">## Enable NAT on our external interface - in my case, gigabitEthernet1
</span></span><span class="line"><span class="cl">0x8KV01(config)# interface gigabitEthernet 1
</span></span><span class="line"><span class="cl">0x8KV01(config-if)# ip nat outside
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">## Create a virtual interface for the guestshell container
</span></span><span class="line"><span class="cl">0x8KV01(config-if)# int virtualportgroup0
</span></span><span class="line"><span class="cl">0x8KV01(config-if)# ip address 192.168.100.1 255.255.255.0
</span></span><span class="line"><span class="cl">0x8KV01(config-if)# ip nat inside
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">## Create an ACL to match traffic from guestshell &amp; Enable NAT
</span></span><span class="line"><span class="cl">0x8KV01(config)# ip access-list standard IOX_NAT
</span></span><span class="line"><span class="cl">0x8KV01(config-std-nacl)# permit 192.168.100.0 0.0.0.255
</span></span><span class="line"><span class="cl">0x8KV01(config)# ip nat inside source list IOX_NAT interface gigabitEthernet 1 overload
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">## Assign network configuration to our guestshell container
</span></span><span class="line"><span class="cl">0x8KV01(config)#app-hosting appid guestshell
</span></span><span class="line"><span class="cl">0x8KV01(config-app-hosting)# app-vnic gateway0 virtualportgroup 0 guest-interface 0
</span></span><span class="line"><span class="cl">0x8KV01(config-app-hosting-gateway0)# guest-ipaddress 192.168.100.5 netmask 255.255.255.0
</span></span><span class="line"><span class="cl">0x8KV01(config-app-hosting-gateway0)# app-default-gateway 192.168.100.1 guest-interface 0
</span></span><span class="line"><span class="cl">0x8KV01(config-app-hosting)# name-server0 8.8.8.8
</span></span></code></pre></div><p>Now, as I mentioned before - this config will look different if you&rsquo;re using a switch vs a router.</p>
<p>So let&rsquo;s take a quick look at what this would look like, if we were on a Catalyst Switch instead:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Cat9k(config)# interface AppGigabitEthernet 1/0/1
</span></span><span class="line"><span class="cl">Cat9k(config-if)# switchport mode trunk
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Cat9k(config)# app-hosting appid name
</span></span><span class="line"><span class="cl">Cat9k(config-app-hosting)# app-vnic AppGigabitEthernet trunk
</span></span><span class="line"><span class="cl">Cat9k(config-app-hosting-trunk)# vlan 10 guest-interface 0
</span></span><span class="line"><span class="cl">Cat9k(config-app-hosting-vlan-access-ip))# guest-ipaddress 192.168.100.1 netmask 255.255.255.0
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Cat9k(config-app-hosting)# app-default-gateway 192.168.100.1 guest-interface 0
</span></span><span class="line"><span class="cl">Cat9k(config)# name-server 8.8.8.8 
</span></span></code></pre></div><p>Once all that config is done - Let&rsquo;s move on to getting our container started!!</p>
<h2 id="managing-the-guestshell-process">Managing the Guestshell Process</h2>
<p>In order to start a container on our Catalyst device, we&rsquo;ll need to go through a process of deploying the app, activating it, then starting it.</p>
<p>For guestshell, there is a shortcut command that will perform all of these steps for you - and make managing the guestshell process much easier.</p>
<p>So let&rsquo;s go ahead and spin up our guestshell container with the command <strong>guestshell enable</strong>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">0x8KV01# guestshell enable
</span></span><span class="line"><span class="cl">Interface will be selected if configured in app-hosting
</span></span><span class="line"><span class="cl">Please wait for completion
</span></span><span class="line"><span class="cl">guestshell installed successfully
</span></span><span class="line"><span class="cl">Current state is: DEPLOYED
</span></span><span class="line"><span class="cl">guestshell activated successfully
</span></span><span class="line"><span class="cl">Current state is: ACTIVATED
</span></span><span class="line"><span class="cl">guestshell started successfully
</span></span><span class="line"><span class="cl">Current state is: RUNNING
</span></span><span class="line"><span class="cl">Guestshell enabled successfully
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">0x8KV01# show app-hosting list
</span></span><span class="line"><span class="cl">App id                                   State
</span></span><span class="line"><span class="cl">---------------------------------------------------------
</span></span><span class="line"><span class="cl">guestshell                               RUNNING
</span></span></code></pre></div><p>And as you can see above, everything gets automatically deployed &amp; started. We can verify using the <strong>show app-hosting list</strong> command to see that our container has been started.</p>
<p>If we need to, we can also stop &amp; deactivate our container using the command <strong>guestshell disable</strong>.</p>
<p>We could also use the commands below if we wanted to perform these steps manually:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">0x8KV01# app-hosting activate appid guestshell
</span></span><span class="line"><span class="cl">0x8KV01# app-hosting start appid guestshell
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">0x8KV01# app-hosting stop appid guestshell
</span></span><span class="line"><span class="cl">0x8KV01# app-hosting deactivate appid guestshell
</span></span></code></pre></div><p>Before we move onto accessing the guestshell interface, I also wanted to show where you can get more detail about the guestshell container.</p>
<p>Using the <strong>show app-hosting detail appid guestshell</strong> command, we can see details around the container version, current MAC/IP config, and resource consumption:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">0x8KV01# show app-hosting detail appid guestshell
</span></span><span class="line"><span class="cl">App id                 : guestshell
</span></span><span class="line"><span class="cl">Owner                  : iox
</span></span><span class="line"><span class="cl">State                  : RUNNING
</span></span><span class="line"><span class="cl">Application
</span></span><span class="line"><span class="cl">  Type                 : lxc
</span></span><span class="line"><span class="cl">  Name                 : GuestShell
</span></span><span class="line"><span class="cl">  Version              : 3.2.0
</span></span><span class="line"><span class="cl">  Description          : Cisco Systems Guest Shell XE for x86_64
</span></span><span class="line"><span class="cl">  Path                 : /guestshell/:guestshell.tar
</span></span><span class="line"><span class="cl">  URL Path             :
</span></span><span class="line"><span class="cl">Activated profile name : custom
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Resource reservation
</span></span><span class="line"><span class="cl">  Memory               : 256 MB
</span></span><span class="line"><span class="cl">  Disk                 : 1 MB
</span></span><span class="line"><span class="cl">  CPU                  : 800 units
</span></span><span class="line"><span class="cl">  CPU-percent          : 3 %
</span></span><span class="line"><span class="cl">  VCPU                 : 1
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Attached devices
</span></span><span class="line"><span class="cl">  Type              Name               Alias
</span></span><span class="line"><span class="cl">  ---------------------------------------------
</span></span><span class="line"><span class="cl">  serial/shell     iox_console_shell   serial0
</span></span><span class="line"><span class="cl">  serial/aux       iox_console_aux     serial1
</span></span><span class="line"><span class="cl">  serial/syslog    iox_syslog          serial2
</span></span><span class="line"><span class="cl">  serial/trace     iox_trace           serial3
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Network interfaces
</span></span><span class="line"><span class="cl">   ---------------------------------------
</span></span><span class="line"><span class="cl">eth0:
</span></span><span class="line"><span class="cl">   MAC address         : 52:54:dd:d:bf:da
</span></span><span class="line"><span class="cl">   IPv4 address        : 192.168.100.5
</span></span><span class="line"><span class="cl">   IPv6 address        : ::
</span></span><span class="line"><span class="cl">   Network name        : VPG0
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Port forwarding
</span></span><span class="line"><span class="cl">  Table-entry  Service  Source-port  Destination-port
</span></span><span class="line"><span class="cl">  ---------------------------------------------------
</span></span></code></pre></div><h2 id="accessing-the-guestshell-cli">Accessing the Guestshell CLI</h2>
<p>Now for the fun part! Let&rsquo;s get into our guestshell container.</p>
<p>We&rsquo;ll just need to use the <strong>guestshell</strong> command, and we&rsquo;ll be dropped into the Linux shell:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">0x8KV01# guestshell
</span></span><span class="line"><span class="cl">[guestshell@guestshell ~]$
</span></span><span class="line"><span class="cl">[guestshell@guestshell ~]$ uname -a
</span></span><span class="line"><span class="cl">Linux guestshell 5.4.40 #1 SMP Tue Oct 6 17:57:00 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
</span></span></code></pre></div><p>Let&rsquo;s also make sure our network &amp; NAT configuration worked:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">[guestshell@guestshell ~]$ ping 8.8.8.8
</span></span><span class="line"><span class="cl">PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
</span></span><span class="line"><span class="cl">64 bytes from 8.8.8.8: icmp_seq=1 ttl=64 time=3.57 ms
</span></span><span class="line"><span class="cl">64 bytes from 8.8.8.8: icmp_seq=2 ttl=64 time=2.64 ms
</span></span><span class="line"><span class="cl">64 bytes from 8.8.8.8: icmp_seq=3 ttl=64 time=2.54 ms
</span></span><span class="line"><span class="cl">^C
</span></span><span class="line"><span class="cl">--- 8.8.8.8 ping statistics ---
</span></span><span class="line"><span class="cl">3 packets transmitted, 3 received, 0% packet loss, time 4ms
</span></span><span class="line"><span class="cl">rtt min/avg/max/mdev = 2.543/2.916/3.567/0.465 ms
</span></span></code></pre></div><p>If needed, we can also run commands on our Catalyst device CLI without leaving the guestshell interface by using the <strong>dohost</strong> utility:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">[guestshell@guestshell ~]$ dohost &#34;show app-hosting list&#34;
</span></span><span class="line"><span class="cl">App id                                   State
</span></span><span class="line"><span class="cl">---------------------------------------------------------
</span></span><span class="line"><span class="cl">guestshell                               RUNNING
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">[guestshell@guestshell ~]$
</span></span></code></pre></div><p>Just a note, the reverse is also possible. Using the <strong>guestshell run</strong> command from our Catalyst CLI, we can run commands in our container:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">0x8KV01# guestshell run uname -a
</span></span><span class="line"><span class="cl">Linux guestshell 5.4.40 #1 SMP Tue Oct 6 17:57:00 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">0x8KV01#
</span></span></code></pre></div><p>It&rsquo;s also worth reiterating, that the guestshell container is a full Linux container (It runs CentOS). So if we need to install additional Linux packages, we can use our Linux package manager (YUM) to do so.</p>
<p>Anyways - Let&rsquo;s wrap this up by looking at the built-in Python modules &amp; capabilities</p>
<h2 id="using-python-in-guestshell">Using Python in Guestshell</h2>
<p>One of the more appealing use cases for guestshell is the ability to run native Python scripts &amp; code directly on your Catalyst device.</p>
<p>A couple of possible use cases could be:</p>
<ul>
<li>Troubleshoot intermittent issues - Automatically collect device state (routes, MAC changes, etc) on a regular basis to log locally or send via email</li>
<li>Automated resolution - If a certain type of state change is observed, we could run a pre-set list of commands to try and automatically fix the issue</li>
<li>Local monitoring / troubleshooting - We could run a series of ping, web page load tests, etc from a python script to help monitor performance from the switch&rsquo;s perspective</li>
<li>Change management / notification - A script could be written to monitor the device configuration for any changes made, then send an automated email when something was detected</li>
<li>Have a risky change that might sever your connection to a remote device? A script could execute the change for you, and if unsuccessful, revert to a working configuration (without doing a <em>reload after</em>)</li>
</ul>
<p>These are just a handful of ideas that came to mind while writing this blog post&hellip; But there are many more possibilities!</p>
<p>Within the guestshell container, there is a special <strong>cli</strong> python module that comes pre-loaded. This module allows us to run CLI commands on our catalyst device directly from a python script &amp; receive the command output for parsing.</p>
<p>Let&rsquo;s look at a quick example using the Python interactive interpreter to save the device configuration:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">[guestshell@guestshell ~]$ python3
</span></span><span class="line"><span class="cl">Python 3.6.8 (default, Aug 24 2020, 17:57:11)
</span></span><span class="line"><span class="cl">[GCC 8.3.1 20191121 (Red Hat 8.3.1-5)] on linux
</span></span><span class="line"><span class="cl">Type &#34;help&#34;, &#34;copyright&#34;, &#34;credits&#34; or &#34;license&#34; for more information.
</span></span><span class="line"><span class="cl">&gt;&gt;&gt; 
</span></span><span class="line"><span class="cl">&gt;&gt;&gt; import cli
</span></span><span class="line"><span class="cl">&gt;&gt;&gt; status = cli.execute(&#34;write memory&#34;)
</span></span><span class="line"><span class="cl">&gt;&gt;&gt; if &#34;OK&#34; in status: print(&#34;Device configuration was saved!&#34;)
</span></span><span class="line"><span class="cl">...
</span></span><span class="line"><span class="cl">Device configuration was saved!
</span></span></code></pre></div><p>The example above uses the <strong>cli.execute</strong> Python function, which will run commands in Cisco&rsquo;s exec mode.</p>
<p>What if we wanted to make configuration changes? In that case we would use the <strong>cli.configure</strong> function:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">&gt;&gt;&gt; config_data = &#34;&#34;&#34;interface loopback200
</span></span><span class="line"><span class="cl">... ip address 172.16.99.10 255.255.255.0
</span></span><span class="line"><span class="cl">... &#34;&#34;&#34;
</span></span><span class="line"><span class="cl">&gt;&gt;&gt;
</span></span><span class="line"><span class="cl">&gt;&gt;&gt; cli.configure(config_data)
</span></span><span class="line"><span class="cl">&#39;Line 1 SUCCESS:  interface loopback200\nLine 2 SUCCESS:  ip address 172.16.99.10 255.255.255.0\n&#39;
</span></span><span class="line"><span class="cl">&gt;&gt;&gt;
</span></span><span class="line"><span class="cl">&gt;&gt;&gt; cli.execute(&#34;show run interface loopback200&#34;)
</span></span><span class="line"><span class="cl">&#39;Building configuration...\nCurrent configuration : 68 bytes\n!\ninterface Loopback200\n ip address 172.16.99.10 255.255.255.0\nend\n&#39;
</span></span></code></pre></div><p>In the above example, we used a multi-line comment to provide the list of commands to enter. The <strong>cli.configure</strong> function also supports a Python list - so we could provide the commands in that format as well.</p>
<p>You&rsquo;ll notice that the Python interpreter returns a status for each command that we attempted to run. This should allow us to error-check &amp; ensure that all of our intended configuration was accepted.</p>
<p>Lastly, we used the <strong>cli.execute</strong> command again to validate that our running configuration looks correct.</p>
<p>There&rsquo;s a bit more functionality built into the <strong>cli</strong> Python module, but I just wanted to cover some of the common use cases. More details can be found <a href="https://www.cisco.com/c/en/us/td/docs/ios-xml/ios/prog/configuration/1610/b_1610_programmability_cg/python_api.html">here</a></p>
<hr>
<h2 id="a-few-common-questions">A Few Common Questions</h2>
<p><strong>Does this give me access to the underlying IOS-XE Linux shell?</strong></p>
<p>Nope, anything running in guestshell is running in a container - which runs <em>on-top</em> of the IOS-XE image.</p>
<p><strong>What about resource conflicts?</strong></p>
<p>The linux containers running on the IOS-XE platform are given their own dedicated resources. Any resource constraints that affect the containers will not impact normal network functions.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Meraki MG - Setting up Meraki&#39;s New Cellular Gateway</title>
      <link>https://0x2142.com/meraki-mg-setting-up-merakis-new-lte-gateway/</link>
      <pubDate>Thu, 20 Aug 2020 21:17:23 +0000</pubDate>
      <guid>https://0x2142.com/meraki-mg-setting-up-merakis-new-lte-gateway/</guid>
      <description>I recently got a Meraki MG21 LTE gateway. Let&amp;rsquo;s set it up!</description>
      <content:encoded><![CDATA[<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
      <iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="allowfullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/Zb5KE8_OFxQ?autoplay=0&amp;controls=1&amp;end=0&amp;loop=0&amp;mute=0&amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"></iframe>
    </div>

<p>So if you&rsquo;ve read some of my recent posts - you may have seen that I purchased a <a href="/how-to-setting-up-google-fi-on-a-netgear-lte-modem/">NetGear LB 1121 LTE Cellular modem</a> to use for home internet backup.</p>
<p>Well - I decided to upgrade!</p>
<p>After using the NetGear modem for a while, I started having some issues where it would disconnect from the cellular connection intermittently. Since it&rsquo;s not necessarily intended for the purpose I&rsquo;m using it for, there wasn&rsquo;t any good way to set up monitoring for it either.</p>
<p>So I opted to upgrade to a Meraki MG21. This is one of the latest additions to the Meraki family of network devices &amp; is available with internal (MG21) and external (MG21E) antenna.</p>
<p>I was pretty excited to get one, since Meraki tends to have decent analytics &amp; configuration - and they make everything so easy!</p>
<p>We&rsquo;ll walk through the setup of the MG below - but if you&rsquo;re interested in seeing what the device looks like as well, definitely check out the video above!</p>
<hr>
<h2 id="mg-setup---changing-the-apn">MG Setup - Changing the APN</h2>
<p>Okay - so after I got the SIM card inserted into the MG, the first configuration step is making sure we have the correct APN configured. As a reminder, I&rsquo;m using Google Fi as my cellular provider.</p>
<p>This change will need to be done <strong>on the local web management interface</strong> - not from Meraki Dashboard.</p>
<p>When the MG powers on, by default it will hand out DHCP addresses to any device connected to port 1. At the time of writing, these addresses were in the 192.168.5.x range.</p>
<p>Connecting a PC directly to the MG port, we should be able to reach the local management web page - either by typing in the IP address into our web browser, or using mg.meraki.com:</p>
<p><img alt="blog-01" loading="lazy" src="/content/images/2020/08/blog-01.PNG#center"></p>
<p>In my case, I could see that the MG had auto-detected my Carrier as Google Fi. However, it still had the incorrect APN.</p>
<p>Using the <strong>Configure</strong> tab, we can change that setting. You&rsquo;ll be prompted for a username &amp; password. By default, the username will be the serial number of the device (including dashes) with a blank password.</p>
<p><img alt="blog-02" loading="lazy" src="/content/images/2020/08/blog-02.PNG#center"></p>
<p>As shown in the screenshot above, we have a handful of options - though we&rsquo;ll only care about APN.</p>
<p>First - change the <strong>Cellular Override</strong> option to <strong>Override SIM Settings</strong>.
Then type in your APN. In my case, it&rsquo;s <strong>h2g2</strong> for Google Fi.
Lastly, hit save at the bottom (just outside the view in the screenshot above).</p>
<p>With any luck, the modem will connect and you&rsquo;ll see something like this:</p>
<p><img alt="blog-03" loading="lazy" src="/content/images/2020/08/blog-03.png#center"></p>
<p>The modem connects, gets an IP from the provider, and is able to validate connectivity to both the internet &amp; Meraki Cloud.</p>
<p>When I originally set up my MG, I did run into some issues with this. My MG connected to the internet successfully, but said it couldn&rsquo;t reach the Meraki Cloud. Not sure what caused it, but it shortly resolved itself within a few minutes. Just gotta be patient sometimes, I suppose!</p>
<h2 id="configuring-the-mg-in-meraki-dashboard">Configuring the MG in Meraki Dashboard</h2>
<p><em>Note: I won&rsquo;t get into how to claim your device in dashboard or how to attach it to a network. If you need help, please check out the video above where I did show how to accomplish these steps</em></p>
<p>Okay! Now that our MG is configured for the correct cell network, we can log into the Meraki Dashboard and begin configuring it.</p>
<p>After we&rsquo;ve added the MG to our network, we&rsquo;ll see a new <strong>Cellular Gateway</strong> menu:</p>
<p><img alt="blog-04" loading="lazy" src="/content/images/2020/08/blog-04.png#center"></p>
<p>We&rsquo;ll start first by going over to <strong>Configure &gt; Settings</strong></p>
<p>First section we&rsquo;ll see is for <strong>Addressing &amp; NAT</strong>:</p>
<p><img alt="blog-05" loading="lazy" src="/content/images/2020/08/blog-05.png#center"></p>
<p>As of today, the MG doesn&rsquo;t support any form of direct internet pass-through. Instead, our only option is <strong>routed</strong> mode - where the MG will hold the IP provided by our Carrier &amp; NAT any requests from the devices behind it.</p>
<p>We can change the DHCP subnet configuration here, which will affect what IP addresses are handed to clients behind the MG. In my case, I&rsquo;m connecting this directly to a firewall as a secondary internet uplink - so the addressing &amp; subnet doesn&rsquo;t matter as much. By default, the MG will always consume the first available address as it&rsquo;s own.</p>
<p>Next, we have a section for <strong>DHCP &amp; subnets</strong>:</p>
<p><img alt="blog-06" loading="lazy" src="/content/images/2020/08/blog-06.png#center"></p>
<p>Here we can change our DHCP lease time, and what DNS servers are provided to our clients. The DNS setting does have pre-defined options for Umbrella DNS, Google DNS, or using whatever the upstream carrier provides. You&rsquo;re also welcome to manually specify which DNS servers to use.</p>
<p>We can also configure reserved &amp; fixed IP addresses here.</p>
<p>Reserved IP ranges are IP addresses that we don&rsquo;t want the MG to provide via DHCP. So if we had any statically configured IP addresses, we could reserve them here.</p>
<p>Fixed IP addresses are for any client that needs a DHCP address, but we want that IP assignment to be permanent. We&rsquo;ll enter the client name &amp; MAC Address here, as well as the IP we want assigned to that device. In my case, I went ahead and inserted my firewall MAC address - and I&rsquo;ll just allow the firewall to get its IP via DHCP from the MG.</p>
<p>By default, the MG will block <strong>all</strong> inbound traffic from the cellular network. If we need to allow any traffic inbound, we can change the <strong>Port Forwarding</strong> settings:</p>
<p><img alt="blog-07" loading="lazy" src="/content/images/2020/08/blog-07.png#center"></p>
<p>This allows for a light configuration of an inbound NAT. Right now, I probably won&rsquo;t be using this. However, I may permit VPN access into my network via the MG at a later date.</p>
<p>If I needed to add anything here, the MG allows us to translate an external / public IP &amp; port to any internal IP / port combination. It appears we can even add a IP filter to permit only trusted source addresses.</p>
<p>Lastly - We can configure settings for <strong>Traffic Shaping</strong>:</p>
<p><img alt="blog-08" loading="lazy" src="/content/images/2020/08/blog-08.PNG#center"></p>
<p>In this section, we can throttle our cellular throughput &amp; configure uplink monitoring.</p>
<p>By default, the cell bandwidth is set to unlimited - but we can drop this down if needed. In my case, I am not using an unlimited cell data plan - so I will throttle cellular speeds to preserve data &amp; reduce charges.</p>
<p>In addition, we can configure one or more IP addresses to check uplink connectivity. These addresses will be used to collect loss &amp; latency data via the cellular connection. The MG monitoring dashboard will collect &amp; graph this data for easy insight into the performance metrics.</p>
<p><strong>Note: As a word of warning, these uplink monitors are constantly sending ICMP/ping requests. If you have a limited amount of cellular data, this may consume more data than you would like. In my testing, using only one IP for uplink monitoring consumed about 70-100M per day. More on this below&hellip;</strong></p>
<h2 id="monitoring-the-mg">Monitoring the MG</h2>
<p>Now we get to the good stuff! The primary reason I opted to buy an MG was for monitoring &amp; analytics.</p>
<p>Back on the dashboard, if we use the lefthand menu - we&rsquo;ll go over to <strong>Cellular Gateway &gt; Monitor &gt; Cellular Gatways</strong>. Then select our MG out of the list.</p>
<p>The primary summary page isn&rsquo;t too exciting:</p>
<p><img alt="blog-09" loading="lazy" src="/content/images/2020/08/blog-09.png#center"></p>
<p>The MG does have two gigabit ethernet ports - and we&rsquo;ll see the status here.</p>
<p>We&rsquo;ll also see the connectivity history to the Meraki cloud - which in my case is nearly 100%. Seems like one <em>very</em> minor blip just after 4am.</p>
<p>We can also see the current network utilization on the MG. This is great to have - though my current utilization is pretty low&hellip; (I am using this as a backup modem, after all).</p>
<p>On the left side of the page, we&rsquo;ll see some of the usual info we expect from a Meraki device. Current IP, location, Serial number, and IMEI. Just below the view of the screenshot, there is also an indicator for firmware version.</p>
<p>Onto the <strong>Uplink</strong> tab! Let&rsquo;s see what we have:</p>
<p><img alt="blog-10" loading="lazy" src="/content/images/2020/08/blog-10.png#center"></p>
<p>First we&rsquo;ll see the <strong>Configuration</strong> section. This just gives us a quick view into what settings the MG currently has.</p>
<p>We&rsquo;ll see the current IP info provided by our carrier, and also some statistics on our cellular connection.</p>
<p>Just below that info, we&rsquo;ll see our cellular graphs:</p>
<p><img alt="blog-11" loading="lazy" src="/content/images/2020/08/blog-11.png"></p>
<p>This is what I wanted! It&rsquo;s great to see a quick view into what our active uplink traffic is - as well as look back historically at what our LTE signal quality has been.</p>
<p>Not pictured here - but there is also a section of graphs on this page for our uplink monitor. This is where we can see our current &amp; historical loss &amp; latency stats for the cellular connection. After a few days of use - I disabled the uplink monitor due to the amount of data the feature consumes.</p>
<p>Finally, we also have the <strong>DHCP</strong> tab:</p>
<p><img alt="blog-12" loading="lazy" src="/content/images/2020/08/blog-12.PNG#center"></p>
<p>This will show our current DHCP subnet &amp; any clients that have been provided an address. In my case, there isn&rsquo;t any current leases here - because my firewall has a fixed IP.</p>
<h2 id="performance--considerations">Performance &amp;&amp; Considerations</h2>
<p>I&rsquo;ve had the MG running for about a week now, and wanted to provide some things to think about.</p>
<p>First - How does the modem perform? Well, the first day I had it set up - I was able to get ~150M download speeds using the MG&rsquo;s built-in speed test utility:</p>
<p><img alt="blog-13" loading="lazy" src="/content/images/2020/08/blog-13.PNG#center"></p>
<p>That being said - I&rsquo;m lucky if I get 30-50M on an average day. I might have just gotten lucky that day with some light cellular utilization in my area. Overall though, I&rsquo;m pleased with the speeds I get - they&rsquo;ll certainly fit my needs.</p>
<p>For the few days that I had the uplink monitoring running, I saw good results. Usually 0% packet loss, with a rare spike of 5-10%. Latency was a little less reliable, but usually bounced between 50-150ms. This was also much less than the NetGear modem I had been using, which averaged 200-250ms.</p>
<p>Speaking of uplink tests! Let&rsquo;s talk about data usage&hellip;.</p>
<p>By default, the MG communicates intermittently with the Meraki cloud - which consumes some data. By my measurement, this is usually less than 10Mb/day. No problem here.</p>
<p>The uplink tests, on the other hand, <strong>do</strong> consume a bit of data. I&rsquo;m not sure what frequency these run on, but it&rsquo;s fairly often. Even with one uplink monitor to 8.8.8.8 configured, I was seeing data usage of 70-100Mb a day.</p>
<p>While seeing those metrics is valuable to me, it&rsquo;s also not worth the data charges. If I was using a SIM card with an unlimited data plan - no doubt I would keep this feature enabled. However, since I am paying for the cell data used - I opted to disable this feature.</p>
<p>The MG does still perform it&rsquo;s check-ins to the Meraki Cloud - so you&rsquo;ll have availability statistics &amp; monitoring&hellip; But disabling the uplink monitor means you&rsquo;ll lose the granular data on loss &amp; latency.</p>
<p>Lastly, and another word of warning, when you&rsquo;re actively viewing the MG monitoring page - this <strong>also consumes additional data</strong>. To demonstrate - I&rsquo;ll post a snippet of the screenshot from earlier:</p>
<p><img alt="blog-14" loading="lazy" src="/content/images/2020/08/blog-14.png#center"></p>
<p>If you notice, all the way on the far left there was barely any activity. However, once I loaded the MG monitoring page - you begin to see minor spikes in data usage as the Meraki Cloud starts actively polling the MG for data.</p>
<p>In my experience so far, this isn&rsquo;t a ton of data. I&rsquo;ve checked in to see how the MG has been performing a few times this week, and each time has totaled around 10-15Mb of data usage.</p>
<p>To sum up - I&rsquo;m cheap and want to avoid excess data usage. Just wanted to provide some of that info as something to be aware of.</p>
<h2 id="final-thoughts">Final Thoughts</h2>
<p>I&rsquo;m only a week in, but pretty pleased with the MG&rsquo;s performance. It&rsquo;s maintained a very solid &amp; stable connection compared to the NetGear modem it replaced. The device is intended to provide LTE connectivity or backup service for business networks, so I would certainly hope it would meet my home needs :)</p>
<p>Outside of that, I do wish there was a little better documentation &amp; clarity from the Meraki team on data usage. Right now their documentation only mentions the 6-8Mb of usage due to backend data to/from the Meraki Cloud:</p>
<p><img alt="blog-15" loading="lazy" src="/content/images/2020/08/blog-15.PNG#center"></p>
<p>I would be happy to see additional settings on the uplink monitor to allow me to choose the polling frequency. I feel like throttling down the amount of requests could reduce data to a point where I would be comfortable re-enabling that feature.</p>
<p><del>Oh - and currently there are no native email alerts for the MG. So if the MG goes offline, etc&hellip; there is no alerting from the Meraki Dashboard. This kinda sucks. I&rsquo;m sure this is coming soon, but for the time being I&rsquo;m inclined to write my own monitor using the Dashboard APIs.</del> (see note below!)</p>
<p>Overall, I&rsquo;m happy with the device. Definitely looking forward to future feature &amp; firmware updates to see where the Meraki team takes this platform!</p>
<hr>
<p><em>Update 08/28/2020 - Looks like in the week since I posted this, Meraki added alerting for the MG! Now you can be notified if the cell gateway goes offline:</em></p>
<p><img alt="blog-16" loading="lazy" src="/content/images/2020/08/blog-16.PNG#center"></p>
]]></content:encoded>
    </item>
    <item>
      <title>Cisco Firepower - Automating Cellular Failover</title>
      <link>https://0x2142.com/cisco-firepower-automating-cellular-failover/</link>
      <pubDate>Fri, 17 Jul 2020 20:41:09 +0000</pubDate>
      <guid>https://0x2142.com/cisco-firepower-automating-cellular-failover/</guid>
      <description>How I automated internet uplink monitoring &amp;amp; route injection on a Cisco Firepower Firewall</description>
      <content:encoded><![CDATA[<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
      <iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="allowfullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/Mf5zIt9HFxk?autoplay=0&amp;controls=1&amp;end=0&amp;loop=0&amp;mute=0&amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"></iframe>
    </div>

<p>In a <a href="/how-to-setting-up-google-fi-on-a-netgear-lte-modem/">recent post</a>, I walked through setting up a Netgear LTE cellular modem with Google Fi. Might seem random - but I had a plan for this!</p>
<p>In trying to ensure I keep a stable internet connection for work, I eventually led myself down the path of buying a cellular modem. That was part one. The next step was being able to somewhat-intelligently monitor my home internet connection, and then fail over to the cell modem when connectivity was poor (think lazy SDWAN).</p>
<p>At first I figured this would be easy&hellip;. but of course nothing is :)</p>
<p>I currently have a Cisco FirePower 1010 appliance that I&rsquo;m using for a home firewall. Unfortunately, while this thing does support IP SLA - It wouldn&rsquo;t quite accomplish what I wanted to do. And to be fair, this box is intended to be a <em>security</em> appliance - not SDWAN.</p>
<p>Anyways - I talked myself into just writing some Python automation to monitor my home internet, and dynamically inject/remove static routing entries. I needed a new project anyways</p>
<p><em>For those of you wanting to jump straight to the code, the GitHub repo is <a href="https://github.com/0x2142/fpwr-route-failover">here</a></em></p>
<hr>
<h2 id="part-1---monitoring-packet-loss--latency">Part 1 - Monitoring Packet Loss &amp; Latency</h2>
<p>So first thing - I regularly experience both complete internet outages (always at the worst times), as well as very high latency. Packet loss seems to be less common with my ISP - but hey, it happens sometimes too.</p>
<p>I opted to use the <a href="https://pypi.org/project/pythonping/">pythonping</a> module as an easy way to collect some of the info I needed.</p>
<p>After importing the module, it&rsquo;s as easy as specifying a destination, packet size, and number of ICMP messages to send:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">pythonping</span> <span class="kn">import</span> <span class="n">ping</span>
</span></span><span class="line"><span class="cl"><span class="n">result</span> <span class="o">=</span> <span class="n">ping</span><span class="p">(</span><span class="s1">&#39;8.8.8.8&#39;</span><span class="p">,</span> <span class="n">size</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">count</span><span class="o">=</span><span class="mi">10</span><span class="p">,</span> <span class="n">verbose</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span></span></code></pre></div><p>To simplify at least one part of the operation, pythonping has a built in function to return the average round trip:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="o">&gt;&gt;&gt;</span> <span class="nb">print</span><span class="p">(</span><span class="n">result</span><span class="o">.</span><span class="n">rtt_avg_ms</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="mf">74.23</span>
</span></span></code></pre></div><p>The actual contents of our ping results are going to be in the following format:
<code>Reply from 8.8.8.8, 10 bytes in 43.82ms</code></p>
<p>So a quick way for me to figure out packet loss was to simply search for the &ldquo;Reply from&rdquo; text in each response:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">lost</span> <span class="o">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">packet</span> <span class="ow">in</span> <span class="n">result</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="s2">&#34;Reply from&#34;</span> <span class="ow">in</span> <span class="nb">str</span><span class="p">(</span><span class="n">packet</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="k">pass</span>
</span></span><span class="line"><span class="cl">    <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">lost</span> <span class="o">+=</span> <span class="mi">1</span>
</span></span></code></pre></div><p>Easy enough - and we can use that to calculate the amount of packet loss against the 10 total packets sent:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">lossperc = 100 * lost / 10
</span></span></code></pre></div><p>Once all that is figured out, we can use a simple expression to determine whether or not the loss or latency thresholds have been exceeded:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">if</span> <span class="n">response</span> <span class="o">&gt;=</span> <span class="n">MAX_LATENCY</span> <span class="ow">or</span> <span class="n">loss</span> <span class="o">&gt;=</span> <span class="n">MAX_LOSS</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;Loss/Latency violate thresholds.&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="kc">True</span>
</span></span><span class="line"><span class="cl"><span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;Loss/Latency within thresholds.&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="kc">False</span>
</span></span></code></pre></div><p>The code I wrote then takes one of two paths.</p>
<ul>
<li>If the loss and latency is ABOVE our thresholds, call to the FirePower module to inject a static default route over the LTE modem</li>
<li>If the loss and latency is BELOW our thresholds, call to the FirePower module to delete the static default route - which returns traffic to the primary internet</li>
</ul>
<p>These functions within the FirePower module were written so that each change will only be made once. For example, if the script checks and finds that the loss/latency is bad, but the static route towards the LTE modem already exists - then no additional changes are made.</p>
<p>So next - Let&rsquo;s take a look at the FirePower module.</p>
<h2 id="part-2---authenticating-to-fdm--initial-checks">Part 2 - Authenticating to FDM &amp; Initial Checks</h2>
<p>This was my first time getting into the FirePower FDM APIs - but they ended up being fairly straightforward to use.</p>
<p>Turns out that FDM has built-in API documentation, which is extremely helpful. This can be found at <code>https://&lt;FDM IP&gt;/#/api-explorer</code></p>
<p><img alt="firepower-api-explorer" loading="lazy" src="/content/images/2020/07/firepower-api-explorer.PNG#center"></p>
<p>Okay - So first thing&rsquo;s first. Authenticating to the firewall:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">oauth_data</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;grant_type&#34;</span><span class="p">:</span> <span class="s2">&#34;password&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;username&#34;</span><span class="p">:</span> <span class="s2">&#34;admin&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;password&#34;</span><span class="p">:</span> <span class="s2">&#34;Cisco1234!&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="n">headers</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="s2">&#34;Content-Type&#34;</span><span class="p">:</span> <span class="s2">&#34;application/json&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="s2">&#34;Accept&#34;</span><span class="p">:</span> <span class="s2">&#34;application/json&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="n">baseurl</span> <span class="o">=</span> <span class="s2">&#34;https://&#34;</span> <span class="o">+</span> <span class="n">FDM</span> <span class="o">+</span> <span class="s2">&#34;/api/fdm/latest&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">authurl</span> <span class="o">=</span> <span class="n">baseurl</span> <span class="o">+</span> <span class="s2">&#34;/fdm/token&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s2">&#34;Posting AUTH request to FDM&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># POST request to FDM with headers / oauth data</span>
</span></span><span class="line"><span class="cl"><span class="n">resp</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">s</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="n">authurl</span><span class="p">,</span> <span class="n">headers</span><span class="o">=</span><span class="n">headers</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                   <span class="n">data</span><span class="o">=</span><span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">oauth_data</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">                   <span class="n">verify</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># If success - only pull out &amp; return the auth token</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="n">resp</span><span class="o">.</span><span class="n">status_code</span> <span class="o">==</span> <span class="mi">200</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;Auth success - got token.&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">resp</span><span class="o">.</span><span class="n">text</span><span class="p">)[</span><span class="s1">&#39;access_token&#39;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;Authentication Failed.&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="nb">print</span><span class="p">(</span><span class="n">resp</span><span class="o">.</span><span class="n">text</span><span class="p">)</span>
</span></span></code></pre></div><p>In the code above - we take the headers and some basic authentication info (username, password, grant type) and send it in an HTTP POST request to <code>https://&lt;FDM IP&gt;/api/fdm/latest/fdm/token</code></p>
<p>This returns an authentication token, which we&rsquo;ll need to include in any further HTTP request to the firewall. This can be done by sending a new set of headers in the future:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">headers</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="s2">&#34;Content-Type&#34;</span><span class="p">:</span> <span class="s2">&#34;application/json&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="s2">&#34;Accept&#34;</span><span class="p">:</span> <span class="s2">&#34;application/json&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="s2">&#34;Authorization&#34;</span><span class="p">:</span> <span class="s2">&#34;Bearer &#34;</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">token</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Next we need to figure out which routing table to insert the route into. Since I am only using the default routing table, the script will just grab the UID for the default global routing table:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">vr_url</span> <span class="o">=</span> <span class="n">baseurl</span> <span class="o">+</span> <span class="s2">&#34;/devices/default/routing/virtualrouters&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">routing_table</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">vr_url</span><span class="p">,</span> <span class="n">headers</span><span class="o">=</span><span class="n">headers</span><span class="p">)</span>
</span></span></code></pre></div><p>I mentioned earlier that the script will not make any changes if the firewall is already in the desired state. So we will take time now to check what state the firewall is in, before attempting to make any changes.</p>
<p>This is accomplished by making our first primary action scanning the routing table to see if our route already exists:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">route_url</span> <span class="o">=</span> <span class="n">baseurl</span> <span class="o">+</span> <span class="s2">&#34;/devices/default/routing/virtualrouters/&#34;</span> <span class="o">+</span> \
</span></span><span class="line"><span class="cl">            <span class="bp">self</span><span class="o">.</span><span class="n">globalVR</span> <span class="o">+</span> <span class="s2">&#34;/staticrouteentries&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">route_data</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">route_url</span><span class="p">,</span> <span class="n">headers</span><span class="o">=</span><span class="n">headers</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Convert returned JSON object</span>
</span></span><span class="line"><span class="cl"><span class="n">current_routes</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">route_data</span><span class="p">)[</span><span class="s1">&#39;items&#39;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Run through each route returned and see if it matches the one we&#39;re looking for</span>
</span></span><span class="line"><span class="cl"><span class="k">for</span> <span class="n">route</span> <span class="ow">in</span> <span class="n">current_routes</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># For each route, we need to manually go look up the uid of our gateway &amp; network objects</span>
</span></span><span class="line"><span class="cl">    <span class="n">gateway</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">getNetworkObject</span><span class="p">(</span><span class="n">route</span><span class="p">[</span><span class="s1">&#39;gateway&#39;</span><span class="p">][</span><span class="s1">&#39;id&#39;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">    <span class="n">dest_network</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">getNetworkObject</span><span class="p">(</span><span class="n">route</span><span class="p">[</span><span class="s1">&#39;networks&#39;</span><span class="p">][</span><span class="mi">0</span><span class="p">][</span><span class="s1">&#39;id&#39;</span><span class="p">])</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;/&#39;</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># Match based on route prefix &amp; upstream next hop gateway</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">gateway</span> <span class="o">==</span> <span class="n">GATEWAY</span> <span class="ow">and</span> <span class="n">dest_network</span> <span class="o">==</span> <span class="n">ROUTE</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;/&#39;</span><span class="p">)[</span><span class="mi">0</span><span class="p">]:</span>
</span></span><span class="line"><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;Found route to </span><span class="si">%s</span><span class="s2"> via </span><span class="si">%s</span><span class="s2">&#34;</span> <span class="o">%</span> <span class="p">(</span><span class="n">dest_network</span><span class="p">,</span> <span class="n">gateway</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">route</span>
</span></span></code></pre></div><p>Depending on whether we were looking to add or remove a route, the script may proceed with doing so - or just quit if the action has already been taken previously.</p>
<h2 id="part-3---failover-add-static-route">Part 3 - Failover (Add Static Route)</h2>
<p>Assuming that we need to <strong>Add</strong> a route, we need to sent a POST request to <code>https://&lt;FDM IP&gt;/api/fdm/latest/devices/default/routing/virtualrouters/&lt;Virtual Router ID&gt;/staticrouteentries</code> with some required information (like subnet info, next-hop, etc)</p>
<p>Unfortunately, we can&rsquo;t just send a POST with the target subnet &amp; gateway. Those need to be created as network objects on the FirePower box beforehand. For each network object, we need to build a quick JSON object with the required info:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">host_data</span> <span class="o">=</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl"><span class="n">host_data</span><span class="p">[</span><span class="s1">&#39;name&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">name</span>
</span></span><span class="line"><span class="cl"><span class="n">host_data</span><span class="p">[</span><span class="s1">&#39;description&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&#34;Created by ISP Failover automation&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">host_data</span><span class="p">[</span><span class="s1">&#39;subType&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">subtype</span>
</span></span><span class="line"><span class="cl"><span class="n">host_data</span><span class="p">[</span><span class="s1">&#39;value&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">address</span>
</span></span><span class="line"><span class="cl"><span class="n">host_data</span><span class="p">[</span><span class="s1">&#39;type&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&#34;networkobject&#34;</span>
</span></span></code></pre></div><p>Then we can send a POST to the FDM API to create the object with our supplied parameters:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">posturl</span> <span class="o">=</span> <span class="n">baseurl</span> <span class="o">+</span> <span class="s2">&#34;/object/networks&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">requests</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="n">posturl</span><span class="p">,</span> <span class="n">headers</span><span class="o">=</span><span class="n">headers</span><span class="p">,</span> <span class="n">json</span><span class="o">=</span><span class="n">host_data</span><span class="p">)</span>
</span></span></code></pre></div><p>Once we have those objects created, we can compile all of that info into a JSON object with all the components needed to create a static route entry:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">routeobject</span> <span class="o">=</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl"><span class="n">routeobject</span><span class="p">[</span><span class="s1">&#39;name&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&#34;route_BACKUP&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">routeobject</span><span class="p">[</span><span class="s1">&#39;description&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&#34;Created by ISP Failover automation&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">routeobject</span><span class="p">[</span><span class="s1">&#39;iface&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl"><span class="n">routeobject</span><span class="p">[</span><span class="s1">&#39;iface&#39;</span><span class="p">][</span><span class="s1">&#39;id&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">iface_ID</span>
</span></span><span class="line"><span class="cl"><span class="n">routeobject</span><span class="p">[</span><span class="s1">&#39;iface&#39;</span><span class="p">][</span><span class="s1">&#39;type&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&#34;physicalinterface&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">routeobject</span><span class="p">[</span><span class="s1">&#39;iface&#39;</span><span class="p">][</span><span class="s1">&#39;name&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">iface_name</span>
</span></span><span class="line"><span class="cl"><span class="n">routeobject</span><span class="p">[</span><span class="s1">&#39;networks&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="p">[{}]</span>
</span></span><span class="line"><span class="cl"><span class="n">routeobject</span><span class="p">[</span><span class="s1">&#39;networks&#39;</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl"><span class="n">routeobject</span><span class="p">[</span><span class="s1">&#39;networks&#39;</span><span class="p">][</span><span class="mi">0</span><span class="p">][</span><span class="s1">&#39;id&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">network_ID</span>
</span></span><span class="line"><span class="cl"><span class="n">routeobject</span><span class="p">[</span><span class="s1">&#39;networks&#39;</span><span class="p">][</span><span class="mi">0</span><span class="p">][</span><span class="s1">&#39;type&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&#34;networkobject&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">routeobject</span><span class="p">[</span><span class="s1">&#39;networks&#39;</span><span class="p">][</span><span class="mi">0</span><span class="p">][</span><span class="s1">&#39;name&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">network_name</span>
</span></span><span class="line"><span class="cl"><span class="n">routeobject</span><span class="p">[</span><span class="s1">&#39;gateway&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl"><span class="n">routeobject</span><span class="p">[</span><span class="s1">&#39;gateway&#39;</span><span class="p">][</span><span class="s1">&#39;id&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">gateway_ID</span>
</span></span><span class="line"><span class="cl"><span class="n">routeobject</span><span class="p">[</span><span class="s1">&#39;gateway&#39;</span><span class="p">][</span><span class="s1">&#39;type&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&#34;networkobject&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">routeobject</span><span class="p">[</span><span class="s1">&#39;gateway&#39;</span><span class="p">][</span><span class="s1">&#39;name&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">gateway_name</span>
</span></span><span class="line"><span class="cl"><span class="n">routeobject</span><span class="p">[</span><span class="s1">&#39;metricValue&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span>
</span></span><span class="line"><span class="cl"><span class="n">routeobject</span><span class="p">[</span><span class="s1">&#39;ipType&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&#34;IPv4&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">routeobject</span><span class="p">[</span><span class="s1">&#39;type&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&#34;staticrouteentry&#34;</span>
</span></span></code></pre></div><p>Then pass all that into a POST request to create the route object:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">add_url</span> <span class="o">=</span> <span class="n">baseurl</span> <span class="o">+</span> <span class="s2">&#34;/devices/default/routing/virtualrouters/&#34;</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">globalVR</span> <span class="o">+</span> <span class="s2">&#34;/staticrouteentries</span>
</span></span><span class="line"><span class="cl"><span class="n">requests</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="n">add_url</span><span class="p">,</span> <span class="n">headers</span><span class="o">=</span><span class="n">headers</span><span class="p">,</span> <span class="n">json</span><span class="o">=</span><span class="n">routeobject</span><span class="p">)</span>
</span></span></code></pre></div><p>Success? Well not quite yet.</p>
<p>FirePower requires all changes to be deployed (or applied) to the system before they take effect.</p>
<p>So next we need to initiate a deployment task - and periodically check on it. Deployments can take a <em>while</em> to complete, depending on number of changes, processing power of the appliance, etc.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># First send a POST to the deployment endpoint:</span>
</span></span><span class="line"><span class="cl"><span class="n">deploy_url</span> <span class="o">=</span> <span class="n">baseurl</span> <span class="o">+</span> <span class="s2">&#34;/operational/deploy&#34;</span>
</span></span><span class="line"><span class="cl"><span class="n">deploy_response</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="n">deploy_url</span><span class="p">,</span> <span class="n">headers</span><span class="o">=</span><span class="n">headers</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Grab the deployment task UID:</span>
</span></span><span class="line"><span class="cl"><span class="n">deploymentID</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">deploy_response</span><span class="o">.</span><span class="n">text</span><span class="p">)[</span><span class="s1">&#39;id&#39;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Loop while deployment is running:</span>
</span></span><span class="line"><span class="cl"><span class="k">while</span> <span class="n">deployed</span> <span class="ow">is</span> <span class="kc">False</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># Sleep for a few seconds:</span>
</span></span><span class="line"><span class="cl">    <span class="n">sleep</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># Get list of all deployment tasks:</span>
</span></span><span class="line"><span class="cl">    <span class="n">tasklist</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">deploy_url</span><span class="p">)</span><span class="o">.</span><span class="n">text</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">task</span> <span class="ow">in</span> <span class="n">taskList</span><span class="p">[</span><span class="s1">&#39;items&#39;</span><span class="p">]:</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">task</span><span class="p">[</span><span class="s1">&#39;id&#39;</span><span class="p">]</span> <span class="o">==</span> <span class="n">deploymentID</span> <span class="ow">and</span> <span class="n">task</span><span class="p">[</span><span class="s1">&#39;state&#39;</span><span class="p">]</span> <span class="o">==</span> <span class="s1">&#39;DEPLOYED&#39;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;Deployment status is: &#34;</span> <span class="o">+</span> <span class="n">task</span><span class="p">[</span><span class="s1">&#39;state&#39;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">            <span class="n">deployed</span> <span class="o">=</span> <span class="kc">True</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="kc">True</span>
</span></span><span class="line"><span class="cl">        <span class="k">elif</span> <span class="n">task</span><span class="p">[</span><span class="s1">&#39;id&#39;</span><span class="p">]</span> <span class="o">==</span> <span class="n">deploymentID</span> <span class="ow">and</span> <span class="n">task</span><span class="p">[</span><span class="s1">&#39;state&#39;</span><span class="p">]</span> <span class="o">!=</span> <span class="s1">&#39;DEPLOYED&#39;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="c1"># If changes not yet deployed, check again momentarily</span>
</span></span><span class="line"><span class="cl">            <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;Deployment status is: &#34;</span> <span class="o">+</span> <span class="n">task</span><span class="p">[</span><span class="s1">&#39;state&#39;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">            <span class="n">deployed</span> <span class="o">=</span> <span class="kc">False</span>
</span></span></code></pre></div><p>So in the above block, we POST a request to deploy changes. The response of that POST request contains our deployment ID, which we keep to check the status later.</p>
<p>Then the script waits a few seconds, and pulls a list of all deployment tasks. Search through that list for our deployment ID - and check to see if it has been completed yet. If not, wait and run the loop again.</p>
<p>And that&rsquo;s it! Once we get confirmation that our changes have been deployed - we&rsquo;ve now routed traffic over the secondary connection (an LTE modem, in my case).</p>
<h2 id="part-4---fail-back-delete-static-route">Part 4 - Fail-Back (Delete Static Route)</h2>
<p>Okay - this section will be fairly quick. We&rsquo;ve already looked at authenticating, checking if our route already exists, and how to add a new route. So the only thing remaining is removing our route if we wanted to migrate traffic back to the primary connection.</p>
<p>Same logic applies as earlier. If our path monitoring script runs and finds that loss &amp; latency are within the thresholds we set, then we make a call to the firepower module. First we check to ensure there <em>is</em> a route for us to delete, and if so - proceed with deleting it.</p>
<p>Adding a route is a little more work, since we may need to create network objects. However, when we delete the route - we&rsquo;ll just leave those objects on the FirePower box. They&rsquo;ll be there for the next time we need them (which also speeds up deployment times).</p>
<p>To get started, we just need the UID for the route we want to delete.</p>
<p>Remember that code I showed above, where we check to see if the static route exists? And match on our intended subnet / gateway pair? Well, I just made that into a function that will return the UID of the route if it finds it. Easy enough!</p>
<p>Next, we just send an HTTP DELETE to the static routing endpoint - and reference that UID:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">del_url</span> <span class="o">=</span> <span class="n">baseurl</span> <span class="o">+</span> <span class="s2">&#34;/devices/default/routing/virtualrouters/&#34;</span> <span class="o">+</span> \
</span></span><span class="line"><span class="cl">          <span class="bp">self</span><span class="o">.</span><span class="n">globalVR</span> <span class="o">+</span> <span class="s2">&#34;/staticrouteentries/&#34;</span> <span class="o">+</span> <span class="n">route</span><span class="p">[</span><span class="s1">&#39;id&#39;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="n">requests</span><span class="o">.</span><span class="n">delete</span><span class="p">(</span><span class="n">del_url</span><span class="p">,</span> <span class="n">headers</span><span class="o">=</span><span class="n">headers</span><span class="p">)</span>
</span></span></code></pre></div><p>Once that succeeds - we use the same logic as earlier to deploy the changes.</p>
<p>After that, our route is removed &amp; traffic should be flowing over our primary connection again.</p>
<hr>
<p>If it helps anyone - I also threw together a quick diagram to explain the flow of operations here:
<img alt="flow-diagram" loading="lazy" src="/content/images/2020/07/flow-diagram.jpg#center"></p>
<hr>
<p>Well - that&rsquo;s it. This was a fun side project to work on over the past week or two. I hadn&rsquo;t spent much time with the FirePower/FDM APIs just yet. While there was a bit of work in creating all the necessary network objects, the overall process was fairly simple.</p>
<p>It helped tremendously that the FDM API explorer exists, and is available on-box. This utility allows you to see all the available API calls, what parameters they require, and even run test calls from the web UI. This greatly reduced the time needed to figure this out.</p>
<p>Hope this was interesting. If you would like to see the whole project - check out the repo on my GitHub page.</p>
]]></content:encoded>
    </item>
    <item>
      <title>How to: Setting up Google Fi on a Netgear LTE Modem</title>
      <link>https://0x2142.com/how-to-setting-up-google-fi-on-a-netgear-lte-modem/</link>
      <pubDate>Thu, 09 Jul 2020 17:16:31 +0000</pubDate>
      <guid>https://0x2142.com/how-to-setting-up-google-fi-on-a-netgear-lte-modem/</guid>
      <description>Let&amp;rsquo;s walk though how to set up a  Netgear LTE modem to work with Google Fi&amp;rsquo;s cellular service</description>
      <content:encoded><![CDATA[<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
      <iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="allowfullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/809Zd4NQnVo?autoplay=0&amp;controls=1&amp;end=0&amp;loop=0&amp;mute=0&amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"></iframe>
    </div>

<p><sup><em>Note: I may receive commissions for purchases made through links in this post. This is to help support my blog and does not have any impact on my recommendations.</em></sup></p>
<p>It&rsquo;s been a crazy couple of months recently. With what began as a temporary lockdown &amp; mandatory work-from-home has now become a question of &ldquo;Will we ever return to the office&rdquo;?</p>
<p>Luckily I have a decent home office setup, as my job is already primarily work from home. That being said - it&rsquo;s more important than ever to have a stable, reliable internet connection available. Can&rsquo;t run the risk of being in an important meeting with a customer and drop from the video conference (or have audio issues, etc).</p>
<p>Needless to say, my internet provider is far from perfect. While it does perform reasonably well most days, the spikes in latency &amp; packet loss have increased substantially with everyone in the neighborhood working from home.</p>
<p>I&rsquo;ve been debating for a while on whether or not to pick up a cellular modem. Originally I had planned on having one handy for a complete internet outage (which happens). But more recently I began to wonder if it might be worth it for routing around my primary provider when the connectivity is poor.</p>
<p>To accomplish this, I decided to use <a href="https://g.co/fi/r/KRT0VY">Google Fi</a>. I&rsquo;ve already used the service as my cellular provider for a number of years now and I&rsquo;ve been extremely pleased with the service. One of the awesome benefits they offer for subscribers is free data-only SIM cards. So I could pay nothing for the SIM card itself (no plan/recurring costs either) - then only pay for data as I use it.</p>
<p>First, I went ahead and tested what typical latency &amp; performance was over my cell connection. Occasionally my home internet provider would see latency spikes up to 1200-1800ms. Checking the cell connection - it seemed pretty stable in the 200-300ms range. Still pretty high, but much more bearable than ~1200ms. Seemed like it should work reasonably well for what I wanted.</p>
<p>Then, I had to double check compatability. Google Fi runs over multiple carriers on the backend - as long as you&rsquo;re using a Fi-compatible device. If not, it seems they default to only using T-Mobile&rsquo;s network. So in that case, Fi requires that our device supports LTE bands 2 &amp; 4 at a minimum. The Netgear LB1120/1121 modems do, so we&rsquo;re good there.</p>
<p>Next, I went ahead and ordered a <a href="https://amzn.to/3flccHi">NetGear LB1121</a> LTE Cellular modem. I opted for the power over ethernet model, since I already had a Cat5 run over to where the modem would be placed. The switch I&rsquo;m using is also being backed up by a UPS, so in the event of a power outage the LTE modem would stay online.</p>
<p>Finally - I placed my order for the Google Fi SIM card. Easy process - $0 for the SIM, $0 for shipping, and it arrived in only a few days. As an additional note - the modem requires a micro-SIM, but Fi provides nano-SIM cards. I also had to pick up a cheap adapter kit to make this work.</p>
<hr>
<h1 id="getting-the-modem-set-up">Getting the Modem Set up</h1>
<p>Once the modem &amp; SIM card arrive, it&rsquo;s time to get started. This will be a fairly quick and straightforward process.</p>
<p>On the bottom of the LTE modem, the device will list it&rsquo;s default IP address &amp; the password to log in. Take note of that, as you&rsquo;ll need it later.</p>
<p>Also on the bottom is the slot to insert the SIM card. Remove the cover, insert your SIM card into the micro-SIM adapter, then insert into the cellular modem.</p>
<p>Next, go ahead and power on the modem &amp; get it plugged into a PC.</p>
<p>Once the modem boots up - we should be able to reach it via a web browser @ 192.168.5.1.</p>
<p>Log in with the credentials from the bottom of the modem.</p>
<p><img alt="netgear-landing-page" loading="lazy" src="/content/images/2020/07/netgear-landing-page.PNG#center"></p>
<p>Upon landing on the main page, you may see that the modem auto-connects to T-Mobile&rsquo;s network. While we might be able to use this as-is, ideally we need to change our connection to specifically use Google Fi&rsquo;s information.</p>
<p>Head over to <strong>Settings</strong> &gt; <strong>General</strong> &gt; <strong>APN</strong>:</p>
<p><img alt="netgear-apn" loading="lazy" src="/content/images/2020/07/netgear-apn.PNG#center"></p>
<p>Click <strong>Add</strong> to create a new cellular profile</p>
<p><img alt="netgear-add-gfi" loading="lazy" src="/content/images/2020/07/netgear-add-gfi.PNG#center"></p>
<p>For the network <strong>Name</strong>, enter <strong>Google Fi</strong>. For the <strong>APN</strong> enter <strong>h2g2</strong>.</p>
<p>Click <strong>Save</strong> to add the profile</p>
<p>Then make sure to select the correct radio button to activate the new profile:</p>
<p><img alt="netgear-activate-profile" loading="lazy" src="/content/images/2020/07/netgear-activate-profile.PNG#center"></p>
<p>At this point, I would recommend deleting the old/default T-Mobile profile. I would also suggest rebooting the device to force it to switch to Google Fi.</p>
<p>If all is well - You&rsquo;ll log back in and see that the modem has now connected to the appropriate network:</p>
<p><img alt="netgear-gfi-connected" loading="lazy" src="/content/images/2020/07/netgear-gfi-connected.PNG#center"></p>
<p><em>Note: I&rsquo;ve had some issues where the carrier name doesn&rsquo;t display correctly. It may take a few minutes to finally display &ldquo;Google Fi&rdquo;. However, at this point you should be connected to the correct network and be able to use it with no issues</em></p>
<h1 id="additional-settings">Additional Settings</h1>
<p>One other thing that may be worth noting. Depending on how you&rsquo;re using the modem, you may want to change the way the modem operates.</p>
<p>Let&rsquo;s go ahead and check out a few options on the LAN settings page. This can be found by going to <strong>Settings</strong> &gt; <strong>Advanced</strong> &gt; <strong>LAN</strong>.</p>
<p><img alt="netgear-lan-opts" loading="lazy" src="/content/images/2020/07/netgear-lan-opts.PNG#center"></p>
<p>By default, the modem operates in <em>router</em> mode. What this means is that the modem terminates the connection from Google Fi - and acts as a gateway between your devices &amp; the carrier network.</p>
<p>You would want to use <em>router</em> mode if you have multiple devices you want to use with the modem &amp; you do not have an additional router or firewall. In this case, the modem will handle providing IP addresses to the client devices. In addition, it will act as a firewall and allow client devices to the internet, while blocking any external devices from accessing the clients directly.</p>
<p>The other available mode is <em>bridge</em> mode. In this case, the modem operates as a pass-through device &amp; assumes that there is another device behind the modem that is providing the routing/firewalling functionality.</p>
<p>You may want to use <em>bridge</em> mode if you already have a router or firewall you want to use - and you want to treat the modem as a second internet connection. When the modem connects to the provider, it will automatically pass the public IP address &amp; configuration straight through to whatever device is plugged into it.</p>
<hr>
<p>If you&rsquo;re interested in how I configured the auto-failover to the cellular modem - check back in a bit. I wrote some custom automation to monitor my primary connection &amp; conditionally inject a route over the LTE modem.</p>
<p>I&rsquo;m just wrapping up some of that, and should have something posted here shortly!</p>
]]></content:encoded>
    </item>
    <item>
      <title>How To: Convert Catalyst 9100 AP to Embedded WLC</title>
      <link>https://0x2142.com/how-to-convert-catalyst-9100-ap-to-embedded-wlc/</link>
      <pubDate>Tue, 05 May 2020 16:19:35 +0000</pubDate>
      <guid>https://0x2142.com/how-to-convert-catalyst-9100-ap-to-embedded-wlc/</guid>
      <description>A tutorial for converting a Cisco 9100 series wireless access point to host an embedded controller</description>
      <content:encoded><![CDATA[<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
      <iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="allowfullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/NBt370eiQ3I?autoplay=0&amp;controls=1&amp;end=0&amp;loop=0&amp;mute=0&amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"></iframe>
    </div>

<p>Hey there! First thing&rsquo;s first - Hope all is well with everyone. The past few months have seen all sorts of craziness going on in the world. I&rsquo;ve been lucky in the sense that my current job role was already well set up to make an easy transition to working from home all the time. That being said, I know it hasn&rsquo;t been easy for everyone - and I know quite a few people who have lost their jobs, etc.</p>
<p>Second thing! As I&rsquo;m sure you may have already seen above - I opted to spend some of my new-found free time trying out a new format. I&rsquo;ve had a couple of ideas in the past for making short videos, but never forced myself to sit down and give it a shot. So here we are - after about a month of on-and-off work - I finally have something to share. Please give it a look if you&rsquo;re interested, and I would appreciate any comments &amp; feedback. I still have a few other ideas - so if this one goes well I may pursue producing a few more of these.</p>
<p>Okay - Now onto the real content!</p>
<hr>
<p>A few months ago I had the chance to pick up a pair of Cisco Catalyst 9100 series access points from work. My home network has been running on Ubiquiti APs for years - but they&rsquo;re getting old and I desperately needed to replace them. So along comes the Catalyst 9100 APs, which are capable of supporting 802.11ax clients - and why not take the time to upgrade &amp; future proof? I needed some practice anyways, as I have a few customers at work that I think will be interested in these in the near future. I ended up with two 9120AXI APs.</p>
<p>So in the process of trying to dive on the opportunity to play with something new - I completely missed the fact that the 9100 APs have two different product SKUs. One which ships the AP pre-configured with the standard lightweight AP code that you might use if you had an external wireless LAN controller (WLC). And a second SKU that ships the AP with the Catalyst 9800 Embedded WLC (eWLC) software loaded. Of course, I grabbed the lightweight APs without checking.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Product SKUs (Example, using 9120AXI):
</span></span><span class="line"><span class="cl"> - Standard Lightweight AP: C9120AXI
</span></span><span class="line"><span class="cl"> - Pre-load with Embedded WLC: C9120AXI-EWC
</span></span></code></pre></div><p>I wrote in a previous blog about getting <a href="/how-to-catalyst-9800-mac-filtering/">MAC address filtering</a> set up on the Catalyst 9800 WLC. When I wrote that blog I was actually using the C9800-CL, which is a virtual machine version of the Catalyst 9800 controller software. I was originally excited to run the controller as a VM and not need a hardware appliance - but then got to thinking that maybe I should try and save VM resources as well. Which led me to looking at the 9800 eWLC.</p>
<hr>
<h2 id="finding-the-software-image">Finding the Software Image</h2>
<p>In order to convert an existing lightweight access point to one running the embedded WLC software - we first need to grab a copy of the software images from Cisco.com. Search for the model of your 9100 access point (in my case, the 9120AXI).</p>
<p>You&rsquo;ll see two options for Software Type - and it may not immediately be obvious - but we&rsquo;ll need to look under IOS XE Software to find the eWLC images:</p>
<p><img alt="image" loading="lazy" src="/content/images/2020/05/image.png#center"></p>
<p>Then we&rsquo;ll grab the EWC AP image bundle. In my case, I was waiting on a specific feature set that wasn&rsquo;t available until 17.x - so I downloaded the 17.2.1 software:</p>
<p><img alt="image" loading="lazy" src="/content/images/2020/05/image-1.png#center"></p>
<p>Okay - after we&rsquo;ve done that - let&rsquo;s drop everything onto a server/laptop/etc which has console connectivity to our AP and a running TFTP server.</p>
<p>Once you un-zip the contents of that AP image bundle, you&rsquo;ll notice there are quite a number of files. We&rsquo;ll only need two of them - one image to load onto the AP itself, and one that will get loaded for the WLC software container. Within the image bundle, there will be a <strong>readme.txt</strong> file that will tell you which image to use with your AP:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">ap1g5 : AP1815, AP154x
</span></span><span class="line"><span class="cl">ap1g4 : AP180x, AP183x, AP185x
</span></span><span class="line"><span class="cl">ap1g7 : C9115, C9120
</span></span><span class="line"><span class="cl">ap1g6 : C9117
</span></span><span class="line"><span class="cl">ap1g6a : C9130
</span></span><span class="line"><span class="cl">ap3g3 : AP380x, AP280x, AP156x
</span></span></code></pre></div><p>So in my case, I would use the file named <strong>ap1g7</strong> since I had the 9120 APs. In addition, you should also see a file named <strong>C9800-AP-iosxe-wlc.bin</strong>which we&rsquo;ll need to load the controller.</p>
<p>What&rsquo;s with that second image? Well - the Catalyst 9100 APs include a feature called Application Hosting (also found on some of the Catalyst 9000 series switches). This is equivalent to running a Linux container or Docker container directly on the AP hardware. At time of writing, this is only available for the embedded WLC software. However,  there will be a future software update that will allow you to provision other software containers as well (according to the data sheet).</p>
<h2 id="converting-the-access-point">Converting the Access Point</h2>
<p>Now we can get started on the actual conversion process. If it&rsquo;s a new AP, we can just go ahead and boot it up with a console cable connected. If it&rsquo;s already running something, you&rsquo;ll likely want to factory reset the AP first. You can find detailed instructions <a href="https://www.cisco.com/c/en/us/support/docs/wireless/embedded-wireless-controller-on-catalyst-access-points/215303-embedded-wireless-controller-conversion.html#anc7">here</a>, but a quick summary - power off the AP, hold the <strong>mode</strong> button while plugging the AP back in, and keep the <strong>mode</strong> button held for at least 20-30 seconds. If you&rsquo;re logged into the console during this time - you&rsquo;ll actually see the AP counting how long you&rsquo;ve held the button for. Once that counter shows at least 20 seconds, release the <strong>mode</strong>button and allow the AP to reboot.</p>
<p>Once the AP is booted. The default login is <strong>Cisco</strong> / <strong>Cisco</strong>. The enable password is also <strong>Cisco</strong>. You may also want to quickly issue a <strong>show version</strong>, and take note of the current software version running on the AP (hint: we&rsquo;ll need that later).</p>
<p>Next - it&rsquo;s important to note that <em>after</em> we convert the AP - our default CLI will actually be the WLC, <strong>not</strong> the AP (even when connected via console). So we should configure a hostname and IP address for the AP now:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">0xAP# capwap ap hostname &lt;hostname&gt;
</span></span><span class="line"><span class="cl">0xAP# capwap ap ip &lt;ip-addr&gt; &lt;netmask&gt; &lt;gateway&gt;
</span></span></code></pre></div><p>Then we can load the new AP image and  WLC image. Depending on which software version you&rsquo;re running today, there is a different command to load the image:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">0xAP# ! If you&#39;re running software 8.9 or lower, use the following:
</span></span><span class="line"><span class="cl">0xAP# ap-type mobility-express &lt;TFTP path to AP image&gt; &lt;TFTP path to WLC image&gt;
</span></span><span class="line"><span class="cl">0xAP# ! If you&#39;re running anything above 8.9, use the following:
</span></span><span class="line"><span class="cl">0xAP# ap-type ewc-ap &lt;TFTP path to AP image&gt; &lt;TFTP path to WLC image&gt;
</span></span></code></pre></div><p>Once those commands are submitted, the AP will begin copying the software from the TFTP server. The AP will automatically reboot after the image load is completed.</p>
<p>Quick note: For one of my APs, the WLC software didn&rsquo;t load correctly - and when my AP rebooted I was left with an error that said &ldquo;EWC-AP in Recovery Mode&rdquo;. Re-copying the WLC image fixed it without much trouble. If this happens, the AP will print out the command to re-image the WLC software, but I&rsquo;ll also put it here for reference:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">0xAP# ! If you end up in &#34;EWC-AP Recovery Mode&#34;, run the following:
</span></span><span class="line"><span class="cl">0xAP# archive download-sw ewc-ap &lt;TFTP path to WLC image&gt;
</span></span></code></pre></div><p>Okay - Once our AP has come back from loading up all the new software, we can get on with a bit of minimal config required to access the WLC web UI.</p>
<p>First, we&rsquo;ll configure the WLC hostname &amp; our local user account. This can be switched over later to your choice of directory service:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">0xC9800eWLC# config t
</span></span><span class="line"><span class="cl">0xC9800eWLC(config)# hostname &lt;hostname&gt;
</span></span><span class="line"><span class="cl">0xC9800eWLC(config)# user-name &lt;admin username&gt;
</span></span><span class="line"><span class="cl">0xC9800eWLC(config-user-name)# password &lt;admin password&gt;
</span></span><span class="line"><span class="cl">0xC9800eWLC(config-user-name)# privilege 15
</span></span></code></pre></div><p>Next we&rsquo;ll also provide the WLC with the administrative credentials used to manage the connected APs:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">0xC9800eWLC(config)# ap profile &lt;profile-name&gt;
</span></span><span class="line"><span class="cl">0xC9800eWLC(config-ap-profile)# mgmtuser username &lt;AP admin user&gt; password 0 &lt;AP admin password&gt; secret 0 &lt;AP admin secret&gt;
</span></span></code></pre></div><p>After that, we&rsquo;ll go ahead and configure our basic network settings. This will be the IP address &amp; gateway info that will be used to connect to the WLC web UI and SSH:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">0xC9800eWLC(config)# interface gigabit 0 
</span></span><span class="line"><span class="cl">0xC9800eWLC(config-if)# ip address &lt;managemnt IP&gt; &lt;Network mask&gt;
</span></span><span class="line"><span class="cl">0xC9800eWLC(config-if)# no shut
</span></span><span class="line"><span class="cl">0xC9800eWLC(config)# ip default-gateway &lt;Gateway IP address&gt;
</span></span></code></pre></div><p>Lastly - we&rsquo;ll need to actually enable the web server. In my case, I opted to not enable the standard HTTP server. I only enabled the encrypted SSL-enabled web server:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">0xC9800eWLC(config)# ! I only enabled the HTTPS server:
</span></span><span class="line"><span class="cl">0xC9800eWLC(config)# ip http secure-server
</span></span><span class="line"><span class="cl">0xC9800eWLC(config)# ! If you wanted to enable the plain-text / unencrypted web server:
</span></span><span class="line"><span class="cl">0xC9800eWLC(config)# ip http server
</span></span><span class="line"><span class="cl">0xC9800eWLC(config)# 
</span></span><span class="line"><span class="cl">0xC9800eWLC(config)# ! Finally - Save the config
</span></span><span class="line"><span class="cl">0xC9800eWLC(config)# exit
</span></span><span class="line"><span class="cl">0xC9800eWLC# wr mem
</span></span></code></pre></div><p>When we save our config for this first time, the AP will verify that the initial configuration pieces have been completed. There is a bit of background cleanup that is performed - which removes any factory config that assisted with provisioning. Once that&rsquo;s all done - we&rsquo;re free to log into the web UI!</p>
<h2 id="embedded-wlc-web-interface">Embedded WLC Web Interface</h2>
<p>I won&rsquo;t spend a lot of time here, as there are far too many things to cover with the new 9800 series controllers. However, I did want to point out a few things that stand out regarding the Embedded WLC.</p>
<p>When we log into our WLC web UI - we&rsquo;ll be able to use the username &amp; password combo that we configured previously. Then we&rsquo;ll be dropped into our WLC dashboard.</p>
<p><img alt="image" loading="lazy" src="/content/images/2020/05/image-2.png#center"></p>
<blockquote>
<p>*Note: Screenshot taken a bit after I did my initial config. This has been running a bit now&hellip;</p></blockquote>
<p>If we click on the number under the <strong>Access Points</strong> heading, we&rsquo;ll be taken to a quick monitoring view of the current connected APs:</p>
<p><img alt="image" loading="lazy" src="/content/images/2020/05/image-3.png#center"></p>
<p>Here we can see the APs we have configured, along with their IP address &amp; status info. We will also see what our <strong>Current Active</strong> WLC controller is, and what our <strong>Current Standby</strong> / <strong>Preferred Active</strong> if we have either configured.</p>
<p>By default, if we boot up a second AP running the embedded WLC software, it will automatically join the WLC cluster as the secondary node. Any WLC config/settings will be copied, then it&rsquo;s ready in case the primary controller fails. In the event of a failure, the secondary WLC will take over - and be accessible using the same IP &amp; login info that we used on the primary.</p>
<p>In my case, I&rsquo;ve also configured one of my APs as a preferred primary controller. For me, this AP is connected to a switch that has a short battery backup - so it&rsquo;s less likely to experience failure. This option can be configured on the individual AP itself. In the left-hand menu, drop into the <strong>Configuration</strong> section, then click on <strong>Access Points</strong> under the <strong>Wireless</strong> header. We&rsquo;ll see a very similar screen to the AP monitoring screen from above. Click on the AP that we want to make our preferred primary, then jump over to the <strong>Advanced</strong> tab. There will be a checkbox for <strong>Preferred Controller</strong>:</p>
<p><img alt="image" loading="lazy" src="/content/images/2020/05/image-4.png#center"></p>
<h2 id="wlc-image-repository">WLC Image Repository</h2>
<p>Last thing - and this one is important. Normally the WLC will have dedicated storage to keep AP software images, which it distributes to new APs when they come online. Unfortunately, while we gain the flexibility and limited footprint of the embedded WLC - we also lose that dedicated storage space. As you might imagine, storage on the AP is limited.</p>
<p>So we&rsquo;ll need to make sure that the WLC has an external image repository that it can use. This configuration can be done via teh web UI and CLI. I&rsquo;ll cover both very quickly here.</p>
<p>From the web UI -  We&rsquo;ll go to <strong>Administration</strong> &gt; <strong>Software Management</strong>:</p>
<p><img alt="image" loading="lazy" src="/content/images/2020/05/image-5.png#center"></p>
<p>Here we&rsquo;ll see our options for where to get images, as well as an inventory of current APs &amp; their images. In the <strong>Mode</strong> drop-down, we&rsquo;ll have the option of tftp, sftp, CCO, and Desktop. TFTP / SFTP are what we&rsquo;re used to. With <strong>Desktop</strong>, we would just upload images directly from our laptop / PC. Interestingly though, <strong>CCO</strong> allows us to provide our Cisco.com credentials - and the controller can pull images directly from Cisco. We&rsquo;ll even have the option to enable automatic software downloads - and specify whether we want to auto-download the latest software release, or only the latest <em>recommended</em> release.</p>
<p>On the CLI side of things - we can accomplish the same using the following commands on our WLC CLI:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">0xC9800eWLC(config)# wireless profile image-download &lt;profile name&gt;
</span></span><span class="line"><span class="cl">0xC9800eWLC(config-wireless-image-download-profile)# image-download mode tftp
</span></span><span class="line"><span class="cl">0xC9800eWLC(config-wireless-image-download-profile-tftp)# tftp-image-server &lt;IP address&gt;
</span></span><span class="line"><span class="cl">0xC9800eWLC(config-wireless-image-download-profile-tftp)# tftp-image-path &lt;path to image files&gt;
</span></span></code></pre></div><p>With that, any new APs that join our WLC should be able to auto-load the software necessary.</p>
<hr>
<p>Thanks for reading!</p>
]]></content:encoded>
    </item>
    <item>
      <title>How to: Catalyst 9800 MAC Filtering</title>
      <link>https://0x2142.com/how-to-catalyst-9800-mac-filtering/</link>
      <pubDate>Tue, 12 Nov 2019 15:35:07 +0000</pubDate>
      <guid>https://0x2142.com/how-to-catalyst-9800-mac-filtering/</guid>
      <description>A tutorial on configuring MAC address filtering on a Cisco 9800 WLC</description>
      <content:encoded><![CDATA[<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
      <iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="allowfullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/rWupjgsF0HM?autoplay=0&amp;controls=1&amp;end=0&amp;loop=0&amp;mute=0&amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"></iframe>
    </div>

<p><strong>Update 2020 / 05 / 19</strong> - I&rsquo;ve added a video above that walks through the steps detailed in this blog post.</p>
<blockquote>
<p>If you&rsquo;re using the &lsquo;Basic&rsquo; Wireless setup, you may see an error when trying to apply the policy: &ldquo;switch 1 dbm wireless Use of default ACL preauth v4 is not permitted&rdquo;</p>
<p>If you come across this error, it&rsquo;s a known bug (<a href="https://quickview.cloudapps.cisco.com/quickview/bug/CSCvt18875">CSCvt18875</a>) specific to only the &lsquo;Basic&rsquo; setup wizard (which is what I used in this post below). If so, check out the video above which walks through the &lsquo;Advanced&rsquo; setup and bypasses this error.</p></blockquote>
<hr>
<p>I&rsquo;ve been spending a bit of time over the past few weeks building up a wireless lab. Trying to get a good understanding of how the new Catalyst 9800 wireless controller works, and how it differs from some of the previous iterations.</p>
<p>In order to play around with the new controller, I decided to try to build a new configuration that mimics my current home wireless. Today I am using Ubiquiti APs, which come with their own free controller software. Most of my current config is fairly straightforward - a few SSIDs, two APs, and a guest network with captive portal. One of my SSIDs is dedicated to any IoT devices and is more restrictive than the other networks. This network uses both a pre-shared key for authentication as well as MAC-based filtering.</p>
<p>In this post - we&rsquo;ll walk through how to set up a new SSID with client MAC filtering.</p>
<p><em>Note: This was written using Catalyst 9800-CL version 16.12.1s. APs are configured in flexconnect with local authentication (no AAA, ISE, etc)</em></p>
<hr>
<p>While this post is not focused on in-depth WLAN config, we will start by quickly setting up a new network.</p>
<p>Once you get logged into the controller - we&rsquo;ll click on the <strong>Wireless Setup</strong> icon in the upper right-hand side. Then drop down to the <strong>Basic</strong> option:</p>
<p><img alt="image" loading="lazy" src="/content/images/2019/11/New-wireless-net-01.jpg#center"></p>
<p>This takes us through a pretty quick and easy wizard to set up our new location &amp; wireless networks. At first, we will have no locations configured - so we will click <strong>Add:</strong></p>
<p><img alt="image" loading="lazy" src="/content/images/2019/11/New-wireless-net-02-.jpg#center"></p>
<p>We&rsquo;ll start off building our location by giving it a name and description. These are used for some naming of policy objects within the WLC, so make sure to use a name that makes sense.</p>
<p>In my case, I&rsquo;m also going with a flexconnect deployment - so we&rsquo;ll select that option and also provide the AP native VLAN.</p>
<p><img alt="image" loading="lazy" src="/content/images/2019/11/New-wireless-net-03.png#center"></p>
<p>Next, we&rsquo;ll click over to the <strong>Wireless Networks</strong> tab. This is where we will create our WLAN and apply the initial configuration. We don&rsquo;t have any networks yet, so click <strong>Add</strong></p>
<p><img alt="image" loading="lazy" src="/content/images/2019/11/New-wireless-net-04.jpg#center"></p>
<p>The two primary things we need to address are highlighted in red below. We need to create a WLAN and assign it to a VLAN. Let&rsquo;s start with the WLAN by clicking <strong>Define new.</strong></p>
<p><img alt="image" loading="lazy" src="/content/images/2019/11/New-wireless-net-05.png#center"></p>
<p>On the <strong>General</strong> tab, we&rsquo;ll give this WLAN a profile name and a SSID.</p>
<p><img alt="image" loading="lazy" src="/content/images/2019/11/New-wireless-net-06.jpg#center"></p>
<p>Next, we&rsquo;ll hop on over to the <strong>Security</strong> tab, and focus on the <strong>Layer 2</strong> sub-tab. The first thing I want to point out - is that at this point, we will not be enabling the <strong>MAC Filtering</strong> checkbox. We&rsquo;ll need some additional config first, then come back to this later.</p>
<p><img alt="image" loading="lazy" src="/content/images/2019/11/New-wireless-net-07.jpg#center"></p>
<p>Scroll down to the bottom of the window and there will be some settings for your authentication. By default, <strong>802.1x</strong> will be enabled. This post won&rsquo;t cover how to setup/configure that. Instead, we&rsquo;ll be deselecting <strong>802.1x</strong> and checking the box for <strong>PSK.</strong> Then a text field will appear for us to enter the <strong>Pre-Shared Key</strong>.</p>
<p><img alt="image" loading="lazy" src="/content/images/2019/11/New-wireless-net-08.jpg#center"></p>
<p>Once we click <strong>Apply to Device</strong>, we&rsquo;ll finish up by assigning our <strong>VLAN or VLAN Group</strong>. In this case, I have already created a VLAN named <strong>IoT</strong>. If you haven&rsquo;t created a VLAN yet, you can do so by going to <strong>Configuration</strong> &gt; <strong>Layer 2</strong> &gt; <strong>VLAN.</strong> Then add a new VLAN under the <strong>VLAN</strong>tab.</p>
<p><img alt="image" loading="lazy" src="/content/images/2019/11/New-wireless-net-09.png#center"></p>
<p>Click <strong>Add</strong>, then we&rsquo;ll be back to the wizard and see the new WLAN we just created.</p>
<p><img alt="image" loading="lazy" src="/content/images/2019/11/New-wireless-net-10.jpg#center"></p>
<p>In order to finish up with the wizard, we just need to assign our Access Points. Click on the <strong>AP Provisioning</strong> tab. If you have already configured APs to join to this controller, you will see them on the left side under <strong>Available APs</strong>. Check which ones to apply this WLAN to, then click the arrow to move them to <strong>APs on this location.</strong></p>
<p><img alt="image" loading="lazy" src="/content/images/2019/11/New-wireless-net-11.jpg#center"></p>
<p>Click <strong>Apply</strong>, and that will finalize all of the configuration we just did - then drop us back to the <strong>Wireless Setup</strong> page.</p>
<p><img alt="image" loading="lazy" src="/content/images/2019/11/New-wireless-net-12.jpg#center"></p>
<p>Okay - Now that we have that completed, we can move onto creating our MAC filtering policies.</p>
<p>Back in the menu - Let&rsquo;s go to <strong>Configuration</strong> &gt; <strong>Security</strong> &gt; <strong>AAA</strong></p>
<p><img alt="image" loading="lazy" src="/content/images/2019/11/mac-auth-01.jpg#center"></p>
<p>In this section - we first need to create an Authorization policy. Select the <strong>AAA Method List</strong> tab, then <strong>Authorization</strong>, then <strong>Add</strong> to create the new policy.</p>
<p><img alt="image" loading="lazy" src="/content/images/2019/11/mac-auth-02.jpg#center"></p>
<p>In here we&rsquo;ll specify a name, then select <strong>Type: network</strong>, and <strong>Group Type: local</strong>. Then go ahead and <strong>Apply to Device</strong></p>
<p><img alt="image" loading="lazy" src="/content/images/2019/11/mac-auth-03.jpg#center"></p>
<p>Once we have that, let&rsquo;s go over to the <strong>AAA Advanced</strong> tab, and click <strong>Add</strong> in the <strong>Attribute List Name</strong> section.</p>
<p><img alt="image" loading="lazy" src="/content/images/2019/11/mac-auth-04.jpg#center"></p>
<p>Here we need to provide the SSID we want our MAC policy to apply to. Under <strong>Attribute Type</strong>, select <strong>SSID.</strong> Then under <strong>Attribute Value</strong>, select the target SSID that our policy will be tied to.</p>
<p><img alt="image" loading="lazy" src="/content/images/2019/11/mac-auth-05.jpg#center"></p>
<p>Don&rsquo;t forget to click <strong>Save</strong> on the attribute before clicking <strong>Apply to Device</strong>!</p>
<p><img alt="image" loading="lazy" src="/content/images/2019/11/mac-auth-06.jpg#center"></p>
<p>Time to input our list of device MAC addresses! Drop into the <strong>Device Authentication</strong> section, and click <strong>Add</strong> - or upload a CSV file if you have one.</p>
<p><img alt="image" loading="lazy" src="/content/images/2019/11/mac-auth-07.jpg#center"></p>
<p>Input the device <strong>MAC Addrees</strong> and select the <strong>Attribute List Name</strong> that we configured just a minute ago. Then <strong>Apply to Device</strong></p>
<p><img alt="image" loading="lazy" src="/content/images/2019/11/mac-auth-08-1.jpg#center"></p>
<p>After that - we should have our completed list of MAC addresses which will be permitted to join our wireless network. All we need to do is go back to our WLAN and enable MAC filtering.</p>
<p><img alt="image" loading="lazy" src="/content/images/2019/11/mac-auth-09.jpg#center"></p>
<p>Let&rsquo;s go to <strong>Configuration</strong> &gt; <strong>Tags &amp; Profiles</strong> &gt; <strong>WLANs</strong></p>
<p><img alt="image" loading="lazy" src="/content/images/2019/11/config-wlans-01.jpg#center"></p>
<p>This should give us the list of any configured WLANS - including the one we created earlier. Go ahead and click on it to edit.</p>
<p><img alt="image" loading="lazy" src="/content/images/2019/11/config-wlans-02.jpg#center"></p>
<p>Next, we&rsquo;ll jump straight to the <strong>Layer 2</strong> section under the <strong>Security</strong> tab. Check the box for <strong>MAC Filtering</strong> and select the <strong>Authorization List</strong> we created from the drop down.</p>
<p><img alt="image" loading="lazy" src="/content/images/2019/11/config-wlans-03.jpg#center"></p>
<p>And we&rsquo;re done! Clients that want to join our newly created SSID will need the pre-shared key we configured, but they will also need to be manually added to our MAC address filter as well.  While this isn&rsquo;t a perfect security measure since MAC addresses can be easily spoofed - it does add an extra layer of protection to keep unauthorized devices from inadvertently being able to join this specific WLAN.</p>
<hr>
<p>In the event that a client is NOT on the authorized list, you may see the following logs in a client debug:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">2019/10/25 22:26:12.327 {wncd_x_R0-0}{1}: &amp;#91;client-orch-sm] &amp;#91;22573]: (note): MAC: aaaa.aaaa.aaaa  Association received. BSSID aaaa.aaaa.b34d, old BSSID 0000.0000.0000, WLAN SuperSecret, Slot 1 AP aaaa.aaaa.b340, AP_3802-1F01
</span></span><span class="line"><span class="cl">2019/10/25 22:26:12.327 {wncd_x_R0-0}{1}: &amp;#91;client-orch-state] &amp;#91;22573]: (note): MAC: aaaa.aaaa.aaaa  Client state transition: S_CO_INIT -&gt; S_CO_ASSOCIATING
</span></span><span class="line"><span class="cl">2019/10/25 22:26:12.328 {wncd_x_R0-0}{1}: &amp;#91;client-orch-state] &amp;#91;22573]: (note): MAC: aaaa.aaaa.aaaa  Client state transition: S_CO_ASSOCIATING -&gt; S_CO_MACAUTH_IN_PROGRESS
</span></span><span class="line"><span class="cl">2019/10/25 22:26:12.328 {wncd_x_R0-0}{1}: &amp;#91;client-auth] &amp;#91;22573]: (note): MAC: aaaa.aaaa.aaaa  MAB Authentication initiated. Policy VLAN 0, AAA override = 0, NAC = 0
</span></span><span class="line"><span class="cl">2019/10/25 22:26:12.329 {wncd_x_R0-0}{1}: &amp;#91;ewlc-infra-evq] &amp;#91;22573]: (note): Authentication Success. Resolved Policy bitmap:11 for client aaaa.aaaa.aaaa 
</span></span><span class="line"><span class="cl">2019/10/25 22:26:12.329 {wncd_x_R0-0}{1}: &amp;#91;ewlc-infra-evq] &amp;#91;22573]: (ERR): SANET_AUTHC_FAILURE - AAA Server Down username ac37434a673a, audit session id 000000000000006B3E9D2A55, 
</span></span><span class="line"><span class="cl">2019/10/25 22:26:12.331 {wncd_x_R0-0}{1}: &amp;#91;client-orch-state] &amp;#91;22573]: (note): MAC: aaaa.aaaa.aaaa  Client state transition: S_CO_MACAUTH_IN_PROGRESS -&gt; S_CO_ASSOCIATING
</span></span><span class="line"><span class="cl">2019/10/25 22:26:12.331 {wncd_x_R0-0}{1}: &amp;#91;dot11] &amp;#91;22573]: (ERR): MAC: aaaa.aaaa.aaaa  Failed to assoc failure tr state entry. Incorrect validation status value :1
</span></span><span class="line"><span class="cl">2019/10/25 22:26:12.331 {wncd_x_R0-0}{1}: &amp;#91;dot11] &amp;#91;22573]: (ERR): MAC: aaaa.aaaa.aaaa  Dot11 update co assoc fail. Sent assoc failure to CO. delete reason: 9, CO_CLIENT_DELETE_REASON_MAB_FAILED
</span></span><span class="line"><span class="cl">2019/10/25 22:26:12.331 {wncd_x_R0-0}{1}: &amp;#91;client-orch-sm] &amp;#91;22573]: (note): MAC: aaaa.aaaa.aaaa  Client delete initiated. Reason: CO_CLIENT_DELETE_REASON_MAB_FAILED, fsm-state transition
</span></span></code></pre></div><p>On the opposite side, when a client is successfully able to pass MAC authentication - the logs will show the following:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">2019/10/25 21:25:53.148 {wncd_x_R0-0}{1}: &amp;#91;client-auth] &amp;#91;22573]: (note): MAC: aaaa.aaaa.aaaa  MAB Authentication initiated. Policy VLAN 0, AAA override = 0, NAC = 0
</span></span><span class="line"><span class="cl">2019/10/25 21:25:53.150 {wncd_x_R0-0}{1}: &amp;#91;ewlc-infra-evq] &amp;#91;22573]: (note): Authentication Success. Resolved Policy bitmap:11 for client aaaa.aaaa.aaaa 
</span></span><span class="line"><span class="cl">2019/10/25 21:25:53.151 {wncd_x_R0-0}{1}: &amp;#91;client-auth] &amp;#91;22573]: (note): MAC: aaaa.aaaa.aaaa  MAB Authentication success.
</span></span><span class="line"><span class="cl">2019/10/25 21:25:53.151 {wncd_x_R0-0}{1}: &amp;#91;client-orch-state] &amp;#91;22573]: (note): MAC: aaaa.aaaa.aaaa  Client state transition: S_CO_MACAUTH_IN_PROGRESS -&gt; S_CO_ASSOCIATING
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">2019/10/25 21:30:08.626 {wncd_x_R0-0}{1}: &amp;#91;client-orch-sm] &amp;#91;22573]: (debug): MAC: aaaa.aaaa.aaaa  Received Dot11 association request. Processing started,SSID: SuperSecret2, Policy profile: Home_WLANID_3, AP Name: AP_3802-3F01, Ap Mac Address: aaaa.aaaa.c9a0 BSSID MAC aaaa.aaaa.b34d wlan ID: 3RSSI: 0, SNR: 32
</span></span><span class="line"><span class="cl">2019/10/25 21:30:08.626 {wncd_x_R0-0}{1}: &amp;#91;client-orch-state] &amp;#91;22573]: (note): MAC: aaaa.aaaa.aaaa  Client state transition: S_CO_L2_AUTH_IN_PROGRESS -&gt; S_CO_L2_AUTH_IN_PROGRESS
</span></span><span class="line"><span class="cl">2019/10/25 21:30:08.626 {wncd_x_R0-0}{1}: &amp;#91;dot11] &amp;#91;22573]: (info): MAC: aaaa.aaaa.aaaa  DOT11 state transition: S_DOT11_ASSOCIATED -&gt; S_DOT11_MAB_PENDING
</span></span><span class="line"><span class="cl">2019/10/25 21:30:08.626 {wncd_x_R0-0}{1}: &amp;#91;client-orch-state] &amp;#91;22573]: (note): MAC: aaaa.aaaa.aaaa  Client state transition: S_CO_L2_AUTH_IN_PROGRESS -&gt; S_CO_MACAUTH_IN_PROGRESS
</span></span><span class="line"><span class="cl">2019/10/25 21:30:08.626 {wncd_x_R0-0}{1}: &amp;#91;client-auth] &amp;#91;22573]: (info): MAC: aaaa.aaaa.aaaa  Client auth-interface state transition: S_AUTHIF_ADD_MOBILE_ACK_WAIT_KM -&gt; S_AUTHIF_MAB_AUTH_DONE
</span></span><span class="line"><span class="cl">2019/10/25 21:30:08.626 {wncd_x_R0-0}{1}: &amp;#91;client-orch-sm] &amp;#91;22573]: (debug): MAC: aaaa.aaaa.aaaa  Processing MAB authentication result status: 0, CO_AUTH_STATUS_SUCCESS
</span></span><span class="line"><span class="cl">2019/10/25 21:30:08.626 {wncd_x_R0-0}{1}: &amp;#91;client-orch-state] &amp;#91;22573]: (note): MAC: aaaa.aaaa.aaaa  Client state transition: S_CO_MACAUTH_IN_PROGRESS -&gt; S_CO_ASSOCIATING
</span></span><span class="line"><span class="cl">2019/10/25 21:30:08.626 {wncd_x_R0-0}{1}: &amp;#91;dot11] &amp;#91;22573]: (debug): MAC: aaaa.aaaa.aaaa  dot11 send association response. Sending association response with resp_status_code: 0 
</span></span><span class="line"><span class="cl">2019/10/25 21:30:08.627 {wncd_x_R0-0}{1}: &amp;#91;dot11] &amp;#91;22573]: (info): MAC: aaaa.aaaa.aaaa  dot11 send association response. Sending assoc response of length: 137 with resp_status_code: 0, DOT11_STATUS: DOT11_STATUS_SUCCESS
</span></span><span class="line"><span class="cl">2019/10/25 21:30:08.627 {wncd_x_R0-0}{1}: &amp;#91;dot11] &amp;#91;22573]: (note): MAC: aaaa.aaaa.aaaa  Association success. AID 1, Roaming = True, WGB = False, 11r = False, 11w = False
</span></span><span class="line"><span class="cl">2019/10/25 21:30:08.627 {wncd_x_R0-0}{1}: &amp;#91;dot11] &amp;#91;22573]: (info): MAC: aaaa.aaaa.aaaa  DOT11 state transition: S_DOT11_MAB_PENDING -&gt; S_DOT11_ASSOCIATED
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>Automated F5 Backups with CatTools</title>
      <link>https://0x2142.com/automated-f5-backups-with-cattools/</link>
      <pubDate>Tue, 27 Mar 2018 11:00:22 +0000</pubDate>
      <guid>https://0x2142.com/automated-f5-backups-with-cattools/</guid>
      <description>How to configure SolarWinds Kiwi CatTools to monitor &amp;amp; back up F5 load balancer configurations</description>
      <content:encoded><![CDATA[<p>We have some new F5 load balancers in our environment, which means I need a method of grabbing regular configuration backups. There are a number of methods out there, but I&rsquo;ve opted to use SolarWind&rsquo;s CatTools software since we already own it.</p>
<p>The config I used is based on <a href="https://lessonsintech.wordpress.com/2017/06/15/automate-f5-backups">this blog post</a>. It&rsquo;s a great write-up on how to back up F5 configurations using CatTools. I don&rsquo;t want to replicate what was written over there - but I did hit some issues that were specific to my use-case that I wanted to share.</p>
<p>While I was happy to find the article linked above, the immediate results didn&rsquo;t work so smooth for me. This may be due to some key configuration differences that I face in my network:</p>
<ul>
<li>All the F5&rsquo;s are LDAP integrated - so there isn&rsquo;t an easy way to provide LDAP users with direct bash access</li></li>
<li>All of my F5&rsquo;s are remote appliances, where the backup configuration is being copied across the WAN</li></li>
</ul>
<p>Getting around the first problem was my biggest challenge. CatTools is a very command/response-oriented application. Any remote LDAP authenticated users are immediately dropped into F5&rsquo;s shell: <strong>tmsh</strong>. To get from there to their &lsquo;advanced shell&rsquo; is as simple as typing <strong>bash</strong>. However, When the terminal prompt changes, it often throws CatTools into a state of &ldquo;I didn&rsquo;t receive the response prompt I expected, therefore kill the job - something went wrong&rdquo;. I spent a bit more time on this than I wanted to - but the underlying problem was that the &ldquo;<strong>F5.BigIP</strong>&rdquo; device type was specifically looking for the tmsh shell and couldn&rsquo;t handle the prompt change. The fix? Switch the device type to &ldquo;<strong>Linux.RedHat.Bash</strong>&rdquo;, then add the <strong>bash</strong> command to the first line of your backup script.</p>
<p>The next problem was using TFTP to copy the backup archives over the WAN. Even some of the new F5&rsquo;s with minimal configuration still generate a 10Mb file. Doesn&rsquo;t seem like much, but when you&rsquo;re copying that over a WAN between two datacenters, that turns into a ~5 minute file transfer. CatTools by default will only wait 30 seconds after executing a command before it expects a response. So every time I tried to run the job, CatTools would kill it only 30-seconds into the file transfer. Luckily enough, they support a utility command that can alter the normal timeout:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">%ctUM: Timeout <span class="m">600</span>
</span></span><span class="line"><span class="cl">tftp -m binary 192.168.1.10 -c put <span class="nv">$filename</span>
</span></span><span class="line"><span class="cl">%ctUM: Timeout <span class="m">0</span>
</span></span></code></pre></div><p>The command <code>%ctUM: Timeout 600</code> changes the timeout value to 600 seconds, or 10 minutes. The TFTP file transfer command is next, which is now permitted up to 10 minutes to finish. The last command resets the timeout back to the default (30 seconds).</p>
<p>I also realized that the original script doesn&rsquo;t purge the backup archive afterwards. For my use case, I would much rather automatically clean up the backup files once they&rsquo;ve been transferred to a central location.</p>
<p>So after all that, here is the version of that script that I&rsquo;m using:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">export</span> <span class="nv">date</span><span class="o">=</span><span class="sb">`</span>date +<span class="s2">&#34;%y%m%d&#34;</span>​<span class="sb">`</span>
</span></span><span class="line"><span class="cl"><span class="nb">export</span> <span class="nv">filename</span><span class="o">=</span><span class="nv">$HOSTNAME</span>.<span class="nv">$date</span>.ucs
</span></span><span class="line"><span class="cl">tmsh save /sys ucs /var/local/ucs/<span class="nv">$filename</span>
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> /var/local/ucs
</span></span><span class="line"><span class="cl">%ctUM: Timeout <span class="m">600</span>
</span></span><span class="line"><span class="cl">tftp -m binary 192.168.1.10 -c put <span class="nv">$filename</span>
</span></span><span class="line"><span class="cl">%ctUM: Timeout <span class="m">0</span>
</span></span><span class="line"><span class="cl">rm -f <span class="nv">$filename</span>
</span></span></code></pre></div><hr>
<p>Thanks again to the <a href="https://lessonsintech.wordpress.com/2017/06/15/automate-f5-backups">original blog post</a> for getting me on the right track with this! I hope that my ramblings here are helpful to anyone with a similar deployment scenario.</p>
]]></content:encoded>
    </item>
    <item>
      <title>L2 Basics: Configuring an EtherChannel</title>
      <link>https://0x2142.com/l2-basics-configuring-an-etherchannel/</link>
      <pubDate>Tue, 30 Jan 2018 10:00:46 +0000</pubDate>
      <guid>https://0x2142.com/l2-basics-configuring-an-etherchannel/</guid>
      <description>How to configure a basic etherchannel on Cisco devices</description>
      <content:encoded><![CDATA[<p>Today we&rsquo;re going to take a look at how to configure an etherchannel between two Cisco Switches.</p>
<p>What is an etherchannel? It&rsquo;s a way of taking multiple independent links and bundling them together, so that they appear as one logical connection between two devices. Etherchannels are commonly used between two switches, or between a switch and a host - which allows for both additional bandwidth and fault tolerance/redundancy. In the example today, we&rsquo;ll be using an etherchannel protocol called Link Aggregation Control Protocol (LACP). LACP is an IEEE standard (802.3ad).</p>
<p>You might be thinking &ldquo;Wait, wouldn&rsquo;t multiple links cause a loop? Or trigger <a href="/l2-basics-spanning-tree-protocol/">Spanning-tree</a> to block ports?&rdquo;. Not in this case! Etherchannel technologies work around those problems by creating a single logical interface for spanning-tree to worry about. The etherchannel protocol itself worries about loop prevention in between the two devices, so we get multiple ports of non-blocking bandwidth.</p>
<p>For everything we cover in this example, we&rsquo;ll be using the following topology:</p>
<p><img alt="image" loading="lazy" src="/content/images/2018/01/lacp.png#center"></p>
<p>So we have two switches, which are connected together via Eth0/0 and Eth0/1. Each switch has three VLANs configured - 10, 20, and 30.</p>
<h2 id="configuring-an-etherchannel">Configuring an Etherchannel</h2>
<p>I&rsquo;ll only be showing the configuration from the perspective of 0x2142-SW1 - but all configuration is replicated on 0x2142-SW2.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">! We&#39;ll use the interface range command to apply the etherchannel configuration to
</span></span><span class="line"><span class="cl">! both Eth0/0 and Eth0/1 at the same time:
</span></span><span class="line"><span class="cl">0x2142-SW1(config)#int range Eth0/0 - 1
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">! We specify which etherchannel protocol to use by configuring &#39;channel-protocol&#39;
</span></span><span class="line"><span class="cl">! PAgP is a Cisco Proprietary protocol, but we&#39;ll be using LACP for this example:
</span></span><span class="line"><span class="cl">0x2142-SW1(config-if-range)#channel-protocol ?
</span></span><span class="line"><span class="cl">  lacp  Prepare interface for LACP protocol
</span></span><span class="line"><span class="cl">  pagp  Prepare interface for PAgP protocol
</span></span><span class="line"><span class="cl">0x2142-SW1(config-if-range)#channel-protocol lacp
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">! Next we need to specify a channel-group and mode:
</span></span><span class="line"><span class="cl">0x2142-SW1(config-if-range)#channel-group 1 mode ?
</span></span><span class="line"><span class="cl">  active     Enable LACP unconditionally
</span></span><span class="line"><span class="cl">  auto       Enable PAgP only if a PAgP device is detected
</span></span><span class="line"><span class="cl">  desirable  Enable PAgP unconditionally
</span></span><span class="line"><span class="cl">  on         Enable Etherchannel only
</span></span><span class="line"><span class="cl">  passive    Enable LACP only if a LACP device is detected
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">0x2142-SW1(config-if-range)#channel-group 1 mode active
</span></span><span class="line"><span class="cl">Creating a port-channel interface Port-channel 1
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">0x2142-SW1(config-if-range)#
</span></span><span class="line"><span class="cl">*Jan 26 01:03:04.532: %LINEPROTO-5-UPDOWN: Line protocol on Interface Port-channel1, changed state to up
</span></span></code></pre></div><p>Let&rsquo;s talk through a few notes about the above configuration. In order to enable etherchannel, we only need to configure two commands: <code>channel-protocol</code> and <code>channel-group</code>. The <code>channel-protocol</code> command tells the switch which etherchannel protocol to use for negotiation (LACP in this case). The <code>channel-group</code> command provides two necessary components: the group number and mode. The group number is just a device-local identifier for which group to add these ports to. When we specified group 1, the switch adds both Eth0/0 and Eth0/1 into the new logical interface Port-Channel 1.</p>
<p>The etherchannel mode is also important. The two primary options we want to look at for LACP are active and passive. Active tells the switch to preemptively send out LACP negotiation packets. In this case, the switch really wants the ports to become a bundle and will ask it&rsquo;s partner device for an etherchannel to be formed. Passive mode tells our switch to only negotiate if another device wants to. In this mode, our switch won&rsquo;t send out any etherchannel negotiation packets unless its partner device does so first.</p>
<p>Generally speaking, the most common configuration is to set the mode on both devices to active. This ensures that both devices actively participate in trying to establish an etherchannel. Placing one device in active and one in passive will work as well. However, if both devices are placed into passive mode, an etherchannel will never form.</p>
<h2 id="validation">Validation</h2>
<p>So how do we validate that the etherchannel has formed correctly? One way is using the <code>show etherchannel summary</code> command:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">0x2142-SW1#show etherchannel summary
</span></span><span class="line"><span class="cl">Flags:  D - down        P - bundled in port-channel
</span></span><span class="line"><span class="cl">        I - stand-alone s - suspended
</span></span><span class="line"><span class="cl">        H - Hot-standby (LACP only)
</span></span><span class="line"><span class="cl">        R - Layer3      S - Layer2
</span></span><span class="line"><span class="cl">        U - in use      N - not in use, no aggregation
</span></span><span class="line"><span class="cl">        f - failed to allocate aggregator
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        M - not in use, minimum links not met
</span></span><span class="line"><span class="cl">        m - not in use, port not aggregated due to minimum links not met
</span></span><span class="line"><span class="cl">        u - unsuitable for bundling
</span></span><span class="line"><span class="cl">        w - waiting to be aggregated
</span></span><span class="line"><span class="cl">        d - default port
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        A - formed by Auto LAG
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Number of channel-groups in use: 1
</span></span><span class="line"><span class="cl">Number of aggregators:           1
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Group  Port-channel  Protocol    Ports
</span></span><span class="line"><span class="cl">------+-------------+-----------+-----------------------------------------------
</span></span><span class="line"><span class="cl">1      Po1(SU)         LACP      Et0/0(P)    Et0/1(P)
</span></span></code></pre></div><p>From the output above, we see that there is one group configured with the group ID of 1. It shows that both Eth0/0 and Eth0/1 have been added into the Port-channel 1 interface. The (SU) next to the Port-channel interface indicate that the etherchannel is up (U) and configured for layer 2 (S).
I mentioned earlier that spanning-tree only worries about the port-channel interface, not the individual member ports. We can also check that out by using <code>the show spanning-tree</code> command:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">0x2142-SW1#sh spanning-tree vlan 20
</span></span><span class="line"><span class="cl">VLAN0020
</span></span><span class="line"><span class="cl">  Spanning tree enabled protocol rstp
</span></span><span class="line"><span class="cl">  Root ID    Priority    32788
</span></span><span class="line"><span class="cl">             Address     aabb.cc00.1000
</span></span><span class="line"><span class="cl">             This bridge is the root
</span></span><span class="line"><span class="cl">             Hello Time   2 sec  Max Age 20 sec  Forward Delay 15 sec
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  Bridge ID  Priority    32788  (priority 32768 sys-id-ext 20)
</span></span><span class="line"><span class="cl">             Address     aabb.cc00.1000
</span></span><span class="line"><span class="cl">             Hello Time   2 sec  Max Age 20 sec  Forward Delay 15 sec
</span></span><span class="line"><span class="cl">             Aging Time  300 sec
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Interface           Role Sts Cost      Prio.Nbr Type
</span></span><span class="line"><span class="cl">------------------- ---- --- --------- -------- --------------------------------
</span></span><span class="line"><span class="cl">Et0/2               Desg FWD 100       128.3    Shr
</span></span><span class="line"><span class="cl">Et0/3               Desg FWD 100       128.4    Shr
</span></span><span class="line"><span class="cl">&lt;-- Output omitted --&gt;
</span></span><span class="line"><span class="cl">Po1                 Desg FWD 56        128.65   Shr
</span></span></code></pre></div><h2 id="making-configuration-changes-to-an-etherchannel">Making Configuration Changes to an Etherchannel</h2>
<p>Now that we have a working etherchannel - We have a few things that need special attention. The individual port configurations, Eth0/0 and Eth0/1 in this case, need to match at all times! Port configuration mis-matches are going to be an easy way to inadvertently bring down the port-channel. The good thing is that we now have a convenient Port-Channel interface which we can use for configuration. This logical port will replicate any configuration changes to all member ports.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">! Let&#39;s jump into our Port-Channel 1 interface and configure a trunk for VLAN 20
</span></span><span class="line"><span class="cl">0x2142-SW1(config)#int po1
</span></span><span class="line"><span class="cl">0x2142-SW1(config-if)#switchport mode trunk
</span></span><span class="line"><span class="cl">0x2142-SW1(config-if)#switchport trunk allowed vlan 20
</span></span><span class="line"><span class="cl">! Now we can check the individual port configs:
</span></span><span class="line"><span class="cl">0x2142-SW1(config-if)#do sh run int e0/0
</span></span><span class="line"><span class="cl">Building configuration...
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Current configuration : 176 bytes
</span></span><span class="line"><span class="cl">!
</span></span><span class="line"><span class="cl">interface Ethernet0/0
</span></span><span class="line"><span class="cl"> switchport trunk allowed vlan 20
</span></span><span class="line"><span class="cl"> switchport mode trunk
</span></span><span class="line"><span class="cl"> channel-protocol lacp
</span></span><span class="line"><span class="cl"> channel-group 1 mode active
</span></span><span class="line"><span class="cl">end
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">0x2142-SW1(config-if)#do sh run int e0/1
</span></span><span class="line"><span class="cl">Building configuration...
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Current configuration : 176 bytes
</span></span><span class="line"><span class="cl">!
</span></span><span class="line"><span class="cl">interface Ethernet0/1
</span></span><span class="line"><span class="cl"> switchport trunk allowed vlan 20
</span></span><span class="line"><span class="cl"> switchport mode trunk
</span></span><span class="line"><span class="cl"> channel-protocol lacp
</span></span><span class="line"><span class="cl"> channel-group 1 mode active
</span></span><span class="line"><span class="cl">end
</span></span></code></pre></div><p>Easy enough, right? The configuration changes for the trunk are now on both Eth0/0 and Eth0/1.</p>
<h2 id="troubleshooting-etherchannels">Troubleshooting Etherchannels</h2>
<p>There is always a possibility that something goes wrong - so let&rsquo;s take a quick look at some common problems and how to fix them.</p>
<p>Remember how I said that the member port configurations had to match? Here&rsquo;s what happens if we make a configuration change on only one of the two member ports:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">0x2142-SW1(config)#int eth0/1
</span></span><span class="line"><span class="cl">0x2142-SW1(config-if)#switchport trunk allowed vlan 30
</span></span><span class="line"><span class="cl">0x2142-SW1(config-if)#
</span></span><span class="line"><span class="cl">*Jan 28 20:43:55.458: %EC-5-CANNOT_BUNDLE2: Et0/1 is not compatible with Et0/0 and will be suspended (vlan mask is different)
</span></span></code></pre></div><p>Eth0/1 immediately gets put into a suspended state, and is no longer active in the port-channel interface. In this case the switch gives us a good hint as to what&rsquo;s wrong - vlan mask is different. Error messages will vary slightly, but a suspended port is easy to fix by comparing individual port configurations and fixing the mismatch.</p>
<p>Here&rsquo;s another one:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">*Jan 28 21:06:07.346: %EC-5-L3DONTBNDL2: Et0/0 suspended: LACP currently not enabled on the remote port.
</span></span><span class="line"><span class="cl">*Jan 28 21:06:08.009: %EC-5-L3DONTBNDL2: Et0/1 suspended: LACP currently not enabled on the remote port.
</span></span></code></pre></div><p>This error message can mean a few things - the common one being exactly what it states! Check both sides of the connection, and ensure that LACP is configured on each device. This error message can also occur on certain mismatches - like if one side is running as a Layer 2 etherchannel, but the other side is running as Layer 3.</p>
<p>One more:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Jan 28 20:83:55.458 %ETHPORT-5-IF_DOWN_PORT_CHANNEL_MEMBERS_DOWN: Interface port-channel1 is down (No operational members)
</span></span></code></pre></div><p>The above message is also somewhat self-explanatory. In this case, the switch is unable to bring up the port-channel interface, because none of the underlying member ports are coming online. Troubleshoot what might be wrong with those ports first, then the port-channel should come up.</p>
<hr>
<p>Hope this was useful! In a later post, we&rsquo;ll dig into more configuration and considerations - like packet hashing, layer 3 etherchannels, and how packets are weighted between interfaces.</p>
<p>Questions? Drop them in the comments below!</p>
]]></content:encoded>
    </item>
    <item>
      <title>SRX Basics: Redunancy Groups and Failover</title>
      <link>https://0x2142.com/srx-basics-redunancy-groups-and-failover/</link>
      <pubDate>Tue, 18 Jul 2017 08:00:24 +0000</pubDate>
      <guid>https://0x2142.com/srx-basics-redunancy-groups-and-failover/</guid>
      <description>Some background &amp;amp; configuration examples for Juniper SRX redundancy groups</description>
      <content:encoded><![CDATA[<p>In last weeks post, we took a look at how to set up a <a href="/srx-basics-clustering/">chassis cluster</a> on a Juniper SRX Firewall. So now that we have a basic cluster setup - Let&rsquo;s explore some of the additional options and configuration items.</p>
<h2 id="redundant-ethernet-interfaces">Redundant Ethernet Interfaces</h2>
<p>So first thing is first - Once you have a cluster configured, you&rsquo;ll probably want to configure a few sets of redundant ethernet interfaces. These interfaces are also often referred to as reth interfaces. This will create a shared interface between your SRX pair, where you can configure IP address and VLAN information to be shared between the two. Let&rsquo;s say that we have a Juniper SRX 1500 cluster, and we want to create a redundant interface for one of our 10Gb ports. Here is how we would do that:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">root@testsrx# set interfaces xe-0/0/16 gigether-options redundant-parent reth1
</span></span><span class="line"><span class="cl">root@testsrx# set interfaces xe-7/0/16 gigether-options redundant-parent reth1
</span></span><span class="line"><span class="cl">root@testsrx# set interfaces reth1 redundant-ether-options redundancy-group 1
</span></span></code></pre></div><p>In the config above, we first take both of our interfaces (xe-0/0/16 on node0, and xe-7/0/16 on node1) and tell them that they now belong to a redundant interface group (reth1). Next, we enter into the reth1 config, and associate it to a redundancy group.</p>
<p>You&rsquo;re also going to need to keep in mind that the SRX requires you to specify how many redundant ethernet interfaces will be configured. This is likely a memory thing, since each SRX also has a different maximum number of reth interfaces that can be configured. For example, if you tell the SRX that you need 5 reth interfaces, then the SRX will allocate system resources to manage those interfaces. In order to set the number of available reth interfaces, we&rsquo;ll use the following command:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">root@testsrx# set chassis cluster reth-count 5
</span></span></code></pre></div><h2 id="redundancy-groups">Redundancy Groups</h2>
<p>A redundancy group, or RG, is used as a container for logically grouping redundant interfaces/virtual routers which must fail over together. A single RG can be configured as primary on one of the two active SRX firewalls is a cluster - with the ability to fail over to the other node. For example, we might want be planning on only using one virtual routing instance on our SRX - so we would create RG1 and assign out interfaces to belong to it.</p>
<p>A quick note - all interfaces in a single virtual router must belong to the same RG. This way the virtual routing instance and all of it&rsquo;s associated interfaces will always run on the same SRX node. In order to achieve an active/active firewall configuration, you would need to create two separate virtual routers, each with their own reth interfaces and different RGs. Then you would make RG1 primary on node0, and RG2 primary on node1.</p>
<p>In most configurations, dumping all of your reth interfaces into RG1 will be sufficient. You&rsquo;re likely going to want to set up a priority for each RG - and maybe even preemptive fail-over. In order to do that - you&rsquo;ll have to configure each cluster member with a priority:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">root@testsrx# set chassis cluster redundancy-group 0 node 0 priority 200
</span></span><span class="line"><span class="cl">root@testsrx# set chassis cluster redundancy-group 0 node 1 priority 50
</span></span><span class="line"><span class="cl">root@testsrx# set chassis cluster redundancy-group 1 node 0 priority 200
</span></span><span class="line"><span class="cl">root@testsrx# set chassis cluster redundancy-group 1 node 1 priority 50
</span></span><span class="line"><span class="cl">root@testsrx# set chassis cluster redundancy-group 1 preempt
</span></span></code></pre></div><p>The higher priority wins here - so if you set node0 to a higher priority and preempt is enabled, then node0 will actively try to take ownership of RG1. I would rather not set preempt on RG0 for a few reasons - which we&rsquo;ll cover in the next section. Priorities can also be modified using interface monitoring, so if a particular interface goes offline we can decrement the priority of that node (also covered below).</p>
<h2 id="a-note-about-rg0">A Note About RG0</h2>
<p>You might notice from the last post, that you&rsquo;re output of <strong>show chassis cluster status</strong> already showed two redundancy groups: RG0 and RG1. RG0 is only used for management traffic and manages the routing engine for your SRX. Unfortunately, this can lead to some weird behaviors that you might not be expecting.</p>
<p>For example, whichever node is primary for RG0 is the only node that collects interface and monitoring statistics. If you&rsquo;re using a monitoring tool that polls data from both of your SRXs, then the secondary for RG0 will report <strong>nothing</strong> about it&rsquo;s interfaces, CPU, etc. This is also true if you log into the actual SRX itself - a <strong>show interfaces</strong> will actually return a bunch of default values, including showing that your ports are half-duplex. Don&rsquo;t panic though, this is just an oddity of RG0. If you log back into the primary node for RG0, then it will show all of the proper statistics for both SRX firewalls.</p>
<p>Due to these weird things about RG0 - I prefer to always leave it on node0. Therefore I know which one to log into whenever I need to look at something, or which SRX to check in our monitoring tools. It&rsquo;s also worth noting that whichever SRX is primary for RG0 is also the node you&rsquo;re going to need to log into for configuration changes - even if all of your other redundancy groups are the other SRX.</p>
<p>Weird, right?</p>
<p>Oh, and be warned that since RG0 controls the routing engine, a failover of this RG can cause brief outages. This is primarily because the routing table and firewall state information will be lost. The secondary node has to spin up new processes for the routing engine, and at least currently there isn&rsquo;t a graceful sync of all of that data.</p>
<h2 id="interface-monitoring">Interface Monitoring</h2>
<p>I mentioned setting device priorities a bit earlier. Setting interface weights is going to be the primary method for dynamically affecting those priorities, and therefore possibly causing a preemptive failover. One example might be that you&rsquo;re using an SRX cluster for your edge firewall, and you want it to automatically fail over if the primary loses it&rsquo;s internet uplink.</p>
<p>Note that you must configure the <em>physical</em> interfaces here, not the redundant ethernet interfaces:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">root@testsrx# set chassis cluster redundancy-group 1 interface-monitor xe-0/0/16 weight 160
</span></span></code></pre></div><p>Remember when we set the priorities of our firewalls earlier? Node0 was set to 200, and node1 at 50. So here we are saying that xe-0/0/16 on node0 is worth 160 points. So if xe-0/0/16 goes down, then node0 will decrement it&rsquo;s priority by 160 - which will be 40. This will trigger a preemtive failover by node1. The reverse is also true - when xe-0/0/16 comes back up, then node0&rsquo;s priority will go back up to 200. Then node0 will take back ownership of RG1.</p>
<h2 id="manual-failover">Manual Failover</h2>
<p>There is a pretty good chance at some point you might need to perform a manual failover of your SRX redundancy groups. Maybe you need to do some maintenance or upgrades, or you just want to make sure failover works as you expect. In either case, the commands to do this are pretty straightforward:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">root@testsrx&gt; show chassis cluster status
</span></span><span class="line"><span class="cl">Cluster ID: 5
</span></span><span class="line"><span class="cl">Node       Priority       Status       Preempt       Manual failover
</span></span><span class="line"><span class="cl">Redundancy group: 0 , Failover count: 0
</span></span><span class="line"><span class="cl">node0      200            primary      no            no 
</span></span><span class="line"><span class="cl">node1      50             secondary    no            no
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Redundancy group: 1 , Failover count: 0
</span></span><span class="line"><span class="cl">node0      200            primary      yes           no 
</span></span><span class="line"><span class="cl">node1      50             secondary    yes           no
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">root@testsrx&gt; request chassis cluster failover redundancy-group 1 node 1 
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">root@testsrx&gt; show chassis cluster status 
</span></span><span class="line"><span class="cl">Cluster ID: 5
</span></span><span class="line"><span class="cl">Node       Priority       Status       Preempt       Manual failover
</span></span><span class="line"><span class="cl">Redundancy group: 0 , Failover count: 0
</span></span><span class="line"><span class="cl">node0     200             primary      no            no 
</span></span><span class="line"><span class="cl">node1     50              secondary    no            no
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Redundancy group: 1 , Failover count: 1
</span></span><span class="line"><span class="cl">node0     200             secondary    yes           yes
</span></span><span class="line"><span class="cl">node1     255             primary      yes           yes
</span></span></code></pre></div><p>Okay - so let&rsquo;s talk about a few things that have happened here. I always recommend that you run a <strong>show chassis cluster status</strong> first, so you know where things already stand. Then we can proceed by requesting a failover. To do this, you have to specify which redundancy group you want to fail over, and which node you want to become the new primary. So in this case, we made node1 the new primary of RG1.</p>
<p>You might also notice that the priorities have changed, and the devices are marked as being in a manual failover state. This is important, because <strong>you cannot manually fail back until you reset this state</strong>. That&rsquo;s right - if you tried to run the failover command again to move RG1 back to node0, it will not work. An automatic failover due to hardware failure or interface monitoring will still be permitted. In order to perform a manual fail-back to node0, we have to run the following reset command:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">root@testsrx&gt; request chassis cluster failover reset redundancy-group 1
</span></span></code></pre></div><hr>
<p>Hopefully between last weeks post and this one, you should have a good handle on the basics of configuring a chassis cluster on your new pair of Juniper SRX firewalls. Let me know in the comments below if this helped you!</p>
]]></content:encoded>
    </item>
    <item>
      <title>SRX Basics: Clustering</title>
      <link>https://0x2142.com/srx-basics-clustering/</link>
      <pubDate>Tue, 11 Jul 2017 08:00:07 +0000</pubDate>
      <guid>https://0x2142.com/srx-basics-clustering/</guid>
      <description>A short tutorial on how to configure Juniper SRX clustering</description>
      <content:encoded><![CDATA[<p>So you just unboxed a brand new pair of Juniper SRX firewalls - now what? Well, the first thing you&rsquo;re likely going to want to do is get the two devices hooked up and clustered together. That should be pretty simple, right? Yeah, mostly - though there are a few variations between device models, and there are a few fine-print steps that might keep you from getting everything working the first time.</p>
<p>So let&rsquo;s take a look at what we need to do!</p>
<h2 id="physical-configuration">Physical configuration</h2>
<p>First thing we need to do is get both devices unboxed and cabled appropriately. In order to get a successful cluster configured, we will need to get two critical ports connected: the HA control port and the cluster fabric port. Technically only the HA control port is required to get a cluster working, but you&rsquo;ll want to get the fabric port working as well - here is what both ports are used for:</p>
<p><strong>HA Control Port</strong> - This is used for communication between the cluster members. This connection is used just for control-plane stuff - like keepalives/heartbeats and config sync between the two nodes.</p>
<p><strong>Fabric Port</strong> - This port is used for data sync between the cluster members. All routing/firewall state information is synced using this port, and any cross-cluster traffic is also transferred using this port (for example, if one SRX was primary for a redundancy group, but the secondary was the active BGP speaker for your upstream connection - then the traffic would come in through the secondary and cross this link to reach the primary RG)</p>
<p>The fabric port is the easiest to connect - because you can use any port you like, then specify which port to use in the CLI. The control port, however, must be the assigned port that Juniper allocates for this use. Unfortunately, this port varies between device models. The two most common SRXs that I&rsquo;ve deployed are the 345 and 1500. The SRX 1500 has a dedicated 10G HA control port, but the SRX 345 actually uses ge-0/0/1 on both nodes for this. Juniper lists what all those port assignments are over on <a href="https://kb.juniper.net/InfoCenter/index?page=content&amp;id=KB15356&amp;actp=METADATA">this page</a>.</p>
<p>Once those ports are connected, go ahead and power on both devices!</p>
<h2 id="junos-config">JunOS Config</h2>
<p>Okay - Once the physical configuration has been completed, there are a few things that need to be configured on both devices before you can establish a cluster.</p>
<p>When you first boot each device, you&rsquo;ll log in with <strong>root</strong> and no password. Then you&rsquo;ll be dropped into the JunOS shell, and you&rsquo;ll need to type <strong>cli</strong> to start the JunOS command-line interface. Then type <strong>configure</strong> to get into the configuration mode.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">root@testsrx% cli
</span></span><span class="line"><span class="cl">root@testsrx&gt; configure
</span></span><span class="line"><span class="cl">root@testsrx#
</span></span></code></pre></div><p>In the config mode, we&rsquo;ll need to set a root password before we can enable the clustering. This password must match on both devices!</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">root@testsrx# set system root-authentication plain-text-password
</span></span><span class="line"><span class="cl">New Password: &lt;type your root password here&gt;
</span></span><span class="line"><span class="cl">Retype new password: &lt;and again...&gt;
</span></span></code></pre></div><p>For the SRX 1500 series, where there is a dedicated HA Control port, this is enough to get the cluster working. But for some of the branch SRXs, like the 300 series, you&rsquo;ll need to make a few additional changes. These devices come with a default config, which includes IP addresses on certain interfaces. Unfortunately, this will conflict with your cluster config and will not allow your cluster to reach a healthy state.</p>
<p>In my config, I already plan on re-configuring all of the interfaces and security-zones to fit my needs - so I will just delete those entire config sections:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">root@testsrx# delete interfaces
</span></span><span class="line"><span class="cl">root@testsrx# delete security
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">After all that is done, we need to commit our changes:
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">```text
</span></span><span class="line"><span class="cl">root@testsrx# commit
</span></span></code></pre></div><p>Finally we can go ahead and set up the cluster! This config is actually done outside of configure mode, so you will need to exit that.</p>
<p>So one thing to note here - each cluster will be configured with a cluster-id. This <strong>MUST</strong>be unique across any layer 2 subnet. So if we had multiple SRX clusters within a single broadcast domain, we would need to assign each one a different cluster ID.  I&rsquo;ll use cluster-id 5 in this example.</p>
<p>On whichever SRX you want to be the primary node:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">root@testsrx# exit
</span></span><span class="line"><span class="cl">root@testsrx&gt; set chassis cluster cluster-id 5 node 0 reboot
</span></span></code></pre></div><p>I personally like to give the primary a minute or to into the boot process before I configure the secondary, but we&rsquo;ll do so with a similar command (just specifying node 1 instead of 0):</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">root@testsrx&gt; set chassis cluster cluster-id 5 node 1 reboot
</span></span></code></pre></div><p>After both nodes come back online, log into node 0 and run the following command:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">root@testsrx&gt; show chassis cluster status 
</span></span><span class="line"><span class="cl">Cluster ID: 5
</span></span><span class="line"><span class="cl">Node       Priority      Status      Preempt      Manual failover
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Redundancy group: 0 , Failover count: 0
</span></span><span class="line"><span class="cl">node0      100           primary     no           no 
</span></span><span class="line"><span class="cl">node1      100           secondary   no           no
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Redundancy group: 1 , Failover count: 0
</span></span><span class="line"><span class="cl">node0      100           primary     yes          no 
</span></span><span class="line"><span class="cl">node1      100           secondary   yes          no
</span></span></code></pre></div><p>Perfect! Now let&rsquo;s go configure our fabric ports! Interface fab0 will be configured as the fabric port on node0, and interface fab1 will be configured as the fabric port on node1.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">root@testsrx&gt; configure
</span></span><span class="line"><span class="cl">root@testsrx# set interface fab0 fabric-options member-interfaces ge-0/0/10
</span></span><span class="line"><span class="cl">root@testsrx# set interface fab1 fabric-options member-interfaces ge-5/0/10
</span></span><span class="line"><span class="cl">root@testsrx# commit
</span></span></code></pre></div><p>Now that we&rsquo;re in a cluster, all of this configuration can be done on node0 - but note that in this case the secondary device&rsquo;s ports all start with ge-5/x/x. This is another oddity of JunOS - that numbering scheme isn&rsquo;t always the case. In the SRX1500s, the node1 ports all start with ge-7/x/x - so this will vary depending on what devices you&rsquo;re working with. If you ever need to check this - you can run <strong>show interface terse</strong> to list all interfaces in the cluster.</p>
<p>As a final verification that all our ports are up, drop out of config mode and run <strong>show chassis cluster interfaces:</strong></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">root@testsrx&gt; show chassis cluster interfaces
</span></span><span class="line"><span class="cl">Control link 0 name: ge-0/0/1
</span></span><span class="line"><span class="cl">Control link status: Up
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Fabric interfaces:
</span></span><span class="line"><span class="cl">Name Child-interface Status
</span></span><span class="line"><span class="cl">fab0 ge-0/0/10 up
</span></span><span class="line"><span class="cl">fab0
</span></span><span class="line"><span class="cl">fab1 ge-5/0/10 up
</span></span><span class="line"><span class="cl">fab1
</span></span><span class="line"><span class="cl">Fabric link status: up
</span></span></code></pre></div><p>Hooray! We now have a functioning SRX cluster!</p>
<p>Sometimes if this doesn&rsquo;t work, the output of <strong>show chassis cluster status</strong> will show the secondary node as <strong>disabled</strong> or <strong>lost.</strong> I&rsquo;ve found that <strong>lost</strong> usually indicates a conflicting configuration on the cluster interfaces (like leaving the default IPs configured). If you see <strong>disabled</strong>, try rebooting the secondary node again - and if that doesn&rsquo;t work, then you may need to disable clustering on both nodes and re-configure. This can be done using the <strong>set chassis cluster disable reboot</strong> command.</p>
<p>Next week, we&rsquo;ll look at redundancy-groups, performing manual failovers, and setting up interface monitoring for automatic failovers. Hope this was helpful!</p>
]]></content:encoded>
    </item>
    <item>
      <title>Quick Tips for Better BGP</title>
      <link>https://0x2142.com/quick-tips-for-better-bgp/</link>
      <pubDate>Tue, 02 May 2017 10:26:42 +0000</pubDate>
      <guid>https://0x2142.com/quick-tips-for-better-bgp/</guid>
      <description>A lot of BGP setups I run into are bare-bones, but there are a few quick ways to improve your configurations</description>
      <content:encoded><![CDATA[<p>A while back I wrote some basic information on how to get started implementing <a href="/bgp-getting-started-with-multi-homed-internet">multi-homed internet using BGP</a>. The details and configurations listed in that post are enough to get the connection up and running - but not quite in an ideal state. So today I want to share some quick tips that will help you maintain a better and more secure BGP connection.</p>
<h2 id="securing-your-bgp-peeringknow-who-youre-connecting-to">Securing your BGP peering (Know who you&rsquo;re connecting to)</h2>
<p>BGP is a little different from most other routing protocols, since it uses a single unicast TCP connection between peers to exchange routing updates. Lucky for us, that means that we can easily filter traffic from only known peers. Once you have direct connectivity up between your edge router/firewall and your direct peer, lock down that connection with an ACL. Permit TCP port 179 traffic <strong>ONLY</strong> from your directly connected peer IP - no one else.</p>
<p>While you&rsquo;re at it, let&rsquo;s take it another step further: Request that your ISP set up BGP authentication. Sure, a majority of BGP implementations today still require use of MD5 for auth (which is terrible) - but some authentication is still better than none. This can usually be arranged at the time of turning up peering. Both sides configure the same authentication password and with any luck the peering still establishes.</p>
<p>BGP by nature is unfortunately not the most secure protocol - but a few simple steps like this will help ensure you&rsquo;re only connecting out to authorized peers.</p>
<h2 id="route-filtering-dont-trust-anyone">Route filtering (Don&rsquo;t trust anyone)</h2>
<p>Usually when you&rsquo;re filling out the BGP peering paperwork for your service provider, they will ask you what kinds of routes you want. In most cases, you should be able to request one of the following:</p>
<p><strong>Default only</strong> - Exactly what it sounds like. Your provider will only advertise a route for 0.0.0.0/0. In many cases, this is probably what you&rsquo;re going to want. With this type of advertisement, each upstream provider will just give us the same default route to the internet. From there we can weight which one we want to use, and traffic will automatically fail-over to the secondary connection should the primary fail.</p>
<p><strong>Partial</strong> - If for any reason you want to weight routes to certain destinations differently, then we might request this. In this case, you&rsquo;re probably going to still receive 0.0.0.0/0 plus any specific routes you ask for. A good example of this is if we wanted to specifically manipulate routes for a remote office we have. Maybe we want to weight Internet traffic for one uplink, and VPN traffic to a remote office on the other uplink.</p>
<p><strong>Full</strong> - In 99% of typical business cases, this won&rsquo;t be required. This option means the upstream providers will be dumping the <em>entire</em> Internet routing table on you. While this offers you a ton of control over path manipulation, it also requires significant memory resources on your routers in order to maintain that routing table.</p>
<p>After we figure this out, the next step is to make sure we are filtering the routes we accept from the upstream provider. Wait - didn&rsquo;t we just tell them exactly what routes to send us? Why do we need to filter them? Well you can never be too safe here - and we would rather perform an unnecessary filtering than have an ISP accidentally misconfigure route advertisements. So if you&rsquo;re only expecting a route for 0.0.0.0/0, then filter your inbound route advertisements so you only accept that route.</p>
<p>Same thing goes for outbound route advertisement  - if we own a /24 of public IP space, then we only want that range to be advertised out. Some providers may already filter this on their end, but again it doesn&rsquo;t hurt here to be extra cautious. If we are accepting anything other than a default route from our provider, then we run the risk of leaking those additional routes between the two providers - which would lead to inadvertently becoming a transit AS. Chances are pretty good that you don&rsquo;t want that, so make sure you configure filtering for all outbound route advertisements.</p>
<h2 id="minimumadvertisement-oh-no-we-have-to-re-address-everything">Minimum Advertisement (Oh no, we have to re-address everything)</h2>
<p>I mentioned this in the original post - but typically when you are peering with two separate upstream providers, you need to advertise no less than a /24. We ran into this at my last job, where we had been provided a /25 by AT&amp;T but we needed to bring in a second carrier via BGP. The reasoning behind this is to keep global routing tables as small as possible, by not allowing them to end up flooded with a ton of routes for smaller subnets. It makes sense, but on the other hand I feel like requiring a /24 in all cases can be a bit wasteful. My last job only required maybe 30 publicly addressable hosts - which meant that the remaining addresses went unused.</p>
<p>At any rate - should you find yourself in this scenario then you&rsquo;re going to have to face the inevitable: Renumbering into a new IP space. Any time you have to do this, it&rsquo;s going to be a bit of a pain - but for external addressing like this it might be easier. So in our case, the entire /25 space was hosted on our external firewall then NAT&rsquo;ed into DMZ servers.</p>
<p>Here is the quick steps that I used to do a side-by-side migration without taking any significant downtime:</p>
<ul>
<li>Get the new subnet up and running - assign the interface addresses on your firewall and BGP up and running</li>
<li>Assign new IP addresses to all of your existing services</li>
<li>Configure NAT rules for the new external IP addresses to the DMZ hosts - while leaving the existing NAT rules for the old subnet (Also make sure your firewall rules permit the same traffic to either IP)</li>
<li>Migrate DNS entries externally to point to the new IP space</li>
<li>Once traffic stops flowing to the old IP, remove the old NAT</li>
</ul>
<p>As a side note - if you procure redundant internet connections through the <em>same</em> upstream provider, then you might be able to work out something else. They may be able to provide you a private ASN to use, and they will likely accept any minimum advertisement - since they will be summarizing upstream within their network anyways.</p>
<hr>
<p>I had a few more things I originally intended to cover here - but it seems that these topics are filling way more space than I thought they would. Specifically, I&rsquo;m thinking about a dedicated post to BGP path manipulation - which is probably something you&rsquo;re going to want to implement after peering is established.
Hopefully these tips help! If you have any questions, throw them in the comments below.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Port Security: Worth the effort?</title>
      <link>https://0x2142.com/port-security-worth-the-effort/</link>
      <pubDate>Tue, 14 Mar 2017 08:00:40 +0000</pubDate>
      <guid>https://0x2142.com/port-security-worth-the-effort/</guid>
      <description>An exploration of practical applications of port-security configurations, based on my past experiences</description>
      <content:encoded><![CDATA[<p>Port Security. Always seems like one of those things covered in Cisco exams, yet how many businesses actually use it? For those that aren&rsquo;t implementing it, should they? Or is it too much of a headache?</p>
<p>So the concept of port security is fairly simple - We want to secure each individual switch port to a physical layer 2 MAC address, or at least limit how many unique MAC addresses might be learned on an individual port. The technology could be used to just limit the number of simultaneous devices on a port - by just setting a MAC threshold. Or we can also take it to the extreme and lock down each port to a hard-coded MAC address - which will never allow another device to connect. You might be thinking that the second method is absolutely ridiculous, but it really depends on the business needs.</p>
<p>First, let&rsquo;s take brief look at the typical port security configuration and some of the options available.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">SecureSwitch(config)# interface x/x  ! Whichever interface we want to lock down
</span></span><span class="line"><span class="cl">SecureSwitch(config-if)# switchport port-security max xx  ! Max number of MAC addresses that can be learned
</span></span><span class="line"><span class="cl">SecureSwitch(config-if)# switchport port-security violation xxxxx  ! Choose to either restrict or shutdown the port (description below)
</span></span><span class="line"><span class="cl">SecureSwitch(config-if)# switchport port-security  ! This actually enables the port security config
</span></span></code></pre></div><p>Fairly straight-forward, right? We choose a port (or you could do a range) and set a few options. The default number of MAC addresses able to be learned on a port is 1, so it&rsquo;s likely you&rsquo;re going to want to change this - unless 1 is all you need. Port security can only be enabled on <strong>access ports</strong>, so 1 MAC address works in most cases  - except where you have a PC daisy-chained off of an IP phone (in which case this will need to be set to 2 or 3).</p>
<p>Next we set our preferred violation action. This step is pretty important because it defines what happens when the port exceeds it&rsquo;s MAC count. <strong>Restrict</strong> is the passive approach. If we have two PC&rsquo;s plugged into a single access port (maybe using an unmanaged switch), then the second PC will just never be able to work as long as our max MAC limit is 1. The first PC to connect will be fine, and the switch will log a message and send an SNMP trap when the second MAC is picked up. <strong>Shutdown</strong> is the more forceful approach. Once that second MAC address turns up on the port, the switch puts the port in an err-disabled state - which shuts down the port to all traffic. This event is also logged and generates an SNMP trap - however the port will not come back online until an administrator manually re-enables it.</p>
<p>Now that we see a basic config, let&rsquo;s take a look at a few different use cases for this feature. In one of my previous jobs, I worked as a network admin for a local government organization. Port security configuration in that environment was <em>extremely</em> strict. Each switchport was configured to permit only one MAC address, shutdown upon violation, and the <code>switchport port-security mac-address sticky</code> command was also used. This command takes the first MAC address learned on the port and commits it to the running configuration, which means that this MAC is essentially hard-coded to be the <strong>only</strong> MAC permitted on the port. So in this environment, a single PC was tied to a single port - nothing else could ever be plugged into that port without either shutting down the port or administrator intervention. In a government office, this was absolutely necessary because every device on the network needed to be tracked and personal devices were not permitted to be connected. We needed to know if anything was ever plugged in that wasn&rsquo;t an authorized device - so manual intervention and investigation was a requirement.</p>
<p>In a more typical office environment - port security configurations can just be a good security practice without going overboard with it. We never want a user to plug in a rouge switch into our network without our knowledge, right? So maybe we assume each user has an IP phone and PC, and limit the port to 2 MAC addresses. In this case, we can go ahead and just set the port to restrict. We don&rsquo;t want to prevent the user from working if a port violation occurs, nor do we want to spend time resetting the port for them - but we might still want to be notified, especially if it happens often. In addition, port security is an excellent way to secure ports public areas. For example, maybe we have an IP phone or kiosk PC in our lobby. These need access to the network, but we don&rsquo;t want anyone to be able to unplug that device and gain access into our network. In cases like this, it would actually make sense to have the switch only permit access from that single MAC address.</p>
<p>Outside of the &lsquo;practical&rsquo; use cases, there is also the strictly security side of things. I&rsquo;ve touched on a few considerations already - but there are also certain types of attacks that can be defeated by port security. One of those would be exhausting the CAM table resources. A malicious person could use publicly available tools to spoof MAC addresses in the packets they send to the switch. Tools like this force the switch to learn hundreds of thousands of MAC addresses, which eventually will overload the CAM table. When a switch CAM table becomes full, the switch begins flooding packets out all interfaces. This is because the switch can no longer assign mappings between MAC addresses and the ports they originate from - so the switch has no choice but to flood everything and hope the correct recipient receives the data. For the attacker, this means they can run a packet capture on the port and collect information they wouldn&rsquo;t have otherwise needed to. This scenario could be prevented by implementing port security, which could simply restrict the number of MAC addresses learned off of any individual interface.</p>
<p>Port security configuration can be implemented in a few different ways depending on your use case. Overall though, it can prove to be a useful way to help implement security controls on your network.  What do you think about port security? Extremely useful or does it just get in the way? Comment below and tell me how you have implemented it!</p>
]]></content:encoded>
    </item>
    <item>
      <title>The Argument for Standardized Configurations</title>
      <link>https://0x2142.com/the-argument-for-standardized-configurations/</link>
      <pubDate>Tue, 31 Jan 2017 08:00:45 +0000</pubDate>
      <guid>https://0x2142.com/the-argument-for-standardized-configurations/</guid>
      <description>Snowflake network designs always make sense at the time. But what happens when there are no standards?</description>
      <content:encoded><![CDATA[<p>There are quite a few things that you don&rsquo;t realize how great they are until you don&rsquo;t have them anymore. For me, one of those things was standard guidelines for device configurations. At my last job, documented standards were extremely important - we had them for everything. While some devices might ultimately be configured in a slightly different manner to accommodate their specific purpose, the underlying basics were all configured exactly the same. Fast forward to where I am at now, and when I started there was no such thing. One device might be configured for management access only over the out of band interface, while a few others might allow management traffic over <em>every</em>interface. Some devices had SNMP configured, some didn&rsquo;t, and yet others had default credentials still enabled.</p>
<p>The problem here stemmed from the fact that there were no documented standards in place. An engineer was given a device to configure, and it was configured depending on who did it and what they felt needed configuring. In a few cases, this actually led to unnecessary security risks being introduced into the environment because something was left enabled. In one instance, this included open root SSH logins via the Internet to a production firewall. Scary, huh?</p>
<p>So how do we go about changing this? Here is a quick little guide I threw together on my method for tackling the situation:</p>
<h2 id="1-define-a-standard">1. Define a standard</h2>
<p>Begin creating a baseline document, whether it be a spreadsheet, word doc, or a wiki page. Start small and choose a single system, like your external firewalls for example.</p>
<h2 id="2-research-best-practices">2. Research best practices</h2>
<p>Check out the vendor&rsquo;s website to see what they recommend. There are also some amazing free resources out there like the Center for Internet Security&rsquo;s <a href="https://benchmarks.cisecurity.org/downloads/browse/index.cfm?category=benchmarks.network">configuration benchmarks</a>, Do your research - there is plenty available to help you.</p>
<h2 id="3-figure-out-whats-best-for-your-network">3. Figure out what&rsquo;s best for your network</h2>
<p>Not all of the best practices or security hardening guides will be a perfect fit for your environment. So it will take a little manual review to see what actually fits. For example, many of these guides recommend disabling local authentication in exchange for something centralized like TACACS+ or RADIUS. But if you don&rsquo;t have that available, then you&rsquo;re going to stick with local authentication. This can still be a great time to find room for future improvement projects though.</p>
<h2 id="4-test">4. Test</h2>
<p>If you have a development or test environment available, then run a device or two through your checklist and make sure there are no big issues. If you don&rsquo;t have a dedicated test area, then try and choose a low-impact device - where not much will be impacted if the changes go wrong.</p>
<h2 id="5-roll-out-the-changes">5. Roll out the changes</h2>
<p>Make sure you have a list of every device that needs to be touched, so that you have a way to validate. Then make the configuration changes to get each device into compliance with your new standards. Have a validation/testing checklist ready, so that you can quickly ensure that no production traffic was impacted</p>
<h2 id="6-train-your-peers">6. Train your peers</h2>
<p>Configuration standards only work well as long as <em>everyone</em>follows them. It only takes one person to ignore the checklist and potentially expose a vulnerability. So take an afternoon, schedule a training session with your team. Help them understand the importance of maintaining these standards, and train them on how to apply the changes (if necessary).</p>
<h2 id="7-automate">7. Automate</h2>
<p>This part is optional, but highly recommended. If nothing else, spend the time to automate verification of the standards - which will make it easy to locate a device that falls out of compliance. If you or your team have the skill set, then automate the entire process from initial deployment to continuous validation. Why is this the last step, instead of being included with the roll out? I am a firm believer that you should completely understand how your device functions and reacts to changes before automating those changes.</p>
<p>So that&rsquo;s more or less how I worked to implement a standardized configuration at my current job. I began with a completely new device platform that we were integrating into our environment, then began to go back to older device platforms. It might be a lot of upfront work, but it certainly helps me sleep better at night not having to wonder if there might be one device out there that&rsquo;s misconfigured (and will cause an issue later, due to that misconfiguration).</p>
<p>So let me know in the comments below - have you ever implemented something like this? If so, what did you do differently? If not, then let me know if you give this a try!</p>
]]></content:encoded>
    </item>
    <item>
      <title>BGP: Getting Started with Multi-homed Internet</title>
      <link>https://0x2142.com/bgp-getting-started-with-multi-homed-internet/</link>
      <pubDate>Tue, 10 Jan 2017 08:00:17 +0000</pubDate>
      <guid>https://0x2142.com/bgp-getting-started-with-multi-homed-internet/</guid>
      <description>Exploring which design/setup questions to ask, and how to begin a basic configuration</description>
      <content:encoded><![CDATA[<p>A few years back I worked for an organization that had a single 100Mb Internet connection. Not bad for just typical corporate traffic, but we also hosted our production web site out of that location as well. An incident occurred where our website was down due to Internet issues during an extremely inconvenient time. So we decided to procure a second Internet uplink through a different provider. At the time, I had no practical experience doing something like this - yet I was put in charge of the project. Let&rsquo;s go over some of what I learned&hellip;</p>
<p>The easy part of the whole process is the first step - ordering a second Internet connection. Our CIO at the time placed a few calls and had a quote back pretty quickly. A local carrier was willing to run new fiber cables to our building in less than a month. Depending on how important uptime is to your organization, this is the point where you might want to ask about a diverse path into the building. If both connections run though the same physical paths, then a single incident could still cause an outage. For example - I once worked somewhere where the redundant Internet connections shared the same telephone poll across the street. So even though the connections were redundant, a single accident involving that telephone poll and both connections were severed.</p>
<p>Next - Ask about IP space. In terms of IPv4, the general rule for external BGP peering is that ISP&rsquo;s don&rsquo;t like to accept any prefixes smaller than a /24. In our case, we had a single /25 block already allocated by our current provider - which wasn&rsquo;t going to work. Luckily, the new service provider offered to give up a free /24 block along with the installation costs. Unfortunately, this meant that we had to re-address all of our public-facing services, which is almost always a pain to do. I have a few tips for this, which helped us to minimize downtime - but that&rsquo;s a story for another time.</p>
<p>Next, we need to obtain a globally unique Autonomous System (AS) number, which will be used to advertise our network to the world. Since we were located in North America, we went though <a href="https://www.arin.net">ARIN</a> for this process - which was fairly painless. Sign up for an account, prove that you&rsquo;re associated with the business, fill out a few forms to justify your need, and then just wait for the approval. One thing to watch out for is 2-byte vs 4-byte AS numbers. 2-byte is the standard and has been around forever, but only allows for up to 65,535 unique IDs. A 4-byte ASN allows for significantly more unique IDs, but I have actually run into instances where an ISP doesn&rsquo;t support these. I would hope that in most cases a 4-byte ASN will be just fine, but it might be worth asking your ISP just in case.</p>
<p>At this point, you should be ready to hit the ground running as soon as that second Internet uplink is installed. This is also assuming you already run a router or multilayer switch on the edge of your network, which also has BGP capabilities. So let&rsquo;s get down to the fun stuff - an extremely basic configuration to peer between two ISPs. I&rsquo;ll dedicate another post to additional recommended settings and configurations - but for now let&rsquo;s focus on getting this running. The configuration sample below is aimed at Cisco devices, but the same concepts apply to most vendors:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">EdgeRouter(config)# router bgp *&lt;YOUR AS NUMBER&gt;  *! The AS number provided by ARIN
</span></span><span class="line"><span class="cl">EdgeRouter(config-router)# network *&lt;YOUR LOCAL SUBNET&gt;*   ! The subnet we need to advertise out both ISPs
</span></span><span class="line"><span class="cl">EdgeRouter(config-router)# neighbor *&lt;ISP1 PEER IP&gt;* remote-as *&lt;ISP1 ASN&gt;* ! Provided by the first ISP - Their remote peer IP and ASN
</span></span><span class="line"><span class="cl">EdgeRouter(config-router)# neighbor *&lt;ISP2 PEER IP&gt; *remote-as *&lt;ISP2 ASN&gt; *! Provided by the second ISP
</span></span></code></pre></div><p>As I mentioned, this config is very basic and will just accomplish what we need to get going. Follow up with a quick <code>show ip bgp neighbors</code> and hopefully you&rsquo;ll see two peers in the <em>established</em> state. Any other state indicates a problem bringing up the peer connection. I won&rsquo;t get into too much detail here - but check the physical connection, ping the peer, and make sure there are no firewalls blocking TCP port 179 between the peer addresses.</p>
<p>Hope this was helpful! Comment below and let me know how your experiences have gone with this type of setup - and look forward to a few more posts regarding BGP peering setup with multiple ISPs.</p>
]]></content:encoded>
    </item>
  </channel>
</rss>
