<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Zach's Blog]]></title><description><![CDATA[Thoughts, stories and ideas.]]></description><link>https://www.zacharyschneider.ca/</link><image><url>https://www.zacharyschneider.ca/assets/ghost-icon.png</url><title>Zach&apos;s Blog</title><link>https://www.zacharyschneider.ca/</link></image><generator>Ghost 5.130</generator><lastBuildDate>Tue, 04 Aug 2026 21:16:53 GMT</lastBuildDate><atom:link href="https://www.zacharyschneider.ca/rss.xml" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[🍞 Bread Recipe]]></title><description><![CDATA[<blockquote>Adapted from <a href="https://www.yummly.com/recipe/Basic-Bread-9082781?ref=zacharyschneider.ca">https://www.yummly.com/recipe/Basic-Bread-9082781</a></blockquote><ul><li>The original recipe asks you to preheat your oven right away, however that isn&apos;t necessary. Instead, if your house is particularly cold or to speed up the rising process, set your oven to the lowest setting then turn it off</li></ul>]]></description><link>https://www.zacharyschneider.ca/2023/04/bread-recipe/</link><guid isPermaLink="false">64347f5b5cbd990001bed7d2</guid><category><![CDATA[recipe]]></category><dc:creator><![CDATA[Zach Schneider]]></dc:creator><pubDate>Sun, 16 Apr 2023 16:24:18 GMT</pubDate><content:encoded><![CDATA[<blockquote>Adapted from <a href="https://www.yummly.com/recipe/Basic-Bread-9082781?ref=zacharyschneider.ca">https://www.yummly.com/recipe/Basic-Bread-9082781</a></blockquote><ul><li>The original recipe asks you to preheat your oven right away, however that isn&apos;t necessary. Instead, if your house is particularly cold or to speed up the rising process, set your oven to the lowest setting then turn it off before placing the dough inside to proof (with the door slightly open).</li><li>I have made this with oat milk instead of whole milk and coconut oil instead of butter and the bread turned out great!</li><li>I replaced a third of my whole-wheat bread flour with white all-purpose flour since I wanted a more mild flavour.</li></ul><p>Makes two loaves.</p><h2 id="ingredients">Ingredients</h2><ul><li><strong>olive oil</strong></li><li><strong>water</strong>, warm (40&#xB0;C &#x2013; 45&#xB0;C); 240 mL</li><li><strong>active dry yeast</strong>; 2 tsp.</li><li><strong>butter</strong>, unsalted; 30 g</li><li><strong>milk</strong>, whole or dairy-free; 240 mL</li><li><strong>honey</strong>; 40 g</li><li><strong>salt</strong>; 1 &#xBD; tsp.</li><li><strong>bread flour</strong>, whole-wheat; 560 g</li><li><strong>all-purpose flour</strong>, white; 275 g</li></ul><h2 id="directions">Directions</h2><h3 id="step-1">Step 1</h3><p>Grease two 9&quot; x 5&quot; load pans lightly with olive oil. Attach the dough hook to your stand mixer. Whisk the two flours together.</p><h3 id="step-2">Step 2</h3><p>Warm the mixer bowl by rinsing with some hot tap water. Pour in warm water and sprinkle the yeast over - let stand for about 5 minutes. In a small sauce pan, combine butter, milk, honey, and salt and heat over low heat until butter is melted - be careful not to boil.</p><h3 id="step-3">Step 3</h3><p>In the mixing bowl, add the warm milk mixture and two cups of the flour mixture. Turn the machine to speed 2 and mix until a batter-like consistency is acheived (2 &#x2013; 3 minutes). Add the remaining flour, &#xBD; cup at a time and continue mixing until the dough forms a ball and clings to the hook. Mix for another 3 &#x2013; 4 minutes - dough should be smooth and elastic and slightly sticky.</p><h3 id="step-4">Step 4</h3><p>On a lightly floured surface, form dough into a ball. Coat a large bowl lightly with olive oil and place dough in the bowl. Turn the ball of dough over to coat with oil. Cover bowl with a clean towel and let rise until double in size.</p><h3 id="step-5">Step 5</h3><p>Punch down dough in bowl and turn onto lightly floured surface, divide into two and let rest for 10 minutes. Pat each ball into an oval, fold into thirds and place into greased loaf pans. Cover pans with a clean towel and let rise until double in size.</p><p>Preheat oven to 220&#xB0;C.</p><h3 id="step-6">Step 6</h3><p>Place pans in oven and reduce heat to 190&#xB0;C and bake for 20 &#x2013; 25 minutes or until internal temperature reaches 87&#xB0;C. Loaves will sound hollow when tapped. Remove from pans and allow to fully cool before slicing.</p>]]></content:encoded></item><item><title><![CDATA[A Web-Based Serial Console]]></title><description><![CDATA[<p>Your web browser can probably communicate with a serial port. That is, if you&apos;re using Chrome or a derivative of Chromium (<a href="https://mozilla.github.io/standards-positions/?ref=zacharyschneider.ca#webserial">Firefox</a> and <a href="https://webkit.org/status/?ref=zacharyschneider.ca#feature-webusb">Safari</a> are rather opposed to the idea of giving access to USB/serial ports). Yes, that 1980s technology is still alive!</p><blockquote>TL;DR - <a href="https://console.zacharyschneider.ca/?ref=zacharyschneider.ca">console.</a></blockquote>]]></description><link>https://www.zacharyschneider.ca/2021/04/a-web-based-serial-console/</link><guid isPermaLink="false">60c2fa8326211e000116dedb</guid><category><![CDATA[Open Source]]></category><category><![CDATA[dev]]></category><dc:creator><![CDATA[Zach Schneider]]></dc:creator><pubDate>Fri, 30 Apr 2021 06:46:49 GMT</pubDate><content:encoded><![CDATA[<p>Your web browser can probably communicate with a serial port. That is, if you&apos;re using Chrome or a derivative of Chromium (<a href="https://mozilla.github.io/standards-positions/?ref=zacharyschneider.ca#webserial">Firefox</a> and <a href="https://webkit.org/status/?ref=zacharyschneider.ca#feature-webusb">Safari</a> are rather opposed to the idea of giving access to USB/serial ports). Yes, that 1980s technology is still alive!</p><blockquote>TL;DR - <a href="https://console.zacharyschneider.ca/?ref=zacharyschneider.ca">console.zacharyschneider.ca</a></blockquote><p>While I was researching the <s><code>Feature-Policy</code></s> <code>Permissions-Policy</code> header, I was curious about the <code>usb</code> API permission and what kind capabilities that might give a web page. Turns out that feature also includes the <a href="https://wicg.github.io/serial/?ref=zacharyschneider.ca">Web Serial API</a> proposal. I thought it would be neat to use a web browser as a serial console for various devices that communicate over RS-232. Right away, I envisioned connecting to an Arduino, a Raspberry Pi, or Netgate pfSense firewall appliances with only a web browser (bye-bye PuTTY). Only caveat is that you need a working internet connection is required... or do you?</p><p>This was also a great opportunity to try creating my first real Vue application. I settled on <a href="https://vitejs.dev/?ref=zacharyschneider.ca">Vite</a> for the TypeScript and VS Code integration. <a href="https://tailwindcss.com/?ref=zacharyschneider.ca">Tailwind CSS</a> to make things look pretty. <a href="https://xtermjs.org/?ref=zacharyschneider.ca">Xterm.js</a> to power the terminal (also used by VS Code&apos;s integrated terminal). All settings are saved to local storage and everything happens in the browser &#x2013; no tracking, fingerprinting, analytics, or data sent back to a server. The app is served by Cloudflare Pages too, without cross-domain dependencies like Google Fonts or third-party libraries. In fact, it should be trivial to make it an installable PWA which would enable offline access.</p>]]></content:encoded></item><item><title><![CDATA[Configuring pfSense and IPv6 on a Telus connection]]></title><description><![CDATA[This is how I've configured my pfSense firewall to support IPv6 on the Telus network.]]></description><link>https://www.zacharyschneider.ca/2020/12/pfsense-ipv6-telus/</link><guid isPermaLink="false">60c2fa8326211e000116ded6</guid><category><![CDATA[pfSense]]></category><category><![CDATA[guide]]></category><category><![CDATA[IPv6]]></category><dc:creator><![CDATA[Zach Schneider]]></dc:creator><pubDate>Sat, 26 Dec 2020 00:00:00 GMT</pubDate><content:encoded><![CDATA[<p>Telus is the major fibre optic and vDSL internet provider in my province. Telus started offering IPv6 sometime around May, 2015 to eligible subscribers on Telus&apos;s converged edge network (provided their local Central Office (CO) was upgraded to supported IPv6). Telus&apos;s IPv6 rollout was completed around mid-2016. Currently, Telus assigns subscribers a <strong>/56</strong> prefix (which is equivalent 256 <strong>/64</strong> networks, more than enough for the average home user).</p><p>Telus&apos;s modems only use <code>IA_PD</code> (Identity Association for Prefix Delegation) and do not use <code>IA_NA</code> (Identity Association for Non-Temporary Addresses). Thus, pfSense must be configured to only request <code>IA_PD</code>.</p><h2 id="modem-configuration">Modem Configuration</h2><p>If you have one of Telus&apos;s &quot;advanced&quot; modems, you must configure the modem to use <em>Port 1 Bridge</em> mode and connect the WAN interface of pfSense to LAN #1 on the modem. However, if you&apos;re lucky enough to obtain a T2200M bridged modem, a Nokia G-010S-A SFP ONT module, or have a Nokia (formerly Alcatel-Lucent) G-240G-A ONT, you can connect directly to the WAN port of those modems/ONTs. The Nokia SFP ONT module has limited support in switching/router hardware.</p><!--kg-card-begin: markdown--><table>
<thead>
<tr>
<th>Modem/ONT</th>
<th>Port</th>
<th>Network</th>
<th>Notes</th>
</tr>
</thead>
<tbody>
<tr>
<td>V1000H, V2000H, T1200H, T2200H, T3200M</td>
<td>LAN 1</td>
<td>DSL</td>
<td>Must use <em>Port 1 Bridge</em> mode</td>
</tr>
<tr>
<td>T2200M</td>
<td>GigE</td>
<td>DSL</td>
<td>Plug-and-Play</td>
</tr>
<tr>
<td>Nokia ONT</td>
<td>Data 1</td>
<td>GPON</td>
<td>Plug-and-Play</td>
</tr>
<tr>
<td>Nokia SFP ONT</td>
<td>&#x2014;</td>
<td>GPON</td>
<td>Residential only; limited vendor support</td>
</tr>
</tbody>
</table>
<!--kg-card-end: markdown--><h2 id="pfsense-configuration">pfSense Configuration</h2><p>I&apos;ve successfully tested this configuration on Telus&apos;s GPON and DSL networks.</p><h4 id="enable-ipv6">Enable IPv6</h4><p>If you haven&apos;t already, pfSense must have IPv6 support turned on. Under <code>System</code> &gt; <code>Advanced</code> &gt; <code>Networking</code> &gt; <code>IPv6 Options</code>, enable <strong>Allow IPv6</strong>.</p><p>Next, configure your <strong>WAN</strong> interface:</p><ul><li><code>Interfaces</code> &gt; <code>WAN</code> &gt; <code>General Configuration</code>:</li><li><strong>IPv6 Configuration Type</strong>: <em>DHCP6</em></li><li><code>Interfaces</code> &gt; <code>WAN</code> &gt; <code>DHCP6 Client Configuration</code>:</li><li><strong>Request only an IPv6 prefix</strong>: <em>Enabled</em></li><li><strong>DHCPv6 Prefix Delegation size</strong>: <em>56</em></li><li><strong>Send IPv6 prefix hint</strong>: <em>Enabled</em></li><li><strong>Do not wait for a RA</strong>: <em>Enabled</em> (request a prefix from the Telus router immediately)</li><li><strong>Do not allow PD release</strong>: <em>Enabled</em></li></ul><h4 id="lan-interface-s-">LAN Interface(s)</h4><p>You can configure multiple LAN interfaces to support IPv6, all you have to do is assign a different <strong>IPv6 Prefix ID</strong> to each LAN interface that should be IPv6 capable. E.g. A prefix ID for your private LAN, another for your guest network, but none for your IPv4-only VoIP network.</p><p>Configure the <strong>LAN</strong> interface to tack the <strong>WAN</strong> interface:</p><ul><li><code>Interfaces</code> &gt; <code>LAN</code> &gt; <code>General Configuration</code>:</li><li><strong>IPv6 Configuration Type</strong>: <em>Track Interface</em></li><li><code>Interfaces</code> &gt; <code>LAN</code> &gt; <code>Track IPv6 Interface</code>:</li><li><strong>IPv6 Interface</strong>: <em>WAN</em></li><li><strong>IPv6 Prefix ID</strong>: <em>0</em> (or something else, depending on how many other interfaces are tracking the WAN interface)</li></ul><h5 id="dhcp-router-advertisements">DHCP &amp; Router Advertisements</h5><p>There are a few ways for hosts to obtain IPv6 addresses: SLAAC (StateLess Address AutoConfiguration), DHCPv6, or a combination of both. In each case, Router Advertisements are required. Which method to use depends on your network&apos;s requirements and potential hosts. For example: Android does not (<a href="https://issuetracker.google.com/issues/36949085?ref=zacharyschneider.ca">and will not</a>) support DHCPv6, Windows 10 supports DHCPv6 and SLAAC (although SLAAC + RDNSS support was missing until version 1703).</p><h6 id="slaac">SLAAC</h6><p>Since I don&apos;t need the extra features of stateful DHCPv6, I&apos;ll use SLAAC to obtain addresses and the RDNSS RA option (<a href="https://tools.ietf.org/html/rfc8106?ref=zacharyschneider.ca">RFC 8106</a>) to provide DNS configuration. In pfSense, this is the <strong>Unmanaged</strong> RA mode. If the <strong>Stateless DHCP</strong> RA mode was used, the DHCPv6 server would have to be enabled in order to provide additional information, like which DNS servers to use.</p><p>To configure Router Advertisements for the LAN interface:</p><ul><li><code>Services</code> &gt; <code>DHCPv6 Server &amp; RA</code> &gt; <code>LAN</code> &gt; <code>DHCPv6 Server</code>:</li><li><strong>DHCPv6 Server</strong>: <em>Disable</em></li><li><code>Services</code> &gt; <code>DHCPv6 Server &amp; RA</code> &gt; <code>LAN</code> &gt; <code>Router Advertisements</code>:</li><li><strong>Router mode</strong>: <em>Unmanaged</em></li></ul><p>In this configuration, pfSense (CPE) will request a prefix from Telus (BNG). Once a network prefix is delegated, Telus will route traffic for that prefix to the customer&apos;s router (pfSense), which will then advertise itself as the DNS server and direct hosts to obtain addresses using SLAAC and the obtained prefix. Clients that support SLAAC will assign their own IPv6 addresses (avoiding address collisions with the Duplicate Address Detection extension of the Neighbour Discovery Protocol) and use pfSense as the DNS server (from the RDNSS option). This configuration is compatible with pfSense&apos;s DNS resolver (unbound).</p><h6 id="stateless-dhcpv6">Stateless DHCPv6</h6><p>This approach still uses SLAAC to obtain addresses but introduces DHCPv6 for obtaining other configuration (like DNS, NTP, etc) after the SLAAC process is finished. Enable the <strong>DHCPv6 Server</strong> for the interface and set the router advertisement mode to <strong>Stateless DHCP</strong>. This configuration is called <em>stateless</em> because pfSense does not keep track of any client leases.</p><h6 id="stateful-dhcpv6">Stateful DHCPv6</h6><p>This approach does not use SLAAC (although some clients will still use SLAAC to generate a &quot;privacy&quot; address) and all configuration is done with DHCPv6. Enable the <strong>DHCPv6 Server</strong> for the interface and set the router advertisement mode to <strong>Managed</strong>.</p><p><em>Note:</em> The <em>Assisted</em> mode in pfSense is almost identical to the <em>Managed</em> mode, except the <code>A</code> flag is also set, which allows hosts to use SLAAC and/or DHCPv6 for address configuration and DNS information.</p><h5 id="more-on-ra-flags">More on RA Flags</h5><p>When a host sends a Router Solicitation (RS) message and a router replies with an RA message, it contains flags that tell the host how to obtain an IPv6 address:</p><!--kg-card-begin: markdown--><table>
<thead>
<tr>
<th>Flag</th>
<th></th>
<th>Meaning</th>
</tr>
</thead>
<tbody>
<tr>
<td>L</td>
<td>On-Link</td>
<td>Addresses with the same prefix are on the same L2 subnet</td>
</tr>
<tr>
<td>M</td>
<td>Managed</td>
<td>Use DHCPv6 for IPv6 address assignment</td>
</tr>
<tr>
<td>O</td>
<td>Other</td>
<td>Other configuration is available through DHCPv6. E.g. DNS servers</td>
</tr>
<tr>
<td>A</td>
<td>Autonomous</td>
<td>Use the advertised prefix for SLAAC (<a href="https://tools.ietf.org/html/rfc4862?ref=zacharyschneider.ca">RFC 4862</a>)</td>
</tr>
</tbody>
</table>
<!--kg-card-end: markdown--><p>In pfSense, these flags are controlled by the <strong>Router Mode</strong> setting for the interface:</p><!--kg-card-begin: markdown--><table>
<thead>
<tr>
<th>Router Mode</th>
<th>Flags</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Disabled</strong></td>
<td>&#x2014;</td>
</tr>
<tr>
<td><strong>Router Only</strong></td>
<td>&#x2014;</td>
</tr>
<tr>
<td><strong>Unmanaged</strong></td>
<td>A</td>
</tr>
<tr>
<td><strong>Managed</strong></td>
<td>M+O</td>
</tr>
<tr>
<td><strong>Assisted</strong></td>
<td>M+O+A</td>
</tr>
<tr>
<td><strong>Stateless DHCP</strong></td>
<td>A+O</td>
</tr>
</tbody>
</table>
<!--kg-card-end: markdown--><p>In all modes except <em>Disabled</em> and <em>Router Only</em>, the <strong>On-Link (L)</strong> flag will also be present.</p><p><a href="https://docs.netgate.com/pfsense/en/latest/services/dhcp/ipv6-ra.html?ref=zacharyschneider.ca#router-advertisements-or-where-is-the-dhcpv6-gateway-option">More information on the different router modes in pfSense.</a></p><h2 id="a-note-on-dsl">A Note on DSL</h2><p>A somewhat annoying issue I&apos;ve faced with a DSL connection and pfSense is that the modem sometimes takes a while to sync again after a power failure. pfSense will sometimes hang during boot or it will never get an IP address, completely preventing remote access. This appears to happen because the physical link is up between the firewall and the modem, but there is no response from the modem until it is ready. A solution that has worked so far is delaying the boot time so that the modem has a chance to sync with the DSLAM, before pfSense tries to request &#xA0;a lease.</p><p>There are two options available for delaying the boot process:</p><figure class="kg-card kg-code-card"><pre><code>###  Loader settings  ########################################
#loader_delay=&quot;3&quot;		# Delay in seconds before loading anything.
				# Default is unset and disabled (no delay).
#autoboot_delay=&quot;10&quot;		# Delay in seconds before autobooting,
				# -1 for no user interrupts, NO to disable</code></pre><figcaption><code>/boot/loader.conf.local</code></figcaption></figure><p>These are added to <code>/boot/loader.conf.local</code> so that they are preserved across reboots and upgrades. I&apos;ve been successful in using <code>loader_delay=&quot;60&quot;</code>.</p>]]></content:encoded></item></channel></rss>