广告平台(站长使用)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

147 line
3.4 KiB

  1. package utils
  2. import (
  3. "errors"
  4. "math"
  5. "net"
  6. "net/http"
  7. "strings"
  8. )
  9. func GetIP(r *http.Request) string {
  10. ip := ClientPublicIP(r)
  11. if ip == "" {
  12. ip = ClientIP(r)
  13. }
  14. if ip == "" {
  15. ip = "0000"
  16. }
  17. return ip
  18. }
  19. // HasLocalIPddr 检测 IP 地址字符串是否是内网地址
  20. // Deprecated: 此为一个错误名称错误拼写的函数,计划在将来移除,请使用 HasLocalIPAddr 函数
  21. func HasLocalIPddr(ip string) bool {
  22. return HasLocalIPAddr(ip)
  23. }
  24. // HasLocalIPAddr 检测 IP 地址字符串是否是内网地址
  25. func HasLocalIPAddr(ip string) bool {
  26. return HasLocalIP(net.ParseIP(ip))
  27. }
  28. // HasLocalIP 检测 IP 地址是否是内网地址
  29. // 通过直接对比ip段范围效率更高,详见:https://github.com/thinkeridea/go-extend/issues/2
  30. func HasLocalIP(ip net.IP) bool {
  31. if ip.IsLoopback() {
  32. return true
  33. }
  34. ip4 := ip.To4()
  35. if ip4 == nil {
  36. return false
  37. }
  38. return ip4[0] == 10 || // 10.0.0.0/8
  39. (ip4[0] == 172 && ip4[1] >= 16 && ip4[1] <= 31) || // 172.16.0.0/12
  40. (ip4[0] == 169 && ip4[1] == 254) || // 169.254.0.0/16
  41. (ip4[0] == 192 && ip4[1] == 168) // 192.168.0.0/16
  42. }
  43. // ClientIP 尽最大努力实现获取客户端 IP 的算法。
  44. // 解析 X-Real-IP 和 X-Forwarded-For 以便于反向代理(nginx 或 haproxy)可以正常工作。
  45. func ClientIP(r *http.Request) string {
  46. ip := strings.TrimSpace(strings.Split(r.Header.Get("X-Forwarded-For"), ",")[0])
  47. if ip != "" {
  48. return ip
  49. }
  50. ip = strings.TrimSpace(r.Header.Get("X-Real-Ip"))
  51. if ip != "" {
  52. return ip
  53. }
  54. if ip, _, err := net.SplitHostPort(strings.TrimSpace(r.RemoteAddr)); err == nil {
  55. return ip
  56. }
  57. return ""
  58. }
  59. // ClientPublicIP 尽最大努力实现获取客户端公网 IP 的算法。
  60. // 解析 X-Real-IP 和 X-Forwarded-For 以便于反向代理(nginx 或 haproxy)可以正常工作。
  61. func ClientPublicIP(r *http.Request) string {
  62. var ip string
  63. for _, ip = range strings.Split(r.Header.Get("X-Forwarded-For"), ",") {
  64. if ip = strings.TrimSpace(ip); ip != "" && !HasLocalIPAddr(ip) {
  65. return ip
  66. }
  67. }
  68. if ip = strings.TrimSpace(r.Header.Get("X-Real-Ip")); ip != "" && !HasLocalIPAddr(ip) {
  69. return ip
  70. }
  71. if ip = RemoteIP(r); !HasLocalIPAddr(ip) {
  72. return ip
  73. }
  74. return ""
  75. }
  76. // RemoteIP 通过 RemoteAddr 获取 IP 地址, 只是一个快速解析方法。
  77. func RemoteIP(r *http.Request) string {
  78. ip, _, _ := net.SplitHostPort(r.RemoteAddr)
  79. return ip
  80. }
  81. // IPString2Long 把ip字符串转为数值
  82. func IPString2Long(ip string) (uint, error) {
  83. b := net.ParseIP(ip).To4()
  84. if b == nil {
  85. return 0, errors.New("invalid ipv4 format")
  86. }
  87. return uint(b[3]) | uint(b[2])<<8 | uint(b[1])<<16 | uint(b[0])<<24, nil
  88. }
  89. // Long2IPString 把数值转为ip字符串
  90. func Long2IPString(i uint) (string, error) {
  91. if i > math.MaxUint32 {
  92. return "", errors.New("beyond the scope of ipv4")
  93. }
  94. ip := make(net.IP, net.IPv4len)
  95. ip[0] = byte(i >> 24)
  96. ip[1] = byte(i >> 16)
  97. ip[2] = byte(i >> 8)
  98. ip[3] = byte(i)
  99. return ip.String(), nil
  100. }
  101. // IP2Long 把net.IP转为数值
  102. func IP2Long(ip net.IP) (uint, error) {
  103. b := ip.To4()
  104. if b == nil {
  105. return 0, errors.New("invalid ipv4 format")
  106. }
  107. return uint(b[3]) | uint(b[2])<<8 | uint(b[1])<<16 | uint(b[0])<<24, nil
  108. }
  109. // Long2IP 把数值转为net.IP
  110. func Long2IP(i uint) (net.IP, error) {
  111. if i > math.MaxUint32 {
  112. return nil, errors.New("beyond the scope of ipv4")
  113. }
  114. ip := make(net.IP, net.IPv4len)
  115. ip[0] = byte(i >> 24)
  116. ip[1] = byte(i >> 16)
  117. ip[2] = byte(i >> 8)
  118. ip[3] = byte(i)
  119. return ip, nil
  120. }