a go dns packet parser
at v0.0.1 18 kB view raw
1package magna 2 3import ( 4 "encoding/binary" 5 "fmt" 6 "net" 7 "strings" 8) 9 10func (a *A) Decode(buf []byte, offset int, rdlength int) (int, error) { 11 bytes, offset, err := getSlice(buf, offset, rdlength) 12 if err != nil { 13 return offset, fmt.Errorf("A record: failed to read address data: %w", err) 14 } 15 16 a.Address = net.IP(bytes) 17 if a.Address.To4() == nil { 18 return offset, fmt.Errorf("A record: decoded data is not a valid IPv4 address: %v", bytes) 19 } 20 return offset, nil 21} 22 23func (a *A) Encode(bytes []byte, offsets *map[string]uint16) ([]byte, error) { 24 ipv4 := a.Address.To4() 25 if ipv4 == nil { 26 return nil, fmt.Errorf("A record: cannot encode non-IPv4 address %s", a.Address.String()) 27 } 28 29 return append(bytes, a.Address.To4()...), nil 30} 31 32func (a A) String() string { 33 return a.Address.String() 34} 35 36func (ns *NS) Decode(buf []byte, offset int, rdlength int) (int, error) { 37 var err error 38 ns.NSDName, offset, err = decodeDomain(buf, offset) 39 if err != nil { 40 return offset, fmt.Errorf("NS record: failed to decode NSDName: %w", err) 41 } 42 43 return offset, nil 44} 45 46func (ns *NS) Encode(bytes []byte, offsets *map[string]uint16) ([]byte, error) { 47 var err error 48 bytes, err = encodeDomain(bytes, ns.NSDName, offsets) 49 if err != nil { 50 return nil, fmt.Errorf("NS record: failed to encode NSDName %s: %w", ns.NSDName, err) 51 } 52 53 return bytes, nil 54} 55 56func (ns NS) String() string { 57 return ns.NSDName 58} 59 60func (md *MD) Decode(buf []byte, offset int, rdlength int) (int, error) { 61 var err error 62 md.MADName, offset, err = decodeDomain(buf, offset) 63 if err != nil { 64 return offset, fmt.Errorf("MD record: failed to decode MADName %s: %w", md.MADName, err) 65 } 66 67 return offset, nil 68} 69 70func (md *MD) Encode(bytes []byte, offsets *map[string]uint16) ([]byte, error) { 71 var err error 72 bytes, err = encodeDomain(bytes, md.MADName, offsets) 73 if err != nil { 74 return nil, fmt.Errorf("MD record: failed to encode MADName %s: %w", md.MADName, err) 75 } 76 77 return bytes, nil 78} 79 80func (md MD) String() string { 81 return md.MADName 82} 83 84func (mf *MF) Decode(buf []byte, offset int, rdlength int) (int, error) { 85 var err error 86 mf.MADName, offset, err = decodeDomain(buf, offset) 87 if err != nil { 88 return offset, fmt.Errorf("MF record: failed to decode MADName: %w", err) 89 } 90 91 return offset, nil 92} 93 94func (mf *MF) Encode(bytes []byte, offsets *map[string]uint16) ([]byte, error) { 95 var err error 96 bytes, err = encodeDomain(bytes, mf.MADName, offsets) 97 if err != nil { 98 return nil, fmt.Errorf("MF record: failed to encode MADName %s: %w", mf.MADName, err) 99 } 100 101 return bytes, nil 102} 103 104func (mf MF) String() string { 105 return mf.MADName 106} 107 108func (c *CNAME) Decode(buf []byte, offset int, rdlength int) (int, error) { 109 var err error 110 c.CName, offset, err = decodeDomain(buf, offset) 111 if err != nil { 112 return offset, fmt.Errorf("CNAME record: failed to decode CNAME: %w", err) 113 } 114 115 return offset, nil 116} 117 118func (c *CNAME) Encode(bytes []byte, offsets *map[string]uint16) ([]byte, error) { 119 var err error 120 bytes, err = encodeDomain(bytes, c.CName, offsets) 121 if err != nil { 122 return nil, fmt.Errorf("CNAME record: failed to encode CNAME %s: %w", c.CName, err) 123 } 124 125 return bytes, nil 126} 127 128func (c CNAME) String() string { 129 return c.CName 130} 131 132func (soa *SOA) Decode(buf []byte, offset int, rdlength int) (int, error) { 133 var err error 134 soa.MName, offset, err = decodeDomain(buf, offset) 135 if err != nil { 136 return offset, fmt.Errorf("SOA record: failed to decode MName: %w", err) 137 } 138 139 soa.RName, offset, err = decodeDomain(buf, offset) 140 if err != nil { 141 return offset, fmt.Errorf("SOA record: failed to decode RName: %w", err) 142 } 143 144 soa.Serial, offset, err = getU32(buf, offset) 145 if err != nil { 146 return offset, fmt.Errorf("SOA record: failed to decode Serial: %w", err) 147 } 148 149 soa.Refresh, offset, err = getU32(buf, offset) 150 if err != nil { 151 return offset, fmt.Errorf("SOA record: failed to decode Refresh: %w", err) 152 } 153 154 soa.Retry, offset, err = getU32(buf, offset) 155 if err != nil { 156 return offset, fmt.Errorf("SOA record: failed to decode Retry: %w", err) 157 } 158 159 soa.Expire, offset, err = getU32(buf, offset) 160 if err != nil { 161 return offset, fmt.Errorf("SOA record: failed to decode Expire: %w", err) 162 } 163 164 soa.Minimum, offset, err = getU32(buf, offset) 165 if err != nil { 166 return offset, fmt.Errorf("SOA record: failed to decode Minimum: %w", err) 167 } 168 169 return offset, nil 170} 171 172func (soa *SOA) Encode(bytes []byte, offsets *map[string]uint16) ([]byte, error) { 173 var err error 174 bytes, err = encodeDomain(bytes, soa.MName, offsets) 175 if err != nil { 176 return nil, fmt.Errorf("SOA record: failed to encode MName %s: %w", soa.MName, err) 177 } 178 179 bytes, err = encodeDomain(bytes, soa.RName, offsets) 180 if err != nil { 181 return nil, fmt.Errorf("SOA record: failed to encode RName %s: %w", soa.RName, err) 182 } 183 184 bytes = binary.BigEndian.AppendUint32(bytes, soa.Serial) 185 bytes = binary.BigEndian.AppendUint32(bytes, soa.Refresh) 186 bytes = binary.BigEndian.AppendUint32(bytes, soa.Retry) 187 bytes = binary.BigEndian.AppendUint32(bytes, soa.Expire) 188 bytes = binary.BigEndian.AppendUint32(bytes, soa.Minimum) 189 190 return bytes, nil 191} 192 193func (soa SOA) String() string { 194 return fmt.Sprintf("%s %s %d %d %d %d %d", soa.MName, soa.RName, soa.Serial, soa.Refresh, soa.Retry, soa.Expire, soa.Minimum) 195} 196 197func (mb *MB) Decode(buf []byte, offset int, rdlength int) (int, error) { 198 madname, offset, err := decodeDomain(buf, offset) 199 if err != nil { 200 return offset, fmt.Errorf("MB record: failed to decode MADName: %w", err) 201 } 202 203 mb.MADName = string(madname) 204 return offset, nil 205} 206 207func (mb *MB) Encode(bytes []byte, offsets *map[string]uint16) ([]byte, error) { 208 var err error 209 bytes, err = encodeDomain(bytes, mb.MADName, offsets) 210 if err != nil { 211 return nil, fmt.Errorf("MB record: failed to encode MADName %s: %w", mb.MADName, err) 212 } 213 214 return bytes, nil 215} 216 217func (mb MB) String() string { 218 return mb.MADName 219} 220 221func (mg *MG) Decode(buf []byte, offset int, rdlength int) (int, error) { 222 var err error 223 mg.MGMName, offset, err = decodeDomain(buf, offset) 224 if err != nil { 225 return offset, fmt.Errorf("MG record: failed to decode MGMName: %w", err) 226 } 227 228 return offset, nil 229} 230 231func (mg *MG) Encode(bytes []byte, offsets *map[string]uint16) ([]byte, error) { 232 var err error 233 bytes, err = encodeDomain(bytes, mg.MGMName, offsets) 234 if err != nil { 235 return nil, fmt.Errorf("MG record: failed to encode MGMName %s: %w", mg.MGMName, err) 236 } 237 return bytes, nil 238} 239 240func (mg MG) String() string { 241 return mg.MGMName 242} 243 244func (mr *MR) Decode(buf []byte, offset int, rdlength int) (int, error) { 245 var err error 246 mr.NEWName, offset, err = decodeDomain(buf, offset) 247 if err != nil { 248 return offset, fmt.Errorf("MR record: failed to decode NEWName: %w", err) 249 } 250 251 return offset, nil 252} 253 254func (mr *MR) Encode(bytes []byte, offsets *map[string]uint16) ([]byte, error) { 255 var err error 256 bytes, err = encodeDomain(bytes, mr.NEWName, offsets) 257 if err != nil { 258 return nil, fmt.Errorf("MR record: failed to encode NEWName: %w", err) 259 } 260 261 return bytes, nil 262} 263 264func (mr MR) String() string { 265 return mr.NEWName 266} 267 268func (null *NULL) Decode(buf []byte, offset int, rdlength int) (int, error) { 269 var err error 270 null.Anything, offset, err = getSlice(buf, offset, int(rdlength)) 271 if err != nil { 272 return offset, fmt.Errorf("NULL record: failed to read data: %w", err) 273 } 274 275 return offset, nil 276} 277 278func (null *NULL) Encode(bytes []byte, offsets *map[string]uint16) ([]byte, error) { 279 return append(bytes, null.Anything...), nil 280} 281 282func (null NULL) String() string { 283 return string(null.Anything) 284} 285 286func (wks *WKS) Decode(buf []byte, offset int, rdlength int) (int, error) { 287 if rdlength < 5 { 288 return len(buf), fmt.Errorf("WKS record: RDLENGTH %d is too short, minimum 5 required", rdlength) 289 } 290 291 addressBytes, nextOffset, err := getSlice(buf, offset, 4) 292 if err != nil { 293 return len(buf), fmt.Errorf("WKS record: failed to read address: %w", err) 294 } 295 offset = nextOffset 296 wks.Address = net.IP(addressBytes) 297 298 protocol, nextOffset, err := getU8(buf, offset) 299 if err != nil { 300 return len(buf), fmt.Errorf("WKS record: failed to read protocol: %w", err) 301 } 302 offset = nextOffset 303 wks.Protocol = protocol 304 305 bitmapLength := rdlength - 5 306 wks.BitMap, nextOffset, err = getSlice(buf, offset, bitmapLength) 307 if err != nil { 308 return len(buf), fmt.Errorf("WKS record: failed to read bitmap: %w", err) 309 } 310 offset = nextOffset 311 312 return offset, nil 313} 314 315func (wks *WKS) Encode(bytes []byte, offsets *map[string]uint16) ([]byte, error) { 316 bytes = append(bytes, wks.Address.To4()...) 317 bytes = append(bytes, wks.Protocol) 318 bytes = append(bytes, wks.BitMap...) 319 320 return bytes, nil 321} 322 323func (wks WKS) String() string { 324 return fmt.Sprintf("%s %d %x", wks.Address.String(), wks.Protocol, wks.BitMap) 325} 326 327func (ptr *PTR) Decode(buf []byte, offset int, rdlength int) (int, error) { 328 var err error 329 ptr.PTRDName, offset, err = decodeDomain(buf, offset) 330 if err != nil { 331 return offset, fmt.Errorf("PTR record: failed to decode PTRDName: %w", err) 332 } 333 334 return offset, nil 335} 336 337func (ptr *PTR) Encode(bytes []byte, offsets *map[string]uint16) ([]byte, error) { 338 var err error 339 bytes, err = encodeDomain(bytes, ptr.PTRDName, offsets) 340 if err != nil { 341 return nil, fmt.Errorf("PTR record: failed to encode PTRD %s: %w", ptr.PTRDName, err) 342 } 343 344 return bytes, nil 345} 346 347func (ptr PTR) String() string { 348 return ptr.PTRDName 349} 350 351func (hinfo *HINFO) Decode(buf []byte, offset int, rdlength int) (int, error) { 352 startOffset := offset 353 endOffset := offset + rdlength 354 if endOffset > len(buf) { 355 return len(buf), &BufferOverflowError{Length: len(buf), Offset: endOffset} 356 } 357 358 currentOffset := offset 359 var err error 360 361 cpuLen, nextOffset, err := getU8(buf, currentOffset) 362 if err != nil { 363 return len(buf), fmt.Errorf("HINFO record: failed to read CPU length: %w", err) 364 } 365 currentOffset = nextOffset 366 if currentOffset+int(cpuLen) > endOffset { 367 return len(buf), &BufferOverflowError{Length: len(buf), Offset: currentOffset + int(cpuLen)} 368 } 369 cpuBytes, nextOffset, err := getSlice(buf, currentOffset, int(cpuLen)) 370 if err != nil { 371 return len(buf), fmt.Errorf("HINFO record: failed to read CPU data: %w", err) 372 } 373 currentOffset = nextOffset 374 hinfo.CPU = string(cpuBytes) 375 376 osLen, nextOffset, err := getU8(buf, currentOffset) 377 if err != nil { 378 if currentOffset == endOffset { 379 return len(buf), fmt.Errorf("HINFO record: missing OS length byte at offset %d (expected end: %d)", currentOffset, endOffset) 380 } 381 return len(buf), fmt.Errorf("HINFO record: failed to read OS length: %w", err) 382 } 383 currentOffset = nextOffset 384 if currentOffset+int(osLen) > endOffset { 385 return len(buf), &BufferOverflowError{Length: len(buf), Offset: currentOffset + int(osLen)} 386 } 387 osBytes, nextOffset, err := getSlice(buf, currentOffset, int(osLen)) 388 if err != nil { 389 return len(buf), fmt.Errorf("HINFO record: failed to read OS data: %w", err) 390 } 391 currentOffset = nextOffset 392 hinfo.OS = string(osBytes) 393 394 if currentOffset != endOffset { 395 return len(buf), fmt.Errorf("HINFO record: RDATA length mismatch, consumed %d bytes, expected %d", currentOffset-startOffset, rdlength) 396 } 397 398 return currentOffset, nil 399} 400 401func (hinfo *HINFO) Encode(bytes []byte, offsets *map[string]uint16) ([]byte, error) { 402 if len(hinfo.CPU) > 255 { 403 return nil, fmt.Errorf("HINFO record: CPU string length %d exceeds maximum 255", len(hinfo.CPU)) 404 } 405 if len(hinfo.OS) > 255 { 406 return nil, fmt.Errorf("HINFO record: OS string length %d exceeds maximum 255", len(hinfo.OS)) 407 } 408 409 bytes = append(bytes, byte(len(hinfo.CPU))) 410 bytes = append(bytes, []byte(hinfo.CPU)...) 411 bytes = append(bytes, byte(len(hinfo.OS))) 412 bytes = append(bytes, []byte(hinfo.OS)...) 413 return bytes, nil 414} 415 416func (hinfo HINFO) String() string { 417 return fmt.Sprintf("%q %q", hinfo.CPU, hinfo.OS) 418} 419 420func (minfo *MINFO) Decode(buf []byte, offset int, rdlength int) (int, error) { 421 var err error 422 423 minfo.RMailBx, offset, err = decodeDomain(buf, offset) 424 if err != nil { 425 return offset, fmt.Errorf("MINFO record: failed to decode RMailBx: %w", err) 426 } 427 428 minfo.EMailBx, offset, err = decodeDomain(buf, offset) 429 if err != nil { 430 return offset, fmt.Errorf("MINFO record: failed to decode EMailBx: %w", err) 431 } 432 433 return offset, nil 434} 435 436func (minfo *MINFO) Encode(bytes []byte, offsets *map[string]uint16) ([]byte, error) { 437 var err error 438 bytes, err = encodeDomain(bytes, minfo.RMailBx, offsets) 439 if err != nil { 440 return nil, fmt.Errorf("MINFO record: failed to encode RMailBx %s: %w", minfo.RMailBx, err) 441 } 442 443 bytes, err = encodeDomain(bytes, minfo.EMailBx, offsets) 444 if err != nil { 445 return nil, fmt.Errorf("MINFO record: failed to encode EMailBx %s: %w", minfo.EMailBx, err) 446 } 447 448 return bytes, nil 449} 450 451func (minfo MINFO) String() string { 452 return minfo.RMailBx + " " + minfo.EMailBx 453} 454 455func (mx *MX) Decode(buf []byte, offset int, rdlength int) (int, error) { 456 var err error 457 mx.Preference, offset, err = getU16(buf, offset) 458 if err != nil { 459 return offset, fmt.Errorf("MX record: failed to decode Preference: %w", err) 460 } 461 462 mx.Exchange, offset, err = decodeDomain(buf, offset) 463 if err != nil { 464 return offset, fmt.Errorf("MX record: failed to decode Exchange: %w", err) 465 } 466 467 return offset, nil 468} 469 470func (mx *MX) Encode(bytes []byte, offsets *map[string]uint16) ([]byte, error) { 471 var err error 472 bytes = binary.BigEndian.AppendUint16(bytes, mx.Preference) 473 bytes, err = encodeDomain(bytes, mx.Exchange, offsets) 474 if err != nil { 475 return nil, fmt.Errorf("MX record: failed to encode Exchange %s: %w", mx.Exchange, err) 476 } 477 478 return bytes, nil 479} 480 481func (mx MX) String() string { 482 return fmt.Sprintf("%d %s", mx.Preference, mx.Exchange) 483} 484 485func (txt *TXT) Decode(buf []byte, offset int, rdlength int) (int, error) { 486 txt.TxtData = make([]string, 0, 1) 487 endOffset := offset + rdlength 488 if endOffset > len(buf) { 489 return len(buf), &BufferOverflowError{Length: len(buf), Offset: endOffset} 490 } 491 492 currentOffset := offset 493 for currentOffset < endOffset { 494 strLen, nextOffsetAfterLen, err := getU8(buf, currentOffset) 495 if err != nil { 496 return len(buf), fmt.Errorf("TXT record: failed to read string length byte: %w", err) 497 } 498 499 nextOffsetAfterData := nextOffsetAfterLen + int(strLen) 500 if nextOffsetAfterData > endOffset { 501 return len(buf), fmt.Errorf("TXT record: string segment length %d exceeds RDLENGTH boundary %d", strLen, endOffset) 502 } 503 504 strBytes, actualNextOffsetAfterData, err := getSlice(buf, nextOffsetAfterLen, int(strLen)) 505 if err != nil { 506 return len(buf), fmt.Errorf("TXT record: failed to read string data (length %d): %w", strLen, err) 507 } 508 509 txt.TxtData = append(txt.TxtData, string(strBytes)) 510 currentOffset = actualNextOffsetAfterData 511 } 512 513 if currentOffset != endOffset { 514 return len(buf), fmt.Errorf("TXT record: RDATA parsing finished at offset %d, but expected end at %d", currentOffset, endOffset) 515 } 516 517 return currentOffset, nil 518} 519 520func (txt *TXT) Encode(bytes []byte, offsets *map[string]uint16) ([]byte, error) { 521 for _, s := range txt.TxtData { 522 if len(s) > 255 { 523 return nil, fmt.Errorf("TXT record: string segment length %d exceeds maximum 255", len(s)) 524 } 525 bytes = append(bytes, byte(len(s))) 526 bytes = append(bytes, []byte(s)...) 527 } 528 return bytes, nil 529} 530 531func (txt TXT) String() string { 532 quoted := make([]string, len(txt.TxtData)) 533 for i, s := range txt.TxtData { 534 quoted[i] = fmt.Sprintf("%q", s) 535 } 536 return strings.Join(quoted, " ") 537} 538 539func (r *Reserved) Decode(buf []byte, offset int, rdlength int) (int, error) { 540 var err error 541 r.Bytes, offset, err = getSlice(buf, offset, int(rdlength)) 542 if err != nil { 543 return offset, fmt.Errorf("reserved record: failed to read data: %w", err) 544 } 545 546 return offset, err 547} 548 549func (r *Reserved) Encode(bytes []byte, offsets *map[string]uint16) ([]byte, error) { 550 return append(bytes, r.Bytes...), nil 551} 552 553func (r Reserved) String() string { 554 return fmt.Sprintf("[Reserved Data: %x]", r.Bytes) 555} 556 557// Decode decodes a resource record from buf at the offset. 558func (r *ResourceRecord) Decode(buf []byte, offset int) (int, error) { 559 var err error 560 r.Name, offset, err = decodeDomain(buf, offset) 561 if err != nil { 562 return offset, fmt.Errorf("rr decode: failed to decode record name: %w", err) 563 } 564 565 var rtype uint16 566 rtype, offset, err = getU16(buf, offset) 567 if err != nil { 568 return offset, fmt.Errorf("rr decode: failed to decode RType for %s: %w", r.Name, err) 569 } 570 r.RType = DNSType(rtype) 571 572 var rclass uint16 573 rclass, offset, err = getU16(buf, offset) 574 if err != nil { 575 return offset, fmt.Errorf("rr decode: failed to decode RClass for %s: %w", r.Name, err) 576 } 577 r.RClass = DNSClass(rclass) 578 579 r.TTL, offset, err = getU32(buf, offset) 580 if err != nil { 581 return offset, fmt.Errorf("rr decode: failed to decode TTL for %s: %w", r.Name, err) 582 } 583 584 r.RDLength, offset, err = getU16(buf, offset) 585 if err != nil { 586 return offset, fmt.Errorf("rr decode: failed to decode RDLength for %s: %w", r.Name, err) 587 } 588 589 switch r.RType { 590 case 1: 591 r.RData = &A{} 592 case 2: 593 r.RData = &NS{} 594 case 3: 595 r.RData = &MD{} 596 case 4: 597 r.RData = &MF{} 598 case 5: 599 r.RData = &CNAME{} 600 case 6: 601 r.RData = &SOA{} 602 case 7: 603 r.RData = &MB{} 604 case 8: 605 r.RData = &MG{} 606 case 9: 607 r.RData = &MR{} 608 case 10: 609 r.RData = &NULL{} 610 case 11: 611 r.RData = &WKS{} 612 case 12: 613 r.RData = &PTR{} 614 case 13: 615 r.RData = &HINFO{} 616 case 14: 617 r.RData = &MINFO{} 618 case 15: 619 r.RData = &MX{} 620 case 16: 621 r.RData = &TXT{} 622 default: 623 r.RData = &Reserved{} 624 } 625 626 if r.RData != nil { 627 offset, err = r.RData.Decode(buf, offset, int(r.RDLength)) 628 if err != nil { 629 return offset, fmt.Errorf("rr decode: failed to decode RData for %s (%s): %w", r.Name, r.RType.String(), err) 630 } 631 } 632 633 return offset, nil 634} 635 636// Encode encdoes a resource record and returns the input bytes appened. 637func (r *ResourceRecord) Encode(bytes []byte, offsets *map[string]uint16) ([]byte, error) { 638 var err error 639 bytes, err = encodeDomain(bytes, r.Name, offsets) 640 if err != nil { 641 return nil, fmt.Errorf("rr encode: failed to encode record name %s: %w", r.Name, err) 642 } 643 644 bytes = binary.BigEndian.AppendUint16(bytes, uint16(r.RType)) 645 bytes = binary.BigEndian.AppendUint16(bytes, uint16(r.RClass)) 646 bytes = binary.BigEndian.AppendUint32(bytes, r.TTL) 647 648 rdata_start := len(bytes) 649 bytes = binary.BigEndian.AppendUint16(bytes, 0) 650 bytes, err = r.RData.Encode(bytes, offsets) 651 if err != nil { 652 return nil, fmt.Errorf("rr encode: failed to encode RData for %s (%s): %w", r.Name, r.RType.String(), err) 653 } 654 655 rdata_length := uint16(len(bytes) - rdata_start - 2) 656 binary.BigEndian.PutUint16(bytes[rdata_start:rdata_start+2], rdata_length) 657 658 return bytes, nil 659}