@@ -5,8 +5,10 @@ import (
55 "errors"
66 "fmt"
77 "io/ioutil"
8+ "math/bits"
89 "os/exec"
910 "regexp"
11+ "strconv"
1012 "strings"
1113
1214 "golang.org/x/text/encoding/unicode"
@@ -41,10 +43,105 @@ func ListAll() (string, error) {
4143 return decoded , nil
4244}
4345
46+ func netmaskToBits (mask uint32 ) int {
47+ return bits .OnesCount32 (mask )
48+ }
49+ func hexToUint32LE (hex string ) (uint32 , error ) {
50+ i , err := strconv .ParseInt (hex [6 :8 ]+ hex [4 :6 ]+ hex [2 :4 ]+ hex [0 :2 ], 16 , 64 )
51+ if err != nil {
52+ return 0 , err
53+ }
54+ return uint32 (i ), nil
55+ }
56+
57+ type routeInfo struct {
58+ net uint32
59+ mask uint32
60+ }
61+
62+ func getRouteInfo (name string ) (* routeInfo , error ) {
63+ cmd := exec .Command ("wsl.exe" , "-d" , name , "--" , "cat" , "/proc/net/route" )
64+ out , err := cmd .Output ()
65+ if err != nil {
66+ return nil , err
67+ }
68+ ri := & routeInfo {}
69+ sout := string (out )
70+ sout = strings .TrimSpace (sout )
71+ lines := strings .Split (sout , "\n " )
72+ lines = lines [1 :]
73+ for _ , line := range lines {
74+ fs := strings .Fields (line )
75+ if ri .mask > 0 && ri .net > 0 {
76+ break
77+ }
78+ if fs [0 ] != "eth0" {
79+ continue
80+ }
81+ if fs [1 ] != "00000000" {
82+ net , err := hexToUint32LE (fs [1 ])
83+ if err != nil {
84+ return nil , fmt .Errorf ("failed to convert network to Uint32: %w" , err )
85+ }
86+ ri .net = net
87+ }
88+ if fs [7 ] != "00000000" {
89+ mask , err := hexToUint32LE (fs [7 ])
90+ if err != nil {
91+ return nil , fmt .Errorf ("failed to convert netmask to Uint32: %w" , err )
92+ }
93+ ri .mask = mask
94+ }
95+ }
96+
97+ return ri , nil
98+ }
99+
100+ func isIPInRange (ri * routeInfo , ip uint32 ) bool {
101+ return (ri .net & ri .mask ) == (ip & ri .mask )
102+ }
103+
104+ func ipToUint32 (ip string ) (uint32 , error ) {
105+ octets := strings .Split (ip , "." )
106+ if len (octets ) != 4 {
107+ return 0 , errors .New ("invalid IP address" )
108+ }
109+
110+ var io uint32
111+
112+ o1 , err := strconv .Atoi (octets [0 ])
113+ if err != nil {
114+ return 0 , fmt .Errorf ("failed to parse IP address, %s: %w" , ip , err )
115+ }
116+ io += uint32 (o1 << 24 )
117+ o2 , err := strconv .Atoi (octets [1 ])
118+ if err != nil {
119+ return 0 , fmt .Errorf ("failed to parse IP address, %s: %w" , ip , err )
120+ }
121+ io += uint32 (o2 << 16 )
122+ o3 , err := strconv .Atoi (octets [2 ])
123+ if err != nil {
124+ return 0 , fmt .Errorf ("failed to parse IP address, %s: %w" , ip , err )
125+ }
126+ io += uint32 (o3 << 8 )
127+ o4 , err := strconv .Atoi (octets [3 ])
128+ if err != nil {
129+ return 0 , fmt .Errorf ("failed to parse IP address, %s: %w" , ip , err )
130+ }
131+ io += uint32 (o4 )
132+
133+ return io , nil
134+ }
135+
44136// GetIP returns the IP address of the given distro
45137// Suggest check if running before calling this function as
46138// it has the side-effect of starting the distro
47139func GetIP (name string ) (string , error ) {
140+ ri , err := getRouteInfo (name )
141+ if err != nil {
142+ return "" , err
143+ }
144+
48145 cmd := exec .Command ("wsl.exe" , "-d" , name , "--" , "cat" , "/proc/net/fib_trie" )
49146 out , err := cmd .Output ()
50147 if err != nil {
@@ -56,13 +153,17 @@ func GetIP(name string) (string, error) {
56153 return "" , errors .New ("invalid output from fib_trie" )
57154 }
58155 lines := strings .Split (sout , "\n " )
59- for i , line := range lines {
156+ for i := len (lines ) - 1 ; i >= 0 ; i -- {
157+ line := lines [i ]
60158 if strings .Index (line , "32 host LOCAL" ) != - 1 {
61- if i > 0 && strings .Index (lines [i - 1 ], "127.0.0.1" ) == - 1 {
62- if fs := strings .Fields (lines [i - 1 ]); len (fs ) > 1 {
63- return strings .TrimSpace (fs [1 ]), nil
64- }
65- break
159+ fs := strings .Fields (lines [i - 1 ])
160+ ipstr := strings .TrimSpace (fs [1 ])
161+ ip , err := ipToUint32 (ipstr )
162+ if err != nil {
163+ return "" , fmt .Errorf ("failed to convert ip, %s: %w" , ipstr , err )
164+ }
165+ if isIPInRange (ri , ip ) {
166+ return ipstr , nil
66167 }
67168 }
68169 }
0 commit comments