Willy Tarreau | 78bb934 | 2023-04-26 09:40:23 +0200 | [diff] [blame] | 1 | #!/usr/bin/env bash |
| 2 | |
| 3 | # Usage: mkhdr -l <len> -t <type> -f <flags> -sid <sid> > hdr.bin |
| 4 | # All fields are optional. 0 assumed when absent. |
| 5 | |
| 6 | USAGE=\ |
Willy Tarreau | e8ae99b | 2023-04-26 11:25:46 +0200 | [diff] [blame] | 7 | "Usage: %s [-l <len> ] [-t <type>] [-f <flags>] [-i <sid>] [ -d <data> ] > hdr.bin |
| 8 | Numbers are decimal or 0xhex. Not set=0. If <data> is passed, it points |
| 9 | to a file that is read and chunked into frames of <len> bytes. |
Willy Tarreau | 78bb934 | 2023-04-26 09:40:23 +0200 | [diff] [blame] | 10 | |
| 11 | Supported symbolic types (case insensitive prefix match): |
| 12 | DATA (0x00) PUSH_PROMISE (0x05) |
| 13 | HEADERS (0x01) PING (0x06) |
| 14 | PRIORITY (0x02) GOAWAY (0x07) |
| 15 | RST_STREAM (0x03) WINDOW_UPDATE (0x08) |
| 16 | SETTINGS (0x04) CONTINUATION (0x09) |
| 17 | |
| 18 | Supported symbolic flags (case insensitive prefix match): |
| 19 | ES (0x01) PAD (0x08) |
| 20 | EH (0x04) PRIO (0x20) |
| 21 | |
| 22 | " |
| 23 | |
| 24 | LEN= |
| 25 | TYPE= |
| 26 | FLAGS= |
| 27 | ID= |
| 28 | |
| 29 | die() { |
| 30 | [ "$#" -eq 0 ] || echo "$*" >&2 |
| 31 | exit 1 |
| 32 | } |
| 33 | |
| 34 | quit() { |
| 35 | [ "$#" -eq 0 ] || echo "$*" |
| 36 | exit 0 |
| 37 | } |
| 38 | |
| 39 | # print usage with $1 as the cmd name |
| 40 | usage() { |
| 41 | printf "$USAGE" "$1"; |
| 42 | } |
| 43 | |
| 44 | # Send frame made of $1 $2 $3 $4 to stdout. |
| 45 | # Usage: mkframe <len> <type> <flags> <id> |
| 46 | mkframe() { |
| 47 | local L="${1:-0}" |
| 48 | local T="${2:-0}" |
| 49 | local F="${3:-0}" |
| 50 | local I="${4:-0}" |
| 51 | local t f |
| 52 | |
| 53 | # get the first match in this order |
| 54 | for t in DATA:0x00 HEADERS:0x01 RST_STREAM:0x03 SETTINGS:0x04 PING:0x06 \ |
| 55 | GOAWAY:0x07 WINDOW_UPDATE:0x08 CONTINUATION:0x09 PRIORITY:0x02 \ |
| 56 | PUSH_PROMISE:0x05; do |
| 57 | if [ -z "${t##${T^^*}*}" ]; then |
| 58 | T="${t##*:}" |
| 59 | break |
| 60 | fi |
| 61 | done |
| 62 | |
| 63 | if [ -n "${T##[0-9]*}" ]; then |
| 64 | echo "Unknown type '$T'" >&2 |
| 65 | usage "${0##*}" |
| 66 | die |
| 67 | fi |
| 68 | |
| 69 | # get the first match in this order |
| 70 | for f in ES:0x01 EH:0x04 PAD:0x08 PRIO:0x20; do |
| 71 | if [ -z "${f##${F^^*}*}" ]; then |
| 72 | F="${f##*:}" |
| 73 | fi |
| 74 | done |
| 75 | |
| 76 | if [ -n "${F##[0-9]*}" ]; then |
| 77 | echo "Unknown type '$T'" >&2 |
| 78 | usage "${0##*}" |
| 79 | die |
| 80 | fi |
| 81 | |
| 82 | L=$(( L )); T=$(( T )); F=$(( F )); I=$(( I )) |
| 83 | |
| 84 | L0=$(( (L >> 16) & 255 )); L0=$(printf "%02x" $L0) |
| 85 | L1=$(( (L >> 8) & 255 )); L1=$(printf "%02x" $L1) |
| 86 | L2=$(( (L >> 0) & 255 )); L2=$(printf "%02x" $L2) |
| 87 | |
| 88 | T0=$(( (T >> 0) & 255 )); T0=$(printf "%02x" $T0) |
| 89 | F0=$(( (F >> 0) & 255 )); F0=$(printf "%02x" $F0) |
| 90 | |
| 91 | I0=$(( (I >> 24) & 127 )); I0=$(printf "%02x" $I0) |
| 92 | I1=$(( (I >> 16) & 255 )); I1=$(printf "%02x" $I1) |
| 93 | I2=$(( (I >> 8) & 255 )); I2=$(printf "%02x" $I2) |
| 94 | I3=$(( (I >> 0) & 255 )); I3=$(printf "%02x" $I3) |
| 95 | |
| 96 | printf "\x$L0\x$L1\x$L2\x$T0\x$F0\x$I0\x$I1\x$I2\x$I3" |
| 97 | } |
| 98 | |
| 99 | ## main |
| 100 | |
| 101 | if [ $# -le 1 ]; then |
| 102 | usage "${0##*}" |
| 103 | die |
| 104 | fi |
| 105 | |
| 106 | while [ -n "$1" -a -z "${1##-*}" ]; do |
| 107 | case "$1" in |
| 108 | -l) LEN="$2" ; shift 2 ;; |
| 109 | -t) TYPE="$2" ; shift 2 ;; |
| 110 | -f) FLAGS="$2" ; shift 2 ;; |
| 111 | -i) ID="$2" ; shift 2 ;; |
Willy Tarreau | e8ae99b | 2023-04-26 11:25:46 +0200 | [diff] [blame] | 112 | -d) DATA="$2" ; shift 2 ;; |
Willy Tarreau | 78bb934 | 2023-04-26 09:40:23 +0200 | [diff] [blame] | 113 | -h|--help) usage "${0##*}"; quit;; |
| 114 | *) usage "${0##*}"; die ;; |
| 115 | esac |
| 116 | done |
| 117 | |
| 118 | if [ $# -gt 0 ]; then |
| 119 | usage "${0##*}" |
| 120 | die |
| 121 | fi |
| 122 | |
| 123 | # default values for LEN and ID |
| 124 | LEN=${LEN:-0}; |
| 125 | if [ -n "${LEN##[0-9]*}" ]; then |
| 126 | echo "Unparsable length '$LEN'" >&2 |
| 127 | usage "${0##*}" |
| 128 | die |
| 129 | fi |
| 130 | |
| 131 | ID=${ID:-0}; |
| 132 | if [ -n "${ID##[0-9]*}" ]; then |
| 133 | echo "Unparsable stream ID '$ID'" >&2 |
| 134 | usage "${0##*}" |
| 135 | die |
| 136 | fi |
| 137 | |
Willy Tarreau | e8ae99b | 2023-04-26 11:25:46 +0200 | [diff] [blame] | 138 | if [ -z "$DATA" ]; then |
| 139 | mkframe "$LEN" "$TYPE" "$FLAGS" "$ID" |
| 140 | else |
| 141 | # read file $DATA in <LEN> chunks and send it in multiple frames |
| 142 | # advertising their respective lengths. |
| 143 | [ $LEN -gt 0 ] || LEN=16384 |
| 144 | |
| 145 | while read -rN "$LEN" payload || [ ${#payload} -gt 0 ]; do |
| 146 | mkframe "${#payload}" "$TYPE" "$FLAGS" "$ID" |
| 147 | echo -n "$payload" |
| 148 | done < "$DATA" |
| 149 | fi |
Willy Tarreau | 78bb934 | 2023-04-26 09:40:23 +0200 | [diff] [blame] | 150 | |
| 151 | exit 0 |