summaryrefslogtreecommitdiff
path: root/plugin
diff options
context:
space:
mode:
authorLoyalsoldier <[email protected]>2021-11-21 15:56:50 +0800
committerLoyalsoldier <[email protected]>2021-11-21 15:56:50 +0800
commit7ace2d59a8c55da66acd3d1a378aac43cc5c2e38 (patch)
tree89ca56d40ab0cea564610f10f6319d5251a6285b /plugin
parenta220557037e61db03c53eb3b73db295482b3b8b2 (diff)
Feat: support v2rayGeoIPDat as input format
Diffstat (limited to 'plugin')
-rw-r--r--plugin/v2ray/dat_in.go204
-rw-r--r--plugin/v2ray/dat_out.go (renamed from plugin/v2ray/dat.go)32
2 files changed, 220 insertions, 16 deletions
diff --git a/plugin/v2ray/dat_in.go b/plugin/v2ray/dat_in.go
new file mode 100644
index 00000000..a8e1974f
--- /dev/null
+++ b/plugin/v2ray/dat_in.go
@@ -0,0 +1,204 @@
+package v2ray
+
+import (
+ "encoding/json"
+ "fmt"
+ "io"
+ "net"
+ "net/http"
+ "os"
+ "strings"
+
+ "github.com/Loyalsoldier/geoip/lib"
+ "github.com/v2fly/v2ray-core/v4/app/router"
+ "google.golang.org/protobuf/proto"
+)
+
+const (
+ typeGeoIPdatIn = "v2rayGeoIPDat"
+ descGeoIPdatIn = "Convert V2Ray GeoIP dat to other formats"
+)
+
+func init() {
+ lib.RegisterInputConfigCreator(typeGeoIPdatIn, func(action lib.Action, data json.RawMessage) (lib.InputConverter, error) {
+ return newGeoIPDatIn(action, data)
+ })
+ lib.RegisterInputConverter(typeGeoIPdatIn, &geoIPDatIn{
+ Description: descGeoIPdatIn,
+ })
+}
+
+func newGeoIPDatIn(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 == "" {
+ return nil, fmt.Errorf("[type %s | action %s] uri must be specified in config", typeGeoIPdatIn, action)
+ }
+
+ return &geoIPDatIn{
+ Type: typeGeoIPdatIn,
+ Action: action,
+ Description: descGeoIPdatIn,
+ URI: tmp.URI,
+ Want: tmp.Want,
+ OnlyIPType: tmp.OnlyIPType,
+ }, nil
+}
+
+type geoIPDatIn struct {
+ Type string
+ Action lib.Action
+ Description string
+ URI string
+ Want []string
+ OnlyIPType lib.IPType
+}
+
+func (g *geoIPDatIn) GetType() string {
+ return g.Type
+}
+
+func (g *geoIPDatIn) GetAction() lib.Action {
+ return g.Action
+}
+
+func (g *geoIPDatIn) GetDescription() string {
+ return g.Description
+}
+
+func (g *geoIPDatIn) Input(container lib.Container) (lib.Container, error) {
+ entries := make(map[string]*lib.Entry)
+ var err error
+
+ switch {
+ case strings.HasPrefix(g.URI, "http://"), strings.HasPrefix(g.URI, "https://"):
+ err = g.walkRemoteFile(g.URI, entries)
+ default:
+ err = g.walkLocalFile(g.URI, entries)
+ }
+
+ if err != nil {
+ return nil, err
+ }
+
+ if len(entries) == 0 {
+ return nil, fmt.Errorf("❌ [type %s | action %s] no entry is newly generated", typeGeoIPdatIn, g.Action)
+ }
+
+ var ignoreIPType lib.IgnoreIPOption
+ switch g.OnlyIPType {
+ case lib.IPv4:
+ ignoreIPType = lib.IgnoreIPv6
+ case lib.IPv6:
+ ignoreIPType = lib.IgnoreIPv4
+ }
+
+ // Filter want list
+ wantList := make(map[string]bool)
+ for _, want := range g.Want {
+ if want = strings.ToUpper(strings.TrimSpace(want)); want != "" {
+ wantList[want] = true
+ }
+ }
+
+ for _, entry := range entries {
+ name := entry.GetName()
+ if len(wantList) > 0 && !wantList[name] {
+ continue
+ }
+
+ switch g.Action {
+ case lib.ActionAdd:
+ if err := container.Add(entry, ignoreIPType); err != nil {
+ return nil, err
+ }
+ case lib.ActionRemove:
+ container.Remove(name, ignoreIPType)
+ }
+ }
+
+ return container, nil
+}
+
+func (g *geoIPDatIn) walkLocalFile(path string, entries map[string]*lib.Entry) error {
+ file, err := os.Open(path)
+ if err != nil {
+ return err
+ }
+ defer file.Close()
+
+ if err := g.generateEntries(file, entries); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (g *geoIPDatIn) walkRemoteFile(url string, entries map[string]*lib.Entry) error {
+ resp, err := http.Get(url)
+ if err != nil {
+ return err
+ }
+ defer resp.Body.Close()
+
+ if resp.StatusCode != 200 {
+ return fmt.Errorf("failed to get remote file %s, http status code %d", url, resp.StatusCode)
+ }
+
+ if err := g.generateEntries(resp.Body, entries); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (g *geoIPDatIn) generateEntries(reader io.Reader, entries map[string]*lib.Entry) error {
+ geoipBytes, err := io.ReadAll(reader)
+ if err != nil {
+ return err
+ }
+
+ var geoipList router.GeoIPList
+ if err := proto.Unmarshal(geoipBytes, &geoipList); err != nil {
+ return err
+ }
+
+ for _, geoip := range geoipList.Entry {
+ var entry *lib.Entry
+ name := geoip.CountryCode
+ if theEntry, found := entries[name]; found {
+ fmt.Printf("⚠️ [type %s | action %s] found duplicated entry: %s. Process anyway\n", typeGeoIPdatIn, g.Action, name)
+ entry = theEntry
+ } else {
+ entry = lib.NewEntry(name)
+ }
+
+ for _, v2rayCIDR := range geoip.Cidr {
+ ipStr := net.IP(v2rayCIDR.GetIp()).String() + "/" + fmt.Sprint(v2rayCIDR.GetPrefix())
+ switch g.Action {
+ case lib.ActionAdd:
+ if err := entry.AddPrefix(ipStr); err != nil {
+ return err
+ }
+ case lib.ActionRemove:
+ if err := entry.RemovePrefix(ipStr); err != nil {
+ return err
+ }
+ }
+ }
+
+ entries[name] = entry
+ }
+
+ return nil
+}
diff --git a/plugin/v2ray/dat.go b/plugin/v2ray/dat_out.go
index 0c4e76d8..7e2f01ec 100644
--- a/plugin/v2ray/dat.go
+++ b/plugin/v2ray/dat_out.go
@@ -16,8 +16,8 @@ import (
)
const (
- typeGeoIPdat = "v2rayGeoIPDat"
- descGeoIPdat = "Convert data to V2Ray GeoIP dat format"
+ typeGeoIPdatOut = "v2rayGeoIPDat"
+ descGeoIPdatOut = "Convert data to V2Ray GeoIP dat format"
)
var (
@@ -26,11 +26,11 @@ var (
)
func init() {
- lib.RegisterOutputConfigCreator(typeGeoIPdat, func(action lib.Action, data json.RawMessage) (lib.OutputConverter, error) {
+ lib.RegisterOutputConfigCreator(typeGeoIPdatOut, func(action lib.Action, data json.RawMessage) (lib.OutputConverter, error) {
return newGeoIPDat(action, data)
})
- lib.RegisterOutputConverter(typeGeoIPdat, &geoIPDat{
- Description: descGeoIPdat,
+ lib.RegisterOutputConverter(typeGeoIPdatOut, &geoIPDatOut{
+ Description: descGeoIPdatOut,
})
}
@@ -57,10 +57,10 @@ func newGeoIPDat(action lib.Action, data json.RawMessage) (lib.OutputConverter,
tmp.OutputDir = defaultOutputDir
}
- return &geoIPDat{
- Type: typeGeoIPdat,
+ return &geoIPDatOut{
+ Type: typeGeoIPdatOut,
Action: action,
- Description: descGeoIPdat,
+ Description: descGeoIPdatOut,
OutputName: tmp.OutputName,
OutputDir: tmp.OutputDir,
Want: tmp.Want,
@@ -69,7 +69,7 @@ func newGeoIPDat(action lib.Action, data json.RawMessage) (lib.OutputConverter,
}, nil
}
-type geoIPDat struct {
+type geoIPDatOut struct {
Type string
Action lib.Action
Description string
@@ -80,19 +80,19 @@ type geoIPDat struct {
OnlyIPType lib.IPType
}
-func (g *geoIPDat) GetType() string {
+func (g *geoIPDatOut) GetType() string {
return g.Type
}
-func (g *geoIPDat) GetAction() lib.Action {
+func (g *geoIPDatOut) GetAction() lib.Action {
return g.Action
}
-func (g *geoIPDat) GetDescription() string {
+func (g *geoIPDatOut) GetDescription() string {
return g.Description
}
-func (g *geoIPDat) Output(container lib.Container) error {
+func (g *geoIPDatOut) Output(container lib.Container) error {
// Filter want list
wantList := make(map[string]bool)
for _, want := range g.Want {
@@ -171,7 +171,7 @@ func (g *geoIPDat) Output(container lib.Container) error {
return nil
}
-func (g *geoIPDat) generateGeoIP(entry *lib.Entry) (*router.GeoIP, error) {
+func (g *geoIPDatOut) generateGeoIP(entry *lib.Entry) (*router.GeoIP, error) {
var entryCidr []string
var err error
switch g.OnlyIPType {
@@ -206,13 +206,13 @@ func (g *geoIPDat) generateGeoIP(entry *lib.Entry) (*router.GeoIP, error) {
}
// Sort by country code to make reproducible builds
-func (g *geoIPDat) sort(list *router.GeoIPList) {
+func (g *geoIPDatOut) sort(list *router.GeoIPList) {
sort.SliceStable(list.Entry, func(i, j int) bool {
return list.Entry[i].CountryCode < list.Entry[j].CountryCode
})
}
-func (g *geoIPDat) writeFile(filename string, geoIPBytes []byte) error {
+func (g *geoIPDatOut) writeFile(filename string, geoIPBytes []byte) error {
if err := os.MkdirAll(g.OutputDir, 0755); err != nil {
return err
}