ips.go 2.5 KB

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