<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.3.4">Jekyll</generator><link href="http://spmzt.net/feed.xml" rel="self" type="application/atom+xml" /><link href="http://spmzt.net/" rel="alternate" type="text/html" /><updated>2026-05-21T12:52:55+03:30</updated><id>http://spmzt.net/feed.xml</id><title type="html">Pouria’s Network (AS214145)</title><subtitle>My website is designed to be user-friendly and free from any intrusive ads, tracking cookies, or other nuisances that are common on the internet. Moreover, it&apos;s designed to be accessible to users who prefer to browse with JavaScript disabled and connect with IPv6.</subtitle><author><name>Seyed Pouria Mousavizadeh Tehrani</name><email>info@spmzt.net</email></author><entry><title type="html">Understanding FreeBSD’s Route Metric</title><link href="http://spmzt.net/2026/05/21/FreeBSD-Route-Metric/" rel="alternate" type="text/html" title="Understanding FreeBSD’s Route Metric" /><published>2026-05-21T12:17:00+03:30</published><updated>2026-05-21T12:17:00+03:30</updated><id>http://spmzt.net/2026/05/21/FreeBSD-Route-Metric</id><content type="html" xml:base="http://spmzt.net/2026/05/21/FreeBSD-Route-Metric/"><![CDATA[<h2 id="understanding-freebsds-route-metric">Understanding FreeBSD’s Route Metric</h2>

<p>Route metrics are a fundamental networking concept that determine which path traffic takes when multiple routes to the same destination exist.
FreeBSD CURRENT now has full metric support in the routing stack.</p>

<p>Let me walk you through how it works with a practical example.</p>

<h2 id="what-is-a-metric">What is a Metric?</h2>

<p>A metric is a numeric value assigned to a route that influences route selection.</p>

<p>When you have multiple routes to the same destination, the kernel prefers the route with the lowest metric.</p>

<p>Think of it as a “cost”, lower cost = preferred path.</p>

<h2 id="default-metric-behavior">Default Metric Behavior</h2>

<p>When you create a route without specifying a metric, FreeBSD assigns a default metric of 1.</p>

<h2 id="wildcard-metric-behavior">Wildcard Metric Behavior</h2>

<p>We don’t allow you to create a route with metric of 0, That one is used for wildcard.
You can delete all of the nexthops without specifiying route metric.</p>

<p>Its netlink behavior is also consistent.
Either you don’t have <code class="language-plaintext highlighter-rouge">RTA_PRIORITY</code> or you have one with metric of zero.</p>

<p>If you’re creating a route, it means you’re not specifying its metric, which means default metric (1).
If you’re deleting a route, it means you don’t care about its metric, you want to delete all of them.</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Create a route without specifying metric</span>
route <span class="nt">-6</span> add <span class="nt">-net</span> 3fff:a::/64 <span class="nt">-gateway</span> 3fff::1

<span class="c"># The route automatically gets metric 1</span>
route <span class="nt">-n6</span> get 3fff:a::/64
netstat <span class="nt">-rn6W</span>
</code></pre></div></div>

<p>This is useful because it means all “equal” routes start with the same priority, and you can selectively add routes with higher metrics as fallbacks.</p>

<h2 id="scenario-building-a-tiered-routing">Scenario: Building a Tiered Routing</h2>

<p>Let’s say you’re a network operator managing traffic to network <code class="language-plaintext highlighter-rouge">3fff:a::/64</code>. You want:</p>

<ol>
  <li>Primary paths (metric 10): Two equal-cost gateways for load balancing</li>
  <li>Secondary path (metric 20): A backup gateway that’s only used if primaries fail</li>
  <li>Fallback path (metric 30): A better gateway that becomes available later</li>
</ol>

<h3 id="step-1-add-primary-ecmp-routes">Step 1: Add Primary ECMP Routes</h3>

<p>You start by creating an Equal-Cost Multi-Path (ECMP) setup with two gateways at metric 10:</p>

<p>For the sake of this example, I want this ECMP route to be unbalanced.</p>
<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>% route <span class="nt">-6</span> add <span class="nt">-net</span> 3fff:a::/64 <span class="nt">-gateway</span> 3fff::2 <span class="nt">-metric</span> 10
add net 3fff:a::/64: gateway 3fff::2 fib 0
% route <span class="nt">-6</span> add <span class="nt">-net</span> 3fff:a::/64 <span class="nt">-gateway</span> 3fff::3 <span class="nt">-weight</span> 2 <span class="nt">-metric</span> 10
% route <span class="nt">-on6</span> get 3fff:a::/64
route to: 3fff:a::
destination: 3fff:a::
mask: ffff:ffff:ffff:ffff::
fib: 0
flags: &lt;UP,GATEWAY,DONE,STATIC&gt;
nhops: 2
via gw 3fff::2 iface vtnet1 metric 10 weight 1 mtu 1500 table inet6.0
via gw 3fff::3 iface vtnet1 metric 10 weight 2 mtu 1500
</code></pre></div></div>

<p>The -weight 2 parameter indicates these are NOT equally balanced within the ECMP group.
Traffic to <code class="language-plaintext highlighter-rouge">3fff:a::/64</code> now load-balances between the two gateways.</p>

<h4 id="verify-unbalanced-ecmp">Verify unbalanced ECMP</h4>

<p>See the value of Slots column:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>% netstat <span class="nt">-On6W</span>
Nexthop <span class="nb">groups </span>data

Internet6:
GrpIdx  NhIdx   Weight  Slots                       Gateway Netif  Refcnt
14      <span class="nt">-------</span> <span class="nt">-------</span> <span class="nt">-------</span> <span class="nt">---------------------------</span> <span class="nt">-----</span>       2
        12      1       1                           3fff::2 vtnet1
        13      2       2                           3fff::3 vtnet1
</code></pre></div></div>

<p>Current best route: 3fff::2 or 3fff::3 (metric 10)
Backup: (none yet)</p>

<h3 id="step-2-add-a-backup-route">Step 2: Add a Backup Route</h3>

<p>Next, you add a backup gateway with a higher metric (20), so it’s only used if the primary routes fail:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>% route <span class="nt">-6</span> add <span class="nt">-net</span> 3fff:a::/64 <span class="nt">-gateway</span> 3fff::1 <span class="nt">-metric</span> 20
add net 3fff:a::/64: gateway 3fff::1 fib 0
% <span class="c"># Verify the results</span>
% route <span class="nt">-on6</span> get 3fff:a::/64
route to: 3fff:a::
destination: 3fff:a::
mask: ffff:ffff:ffff:ffff::
fib: 0
flags: &lt;UP,GATEWAY,DONE,STATIC&gt;
nhops: 3
via gw 3fff::2 iface vtnet1 metric 10 weight 1 mtu 1500 table inet6.0
via gw 3fff::3 iface vtnet1 metric 10 weight 2 mtu 1500
via gw 3fff::1 iface vtnet1 metric 20 weight 1 mtu 1500
% netstat <span class="nt">-On6W</span>
Nexthop <span class="nb">groups </span>data

Internet6:
GrpIdx  NhIdx   Weight  Slots                       Gateway Netif  Refcnt
16      <span class="nt">-------</span> <span class="nt">-------</span> <span class="nt">-------</span> <span class="nt">---------------------------</span> <span class="nt">-----</span>       2
        12       1       0                          3fff::2 vtnet1
        13       2       2                          3fff::3 vtnet1
        15       1       0                          3fff::1 vtnet1
</code></pre></div></div>

<p>The system now has three routes, but only uses the metric 10 paths:</p>

<p>Current best route: 3fff::2 or 3fff::3 (metric 10)
Backup: 3fff::1 (metric 20), waiting in the RIB</p>

<h3 id="step-3-attempting-duplicates-what-fails">Step 3: Attempting Duplicates (What Fails)</h3>

<p>If you try to add the same gateway with the same metric again, the system rejects it:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>% route <span class="nt">-6</span> add <span class="nt">-net</span> 3fff:a::/64 <span class="nt">-gateway</span> 3fff::1 <span class="nt">-metric</span> 20
route: message indicates error: File exists
add net 3fff:a::/64: gateway 3fff::1 fib 0: route already <span class="k">in </span>table
</code></pre></div></div>

<p>This prevents accidental duplicates.</p>

<h3 id="step-4-promoting-a-better-gateway">Step 4: Promoting a Better Gateway</h3>

<p>Now your new, faster gateway 3fff::1 becomes available.
You can immediately promote it to metric 5, better than the current metric 20 routes:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>% route <span class="nt">-6</span> add <span class="nt">-net</span> 3fff:a::/64 <span class="nt">-gateway</span> 3fff::1 <span class="nt">-metric</span> 5
add net 3fff:a::/64: gateway 3fff::1 fib 0
% route <span class="nt">-on6</span> get 3fff:a::/64
route to: 3fff:a::
destination: 3fff:a::
mask: ffff:ffff:ffff:ffff::
fib: 0
flags: &lt;UP,GATEWAY,DONE,STATIC&gt;
nhops: 4
via gw 3fff::2 iface vtnet1 metric 10 weight 1 mtu 1500 table inet6.0
via gw 3fff::3 iface vtnet1 metric 10 weight 2 mtu 1500
via gw 3fff::1 iface vtnet1 metric 5 weight 1 mtu 1500
via gw 3fff::1 iface vtnet1 metric 20 weight 1 mtu 1500
% netstat <span class="nt">-On6W</span>
Nexthop <span class="nb">groups </span>data

Internet6:
GrpIdx  NhIdx   Weight  Slots                      Gateway Netif  Refcnt
17      <span class="nt">-------</span> <span class="nt">-------</span> <span class="nt">-------</span> <span class="nt">--------------------------</span> <span class="nt">-----</span>       2
        12       1       0                         3fff::2 vtnet1
        13       2       0                         3fff::3 vtnet1
        14       1       1                         3fff::1 vtnet1
        15       1       0                         3fff::1 vtnet1
</code></pre></div></div>

<p>The routing table now has four routes, but the best one changes:</p>

<p>Current best route: 3fff::1 (metric 5, NEW PRIMARY)
Alternate: 3fff::2, 3fff::3 (metric 10)
Backup: 3fff::1 (metric 20, This one is shadowed now)</p>

<h2 id="advanced-selective-route-deletion">Advanced: Selective Route Deletion</h2>

<p>The metric system also enables fine-grained route deletion.
You can delete routes by:</p>

<ul>
  <li>Gateway + Metric: Remove a specific route</li>
  <li>Gateway only: Remove all routes to that gateway</li>
  <li>Metric only: Remove all routes with that metric</li>
</ul>

<h3 id="example-clean-up-by-metric">Example: Clean Up by Metric</h3>

<p>After the gateway <code class="language-plaintext highlighter-rouge">3fff::1</code> at metric 5 has proven stable, you can remove the old metric 20 routes without affecting your ECMP setup:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>% route <span class="nt">-n6</span> delete <span class="nt">-net</span> 3fff:a::/64 <span class="nt">-metric</span> 20
delete net 3fff:a::/64 fib 0
% route <span class="nt">-on6</span> get 3fff:a::/64
route to: 3fff:a::
destination: 3fff:a::
mask: ffff:ffff:ffff:ffff::
fib: 0
flags: &lt;UP,GATEWAY,DONE,STATIC&gt;
nhops: 3
via gw 3fff::2 iface vtnet1 metric 10 weight 1 mtu 1500 table inet6.0
via gw 3fff::3 iface vtnet1 metric 10 weight 2 mtu 1500
via gw 3fff::1 iface vtnet1 metric 5 weight 1 mtu 1500
</code></pre></div></div>

<p>Now you have:</p>

<ul>
  <li>3fff::1 (metric 5) - best</li>
  <li>3fff::2, 3fff::3 (metric 10) - secondaries</li>
</ul>

<p>Or, remove a specific gateway from ECMP without touching other metrics:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>% route <span class="nt">-n6</span> delete <span class="nt">-net</span> 3fff:a::/64 <span class="nt">-gateway</span> 3fff::3 <span class="nt">-metric</span> 10
delete net 3fff:a::/64: gateway 3fff::3 fib 0
% route <span class="nt">-on6</span> get 3fff:a::/64
route to: 3fff:a::
destination: 3fff:a::
mask: ffff:ffff:ffff:ffff::
fib: 0
flags: &lt;UP,GATEWAY,DONE,STATIC&gt;
nhops: 2
via gw 3fff::2 iface vtnet1 metric 10 weight 1 mtu 1500 table inet6.0
via gw 3fff::1 iface vtnet1 metric 5 weight 1 mtu 1500
% netstat <span class="nt">-On6W</span>
Nexthop <span class="nb">groups </span>data

Internet6:
GrpIdx  NhIdx   Weight  Slots                      Gateway Netif  Refcnt
15      <span class="nt">-------</span> <span class="nt">-------</span> <span class="nt">-------</span> <span class="nt">--------------------------</span> <span class="nt">-----</span>       2
        12      1       0                          3fff::2 vtnet1
        14      1       1                          3fff::1 vtnet1
</code></pre></div></div>

<h2 id="viewing-metrics-in-netstat">Viewing Metrics in netstat</h2>

<p>You can now see metric values in netstat output:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>netstat <span class="nt">-rn6</span> <span class="nt">-W</span>  <span class="c"># Wide output includes metric</span>
netstat <span class="nt">-rn6</span> <span class="nt">--libxo</span> json  <span class="c"># Structured output with metric field</span>
</code></pre></div></div>

<h3 id="metric-filtering-using-netstat">metric filtering using netstat</h3>

<p>You can find the metric attribute in libxo output.</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>% netstat <span class="nt">-rn6</span> <span class="nt">--libxo</span> json | jq <span class="s1">'.statistics."route-information"."route-table"."rt-family".[]."rt-entry".[] | select(.destination | contains("3fff:a::/64"))'</span>
</code></pre></div></div>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
    </span><span class="nl">"destination"</span><span class="p">:</span><span class="w"> </span><span class="s2">"3fff:a::/64"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"gateway"</span><span class="p">:</span><span class="w"> </span><span class="s2">"3fff::2"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"flags"</span><span class="p">:</span><span class="w"> </span><span class="s2">"UGS"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"flags_pretty"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
        </span><span class="s2">"up"</span><span class="p">,</span><span class="w">
      </span><span class="s2">"gateway"</span><span class="p">,</span><span class="w">
      </span><span class="s2">"static"</span><span class="w">
        </span><span class="p">],</span><span class="w">
      </span><span class="nl">"weight"</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w">
      </span><span class="nl">"metric"</span><span class="p">:</span><span class="w"> </span><span class="mi">10</span><span class="p">,</span><span class="w">
      </span><span class="nl">"nhg-kidx"</span><span class="p">:</span><span class="w"> </span><span class="mi">15</span><span class="p">,</span><span class="w">
      </span><span class="nl">"interface-name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"vtnet1"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">{</span><span class="w">
    </span><span class="nl">"destination"</span><span class="p">:</span><span class="w"> </span><span class="s2">"3fff:a::/64"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"gateway"</span><span class="p">:</span><span class="w"> </span><span class="s2">"3fff::1"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"flags"</span><span class="p">:</span><span class="w"> </span><span class="s2">"UGS"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"flags_pretty"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
        </span><span class="s2">"up"</span><span class="p">,</span><span class="w">
      </span><span class="s2">"gateway"</span><span class="p">,</span><span class="w">
      </span><span class="s2">"static"</span><span class="w">
        </span><span class="p">],</span><span class="w">
      </span><span class="nl">"weight"</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w">
      </span><span class="nl">"metric"</span><span class="p">:</span><span class="w"> </span><span class="mi">5</span><span class="p">,</span><span class="w">
      </span><span class="nl">"nhg-kidx"</span><span class="p">:</span><span class="w"> </span><span class="mi">15</span><span class="p">,</span><span class="w">
      </span><span class="nl">"interface-name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"vtnet1"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<h2 id="viewing-all-nexthops-of-a-route">Viewing all nexthops of a route</h2>

<p>You can now see all the nexthops of a route in route output:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>% route <span class="nt">-on</span> 3fff:a::/64
route to: 3fff:a::
destination: 3fff:a::
mask: ffff:ffff:ffff:ffff::
fib: 0
flags: &lt;UP,GATEWAY,DONE,STATIC&gt;
nhops: 3
via gw 3fff::2 iface vtnet1 metric 10 weight 1 mtu 1500 table inet6.0
via gw 3fff::3 iface vtnet1 metric 10 weight 2 mtu 1500
via gw 3fff::1 iface vtnet1 metric 5 weight 1 mtu 1500
</code></pre></div></div>

<h2 id="bird">Bird</h2>

<p>By default bird uses metric value of 32 during route installation, you can overwrite it by setting metric keyword in kernel section:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>protocol kernel kernel6 <span class="o">{</span>
	metric 1<span class="p">;</span>
	ipv6 <span class="o">{</span>
		import all<span class="p">;</span>
		<span class="nb">export </span>all<span class="p">;</span>
	<span class="o">}</span><span class="p">;</span>
	learn all<span class="p">;</span>
	merge paths<span class="p">;</span>
<span class="o">}</span>
</code></pre></div></div>]]></content><author><name>Seyed Pouria Mousavizadeh Tehrani</name><email>info@spmzt.net</email></author><category term="Style" /><summary type="html"><![CDATA[Understanding FreeBSD’s Route Metric]]></summary></entry><entry><title type="html">Exploring the FreeBSD UMA</title><link href="http://spmzt.net/2025/05/02/Exploring-UMA/" rel="alternate" type="text/html" title="Exploring the FreeBSD UMA" /><published>2025-05-02T00:43:00+03:30</published><updated>2025-05-02T00:43:00+03:30</updated><id>http://spmzt.net/2025/05/02/Exploring-UMA</id><content type="html" xml:base="http://spmzt.net/2025/05/02/Exploring-UMA/"><![CDATA[<p>I’m trying to learn UMA or general-purpose kernel object allocator through the kernel source code.
This approach maybe weird, but the FreeBSD source code is organized and clear.
Worth mentioning that it’s documentation inside source code and has its own manual <em>uma(9)</em>.</p>

