The header's flags word is sixteen bits packing eight separate fields. Today you build the high flag byte - QR, Opcode, AA, TC, and RD - and pin the RD bit to its exact position, the bit a standard query sets to ask for recursion.
Pack the high-byte flag fields into the top byte of the flags word.
The flags word looks like one 16-bit number but is really eight fields packed into its bits. The high byte, reading from the top bit down, is QR (0 for a query, 1 for a response), a 4-bit Opcode, AA (authoritative answer), TC (truncated), and RD (recursion desired) in the lowest bit. Because a DNS message is stored big-endian, this high byte is the third byte of the whole message, right after the two ID bytes.
The bit that matters most for a client is RD: set it and you are asking the
server to do the recursive work of chasing the answer for you. RD is bit 0 of the
high byte, so a query that sets only RD has a high flag byte of 0x01 and a flags
word of 0x0100. Build the packing as an OR of the individual bit masks so you
can combine any set of flags; the low byte (RA, Z, RCODE) is tomorrow’s job.
// high byte bit positions (a query with recursion desired sets RD)const (flagRD uint16 = 1 << 8 // bit 0 of the high byteflagTC uint16 = 1 << 9flagAA uint16 = 1 << 10flagQR uint16 = 1 << 15 // top bit of the whole word)// Opcode occupies bits 11-14; OR the flags you want set together