gitea

Development moved to Codeberg

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
  22. 22
  23. 23
  24. 24
  25. 25
  26. 26
  27. 27
  28. 28
  29. 29
  30. 30
  31. 31
  32. 32
  33. 33
  34. 34
  35. 35
  36. 36
  37. 37
  38. 38
  39. 39
  40. 40
  41. 41
  42. 42
  43. 43
  44. 44
  45. 45
  46. 46
  47. 47
  48. 48
  49. 49
  50. 50
  51. 51
  52. 52
  53. 53
  54. 54
  55. 55
  56. 56
  57. 57
  58. 58
  59. 59
  60. 60
  61. 61
  62. 62
  63. 63
  64. 64
  65. 65
  66. 66
  67. 67
  68. 68
  69. 69
  70. 70
  71. 71
  72. 72
  73. 73
  74. 74
  75. 75
  76. 76
  77. 77
  78. 78
  79. 79
  80. 80
  81. 81
  82. 82
  83. 83
  84. 84
  85. 85
  86. 86
  87. 87
  88. 88
  89. 89
  90. 90
  91. 91
  92. 92
  93. 93
package dns

import (
	"net"
	"reflect"
	"strconv"
)

// NumField returns the number of rdata fields r has.
func NumField(r RR) int {
	return reflect.ValueOf(r).Elem().NumField() - 1 // Remove RR_Header
}

// Field returns the rdata field i as a string. Fields are indexed starting from 1.
// RR types that holds slice data, for instance the NSEC type bitmap will return a single
// string where the types are concatenated using a space.
// Accessing non existing fields will cause a panic.
func Field(r RR, i int) string {
	if i == 0 {
		return ""
	}
	d := reflect.ValueOf(r).Elem().Field(i)
	switch d.Kind() {
	case reflect.String:
		return d.String()
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return strconv.FormatInt(d.Int(), 10)
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return strconv.FormatUint(d.Uint(), 10)
	case reflect.Slice:
		switch reflect.ValueOf(r).Elem().Type().Field(i).Tag {
		case `dns:"a"`:
			// TODO(miek): Hmm store this as 16 bytes
			if d.Len() < net.IPv4len {
				return ""
			}
			if d.Len() < net.IPv6len {
				return net.IPv4(byte(d.Index(0).Uint()),
					byte(d.Index(1).Uint()),
					byte(d.Index(2).Uint()),
					byte(d.Index(3).Uint())).String()
			}
			return net.IPv4(byte(d.Index(12).Uint()),
				byte(d.Index(13).Uint()),
				byte(d.Index(14).Uint()),
				byte(d.Index(15).Uint())).String()
		case `dns:"aaaa"`:
			if d.Len() < net.IPv6len {
				return ""
			}
			return net.IP{
				byte(d.Index(0).Uint()),
				byte(d.Index(1).Uint()),
				byte(d.Index(2).Uint()),
				byte(d.Index(3).Uint()),
				byte(d.Index(4).Uint()),
				byte(d.Index(5).Uint()),
				byte(d.Index(6).Uint()),
				byte(d.Index(7).Uint()),
				byte(d.Index(8).Uint()),
				byte(d.Index(9).Uint()),
				byte(d.Index(10).Uint()),
				byte(d.Index(11).Uint()),
				byte(d.Index(12).Uint()),
				byte(d.Index(13).Uint()),
				byte(d.Index(14).Uint()),
				byte(d.Index(15).Uint()),
			}.String()
		case `dns:"nsec"`:
			if d.Len() == 0 {
				return ""
			}
			s := Type(d.Index(0).Uint()).String()
			for i := 1; i < d.Len(); i++ {
				s += " " + Type(d.Index(i).Uint()).String()
			}
			return s
		default:
			// if it does not have a tag its a string slice
			fallthrough
		case `dns:"txt"`:
			if d.Len() == 0 {
				return ""
			}
			s := d.Index(0).String()
			for i := 1; i < d.Len(); i++ {
				s += " " + d.Index(i).String()
			}
			return s
		}
	}
	return ""
}