Skip to content

Commit

Permalink
Feat: support to exclude specified lists when output
Browse files Browse the repository at this point in the history
  • Loading branch information
Loyalsoldier committed Oct 23, 2024
1 parent 4cf5064 commit 40e0ad6
Show file tree
Hide file tree
Showing 8 changed files with 410 additions and 225 deletions.
146 changes: 143 additions & 3 deletions configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -728,6 +728,7 @@
- **outputDir**:(可选)输出目录
- **outputExtension**:(可选)输出文件的扩展名
- **wantedList**:(可选,数组)指定需要输出的类别
- **excludedList**:(可选,数组)指定不需要输出的类别
- **onlyIPType**:(可选)输出的 IP 地址类型,值为 `ipv4``ipv6`

```jsonc
Expand Down Expand Up @@ -774,6 +775,18 @@
}
```

```jsonc
{
"type": "clashRuleSet",
"action": "output",
"args": {
"outputDir": "./clash/ipcidr", // 输出文件到目录 ./clash/ipcidr
"outputExtension": ".yaml", // 输出文件的扩展名为 .yaml
"excludedList": ["cn", "us", "jp"] // 不输出名为 cn、us、jp 这三个类别的 IPv4 和 IPv6 地址
}
}
```

### **clashRuleSetClassical**

- **type**:(必须)输入格式的名称
Expand All @@ -782,6 +795,7 @@
- **outputDir**:(可选)输出目录
- **outputExtension**:(可选)输出文件的扩展名
- **wantedList**:(可选,数组)指定需要输出的类别
- **excludedList**:(可选,数组)指定不需要输出的类别
- **onlyIPType**:(可选)输出的 IP 地址类型,值为 `ipv4``ipv6`

```jsonc
Expand Down Expand Up @@ -828,6 +842,18 @@
}
```

```jsonc
{
"type": "clashRuleSetClassical",
"action": "output",
"args": {
"outputDir": "./clash/classical", // 输出文件到目录 ./clash/classical
"outputExtension": ".yaml", // 输出文件的扩展名为 .yaml
"excludedList": ["cn", "us", "jp"] // 不输出名为 cn、us、jp 这三个类别的 IPv4 和 IPv6 地址
}
}
```

### **lookup**

- **type**:(必须)输入格式的名称
Expand Down Expand Up @@ -868,11 +894,14 @@
- **outputDir**:(可选)输出目录
- **onlyIPType**:(可选)输出的 IP 地址类型,值为 `ipv4``ipv6`
- **wantedList**:(可选,数组)指定需要输出的类别
- **excludedList**:(可选,数组)指定不需要输出的类别
- **overwriteList**:(可选,数组)指定最后写入的类别(原因见👇)

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

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

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

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

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

### **mihomoMRS**

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

```jsonc
Expand All @@ -945,6 +1011,17 @@
}
```

```jsonc
{
"type": "mihomoMRS",
"action": "output",
"args": {
"outputDir": "./output", // 输出文件到 output 目录
"excludedList": ["cn", "private"] // 不输出 cn、private 类别
}
}
```