<h2 id="what-is-uma">What is UMA?</h2>

<p>Let’s look at the manual first:</p>

<blockquote>
  <p>UMA (Universal Memory Allocator) provides an efficient interface for
managing dynamically-sized collections of items of identical size,
referred to as zones.</p>
</blockquote>

<p>Looks like UMA directly responsible for zones. But, what are zones?
The manual continues with:</p>

<blockquote>
  <p>Zones keep track of which items are in use and
which are not, and UMA provides functions for allocating items from a
zone and for releasing them back, making them available for subsequent
allocation requests.</p>
</blockquote>

<p>Ok, I should start looking for its code.</p>

<h2 id="where-to-start">Where to start?</h2>

<p>As defined in SYNOPSIS of <em>UMA(9)</em>, the source code resides in <code class="language-plaintext highlighter-rouge">/usr/src/sys/vm/</code>. So let’s list files with uma in their names.</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">[</span>spmzt@cornelia] <span class="o">[</span>/usr/src/sys/vm] % <span class="nb">ls</span> <span class="k">*</span>uma<span class="k">*</span>              
uma_align_mask.h	uma_core.c		uma_dbg.c		uma_dbg.h		uma_int.h		uma.h
</code></pre></div></div>

<p>By seeing their namees, I instantly know I should start with <code class="language-plaintext highlighter-rouge">uma_core.c</code> for the main code and <code class="language-plaintext highlighter-rouge">uma.h</code> for it’s header.</p>

<p>Now, I probably should looking for zone structures, let’s open the <code class="language-plaintext highlighter-rouge">uma.h</code> first.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/* Types and type defs */</span>
<span class="k">struct</span> <span class="n">uma_zone</span><span class="p">;</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">uma_zone</code> structure is the first structure defined in the system. However, as you can see, it’s a forward declaration.
We should find it. If you familiar with <code class="language-plaintext highlighter-rouge">style(9)</code>, you can easily find your desired code in the FreeBSD kernel.</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">[</span>root@cornelia] <span class="o">[</span>/usr/src/sys/vm] <span class="c"># grep -ri '^struct uma_zone {'</span>
uma_int.h:struct uma_zone <span class="o">{</span>
</code></pre></div></div>

<p>Yup, it did the trick. our main zone structure is defined in <code class="language-plaintext highlighter-rouge">uma_int.h</code>.
After, I opened the <code class="language-plaintext highlighter-rouge">uma_int.h</code> file, I saw more than hundered of documentation at the beginning of the file.</p>

<p>Here is the break down of what it says.</p>

<p><strong>Zone</strong></p>

<blockquote>
  <p>…Zones describe unique allocation types.  Zones are</p>
  <ul>
    <li>organized into per-CPU caches which are filled by buckets.</li>
  </ul>
</blockquote>

<p><strong>Bucket</strong></p>

<blockquote>
  <p>…Buckets are</p>
  <ul>
    <li>organized according to memory domains.  Buckets are filled from kegs which</li>
    <li>are also organized according to memory domains.</li>
  </ul>
</blockquote>

<p><strong>Keg</strong></p>

<blockquote>
  <p>… Kegs describe a unique</p>
  <ul>
    <li>allocation type, backend memory provider, and layout.  Kegs are associated</li>
    <li>with one or more zones and zones reference one or more kegs.</li>
  </ul>
</blockquote>

<p><strong>Slab</strong></p>

<blockquote>
  <p>…Kegs provide</p>
  <ul>
    <li>slabs which are virtually contiguous collections of pages.  Each slab is</li>
    <li>broken down int one or more items that will satisfy an individual allocation.</li>
  </ul>
</blockquote>

<p>At the end of its brief summary, there is an ASCII representation of a slab.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/*
 *  This is the representation for normal (Non OFFPAGE slab)
 *
 *  i == item
 *  s == slab pointer
 *
 *  &lt;----------------  Page (UMA_SLAB_SIZE) ------------------&gt;
 *  ___________________________________________________________
 *     | _  _  _  _  _  _  _  _  _  _  _  _  _  _  _   ___________ |
 *     ||i||i||i||i||i||i||i||i||i||i||i||i||i||i||i| |slab header||
 *     ||_||_||_||_||_||_||_||_||_||_||_||_||_||_||_| |___________|| 
 *     |___________________________________________________________|
 *
 *
 *  This is an OFFPAGE slab. These can be larger than UMA_SLAB_SIZE.
 *
 *  ___________________________________________________________
 *     | _  _  _  _  _  _  _  _  _  _  _  _  _  _  _  _  _  _  _   |
 *     ||i||i||i||i||i||i||i||i||i||i||i||i||i||i||i||i||i||i||i|  |
 *     ||_||_||_||_||_||_||_||_||_||_||_||_||_||_||_||_||_||_||_|  |
 *     |___________________________________________________________|
 *       ___________    ^
 *  |slab header|   |
 *  |___________|---*
 *
 */</span>
</code></pre></div></div>

<p>So, we have a slab type which called normal or non OFFPAGE slab that its slab header is located at the end of the allocated page.
Also, there is an OFFPAGE slab, it can be larger than UMA_SLAB_SIZE which is currently defined as a PAGE_SIZE (which is 4096 bytes in my laptop.).
How I know that? using <code class="language-plaintext highlighter-rouge">sysctl hw.pagesize</code> you can findout your own pagesize. Typically, it is 4096 bytes in x86 architectures.
Back to OFFPAGE slab, it uses a separate slab header outside the allocated page.</p>

<p>Continuing on <code class="language-plaintext highlighter-rouge">uma_zone</code> structure, it has a lot of fields inside its struct. Some of them catches my attention:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">uint32_t</span>    <span class="n">uz_size</span><span class="p">;</span>    <span class="cm">/* Size inherited from kegs */</span>
<span class="kt">uint64_t</span>    <span class="n">uz_max_items</span><span class="p">;</span>   <span class="cm">/* Maximum number of items to alloc */</span>
</code></pre></div></div>

<p>We have size of each object and the maximum number of objects in here.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">uma_ctor</span>    <span class="n">uz_ctor</span><span class="p">;</span>    <span class="cm">/* Constructor for each allocation */</span>
<span class="n">uma_dtor</span>    <span class="n">uz_dtor</span><span class="p">;</span>    <span class="cm">/* Destructor */</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">ctor</code> and <code class="language-plaintext highlighter-rouge">dtor</code> is described in <em>UMA(9)</em> manual:</p>

<blockquote>
  <p>The ctor and dtor arguments are callback functions that are called by the
UMA subsystem at the time of the call to uma_zalloc() and uma_zfree()
respectively.  Their purpose is to provide hooks for initializing or
destroying things that need to be done at the time of the allocation or
release of a resource.  A good usage for the ctor and dtor callbacks
might be to initialize a data structure embedded in the item, such as a
queue(3) head.</p>
</blockquote>

<p>In summary, we use them to initialize a data structure in the items at the time of allocation or release of a resource.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">uint16_t</span>    <span class="n">uz_bucket_size</span><span class="p">;</span> <span class="cm">/* Number of items in full bucket */</span>
<span class="kt">uint16_t</span>    <span class="n">uz_bucket_size_max</span><span class="p">;</span> <span class="cm">/* Maximum number of bucket items */</span>
</code></pre></div></div>

<p>These are used for defining the number of items in full bucket of a zone and its max limitation of items in that those buckets.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">const</span> <span class="kt">char</span>  <span class="o">*</span><span class="n">uz_name</span><span class="p">;</span>   <span class="cm">/* Text name of the zone */</span>
</code></pre></div></div>

<p>The name of the zone defined here.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">uma_init</span>    <span class="n">uz_init</span><span class="p">;</span>    <span class="cm">/* Initializer for each item */</span>
<span class="n">uma_fini</span>    <span class="n">uz_fini</span><span class="p">;</span>    <span class="cm">/* Finalizer for each item. */</span>
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">init</code> and <code class="language-plaintext highlighter-rouge">fini</code> are described in <em>UMA(9)</em> too:</p>

<blockquote>
  <p>The zinit and zfini arguments are used to optimize the allocation of
items from the zone.  They are called by the UMA subsystem whenever it
needs to allocate or free items to satisfy requests or memory pressure.
A good use for the zinit and zfini callbacks might be to initialize and
destroy a mutex contained within an item.  This would allow one to avoid
destroying and re-initializing the mutex each time the item is freed and
re-allocated.</p>
</blockquote>

<p>memory pressure is refered to <code class="language-plaintext highlighter-rouge">pageout</code> daemon, which is the only process that ask the UMA to free its items to free memory.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">LIST_ENTRY</span><span class="p">(</span><span class="n">uma_zone</span><span class="p">)</span> <span class="n">uz_link</span><span class="p">;</span>   <span class="cm">/* List of all zones in keg */</span>
<span class="n">uma_keg_t</span>   <span class="n">uz_keg</span><span class="p">;</span>     <span class="cm">/* This zone's keg if !CACHE */</span>
</code></pre></div></div>

<p>Finally, here is a pointer from zone to keg. We probably should move to the keg structure to see what actually are they.
You can find the <code class="language-plaintext highlighter-rouge">uma_keg</code> structure in the file we are currently looking at.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">LIST_HEAD</span><span class="p">(,</span><span class="n">uma_zone</span><span class="p">)</span>    <span class="n">uk_zones</span><span class="p">;</span>   <span class="cm">/* Keg's zones */</span>
</code></pre></div></div>

<p>This field in <code class="language-plaintext highlighter-rouge">uma_keg</code> shows us the keg can have multiple zones connected together using a linked list.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">uint32_t</span>    <span class="n">uk_size</span><span class="p">;</span>    <span class="cm">/* Requested size of each item */</span>
<span class="kt">uint32_t</span>    <span class="n">uk_rsize</span><span class="p">;</span>   <span class="cm">/* Real size of each item */</span>
</code></pre></div></div>

<p>These struct members are the one that zone inherited the size from them. So which one it uses?</p>

<p>You see these two lines under the <code class="language-plaintext highlighter-rouge">zone_ctor</code> function. The one who initializes all fields, lock, etc for a zone:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="n">zone</span><span class="o">-&gt;</span><span class="n">uz_keg</span> <span class="o">=</span> <span class="n">keg</span><span class="p">;</span>
 <span class="n">zone</span><span class="o">-&gt;</span><span class="n">uz_size</span> <span class="o">=</span> <span class="n">keg</span><span class="o">-&gt;</span><span class="n">uk_size</span><span class="p">;</span>
</code></pre></div></div>

<p>So it’s the requested size of each item stored in zone struct, not the real size.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">uma_init</span>    <span class="n">uk_init</span><span class="p">;</span>    <span class="cm">/* Keg's init routine */</span>
<span class="n">uma_fini</span>    <span class="n">uk_fini</span><span class="p">;</span>    <span class="cm">/* Keg's fini routine */</span>
</code></pre></div></div>

<p>As you can see, we have <code class="language-plaintext highlighter-rouge">uma_init</code> and <code class="language-plaintext highlighter-rouge">uma_fini</code> for kegs too.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">uma_alloc</span>   <span class="n">uk_allocf</span><span class="p">;</span>  <span class="cm">/* Allocation function */</span>
<span class="n">uma_free</span>    <span class="n">uk_freef</span><span class="p">;</span>   <span class="cm">/* Free routine */</span>
</code></pre></div></div>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">uint16_t</span>    <span class="n">uk_ipers</span><span class="p">;</span>   <span class="cm">/* Items per slab */</span>
</code></pre></div></div>

<p>As we follow the structure, we can see a clear hierarchy in normal zone. Zones have number of items, and keg have their own number of items per slab.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">const</span> <span class="kt">char</span>  <span class="o">*</span><span class="n">uk_name</span><span class="p">;</span>       <span class="o">/*</span> <span class="n">Name</span> <span class="n">of</span> <span class="n">creating</span> <span class="n">zone</span><span class="p">.</span> <span class="o">*</span>
</code></pre></div></div>

<p>Here is the name of the keg, as defined in comment of the code, it uses the same of zone name. I can confirm it in the <code class="language-plaintext highlighter-rouge">keg_ctor</code> function:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">keg</span><span class="o">-&gt;</span><span class="n">uk_name</span> <span class="o">=</span> <span class="n">zone</span><span class="o">-&gt;</span><span class="n">uz_name</span><span class="p">;</span>
</code></pre></div></div>

<p>And last but not least:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">LIST_ENTRY</span><span class="p">(</span><span class="n">uma_keg</span><span class="p">)</span> <span class="n">uk_link</span><span class="p">;</span>    <span class="cm">/* List of all kegs */</span>
</code></pre></div></div>

<p>All of the kegs linked together.</p>

<p>Now it’s time to move to the <code class="language-plaintext highlighter-rouge">uma_slab</code> structure. The structure is simple and self explaining. Here is the full structure:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/*
 * The slab structure manages a single contiguous allocation from backing
 * store and subdivides it into individually allocatable items.
 */</span>
<span class="k">struct</span> <span class="n">uma_slab</span> <span class="p">{</span>
    <span class="n">LIST_ENTRY</span><span class="p">(</span><span class="n">uma_slab</span><span class="p">)</span>    <span class="n">us_link</span><span class="p">;</span>    <span class="cm">/* slabs in zone */</span>
    <span class="kt">uint16_t</span>    <span class="n">us_freecount</span><span class="p">;</span>       <span class="cm">/* How many are free? */</span>
    <span class="kt">uint8_t</span>     <span class="n">us_flags</span><span class="p">;</span>       <span class="cm">/* Page flags see uma.h */</span>
    <span class="kt">uint8_t</span>     <span class="n">us_domain</span><span class="p">;</span>      <span class="cm">/* Backing NUMA domain. */</span>
    <span class="k">struct</span> <span class="n">noslabbits</span> <span class="n">us_free</span><span class="p">;</span>      <span class="cm">/* Free bitmask, flexible. */</span>
<span class="p">};</span>
</code></pre></div></div>

<p>The only struct member that may need explaining is free bitmask. Bitmask simply represent free and allocated items.</p>

<p>To be continued…</p>]]></content><author><name>Seyed Pouria Mousavizadeh Tehrani</name><email>info@spmzt.net</email></author><category term="FreeBSD" /><category term="UMA" /><category term="VM" /><category term="Zone" /><summary type="html"><![CDATA[I’m trying to learn UMA or general-purpose kernel object allocator through the kernel source code. This approach maybe weird, but the FreeBSD source code is organized and clear. Worth mentioning that it’s documentation inside source code and has its own manual uma(9).]]></summary></entry><entry><title type="html">From VM to Hierarchial Jails</title><link href="http://spmzt.net/2024/11/30/From-VM-to-Hierarchial-Jails/" rel="alternate" type="text/html" title="From VM to Hierarchial Jails" /><published>2024-11-30T17:32:00+03:30</published><updated>2024-11-30T17:32:00+03:30</updated><id>http://spmzt.net/2024/11/30/From-VM-to-Hierarchial-Jails</id><content type="html" xml:base="http://spmzt.net/2024/11/30/From-VM-to-Hierarchial-Jails/"><![CDATA[<h2 id="crux">Crux</h2>

<p>I’m tired of managing different virtual machines when I can use hierarchial jails to achieve my requirement of separation and isolation. After all, using virtual machines while using same FreeBSD OS for different tasks plus having ZFS on every VM is pointless. I’ll stop ranting. Let’s get to work.</p>

<p>I want to migrate each of my virtual machines to a separate jail for each of them and I’ll use hierarchial jails in order to migrate jails on those VMs.</p>

<h3 id="network">Network</h3>

<p>I was using standard switches (A.K.A bridge) on my hypervisor with uplinks of my server. So in order to make things easier, I want to use <code class="language-plaintext highlighter-rouge">JIB</code> to manage each of the jails interfaces under its required uplink. In order to accomplish that, I have to use <code class="language-plaintext highlighter-rouge">VNET</code> to virtualize network stack.</p>

<h4 id="install-jib">Install JIB</h4>

<p>It’s in the base, so:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">install</span> <span class="nt">-o</span> root <span class="nt">-g</span> wheel <span class="nt">-m</span> 0555 /usr/share/examples/jails/jib /usr/local/sbin/jib
</code></pre></div></div>

<h4 id="firewall">Firewall</h4>

<p>I will use the <code class="language-plaintext highlighter-rouge">pf</code> firewall for my jails. Of course we have to deal with <code class="language-plaintext highlighter-rouge">devfs</code> and <code class="language-plaintext highlighter-rouge">bridge</code> for <code class="language-plaintext highlighter-rouge">jib</code> in order to make this happen.</p>

<h5 id="devfs-rules">DevFS Rules</h5>

<p>If you do not want to use ZFS, there is no need for adding new rules. Use can use the <code class="language-plaintext highlighter-rouge">devfsrules_jail_vnet=5</code> which is already configured by default.
However, I want my jails to have access to zfs in order to create datasets. So I will create new devfs rules at <code class="language-plaintext highlighter-rouge">/etc/devfs.rules</code>.</p>

<pre><code class="language-devfs.rules">[jail_vnet_zfs=6]
add include $devfsrules_hide_all
add include $devfsrules_unhide_basic
add include $devfsrules_unhide_login
add include $devfsrules_jail
add include $devfsrules_jail_vnet
add path zfs unhide
</code></pre>

<p>Use this under your jail configuration:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="c"># unhide pf</span>
  mount.devfs<span class="p">;</span>
  devfs_ruleset <span class="o">=</span> 6<span class="p">;</span>
</code></pre></div></div>

<h5 id="bridges">Bridges</h5>

<p>I do not want the <code class="language-plaintext highlighter-rouge">pf</code> to care about any <code class="language-plaintext highlighter-rouge">bridge</code> interfaces in my network. So we have to tell it somehow.
Add these configuration to your <code class="language-plaintext highlighter-rouge">/etc/sysctl.conf</code> and apply it using <code class="language-plaintext highlighter-rouge">sysctl -f /etc/sysctl.conf</code>.</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>net.link.bridge.pfil_bridge<span class="o">=</span>0
net.link.bridge.pfil_onlyip<span class="o">=</span>0
net.link.bridge.pfil_member<span class="o">=</span>0
</code></pre></div></div>

