nx_quic_hdr.nx source
↩ module page · 67 lines · 3355 B
1// nx_quic_hdr.nx -- RUNG 3 of the sovereign QUIC transport: long + short packet headers
2// (RFC 9000 sec 17.2 / 17.3). Long header carries the handshake (Initial/0-RTT/Handshake/Retry) with
3// version + connection IDs; short header is the 1-RTT data path that carries DATAGRAM frames. Parsing
4// these exactly (form bit, fixed bit, type, CIDs, packet-number length) is the frame around everything
5// the relay and client exchange. No float. license_tier: ORIGINAL
6import "nx_quic_wire.nx"
7
8// ---- Long header (RFC 9000 sec 17.2). info out:
9// info[0]=long packet type (0=Initial,1=0RTT,2=Handshake,3=Retry)
10// info[1]=version info[2]=dcid off info[3]=dcid len info[4]=scid off info[5]=scid len
11// info[6]=offset just past SCID (start of type-specific bytes) info[7]=pn_len (from low 2 bits, +1)
12// returns 0 ok, -1 malformed.
13func quic_lhdr_parse(buf: *u8, n: i64, info: *i64) -> i64 {
14 if n < 7 { return 0 - 1 }
15 let b0: i64 = buf[0] as i64
16 if (b0 & 0x80) == 0 { return 0 - 1 } // header form must be 1 (long)
17 if (b0 & 0x40) == 0 { return 0 - 1 } // fixed bit must be 1
18 info[0] = (b0 >> 4) & 3
19 info[7] = (b0 & 3) + 1
20 info[1] = ((buf[1] as i64) << 24) | ((buf[2] as i64) << 16) | ((buf[3] as i64) << 8) | (buf[4] as i64)
21 var off: i64 = 5
22 let dcil: i64 = buf[off] as i64; off = off + 1
23 if off + dcil > n { return 0 - 1 }
24 info[2] = off; info[3] = dcil; off = off + dcil
25 if off >= n { return 0 - 1 }
26 let scil: i64 = buf[off] as i64; off = off + 1
27 if off + scil > n { return 0 - 1 }
28 info[4] = off; info[5] = scil; off = off + scil
29 info[6] = off
30 return 0
31}
32
33// encode the long header through the SCID (first byte + version + dcid + scid). pn_len 1..4 -> low 2 bits.
34func quic_lhdr_encode(out: *u8, ptype: i64, version: i64, dcid: *u8, dcil: i64, scid: *u8, scil: i64, pn_len: i64) -> i64 {
35 out[0] = (0x80 | 0x40 | ((ptype & 3) << 4) | ((pn_len - 1) & 3)) as u8
36 out[1] = ((version >> 24) & 0xff) as u8
37 out[2] = ((version >> 16) & 0xff) as u8
38 out[3] = ((version >> 8) & 0xff) as u8
39 out[4] = (version & 0xff) as u8
40 var off: i64 = 5
41 out[off] = dcil as u8; off = off + 1
42 var i: i64 = 0; while i < dcil { out[off + i] = dcid[i]; i = i + 1 } off = off + dcil
43 out[off] = scil as u8; off = off + 1
44 i = 0; while i < scil { out[off + i] = scid[i]; i = i + 1 } off = off + scil
45 return off
46}
47
48// ---- Short header (RFC 9000 sec 17.3), 1-RTT. The DCID length is known from connection state.
49// first byte: 0(form) 1(fixed) spin 0 0 keyphase pnlen[2]
50func quic_shdr_encode(out: *u8, spin: i64, keyphase: i64, pn_len: i64, dcid: *u8, dcil: i64) -> i64 {
51 out[0] = (0x40 | ((spin & 1) << 5) | ((keyphase & 1) << 2) | ((pn_len - 1) & 3)) as u8
52 var i: i64 = 0; while i < dcil { out[1 + i] = dcid[i]; i = i + 1 }
53 return 1 + dcil
54}
55// parse short header given the known DCID length. info[0]=keyphase info[1]=pn_len info[2]=pn offset.
56func quic_shdr_parse(buf: *u8, n: i64, dcil: i64, info: *i64) -> i64 {
57 if n < 1 + dcil { return 0 - 1 }
58 let b0: i64 = buf[0] as i64
59 if (b0 & 0x80) != 0 { return 0 - 1 } // must be short (form bit 0)
60 if (b0 & 0x40) == 0 { return 0 - 1 } // fixed bit 1
61 info[0] = (b0 >> 2) & 1
62 info[1] = (b0 & 3) + 1
63 info[2] = 1 + dcil
64 return 0
65}
66
67func main() -> i64 { return 0 }