ips.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. package utils
  2. import (
  3. "net"
  4. )
  5. var hexTable = [256]byte{
  6. '0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9,
  7. 'a': 10, 'b': 11, 'c': 12, 'd': 13, 'e': 14, 'f': 15,
  8. 'A': 10, 'B': 11, 'C': 12, 'D': 13, 'E': 14, 'F': 15,
  9. }
  10. // IsIPv4 works the same way as net.ParseIP,
  11. // but without check for IPv6 case and without returning net.IP slice, whereby IsIPv4 makes no allocations.
  12. func IsIPv4(s string) bool {
  13. for i := range net.IPv4len {
  14. if len(s) == 0 {
  15. return false
  16. }
  17. if i > 0 {
  18. if s[0] != '.' {
  19. return false
  20. }
  21. s = s[1:]
  22. }
  23. n, ci := 0, 0
  24. for ci = 0; ci < len(s) && '0' <= s[ci] && s[ci] <= '9'; ci++ {
  25. n = n*10 + int(s[ci]-'0')
  26. if n > 0xFF {
  27. return false
  28. }
  29. }
  30. if ci == 0 || (ci > 1 && s[0] == '0') {
  31. return false
  32. }
  33. s = s[ci:]
  34. }
  35. return len(s) == 0
  36. }
  37. // IsIPv6 works the same way as net.ParseIP,
  38. // but without check for IPv4 case and without returning net.IP slice, whereby IsIPv6 makes no allocations.
  39. func IsIPv6(s string) bool {
  40. ellipsis := -1 // position of ellipsis in ip
  41. // Might have leading ellipsis
  42. if len(s) >= 2 && s[0] == ':' && s[1] == ':' {
  43. ellipsis = 0
  44. s = s[2:]
  45. // Might be only ellipsis
  46. if len(s) == 0 {
  47. return true
  48. }
  49. }
  50. // Loop, parsing hex numbers followed by colon.
  51. i := 0
  52. for i < net.IPv6len {
  53. // Hex number.
  54. n, ci := 0, 0
  55. for ci = 0; ci < len(s); ci++ {
  56. if (s[ci] < '0' || s[ci] > '9') && (s[ci] < 'a' || s[ci] > 'f') && (s[ci] < 'A' || s[ci] > 'F') {
  57. break
  58. }
  59. n *= 16
  60. n += int(hexTable[s[ci]])
  61. if n > 0xFFFF {
  62. return false
  63. }
  64. }
  65. if ci == 0 || n > 0xFFFF {
  66. return false
  67. }
  68. if ci < len(s) && s[ci] == '.' {
  69. if ellipsis < 0 && i != net.IPv6len-net.IPv4len {
  70. return false
  71. }
  72. if i+net.IPv4len > net.IPv6len {
  73. return false
  74. }
  75. if !IsIPv4(s) {
  76. return false
  77. }
  78. s = ""
  79. i += net.IPv4len
  80. break
  81. }
  82. // Save this 16-bit chunk.
  83. i += 2
  84. // Stop at end of string.
  85. s = s[ci:]
  86. if len(s) == 0 {
  87. break
  88. }
  89. // Otherwise must be followed by colon and more.
  90. if s[0] != ':' || len(s) == 1 {
  91. return false
  92. }
  93. s = s[1:]
  94. // Look for ellipsis.
  95. if s[0] == ':' {
  96. if ellipsis >= 0 { // already have one
  97. return false
  98. }
  99. ellipsis = i
  100. s = s[1:]
  101. if len(s) == 0 { // can be at end
  102. break
  103. }
  104. }
  105. }
  106. // Must have used entire string.
  107. if len(s) != 0 {
  108. return false
  109. }
  110. // If didn't parse enough, expand ellipsis.
  111. if i < net.IPv6len {
  112. if ellipsis < 0 {
  113. return false
  114. }
  115. } else if ellipsis >= 0 {
  116. // Ellipsis must represent at least one 0 group.
  117. return false
  118. }
  119. return true
  120. }