<h3 id="storage-and-zfs">Storage and ZFS</h3>

<p>As the matter of fact, We mostly like the snapshot ability on the hypervisors and that is one of the main reasons that we put EVERYTHING under a separate VM.
Then we realize ZFS under FreeBSD bring us this ability perfectly. As well as, It’s ZFS, you probably can name many other reasons why use the ZFS for each of the jails.</p>

<p>I will create a separate dataset for jails directory of my server, and then for root directory of each jails.</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>zfs create <span class="nt">-o</span> <span class="nv">mountpoint</span><span class="o">=</span>/usr/jails tank/jails
zfs create <span class="nt">-p</span> tank/jails/vm1/usr
</code></pre></div></div>

<h4 id="jailed-zfs-and-vnet">Jailed ZFS and VNET</h4>

<p>Attach the ZFS dataset under your jails and create your vnet interfaces.
This is how i do it:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  vnet<span class="p">;</span>
  vnet.interface <span class="o">=</span> <span class="s2">"e0b_</span><span class="k">${</span><span class="nv">name</span><span class="k">}</span><span class="s2">"</span><span class="p">;</span>

  exec.prestart +<span class="o">=</span> <span class="s2">"jib addm </span><span class="k">${</span><span class="nv">name</span><span class="k">}</span><span class="s2"> </span><span class="nv">$pif</span><span class="s2">"</span><span class="p">;</span>
  exec.created +<span class="o">=</span> <span class="s2">"zfs set jailed=on tank/jails/</span><span class="k">${</span><span class="nv">name</span><span class="k">}</span><span class="s2">/usr || echo ZFS already jailed"</span><span class="p">;</span>
  exec.created +<span class="o">=</span> <span class="s2">"zfs jail </span><span class="k">${</span><span class="nv">name</span><span class="k">}</span><span class="s2"> tank/jails/</span><span class="k">${</span><span class="nv">name</span><span class="k">}</span><span class="s2">/usr"</span><span class="p">;</span>
  exec.poststart +<span class="o">=</span> <span class="s2">"jexec </span><span class="k">${</span><span class="nv">name</span><span class="k">}</span><span class="s2"> zfs mount -R tank/jails/</span><span class="k">${</span><span class="nv">name</span><span class="k">}</span><span class="s2">/usr"</span><span class="p">;</span>
  exec.poststart +<span class="o">=</span> <span class="s2">"jexec </span><span class="k">${</span><span class="nv">name</span><span class="k">}</span><span class="s2"> zfs list -H -o name -r tank/jails/</span><span class="k">${</span><span class="nv">name</span><span class="k">}</span><span class="s2">/usr | xargs -I '{}' jexec </span><span class="k">${</span><span class="nv">name</span><span class="k">}</span><span class="s2"> zfs mount {} || echo ZFS already mounted"</span><span class="p">;</span>
  exec.poststart +<span class="o">=</span> <span class="s2">"service -j </span><span class="k">${</span><span class="nv">name</span><span class="k">}</span><span class="s2"> jail onestart"</span><span class="p">;</span>
  exec.prestop  +<span class="o">=</span> <span class="s2">"zfs unjail </span><span class="k">${</span><span class="nv">name</span><span class="k">}</span><span class="s2"> tank/jails/</span><span class="k">${</span><span class="nv">name</span><span class="k">}</span><span class="s2">/usr || echo zfs dataset is already unjailed"</span><span class="p">;</span>
  exec.poststop +<span class="o">=</span> <span class="s2">"jib destroy </span><span class="k">${</span><span class="nv">name</span><span class="k">}</span><span class="s2">"</span><span class="p">;</span>
</code></pre></div></div>

<h3 id="jail-configurations-of-the-host">Jail configurations of the host</h3>

<p>I do not like the jail managers everytime I do not have the CI/CD pipelines. In like manner, I found it easier to use the <code class="language-plaintext highlighter-rouge">jail.conf.d</code> itself in the base system.
Remamber to replace <code class="language-plaintext highlighter-rouge">$pif</code> variable with your own uplink interface of the host.
Simply create the base jail configuration at <code class="language-plaintext highlighter-rouge">/etc/jail.conf</code>:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>path <span class="o">=</span> <span class="s2">"/usr/jails/</span><span class="k">${</span><span class="nv">name</span><span class="k">}</span><span class="s2">"</span><span class="p">;</span>
exec.start <span class="o">=</span> <span class="s2">"/bin/sh /etc/rc"</span><span class="p">;</span>
exec.stop  <span class="o">=</span> <span class="s2">"/bin/sh /etc/rc.shutdown"</span><span class="p">;</span>
exec.clean<span class="p">;</span>

<span class="c"># FQDN</span>
host.hostname <span class="o">=</span> <span class="s2">"</span><span class="k">${</span><span class="nv">name</span><span class="k">}</span><span class="s2">.spmzt.net"</span><span class="p">;</span>
host.domainname <span class="o">=</span> <span class="s2">"spmzt.net"</span><span class="p">;</span>

<span class="c"># Global Variables</span>
<span class="nv">$pif</span><span class="o">=</span><span class="s2">"vmx0"</span><span class="p">;</span>
</code></pre></div></div>

<p>Then create the configuration of your jails in the separate files under <code class="language-plaintext highlighter-rouge">/etc/jail.conf.d/</code>:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.include <span class="s2">"/etc/jail.conf"</span><span class="p">;</span>
mayuri <span class="o">{</span>
  persist<span class="p">;</span>

  <span class="c"># unhide pf</span>
  mount.devfs<span class="p">;</span>
  devfs_ruleset <span class="o">=</span> 5<span class="p">;</span>

  <span class="c"># parent permissions</span>
  children.max <span class="o">=</span> 12<span class="p">;</span>
  allow.mount.devfs<span class="p">;</span>

  <span class="c"># required by zfs jailed</span>
  allow.mount<span class="p">;</span>
  allow.mount.zfs<span class="p">;</span>
  <span class="nv">enforce_statfs</span><span class="o">=</span>0<span class="p">;</span>

  <span class="c"># parent permission (required by netflow grandchild)</span>
  allow.sysvipc<span class="p">;</span>

  <span class="c"># parent permission (required by ocserv1 grandchild)</span>
  allow.mount.procfs<span class="p">;</span>

  <span class="c"># decrease securelevel to be able to mount</span>
  <span class="nv">securelevel</span><span class="o">=</span>0<span class="p">;</span>

  <span class="c"># Network Configurations</span>
  vnet<span class="p">;</span>
  vnet.interface <span class="o">=</span> <span class="s2">"e0b_</span><span class="k">${</span><span class="nv">name</span><span class="k">}</span><span class="s2">"</span><span class="p">;</span>

  exec.prestart +<span class="o">=</span> <span class="s2">"jib addm </span><span class="k">${</span><span class="nv">name</span><span class="k">}</span><span class="s2"> </span><span class="nv">$pif</span><span class="s2">"</span><span class="p">;</span>
  exec.poststart +<span class="o">=</span> <span class="s2">"zfs set jailed=on tank/jails/</span><span class="k">${</span><span class="nv">name</span><span class="k">}</span><span class="s2">/usr || echo ZFS already jailed"</span><span class="p">;</span>
  exec.poststart +<span class="o">=</span> <span class="s2">"zfs jail </span><span class="k">${</span><span class="nv">name</span><span class="k">}</span><span class="s2"> tank/jails/</span><span class="k">${</span><span class="nv">name</span><span class="k">}</span><span class="s2">/usr"</span><span class="p">;</span>
  exec.poststart +<span class="o">=</span> <span class="s2">"jexec </span><span class="k">${</span><span class="nv">name</span><span class="k">}</span><span class="s2"> zfs mount -R tank/jails/</span><span class="k">${</span><span class="nv">name</span><span class="k">}</span><span class="s2">/usr"</span><span class="p">;</span>
  exec.poststart +<span class="o">=</span> <span class="s2">"jexec </span><span class="k">${</span><span class="nv">name</span><span class="k">}</span><span class="s2"> zfs list -H -o name -r tank/jails/</span><span class="k">${</span><span class="nv">name</span><span class="k">}</span><span class="s2">/usr | xargs -I '{}' jexec </span><span class="k">${</span><span class="nv">name</span><span class="k">}</span><span class="s2"> zfs mount {} || echo ZFS already mounted"</span><span class="p">;</span>
  exec.poststart +<span class="o">=</span> <span class="s2">"service -j </span><span class="k">${</span><span class="nv">name</span><span class="k">}</span><span class="s2"> jail onestart"</span><span class="p">;</span>
  exec.prestop  +<span class="o">=</span> <span class="s2">"zfs unjail </span><span class="k">${</span><span class="nv">name</span><span class="k">}</span><span class="s2"> tank/jails/</span><span class="k">${</span><span class="nv">name</span><span class="k">}</span><span class="s2">/usr || echo zfs dataset is already unjailed"</span><span class="p">;</span>
  exec.poststop +<span class="o">=</span> <span class="s2">"jib destroy </span><span class="k">${</span><span class="nv">name</span><span class="k">}</span><span class="s2">"</span><span class="p">;</span>
</code></pre></div></div>

<h4 id="note">Note</h4>

<p>You need the command below in your jail configuration to start child jails.</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  exec.poststart +<span class="o">=</span> <span class="s2">"service -j </span><span class="k">${</span><span class="nv">name</span><span class="k">}</span><span class="s2"> jail onestart"</span><span class="p">;</span>
</code></pre></div></div>

<h3 id="kernel-modules">Kernel Modules</h3>

<p>I need some kernel modules inside my virtual machine when I want to use them as jails inside my host.
I add to add those kernel modules inside the host itself.</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sysrc <span class="nv">kld_list</span><span class="o">=</span>+<span class="s2">"netgraph ng_ether ng_tee ng_socket ng_netflow ng_ksocket ng_eiface ng_iface ng_bridge ipsec"</span>
</code></pre></div></div>]]></content><author><name>Seyed Pouria Mousavizadeh Tehrani</name><email>info@spmzt.net</email></author><category term="FreeBSD" /><category term="Virtualization" /><category term="ZFS" /><category term="Jail" /><category term="VNET" /><summary type="html"><![CDATA[Crux]]></summary></entry><entry><title type="html">FreeBSD IPFW Best Practices (IPv6 and IPv4)</title><link href="http://spmzt.net/2024/11/16/FreeBSD-IPFW-Best-Practices/" rel="alternate" type="text/html" title="FreeBSD IPFW Best Practices (IPv6 and IPv4)" /><published>2024-11-16T11:43:00+03:30</published><updated>2024-11-16T11:43:00+03:30</updated><id>http://spmzt.net/2024/11/16/FreeBSD-IPFW-Best-Practices</id><content type="html" xml:base="http://spmzt.net/2024/11/16/FreeBSD-IPFW-Best-Practices/"><![CDATA[<p>Configuration of IPFW can be quite complex. However once you understand its syntax it will be fairly simple.
But, This article is not a manual explaining things. It’s for those who already can understand what are they doing with IPFW.</p>

<h2 id="best-practise">Best Practise</h2>

<p>To enable IPFW with logging:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># IPFW</span>
<span class="nv">firewall_enable</span><span class="o">=</span><span class="s2">"YES"</span>
<span class="nv">firewall_script</span><span class="o">=</span><span class="s2">"/etc/ipfw.rules"</span>
<span class="nv">firewall_logging</span><span class="o">=</span><span class="s2">"YES"</span>
<span class="nv">firewall_logif</span><span class="o">=</span><span class="s2">"YES"</span>
</code></pre></div></div>

<p>Configure IPFW by adding rules inside <code class="language-plaintext highlighter-rouge">/etc/ipfw.rules</code> as shell script:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/sh</span>
<span class="c"># Flush out the list before we begin.</span>
ipfw <span class="nt">-q</span> <span class="nt">-f</span> flush

<span class="c"># Delete tables and NATs</span>
ipfw <span class="nt">-q</span> table all destroy
ipfw <span class="nt">-q</span> nat64lsn all destroy
ipfw <span class="nt">-q</span> nat64stl all destroy

<span class="c"># Replace config</span>
ipfw <span class="nb">set </span>disable 1

<span class="c"># Set rules command prefix (for test add -n)</span>
<span class="nv">cmd</span><span class="o">=</span><span class="s2">"/sbin/ipfw -q add"</span>
<span class="c"># interface name of NIC attached to Internet</span>
<span class="nv">pif</span><span class="o">=</span><span class="s2">"vmx0"</span>
<span class="nv">epairs</span><span class="o">=</span><span class="s2">"epair*"</span>

<span class="c"># Non-routable IPv4 addresses</span>
<span class="c">## Enable this for RFC1918</span>
<span class="c">#martians="{ 192.168.0.0/16 or 172.16.0.0/12 or 10.0.0.0/8 \</span>
<span class="c">## Note: 204.152.64.0/23 is for Sun cluster interconnect</span>
<span class="nv">martians</span><span class="o">=</span><span class="s2">"{ 127.0.0.0/8 or 169.254.0.0/16 or 192.0.2.0/24 or 0.0.0.0/8 or 240.0.0.0/4 </span><span class="se">\</span><span class="s2">
		or 204.152.64.0/23 or 224.0.0.0/3 }"</span>

<span class="c"># IPv6</span>
<span class="c">## Allow IPv6 DAD</span>
<span class="nv">$cmd</span> 00031 <span class="nb">set </span>1 pass icmp6 from :: to ff02::/16

<span class="c">## Allow IPv6 RS, RA, NS, NA, &amp; redirect</span>
<span class="nv">$cmd</span> 00032 <span class="nb">set </span>1 pass icmp6 from fe80::/10 to fe80::/10
<span class="nv">$cmd</span> 00033 <span class="nb">set </span>1 pass icmp6 from fe80::/10 to ff02::/16

<span class="c"># Allow ICMPv6 destination unreachable, NS, NA, &amp; too-big</span>
<span class="nv">$cmd</span> 00034 <span class="nb">set </span>1 pass icmp6 from any to any icmp6types 1,2,3,4
<span class="nv">$cmd</span> 00035 <span class="nb">set </span>1 pass icmp6 from any to any icmp6types 135,136

<span class="c"># NAT64 Rules (50-69)</span>

<span class="c"># No restrictions on Loopback/me Interfaces</span>
<span class="nv">$cmd</span> 00070 <span class="nb">set </span>1 pass log all from any to any via lo0 record-state
<span class="nv">$cmd</span> 00071 <span class="nb">set </span>1 pass log all from <span class="o">{</span> me or me6 <span class="o">}</span> to <span class="o">{</span> me or me6 <span class="o">}</span> record-state

<span class="c"># Scrub</span>
<span class="nv">$cmd</span> 00099 <span class="nb">set </span>1 reass all from any to any <span class="k">in</span>

<span class="c"># NAT Rules (100-149)</span>

<span class="c"># Passes the packet through if it matches an existing entry in the dynamic rules table</span>
<span class="nv">$cmd</span> 00150 <span class="nb">set </span>1 check-state

<span class="c"># Pass from me</span>
<span class="nv">$cmd</span> 00161 <span class="nb">set </span>1 pass tcp from <span class="o">{</span> me or me6 <span class="o">}</span> to any established keep-state
<span class="nv">$cmd</span> 00163 <span class="nb">set </span>1 pass tcp from <span class="o">{</span> me or me6 <span class="o">}</span> to any setup keep-state
<span class="nv">$cmd</span> 00165 <span class="nb">set </span>1 pass udp from <span class="o">{</span> me or me6 <span class="o">}</span> to any keep-state
<span class="nv">$cmd</span> 00167 <span class="nb">set </span>1 pass icmp from me to any keep-state
<span class="nv">$cmd</span> 00168 <span class="nb">set </span>1 pass icmp6 from me6 to any keep-state

<span class="c"># Deny RH0 (RFC5095)</span>
<span class="nv">$cmd</span> 00201 <span class="nb">set </span>1 drop log ipv6 from any to any ext6hdr rthdr0 

<span class="c"># Deny fragmented NDP packets (RFC6980)</span>
<span class="nv">$cmd</span> 00211 <span class="nb">set </span>1 drop log icmp6 from any to any ext6hdr frag icmp6types 130,131,132,133,134,135,136,143

<span class="c"># uRPF (RFC)</span>
<span class="nv">$cmd</span> 00221 <span class="nb">set </span>1 drop log ip from any to any not antispoof <span class="k">in</span>

<span class="c"># Deny ICMPv6 Redirect and Renumbering</span>
<span class="nv">$cmd</span> 00231 <span class="nb">set </span>1 drop log icmp6 from any to any icmp6types 137,138

