Skip to content

Instantly share code, notes, and snippets.

@cb341
Created April 12, 2026 09:50
Show Gist options
  • Select an option

  • Save cb341/8819e5b5d5449caa6e245beab3f8a57c to your computer and use it in GitHub Desktop.

Select an option

Save cb341/8819e5b5d5449caa6e245beab3f8a57c to your computer and use it in GitHub Desktop.
IP Frame Schema Reference
#!/bin/bash
# IPv4 Header Frame Schema - ANSI box drawing
# Grid: 32 bits per row, each bit = 3 chars wide (2 content + 1 separator)
# Total inner width = 32*3 - 1 = 95 chars
R='\033[0m'
B='\033[1;34m'
W='\033[1;37m'
G='\033[1;32m'
Y='\033[1;33m'
C='\033[1;36m'
# Build a horizontal border between two rows.
# For each bit boundary (positions 1..31), decide the junction character:
# - above_split AND below_split: ┼
# - above_split only: ┴
# - below_split only: ┬
# - neither: ─
# left/right are the edge chars (┌├└ / ┐┤┘)
border() {
local left="$1" right="$2"
shift 2
local -a above=() below=()
local mode="above"
for arg in "$@"; do
if [ "$arg" = "|" ]; then
mode="below"
continue
fi
if [ "$mode" = "above" ]; then
above+=("$arg")
else
below+=("$arg")
fi
done
printf " ${B}${left}"
for bit in $(seq 0 31); do
# print 2 dash chars for this bit
printf "──"
# after each bit except last, print junction or dash
if [ $bit -lt 31 ]; then
local in_above=0 in_below=0
local boundary=$((bit + 1))
for a in "${above[@]}"; do [ "$a" -eq "$boundary" ] && in_above=1 && break; done
for b in "${below[@]}"; do [ "$b" -eq "$boundary" ] && in_below=1 && break; done
if [ $in_above -eq 1 ] && [ $in_below -eq 1 ]; then
printf "┼"
elif [ $in_above -eq 1 ]; then
printf "┴"
elif [ $in_below -eq 1 ]; then
printf "┬"
else
printf "─"
fi
fi
done
printf "${right}${R}\n"
}
# Print a content row. Args: pairs of (num_bits label)
row() {
printf " "
while [ $# -ge 2 ]; do
local nbits=$1 label="$2"
shift 2
local width=$(( nbits * 3 - 1 ))
local lbl_len=${#label}
if (( lbl_len > width )); then
label="${label:0:$width}"
lbl_len=$width
fi
local pad=$(( (width - lbl_len) / 2 ))
local rpad=$(( width - lbl_len - pad ))
printf "${B}│${Y}%*s%s%*s${R}" $pad "" "$label" $rpad ""
done
printf "${B}│${R}\n"
}
printf "\n${W} IPv4 Header Format${R}\n"
printf "${C} (each column = 1 bit, 32 bits/row)${R}\n\n"
# Bit ruler - each number takes 3 chars (right-aligned in its cell) except last
printf " ${G}"
for i in $(seq 0 31); do
if [ $i -eq 0 ]; then
printf " %d" $i
else
printf " %2d" $((i))
fi
done
printf "${R}\n"
# Define splits per row (bit positions where fields start, excluding 0)
# Row 1: Ver(0-3) IHL(4-7) DSCP(8-13) ECN(14-15) TotalLen(16-31) -> splits: 4,8,14,16
# Row 2: ID(0-15) Flags(16-18) FragOff(19-31) -> splits: 16,19
# Row 3: TTL(0-7) Proto(8-15) Checksum(16-31) -> splits: 8,16
# Row 4: SrcAddr(0-31) -> splits: none
# Row 5: DstAddr(0-31) -> splits: none
# Row 6: Options(0-23) Padding(24-31) -> splits: 24
# Top border (nothing above, row1 below)
border "┌" "┐" "|" 4 8 14 16
# Row 1
row 4 "Ver" 4 "IHL" 6 "DSCP" 2 "EC" 16 "Total Length"
# Border between row1 and row2
border "├" "┤" 4 8 14 16 "|" 16 19
# Row 2
row 16 "Identification" 3 "Flg" 13 "Fragment Offset"
# Border between row2 and row3
border "├" "┤" 16 19 "|" 8 16
# Row 3
row 8 "TTL" 8 "Protocol" 16 "Header Checksum"
# Border between row3 and row4
border "├" "┤" 8 16 "|"
# Row 4
row 32 "Source Address"
# Border between row4 and row5
border "├" "┤" "|"
# Row 5
row 32 "Destination Address"
# Border between row5 and row6
border "├" "┤" "|" 24
# Row 6
row 24 "Options (variable)" 8 "Padding"
# Bottom border (row6 above, nothing below)
border "└" "┘" 24 "|"
# Legend box - same inner width as header (95 chars)
LW=95
lbox_border() {
local left="$1" right="$2"
printf " ${B}${left}"
printf '%0.s─' $(seq 1 $LW)
printf "${right}${R}\n"
}
lbox_line() {
local color="$1" text="$2"
local len=${#text}
local pad=$(( LW - len ))
printf " ${B}│${color}%s%*s${R}${B}│${R}\n" "$text" $pad ""
}
lh() { lbox_line "$Y" " $1"; } # header (yellow)
lv() { lbox_line "$R" " $1"; } # value line
le() { lbox_line "$R" ""; } # empty line
printf "\n"
lbox_border "┌" "┐"
lbox_line "$W" " FIELD REFERENCE"
lbox_border "├" "┤"
le
lh "Version (4 bits)"
lv "4 = IPv4"
lv "6 = IPv6 (not used in IPv4 headers, but reserved)"
le
lh "IHL - Internet Header Length (4 bits)"
lv "5 = 20 bytes (no options, minimum)"
lv "6-15 = 24-60 bytes (with options)"
le
lh "DSCP - Differentiated Services Code Point (6 bits)"
lv "000000 = CS0 (Best Effort / Default)"
lv "001000 = CS1 (Scavenger)"
lv "001010 = AF11 (Assured Forwarding 11)"
lv "001100 = AF12 (Assured Forwarding 12)"
lv "001110 = AF13 (Assured Forwarding 13)"
lv "010000 = CS2 (OAM)"
lv "010010 = AF21 (Assured Forwarding 21)"
lv "010100 = AF22 (Assured Forwarding 22)"
lv "010110 = AF23 (Assured Forwarding 23)"
lv "011000 = CS3 (Signaling)"
lv "011010 = AF31 (Assured Forwarding 31)"
lv "011100 = AF32 (Assured Forwarding 32)"
lv "011110 = AF33 (Assured Forwarding 33)"
lv "100000 = CS4 (Real-Time Interactive)"
lv "100010 = AF41 (Assured Forwarding 41)"
lv "100100 = AF42 (Assured Forwarding 42)"
lv "100110 = AF43 (Assured Forwarding 43)"
lv "101000 = CS5 (Broadcast Video)"
lv "101110 = EF (Expedited Forwarding - low latency)"
lv "110000 = CS6 (Network Control)"
lv "111000 = CS7 (Reserved)"
le
lh "ECN - Explicit Congestion Notification (2 bits)"
lv "00 = Not-ECT (Not ECN-Capable Transport)"
lv "01 = ECT(1) (ECN-Capable Transport)"
lv "10 = ECT(0) (ECN-Capable Transport)"
lv "11 = CE (Congestion Experienced)"
le
lh "Flags (3 bits)"
lv "Bit 0: Reserved (must be 0)"
lv "Bit 1: DF (Don't Fragment)"
lv " 0 = May fragment"
lv " 1 = Don't fragment"
lv "Bit 2: MF (More Fragments)"
lv " 0 = Last fragment"
lv " 1 = More fragments follow"
le
lh "Protocol (8 bits) - common values"
lv "1 = ICMP (Internet Control Message Protocol)"
lv "2 = IGMP (Internet Group Management Protocol)"
lv "6 = TCP (Transmission Control Protocol)"
lv "17 = UDP (User Datagram Protocol)"
lv "41 = IPv6 (IPv6 Encapsulation)"
lv "47 = GRE (Generic Routing Encapsulation)"
lv "50 = ESP (Encapsulating Security Payload)"
lv "51 = AH (Authentication Header)"
lv "89 = OSPF (Open Shortest Path First)"
lv "132 = SCTP (Stream Control Transmission Protocol)"
le
lh "TTL - Time To Live (8 bits)"
lv "Common defaults: 64 (Linux), 128 (Windows), 255 (Cisco)"
lv "Decremented by 1 at each hop; packet discarded at 0"
le
lh "Fragment Offset (13 bits)"
lv "Measured in 8-byte units. Max offset = 8191 x 8 = 65528 bytes"
le
lh "Total Length (16 bits)"
lv "Min = 20 (header only), Max = 65535 bytes"
lv "Includes header + payload"
le
lbox_border "└" "┘"
printf "\n"
@cb341

cb341 commented Apr 12, 2026

Copy link
Copy Markdown
Author
CleanShot 2026-04-12 at 11 50 24@2x

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment