format.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. package dns
  2. import (
  3. "net"
  4. "reflect"
  5. "strconv"
  6. )
  7. // NumField returns the number of rdata fields r has.
  8. func NumField(r RR) int {
  9. return reflect.ValueOf(r).Elem().NumField() - 1 // Remove RR_Header
  10. }
  11. // Field returns the rdata field i as a string. Fields are indexed starting from 1.
  12. // RR types that holds slice data, for instance the NSEC type bitmap will return a single
  13. // string where the types are concatenated using a space.
  14. // Accessing non existing fields will cause a panic.
  15. func Field(r RR, i int) string {
  16. if i == 0 {
  17. return ""
  18. }
  19. d := reflect.ValueOf(r).Elem().Field(i)
  20. switch d.Kind() {
  21. case reflect.String:
  22. return d.String()
  23. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  24. return strconv.FormatInt(d.Int(), 10)
  25. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
  26. return strconv.FormatUint(d.Uint(), 10)
  27. case reflect.Slice:
  28. switch reflect.ValueOf(r).Elem().Type().Field(i).Tag {
  29. case `dns:"a"`:
  30. // TODO(miek): Hmm store this as 16 bytes
  31. if d.Len() < net.IPv4len {
  32. return ""
  33. }
  34. if d.Len() < net.IPv6len {
  35. return net.IPv4(byte(d.Index(0).Uint()),
  36. byte(d.Index(1).Uint()),
  37. byte(d.Index(2).Uint()),
  38. byte(d.Index(3).Uint())).String()
  39. }
  40. return net.IPv4(byte(d.Index(12).Uint()),
  41. byte(d.Index(13).Uint()),
  42. byte(d.Index(14).Uint()),
  43. byte(d.Index(15).Uint())).String()
  44. case `dns:"aaaa"`:
  45. if d.Len() < net.IPv6len {
  46. return ""
  47. }
  48. return net.IP{
  49. byte(d.Index(0).Uint()),
  50. byte(d.Index(1).Uint()),
  51. byte(d.Index(2).Uint()),
  52. byte(d.Index(3).Uint()),
  53. byte(d.Index(4).Uint()),
  54. byte(d.Index(5).Uint()),
  55. byte(d.Index(6).Uint()),
  56. byte(d.Index(7).Uint()),
  57. byte(d.Index(8).Uint()),
  58. byte(d.Index(9).Uint()),
  59. byte(d.Index(10).Uint()),
  60. byte(d.Index(11).Uint()),
  61. byte(d.Index(12).Uint()),
  62. byte(d.Index(13).Uint()),
  63. byte(d.Index(14).Uint()),
  64. byte(d.Index(15).Uint()),
  65. }.String()
  66. case `dns:"nsec"`:
  67. if d.Len() == 0 {
  68. return ""
  69. }
  70. s := Type(d.Index(0).Uint()).String()
  71. for i := 1; i < d.Len(); i++ {
  72. s += " " + Type(d.Index(i).Uint()).String()
  73. }
  74. return s
  75. default:
  76. // if it does not have a tag its a string slice
  77. fallthrough
  78. case `dns:"txt"`:
  79. if d.Len() == 0 {
  80. return ""
  81. }
  82. s := d.Index(0).String()
  83. for i := 1; i < d.Len(); i++ {
  84. s += " " + d.Index(i).String()
  85. }
  86. return s
  87. }
  88. }
  89. return ""
  90. }