SHA256
1
0

include IPv4 Option padding and type packing/unpacking

This commit is contained in:
brent saner
2025-08-31 00:29:20 -04:00
parent e48754ae4b
commit cd5570d34b
9 changed files with 586 additions and 24 deletions

View File

@@ -1,8 +1,8 @@
package main
import (
`fmt`
`log`
"fmt"
"log"
"strconv"
)

View File

@@ -1,8 +1,8 @@
package main
import (
`fmt`
`log`
"fmt"
"log"
"strconv"
)

73
examples/v4optspad.go Normal file
View 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
View 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)
}
}
}

View File

@@ -1,8 +1,8 @@
package main
import (
`fmt`
`log`
"fmt"
"log"
"strconv"
)

View File

@@ -1,8 +1,8 @@
package main
import (
`fmt`
`log`
"fmt"
"log"
"strconv"
)