Skip to content

Commit

Permalink
Feat: support DB-IP country mmdb format as input & output
Browse files Browse the repository at this point in the history
Download DB-IP free country lite mmdb file here: https://db-ip.com/db/download/ip-to-country-lite
  • Loading branch information
Loyalsoldier committed Nov 3, 2024
1 parent 2e70d7f commit b7daf13
Show file tree
Hide file tree
Showing 10 changed files with 347 additions and 94 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,10 @@ $RECYCLE.BIN/
tmp/
data/
geolite2/
db-ip/
output/
geoip
*.dat
*.mmdb
*.srs
*.mrs
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,7 @@ These two concepts are notable: `input` and `output`. The `input` is the data so
- **maxmindMMDB**:MaxMind GeoLite2 country mmdb 数据格式(`GeoLite2-Country.mmdb`)
- **maxmindGeoLite2ASNCSV**:MaxMind GeoLite2 ASN CSV 数据格式(`GeoLite2-ASN-CSV.zip`)
- **maxmindGeoLite2CountryCSV**:MaxMind GeoLite2 country CSV 数据格式(`GeoLite2-Country-CSV.zip`)
- **dbipCountryMMDB**:DB-IP country mmdb 数据格式(`dbip-country-lite.mmdb`)
- **mihomoMRS**:mihomo MRS 数据格式(`geoip-cn.mrs`)
- **singboxSRS**:sing-box SRS 数据格式(`geoip-cn.srs`)
- **clashRuleSetClassical**:[classical 类型的 Clash RuleSet](https://github.com/Dreamacro/clash/wiki/premium-core-features#classical)
Expand All @@ -474,6 +475,7 @@ These two concepts are notable: `input` and `output`. The `input` is the data so
- **lookup**:从指定的列表中查找指定的 IP 或 CIDR
- **v2rayGeoIPDat**:V2Ray GeoIP dat 数据格式(`geoip.dat`)
- **maxmindMMDB**:MaxMind GeoLite2 country mmdb 数据格式(`GeoLite2-Country.mmdb`)
- **dbipCountryMMDB**:DB-IP country mmdb 数据格式(`dbip-country-lite.mmdb`)
- **mihomoMRS**:mihomo MRS 数据格式(`geoip-cn.mrs`)
- **singboxSRS**:sing-box SRS 数据格式(`geoip-cn.srs`)
- **clashRuleSetClassical**:[classical 类型的 Clash RuleSet](https://github.com/Dreamacro/clash/wiki/premium-core-features#classical)
Expand Down Expand Up @@ -527,6 +529,7 @@ All available input formats:
- clashRuleSet (Convert ipcidr type of Clash RuleSet to other formats)
- clashRuleSetClassical (Convert classical type of Clash RuleSet to other formats (just processing IP & CIDR lines))
- cutter (Remove data from previous steps)
- dbipCountryMMDB (Convert DB-IP country mmdb database to other formats)
- json (Convert JSON data to other formats)
- maxmindGeoLite2ASNCSV (Convert MaxMind GeoLite2 ASN CSV data to other formats)
- maxmindGeoLite2CountryCSV (Convert MaxMind GeoLite2 country CSV data to other formats)
Expand All @@ -543,6 +546,7 @@ All available input formats:
All available output formats:
- clashRuleSet (Convert data to ipcidr type of Clash RuleSet)
- clashRuleSetClassical (Convert data to classical type of Clash RuleSet)
- dbipCountryMMDB (Convert data to DB-IP country mmdb database format)
- lookup (Lookup specified IP or CIDR from various formats of data)
- maxmindMMDB (Convert data to MaxMind mmdb database format)
- mihomoMRS (Convert data to mihomo MRS format)
Expand Down
151 changes: 151 additions & 0 deletions configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
- **clashRuleSet**:ipcidr 类型的 Clash RuleSet
- **clashRuleSetClassical**:classical 类型的 Clash RuleSet
- **cutter**:用于裁剪前置步骤中的数据
- **dbipCountryMMDB**:DB-IP country mmdb 数据格式(`dbip-country-lite.mmdb`
- **json**:JSON 数据格式
- **maxmindGeoLite2ASNCSV**:MaxMind GeoLite2 ASN CSV 数据格式(`GeoLite2-ASN-CSV.zip`
- **maxmindGeoLite2CountryCSV**:MaxMind GeoLite2 country CSV 数据格式(`GeoLite2-Country-CSV.zip`
Expand All @@ -34,6 +35,7 @@

- **clashRuleSet**:ipcidr 类型的 Clash RuleSet
- **clashRuleSetClassical**:classical 类型的 Clash RuleSet
- **dbipCountryMMDB**:DB-IP country mmdb 数据格式(`dbip-country-lite.mmdb`
- **lookup**:从指定的列表中查找指定的 IP 或 CIDR
- **maxmindMMDB**:MaxMind GeoLite2 country mmdb 数据格式(`GeoLite2-Country.mmdb`
- **mihomoMRS**:mihomo MRS 数据格式(`geoip-cn.mrs`
Expand Down Expand Up @@ -166,6 +168,58 @@
}
```

### **dbipCountryMMDB**

- **type**:(必须)输入格式的名称
- **action**:(必须)操作类型,值为 `add`(添加 IP 地址)或 `remove`(移除 IP 地址)
- **args**:(可选)
- **uri**:(可选)DB-IP country MMDB 格式文件路径,可为本地文件路径或远程 `http``https` 文件 URL。
- **wantedList**:(可选)指定需要的类别/文件。
- **onlyIPType**:(可选)只处理的 IP 地址类型,值为 `ipv4``ipv6`

```jsonc
// 默认使用文件:
// ./db-ip/dbip-country-lite.mmdb
{
"type": "dbipCountryMMDB",
"action": "add" // 添加 IP 地址
}
```

```jsonc
{
"type": "dbipCountryMMDB",
"action": "add", // 添加 IP 地址
"args": {
"uri": "./db-ip/dbip-country-lite.mmdb"
}
}
```

```jsonc
{
"type": "dbipCountryMMDB",
"action": "add", // 添加 IP 地址
"args": {
"uri": "https://example.com/my.mmdb",
"wantedList": ["cn", "us", "jp"], // 只需要名为 cn、us、jp 的类别
"onlyIPType": "ipv4" // 只添加 IPv4 地址
}
}
```

```jsonc
{
"type": "dbipCountryMMDB",
"action": "remove", // 添加 IP 地址
"args": {
"uri": "https://example.com/my.mmdb",
"wantedList": ["cn", "us", "jp"], // 只移除名为 cn、us、jp 这三个类别的 IPv4 地址
"onlyIPType": "ipv4" // 只移除 IPv4 地址
}
}
```

### **json**

- **type**:(必须)输入格式的名称
Expand Down Expand Up @@ -854,6 +908,103 @@
}
```

### **dbipCountryMMDB**

- **type**:(必须)输入格式的名称
- **action**:(必须)操作类型,值必须为 `output`
- **args**:(可选)
- **outputName**:(可选)输出的文件名
- **outputDir**:(可选)输出目录
- **onlyIPType**:(可选)输出的 IP 地址类型,值为 `ipv4``ipv6`
- **wantedList**:(可选,数组)指定需要输出的类别
- **excludedList**:(可选,数组)指定不需要输出的类别
- **overwriteList**:(可选,数组)指定最后写入的类别(原因见👇)

> 由于 DB-IP mmdb 文件格式的限制,当不同列表的 IP 或 CIDR 数据有交集或重复项时,后写入的列表的 IP 或 CIDR 数据会覆盖(overwrite)之前已写入的列表的数据。譬如,IP `1.1.1.1` 同属于列表 `AU` 和列表 `Cloudflare`。如果 `Cloudflare``AU` 之后写入,则 IP `1.1.1.1` 最终归属于列表 `Cloudflare`
>
> 为了确保某些指定的列表、被修改的列表一定囊括属于它的所有 IP 或 CIDR 数据,可在 output 输出格式为 `dbipCountryMMDB` 的配置中增加选项 `overwriteList`,该选项中指定的列表会在最后逐一写入,列表中最后一项优先级最高。若已设置选项 `wantedList`,则无需设置 `overwriteList``wantedList` 中指定的列表会在最后逐一写入,列表中最后一项优先级最高。
>
> `wantedList``overwriteList``excludedList` 三者中,`excludedList` 优先级最高。即:若设置了选项 `excludedList`,最终不会输出存在于 `excludedList` 中的列表。
```jsonc
// 默认输出目录 ./output/db-ip
{
"type": "dbipCountryMMDB",
"action": "output"
}
```

```jsonc
{
"type": "dbipCountryMMDB",
"action": "output",
"args": {
"outputDir": "./output", // 输出文件到 output 目录
"outputName": "Country-only-cn-private.mmdb", // 输出文件名为 Country-only-cn-private.mmdb
"wantedList": ["cn", "private"] // 只输出 cn、private 类别
}
}
```

```jsonc
{
"type": "dbipCountryMMDB",
"action": "output",
"args": {
"outputDir": "./output", // 输出文件到 output 目录
"outputName": "Country-without-cn-private.mmdb", // 输出文件名为 Country-without-cn-private.mmdb
"excludedList": ["cn", "private"] // 不输出 cn、private 类别
}
}
```

```jsonc
{
"type": "dbipCountryMMDB",
"action": "output",
"args": {
"outputName": "Country.mmdb", // 输出文件名为 Country.mmdb
"overwriteList": ["cn", "google"] // 确保 cn、google 类别最后写入,且 google 比 cn 后写入
}
}
```

```jsonc
{
"type": "dbipCountryMMDB",
"action": "output",
"args": {
"outputName": "Country.mmdb", // 输出文件名为 Country.mmdb
"overwriteList": ["cn", "google"], // 确保 cn、google 类别最后写入,且 google 比 cn 后写入
"onlyIPType": "ipv4" // 只输出 cn、private 类别的 IPv4 地址
}
}
```

```jsonc
{
"type": "dbipCountryMMDB",
"action": "output",
"args": {
"outputName": "Country.mmdb", // 输出文件名为 Country.mmdb
"excludedList": ["private"], // 最终不输出 private 类别
"wantedList": ["private" ,"au", "cloudflare"] // 只输出 au、cloudflare 类别,并确保 cloudflare 比 au 后写入。但由于 private 存在于 excludedList 中,最终不输出 private 类别
}
}
```

```jsonc
{
"type": "dbipCountryMMDB",
"action": "output",
"args": {
"outputName": "Country.mmdb", // 输出文件名为 Country.mmdb
"excludedList": ["private"], // 最终不输出 private 类别
"overwriteList": ["private" ,"cn", "google"] // 确保 cn、google 类别最后写入,且 google 比 cn 后写入。但由于 private 存在于 excludedList 中,最终不输出 private 类别
}
}
```

### **lookup**

- **type**:(必须)输入格式的名称
Expand Down
2 changes: 1 addition & 1 deletion lookup.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ func getInputForLookup(format, name, uri, dir string) lib.InputConverter {

switch strings.ToLower(format) {
case strings.ToLower(maxmind.TypeMaxmindMMDBIn):
input = &maxmind.MaxmindMMDBIn{
input = &maxmind.MMDBIn{
Type: maxmind.TypeMaxmindMMDBIn,
Action: lib.ActionAdd,
Description: maxmind.DescMaxmindMMDBIn,
Expand Down
55 changes: 55 additions & 0 deletions plugin/maxmind/common_in.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package maxmind

import (
"encoding/json"
"path/filepath"
"strings"

"github.com/Loyalsoldier/geoip/lib"
)

var (
defaultGeoLite2MMDBFile = filepath.Join("./", "geolite2", "GeoLite2-Country.mmdb")
defaultDBIPCountryMMDBFile = filepath.Join("./", "db-ip", "dbip-country-lite.mmdb")
)

func newMMDBIn(iType string, iDesc string, action lib.Action, data json.RawMessage) (lib.InputConverter, error) {
var tmp struct {
URI string `json:"uri"`
Want []string `json:"wantedList"`
OnlyIPType lib.IPType `json:"onlyIPType"`
}

if len(data) > 0 {
if err := json.Unmarshal(data, &tmp); err != nil {
return nil, err
}
}

if tmp.URI == "" {
switch iType {
case TypeMaxmindMMDBIn:
tmp.URI = defaultGeoLite2MMDBFile

case TypeDBIPCountryMMDBIn:
tmp.URI = defaultDBIPCountryMMDBFile
}
}

// Filter want list
wantList := make(map[string]bool)
for _, want := range tmp.Want {
if want = strings.ToUpper(strings.TrimSpace(want)); want != "" {
wantList[want] = true
}
}

return &MMDBIn{
Type: iType,
Action: action,
Description: iDesc,
URI: tmp.URI,
Want: wantList,
OnlyIPType: tmp.OnlyIPType,
}, nil
}
57 changes: 57 additions & 0 deletions plugin/maxmind/common_out.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package maxmind

import (
"encoding/json"
"path/filepath"

"github.com/Loyalsoldier/geoip/lib"
)

var (
defaultOutputName = "Country.mmdb"
defaultMaxmindOutputDir = filepath.Join("./", "output", "maxmind")
defaultDBIPOutputDir = filepath.Join("./", "output", "db-ip")
)

func newMMDBOut(iType string, iDesc string, action lib.Action, data json.RawMessage) (lib.OutputConverter, error) {
var tmp struct {
OutputName string `json:"outputName"`
OutputDir string `json:"outputDir"`
Want []string `json:"wantedList"`
Overwrite []string `json:"overwriteList"`
Exclude []string `json:"excludedList"`
OnlyIPType lib.IPType `json:"onlyIPType"`
}

if len(data) > 0 {
if err := json.Unmarshal(data, &tmp); err != nil {
return nil, err
}
}

if tmp.OutputName == "" {
tmp.OutputName = defaultOutputName
}

if tmp.OutputDir == "" {
switch iType {
case TypeMaxmindMMDBOut:
tmp.OutputDir = defaultMaxmindOutputDir

case TypeDBIPCountryMMDBOut:
tmp.OutputDir = defaultDBIPOutputDir
}
}

return &MMDBOut{
Type: iType,
Action: action,
Description: iDesc,
OutputName: tmp.OutputName,
OutputDir: tmp.OutputDir,
Want: tmp.Want,
Overwrite: tmp.Overwrite,
Exclude: tmp.Exclude,
OnlyIPType: tmp.OnlyIPType,
}, nil
}
26 changes: 26 additions & 0 deletions plugin/maxmind/dbip_mmdb_in.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package maxmind

import (
"encoding/json"

"github.com/Loyalsoldier/geoip/lib"
)

/*
The types in this file extend the type `typeMaxmindMMDBIn`,
which make it possible to support more formats for the project.
*/

const (
TypeDBIPCountryMMDBIn = "dbipCountryMMDB"
DescDBIPCountryMMDBIn = "Convert DB-IP country mmdb database to other formats"
)

func init() {
lib.RegisterInputConfigCreator(TypeDBIPCountryMMDBIn, func(action lib.Action, data json.RawMessage) (lib.InputConverter, error) {
return newMMDBIn(TypeDBIPCountryMMDBIn, DescDBIPCountryMMDBIn, action, data)
})
lib.RegisterInputConverter(TypeDBIPCountryMMDBIn, &MMDBIn{
Description: DescDBIPCountryMMDBIn,
})
}
26 changes: 26 additions & 0 deletions plugin/maxmind/dbip_mmdb_out.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package maxmind

import (
"encoding/json"

"github.com/Loyalsoldier/geoip/lib"
)

/*
The types in this file extend the type `typeMaxmindMMDBOut`,
which make it possible to support more formats for the project.
*/

const (
TypeDBIPCountryMMDBOut = "dbipCountryMMDB"
DescDBIPCountryMMDBOut = "Convert data to DB-IP country mmdb database format"
)

func init() {
lib.RegisterOutputConfigCreator(TypeDBIPCountryMMDBOut, func(action lib.Action, data json.RawMessage) (lib.OutputConverter, error) {
return newMMDBOut(TypeDBIPCountryMMDBOut, DescDBIPCountryMMDBOut, action, data)
})
lib.RegisterOutputConverter(TypeDBIPCountryMMDBOut, &MMDBOut{
Description: DescDBIPCountryMMDBOut,
})
}
Loading

0 comments on commit b7daf13

Please sign in to comment.