<span class="c"># Deny all inbound traffic from non-routable reserved address spaces</span>
<span class="c">## IPv4</span>
<span class="nv">$cmd</span> 00301 <span class="nb">set </span>1 drop log ipv4 from <span class="nv">$martians</span> to any <span class="k">in </span>recv <span class="nv">$pif</span>
<span class="nv">$cmd</span> 00302 <span class="nb">set </span>1 drop log ipv4 from any to <span class="nv">$martians</span> out xmit <span class="nv">$pif</span>
<span class="c">## IPv6</span>
<span class="nv">$cmd</span> 00321 <span class="nb">set </span>1 drop log all from ::1/128 to any via <span class="nv">$pif</span>
<span class="c">### Site-local (RFC3879)</span>
<span class="nv">$cmd</span> 00322 <span class="nb">set </span>1 drop log all from fec0::/10 to any
<span class="c">### IPv4-Compatible IPv6 (RFC4291)</span>
<span class="nv">$cmd</span> 00323 <span class="nb">set </span>1 drop log all from ::/96 to any
<span class="c">### Deny Teredo IPv6 (RFC4380)</span>
<span class="nv">$cmd</span> 00324 <span class="nb">set </span>1 drop log all from 2001::/32 to any
<span class="nv">$cmd</span> 00325 <span class="nb">set </span>1 drop log udp from any to any 3544
<span class="c">### Deny IPv6 Documentation (RFC3849)</span>
<span class="nv">$cmd</span> 00326 <span class="nb">set </span>1 drop log all from 2001:db8::/32 to any
<span class="c">### Deny Discard-Only IPv6 Address (RFC6666)</span>
<span class="nv">$cmd</span> 00327 <span class="nb">set </span>1 drop log all from 100::/64 to any
<span class="c">### Deny ORCHID (RFC5156)</span>
<span class="nv">$cmd</span> 00328 <span class="nb">set </span>1 drop log all from 2001:10::/28 to any
<span class="c">### Deny Benchmarking IPv6 (RFC5180)</span>
<span class="nv">$cmd</span> 00329 <span class="nb">set </span>1 drop log all from 2001:2::/48 to any
<span class="c">### Deny 6Bone (RFC3701)</span>
<span class="nv">$cmd</span> 00330 <span class="nb">set </span>1 drop log all from <span class="o">{</span> 3ffe::/16 or 5f00::/8 <span class="o">}</span> to any
<span class="c">### Deny AYIYA (draft-massar-v6ops-ayiya-02)</span>
<span class="nv">$cmd</span> 00331 <span class="nb">set </span>1 drop log all from any to any 5072
<span class="c">### Deny TSP (RFC5572)</span>
<span class="nv">$cmd</span> 00332 <span class="nb">set </span>1 drop log all from any to any 3653

<span class="c">### XMAS tree</span>
<span class="nv">$cmd</span> 00341 <span class="nb">set </span>1 drop log tcp from any to any <span class="k">in </span>tcpflags fin,psh,urg recv <span class="nv">$pif</span>
<span class="c">### NULL scan (no flag set at all)</span>
<span class="nv">$cmd</span> 00342 <span class="nb">set </span>1 drop log tcp from any to any <span class="k">in </span>tcpflags <span class="o">!</span>fin,!syn,!rst,!psh,!ack,!urg recv <span class="nv">$pif</span>
<span class="c">### SYN flood (SYN,FIN)</span>
<span class="nv">$cmd</span> 00343 <span class="nb">set </span>1 drop log tcp from any to any <span class="k">in </span>tcpflags syn,fin recv <span class="nv">$pif</span>
<span class="c">### Stealth FIN scan (FIN,RST)</span>
<span class="nv">$cmd</span> 00344 <span class="nb">set </span>1 drop log tcp from any to any <span class="k">in </span>tcpflags fin,rst recv <span class="nv">$pif</span>
<span class="c">### forced packet routing</span>
<span class="nv">$cmd</span> 00345 <span class="nb">set </span>1 drop log ip from any to any <span class="k">in </span>ipoptions ssrr,lsrr,rr,ts recv <span class="nv">$pif</span>
<span class="c">### Ack scan</span>
<span class="nv">$cmd</span> 00346 <span class="nb">set </span>1 drop log tcp from any to any <span class="k">in </span>tcpflags ack,rst recv <span class="nv">$pif</span>

<span class="c"># Deny ident</span>
<span class="nv">$cmd</span> 00351 <span class="nb">set </span>1 drop log tcp from any to any 113 <span class="k">in </span>via <span class="nv">$pif</span>

<span class="c"># Deny all Netbios services.</span>
<span class="nv">$cmd</span> 00361 <span class="nb">set </span>1 drop log tcp from any to any 137 <span class="k">in </span>via <span class="nv">$pif</span>
<span class="nv">$cmd</span> 00362 <span class="nb">set </span>1 drop log tcp from any to any 138 <span class="k">in </span>via <span class="nv">$pif</span>
<span class="nv">$cmd</span> 00363 <span class="nb">set </span>1 drop log tcp from any to any 139 <span class="k">in </span>via <span class="nv">$pif</span>
<span class="nv">$cmd</span> 00364 <span class="nb">set </span>1 drop log tcp from any to any 81 <span class="k">in </span>via <span class="nv">$pif</span>

<span class="c"># Deny fragments</span>
<span class="nv">$cmd</span> 00370 <span class="nb">set </span>1 drop log all from any to not me6 frag <span class="k">in </span>via <span class="nv">$pif</span>

<span class="c"># Pass ICMP</span>
<span class="c"># pass path-mtu in both directions</span>
<span class="nv">$cmd</span> 00381 <span class="nb">set </span>1 pass icmp from any to any icmptypes 3

<span class="c"># pass source quench in and out</span>
<span class="nv">$cmd</span> 00383 <span class="nb">set </span>1 pass icmp from any to any icmptypes 4

<span class="c"># pass outbound traceroutes</span>
<span class="nv">$cmd</span> 00385 <span class="nb">set </span>1 pass icmp from any to any icmptypes 11 <span class="k">in</span>

<span class="c"># Allow DHCP</span>
<span class="nv">$cmd</span> 00391 <span class="nb">set </span>1 pass udp from any dhcpv6<span class="se">\\</span><span class="nt">-server</span> to me6 dhcpv6<span class="se">\\</span><span class="nt">-client</span> <span class="k">in </span>via <span class="nv">$pif</span> keep-state
<span class="nv">$cmd</span> 00393 <span class="nb">set </span>1 pass udp from any 67 to me 68 <span class="k">in </span>recv <span class="nv">$pif</span> keep-state

<span class="c"># Local Rules (From 400 Rule)</span>
<span class="c">## Note: For ssh protection use blacklistd(8)</span>

<span class="c"># Pass ICMPv6 Ping</span>
<span class="nv">$cmd</span> 00401 <span class="nb">set </span>1 pass icmp6 from any to any icmp6types 128,129 keep-state

<span class="c"># Pass outbound pings and incoming ping responses</span>
<span class="c">#$cmd 00403 set 1 pass icmp from any to any icmptypes 8 out</span>
<span class="c">#$cmd 00404 set 1 pass icmp from any to any icmptypes 0 in</span>

<span class="c"># SSH</span>
<span class="nv">$cmd</span> 00405 <span class="nb">set </span>1 pass tcp from any to <span class="o">{</span> me or me6 <span class="o">}</span> ssh <span class="k">in </span>recv <span class="nv">$pif</span>

<span class="c"># Pass Outgoing Traffic</span>
<span class="nv">$cmd</span> 09901 <span class="nb">set </span>1 pass all from any to any out keep-state

<span class="c"># Deny ACK packets that did not match the dynamic rule table</span>
<span class="nv">$cmd</span> 09903 <span class="nb">set </span>1 drop log tcp from any to any established <span class="k">in </span>via <span class="nv">$pif</span>

<span class="c"># Everything else is denied</span>
<span class="nv">$cmd</span> 09999 <span class="nb">set </span>1 drop log all from any to any
<span class="c">#$cmd 09999 set 1 pass log all from any to any in</span>

<span class="c"># NAT Outbound (10000)</span>

<span class="c"># Out (Maybe)</span>
<span class="nv">$cmd</span> 10001 <span class="nb">set </span>1 pass log all from any to any out keep-state

<span class="c"># Drop Outgoing Traffic after pass ipv4 NAT</span>
<span class="nv">$cmd</span> 19999 <span class="nb">set </span>1 drop log all from any to any out

<span class="c"># Replace config</span>
ipfw <span class="nb">set </span>swap 0 1
ipfw delete <span class="nb">set </span>1
</code></pre></div></div>

<p>Don’t forget to add execute permission:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">chmod</span> +x /etc/ipfw.rules
</code></pre></div></div>

<h3 id="logging">Logging</h3>

<p>To limit the number of times a rule is logged per connection attempt, specify the number using this line in <code class="language-plaintext highlighter-rouge">/etc/sysctl.conf</code>:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>net.inet.ip.fw.verbose_limit<span class="o">=</span>5000
</code></pre></div></div>

<p>And make it persistent:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">echo</span> <span class="s2">"net.inet.ip.fw.verbose_limit=5000"</span> <span class="o">&gt;&gt;</span> /etc/sysctl.conf
</code></pre></div></div>

<h3 id="keep-your-sessions-during-flush">Keep your sessions during flush</h3>

<p>To keep sessions during flush:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">echo </span>net.inet.ip.fw.dyn_keep_states<span class="o">=</span>1 <span class="o">&gt;&gt;</span> /etc/sysctl.conf
</code></pre></div></div>

<h3 id="increase-state-timeouts">Increase state timeouts</h3>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">echo </span>net.inet.ip.fw.dyn_short_lifetime<span class="o">=</span>30 <span class="o">&gt;&gt;</span> /etc/sysctl.conf
<span class="nb">echo </span>net.inet.ip.fw.dyn_fin_lifetime<span class="o">=</span>3 <span class="o">&gt;&gt;</span> /etc/sysctl.conf
<span class="nb">echo </span>net.inet.ip.fw.dyn_rst_lifetime<span class="o">=</span>3 <span class="o">&gt;&gt;</span> /etc/sysctl.conf
<span class="nb">echo </span>net.inet.ip.fw.dyn_syn_lifetime<span class="o">=</span>30 <span class="o">&gt;&gt;</span> /etc/sysctl.conf
</code></pre></div></div>

<h3 id="default-to-accept-for-vnets">Default to accept for VNETs</h3>

<p>To make your life easier by not forcing every jails that using VNET for their network to have a configured firewall.</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">echo</span> <span class="s1">'net.inet.ip.fw.default_to_accept=1'</span> <span class="o">&gt;&gt;</span> /boot/loader.conf.local
</code></pre></div></div>

<h2 id="in-kernel-nat">In-Kernel NAT</h2>

<p>Do not forget to disable TSO.</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">echo </span>net.inet.tcp.tso<span class="o">=</span>0 <span class="o">&gt;&gt;</span> /etc/sysctl.conf 
</code></pre></div></div>

<h3 id="snat">SNAT</h3>

<p>Configure the NAT instance:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kldstat <span class="nt">-q</span> <span class="nt">-m</span> ipfw_nat <span class="o">||</span> kldload ipfw_nat
ipfw nat 1 config <span class="k">if</span> <span class="nv">$pif</span> same_ports unreg_only reset
</code></pre></div></div>

<p>The inbound NAT rule is inserted <em>after</em> the two rules which allow all traffic on the trusted and loopback interfaces and after the reassemble rule but <em>before</em> the <code class="language-plaintext highlighter-rouge">check-state</code> rule.</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$cmd</span> 00100 <span class="nb">set </span>1 nat 1 ipv4 from any to any <span class="k">in </span>recv <span class="nv">$pif</span>
</code></pre></div></div>

<p>This one for outbound:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$cmd</span> 10000 <span class="nb">set </span>1 nat 1 ipv4 from any to any out xmit <span class="nv">$pif</span>
</code></pre></div></div>

<h3 id="skipto">Skipto</h3>

<p>Add an <code class="language-plaintext highlighter-rouge">skipto 10000</code> before any <code class="language-plaintext highlighter-rouge">pass</code> outbound rule after inbount NAT rule.</p>

<p>For our base rules:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Pass from me</span>
<span class="nv">$cmd</span> 00160 <span class="nb">set </span>1 skipto 10000 ipv4 from me to any proto tcp out xmit <span class="nv">$pif</span>
<span class="nv">$cmd</span> 00161 <span class="nb">set </span>1 pass tcp from <span class="o">{</span> me or me6 <span class="o">}</span> to any established keep-state
<span class="nv">$cmd</span> 00162 <span class="nb">set </span>1 skipto 10000 ipv4 from me to any proto tcp out xmit <span class="nv">$pif</span>
<span class="nv">$cmd</span> 00163 <span class="nb">set </span>1 pass tcp from <span class="o">{</span> me or me6 <span class="o">}</span> to any setup keep-state
<span class="nv">$cmd</span> 00164 <span class="nb">set </span>1 skipto 10000 ipv4 from me to any proto udp out xmit <span class="nv">$pif</span>
<span class="nv">$cmd</span> 00165 <span class="nb">set </span>1 pass udp from <span class="o">{</span> me or me6 <span class="o">}</span> to any keep-state
<span class="nv">$cmd</span> 00166 <span class="nb">set </span>1 skipto 10000 ipv4 from me to any proto icmp out xmit <span class="nv">$pif</span>
<span class="nv">$cmd</span> 00167 <span class="nb">set </span>1 pass ipv4 from me to any proto icmp keep-state
<span class="nv">$cmd</span> 00168 <span class="nb">set </span>1 pass icmp6 from me6 to any keep-state

<span class="c"># Pass ICMP</span>
<span class="c"># pass path-mtu in both directions</span>
<span class="nv">$cmd</span> 00380 <span class="nb">set </span>1 skipto 10000  ipv4 from any to any proto icmp icmptypes 3 out xmit <span class="nv">$pif</span>
<span class="nv">$cmd</span> 00381 <span class="nb">set </span>1 pass icmp from any to any icmptypes 3

<span class="c"># pass source quench in and out</span>
<span class="nv">$cmd</span> 00382 <span class="nb">set </span>1 skipto 10000  ipv4 from any to any proto icmp icmptypes 4 out xmit <span class="nv">$pif</span>
<span class="nv">$cmd</span> 00383 <span class="nb">set </span>1 pass icmp from any to any icmptypes 4

<span class="c"># pass outbound traceroutes</span>
<span class="nv">$cmd</span> 00384 <span class="nb">set </span>1 skipto 10000 ipv4 from any to any proto icmp icmptypes 11 <span class="k">in</span>
<span class="nv">$cmd</span> 00385 <span class="nb">set </span>1 pass icmp from any to any icmptypes 11 <span class="k">in</span>

<span class="c"># Pass ICMPv6 Ping</span>
<span class="nv">$cmd</span> 00401 <span class="nb">set </span>1 pass icmp6 from any to any icmp6types 128,129 keep-state

<span class="c"># Pass outbound pings and incoming ping responses</span>
<span class="c">#$cmd 00402 set 1 skipto 10000 ipv4 from any to any proto icmp icmptypes 8 out xmit $pif</span>
<span class="c">#$cmd 00403 set 1 pass icmp from any to any icmptypes 8 out</span>
<span class="c">#$cmd 00404 set 1 pass icmp from any to any icmptypes 0 in</span>

<span class="c"># Pass Outgoing Traffic</span>
<span class="nv">$cmd</span> 09900 <span class="nb">set </span>1 skipto 10000 ipv4 from any to any out xmit <span class="nv">$pif</span>
<span class="nv">$cmd</span> 09901 <span class="nb">set </span>1 pass all from any to any out keep-state
</code></pre></div></div>

<h3 id="dnat">DNAT</h3>

<p>Configure the NAT instance:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ipfw nat 123 config redirect_addr 10.0.0.1 10.0.0.66
				  redirect_port	tcp 192.168.0.1:80 500
				  redirect_proto udp 192.168.1.43 192.168.1.1
				  redirect_addr	192.168.0.10,192.168.0.11
					     10.0.0.100	 <span class="c"># LSNAT</span>
				  redirect_port	tcp 192.168.0.1:80,192.168.0.10:22
					     500	 <span class="c"># LSNAT</span>
</code></pre></div></div>

<p>or it could be split in:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ipfw nat 1 config redirect_addr 10.0.0.1 10.0.0.66
ipfw nat 2 config redirect_port tcp 192.168.0.1:80 500
ipfw nat 3 config redirect_proto udp 192.168.1.43 192.168.1.1
ipfw nat 4 config redirect_addr 192.168.0.10,192.168.0.11,192.168.0.12 10.0.0.100
ipfw nat 5 config redirect_port tcp 192.168.0.1:80,192.168.0.10:22,192.168.0.20:25 500
</code></pre></div></div>
<h2 id="in-kernel-nat64">In-Kernel NAT64</h2>

<h3 id="separate-inout-traffic">Separate In/Out Traffic</h3>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">echo</span> <span class="s1">'net.inet.ip.fw.nat64_direct_output=1'</span> <span class="o">&gt;&gt;</span> /etc/sysctl.conf
</code></pre></div></div>

<h3 id="stateless">Stateless</h3>

<h4 id="create-lookup-tables">Create lookup tables</h4>

<ol>
  <li>Create lookup tables:</li>
</ol>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ipfw <span class="nt">-q</span> table T46 create <span class="nb">type </span>addr valtype ipv6
ipfw <span class="nt">-q</span> table T64 create <span class="nb">type </span>addr valtype ipv4
</code></pre></div></div>

<ol>
  <li>Fill the tables</li>
</ol>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ipfw <span class="nt">-q</span> table T46 add 2.2.1.1 2a01:e140::53
ipfw <span class="nt">-q</span> table T64 add 2a01:e140::53 2.2.1.1
</code></pre></div></div>

<ol>
  <li>Create NAT64 instance:</li>
</ol>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ipfw <span class="nt">-q</span> nat64stl NAT create table4 T46 table6 T64
</code></pre></div></div>

<ol>
  <li>Add rules that matches the traffic:</li>
</ol>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$cmd</span> 00100 <span class="nb">set </span>1 nat64stl NAT ip from any to table<span class="o">(</span>T46<span class="o">)</span>
<span class="nv">$cmd</span> 00101 <span class="nb">set </span>1 nat64stl NAT ip from table<span class="o">(</span>T64<span class="o">)</span> to 64:ff9b::/96
</code></pre></div></div>

<h4 id="stateful">Stateful</h4>

<ol>
  <li>Create NAT64 instance:</li>
</ol>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ipfw <span class="nt">-q</span> <span class="nb">set </span>1 nat64lsn NAT64 create prefix4 A.B.C.D/32
</code></pre></div></div>

<ol>
  <li>Add rules that matches the traffic:</li>
</ol>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$cmd</span> 00110 <span class="nb">set </span>1 nat64lsn NAT64 ipv4 from any to A.B.C.D/32 <span class="k">in</span>
<span class="nv">$cmd</span> 00111 <span class="nb">set </span>1 nat64lsn NAT64 ipv6 from any to 64:ff9b::/96 <span class="k">in</span>
</code></pre></div></div>

<ol>
  <li>Don’t forget to add their firewall rules</li>
</ol>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$cmd</span> <span class="nb">set </span>1 pass ip from any to any
</code></pre></div></div>

