cmd_geoip_export.go 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. package main
  2. import (
  3. "io"
  4. "net"
  5. "os"
  6. "strings"
  7. C "github.com/sagernet/sing-box/constant"
  8. "github.com/sagernet/sing-box/log"
  9. "github.com/sagernet/sing-box/option"
  10. E "github.com/sagernet/sing/common/exceptions"
  11. "github.com/sagernet/sing/common/json"
  12. "github.com/oschwald/maxminddb-golang"
  13. "github.com/spf13/cobra"
  14. )
  15. var flagGeoipExportOutput string
  16. const flagGeoipExportDefaultOutput = "geoip-<country>.srs"
  17. var commandGeoipExport = &cobra.Command{
  18. Use: "export <country>",
  19. Short: "Export geoip country as rule-set",
  20. Args: cobra.ExactArgs(1),
  21. Run: func(cmd *cobra.Command, args []string) {
  22. err := geoipExport(args[0])
  23. if err != nil {
  24. log.Fatal(err)
  25. }
  26. },
  27. }
  28. func init() {
  29. commandGeoipExport.Flags().StringVarP(&flagGeoipExportOutput, "output", "o", flagGeoipExportDefaultOutput, "Output path")
  30. commandGeoip.AddCommand(commandGeoipExport)
  31. }
  32. func geoipExport(countryCode string) error {
  33. networks := geoipReader.Networks(maxminddb.SkipAliasedNetworks)
  34. countryMap := make(map[string][]*net.IPNet)
  35. var (
  36. ipNet *net.IPNet
  37. nextCountryCode string
  38. err error
  39. )
  40. for networks.Next() {
  41. ipNet, err = networks.Network(&nextCountryCode)
  42. if err != nil {
  43. return err
  44. }
  45. countryMap[nextCountryCode] = append(countryMap[nextCountryCode], ipNet)
  46. }
  47. ipNets := countryMap[strings.ToLower(countryCode)]
  48. if len(ipNets) == 0 {
  49. return E.New("country code not found: ", countryCode)
  50. }
  51. var (
  52. outputFile *os.File
  53. outputWriter io.Writer
  54. )
  55. if flagGeoipExportOutput == "stdout" {
  56. outputWriter = os.Stdout
  57. } else if flagGeoipExportOutput == flagGeoipExportDefaultOutput {
  58. outputFile, err = os.Create("geoip-" + countryCode + ".json")
  59. if err != nil {
  60. return err
  61. }
  62. defer outputFile.Close()
  63. outputWriter = outputFile
  64. } else {
  65. outputFile, err = os.Create(flagGeoipExportOutput)
  66. if err != nil {
  67. return err
  68. }
  69. defer outputFile.Close()
  70. outputWriter = outputFile
  71. }
  72. encoder := json.NewEncoder(outputWriter)
  73. encoder.SetIndent("", " ")
  74. var headlessRule option.DefaultHeadlessRule
  75. headlessRule.IPCIDR = make([]string, 0, len(ipNets))
  76. for _, cidr := range ipNets {
  77. headlessRule.IPCIDR = append(headlessRule.IPCIDR, cidr.String())
  78. }
  79. var plainRuleSet option.PlainRuleSetCompat
  80. plainRuleSet.Version = C.RuleSetVersion1
  81. plainRuleSet.Options.Rules = []option.HeadlessRule{
  82. {
  83. Type: C.RuleTypeDefault,
  84. DefaultOptions: headlessRule,
  85. },
  86. }
  87. return encoder.Encode(plainRuleSet)
  88. }