Files
SamWaf/utils/common.go
2024-12-02 08:22:16 +08:00

369 lines
8.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package utils
import (
"SamWaf/common/zlog"
"SamWaf/global"
"SamWaf/model"
"fmt"
"github.com/lionsoul2014/ip2region/binding/golang/xdb"
"github.com/oschwald/geoip2-golang"
"io/ioutil"
"net"
"net/http"
"os"
"path/filepath"
"strconv"
"strings"
"time"
)
func GetExternalIp() string {
resp, err := http.Get("http://myexternalip.com/raw")
if err != nil {
return ""
}
defer resp.Body.Close()
//io.Copy(os.Stdout, resp.Body)
body, _ := ioutil.ReadAll(resp.Body)
clientIP := fmt.Sprintf("%s", string(body))
return clientIP
}
func GetCurrentDir() string {
// 检测环境变量是否存在
envVar := "SamWafIDE"
if value, exists := os.LookupEnv(envVar); exists {
zlog.Info("当前在IDE,环境变量", value)
return "."
}
exePath, err := os.Executable()
if err != nil {
zlog.Error("Failed to get executable path:", err)
return ""
}
zlog.Info("当前程序所在文件位置", exePath)
exeDir := filepath.Dir(exePath)
return exeDir
}
func GetServerByHosts(hosts model.Hosts) string {
if hosts.Ssl == 1 {
return "https"
} else {
return "http"
}
}
/*
*
计算两个自然天数的间隔数
*/
func DiffNatureDays(t1, t2 int64) int {
var SecondsOfDay int64 = 86400
if t1 == t2 {
return -1
}
if t1 > t2 {
t1, t2 = t2, t1
}
diffDays := 0
secDiff := t2 - t1
if secDiff > SecondsOfDay {
tmpDays := int(secDiff / SecondsOfDay)
t1 += int64(tmpDays) * SecondsOfDay
diffDays += tmpDays
}
st := time.Unix(t1, 0)
et := time.Unix(t2, 0)
dateFormatTpl := "20060102"
if st.Format(dateFormatTpl) != et.Format(dateFormatTpl) {
diffDays += 1
}
return diffDays
}
/**字符串->时间对象*/
func Str2Time(formatTimeStr string) time.Time {
timeLayout := "20060102"
loc, _ := time.LoadLocation("Local")
theTime, _ := time.ParseInLocation(timeLayout, formatTimeStr, loc) //使用模板在对应时区转化为time.time类型
return theTime
}
/*
*
时间转int天
*/
func TimeToDayInt(t time.Time) int {
day, _ := strconv.Atoi(t.Format("20060102"))
return day
}
func GetPublicIP() string {
conn, err := net.Dial("udp", "8.8.8.8:80")
if err != nil {
return "localhost"
// log.Fatal(err)
}
defer conn.Close()
localAddr := conn.LocalAddr().String()
idx := strings.LastIndex(localAddr, ":")
return localAddr[0:idx]
}
func GetCountry(ip string) []string {
if IsValidIPv6(ip) {
a := "ipv6|ipv6|ipv6|ipv6|ipv6"
if global.GCACHE_IPV6_SEARCHER == nil {
db, err := geoip2.FromBytes(global.GCACHE_IP_V6_COUNTRY_CBUFF)
if err != nil {
zlog.Error("Failed to open GeoLite2-Country.mmdb:", err)
return strings.Split(a, "|")
}
global.GCACHE_IPV6_SEARCHER = db
}
ipv6 := net.ParseIP(ip)
record, err := global.GCACHE_IPV6_SEARCHER.Country(ipv6)
if err != nil {
zlog.Error("Failed to Search GeoLite2-Country.mmdb:", err)
return strings.Split(a, "|")
}
if record.Country.Names == nil {
a = "内网" + "||||"
} else {
a = record.Country.Names["zh-CN"] + "||||"
}
return strings.Split(a, "|")
}
//IPV4得查询逻辑
if global.GCACHE_IPV4_SEARCHER == nil {
// 2、用全局的 cBuff 创建完全基于内存的查询对象。
searcher, err := xdb.NewWithBuffer(global.GCACHE_IP_CBUFF)
if err != nil {
fmt.Printf("failed to create searcher with content: %s\n", err)
}
global.GCACHE_IPV4_SEARCHER = searcher
}
// do the search
var tStart = time.Now()
// 备注:并发使用,每个 goroutine 需要创建一个独立的 searcher 对象。
region, err := global.GCACHE_IPV4_SEARCHER.SearchByStr(ip)
if err != nil {
fmt.Printf("failed to SearchIP(%s): %s\n", ip, err)
return []string{"无", "无"}
}
zlog.Debug("{region: %s, took: %s}\n", region, time.Since(tStart))
regions := strings.Split(region, "|")
//如果是内网IP情况下显示内网的内容
if regions[4] == "内网IP" {
regions[0] = "内网"
regions[1] = "内网"
regions[2] = "内网"
}
return regions
}
// CloseIPDatabase 关闭IP数据库
func CloseIPDatabase() {
if global.GCACHE_IPV4_SEARCHER != nil {
global.GCACHE_IPV4_SEARCHER.Close()
}
if global.GCACHE_IPV6_SEARCHER != nil {
err := global.GCACHE_IPV6_SEARCHER.Close()
if err != nil {
return
}
}
}
// PortCheck 检查端口是否可用,可用-true 不可用-false
func PortCheck(port int) bool {
conn, err := net.DialTimeout("tcp", fmt.Sprintf(":%d", port), time.Second)
if err != nil {
return true // Port is available
}
defer conn.Close()
return false // Port is not available
}
/*
*
通过ip段CIDR来查询是否在很多CIDR段内
*/
func CheckIPInRanges(ip string, ipRanges []string) bool {
parsedIP := net.ParseIP(ip)
if parsedIP == nil {
return false // 如果IP地址解析失败则返回false
}
for _, ipRange := range ipRanges {
_, ipNet, err := net.ParseCIDR(ipRange)
if err != nil {
return false // 如果CIDR格式解析失败则返回false
}
if ipNet.Contains(parsedIP) {
return true // 如果IP地址在指定的CIDR范围内则返回true
}
}
return false // 如果IP地址不在任何一个CIDR范围内则返回false
}
/*
*
通过ip段CIDR来查询是否在这个段内
*/
func CheckIPInCIDR(ip string, ipRange string) bool {
parts := strings.Split(ipRange, "/")
if len(parts) != 2 {
// 如果是普通ip
if ip == ipRange {
return true
} else {
return false
}
} else {
//如果是网段IP
parsedIP := net.ParseIP(ip)
if parsedIP == nil {
return false // 如果IP地址解析失败则返回false
}
_, ipNet, err := net.ParseCIDR(ipRange)
if err != nil {
return false // 如果CIDR格式解析失败则返回false
}
if ipNet.Contains(parsedIP) {
return true // 如果IP地址在指定的CIDR范围内则返回true
}
return false // 如果IP地址不在任何一个CIDR范围内则返回false
}
}
// IsValidIPOrNetwork 检查给定的字符串是否为有效的 IP 地址或 IP 段CIDR
func IsValidIPOrNetwork(input string) (bool, string) {
// 尝试解析为 IP 地址
if ip := net.ParseIP(input); ip != nil {
return true, "valid IP address"
}
// 尝试解析为 IP 段CIDR
_, _, err := net.ParseCIDR(input)
if err == nil {
return true, "valid IP network (CIDR)"
}
return false, "not a valid IP or IP network (CIDR)"
}
// 检查 JSON 字符串是否为有效的 UTF-8 编码
func CheckJSONValidity(jsonStr []byte) bool {
for i := 0; i < len(jsonStr); {
r, size := rune(jsonStr[i]), 1
switch {
case r >= 0xF0:
r, size = rune(jsonStr[i+3]), 4
case r >= 0xE0:
r, size = rune(jsonStr[i+2]), 3
case r >= 0xC0:
r, size = rune(jsonStr[i+1]), 2
default:
}
if r > 0xFFFF {
return false
}
i += size
}
return true
}
/*
*
删除老旧数据
*/
func DeleteOldFiles(dir string, duration time.Duration) error {
// 遍历目录下的文件
return filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
// 如果是文件并且文件创建时间超过指定的时间
if !info.IsDir() {
// 获取文件的修改时间(可以近似认为是创建时间)
fileModTime := info.ModTime()
// 判断文件是否超过指定的时间比如30分钟
if time.Since(fileModTime) > duration {
// 删除文件
zlog.Info("删除陈旧文件:", path)
err := os.Remove(path)
if err != nil {
return err
}
}
}
return nil
})
}
// 检测是否属于ipv4
func IsValidIPv4(ip string) bool {
parsedIP := net.ParseIP(ip)
return parsedIP != nil && parsedIP.To4() != nil
}
// 验证IPv6地址是否有效
func IsValidIPv6(ip string) bool {
parsedIP := net.ParseIP(ip)
// 如果解析出的 IP 类型是 IPv6 且不是 IPv4 映射地址IPv4-mapped IPv6 addresses
return parsedIP != nil && strings.Contains(ip, ":") && parsedIP.To4() == nil
}
// 获取纯域名
func GetPureDomain(host string) string {
// 检查是否包含端口号
if strings.Contains(host, ":") {
host, _, _ = net.SplitHostPort(host)
}
return host
}
// UpdateFileIsHasNewInfo 检查文件内容并更新
func UpdateFileIsHasNewInfo(filePath, newContent string) error {
// 检查文件是否存在
if _, err := os.Stat(filePath); os.IsNotExist(err) {
// 文件不存在,写入新内容
if err := ioutil.WriteFile(filePath, []byte(newContent), 0644); err != nil {
return fmt.Errorf("failed to write file %s: %v", filePath, err)
}
} else {
// 文件存在,读取当前内容
currentContent, err := ioutil.ReadFile(filePath)
if err != nil {
return fmt.Errorf("failed to read file %s: %v", filePath, err)
}
// 比较内容是否一致
if string(currentContent) != newContent {
// 内容不一致,更新文件
if err := ioutil.WriteFile(filePath, []byte(newContent), 0644); err != nil {
return fmt.Errorf("failed to update file %s: %v", filePath, err)
}
}
}
return nil
}