chore: baseline snapshot before moderation-strictness feature

Repo .git was damaged (refs/ missing, index truncated, object store near-empty).
Repaired via git init (rebuilt refs), stale index preserved as .git/index.corrupt-20260910.bak,
then full worktree committed as a rollback baseline.
This commit is contained in:
tamakyi
2026-09-10 10:56:27 +08:00
commit e3e59e7c69
296 changed files with 67458 additions and 0 deletions
+84
View File
@@ -0,0 +1,84 @@
// Package ipinfo 识别 IP 的网络归属(CDN / 云厂商 / WAF)。
// 基于 projectdiscovery/cdncheck 的离线签名(编译期嵌入,上游每周更新指纹),
// 判定过程零外部网络请求,适合 1C1G 小型服务器与告警链路使用。
// 当前用于安全告警邮件:展示扫描来源的网络归属,帮助管理员判断告警严重性。
package ipinfo
import (
"fmt"
"net"
"strings"
"sync"
"github.com/projectdiscovery/cdncheck"
)
var (
clientOnce sync.Once
client *cdncheck.Client
)
// getClient 懒加载判定客户端(签名数据编译期嵌入,New 无错误返回)。
func getClient() *cdncheck.Client {
clientOnce.Do(func() {
client = cdncheck.New()
})
return client
}
// Lookup 判定 IP 的网络归属。
// 返回:
// - label:展示用标签,如 "Cloudflare(CDN)"、"亚马逊(云厂商)";
// 未命中返回 "未识别(普通网络)",输入非法或判定出错返回 "识别失败"。
// - proxied:IP 是否属于 CDN/WAF/代理网络(用于提示"封禁可能无法拦截真实来源")。
//
// 任何内部错误都被折叠为展示标签,不向调用方传播——告警链路不应因归属识别失败而中断。
func Lookup(ipStr string) (label string, proxied bool) {
ip := net.ParseIP(strings.TrimSpace(ipStr))
if ip == nil {
return "识别失败(IP 格式异常)", false
}
matched, value, itemType, err := getClient().Check(ip)
if err != nil {
return "识别失败", false
}
if !matched || value == "" {
return "未识别(普通网络)", false
}
return fmt.Sprintf("%s(%s)", title(value), typeLabel(itemType)), true
}
// typeLabel 将 cdncheck 的 itemType 翻译为中文展示。
func typeLabel(itemType string) string {
switch itemType {
case "cdn":
return "CDN"
case "waf":
return "WAF"
case "cloud":
return "云厂商"
default:
return "未知类型"
}
}
// acronymProviders 需要保持全大写的提供商缩写(cdncheck 返回全小写,如 aws → AWS)。
var acronymProviders = map[string]bool{
"aws": true, "gcp": true, "oci": true, "gds": true, "ovh": true,
}
// title 将提供商名转为展示形式:缩写全大写(aws → AWS),其余首字母大写
// (cloudflare → Cloudflare)。
func title(s string) string {
if s == "" {
return s
}
lower := strings.ToLower(s)
if acronymProviders[lower] {
return strings.ToUpper(lower)
}
r := []rune(lower)
return strings.ToUpper(string(r[0])) + string(r[1:])
}
+27
View File
@@ -0,0 +1,27 @@
package ipinfo
import "testing"
// TestLookupInvalidIP 非法输入必须折叠为展示标签且不 panic,proxied 恒为 false。
func TestLookupInvalidIP(t *testing.T) {
for _, in := range []string{"", "not-an-ip", "999.1.1.1", " "} {
label, proxied := Lookup(in)
if proxied {
t.Errorf("Lookup(%q) proxied = true, want false", in)
}
if label == "" {
t.Errorf("Lookup(%q) label is empty, want a fallback label", in)
}
}
}
// TestLookupReturnsLabel 合法 IP 应返回非空标签且不 panic(不锁定具体归属,
// 避免上游签名快照更新导致测试抖动)。
func TestLookupReturnsLabel(t *testing.T) {
for _, in := range []string{"1.1.1.1", "8.8.8.8", "2606:4700:4700::1111"} {
label, _ := Lookup(in)
if label == "" {
t.Errorf("Lookup(%q) label is empty", in)
}
}
}