ips.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. package utils
  2. import "net"
  3. // IsIPv4 works the same way as net.ParseIP,
  4. // but without check for IPv6 case and without returning net.IP slice, whereby IsIPv4 makes no allocations.
  5. func IsIPv4(s string) bool {
  6. for i := 0; i < net.IPv4len; i++ {
  7. if len(s) == 0 {
  8. return false
  9. }
  10. if i > 0 {
  11. if s[0] != '.' {
  12. return false
  13. }
  14. s = s[1:]
  15. }
  16. n, ci := 0, 0
  17. for ci = 0; ci < len(s) && '0' <= s[ci] && s[ci] <= '9'; ci++ {
  18. n = n*10 + int(s[ci]-'0')
  19. if n >= 0xFF {
  20. return false
  21. }
  22. }
  23. if ci == 0 || n > 0xFF || (ci > 1 && s[0] == '0') {
  24. return false
  25. }
  26. s = s[ci:]
  27. }
  28. return len(s) == 0
  29. }
  30. // IsIPv6 works the same way as net.ParseIP,
  31. // but without check for IPv4 case and without returning net.IP slice, whereby IsIPv6 makes no allocations.
  32. func IsIPv6(s string) bool {
  33. ellipsis := -1 // position of ellipsis in ip
  34. // Might have leading ellipsis
  35. if len(s) >= 2 && s[0] == ':' && s[1] == ':' {
  36. ellipsis = 0
  37. s = s[2:]
  38. // Might be only ellipsis
  39. if len(s) == 0 {
  40. return true
  41. }
  42. }
  43. // Loop, parsing hex numbers followed by colon.
  44. i := 0
  45. for i < net.IPv6len {
  46. // Hex number.
  47. n, ci := 0, 0
  48. for ci = 0; ci < len(s); ci++ {
  49. if '0' <= s[ci] && s[ci] <= '9' {
  50. n *= 16
  51. n += int(s[ci] - '0')
  52. } else if 'a' <= s[ci] && s[ci] <= 'f' {
  53. n *= 16
  54. n += int(s[ci]-'a') + 10
  55. } else if 'A' <= s[ci] && s[ci] <= 'F' {
  56. n *= 16
  57. n += int(s[ci]-'A') + 10
  58. } else {
  59. break
  60. }
  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. }