<p>For example</p>
<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kldstat <span class="nt">-q</span> <span class="nt">-m</span> ipfw_nat64 <span class="o">||</span> kldload ipfw_nat64
<span class="nv">myip4</span><span class="o">=</span><span class="s2">"1.1.1.1/32"</span>

<span class="nv">$cmd</span> <span class="nt">-f</span> flush
ipfw <span class="nt">-q</span> nat64lsn all destroy

<span class="c"># NAT64 Rules</span>
<span class="nv">$cmd</span> 00050 <span class="nb">set </span>1 nat64lsn NAT64 log ipv4 from any to <span class="nv">$myip4</span> <span class="k">in </span>recv <span class="nv">$pif</span> record-state
<span class="nv">$cmd</span> 00051 <span class="nb">set </span>1 nat64lsn NAT64 log ipv6 from 2a01:e140:dead::/44 to 2a01:e140:cafe:ff::/96 <span class="k">in </span>record-state
<span class="nv">$cmd</span> 00060 <span class="nb">set </span>1 pass ipv4 from 172.30.10.2 to any <span class="k">in </span>recv lo0 record-state
<span class="nv">$cmd</span> 00061 <span class="nb">set </span>1 pass ipv4 from 172.30.10.2 to any out xmit <span class="nv">$pif</span> record-state
<span class="nv">$cmd</span> 00062 <span class="nb">set </span>1 pass ipv6 from 2a01:e140:cafe:ff::/96 to 2a01:e140:dead::/44 <span class="k">in </span>recv <span class="nv">$pif</span> record-state
<span class="nv">$cmd</span> 00063 <span class="nb">set </span>1 pass ipv6 from 2a01:e140:cafe:ff::/96 to 2a01:e140:dead::/44 out xmit <span class="nv">$pif</span> record-state
<span class="nv">$cmd</span> 00064 <span class="nb">set </span>1 pass ipv6 from 2a01:e140:cafe:ff::/96 to 2a01:e140:dead::/44 <span class="k">in </span>recv lo0 record-state
</code></pre></div></div>

<h4 id="note">Note</h4>
<ul>
  <li>Both ipv4 and ipv6 routing should be enabled.</li>
</ul>

<h2 id="bidirectional-ipfw">Bidirectional IPFW</h2>

<p>By using sysctl variable below, you can separately manage/filter your inbound and outbound traffic:</p>
<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sysctl net.inet.ip.fw.one_pass<span class="o">=</span>0
</code></pre></div></div>

<p>Here is my recommended configuration:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/sh</span>
kldstat <span class="nt">-q</span> <span class="nt">-m</span> ipfw_nat <span class="o">||</span> kldload ipfw_nat
kldstat <span class="nt">-q</span> <span class="nt">-m</span> ipfw_nat64 <span class="o">||</span> kldload ipfw_nat64

<span class="c">### Documentations</span>
<span class="c">## 5           Outgoing Jump</span>
<span class="c">## 9-99        Before incoming NAT</span>
<span class="c">## 100-199     Incoming NAT64</span>
<span class="c">## 200-299     Incoming NAT</span>
<span class="c">## 300-399     Check-state After incoming NAT</span>
<span class="c">## 400-499     After incoming NAT</span>
<span class="c">## 500-599     Before outgoing NAT</span>
<span class="c">## 600-699     Outgoing NAT</span>
<span class="c">## 700-799     Check-state After outgoing NAT</span>
<span class="c">## 800-899     After NAT outgoing</span>
<span class="c">### Skipto </span>
<span class="c">## 1000-1999   IPv6 to me before incoming NAT</span>
<span class="c">## 2000-2999   IPv4 to me before incoming NAT</span>
<span class="c">## 3000-3999   IPv6 to me after incoming NAT</span>
<span class="c">## 4000-4999   IPv4 to me after incoming NAT</span>
<span class="c">## 5000-5999   IPv6 from me before outgoing NAT</span>
<span class="c">## 6000-6999   IPv4 from me before outgoing NAT</span>
<span class="c">## 7000-7999   IPv6 from me after outgoing NAT</span>
<span class="c">## 8000-8999   IPv4 from me after outgoing NAT</span>
<span class="c">## 9000-9099   IPv6 Link-Locals Only</span>
<span class="c">## 9100-9199   Silent Drop (Incoming Drop Only)</span>
<span class="c">## 9200-9999   Dangerous Packets (Incoming Drop Only)</span>
<span class="c">## 10000-10999 IPv6 incoming forward</span>
<span class="c">## 11000-11999 IPv4 incoming forward</span>
<span class="c">## 12000-12999 IPv6 outgoing forward</span>
<span class="c">## 13000-13999 IPv4 outgoing forward</span>


<span class="c"># Flush out the list before we begin.</span>
ipfw <span class="nt">-q</span> <span class="nt">-f</span> flush

<span class="c"># Delete tables and NATs</span>
ipfw <span class="nt">-q</span> table all destroy
ipfw <span class="nt">-q</span> nat64lsn all destroy
ipfw <span class="nt">-q</span> nat64stl all destroy

<span class="c"># Replace Config</span>
ipfw <span class="nb">set </span>disable 1

<span class="c"># Set rules command prefix (for test add -n)</span>
<span class="nv">cmd</span><span class="o">=</span><span class="s2">"/sbin/ipfw -q add"</span>

<span class="c"># interface name of NIC attached to Internet</span>
<span class="nv">pif</span><span class="o">=</span><span class="s2">"vtnet0"</span>
<span class="nv">myip4</span><span class="o">=</span><span class="s2">"198.51.100.10/32"</span>
<span class="c"># Networks</span>
<span class="nv">corp_pub</span><span class="o">=</span><span class="s2">"{ 192.0.2.0/24 or 203.0.113.0/24 }"</span>
<span class="nv">corp_pub6</span><span class="o">=</span><span class="s2">"{ 2001:2:1::/48 or 2001:2:2::/48 }"</span>

<span class="c"># Non-routable IPv4 addresses</span>
<span class="c">## Enable this for RFC1918</span>
<span class="c">#martians="{ 127.0.0.0/8 or 192.168.0.0/16 or 172.16.0.0/12 or 10.0.0.0/8 \</span>
<span class="c">## Note: 204.152.64.0/23 is for Sun cluster interconnect</span>
<span class="nv">martians</span><span class="o">=</span><span class="s2">"{ 169.254.0.0/16 or 192.0.2.0/24 or 0.0.0.0/8 or 240.0.0.0/4 </span><span class="se">\</span><span class="s2">
		or 204.152.64.0/23 or 224.0.0.0/3 }"</span>

<span class="c"># NAT64</span>
<span class="c">#ipfw -q table T46 create type addr valtype ipv6</span>
<span class="c">#ipfw -q table T64 create type addr valtype ipv4</span>
<span class="c">#ipfw -q set 1 nat64lsn NAT64 create prefix4 $myip4 prefix6 64:ff9b::/96</span>

<span class="c"># NAT</span>
ipfw nat 1 config <span class="k">if</span> <span class="nv">$pif</span> same_ports unreg_only <span class="se">\</span>
                  redirect_port tcp 172.29.0.1:80 80 <span class="se">\</span>
                  redirect_port tcp 172.29.0.2:53 53 <span class="se">\</span>

<span class="c"># IPv6 Link-locals</span>
<span class="nv">$cmd</span> 00001 <span class="nb">set </span>1 call 9000 ipv6 from any to any

<span class="c"># Outgoing Jump</span>
<span class="nv">$cmd</span> 00005 <span class="nb">set </span>1 skipto 00500 all from any to any out

<span class="c">#### Before incoming NAT</span>
<span class="c"># Silent Drop to avoid logging</span>
<span class="nv">$cmd</span> 00020 <span class="nb">set </span>1 call 9100 all from any to any <span class="k">in</span>

<span class="c"># Dangerous Packets</span>
<span class="nv">$cmd</span> 00030 <span class="nb">set </span>1 call 9200 all from any to any <span class="k">in</span>

<span class="c"># IPv6 to me</span>
<span class="nv">$cmd</span> 00040 <span class="nb">set </span>1 call 1000 ipv6 from any to me6 <span class="k">in</span>

<span class="c"># IPv4 to me</span>
<span class="nv">$cmd</span> 00050 <span class="nb">set </span>1 call 2000 ipv4 from any to me <span class="k">in</span>

<span class="c"># Forward incoming IPv6</span>
<span class="nv">$cmd</span> 00060 <span class="nb">set </span>1 call 10000 ipv6 from any to any <span class="k">in</span>

<span class="c"># Forward incoming IPv4</span>
<span class="nv">$cmd</span> 00070 <span class="nb">set </span>1 call 11000 ipv4 from any to any <span class="k">in</span>

<span class="c"># Scrub (IPv4)</span>
<span class="nv">$cmd</span> 00099 <span class="nb">set </span>1 reass all from any to any <span class="k">in</span>

<span class="c">#### Incoming NAT</span>
<span class="c"># NAT64 Rules (100-199)</span>
<span class="c">#$cmd 00110 set 1 nat64lsn NAT64 ipv4 from any to $myip4 in</span>
<span class="c">#$cmd 00111 set 1 nat64lsn NAT64 ipv6 from any to 64:ff9b::/96 in</span>
<span class="c">#$cmd 00120 set 1 pass ipv4 from $myip4 to any in recv lo0 record-state</span>
<span class="c">#$cmd 00121 set 1 pass ipv4 from $myip4 to any out xmit $pif record-state</span>
<span class="c">#$cmd 00130 set 1 pass ipv6 from 64:ff9b::/96 to 2a01:e140:dead::/44 in recv $pif record-state</span>
<span class="c">#$cmd 00131 set 1 pass ipv6 from 64:ff9b::/96 to 2a01:e140:dead::/44 out xmit $pif record-state</span>
<span class="c">#$cmd 00132 set 1 pass ipv6 from 64:ff9b::/96 to 2a01:e140:dead::/44 in recv lo0 record-state</span>

<span class="c"># NAT Rules (200-299)</span>
<span class="nv">$cmd</span> 00200 <span class="nb">set </span>1 nat 1 ipv4 from any to <span class="nv">$myip4</span> <span class="k">in </span>recv <span class="nv">$pif</span>


<span class="c">### Check-state After incoming NAT</span>
<span class="c"># Passes the packet through if it matches an existing entry in the dynamic rules table</span>
<span class="nv">$cmd</span> 00300 <span class="nb">set </span>1 check-state

<span class="c">### After incoming NAT</span>
<span class="c"># Dangerous Packets</span>
<span class="nv">$cmd</span> 00400 <span class="nb">set </span>1 call 9200 all from any to any <span class="k">in</span>

<span class="c"># IPv6 to me</span>
<span class="nv">$cmd</span> 00410 <span class="nb">set </span>1 call 3000 ipv6 from any to me6 <span class="k">in</span>

<span class="c"># IPv4 to me</span>
<span class="nv">$cmd</span> 00420 <span class="nb">set </span>1 call 4000 ipv4 from any to me <span class="k">in</span>

<span class="c">### Before outgoing NAT (500)</span>
<span class="c"># IPv6 from me out</span>
<span class="nv">$cmd</span> 00510 <span class="nb">set </span>1 call 5000 ipv6 from me6 to any out

<span class="c"># IPv4 from me out</span>
<span class="nv">$cmd</span> 00520 <span class="nb">set </span>1 call 6000 ipv4 from me to any out

<span class="c"># Forward Outgoing IPv6</span>
<span class="nv">$cmd</span> 00530 <span class="nb">set </span>1 call 12000 ipv6 from any to any out

<span class="c"># Forward Outgoing IPv4</span>
<span class="nv">$cmd</span> 00540 <span class="nb">set </span>1 call 13000 ipv4 from any to any out

<span class="c"># NAT outbound</span>
<span class="nv">$cmd</span> 00600 <span class="nb">set </span>1 nat 1 ipv4 from any to any out xmit <span class="nv">$pif</span>

<span class="c">### Check-state After outgoing NAT</span>
<span class="c"># Passes the packet through if it matches an existing entry in the dynamic rules table</span>
<span class="nv">$cmd</span> 00700 <span class="nb">set </span>1 check-state

<span class="c">### After outgoing NAT (800)</span>
<span class="c"># IPv6 from me</span>
<span class="nv">$cmd</span> 00810 <span class="nb">set </span>1 call 7000 ipv6 from me6 to any out

<span class="c"># IPv4 from me</span>
<span class="nv">$cmd</span> 00820 <span class="nb">set </span>1 call 8000 ipv4 from any to any out

<span class="c"># Everything else is denied</span>
<span class="nv">$cmd</span> 00999 <span class="nb">set </span>1 drop log all from any to any


<span class="c"># IPv6 to me before incoming NAT (1000 -&gt; 1999)</span>
<span class="c"># Pass myself</span>
<span class="nv">$cmd</span> 01000 <span class="nb">set </span>1 pass ipv6 from me6 to me6 <span class="k">in</span>
<span class="c"># Pass SSH</span>
<span class="nv">$cmd</span> 01001 <span class="nb">set </span>1 pass tcp from any to me6 ssh record-state defer-action <span class="k">in</span>
<span class="c"># DNS</span>
<span class="nv">$cmd</span> 01002 <span class="nb">set </span>1 pass <span class="o">{</span> tcp or udp <span class="o">}</span> from any to <span class="o">{</span> 2001:2::53 or 2001:2:10::53 <span class="o">}</span> domain, domain<span class="se">\\</span><span class="nt">-s</span> record-state defer-action <span class="k">in</span>
<span class="c"># Web</span>
<span class="nv">$cmd</span> 01003 <span class="nb">set </span>1 pass <span class="o">{</span> tcp or udp <span class="o">}</span> from any to <span class="o">{</span> 2001:2::80 or 2001:2:10::80 <span class="o">}</span> https,http record-state defer-action <span class="k">in</span>

<span class="c"># Pass Internal Prefix</span>
<span class="nv">$cmd</span> 01090 <span class="nb">set </span>1 pass ipv6 from <span class="nv">$corp_pub6</span> to any record-state defer-action <span class="k">in</span>

<span class="c"># Pass ICMPv6</span>
<span class="nv">$cmd</span> 01100 <span class="nb">set </span>1 pass icmp6 from any to any <span class="k">in</span>

<span class="c"># End of IPv6 to me6</span>
<span class="nv">$cmd</span> 01999 <span class="nb">set </span>1 <span class="k">return </span>via any


<span class="c"># IPv4 to me before NAT (2000 -&gt; 2999)</span>
<span class="c"># Pass me</span>
<span class="nv">$cmd</span> 02000 <span class="nb">set </span>1 pass ipv4 from me to me <span class="k">in</span>
<span class="c"># Pass SSH</span>
<span class="nv">$cmd</span> 02001 <span class="nb">set </span>1 pass tcp from any to <span class="nv">$myip4</span> ssh record-state defer-action <span class="k">in </span>recv <span class="nv">$pif</span>
<span class="c"># DNS</span>
<span class="nv">$cmd</span> 02002 <span class="nb">set </span>1 pass <span class="o">{</span> tcp or udp <span class="o">}</span> from any to <span class="nv">$myip4</span> domain, domain<span class="se">\\</span><span class="nt">-s</span> record-state defer-action <span class="k">in </span>recv <span class="nv">$pif</span>
<span class="c"># Web</span>
<span class="nv">$cmd</span> 02003 <span class="nb">set </span>1 pass tcp from any to <span class="nv">$myip4</span> https,http record-state defer-action <span class="k">in </span>recv <span class="nv">$pif</span>

<span class="c"># Pass Corp</span>
<span class="nv">$cmd</span> 02090 <span class="nb">set </span>1 pass ipv4 from <span class="nv">$corp_pub</span> to any record-state defer-action <span class="k">in </span>recv <span class="nv">$pif</span>

<span class="c"># Pass ICMPv4</span>
<span class="nv">$cmd</span> 02100 <span class="nb">set </span>1 pass icmp from any to me record-state defer-action <span class="k">in </span>recv <span class="nv">$pif</span>

<span class="c"># End of IPv4 to me</span>
<span class="nv">$cmd</span> 02999 <span class="nb">set </span>1 <span class="k">return </span>via any


<span class="c"># IPv6 to me after incoming NAT (3000 -&gt; 3999)</span>
<span class="c"># End of IPv6 to me</span>
<span class="nv">$cmd</span> 03999 <span class="nb">set </span>1 <span class="k">return </span>via any


<span class="c"># IPv4 to me after incoming NAT (4000 -&gt; 4999)</span>
<span class="c"># DNS</span>
<span class="nv">$cmd</span> 04001 <span class="nb">set </span>1 pass <span class="o">{</span> tcp or udp <span class="o">}</span> from any to 172.29.0.2 domain, domain<span class="se">\\</span><span class="nt">-s</span> keep-state <span class="k">in </span>recv <span class="nv">$pif</span>
<span class="c"># Web</span>
<span class="nv">$cmd</span> 04002 <span class="nb">set </span>1 pass tcp from any to 172.29.0.1 https,http keep-state <span class="k">in </span>recv <span class="nv">$pif</span>

<span class="c"># End of IPv4 to me</span>
<span class="nv">$cmd</span> 04999 <span class="nb">set </span>1 <span class="k">return </span>via any


<span class="c"># IPv6 from me before outgoing nat (5000 -&gt; 5999)</span>
<span class="nv">$cmd</span> 05000 <span class="nb">set </span>1 pass ipv6 from me6 to me6 out
<span class="nv">$cmd</span> 05001 <span class="nb">set </span>1 pass ipv6 from me6 to any record-state defer-action out

<span class="c"># End of IPv6 from me6</span>
<span class="nv">$cmd</span> 05999 <span class="nb">set </span>1 <span class="k">return </span>via any


<span class="c"># IPv4 from me before outgoing NAT (6000 -&gt; 6999)</span>
<span class="nv">$cmd</span> 06000 <span class="nb">set </span>1 pass ipv4 from me to me out

<span class="c"># Allow any other out</span>
<span class="nv">$cmd</span> 06101 <span class="nb">set </span>1 pass ipv4 from me to any record-state defer-action out

