Created
February 3, 2022 21:01
-
-
Save amitavaghosh1/6d4b93d1f28eb7ae3c0a53b2ffd5aba1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bytes" | |
"fmt" | |
"io/ioutil" | |
"os" | |
) | |
func penik(err interface{}) { | |
panic(err) | |
} | |
type H func(b []byte, groupLen int) uint16 | |
type DnsHeader struct { | |
ID uint16 | |
QrCode uint // 4 | |
OpCode uint | |
Answer uint | |
Truncation uint | |
RecursionD uint | |
RecursionA uint | |
Z uint //3 | |
Rcode uint //4 | |
QDCount uint16 | |
ANCount uint16 | |
NSCount uint16 | |
ARCount uint16 | |
} | |
type QuestionFormat struct { | |
QNames []uint16 | |
QType uint16 | |
QClass uint16 | |
} | |
type AnswerFormat struct { | |
Names []uint16 | |
RData []uint16 | |
Type uint16 | |
Class uint16 | |
TTL uint16 | |
RDLength uint16 | |
} | |
type DnsMessage struct { | |
Header DnsHeader | |
Question QuestionFormat | |
Answer AnswerFormat | |
} | |
type BitReader struct { | |
value []byte | |
ptr int | |
} | |
func (br *BitReader) Read16() []byte { | |
res := []byte{} | |
for i := 0; i < 4; i++ { | |
res = append(res, br.value[br.ptr]) | |
br.ptr += 1 | |
} | |
return res | |
} | |
func (br *BitReader) Read8() []byte { | |
res := []byte{} | |
for i := 0; i < 2; i++ { | |
res = append(res, br.value[br.ptr]) | |
br.ptr += 1 | |
} | |
return res | |
} | |
func hexer(hexMap map[rune]uint16) H { | |
return func(b []byte, groupLen int) uint16 { | |
b = bytes.ToUpper(b) | |
var res uint16 = 0 | |
for i, r := range b { | |
shiftLen := groupLen - (4 * i) | |
// fmt.Println(shiftLen, rune(r), string(r)) | |
res = (res << shiftLen) | hexMap[rune(r)] | |
} | |
return res | |
} | |
} | |
func getHexMap() map[rune]uint16 { | |
hmap := map[rune]uint16{ | |
'A': 0xA, | |
'B': 0xB, | |
'C': 0xC, | |
'D': 0xD, | |
'E': 0xE, | |
'F': 0xF, | |
} | |
for i := 0; i < 10; i++ { | |
hmap[rune('0'+i)] = uint16(i) | |
} | |
return hmap | |
} | |
func ParseHeader(br *BitReader, toBytes H) DnsHeader { | |
header := DnsHeader{ | |
ID: toBytes(br.Read16(), 16), | |
} | |
nextBits := toBytes(br.Read8(), 8) | |
header.QrCode = uint(nextBits >> 7) // 1st bit | |
header.OpCode = uint((nextBits >> 3) & maskOne) // discard last 3 and 0 out Qr | |
restOfHeader2 := nextBits << 5 | |
header.Answer = uint(restOfHeader2 & maskOne) | |
header.Truncation = uint((restOfHeader2 << 1) & maskOne) | |
header.RecursionD = uint((restOfHeader2 << 2) & maskOne) | |
nextBits = toBytes(br.Read8(), 8) | |
header.RecursionA = uint(nextBits >> 7) | |
header.Z = uint((nextBits << 1) & 0b11100000) | |
header.Rcode = uint((nextBits << 4) & 0b11110000) | |
header.QDCount = toBytes(br.Read16(), 16) | |
header.ANCount = toBytes(br.Read16(), 16) | |
header.NSCount = toBytes(br.Read16(), 16) | |
header.ARCount = toBytes(br.Read16(), 16) | |
return header | |
} | |
func ParseQuestions(br *BitReader, qLen int, toBytes H) QuestionFormat { | |
question := QuestionFormat{} | |
for i := 0; i < qLen; i++ { | |
question.QNames = append(question.QNames, toBytes(br.Read16(), 16)) | |
} | |
question.QType = toBytes(br.Read16(), 16) | |
question.QClass = toBytes(br.Read16(), 16) | |
return question | |
} | |
func ParseAnswer(br *BitReader, aLen int, toBytes H) AnswerFormat { | |
answer := AnswerFormat{} | |
for i := 0; i < aLen; i++ { | |
answer.Names = append(answer.Names, toBytes(br.Read16(), 16)) | |
} | |
answer.Type = toBytes(br.Read16(), 16) | |
answer.Class = toBytes(br.Read16(), 16) | |
// ttl and others | |
return answer | |
} | |
const ( | |
maskOne = 0b10000000 | |
) | |
func main() { | |
fileName := os.Args[1] | |
byts, err := ioutil.ReadFile(fileName) | |
if err != nil { | |
penik(err) | |
} | |
toBytes := hexer(getHexMap()) | |
dns := &DnsMessage{} | |
brr := &BitReader{value: byts, ptr: 0} | |
dns.Header = ParseHeader(brr, toBytes) | |
dns.Question = ParseQuestions(brr, int(dns.Header.QDCount), toBytes) | |
fmt.Printf("%+v\n", dns) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment