44 "encoding/json"
55 "fmt"
66 "log"
7+ "net"
78 "slices"
9+ "sort"
810 "strings"
911 "sync"
1012
@@ -405,6 +407,144 @@ func filterRules(rules []json.RawMessage, apiTag string) ([]json.RawMessage, err
405407 return filtered , nil
406408}
407409
410+ var privateCIDRs = []string {
411+ "0.0.0.0/8" ,
412+ "10.0.0.0/8" ,
413+ "100.64.0.0/10" ,
414+ "127.0.0.0/8" ,
415+ "169.254.0.0/16" ,
416+ "172.16.0.0/12" ,
417+ "192.0.0.0/24" ,
418+ "192.168.0.0/16" ,
419+ "198.18.0.0/15" ,
420+ "224.0.0.0/4" ,
421+ "240.0.0.0/4" ,
422+ "::/128" ,
423+ "::1/128" ,
424+ "fc00::/7" ,
425+ "fe80::/10" ,
426+ }
427+
428+ func replaceGeoIPPrivate (values any ) (any , bool ) {
429+ list , ok := values .([]any )
430+ if ! ok {
431+ return values , false
432+ }
433+
434+ updated := make ([]any , 0 , len (list )+ len (privateCIDRs ))
435+ changed := false
436+ for _ , entry := range list {
437+ s , strOK := entry .(string )
438+ if strOK && strings .EqualFold (s , "geoip:private" ) {
439+ for _ , cidr := range privateCIDRs {
440+ updated = append (updated , cidr )
441+ }
442+ changed = true
443+ continue
444+ }
445+ updated = append (updated , entry )
446+ }
447+
448+ if ! changed {
449+ return values , false
450+ }
451+
452+ return updated , true
453+ }
454+
455+ func normalizeGeoIPPrivateRules (rules []json.RawMessage ) ([]json.RawMessage , error ) {
456+ if rules == nil {
457+ return []json.RawMessage {}, nil
458+ }
459+
460+ normalized := make ([]json.RawMessage , 0 , len (rules ))
461+ for _ , raw := range rules {
462+ var obj map [string ]any
463+ if err := json .Unmarshal (raw , & obj ); err != nil {
464+ return nil , fmt .Errorf ("invalid JSON in rule: %w" , err )
465+ }
466+
467+ ruleChanged := false
468+ if ip , ok := obj ["ip" ]; ok {
469+ newIP , changed := replaceGeoIPPrivate (ip )
470+ if changed {
471+ obj ["ip" ] = newIP
472+ ruleChanged = true
473+ }
474+ }
475+
476+ if source , ok := obj ["source" ]; ok {
477+ newSource , changed := replaceGeoIPPrivate (source )
478+ if changed {
479+ obj ["source" ] = newSource
480+ ruleChanged = true
481+ }
482+ }
483+
484+ if ! ruleChanged {
485+ normalized = append (normalized , raw )
486+ continue
487+ }
488+
489+ rawBytes , err := json .Marshal (obj )
490+ if err != nil {
491+ return nil , fmt .Errorf ("failed to marshal normalized rule: %w" , err )
492+ }
493+ normalized = append (normalized , json .RawMessage (rawBytes ))
494+ }
495+
496+ return normalized , nil
497+ }
498+
499+ func apiRuleSources () []string {
500+ seen := map [string ]struct {}{
501+ "127.0.0.1" : {},
502+ "::1" : {},
503+ }
504+
505+ ifaces , err := net .Interfaces ()
506+ if err != nil {
507+ return []string {"127.0.0.1" , "::1" }
508+ }
509+
510+ for _ , iface := range ifaces {
511+ if iface .Flags & net .FlagUp == 0 {
512+ continue
513+ }
514+
515+ addrs , err := iface .Addrs ()
516+ if err != nil {
517+ continue
518+ }
519+
520+ for _ , addr := range addrs {
521+ var ip net.IP
522+ switch v := addr .(type ) {
523+ case * net.IPNet :
524+ ip = v .IP
525+ case * net.IPAddr :
526+ ip = v .IP
527+ default :
528+ continue
529+ }
530+
531+ if ip == nil || ip .IsUnspecified () {
532+ continue
533+ }
534+
535+ seen [ip .String ()] = struct {}{}
536+ }
537+ }
538+
539+ sources := make ([]string , 0 , len (seen ))
540+ for source := range seen {
541+ sources = append (sources , source )
542+ }
543+ sort .Strings (sources )
544+
545+ return sources
546+ }
547+
408548func (c * Config ) ApplyAPI (apiPort int ) (err error ) {
409549 // Remove the existing inbound with the API_INBOUND tag
410550 for i , inbound := range c .InboundConfigs {
@@ -425,7 +565,14 @@ func (c *Config) ApplyAPI(apiPort int) (err error) {
425565 }
426566
427567 rules := c .RouterConfig .RuleList
568+ rules , err = normalizeGeoIPPrivateRules (rules )
569+ if err != nil {
570+ return err
571+ }
428572 c .RouterConfig .RuleList , err = filterRules (rules , apiTag )
573+ if err != nil {
574+ return err
575+ }
429576
430577 c .checkPolicy ()
431578
@@ -442,7 +589,7 @@ func (c *Config) ApplyAPI(apiPort int) (err error) {
442589
443590 rule := map [string ]any {
444591 "inboundTag" : []string {"API_INBOUND" },
445- "source" : [] string { "127.0.0.1" } ,
592+ "source" : apiRuleSources () ,
446593 "outboundTag" : "API" ,
447594 "type" : "field" ,
448595 }
0 commit comments