include IPv4 Option padding and type packing/unpacking
This commit is contained in:
parent
e48754ae4b
commit
cd5570d34b
15
.githooks/pre-commit/02-gofmt
Executable file
15
.githooks/pre-commit/02-gofmt
Executable file
@ -0,0 +1,15 @@
|
||||
#!/bin/bash
|
||||
|
||||
srcdir="${PWD}/examples"
|
||||
|
||||
if ! command -v gofmt &> /dev/null;
|
||||
then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
for f in $(find ${srcdir} -type f -iname "*.go");
|
||||
do
|
||||
gofmt -w "${f}"
|
||||
git add "${f}"
|
||||
done
|
||||
echo "Reformatted examples"
|
75
README.adoc
75
README.adoc
@ -270,7 +270,7 @@ A flag's presence can be checked via a bit-wise `AND` against _flag_ being equal
|
||||
[%collapsible]
|
||||
.Example in Go
|
||||
=====
|
||||
.`hasflag.go`
|
||||
.`examples/hasflag.go`
|
||||
[source,go]
|
||||
----
|
||||
include::examples/hasflag.go[]
|
||||
@ -390,7 +390,7 @@ IP:P:: <<spec_bcast_protonum, IP/Transport Protocol Number>> _(1 Byte)_
|
||||
IP:C:: Header Checksum (RFC https://datatracker.ietf.org/doc/html/rfc1071[1071^], https://datatracker.ietf.org/doc/html/rfc1071[1141^], https://datatracker.ietf.org/doc/html/rfc1624[1624^]) _(2 Bytes)_
|
||||
IP:S:: Source IPv4 Address _(32 Bits/4 Bytes)_
|
||||
IP:D:: Destination IPv4 Address _(32 Bits/4 Bytes)_
|
||||
IP:O:: Options (Optional) (See the https://www.iana.org/assignments/ip-parameters/ip-parameters.xhtml[IANA Registered IP Parameters^] for details) _(Variable Length)_
|
||||
IP:O:: Options + Null Padding (Optional) _(Variable Length, see <<xtra_pad_v4opts,Addendum>>)_
|
||||
|
||||
[id="spec_bcast_v6"]
|
||||
==== IPv6
|
||||
@ -541,6 +541,7 @@ To *retrieve* the Version and IHL, the value is bit-shifted to the *right* by 4
|
||||
[%collapsible]
|
||||
.Example in Go
|
||||
====
|
||||
.`examples/vihl.go`
|
||||
[source,go]
|
||||
----
|
||||
include::examples/vihl.go[]
|
||||
@ -571,6 +572,7 @@ Notable ECN mentions are:
|
||||
[%collapsible]
|
||||
.Example in Go
|
||||
====
|
||||
.`examples/de.go`
|
||||
[source,go]
|
||||
----
|
||||
include::examples/de.go[]
|
||||
@ -586,12 +588,31 @@ The Fragmentation Flags and Offset are defined in https://datatracker.ietf.org/d
|
||||
[%collapsible]
|
||||
.Example in Go
|
||||
====
|
||||
.`examples/frag.go`
|
||||
[source,go]
|
||||
----
|
||||
include::examples/frag.go[]
|
||||
----
|
||||
====
|
||||
|
||||
[id="xtra_bitpacked_ip4opt_t"]
|
||||
==== IPv4 Option Type
|
||||
The *Type* field of an <<xtra_pad_v4opts,IPv4 option>> is a single byte that consists of:
|
||||
|
||||
* A "Copy" flag _(1 Bit)_
|
||||
* A "Class" flag _(2 Bits)_
|
||||
* An Option "Number" _(5 Bits)_
|
||||
|
||||
[%collapsible]
|
||||
.Example in Go
|
||||
====
|
||||
.`examples/v4optstype.go`
|
||||
[source,go]
|
||||
----
|
||||
include::examples/v4optstype.go[]
|
||||
----
|
||||
====
|
||||
|
||||
[id="xtra_bitpacked_vtf"]
|
||||
==== IP Version, Traffic Class, Flow Label (IPv6)
|
||||
IPv6 thankfully only has one bitpacking in the header. Unfortunately, it's a triple-whammy.
|
||||
@ -607,8 +628,58 @@ The IP Version takes up 4 bits (just as in IPv4, except it will always be `6` th
|
||||
[%collapsible]
|
||||
.Example in Go
|
||||
====
|
||||
.`examples/vtf.go`
|
||||
[source,go]
|
||||
----
|
||||
include::examples/vtf.go[]
|
||||
----
|
||||
====
|
||||
|
||||
|
||||
[id="xtra_pad"]
|
||||
=== Padded Fields
|
||||
|
||||
[id="xtra_pad_v4opts"]
|
||||
==== IPv4 Options
|
||||
The IPv4 options, if specified, *must* align to a 32-bit/4-byte multiple size.
|
||||
(In other words, its total length of bytes *must* be cleanly divisible by 4;
|
||||
or said another way its total length of bits must be cleanly divisible by 32).
|
||||
|
||||
It uses null-byte (`0x00`) padding to achieve this.
|
||||
|
||||
[%collapsible]
|
||||
.Example in Go
|
||||
====
|
||||
.`examples/v4optspad.go`
|
||||
[source,go]
|
||||
----
|
||||
include::examples/v4optspad.go[]
|
||||
----
|
||||
====
|
||||
|
||||
For more extensive details, see https://datatracker.ietf.org/doc/html/rfc791#section-3.1[RFC 791 § 3.1^]
|
||||
and the https://www.iana.org/assignments/ip-parameters/ip-parameters.xhtml[IANA Registered IP Paramaeters^]
|
||||
(the *Value* column is what should be used as the *Type*, see <<xtra_bitpacked_ip4opt_t>>.
|
||||
|
||||
Each option (with two exceptions) is a TLV (<<xtra_pad_v4opts_t,type>> / <<xtra_pad_v4opts_l,length>> / <<xtra_pad_v4opts_v,value>>) structured field.
|
||||
|
||||
The two exceptions for the above are `EOOL` (`0x00`) and `NOP` (`0x01`), both of which occupy only a single byte -- they are *unvalued*, so they have no length or value field.
|
||||
|
||||
[id="xtra_pad_v4opts_t"]
|
||||
===== Type
|
||||
See <<xtra_bitpacked_ip4opt_t>> for details.
|
||||
|
||||
[id="xtra_pad_v4opts_l"]
|
||||
===== Length
|
||||
The *Length* is the length of this _entire_ option as an 8-bit unsigned integer.
|
||||
|
||||
In other words it includes the length of the <<xtra_pad_v4opts_t>> field, the <<xtra_pad_v4opts_l>> field (this field),
|
||||
*and* the <<xtra_pad_v4opts_v>> field together.
|
||||
|
||||
This is not present for `EOOL` (`0x00`) and `NOP` (`0x01`) (or any other "non-valued" options).
|
||||
|
||||
[id="xtra_pad_v4opts_v"]
|
||||
===== Value
|
||||
Value is the option's value. Its <<xtra_pad_v4opts_l>> is variable depending on the <<xtra_pad_v4opts_t>>.
|
||||
|
||||
This is not present for `EOOL` (`0x00`) and `NOP` (`0x01`) (or any other "non-valued" options).
|
||||
|
320
README.html
320
README.html
@ -559,7 +559,7 @@ pre.rouge .gs {
|
||||
<div class="details">
|
||||
<span id="author" class="author">Brent Saner</span><br>
|
||||
<span id="email" class="email"><a href="mailto:bts@square-r00t.net">bts@square-r00t.net</a></span><br>
|
||||
<span id="revdate">Last rendered 2025-08-30 17:05:09 -0400</span>
|
||||
<span id="revdate">Last rendered 2025-08-31 00:29:24 -0400</span>
|
||||
</div>
|
||||
<div id="toc" class="toc2">
|
||||
<div id="toctitle">Table of Contents</div>
|
||||
@ -625,7 +625,19 @@ pre.rouge .gs {
|
||||
<li><a href="#xtra_bitpacked_vihl">8.1.1. IP Version, IHL (IPv4)</a></li>
|
||||
<li><a href="#xtra_bitpacked_de">8.1.2. DSCP, ECN (IPv4)</a></li>
|
||||
<li><a href="#xtra_bitpacked_frag">8.1.3. Flags, Fragmentation Offset (IPv4)</a></li>
|
||||
<li><a href="#xtra_bitpacked_vtf">8.1.4. IP Version, Traffic Class, Flow Label (IPv6)</a></li>
|
||||
<li><a href="#xtra_bitpacked_ip4opt_t">8.1.4. IPv4 Option Type</a></li>
|
||||
<li><a href="#xtra_bitpacked_vtf">8.1.5. IP Version, Traffic Class, Flow Label (IPv6)</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#xtra_pad">8.2. Padded Fields</a>
|
||||
<ul class="sectlevel3">
|
||||
<li><a href="#xtra_pad_v4opts">8.2.1. IPv4 Options</a>
|
||||
<ul class="sectlevel4">
|
||||
<li><a href="#xtra_pad_v4opts_t">8.2.1.1. Type</a></li>
|
||||
<li><a href="#xtra_pad_v4opts_l">8.2.1.2. Length</a></li>
|
||||
<li><a href="#xtra_pad_v4opts_v">8.2.1.3. Value</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
@ -1700,7 +1712,7 @@ If using the online version, <em>Part I-2</em> is summarized/starts <a href="htt
|
||||
<summary class="title">Example in Go</summary>
|
||||
<div class="content">
|
||||
<div class="listingblock">
|
||||
<div class="title"><code>hasflag.go</code></div>
|
||||
<div class="title"><code>examples/hasflag.go</code></div>
|
||||
<div class="content">
|
||||
<pre class="rouge highlight"><code data-lang="go"><span class="k">package</span> <span class="n">main</span>
|
||||
|
||||
@ -2079,7 +2091,7 @@ Its source <em>must</em> be the MAC/PHYS address of the network interface it is
|
||||
</dd>
|
||||
<dt class="hdlist1">IP:O</dt>
|
||||
<dd>
|
||||
<p>Options (Optional) (See the <a href="https://www.iana.org/assignments/ip-parameters/ip-parameters.xhtml" target="_blank" rel="noopener">IANA Registered IP Parameters</a> for details) <em>(Variable Length)</em></p>
|
||||
<p>Options + Null Padding (Optional) <em>(Variable Length, see <a href="#xtra_pad_v4opts">Addendum</a>)</em></p>
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
@ -2439,12 +2451,13 @@ IPv6 does not require a header checksum.</p>
|
||||
<summary class="title">Example in Go</summary>
|
||||
<div class="content">
|
||||
<div class="listingblock">
|
||||
<div class="title"><code>examples/vihl.go</code></div>
|
||||
<div class="content">
|
||||
<pre class="rouge highlight"><code data-lang="go"><span class="k">package</span> <span class="n">main</span>
|
||||
|
||||
<span class="k">import</span> <span class="p">(</span>
|
||||
<span class="s">`fmt`</span>
|
||||
<span class="s">`log`</span>
|
||||
<span class="s">"fmt"</span>
|
||||
<span class="s">"log"</span>
|
||||
<span class="s">"strconv"</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
@ -2573,12 +2586,13 @@ IPv6 does not require a header checksum.</p>
|
||||
<summary class="title">Example in Go</summary>
|
||||
<div class="content">
|
||||
<div class="listingblock">
|
||||
<div class="title"><code>examples/de.go</code></div>
|
||||
<div class="content">
|
||||
<pre class="rouge highlight"><code data-lang="go"><span class="k">package</span> <span class="n">main</span>
|
||||
|
||||
<span class="k">import</span> <span class="p">(</span>
|
||||
<span class="s">`fmt`</span>
|
||||
<span class="s">`log`</span>
|
||||
<span class="s">"fmt"</span>
|
||||
<span class="s">"log"</span>
|
||||
<span class="s">"strconv"</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
@ -2665,12 +2679,13 @@ IPv6 does not require a header checksum.</p>
|
||||
<summary class="title">Example in Go</summary>
|
||||
<div class="content">
|
||||
<div class="listingblock">
|
||||
<div class="title"><code>examples/frag.go</code></div>
|
||||
<div class="content">
|
||||
<pre class="rouge highlight"><code data-lang="go"><span class="k">package</span> <span class="n">main</span>
|
||||
|
||||
<span class="k">import</span> <span class="p">(</span>
|
||||
<span class="s">`fmt`</span>
|
||||
<span class="s">`log`</span>
|
||||
<span class="s">"fmt"</span>
|
||||
<span class="s">"log"</span>
|
||||
<span class="s">"strconv"</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
@ -2747,7 +2762,147 @@ IPv6 does not require a header checksum.</p>
|
||||
</details>
|
||||
</div>
|
||||
<div class="sect3">
|
||||
<h4 id="xtra_bitpacked_vtf"><a class="link" href="#xtra_bitpacked_vtf">8.1.4. IP Version, Traffic Class, Flow Label (IPv6)</a></h4>
|
||||
<h4 id="xtra_bitpacked_ip4opt_t"><a class="link" href="#xtra_bitpacked_ip4opt_t">8.1.4. IPv4 Option Type</a></h4>
|
||||
<div class="paragraph">
|
||||
<p>The <strong>Type</strong> field of an <a href="#xtra_pad_v4opts">IPv4 option</a> is a single byte that consists of:</p>
|
||||
</div>
|
||||
<div class="ulist">
|
||||
<ul>
|
||||
<li>
|
||||
<p>A "Copy" flag <em>(1 Bit)</em></p>
|
||||
</li>
|
||||
<li>
|
||||
<p>A "Class" flag <em>(2 Bits)</em></p>
|
||||
</li>
|
||||
<li>
|
||||
<p>An Option "Number" <em>(5 Bits)</em></p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<details>
|
||||
<summary class="title">Example in Go</summary>
|
||||
<div class="content">
|
||||
<div class="listingblock">
|
||||
<div class="title"><code>examples/v4optstype.go</code></div>
|
||||
<div class="content">
|
||||
<pre class="rouge highlight"><code data-lang="go"><span class="k">package</span> <span class="n">main</span>
|
||||
|
||||
<span class="k">import</span> <span class="p">(</span>
|
||||
<span class="s">"fmt"</span>
|
||||
<span class="s">"log"</span>
|
||||
<span class="s">"strconv"</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
<span class="k">const</span> <span class="p">(</span>
|
||||
<span class="n">ClassControl</span> <span class="kt">uint8</span> <span class="o">=</span> <span class="no">iota</span>
|
||||
<span class="n">ClassReserved</span>
|
||||
<span class="n">ClassDebug</span>
|
||||
<span class="n">ClassReserved2</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
<span class="k">var</span> <span class="p">(</span>
|
||||
<span class="n">classStr</span> <span class="k">map</span><span class="p">[</span><span class="kt">uint8</span><span class="p">]</span><span class="kt">string</span> <span class="o">=</span> <span class="k">map</span><span class="p">[</span><span class="kt">uint8</span><span class="p">]</span><span class="kt">string</span><span class="p">{</span>
|
||||
<span class="n">ClassControl</span><span class="o">:</span> <span class="s">"Control"</span><span class="p">,</span>
|
||||
<span class="n">ClassReserved</span><span class="o">:</span> <span class="s">"Reserved (1)"</span><span class="p">,</span>
|
||||
<span class="n">ClassDebug</span><span class="o">:</span> <span class="s">"Debugging/Measurement"</span><span class="p">,</span>
|
||||
<span class="n">ClassReserved2</span><span class="o">:</span> <span class="s">"Reserved (2)"</span><span class="p">,</span>
|
||||
<span class="p">}</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
<span class="k">const</span> <span class="p">(</span>
|
||||
<span class="c">/// This is the same type from examples/v4optspad.go.</span>
|
||||
<span class="n">ip4OptTypBits</span> <span class="kt">string</span> <span class="o">=</span> <span class="s">"10010100"</span> <span class="c">// [1001 0100], or 148 (0x94)</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
<span class="k">var</span> <span class="p">(</span>
|
||||
<span class="n">v4TypCpyOffset</span> <span class="kt">uint8</span> <span class="o">=</span> <span class="m">0x80</span> <span class="c">// 128</span>
|
||||
<span class="n">v4TypCpyMask</span> <span class="kt">uint8</span> <span class="o">=</span> <span class="m">0x01</span> <span class="c">// Mask to 1 bit</span>
|
||||
<span class="n">v4TypCpyPos</span> <span class="kt">uint8</span> <span class="o">=</span> <span class="m">8</span> <span class="o">-</span> <span class="n">v4TypCpyMask</span> <span class="c">// 7 or 0x07 (8 (bits) - mask = Shifted to 7th bit)</span>
|
||||
|
||||
<span class="n">v4TypClsOffset</span> <span class="kt">uint8</span> <span class="o">=</span> <span class="m">0x60</span> <span class="c">// 96</span>
|
||||
<span class="n">v4TypClsMask</span> <span class="kt">uint8</span> <span class="o">=</span> <span class="m">0x05</span> <span class="c">// mask to 5 bits</span>
|
||||
<span class="n">v4TypClsPos</span> <span class="kt">uint8</span> <span class="o">=</span> <span class="m">8</span> <span class="o">-</span> <span class="n">v4TypClsMask</span>
|
||||
|
||||
<span class="n">v4TypNumOffset</span> <span class="kt">uint8</span> <span class="o">=</span> <span class="m">0x1f</span> <span class="c">// 31</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
<span class="k">func</span> <span class="n">ToV4OptTyp</span><span class="p">(</span><span class="n">copied</span><span class="p">,</span> <span class="n">class</span><span class="p">,</span> <span class="n">num</span> <span class="kt">uint8</span><span class="p">)</span> <span class="p">(</span><span class="n">typ</span> <span class="kt">uint8</span><span class="p">)</span> <span class="p">{</span>
|
||||
|
||||
<span class="n">typ</span> <span class="o">=</span> <span class="p">((</span><span class="n">copied</span> <span class="o">&</span> <span class="n">v4TypCpyMask</span><span class="p">)</span> <span class="o"><<</span> <span class="n">v4TypCpyPos</span><span class="p">)</span> <span class="o">|</span> <span class="p">((</span><span class="n">class</span> <span class="o">&</span> <span class="n">v4TypClsMask</span><span class="p">)</span> <span class="o"><<</span> <span class="n">v4TypClsPos</span><span class="p">)</span> <span class="o">|</span> <span class="p">(</span><span class="n">num</span> <span class="o">&</span> <span class="n">v4TypNumOffset</span><span class="p">)</span>
|
||||
|
||||
<span class="k">return</span>
|
||||
<span class="p">}</span>
|
||||
|
||||
<span class="k">func</span> <span class="n">FromV4OptTyp</span><span class="p">(</span><span class="n">typ</span> <span class="kt">uint8</span><span class="p">)</span> <span class="p">(</span><span class="n">copied</span><span class="p">,</span> <span class="n">class</span><span class="p">,</span> <span class="n">num</span> <span class="kt">uint8</span><span class="p">)</span> <span class="p">{</span>
|
||||
|
||||
<span class="n">copied</span> <span class="o">=</span> <span class="p">(</span><span class="n">typ</span> <span class="o">&</span> <span class="n">v4TypCpyOffset</span><span class="p">)</span> <span class="o">>></span> <span class="n">v4TypCpyPos</span>
|
||||
<span class="n">class</span> <span class="o">=</span> <span class="p">(</span><span class="n">typ</span> <span class="o">&</span> <span class="n">v4TypClsOffset</span><span class="p">)</span> <span class="o">>></span> <span class="n">v4TypClsPos</span>
|
||||
<span class="n">num</span> <span class="o">=</span> <span class="p">(</span><span class="n">typ</span> <span class="o">&</span> <span class="n">v4TypNumOffset</span><span class="p">)</span>
|
||||
|
||||
<span class="k">return</span>
|
||||
<span class="p">}</span>
|
||||
|
||||
<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
|
||||
|
||||
<span class="k">var</span> <span class="n">err</span> <span class="kt">error</span>
|
||||
<span class="k">var</span> <span class="n">u64</span> <span class="kt">uint64</span>
|
||||
<span class="k">var</span> <span class="n">typ</span> <span class="kt">uint8</span>
|
||||
<span class="k">var</span> <span class="n">cpd</span> <span class="kt">uint8</span>
|
||||
<span class="k">var</span> <span class="n">cls</span> <span class="kt">uint8</span>
|
||||
<span class="k">var</span> <span class="n">num</span> <span class="kt">uint8</span>
|
||||
|
||||
<span class="c">// Given a type of ip4OptTypBits (see const at top)...</span>
|
||||
<span class="k">if</span> <span class="n">u64</span><span class="p">,</span> <span class="n">err</span> <span class="o">=</span> <span class="n">strconv</span><span class="o">.</span><span class="n">ParseUint</span><span class="p">(</span><span class="n">ip4OptTypBits</span><span class="p">,</span> <span class="m">2</span><span class="p">,</span> <span class="m">8</span><span class="p">);</span> <span class="n">err</span> <span class="o">!=</span> <span class="no">nil</span> <span class="p">{</span>
|
||||
<span class="n">log</span><span class="o">.</span><span class="n">Panicln</span><span class="p">(</span><span class="n">err</span><span class="p">)</span>
|
||||
<span class="p">}</span>
|
||||
<span class="n">typ</span> <span class="o">=</span> <span class="kt">uint8</span><span class="p">(</span><span class="n">u64</span><span class="p">)</span>
|
||||
<span class="c">// Prints:</span>
|
||||
<span class="c">/*
|
||||
Type is: 148 (0x0094)
|
||||
*/</span>
|
||||
<span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"Type is:</span><span class="se">\t</span><span class="s">%d (%#04x)</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">typ</span><span class="p">,</span> <span class="n">typ</span><span class="p">)</span>
|
||||
|
||||
<span class="n">cpd</span><span class="p">,</span> <span class="n">cls</span><span class="p">,</span> <span class="n">num</span> <span class="o">=</span> <span class="n">FromV4OptTyp</span><span class="p">(</span><span class="n">typ</span><span class="p">)</span>
|
||||
<span class="c">// Prints:</span>
|
||||
<span class="c">/*
|
||||
Copied: 1 (0x0001)
|
||||
Class: 0 (0x0000)
|
||||
Number: 20 (0x0014)
|
||||
*/</span>
|
||||
<span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span>
|
||||
<span class="s">"Copied:</span><span class="se">\t\t</span><span class="s">%d %#04x)</span><span class="se">\n</span><span class="s">"</span><span class="o">+</span>
|
||||
<span class="s">"Class:</span><span class="se">\t\t</span><span class="s">%d (%#04x)</span><span class="se">\n</span><span class="s">"</span><span class="o">+</span>
|
||||
<span class="s">"Number:</span><span class="se">\t\t</span><span class="s">%d (%#04x)</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span>
|
||||
<span class="n">cpd</span><span class="p">,</span> <span class="n">cpd</span><span class="p">,</span>
|
||||
<span class="n">cls</span><span class="p">,</span> <span class="n">cls</span><span class="p">,</span>
|
||||
<span class="n">num</span><span class="p">,</span> <span class="n">num</span><span class="p">,</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
<span class="n">typ</span> <span class="o">=</span> <span class="n">ToV4OptTyp</span><span class="p">(</span><span class="n">cpd</span><span class="p">,</span> <span class="n">cls</span><span class="p">,</span> <span class="n">num</span><span class="p">)</span>
|
||||
<span class="c">// Prints:</span>
|
||||
<span class="c">/*
|
||||
Confirmed Type: 148 (0x94)
|
||||
*/</span>
|
||||
<span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"Confirmed Type:</span><span class="se">\t</span><span class="s">%d (%#02x)</span><span class="se">\n\n</span><span class="s">"</span><span class="p">,</span> <span class="n">typ</span><span class="p">,</span> <span class="n">typ</span><span class="p">)</span>
|
||||
|
||||
<span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="s">"Class Name:"</span><span class="p">)</span>
|
||||
<span class="c">// Prints:</span>
|
||||
<span class="c">/*
|
||||
Control
|
||||
*/</span>
|
||||
<span class="k">for</span> <span class="n">c</span><span class="p">,</span> <span class="n">cNm</span> <span class="o">:=</span> <span class="k">range</span> <span class="n">classStr</span> <span class="p">{</span>
|
||||
<span class="k">if</span> <span class="n">c</span> <span class="o">==</span> <span class="n">cls</span> <span class="p">{</span>
|
||||
<span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="n">cNm</span><span class="p">)</span>
|
||||
<span class="p">}</span>
|
||||
<span class="p">}</span>
|
||||
<span class="p">}</span></code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
<div class="sect3">
|
||||
<h4 id="xtra_bitpacked_vtf"><a class="link" href="#xtra_bitpacked_vtf">8.1.5. IP Version, Traffic Class, Flow Label (IPv6)</a></h4>
|
||||
<div class="paragraph">
|
||||
<p>IPv6 thankfully only has one bitpacking in the header. Unfortunately, it’s a triple-whammy.</p>
|
||||
</div>
|
||||
@ -2774,12 +2929,13 @@ IPv6 does not require a header checksum.</p>
|
||||
<summary class="title">Example in Go</summary>
|
||||
<div class="content">
|
||||
<div class="listingblock">
|
||||
<div class="title"><code>examples/vtf.go</code></div>
|
||||
<div class="content">
|
||||
<pre class="rouge highlight"><code data-lang="go"><span class="k">package</span> <span class="n">main</span>
|
||||
|
||||
<span class="k">import</span> <span class="p">(</span>
|
||||
<span class="s">`fmt`</span>
|
||||
<span class="s">`log`</span>
|
||||
<span class="s">"fmt"</span>
|
||||
<span class="s">"log"</span>
|
||||
<span class="s">"strconv"</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
@ -2866,12 +3022,148 @@ IPv6 does not require a header checksum.</p>
|
||||
</details>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="xtra_pad"><a class="link" href="#xtra_pad">8.2. Padded Fields</a></h3>
|
||||
<div class="sect3">
|
||||
<h4 id="xtra_pad_v4opts"><a class="link" href="#xtra_pad_v4opts">8.2.1. IPv4 Options</a></h4>
|
||||
<div class="paragraph">
|
||||
<p>The IPv4 options, if specified, <strong>must</strong> align to a 32-bit/4-byte multiple size.
|
||||
(In other words, its total length of bytes <strong>must</strong> be cleanly divisible by 4;
|
||||
or said another way its total length of bits must be cleanly divisible by 32).</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>It uses null-byte (<code>0x00</code>) padding to achieve this.</p>
|
||||
</div>
|
||||
<details>
|
||||
<summary class="title">Example in Go</summary>
|
||||
<div class="content">
|
||||
<div class="listingblock">
|
||||
<div class="title"><code>examples/v4optspad.go</code></div>
|
||||
<div class="content">
|
||||
<pre class="rouge highlight"><code data-lang="go"><span class="k">package</span> <span class="n">main</span>
|
||||
|
||||
<span class="k">import</span> <span class="p">(</span>
|
||||
<span class="s">"bytes"</span>
|
||||
<span class="s">"fmt"</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
<span class="k">const</span> <span class="p">(</span>
|
||||
<span class="n">padVal</span> <span class="kt">uint8</span> <span class="o">=</span> <span class="m">0x00</span> <span class="c">// Padded with NUL/null-bytes</span>
|
||||
<span class="n">alignLen</span> <span class="kt">int</span> <span class="o">=</span> <span class="m">4</span> <span class="c">// 4-Byte alignment</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
<span class="k">var</span> <span class="p">(</span>
|
||||
<span class="c">// See the examples/v4opts.go for how these bytes are constructed.</span>
|
||||
<span class="n">opts</span> <span class="p">[]</span><span class="kt">byte</span> <span class="o">=</span> <span class="p">[]</span><span class="kt">byte</span><span class="p">{</span>
|
||||
<span class="c">// This is an example.</span>
|
||||
<span class="c">// Option 1</span>
|
||||
<span class="m">0x94</span><span class="p">,</span> <span class="c">// Type 148, RTRALT (Router Alert) (RFC 2113)</span>
|
||||
<span class="m">0x04</span><span class="p">,</span> <span class="c">// Length (4 bytes)</span>
|
||||
<span class="m">0x00</span><span class="p">,</span> <span class="m">0x00</span><span class="p">,</span> <span class="c">// "Router shall examine packet"</span>
|
||||
<span class="c">// EOOL</span>
|
||||
<span class="m">0x00</span><span class="p">,</span>
|
||||
<span class="c">// Padding will go here.</span>
|
||||
<span class="p">}</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
<span class="k">func</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
|
||||
|
||||
<span class="k">var</span> <span class="n">optLen</span> <span class="kt">int</span>
|
||||
<span class="k">var</span> <span class="n">padLen</span> <span class="kt">int</span>
|
||||
<span class="k">var</span> <span class="n">pad</span> <span class="p">[]</span><span class="kt">byte</span>
|
||||
|
||||
<span class="n">optLen</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">opts</span><span class="p">)</span>
|
||||
|
||||
<span class="n">fmt</span><span class="o">.</span><span class="n">Println</span><span class="p">(</span><span class="s">"Before padding:"</span><span class="p">)</span>
|
||||
<span class="c">// Prints:</span>
|
||||
<span class="c">/*
|
||||
0x9404000000
|
||||
(Length: 5)
|
||||
*/</span>
|
||||
<span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"%#02x</span><span class="se">\n</span><span class="s">(Length: %d)</span><span class="se">\n\n</span><span class="s">"</span><span class="p">,</span> <span class="n">opts</span><span class="p">,</span> <span class="n">optLen</span><span class="p">)</span>
|
||||
|
||||
<span class="c">/*
|
||||
The remainder of the current length divided by
|
||||
alignLen (4) (modulo) is subtracted from the alignLen
|
||||
to determine how much must be added to reach the next
|
||||
"boundary". It's then modulo'd *again* to rule out
|
||||
currently being on an alignment bounary.
|
||||
*/</span>
|
||||
<span class="n">padLen</span> <span class="o">=</span> <span class="p">(</span><span class="n">alignLen</span> <span class="o">-</span> <span class="p">(</span><span class="n">optLen</span> <span class="o">%</span> <span class="n">alignLen</span><span class="p">))</span> <span class="o">%</span> <span class="n">alignLen</span>
|
||||
<span class="c">// Prints:</span>
|
||||
<span class="c">/*
|
||||
Pad length needed: 3
|
||||
*/</span>
|
||||
<span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"Pad length needed:</span><span class="se">\t</span><span class="s">%d</span><span class="se">\n\n</span><span class="s">"</span><span class="p">,</span> <span class="n">padLen</span><span class="p">)</span>
|
||||
<span class="n">pad</span> <span class="o">=</span> <span class="n">bytes</span><span class="o">.</span><span class="n">Repeat</span><span class="p">([]</span><span class="kt">byte</span><span class="p">{</span><span class="n">padVal</span><span class="p">},</span> <span class="n">padLen</span><span class="p">)</span>
|
||||
|
||||
<span class="n">opts</span> <span class="o">=</span> <span class="nb">append</span><span class="p">(</span><span class="n">opts</span><span class="p">,</span> <span class="n">pad</span><span class="o">...</span><span class="p">)</span>
|
||||
|
||||
<span class="c">// Alternatively, this can be implemented with a loop, though it's likely less efficient:</span>
|
||||
<span class="c">/*
|
||||
for len(opts) % alignLen != 0 {}
|
||||
opts = append(opts, padVal)
|
||||
}
|
||||
*/</span>
|
||||
|
||||
<span class="c">// Prints:</span>
|
||||
<span class="c">/*
|
||||
Padded:
|
||||
0x9404000000000000
|
||||
*/</span>
|
||||
<span class="n">fmt</span><span class="o">.</span><span class="n">Printf</span><span class="p">(</span><span class="s">"Padded:</span><span class="se">\n</span><span class="s">%#x</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">opts</span><span class="p">)</span>
|
||||
<span class="p">}</span></code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
<div class="paragraph">
|
||||
<p>For more extensive details, see <a href="https://datatracker.ietf.org/doc/html/rfc791#section-3.1" target="_blank" rel="noopener">RFC 791 § 3.1</a>
|
||||
and the <a href="https://www.iana.org/assignments/ip-parameters/ip-parameters.xhtml" target="_blank" rel="noopener">IANA Registered IP Paramaeters</a>
|
||||
(the <strong>Value</strong> column is what should be used as the <strong>Type</strong>, see <a href="#xtra_bitpacked_ip4opt_t">IPv4 Option Type</a>.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Each option (with two exceptions) is a TLV (<a href="#xtra_pad_v4opts_t">type</a> / <a href="#xtra_pad_v4opts_l">length</a> / <a href="#xtra_pad_v4opts_v">value</a>) structured field.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>The two exceptions for the above are <code>EOOL</code> (<code>0x00</code>) and <code>NOP</code> (<code>0x01</code>), both of which occupy only a single byte — they are <strong>unvalued</strong>, so they have no length or value field.</p>
|
||||
</div>
|
||||
<div class="sect4">
|
||||
<h5 id="xtra_pad_v4opts_t"><a class="link" href="#xtra_pad_v4opts_t">8.2.1.1. Type</a></h5>
|
||||
<div class="paragraph">
|
||||
<p>See <a href="#xtra_bitpacked_ip4opt_t">IPv4 Option Type</a> for details.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect4">
|
||||
<h5 id="xtra_pad_v4opts_l"><a class="link" href="#xtra_pad_v4opts_l">8.2.1.2. Length</a></h5>
|
||||
<div class="paragraph">
|
||||
<p>The <strong>Length</strong> is the length of this <em>entire</em> option as an 8-bit unsigned integer.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>In other words it includes the length of the <a href="#xtra_pad_v4opts_t">Type</a> field, the <a href="#xtra_pad_v4opts_l">Length</a> field (this field),
|
||||
<strong>and</strong> the <a href="#xtra_pad_v4opts_v">Value</a> field together.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>This is not present for <code>EOOL</code> (<code>0x00</code>) and <code>NOP</code> (<code>0x01</code>) (or any other "non-valued" options).</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect4">
|
||||
<h5 id="xtra_pad_v4opts_v"><a class="link" href="#xtra_pad_v4opts_v">8.2.1.3. Value</a></h5>
|
||||
<div class="paragraph">
|
||||
<p>Value is the option’s value. Its <a href="#xtra_pad_v4opts_l">Length</a> is variable depending on the <a href="#xtra_pad_v4opts_t">Type</a>.</p>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>This is not present for <code>EOOL</code> (<code>0x00</code>) and <code>NOP</code> (<code>0x01</code>) (or any other "non-valued" options).</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="footer">
|
||||
<div id="footer-text">
|
||||
Last updated 2025-08-30 16:39:39 -0400
|
||||
Last updated 2025-08-31 00:25:52 -0400
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
@ -1,8 +1,8 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
`fmt`
|
||||
`log`
|
||||
"fmt"
|
||||
"log"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
`fmt`
|
||||
`log`
|
||||
"fmt"
|
||||
"log"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
|
73
examples/v4optspad.go
Normal file
73
examples/v4optspad.go
Normal file
@ -0,0 +1,73 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
const (
|
||||
padVal uint8 = 0x00 // Padded with NUL/null-bytes
|
||||
alignLen int = 4 // 4-Byte alignment
|
||||
)
|
||||
|
||||
var (
|
||||
// See the examples/v4opts.go for how these bytes are constructed.
|
||||
opts []byte = []byte{
|
||||
// This is an example.
|
||||
// Option 1
|
||||
0x94, // Type 148, RTRALT (Router Alert) (RFC 2113)
|
||||
0x04, // Length (4 bytes)
|
||||
0x00, 0x00, // "Router shall examine packet"
|
||||
// EOOL
|
||||
0x00,
|
||||
// Padding will go here.
|
||||
}
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
var optLen int
|
||||
var padLen int
|
||||
var pad []byte
|
||||
|
||||
optLen = len(opts)
|
||||
|
||||
fmt.Println("Before padding:")
|
||||
// Prints:
|
||||
/*
|
||||
0x9404000000
|
||||
(Length: 5)
|
||||
*/
|
||||
fmt.Printf("%#02x\n(Length: %d)\n\n", opts, optLen)
|
||||
|
||||
/*
|
||||
The remainder of the current length divided by
|
||||
alignLen (4) (modulo) is subtracted from the alignLen
|
||||
to determine how much must be added to reach the next
|
||||
"boundary". It's then modulo'd *again* to rule out
|
||||
currently being on an alignment bounary.
|
||||
*/
|
||||
padLen = (alignLen - (optLen % alignLen)) % alignLen
|
||||
// Prints:
|
||||
/*
|
||||
Pad length needed: 3
|
||||
*/
|
||||
fmt.Printf("Pad length needed:\t%d\n\n", padLen)
|
||||
pad = bytes.Repeat([]byte{padVal}, padLen)
|
||||
|
||||
opts = append(opts, pad...)
|
||||
|
||||
// Alternatively, this can be implemented with a loop, though it's likely less efficient:
|
||||
/*
|
||||
for len(opts) % alignLen != 0 {}
|
||||
opts = append(opts, padVal)
|
||||
}
|
||||
*/
|
||||
|
||||
// Prints:
|
||||
/*
|
||||
Padded:
|
||||
0x9404000000000000
|
||||
*/
|
||||
fmt.Printf("Padded:\n%#x\n", opts)
|
||||
}
|
111
examples/v4optstype.go
Normal file
111
examples/v4optstype.go
Normal file
@ -0,0 +1,111 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
const (
|
||||
ClassControl uint8 = iota
|
||||
ClassReserved
|
||||
ClassDebug
|
||||
ClassReserved2
|
||||
)
|
||||
|
||||
var (
|
||||
classStr map[uint8]string = map[uint8]string{
|
||||
ClassControl: "Control",
|
||||
ClassReserved: "Reserved (1)",
|
||||
ClassDebug: "Debugging/Measurement",
|
||||
ClassReserved2: "Reserved (2)",
|
||||
}
|
||||
)
|
||||
|
||||
const (
|
||||
/// This is the same type from examples/v4optspad.go.
|
||||
ip4OptTypBits string = "10010100" // [1001 0100], or 148 (0x94)
|
||||
)
|
||||
|
||||
var (
|
||||
v4TypCpyOffset uint8 = 0x80 // 128
|
||||
v4TypCpyMask uint8 = 0x01 // Mask to 1 bit
|
||||
v4TypCpyPos uint8 = 8 - v4TypCpyMask // 7 or 0x07 (8 (bits) - mask = Shifted to 7th bit)
|
||||
|
||||
v4TypClsOffset uint8 = 0x60 // 96
|
||||
v4TypClsMask uint8 = 0x05 // mask to 5 bits
|
||||
v4TypClsPos uint8 = 8 - v4TypClsMask
|
||||
|
||||
v4TypNumOffset uint8 = 0x1f // 31
|
||||
)
|
||||
|
||||
func ToV4OptTyp(copied, class, num uint8) (typ uint8) {
|
||||
|
||||
typ = ((copied & v4TypCpyMask) << v4TypCpyPos) | ((class & v4TypClsMask) << v4TypClsPos) | (num & v4TypNumOffset)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func FromV4OptTyp(typ uint8) (copied, class, num uint8) {
|
||||
|
||||
copied = (typ & v4TypCpyOffset) >> v4TypCpyPos
|
||||
class = (typ & v4TypClsOffset) >> v4TypClsPos
|
||||
num = (typ & v4TypNumOffset)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
var err error
|
||||
var u64 uint64
|
||||
var typ uint8
|
||||
var cpd uint8
|
||||
var cls uint8
|
||||
var num uint8
|
||||
|
||||
// Given a type of ip4OptTypBits (see const at top)...
|
||||
if u64, err = strconv.ParseUint(ip4OptTypBits, 2, 8); err != nil {
|
||||
log.Panicln(err)
|
||||
}
|
||||
typ = uint8(u64)
|
||||
// Prints:
|
||||
/*
|
||||
Type is: 148 (0x0094)
|
||||
*/
|
||||
fmt.Printf("Type is:\t%d (%#04x)\n", typ, typ)
|
||||
|
||||
cpd, cls, num = FromV4OptTyp(typ)
|
||||
// Prints:
|
||||
/*
|
||||
Copied: 1 (0x0001)
|
||||
Class: 0 (0x0000)
|
||||
Number: 20 (0x0014)
|
||||
*/
|
||||
fmt.Printf(
|
||||
"Copied:\t\t%d %#04x)\n"+
|
||||
"Class:\t\t%d (%#04x)\n"+
|
||||
"Number:\t\t%d (%#04x)\n",
|
||||
cpd, cpd,
|
||||
cls, cls,
|
||||
num, num,
|
||||
)
|
||||
|
||||
typ = ToV4OptTyp(cpd, cls, num)
|
||||
// Prints:
|
||||
/*
|
||||
Confirmed Type: 148 (0x94)
|
||||
*/
|
||||
fmt.Printf("Confirmed Type:\t%d (%#02x)\n\n", typ, typ)
|
||||
|
||||
fmt.Println("Class Name:")
|
||||
// Prints:
|
||||
/*
|
||||
Control
|
||||
*/
|
||||
for c, cNm := range classStr {
|
||||
if c == cls {
|
||||
fmt.Println(cNm)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
`fmt`
|
||||
`log`
|
||||
"fmt"
|
||||
"log"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
`fmt`
|
||||
`log`
|
||||
"fmt"
|
||||
"log"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user