Skip to content

Commit 1c9065d

Browse files
committed
More robust IP discovery, attempted fix for #17
1 parent d9a11d5 commit 1c9065d

File tree

2 files changed

+108
-7
lines changed

2 files changed

+108
-7
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module github.com/shayne/go-wsl2-host
22

3-
go 1.12
3+
go 1.14
44

55
require (
66
github.com/stretchr/testify v1.4.0

pkg/wslcli/wslcli.go

Lines changed: 107 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -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
47139
func 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

Comments
 (0)