diff options
| author | Loyalsoldier <[email protected]> | 2025-01-31 12:13:04 +0800 |
|---|---|---|
| committer | Loyalsoldier <[email protected]> | 2025-01-31 12:47:42 +0800 |
| commit | d9ccff71c634dae0ed85608d37b2d0c2d732fa1a (patch) | |
| tree | c2be47037421000cd05e1bd08d0c3aadbb47ba6f | |
| parent | ebc3b252c97455b32f1cdb3fbba92fff6d6fe6c9 (diff) | |
Feat: support to generate pure ASN data202501310448
when using maxmindGeoLite2ASNCSV as input format
| -rw-r--r-- | configuration.md | 52 | ||||
| -rw-r--r-- | lib/common.go | 28 | ||||
| -rw-r--r-- | plugin/maxmind/maxmind_asn_csv_in.go | 60 |
3 files changed, 121 insertions, 19 deletions
diff --git a/configuration.md b/configuration.md index da1bfaae..b62f5ae0 100644 --- a/configuration.md +++ b/configuration.md @@ -328,10 +328,10 @@ - **type**:(必须)输入格式的名称 - **action**:(必须)操作类型,值为 `add`(添加 IP 地址)或 `remove`(移除 IP 地址) -- **args**:(必须) +- **args**:(可选) - **ipv4**:(可选)MaxMind GeoLite2 ASN IPv4 文件路径(`GeoLite2-ASN-Blocks-IPv4.csv`),可为本地文件路径或远程 `http`、`https` 文件 URL。 - **ipv6**:(可选)MaxMind GeoLite2 ASN IPv6 文件路径(`GeoLite2-ASN-Blocks-IPv6.csv`),可为本地文件路径或远程 `http`、`https` 文件 URL。 - - **wantedList**:(必须,对象,键为字符串类别名,值为 ASN 字符串数组)指定类别名及其包含的 ASN。 + - **wantedList**:(可选,数组或对象;当为数组时,值为 ASN 字符串;当为对象时,键为类别名,值为 ASN 字符串数组)指定 ASN 或类别名及其包含的 ASN。若未指定,则默认选择所有 ASN。 - **onlyIPType**:(可选)只处理的 IP 地址类型,值为 `ipv4` 或 `ipv6`。 ```jsonc @@ -366,6 +366,54 @@ } ``` +```jsonc +// 由于未指定 `wantedList`,自动将所有 ASN 添加为类别,类别名格式为 AS + ASN 字符串,如 `AS123`、`AS12345` +{ + "type": "maxmindGeoLite2ASNCSV", + "action": "add" // 添加 IP 地址 +} +``` + +```jsonc +// 由于未指定 `wantedList`,自动将所有 ASN 添加为类别,类别名格式为 AS + ASN 字符串,如 `AS123`、`AS12345` +{ + "type": "maxmindGeoLite2ASNCSV", + "action": "add", // 添加 IP 地址 + "args": { + "onlyIPType": "ipv4" // 只添加各自的 IPv4 地址 + } +} +``` + +```jsonc +// 由于未指定 `wantedList`,自动移除所有匹配的 ASN 类别,匹配的类别名格式为 AS + ASN 字符串,如 `AS123`、`AS12345` +{ + "type": "maxmindGeoLite2ASNCSV", + "action": "remove" // 移除 IP 地址 +} +``` + +```jsonc +{ + "type": "maxmindGeoLite2ASNCSV", + "action": "add", // 添加 IP 地址 + "args": { + "wantedList": ["AS123", "AS4567"] // 向名为 AS123 和 AS4567 的类别中分别添加各自的 IPv4 和 IPv6 地址 + } +} +``` + +```jsonc +{ + "type": "maxmindGeoLite2ASNCSV", + "action": "remove", // 移除 IP 地址 + "args": { + "wantedList": ["AS123", "AS4567"], // 从名为 AS123 和 AS4567 的类别中分别移除各自的 IPv6 地址 + "onlyIPType": "ipv6" + } +} +``` + ### **maxmindGeoLite2CountryCSV** - **type**:(必须)输入格式的名称 diff --git a/lib/common.go b/lib/common.go index 51fd6b24..ed7c2e02 100644 --- a/lib/common.go +++ b/lib/common.go @@ -1,6 +1,7 @@ package lib import ( + "encoding/json" "fmt" "io" "net/http" @@ -32,3 +33,30 @@ func GetRemoteURLReader(url string) (io.ReadCloser, error) { return resp.Body, nil } + +type WantedListExtended struct { + TypeSlice []string + TypeMap map[string][]string +} + +func (w *WantedListExtended) UnmarshalJSON(data []byte) error { + if len(data) == 0 { + return nil + } + + slice := make([]string, 0) + mapMap := make(map[string][]string, 0) + + err := json.Unmarshal(data, &slice) + if err != nil { + err2 := json.Unmarshal(data, &mapMap) + if err2 != nil { + return err2 + } + } + + w.TypeSlice = slice + w.TypeMap = mapMap + + return nil +} diff --git a/plugin/maxmind/maxmind_asn_csv_in.go b/plugin/maxmind/maxmind_asn_csv_in.go index 39d1e76a..8c8c3fe2 100644 --- a/plugin/maxmind/maxmind_asn_csv_in.go +++ b/plugin/maxmind/maxmind_asn_csv_in.go @@ -33,10 +33,10 @@ func init() { func newGeoLite2ASNCSV(action lib.Action, data json.RawMessage) (lib.InputConverter, error) { var tmp struct { - IPv4File string `json:"ipv4"` - IPv6File string `json:"ipv6"` - Want map[string][]string `json:"wantedList"` - OnlyIPType lib.IPType `json:"onlyIPType"` + IPv4File string `json:"ipv4"` + IPv6File string `json:"ipv6"` + Want lib.WantedListExtended `json:"wantedList"` + OnlyIPType lib.IPType `json:"onlyIPType"` } if len(data) > 0 { @@ -53,8 +53,9 @@ func newGeoLite2ASNCSV(action lib.Action, data json.RawMessage) (lib.InputConver } // Filter want list - wantList := make(map[string][]string) // map[asn][]listname - for list, asnList := range tmp.Want { + wantList := make(map[string][]string) // map[asn][]listname or map[asn][]asn + + for list, asnList := range tmp.Want.TypeMap { list = strings.ToUpper(strings.TrimSpace(list)) if list == "" { continue @@ -75,8 +76,13 @@ func newGeoLite2ASNCSV(action lib.Action, data json.RawMessage) (lib.InputConver } } - if len(wantList) == 0 { - return nil, fmt.Errorf("❌ [type %s | action %s] wantedList must be specified in config", TypeASNCSV, action) + for _, asn := range tmp.Want.TypeSlice { + asn = strings.TrimPrefix(strings.ToLower(strings.TrimSpace(asn)), "as") + if asn == "" { + continue + } + + wantList[asn] = []string{"AS" + asn} } return &GeoLite2ASNCSV{ @@ -192,16 +198,36 @@ func (g *GeoLite2ASNCSV) process(file string, entries map[string]*lib.Entry) err return fmt.Errorf("❌ [type %s | action %s] invalid record: %v", g.Type, g.Action, record) } - if listArr, found := g.Want[strings.TrimSpace(record[1])]; found { - for _, listName := range listArr { - entry, got := entries[listName] - if !got { - entry = lib.NewEntry(listName) - } - if err := entry.AddPrefix(strings.TrimSpace(record[0])); err != nil { - return err + // Maxmind ASN CSV reference: + // network,autonomous_system_number,autonomous_system_organization + // 1.0.0.0/24,13335,CLOUDFLARENET + // 1.0.4.0/22,38803,"Gtelecom Pty Ltd" + // 1.0.16.0/24,2519,"ARTERIA Networks Corporation" + + switch len(g.Want) { + case 0: // it means user wants all ASNs + asn := "AS" + strings.TrimSpace(record[1]) // default list name is in "AS12345" format + entry, got := entries[asn] + if !got { + entry = lib.NewEntry(asn) + } + if err := entry.AddPrefix(strings.TrimSpace(record[0])); err != nil { + return err + } + entries[asn] = entry + + default: // it means user wants specific ASNs or customized lists with specific ASNs + if listArr, found := g.Want[strings.TrimSpace(record[1])]; found { + for _, listName := range listArr { + entry, got := entries[listName] + if !got { + entry = lib.NewEntry(listName) + } + if err := entry.AddPrefix(strings.TrimSpace(record[0])); err != nil { + return err + } + entries[listName] = entry } - entries[listName] = entry } } } |