<span class="c"># IPv4 xmit $pif Skipto outgoing NAT</span>
<span class="nv">$cmd</span> 06900 <span class="nb">set </span>1 skipto 00600 ipv4 from me to any out xmit <span class="nv">$pif</span>

<span class="c"># End of IPv4 from me before NAT</span>
<span class="nv">$cmd</span> 06999 <span class="nb">set </span>1 <span class="k">return </span>via any


<span class="c"># IPv6 from me after outgoing nat (7000 -&gt; 7999)</span>
<span class="nv">$cmd</span> 07000 <span class="nb">set </span>1 pass ipv6 from me6 to me6 out
<span class="nv">$cmd</span> 07001 <span class="nb">set </span>1 pass ipv6 from me6 to any keep-state out

<span class="c"># End of IPv6 from me</span>
<span class="nv">$cmd</span> 07999 <span class="nb">set </span>1 <span class="k">return </span>via any


<span class="c"># IPv4 from me after outgoing nat (8000 -&gt; 8999)</span>
<span class="nv">$cmd</span> 08000 <span class="nb">set </span>1 pass ipv4 from me to me out
<span class="nv">$cmd</span> 08001 <span class="nb">set </span>1 pass ipv4 from me to any keep-state out

<span class="c"># End of IPv4 from me</span>
<span class="nv">$cmd</span> 08999 <span class="nb">set </span>1 <span class="k">return </span>via any


<span class="c"># Link-Locals Only (9000 -&gt; 9099)</span>
<span class="c">## Allow IPv6 DAD</span>
<span class="nv">$cmd</span> 09000 <span class="nb">set </span>1 pass icmp6 from :: to ff02::/16

<span class="c">## Allow IPv6 Link-locals specially for NDP (RS, RA, NS, NA, &amp; redirect)</span>
<span class="nv">$cmd</span> 09001 <span class="nb">set </span>1 pass icmp6 from fe80::/10 to fe80::/10
<span class="nv">$cmd</span> 09002 <span class="nb">set </span>1 pass icmp6 from fe80::/10 to ff02::/16

<span class="c"># Allow ICMPv6 NS, NA</span>
<span class="nv">$cmd</span> 09010 <span class="nb">set </span>1 pass icmp6 from fe80::/10 to 2000::/3 icmp6types 135,136
<span class="nv">$cmd</span> 09011 <span class="nb">set </span>1 pass icmp6 from 2000::/3 to <span class="o">{</span> ff02::/16 or fe80::/10 <span class="o">}</span> icmp6types 135,136

<span class="c"># Link-Local Protocols</span>
<span class="c"># Pass OSPF</span>
<span class="nv">$cmd</span> 09020 <span class="nb">set </span>1 pass ospf from fe80::/64 to any <span class="k">in </span>recv <span class="nv">$pif</span>

<span class="c"># End of Link-Locals Only</span>
<span class="nv">$cmd</span> 09099 <span class="nb">set </span>1 <span class="k">return </span>via any


<span class="c"># Silent Drop (9100 -&gt; 9199)</span>
<span class="c"># Drop Sooner to prevent being logged for nothing</span>
<span class="nv">$cmd</span> 09100 <span class="nb">set </span>1 drop udp from 0.0.0.0 68 to 255.255.255.255 67 <span class="k">in</span>
<span class="nv">$cmd</span> 09101 <span class="nb">set </span>1 drop udp from any 5678 to any 5678 <span class="k">in</span>
<span class="nv">$cmd</span> 09102 <span class="nb">set </span>1 drop udp from any to 255.255.255.255 5353 <span class="k">in</span>
<span class="nv">$cmd</span> 09103 <span class="nb">set </span>1 drop udp from any to 255.255.255.255 1900 <span class="k">in</span>

<span class="c"># End of Silent Drop</span>
<span class="nv">$cmd</span> 09199 <span class="nb">set </span>1 <span class="k">return </span>via any


<span class="c"># Dangerous Packets Drop Only (9200 -&gt; 9999)</span>
<span class="c"># Deny RH0 (RFC5095)</span>
<span class="nv">$cmd</span> 09200 <span class="nb">set </span>1 drop log ipv6 from any to any ext6hdr rthdr0 <span class="k">in</span>

<span class="c"># uRPF (RFC)</span>
<span class="nv">$cmd</span> 09201 <span class="nb">set </span>1 drop log ip from not me to any not antispoof <span class="k">in</span>

<span class="c"># Deny all inbound traffic from non-routable reserved address spaces</span>
<span class="c">## IPv4</span>
<span class="nv">$cmd</span> 09211 <span class="nb">set </span>1 drop log ipv4 from <span class="nv">$martians</span> to any <span class="k">in </span>recv <span class="nv">$pif</span>
<span class="nv">$cmd</span> 09212 <span class="nb">set </span>1 drop log ipv4 from <span class="nv">$martians</span> to any <span class="k">in </span>recv vtnet1

<span class="c">## IPv6</span>
<span class="nv">$cmd</span> 09230 <span class="nb">set </span>1 drop log ipv6 from ::1/128 to any <span class="k">in</span>
<span class="c">### Site-local (RFC3879)</span>
<span class="nv">$cmd</span> 09231 <span class="nb">set </span>1 drop log ipv6 from fec0::/10 to any <span class="k">in</span>
<span class="c">### IPv4-Compatible IPv6 (RFC4291)</span>
<span class="nv">$cmd</span> 09232 <span class="nb">set </span>1 drop log ipv6 from ::/96 to any <span class="k">in</span>
<span class="c">### Deny Teredo IPv6 (RFC4380)</span>
<span class="nv">$cmd</span> 09233 <span class="nb">set </span>1 drop log ipv6 from 2001::/32 to any <span class="k">in</span>
<span class="c">### Deny IPv6 Documentation (RFC3849)</span>
<span class="nv">$cmd</span> 09234 <span class="nb">set </span>1 drop log ipv6 from 2001:db8::/32 to any <span class="k">in</span>
<span class="c">### Deny Discard-Only IPv6 Address (RFC6666)</span>
<span class="nv">$cmd</span> 09235 <span class="nb">set </span>1 drop log ipv6 from 100::/64 to any <span class="k">in</span>
<span class="c">### Deny ORCHID (RFC5156)</span>
<span class="nv">$cmd</span> 09236 <span class="nb">set </span>1 drop log ipv6 from 2001:10::/28 to any <span class="k">in</span>
<span class="c">### Deny Benchmarking IPv6 (RFC5180)</span>
<span class="nv">$cmd</span> 09237 <span class="nb">set </span>1 drop log ipv6 from 2001:2::/48 to any <span class="k">in</span>
<span class="c">### Deny 6Bone (RFC3701)</span>
<span class="nv">$cmd</span> 09238 <span class="nb">set </span>1 drop log ipv6 from <span class="o">{</span> 3ffe::/16 or 5f00::/8 <span class="o">}</span> to any <span class="k">in</span>

<span class="c">### XMAS tree</span>
<span class="nv">$cmd</span> 09251 <span class="nb">set </span>1 drop log tcp from any to any tcpflags fin,psh,urg <span class="k">in</span>
<span class="c">### NULL scan (no flag set at all)</span>
<span class="nv">$cmd</span> 09252 <span class="nb">set </span>1 drop log tcp from any to any tcpflags <span class="o">!</span>fin,!syn,!rst,!psh,!ack,!urg <span class="k">in</span>
<span class="c">### SYN flood (SYN,FIN)</span>
<span class="nv">$cmd</span> 09253 <span class="nb">set </span>1 drop log tcp from any to any tcpflags syn,fin <span class="k">in</span>
<span class="c">### Stealth FIN scan (FIN,RST)</span>
<span class="nv">$cmd</span> 09254 <span class="nb">set </span>1 drop log tcp from any to any tcpflags fin,rst <span class="k">in</span>
<span class="c">### forced packet routing</span>
<span class="nv">$cmd</span> 09255 <span class="nb">set </span>1 drop log ip from any to any ipoptions ssrr,lsrr,rr,ts <span class="k">in</span>

<span class="c"># Deny fragmented NDP packets (RFC6980)</span>
<span class="nv">$cmd</span> 09271 <span class="nb">set </span>1 drop log icmp6 from any to any ext6hdr frag icmp6types 130,131,132,133,134,135,136,143 <span class="k">in</span>

<span class="c"># Deny ICMPv6 Redirect and Renumbering</span>
<span class="nv">$cmd</span> 09272 <span class="nb">set </span>1 drop log icmp6 from any to any icmp6types 137,138 <span class="k">in</span>

<span class="c"># End of Dangerous packets</span>
<span class="nv">$cmd</span> 09999 <span class="nb">set </span>1 <span class="k">return </span>via any


<span class="c">## 10000-10999 IPv6 incoming forward</span>
<span class="nv">$cmd</span> 10000 <span class="nb">set </span>1 pass ipv6 from 2a01:e140:dead::/48 to any <span class="k">in</span>
<span class="nv">$cmd</span> 10001 <span class="nb">set </span>1 pass ipv6 from any to 2a01:e140:dead::/48 <span class="k">in</span>

<span class="c"># End of IPv6 Incoming Forward</span>
<span class="nv">$cmd</span> 10999 <span class="nb">set </span>1 <span class="k">return </span>via any


<span class="c">## 11000-11999 IPv4 incoming forward</span>

<span class="c"># End of IPv4 Incoming Forward</span>
<span class="nv">$cmd</span> 11999 <span class="nb">set </span>1 <span class="k">return </span>via any


<span class="c">## 12000-12999 IPv6 outgoing forward</span>
<span class="nv">$cmd</span> 12000 <span class="nb">set </span>1 pass ipv6 from any to 2a01:e140:dead::/48 out
<span class="nv">$cmd</span> 12001 <span class="nb">set </span>1 pass ipv6 from 2a01:e140:dead::/48 to any out

<span class="c"># End of IPv6 Incoming Forward</span>
<span class="nv">$cmd</span> 12999 <span class="nb">set </span>1 <span class="k">return </span>via any


<span class="c">## 13000-13999 IPv4 outgoing forward</span>

<span class="c"># End of IPv4 outgoing Forward</span>
<span class="nv">$cmd</span> 13999 <span class="nb">set </span>1 <span class="k">return </span>via any


<span class="c"># Replace Config</span>
ipfw <span class="nb">set </span>swap 0 1
ipfw delete <span class="nb">set </span>1

</code></pre></div></div>

<p>Hope it helps!</p>]]></content><author><name>Seyed Pouria Mousavizadeh Tehrani</name><email>info@spmzt.net</email></author><category term="FreeBSD" /><category term="IPFW" /><category term="Firewall" /><category term="IPv6" /><category term="IPv4" /><summary type="html"><![CDATA[Configuration of IPFW can be quite complex. However once you understand its syntax it will be fairly simple. But, This article is not a manual explaining things. It’s for those who already can understand what are they doing with IPFW.]]></summary></entry><entry><title type="html">Setup FreeBSD NFSv3 with ZFS</title><link href="http://spmzt.net/2024/02/20/FreeBSD-NFSv3/" rel="alternate" type="text/html" title="Setup FreeBSD NFSv3 with ZFS" /><published>2024-02-20T03:52:00+03:30</published><updated>2024-02-20T03:52:00+03:30</updated><id>http://spmzt.net/2024/02/20/FreeBSD-NFSv3</id><content type="html" xml:base="http://spmzt.net/2024/02/20/FreeBSD-NFSv3/"><![CDATA[<p>Configuration of NFSv3 with ZFS is fairly simple.</p>

<h2 id="server-configuration">Server configuration</h2>

<p>Enable (Persist) Services:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">nfs_server_enable</span><span class="o">=</span><span class="s2">"YES"</span>
<span class="nv">nfs_server_flags</span><span class="o">=</span><span class="s2">"-u -t -n 4"</span>
<span class="nv">rpc_lockd_enable</span><span class="o">=</span><span class="s2">"YES"</span>
<span class="nv">rpc_statd_enable</span><span class="o">=</span><span class="s2">"YES"</span>
</code></pre></div></div>

<p>Start Services:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>service nfsd start
service lockd start
service statd start
</code></pre></div></div>

<h2 id="zfs">ZFS</h2>

<p>Share <code class="language-plaintext highlighter-rouge">tank/share</code> dateset for 10.0.0.0/24 network:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>zfs <span class="nb">set </span><span class="nv">mountpoint</span><span class="o">=</span><span class="s2">"maproot=root,sec=sys,alldirs,network=10.0.0.0/24"</span> tank/share
zfs share tank/share
</code></pre></div></div>]]></content><author><name>Seyed Pouria Mousavizadeh Tehrani</name><email>info@spmzt.net</email></author><category term="FreeBSD" /><category term="NFSv3" /><category term="ZFS" /><summary type="html"><![CDATA[Configuration of NFSv3 with ZFS is fairly simple.]]></summary></entry><entry><title type="html">Binding SSH Port on Another Server</title><link href="http://spmzt.net/2023/04/13/2023-04-12-Autossh-Tunnel/" rel="alternate" type="text/html" title="Binding SSH Port on Another Server" /><published>2023-04-13T01:47:00+03:30</published><updated>2023-04-13T01:47:00+03:30</updated><id>http://spmzt.net/2023/04/13/2023-04-12-Autossh-Tunnel</id><content type="html" xml:base="http://spmzt.net/2023/04/13/2023-04-12-Autossh-Tunnel/"><![CDATA[<p>Whether your servers are connected to the internet or not, it’s always a good maintenance practice to bind the SSH ports to a different server. 
This guide will walk you through the steps to bind your servers’ SSH ports to another server.</p>

<h3 id="create-user-folder-with-ssh">Create user folder with ssh</h3>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">mkdir</span> <span class="nt">-p</span> /home/user/.ssh
</code></pre></div></div>

<h3 id="add-user">Add user</h3>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>useradd user <span class="nt">-m</span> <span class="nt">-d</span> /home/user <span class="nt">-s</span> /bin/true
</code></pre></div></div>

<h3 id="add-your-key-to-authorized-keys">Add your key to authorized keys</h3>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">echo</span> <span class="s1">'client-key'</span> <span class="o">&gt;</span> /home/user/.ssh/authorized_keys
</code></pre></div></div>

<h3 id="change-directory-ownership">Change directory ownership</h3>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">chown</span> <span class="nt">-R</span> user:user /home/user
</code></pre></div></div>

<h2 id="client-linux">Client (Linux)</h2>

<h3 id="create-systemd-service">Create Systemd service</h3>

<p>Replace <code class="language-plaintext highlighter-rouge">x</code> with your wanted remote port on the remote server.
Add to <code class="language-plaintext highlighter-rouge">/etc/systemd/system/autossh-tunnel.service</code>:</p>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">[Unit]</span>
<span class="py">Description</span><span class="p">=</span><span class="s">AutoSSH tunnel service to server on local port 22</span>
<span class="py">After</span><span class="p">=</span><span class="s">network.target</span>

<span class="nn">[Service]</span>
<span class="py">Environment</span><span class="p">=</span><span class="s">"AUTOSSH_GATETIME=0"</span>
<span class="py">User</span><span class="p">=</span><span class="s">spmzt</span>
<span class="py">Group</span><span class="p">=</span><span class="s">spmzt</span>
<span class="py">ExecStart</span><span class="p">=</span><span class="s">/usr/bin/autossh -M 0 -o "ServerAliveInterval 30" -o "ServerAliveCountMax 3" -NR x:localhost:22 user@spmzt.net -p 22</span>

<span class="nn">[Install]</span>
<span class="py">WantedBy</span><span class="p">=</span><span class="s">multi-user.target</span>
</code></pre></div></div>

<h2 id="client-freebsd">Client (FreeBSD)</h2>

<h3 id="create-rc-script">Create RC Script</h3>

<p>Replace <code class="language-plaintext highlighter-rouge">x</code> with your wanted remote port on the remote server.
Add to <code class="language-plaintext highlighter-rouge">/usr/local/etc/rc.d/autossh_tunnel</code>:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/sh</span>
<span class="c">#</span>
<span class="c"># PROVIDE: autossh_tunnel</span>
<span class="c"># REQUIRE: sshd</span>
<span class="c"># KEYWORD: shutdown</span>

<span class="nb">.</span> /etc/rc.subr

<span class="nv">name</span><span class="o">=</span>autossh_tunnel
<span class="nv">desc</span><span class="o">=</span><span class="s2">"AutoSSH tunnel service to server on port 22"</span>
<span class="nv">rcvar</span><span class="o">=</span>autossh_tunnel_enable

<span class="nb">command</span><span class="o">=</span><span class="s2">"/usr/local/bin/sudo"</span>
<span class="nv">command_args</span><span class="o">=</span><span class="s1">'-u user /usr/local/bin/autossh -f -M 0 -o "ServerAliveInterval 30" -o "ServerAliveCountMax 3" -NR x:localhost:22 user@spmzt.net -p 22'</span>

load_rc_config <span class="nv">$name</span>

<span class="c">#</span>
<span class="c"># DO NOT CHANGE THESE DEFAULT VALUES HERE</span>
<span class="c"># SET THEM IN THE /etc/rc.conf FILE</span>
<span class="c">#</span>
<span class="nv">autossh_tunnel_enable</span><span class="o">=</span><span class="k">${</span><span class="nv">autossh_tunnel_enable</span><span class="p">-</span><span class="s2">"NO"</span><span class="k">}</span>
<span class="nv">pidfile</span><span class="o">=</span><span class="k">${</span><span class="nv">autossh_tunnel_pidfile</span><span class="p">-</span><span class="s2">"/var/run/autossh_tunnel.pid"</span><span class="k">}</span>

