@@ -3,13 +3,17 @@ package hcore
33import (
44 "context"
55 "fmt"
6+ "net"
67 "runtime"
8+ "strings"
79 "time"
810
911 "github.com/hiddify/hiddify-core/v2/config"
1012 "github.com/hiddify/hiddify-core/v2/db"
1113 hcommon "github.com/hiddify/hiddify-core/v2/hcommon"
1214 "github.com/sagernet/sing-box/adapter"
15+ "github.com/wlynxg/anet"
16+
1317 // "github.com/sagernet/sing-box/common/conntrack"
1418 "github.com/sagernet/sing-box/protocol/group"
1519
@@ -383,3 +387,63 @@ func (h *HiddifyInstance) UrlTest(in *UrlTestRequest) (*hcommon.Response, error)
383387 Message : "" ,
384388 }, nil
385389}
390+
391+ func (s * CoreService ) GetLANIP (ctx context.Context , req * hcommon.Empty ) (* LANIPResponse , error ) {
392+ // Use anet instead of net to bypass Android 11+ SELinux restrictions
393+ // that block direct Netlink socket binding (permission denied error).
394+ ifaces , err := anet .Interfaces ()
395+ if err != nil {
396+ Log (LogLevel_ERROR , LogType_CORE , "GetLANIP failed: " , err )
397+ return & LANIPResponse {Ip : "127.0.0.1" }, nil
398+ }
399+
400+ for _ , iface := range ifaces {
401+ // Filter out interfaces that are down, loopback, or point-to-point (VPN/Tunnels)
402+ if iface .Flags & net .FlagUp == 0 || iface .Flags & net .FlagLoopback != 0 || iface .Flags & net .FlagPointToPoint != 0 {
403+ continue
404+ }
405+
406+ // Exclude interfaces with names typical for VPNs, TAP, or TUN devices
407+ name := strings .ToLower (iface .Name )
408+ if strings .Contains (name , "tun" ) || strings .Contains (name , "tap" ) ||
409+ strings .Contains (name , "wintun" ) || strings .Contains (name , "utun" ) ||
410+ strings .Contains (name , "vpn" ) || strings .Contains (name , "ppp" ) {
411+ continue
412+ }
413+
414+ // Retrieve addresses using anet to ensure compatibility on Android 11+
415+ addrs , err := anet .InterfaceAddrsByInterface (& iface )
416+ if err != nil {
417+ continue
418+ }
419+
420+ for _ , addr := range addrs {
421+ var ip net.IP
422+ switch v := addr .(type ) {
423+ case * net.IPNet :
424+ ip = v .IP
425+ case * net.IPAddr :
426+ ip = v .IP
427+ }
428+
429+ if ip == nil || ip .IsLoopback () {
430+ continue
431+ }
432+
433+ // Ensure it is a valid IPv4 address
434+ ip4 := ip .To4 ()
435+ if ip4 == nil {
436+ continue
437+ }
438+
439+ // Verify the IP belongs to a standard private IP range (RFC 1918)
440+ if ip4 [0 ] == 10 ||
441+ (ip4 [0 ] == 172 && ip4 [1 ] >= 16 && ip4 [1 ] <= 31 ) ||
442+ (ip4 [0 ] == 192 && ip4 [1 ] == 168 ) {
443+ return & LANIPResponse {Ip : ip4 .String ()}, nil
444+ }
445+ }
446+ }
447+ // Fallback to loopback if no physical LAN interface is found
448+ return & LANIPResponse {Ip : "127.0.0.1" }, nil
449+ }
0 commit comments