```jsonc
{
"type": "mihomoMRS",
Expand All @@ -962,6 +1039,7 @@
- **args**:(可选)
- **outputDir**:(可选)输出目录
- **wantedList**:(可选,数组)指定需要输出的类别
- **excludedList**:(可选,数组)指定不需要输出的类别
- **onlyIPType**:(可选)输出的 IP 地址类型,值为 `ipv4``ipv6`

```jsonc
Expand All @@ -983,6 +1061,17 @@
}
```

```jsonc
{
"type": "singboxSRS",
"action": "output",
"args": {
"outputDir": "./output", // 输出文件到 output 目录
"excludedList": ["cn", "private"] // 不输出 cn、private 类别
}
}
```

```jsonc
{
"type": "singboxSRS",
Expand All @@ -999,6 +1088,7 @@
- **action**:(必须)操作类型,值必须为 `output`
- **args**:(可选)
- **wantedList**:(可选,数组)指定需要输出的类别
- **excludedList**:(可选,数组)指定不需要输出的类别
- **onlyIPType**:(可选)输出的 IP 地址类型,值为 `ipv4``ipv6`

```jsonc
Expand All @@ -1018,6 +1108,16 @@
}
```

```jsonc
{
"type": "stdout",
"action": "output",
"args": {
"excludedList": ["cn", "private"] // 不输出 cn、private 类别到 standard output
}
}
```

```jsonc
{
"type": "stdout",
Expand All @@ -1036,6 +1136,7 @@
- **outputDir**:(可选)输出目录
- **outputExtension**:(可选)输出的文件的扩展名
- **wantedList**:(可选,数组)指定需要输出的类别
- **excludedList**:(可选,数组)指定不需要输出的类别
- **onlyIPType**:(可选)输出的 IP 地址类型,值为 `ipv4``ipv6`

```jsonc
Expand Down Expand Up @@ -1069,6 +1170,18 @@
}
```

```jsonc
{
"type": "surgeRuleSet",
"action": "output",
"args": {
"outputDir": "./surge", // 输出文件到目录 ./surge
"outputExtension": ".conf", // 输出文件的扩展名为 .conf
"excludedList": ["cn", "us", "jp"] // 不输出名为 cn、us、jp 这三个类别的 IPv4 和 IPv6 地址
}
}
```

```jsonc
{
"type": "surgeRuleSet",
Expand All @@ -1090,6 +1203,7 @@
- **outputDir**:(可选)输出目录
- **outputExtension**:(可选)输出的文件的扩展名
- **wantedList**:(可选,数组)指定需要输出的类别
- **excludedList**:(可选,数组)指定不需要输出的类别
- **onlyIPType**:(可选)输出的 IP 地址类型,值为 `ipv4``ipv6`
- **addPrefixInLine**:(可选)给输出的每一行添加的字符串前缀
- **addSuffixInLine**:(可选)给输出的每一行添加的字符串后缀
Expand Down Expand Up @@ -1134,6 +1248,19 @@
}
```

```jsonc
{
"type": "text",
"action": "output",
"args": {
"outputDir": "./text", // 输出文件到目录 ./text
"outputExtension": ".conf", // 输出文件的扩展名为 .conf
"excludedList": ["cn", "us", "jp"], // 不输出名为 cn、us、jp 这三个类别的 IPv4 和 IPv6 地址
"addPrefixInLine": "HOST,"
}
}
```

```jsonc
{
"type": "text",
Expand All @@ -1156,6 +1283,7 @@
- **outputName**:(可选)输出的文件名
- **outputDir**:(可选)输出目录
- **wantedList**:(可选,数组)指定需要输出的类别
- **excludedList**:(可选,数组)指定不需要输出的类别
- **onlyIPType**:(可选)输出的 IP 地址类型,值为 `ipv4``ipv6`
- **oneFilePerList**:(可选)每个类别输出为一个单独的文件,值为 `true``false`(默认值)

Expand Down Expand Up @@ -1189,6 +1317,18 @@
}
```

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

```jsonc
{
"type": "v2rayGeoIPDat",
Expand Down
32 changes: 19 additions & 13 deletions plugin/maxmind/mmdb_out.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package maxmind

import (
"encoding/json"
"fmt"
"log"
"net"
"os"
Expand Down Expand Up @@ -40,6 +39,7 @@ func newMMDBOut(action lib.Action, data json.RawMessage) (lib.OutputConverter, e
OutputDir string `json:"outputDir"`
Want []string `json:"wantedList"`
Overwrite []string `json:"overwriteList"`
Exclude []string `json:"excludedList"`
OnlyIPType lib.IPType `json:"onlyIPType"`
}

Expand All @@ -65,6 +65,7 @@ func newMMDBOut(action lib.Action, data json.RawMessage) (lib.OutputConverter, e
OutputDir: tmp.OutputDir,
Want: tmp.Want,
Overwrite: tmp.Overwrite,
Exclude: tmp.Exclude,
OnlyIPType: tmp.OnlyIPType,
}, nil
}
Expand All @@ -77,6 +78,7 @@ type mmdbOut struct {
OutputDir string
Want []string
Overwrite []string
Exclude []string
OnlyIPType lib.IPType
}

Expand Down Expand Up @@ -106,30 +108,28 @@ func (m *mmdbOut) Output(container lib.Container) error {
}

updated := false
for _, name := range m.getEntryNameListInOrder(container) {
for _, name := range m.filterAndSortList(container) {
entry, found := container.GetEntry(name)
if !found {
log.Printf("❌ entry %s not found", name)
log.Printf("❌ entry %s not found\n", name)
continue
}

if err := m.marshalData(writer, entry); err != nil {
return err
}

updated = true
}

if updated {
if err := m.writeFile(m.OutputName, writer); err != nil {
return err
}
} else {
return fmt.Errorf("❌ [type %s | action %s] failed to write file", m.Type, m.Action)
return m.writeFile(m.OutputName, writer)
}

return nil
}

func (m *mmdbOut) getEntryNameListInOrder(container lib.Container) []string {
func (m *mmdbOut) filterAndSortList(container lib.Container) []string {
/*
Note: The IPs and/or CIDRs of the latter list will overwrite those of the former one
when duplicated data found due to MaxMind mmdb file format constraint.
Expand All @@ -140,9 +140,16 @@ func (m *mmdbOut) getEntryNameListInOrder(container lib.Container) []string {
The order of names in wantedList has a higher priority than which of the overwriteList.
*/

excludeMap := make(map[string]bool)
for _, exclude := range m.Exclude {
if exclude = strings.ToUpper(strings.TrimSpace(exclude)); exclude != "" {
excludeMap[exclude] = true
}
}

wantList := make([]string, 0, len(m.Want))
for _, want := range m.Want {
if want = strings.ToUpper(strings.TrimSpace(want)); want != "" {
if want = strings.ToUpper(strings.TrimSpace(want)); want != "" && !excludeMap[want] {
wantList = append(wantList, want)
}
}
Expand All @@ -154,7 +161,7 @@ func (m *mmdbOut) getEntryNameListInOrder(container lib.Container) []string {
overwriteList := make([]string, 0, len(m.Overwrite))
overwriteMap := make(map[string]bool)
for _, overwrite := range m.Overwrite {
if overwrite = strings.ToUpper(strings.TrimSpace(overwrite)); overwrite != "" {
if overwrite = strings.ToUpper(strings.TrimSpace(overwrite)); overwrite != "" && !excludeMap[overwrite] {
overwriteList = append(overwriteList, overwrite)
overwriteMap[overwrite] = true
}
Expand All @@ -163,8 +170,7 @@ func (m *mmdbOut) getEntryNameListInOrder(container lib.Container) []string {
list := make([]string, 0, 300)
for entry := range container.Loop() {
name := entry.GetName()
_, found := overwriteMap[name]
if found {
if excludeMap[name] || overwriteMap[name] {
continue
}
list = append(list, name)
Expand Down
Loading

0 comments on commit 40e0ad6

Please sign in to comment.