run_rc_command <span class="s2">"</span><span class="nv">$1</span><span class="s2">"</span>
</code></pre></div></div>]]></content><author><name>Seyed Pouria Mousavizadeh Tehrani</name><email>info@spmzt.net</email></author><category term="FreeBSD" /><category term="SSH" /><category term="Linux" /><summary type="html"><![CDATA[Whether your servers are connected to the internet or not, it’s always a good maintenance practice to bind the SSH ports to a different server. This guide will walk you through the steps to bind your servers’ SSH ports to another server.]]></summary></entry><entry><title type="html">Setup FreeBSD Intermediate VPN by using Openconnect in Jail with vnet and separate fib on host</title><link href="http://spmzt.net/2023/04/12/FreeBSD-Intermediate-VPN/" rel="alternate" type="text/html" title="Setup FreeBSD Intermediate VPN by using Openconnect in Jail with vnet and separate fib on host" /><published>2023-04-12T21:48:00+03:30</published><updated>2023-04-12T21:48:00+03:30</updated><id>http://spmzt.net/2023/04/12/FreeBSD-Intermediate-VPN</id><content type="html" xml:base="http://spmzt.net/2023/04/12/FreeBSD-Intermediate-VPN/"><![CDATA[<p>Have you ever found yourself unable to connect to specific VPNs due to firewalls or censorship devices that block your connection to outside networks? It can be frustrating, but there’s a solution: routing your traffic through a trusted network that you can access.</p>

<p>Here’s the problem: you may have access to a trusted network, but it doesn’t have direct access to the outside world. This means that you need to create an intermediate VPN that allows you to connect to the outside world from within the trusted network.</p>

<p>One way to set up this intermediate VPN is by using FreeBSD Jails with multiple FIBs. With this setup, you have full control over the traffic and can access multiple VPNs at the same time.</p>

<p>Here’s how it works: first, you establish a VPN connection from your laptop to the trusted network, which is your intermediate VPN. Then, using FreeBSD Jails with multiple FIBs, you can establish additional VPN connections from your intermediate VPN to multiple VPN endpoints. This allows you to bypass censorship and connect to VPNs that were previously inaccessible.</p>

<p>Using FreeBSD Jails with multiple FIBs is a powerful solution for those who need to access restricted networks. With this setup, you can have full control over your traffic and access multiple VPNs simultaneously.</p>

<p>In this blog post, I’m going to share my current network configuration. I’m going to break down my configuration step by step and explain each component in detail.</p>

<h2 id="documentation">Documentation</h2>

<ul>
  <li>
    <p>fib 0: without VPN</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  * vtnet0: 1.1.1.2/24
  * e0a_overlay: 172.31.87.1/30
</code></pre></div>    </div>
  </li>
  <li>
    <p>fib 1: with VPN</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  * e1a_overlay: 172.31.88.1/30
  * tun257: openvpn-client 172.31.1.174 -&gt; 173
</code></pre></div>    </div>
  </li>
  <li>
    <p>jail:</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  * e0b_overlay: 172.31.87.2/30
  * e1b_overlay: 172.31.88.2/30
  * ocserv clients: 172.31.5.0/24
</code></pre></div>    </div>
  </li>
</ul>

<p>Firstly, my network consists of two FIBs: one without VPN and one with VPN. For the first FIB, I use the <code class="language-plaintext highlighter-rouge">vtnet0</code> interface with IP address <code class="language-plaintext highlighter-rouge">1.1.1.2/24</code>, while for the second FIB, I use the <code class="language-plaintext highlighter-rouge">tun257</code> interface with IP address <code class="language-plaintext highlighter-rouge">172.31.1.174</code> -&gt; 173. The VPN is established through OpenVPN, and the IP addresses for the VPN connections are <code class="language-plaintext highlighter-rouge">172.31.87.1/30</code> for <code class="language-plaintext highlighter-rouge">e0a_overlay</code>, and <code class="language-plaintext highlighter-rouge">172.31.88.1/30</code> for <code class="language-plaintext highlighter-rouge">e1a_overlay</code>.</p>

<h3 id="rcconf">rc.conf</h3>

<p>Replace ip addresses and interface names to your own environment.
Add these to your <code class="language-plaintext highlighter-rouge">/etc/rc.conf</code> configurations:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">ifconfig_vtnet0</span><span class="o">=</span><span class="s2">"inet 1.1.1.2/24 -tso -rxcsum"</span>
<span class="nv">defaultrouter</span><span class="o">=</span><span class="s2">"1.1.1.1"</span>
<span class="nv">cloned_interfaces</span><span class="o">=</span><span class="s2">"tun257 epair1 epair0"</span>
<span class="nv">ifconfig_epair0a</span><span class="o">=</span><span class="s2">"name e0a_overlay -tso -rxcsum"</span>
<span class="nv">ifconfig_epair0b</span><span class="o">=</span><span class="s2">"name e0b_overlay -tso -rxcsum"</span>
<span class="nv">ifconfig_epair1a</span><span class="o">=</span><span class="s2">"name e1a_overlay fib 1 -tso -rxcsum"</span>
<span class="nv">ifconfig_epair1b</span><span class="o">=</span><span class="s2">"name e1b_overlay fib 1 -tso -rxcsum"</span>
<span class="nv">ifconfig_tun257</span><span class="o">=</span><span class="s2">"fib 1 -tso -rxcsum"</span>
<span class="nv">pf_enable</span><span class="o">=</span><span class="s2">"YES"</span>
<span class="nv">pflog_enable</span><span class="o">=</span><span class="s2">"YES"</span>
<span class="nv">ezjail_enable</span><span class="o">=</span><span class="s2">"YES"</span>
<span class="nv">gateway_enable</span><span class="o">=</span><span class="s2">"YES"</span>
<span class="nv">static_routes</span><span class="o">=</span><span class="s2">"outsidevpn defaultfib1"</span>
<span class="nv">route_outsidevpn</span><span class="o">=</span><span class="s2">"-net 2.2.2.2 -gateway 1.1.1.1 -fib 1"</span>
<span class="nv">route_defaultfib1</span><span class="o">=</span><span class="s2">"-net default -gateway 1.1.1.1 -fib 1"</span>
<span class="nv">openvpn_outsidevpn_enable</span><span class="o">=</span><span class="s2">"YES"</span>
<span class="nv">openvpn_outsidevpn_fib</span><span class="o">=</span><span class="s2">"1"</span>
<span class="nv">openvpn_outsidevpn_configfile</span><span class="o">=</span><span class="s2">"/usr/local/etc/openvpn/outsidevpn.conf"</span>
</code></pre></div></div>

<p>Next, let’s take a look at the <code class="language-plaintext highlighter-rouge">rc.conf</code> file. Here, we specify the configuration for our interfaces and the routing table. We enable the PF firewall and configure static routes for traffic to <code class="language-plaintext highlighter-rouge">2.2.2.2</code> which is our final vpn ip address. We also enable OpenVPN for outsidevpn, specifying that it uses FIB 1, and we provide the path to the OpenVPN configuration file.</p>

<h2 id="jail-rcconf">(Jail) rc.conf</h2>

<p><code class="language-plaintext highlighter-rouge">/usr/jails/overlay/etc/rc.conf</code>:</p>

<pre><code class="language-tcsh">ifconfig_e0b_overlay="inet 172.31.87.2/30 fib 0"
ifconfig_e1b_overlay="inet 172.31.88.2/30 fib 0"
defaultrouter="172.31.88.1"
ocserv_enable="YES"
gateway_enable="YES"
</code></pre>

<h2 id="ezjailjail-configuration">ezjail/jail configuration</h2>

<p>Use the configuration below if you use <code class="language-plaintext highlighter-rouge">ezjail</code> for jail management.</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">export </span><span class="nv">jail_overlay_hostname</span><span class="o">=</span><span class="s2">"overlay"</span>
<span class="nb">export </span><span class="nv">jail_overlay_ip</span><span class="o">=</span><span class="s2">""</span>
<span class="nb">export </span><span class="nv">jail_overlay_rootdir</span><span class="o">=</span><span class="s2">"/usr/jails/overlay"</span>
<span class="nb">export </span><span class="nv">jail_overlay_exec_start</span><span class="o">=</span><span class="s2">"/bin/sh /etc/rc"</span>
<span class="nb">export </span><span class="nv">jail_overlay_exec_stop</span><span class="o">=</span><span class="s2">""</span>
<span class="nb">export </span><span class="nv">jail_overlay_mount_enable</span><span class="o">=</span><span class="s2">"YES"</span>
<span class="nb">export </span><span class="nv">jail_overlay_devfs_enable</span><span class="o">=</span><span class="s2">"YES"</span>
<span class="nb">export </span><span class="nv">jail_overlay_devfs_ruleset</span><span class="o">=</span><span class="s2">"6"</span>
<span class="nb">export </span><span class="nv">jail_overlay_procfs_enable</span><span class="o">=</span><span class="s2">"YES"</span>
<span class="nb">export </span><span class="nv">jail_overlay_fdescfs_enable</span><span class="o">=</span><span class="s2">"YES"</span>
<span class="nb">export </span><span class="nv">jail_overlay_image</span><span class="o">=</span><span class="s2">""</span>
<span class="nb">export </span><span class="nv">jail_overlay_imagetype</span><span class="o">=</span><span class="s2">"zfs"</span>
<span class="nb">export </span><span class="nv">jail_overlay_attachparams</span><span class="o">=</span><span class="s2">""</span>
<span class="nb">export </span><span class="nv">jail_overlay_attachblocking</span><span class="o">=</span><span class="s2">""</span>
<span class="nb">export </span><span class="nv">jail_overlay_forceblocking</span><span class="o">=</span><span class="s2">""</span>
<span class="nb">export </span><span class="nv">jail_overlay_zfs_datasets</span><span class="o">=</span><span class="s2">""</span>
<span class="nb">export </span><span class="nv">jail_overlay_cpuset</span><span class="o">=</span><span class="s2">""</span>
<span class="nb">export </span><span class="nv">jail_overlay_fib</span><span class="o">=</span><span class="s2">""</span>
<span class="nb">export </span><span class="nv">jail_overlay_parentzfs</span><span class="o">=</span><span class="s2">"zroot/jails"</span>
<span class="nb">export </span><span class="nv">jail_overlay_parameters</span><span class="o">=</span><span class="s2">""</span>
<span class="nb">export </span><span class="nv">jail_overlay_post_start_script</span><span class="o">=</span><span class="s2">""</span>
<span class="nb">export </span><span class="nv">jail_overlay_retention_policy</span><span class="o">=</span><span class="s2">""</span>
<span class="nb">export </span><span class="nv">jail_overlay_vnet_enable</span><span class="o">=</span><span class="s2">"YES"</span>
<span class="nb">export </span><span class="nv">jail_overlay_vnet_interface</span><span class="o">=</span><span class="s2">"e0b_overlay e1b_overlay"</span>
<span class="nb">export </span><span class="nv">jail_overlay_exec_prestart0</span><span class="o">=</span><span class="s2">"/sbin/ifconfig e0a_overlay inet 172.31.87.1/30"</span>
<span class="nb">export </span><span class="nv">jail_overlay_exec_prestart1</span><span class="o">=</span><span class="s2">"/sbin/ifconfig e1a_overlay inet 172.31.88.1/30"</span>
<span class="nb">export </span><span class="nv">jail_overlay_exec_prestart2</span><span class="o">=</span><span class="s2">"/sbin/route add -net 172.31.5.0/24 -gateway 172.31.88.2 -fib 1"</span>
<span class="nb">export </span><span class="nv">jail_overlay_exec_prestart3</span><span class="o">=</span><span class="s2">"/sbin/route add -net 172.31.5.0/24 -gateway 172.31.87.2"</span>
<span class="nb">export </span><span class="nv">jail_overlay_exec_poststop0</span><span class="o">=</span><span class="s2">"/sbin/route del -net 172.31.5.0/24 -gateway 172.31.87.2"</span>
<span class="nb">export </span><span class="nv">jail_overlay_exec_poststop1</span><span class="o">=</span><span class="s2">"/sbin/route del -net 172.31.5.0/24 -gateway 172.31.88.2 -fib 1"</span>
<span class="nb">export </span><span class="nv">jail_overlay_exec_poststop2</span><span class="o">=</span><span class="s2">"/sbin/ifconfig e0a_overlay delete"</span>
<span class="nb">export </span><span class="nv">jail_overlay_exec_poststop3</span><span class="o">=</span><span class="s2">"/sbin/ifconfig e1a_overlay delete"</span>
</code></pre></div></div>

<p>Moving on to the jail configuration, we define several environment variables that specify the configuration for our jail. The <code class="language-plaintext highlighter-rouge">jail_overlay_hostname</code> specifies the hostname of the jail, while <code class="language-plaintext highlighter-rouge">jail_overlay_ip</code> is left empty because we use VNET to assign an IP address to the jail. We specify the root directory for the jail, as well as the startup and shutdown scripts. We enable various filesystems and attach the jail to a ZFS dataset. We also enable the VNET feature and specify the interfaces that the jail uses.</p>

<hr />

<h2 id="jail-ocservconf">(Jail) ocserv.conf</h2>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>auth <span class="o">=</span> <span class="s2">"plain[passwd=/usr/local/etc/ocserv/auth.passwd]"</span>
listen-host <span class="o">=</span> 172.31.87.2
udp-listen-host <span class="o">=</span> 172.31.87.2
tcp-port <span class="o">=</span> 1435
udp-port <span class="o">=</span> 1435
run-as-user <span class="o">=</span> _ocserv
run-as-group <span class="o">=</span> _ocserv
socket-file <span class="o">=</span> /var/run/ocserv-socket
server-cert <span class="o">=</span> /usr/local/etc/ocserv/fullchain.pem
server-key <span class="o">=</span> /usr/local/etc/ocserv/privkey.pem
dh-params <span class="o">=</span> /usr/local/etc/ocserv/dh.pem
ca-cert <span class="o">=</span> /usr/local/etc/ocserv/ca.pem
banner <span class="o">=</span> <span class="s2">"It's Pouria, Welcome. All Clients Have 2 Concurrent Limitation."</span>
max-clients <span class="o">=</span> 32
max-same-clients <span class="o">=</span> 2
rate-limit-ms <span class="o">=</span> 100
server-stats-reset-time <span class="o">=</span> 604800
keepalive <span class="o">=</span> 32400
dpd <span class="o">=</span> 90
mobile-dpd <span class="o">=</span> 1800
switch-to-tcp-timeout <span class="o">=</span> 25
try-mtu-discovery <span class="o">=</span> <span class="nb">true
</span>cert-user-oid <span class="o">=</span> 0.9.2342.19200300.100.1.1
tls-priorities <span class="o">=</span> <span class="s2">"NORMAL:%SERVER_PRECEDENCE:%COMPAT:-VERS-SSL3.0:-VERS-TLS1.0:-VERS-TLS1.1"</span>
auth-timeout <span class="o">=</span> 240
min-reauth-time <span class="o">=</span> 300
max-ban-score <span class="o">=</span> 80
ban-reset-time <span class="o">=</span> 1200
cookie-timeout <span class="o">=</span> 300
deny-roaming <span class="o">=</span> <span class="nb">false
</span>rekey-time <span class="o">=</span> 172800
rekey-method <span class="o">=</span> ssl
use-occtl <span class="o">=</span> <span class="nb">true
</span>pid-file <span class="o">=</span> /var/run/ocserv.pid
log-level <span class="o">=</span> 1
device <span class="o">=</span> tun
predictable-ips <span class="o">=</span> <span class="nb">true
</span>default-domain <span class="o">=</span> overlay.spmzt.net
ipv4-network <span class="o">=</span> 172.31.5.0
ipv4-netmask <span class="o">=</span> 255.255.255.0
tunnel-all-dns <span class="o">=</span> <span class="nb">true
</span>dns <span class="o">=</span> 9.9.9.9
dns <span class="o">=</span> 1.1.1.1
ping-leases <span class="o">=</span> <span class="nb">false
</span>route <span class="o">=</span> default
cisco-client-compat <span class="o">=</span> <span class="nb">true
</span>dtls-legacy <span class="o">=</span> <span class="nb">true
</span>client-bypass-protocol <span class="o">=</span> <span class="nb">false</span>
</code></pre></div></div>

<p>I also have a jail, which has two interfaces, <code class="language-plaintext highlighter-rouge">e0b_overlay</code> and <code class="language-plaintext highlighter-rouge">e1b_overlay</code>, with IP addresses <code class="language-plaintext highlighter-rouge">172.31.87.2/30</code> and <code class="language-plaintext highlighter-rouge">172.31.88.2/30</code>, respectively. This jail serves as an ocserv server, and all clients of ocserv have IP addresses in the range <code class="language-plaintext highlighter-rouge">172.31.5.0/24</code>.</p>

<p>We take a look at the <code class="language-plaintext highlighter-rouge">ocserv.conf</code> file, which specifies the configuration for the ocserv server. Here, we define the authentication method and the port numbers for the TCP and UDP protocols. We also specify the server certificate and key, the Diffie-Hellman parameters, and the CA certificate.</p>

<hr />

<h2 id="pfconf">pf.conf</h2>

<pre><code class="language-pf">set skip on { lo0 }

scrub in on vtnet0 all

nat pass on vtnet0 from 172.31.5.0/24 to any -&gt; 1.1.1.2
nat pass on vtnet0 from 172.31.87.0/30 to any -&gt; 1.1.1.2

nat pass on tun257 from 172.31.5.0/24 to any rtable 1 -&gt; ( tun257 )
nat pass on tun257 from 172.31.88.0/30 to any rtable 1 -&gt; ( tun257 )

rdr pass on vtnet0 inet proto tcp from any to 1.1.1.2 port = 1435 -&gt; 172.31.87.2
rdr pass on vtnet0 inet proto udp from any to 1.1.1.2 port = 1435 -&gt; 172.31.87.2

antispoof quick for vtnet0

block all

pass out on vtnet0 all
pass out on vtnet0 all rtable 1

pass log on e0a_overlay
pass log on e1a_overlay rtable 1

pass on tun257 all rtable 1
pass in on vtnet0 all
</code></pre>

<p>This is a configuration file for pf (Packet Filter), a firewall software for OpenBSD and other BSD-based operating systems.</p>

<p>The first line skips the firewall rules for the loopback interface.</p>

<p>The “scrub” line enables packet scrubbing on the “vtnet0” interface, which helps prevent certain types of attacks.</p>

<p>The next two “nat” lines perform network address translation (NAT) on traffic going out of the “vtnet0” interface, translating the source IP addresses from either the 172.31.5.0/24 or 172.31.87.0/30 network to 1.1.1.2.</p>

<p>The two “nat” lines that follow perform similar NAT functions for traffic going out of the “tun257” interface.</p>

<p>The two “rdr” lines redirect incoming TCP and UDP traffic destined for 1.1.1.2 on the “vtnet0” interface to 172.31.87.2.</p>

<p>The “antispoof” line enables antispoofing for the “vtnet0” interface, which helps prevent IP spoofing attacks.</p>

<p>The “block all” line blocks all traffic that is not specifically allowed by other rules.</p>

<p>The “pass out” lines allow all outgoing traffic on the “vtnet0” interface and also allow traffic from that interface with an associated routing table called “rtable 1”.</p>

<p>The two “pass log” lines allow traffic through two overlay interfaces called “e0a_overlay” and “e1a_overlay”, respectively.</p>

<p>The last two lines allow all traffic on the “tun257” interface and allow all incoming traffic on the “vtnet0” interface.</p>

<hr />

<p>In the <code class="language-plaintext highlighter-rouge">sysctl.conf</code> file, we set <code class="language-plaintext highlighter-rouge">net.add_addr_allfibs</code> to 1.</p>

<h2 id="sysctlconf">sysctl.conf</h2>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>net.add_addr_allfibs<span class="o">=</span>1
net.fibs<span class="o">=</span>2
</code></pre></div></div>

<h3 id="apply-sysctl-configurations">Apply sysctl configurations</h3>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sysctl <span class="nt">-f</span> /etc/sysctl.conf
</code></pre></div></div>

<hr />

<h2 id="etcdevfsrules">/etc/devfs.rules</h2>

<pre><code class="language-devfs">[devfsrules_jail_vnet_tun=6]
add include $devfsrules_hide_all
add include $devfsrules_unhide_basic
add include $devfsrules_unhide_login
add include $devfsrules_jail
add include $devfsrules_jail_vnet
add path 'tun*' unhide
</code></pre>

<p>The code you provided is a configuration file for <code class="language-plaintext highlighter-rouge">devfs</code>, which is the device file system used in FreeBSD operating system. The file is called <code class="language-plaintext highlighter-rouge">devfs.conf</code> and it contains a set of rules that specify how devices are accessed and managed.</p>

<p>The first line in the file sets the rule for a jail that has Virtual Network Interface Card (VNET) and a Tunnel interface (TUN) with the number 6. The following lines include other rules that hide or unhide various types of devices, such as basic devices, login devices, and jail devices. The final line in the file specifies that any device path that starts with “tun” should be unhidden, meaning it can be accessed by the jail.</p>

<p>Overall, this configuration allows me to maintain a secure and reliable network, with multiple FIBs and a jail that serves as an ocserv server. I hope this breakdown of my configuration has been helpful to you.</p>]]></content><author><name>Seyed Pouria Mousavizadeh Tehrani</name><email>info@spmzt.net</email></author><category term="FreeBSD" /><category term="VPN" /><category term="Openconnect" /><category term="FIB" /><category term="VNET" /><summary type="html"><![CDATA[Have you ever found yourself unable to connect to specific VPNs due to firewalls or censorship devices that block your connection to outside networks? It can be frustrating, but there’s a solution: routing your traffic through a trusted network that you can access.]]></summary></entry><entry><title type="html">How to Migrate Your FreeBSD System to Another Disk Using ZFS on Root and GELI Full Disk Encryption</title><link href="http://spmzt.net/2023/04/12/GELI_ZFSOnRoot/" rel="alternate" type="text/html" title="How to Migrate Your FreeBSD System to Another Disk Using ZFS on Root and GELI Full Disk Encryption" /><published>2023-04-12T21:08:00+03:30</published><updated>2023-04-12T21:08:00+03:30</updated><id>http://spmzt.net/2023/04/12/GELI_ZFSOnRoot</id><content type="html" xml:base="http://spmzt.net/2023/04/12/GELI_ZFSOnRoot/"><![CDATA[<p>Migrating a FreeBSD system to a new disk while using ZFS on root and GELI full disk encryption can be a complex process. However, with the right approach and a thorough understanding of the steps involved, it can be accomplished without data loss. In this post, we will provide a step-by-step guide on how to migrate your FreeBSD system to a new disk using ZFS on root and GELI full disk encryption.</p>

<p>In this case, I will move my entire operating system from <code class="language-plaintext highlighter-rouge">ada0</code> to <code class="language-plaintext highlighter-rouge">nvd0</code>.</p>

<h2 id="setup-disk">Setup Disk</h2>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gpart create <span class="nt">-s</span> gpt nvd0
gpart add <span class="nt">-a</span> 1M <span class="nt">-s</span> 260M <span class="nt">-t</span> efi <span class="nt">-l</span> efiboot1 nvd0
gpart add <span class="nt">-a</span> 1M <span class="nt">-s</span> 4G <span class="nt">-t</span> freebsd-swap <span class="nt">-l</span> swap1 nvd0
gpart add <span class="nt">-t</span> freebsd-zfs <span class="nt">-l</span> zfsroot1 nvd0
</code></pre></div></div>

<p>The first command, <code class="language-plaintext highlighter-rouge">gpart create -s gpt nvd0</code>, creates a new partition table of type GPT (GUID Partition Table) on the disk identified as nvd0.</p>

<p>The next three commands add partitions to the newly created partition table on the nvd0 disk.</p>

<p>The command <code class="language-plaintext highlighter-rouge">gpart add -a 1M -s 260M -t efi -l efiboot1 nvd0</code> adds a partition for EFI system, with a size of 260 megabytes and a label of <code class="language-plaintext highlighter-rouge">efiboot1</code>.</p>

<p>The command <code class="language-plaintext highlighter-rouge">gpart add -a 1M -s 4G -t freebsd-swap -l swap1 nvd0</code> adds a partition for swap space, with a size of 4 gigabytes and a label of <code class="language-plaintext highlighter-rouge">swap1</code>.</p>

<p>The command <code class="language-plaintext highlighter-rouge">gpart add -t freebsd-zfs -l zfsroot1 nvd0</code> adds a partition for ZFS (Zettabyte File System) and labels it <code class="language-plaintext highlighter-rouge">zfsroot1</code>.</p>

<h3 id="verify">Verify</h3>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gpart show <span class="nt">-p</span> nvd0
</code></pre></div></div>

<h2 id="setup-efi-partition">Setup EFI Partition</h2>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>newfs_msdos <span class="nt">-F32</span> <span class="nt">-c</span> 1 /dev/nvd0p1
mount <span class="nt">-t</span> msdosfs <span class="nt">-o</span> longnames /dev/nvd0p1 /mnt/
<span class="nb">mkdir</span> <span class="nt">-p</span> /mnt/EFI/BOOT
<span class="nb">cp</span> /boot/loader.efi /mnt/EFI/BOOT/BOOTX64.efi
umount /mnt/
</code></pre></div></div>

<p>The commands are used to format and mount an EFI System Partition (ESP) on a storage device <code class="language-plaintext highlighter-rouge">/dev/nvd0</code> in the msdos file system format.</p>

<p>The first command <code class="language-plaintext highlighter-rouge">newfs_msdos</code> creates a new file system on the first partition <code class="language-plaintext highlighter-rouge">/dev/nvd0p1</code> with the <code class="language-plaintext highlighter-rouge">-F32</code> flag indicating to use the FAT32 file system, and the <code class="language-plaintext highlighter-rouge">-c 1</code> flag indicates to set the cluster size to 1 sector.</p>

<p>The second command mount mounts the newly formatted partition on the mount point <code class="language-plaintext highlighter-rouge">/mnt</code> with the <code class="language-plaintext highlighter-rouge">-t msdosfs</code> flag indicating that the file system is <code class="language-plaintext highlighter-rouge">msdosfs and the -o longnames</code> flag enabling long file name support.</p>

<p>The third command creates the directory <code class="language-plaintext highlighter-rouge">/mnt/EFI/BOOT</code> with <code class="language-plaintext highlighter-rouge">sudo mkdir -p</code> to create the necessary folder structure for the EFI boot loader.</p>

<p>The fourth command copies the EFI boot loader <code class="language-plaintext highlighter-rouge">loader.efi</code> to <code class="language-plaintext highlighter-rouge">/mnt/EFI/BOOT/BOOTX64.efi</code> with <code class="language-plaintext highlighter-rouge">sudo cp</code> to make it available for booting.</p>

<p>The fifth and final command umount unmounts the partition at <code class="language-plaintext highlighter-rouge">/mnt</code>.</p>

<h2 id="setup-geli">Setup GELI</h2>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>geli init <span class="nt">-b</span> <span class="nt">-g</span> <span class="nt">-K</span> /root/nvd0p3.key <span class="nt">-s</span> 4096 <span class="nt">-l</span> 256 /dev/nvd0p3
</code></pre></div></div>

<p>This is a command that initializes encryption using GELI (FreeBSD’s cryptographic disk encryption system) on the device <code class="language-plaintext highlighter-rouge">/dev/nvd0p3</code>.</p>

<p>The command uses several options:</p>

<p><code class="language-plaintext highlighter-rouge">-b</code> creates a bootable GELI partition.</p>

<p><code class="language-plaintext highlighter-rouge">-g</code> Enable booting from this encrypted root filesystem.</p>

<p><code class="language-plaintext highlighter-rouge">-K /root/nvd0p3.key</code> specifies a key file to export for the encryption.</p>

<p><code class="language-plaintext highlighter-rouge">-s 4096</code> sets the sector size for the encrypted partition to 4096 bytes.</p>

<p><code class="language-plaintext highlighter-rouge">-l 256</code> sets the number of PBKDF2 iterations to use for key derivation.</p>

<p>Once the command is run, the system prompts the user to enter a passphrase to encrypt the partition. The encrypted partition can then be used like any other disk partition.</p>

<h2 id="backup-metadata-and-keys">Backup Metadata and Keys</h2>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cp</span> <span class="nt">-R</span> /var/backups/nvd0p3.eli /root/nvd0p3.key /media/da0p1/
</code></pre></div></div>

<h2 id="remove-geliboot-flag-from-old-disk">Remove GELIBOOT Flag From Old Disk</h2>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>geli configure <span class="nt">-G</span> /dev/ada0p3
</code></pre></div></div>

<h2 id="attach">Attach</h2>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>geli attach <span class="nt">-k</span> /root/keys/nvd0p3.key /dev/nvd0p3
</code></pre></div></div>

<h3 id="setup-zfs">Setup ZFS</h3>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>zpool attach zroot /dev/ada0p3.eli /dev/nvd0p3.eli
</code></pre></div></div>

<h2 id="zpool-status">ZPool Status</h2>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>zpool status zroot
</code></pre></div></div>

<h2 id="remove-old-disk">Remove Old Disk</h2>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>zpool detach zroot /dev/ada0p3.eli
</code></pre></div></div>]]></content><author><name>Seyed Pouria Mousavizadeh Tehrani</name><email>info@spmzt.net</email></author><category term="FreeBSD" /><category term="GELI" /><category term="ZFS" /><summary type="html"><![CDATA[Migrating a FreeBSD system to a new disk while using ZFS on root and GELI full disk encryption can be a complex process. However, with the right approach and a thorough understanding of the steps involved, it can be accomplished without data loss. In this post, we will provide a step-by-step guide on how to migrate your FreeBSD system to a new disk using ZFS on root and GELI full disk encryption.]]></summary></entry><entry><title type="html">A Step-by-Step Guide to Adding FIBs to FreeBSD for Improved Routing Flexibility</title><link href="http://spmzt.net/2023/04/12/FreeBSD-Fibs/" rel="alternate" type="text/html" title="A Step-by-Step Guide to Adding FIBs to FreeBSD for Improved Routing Flexibility" /><published>2023-04-12T20:38:00+03:30</published><updated>2023-04-12T20:38:00+03:30</updated><id>http://spmzt.net/2023/04/12/FreeBSD-Fibs</id><content type="html" xml:base="http://spmzt.net/2023/04/12/FreeBSD-Fibs/"><![CDATA[<p>FreeBSD is a powerful and flexible operating system that allows for advanced network routing configurations. One way to enhance this capability is by using Forwarding Information Bases (FIBs), which enable administrators to segregate network traffic and apply different routing rules to specific subsets of traffic. In this post, we will walk you through the process of adding FIBs to your FreeBSD system.</p>

<h2 id="add-fib">Add FIB</h2>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sysctl net.fibs<span class="o">=</span>2
setfib 1 route add default 172.16.1.1
</code></pre></div></div>

<h2 id="make-it-persistent">Make it Persistent</h2>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">echo</span> <span class="s1">'net.fibs=2'</span> <span class="o">&gt;&gt;</span> /etc/sysctl.conf
</code></pre></div></div>

<h2 id="jails">Jails</h2>

<p>add in <code class="language-plaintext highlighter-rouge">jail.conf</code>:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>exec.fib<span class="o">=</span>1<span class="p">;</span>
</code></pre></div></div>

<h2 id="change-interface-fib">Change Interface FIB</h2>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ifconfig lo1 fib 1
</code></pre></div></div>

<h2 id="add-connected-routes-to-allfibs">Add Connected Routes To allfibs</h2>

<p>The allfibs line is needed for FreeBSD 12+.</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">echo</span> <span class="s1">'net.add_addr_allfibs=0'</span> <span class="o">&gt;&gt;</span> /boot/loader.conf
</code></pre></div></div>]]></content><author><name>Seyed Pouria Mousavizadeh Tehrani</name><email>info@spmzt.net</email></author><category term="FreeBSD" /><category term="Fib" /><summary type="html"><![CDATA[FreeBSD is a powerful and flexible operating system that allows for advanced network routing configurations. One way to enhance this capability is by using Forwarding Information Bases (FIBs), which enable administrators to segregate network traffic and apply different routing rules to specific subsets of traffic. In this post, we will walk you through the process of adding FIBs to your FreeBSD system.]]></summary></entry><entry><title type="html">How to Automount NTFS, EXT4, and FAT File Systems on FreeBSD and Allow Non-Root User Access</title><link href="http://spmzt.net/2023/04/12/FreeBSD-Automount/" rel="alternate" type="text/html" title="How to Automount NTFS, EXT4, and FAT File Systems on FreeBSD and Allow Non-Root User Access" /><published>2023-04-12T20:26:00+03:30</published><updated>2023-04-12T20:26:00+03:30</updated><id>http://spmzt.net/2023/04/12/FreeBSD-Automount</id><content type="html" xml:base="http://spmzt.net/2023/04/12/FreeBSD-Automount/"><![CDATA[<p>FreeBSD is a robust and versatile operating system that can be used to access a wide range of file systems, including NTFS, EXT4, and FAT. While FreeBSD has built-in support for these file systems, automounting them and granting non-root users access can be a challenge. In this post, we will provide a step-by-step guide on how to automount these file systems on FreeBSD and enable non-root users to access them.</p>

<h2 id="setup-mount">Setup Mount</h2>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pkg <span class="nb">install</span> <span class="nt">-y</span> fusefs-exfat fusefs-ext2 fusefs-ntfs exfat-utils
<span class="nb">echo</span> <span class="s1">'vfs.usermount=1'</span> | <span class="nb">tee</span> <span class="nt">-a</span> /etc/sysctl.conf
sysctl vfs.usermount<span class="o">=</span>1
sysrc <span class="nv">devfs_system_ruleset</span><span class="o">=</span><span class="s2">"localrules"</span>
sysrc kld_list+<span class="o">=</span><span class="s2">"fusefs"</span>
</code></pre></div></div>

<p>Add these lines to <code class="language-plaintext highlighter-rouge">/etc/devfs.conf</code>:</p>

<pre><code class="language-devfs">[localrules=5]
add path 'da[1-3]p*' mode 0660 group operator
</code></pre>

<p>Done:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mount <span class="nt">-t</span> msdosfs <span class="nt">-o</span> <span class="nt">-m</span><span class="o">=</span>644,-M<span class="o">=</span>755 /dev/da1p1 /media
</code></pre></div></div>

<h2 id="automount">Automount</h2>

<p>USB devices can be automatically mounted by uncommenting this line below in <code class="language-plaintext highlighter-rouge">/etc/auto_master</code>:</p>

<pre><code class="language-auto_master">/media  -media  -nosuid
</code></pre>

<p>Edit `/etc/devd.conf</p>

<pre><code class="language-devd">notify 100 {
 match "system" "GEOM";
 match "subsystem" "DEV";
 action "/usr/sbin/automount -c";
};
</code></pre>

<p>And:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sysrc <span class="nv">autofs_enable</span><span class="o">=</span><span class="s2">"YES"</span>
service automount restart
service automountd restart
service autounmountd restart
service devd restart
</code></pre></div></div>

<h3 id="more-to-read">More to read</h3>

<p><a href="https://kflu.github.io/2018/02/03/2018-02-03-freebsd-ntfs/">ntfs</a></p>

<h2 id="or-use-dsb">or Use DSB</h2>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pkg <span class="nb">install</span> <span class="nt">-y</span> dsbmc dsbmc-cli
sysrc <span class="nv">dsbmd_enable</span><span class="o">=</span>YES
service dsbmd start
</code></pre></div></div>

<p>Mount:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dsbmc-cli <span class="nt">-m</span> /dev/da0s1
</code></pre></div></div>]]></content><author><name>Seyed Pouria Mousavizadeh Tehrani</name><email>info@spmzt.net</email></author><category term="FreeBSD" /><category term="mount" /><summary type="html"><![CDATA[FreeBSD is a robust and versatile operating system that can be used to access a wide range of file systems, including NTFS, EXT4, and FAT. While FreeBSD has built-in support for these file systems, automounting them and granting non-root users access can be a challenge. In this post, we will provide a step-by-step guide on how to automount these file systems on FreeBSD and enable non-root users to access them.]]></summary></entry></feed>