Fix routing reading issues

- Detect VPN gateway properly
- Fix local subnet detection, refers to #188
- Split LocalSubnet from DefaultRoute (2 different routes actually)
This commit is contained in:
Quentin McGaw
2020-07-12 19:05:48 +00:00
parent 2acf627918
commit 6afa4f69a0
7 changed files with 150 additions and 47 deletions

View File

@@ -14,6 +14,16 @@ import (
"github.com/qdm12/private-internet-access-docker/internal/constants"
)
const exampleRouteData = `Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
tun0 00000000 050A030A 0003 0 0 0 00000080 0 0 0
eth0 00000000 010011AC 0003 0 0 0 00000000 0 0 0
tun0 010A030A 050A030A 0007 0 0 0 FFFFFFFF 0 0 0
tun0 050A030A 00000000 0005 0 0 0 FFFFFFFF 0 0 0
eth0 42196956 010011AC 0007 0 0 0 FFFFFFFF 0 0 0
tun0 00000080 050A030A 0003 0 0 0 00000080 0 0 0
eth0 000011AC 00000000 0001 0 0 0 0000FFFF 0 0 0
`
func Test_parseRoutingTable(t *testing.T) {
t.Parallel()
tests := map[string]struct {
@@ -93,7 +103,6 @@ func Test_DefaultRoute(t *testing.T) {
readErr error
defaultInterface string
defaultGateway net.IP
defaultSubnet net.IPNet
err error
}{
"no data": {
@@ -104,6 +113,73 @@ func Test_DefaultRoute(t *testing.T) {
"parse error": {
data: []byte(`Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
eth0 x
`),
err: fmt.Errorf("line 1 in /proc/net/route: line \"eth0 x\": not enough fields")},
"single entry": {
data: []byte(`Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
eth0 00000000 050A090A 0003 0 0 0 00000080 0 0 0
`),
err: fmt.Errorf("not enough entries (1) found in %s", constants.NetRoute)},
"success": {
data: []byte(exampleRouteData),
defaultInterface: "eth0",
defaultGateway: net.IP{172, 17, 0, 1},
},
"not found": {
data: []byte(`Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
eth0 00000000 010011AC 0003 0 0 0 10000000 0 0 0
eth0 000011AC 00000000 0001 0 0 0 0000FFFF 0 0 0
`),
err: fmt.Errorf("cannot find default route"),
},
}
for name, tc := range tests {
tc := tc
t.Run(name, func(t *testing.T) {
t.Parallel()
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
logger := mock_logging.NewMockLogger(mockCtrl)
filemanager := mock_files.NewMockFileManager(mockCtrl)
filemanager.EXPECT().ReadFile(string(constants.NetRoute)).
Return(tc.data, tc.readErr).Times(1)
if tc.err == nil {
logger.EXPECT().Info(
"default route found: interface %s, gateway %s",
tc.defaultInterface, tc.defaultGateway.String(),
).Times(1)
}
r := &routing{logger: logger, fileManager: filemanager}
defaultInterface, defaultGateway, err := r.DefaultRoute()
if tc.err != nil {
require.Error(t, err)
assert.Equal(t, tc.err.Error(), err.Error())
} else {
assert.NoError(t, err)
}
assert.Equal(t, tc.defaultInterface, defaultInterface)
assert.Equal(t, tc.defaultGateway, defaultGateway)
})
}
}
func Test_LocalSubnet(t *testing.T) {
t.Parallel()
tests := map[string]struct {
data []byte
readErr error
localSubnet net.IPNet
err error
}{
"no data": {
err: fmt.Errorf("not enough entries (0) found in %s", constants.NetRoute)},
"read error": {
readErr: fmt.Errorf("error"),
err: fmt.Errorf("error")},
"parse error": {
data: []byte(`Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
eth0 x
`),
err: fmt.Errorf("line 1 in /proc/net/route: line \"eth0 x\": not enough fields")},
"single entry": {
@@ -112,16 +188,19 @@ eth0 00000000 050A090A 0003 0 0 0 00000080
`),
err: fmt.Errorf("not enough entries (1) found in %s", constants.NetRoute)},
"success": {
data: []byte(`Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
eth0 00000000 010011AC 0003 0 0 0 00000000 0 0 0
eth0 000011AC 00000000 0001 0 0 0 0000FFFF 0 0 0
`),
defaultInterface: "eth0",
defaultGateway: net.IP{172, 17, 0, 1},
defaultSubnet: net.IPNet{
data: []byte(exampleRouteData),
localSubnet: net.IPNet{
IP: net.IP{172, 17, 0, 0},
Mask: net.IPMask{255, 255, 0, 0},
}},
},
},
"not found": {
data: []byte(`Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
eth0 00000000 010011AC 0003 0 0 0 00000000 0 0 0
eth0 000011AC 10000000 0001 0 0 0 0000FFFF 0 0 0
`),
err: fmt.Errorf("cannot find local subnet route"),
},
}
for name, tc := range tests {
tc := tc
@@ -134,24 +213,18 @@ eth0 000011AC 00000000 0001 0 0 0 0000FFFF
filemanager.EXPECT().ReadFile(string(constants.NetRoute)).
Return(tc.data, tc.readErr).Times(1)
logger.EXPECT().Info("detecting default network route").Times(1)
if tc.err == nil {
logger.EXPECT().Info(
"default route found: interface %s, gateway %s, subnet %s",
tc.defaultInterface, tc.defaultGateway.String(), tc.defaultSubnet.String(),
).Times(1)
logger.EXPECT().Info("local subnet found: %s", tc.localSubnet.String()).Times(1)
}
r := &routing{logger: logger, fileManager: filemanager}
defaultInterface, defaultGateway, defaultSubnet, err := r.DefaultRoute()
localSubnet, err := r.LocalSubnet()
if tc.err != nil {
require.Error(t, err)
assert.Equal(t, tc.err.Error(), err.Error())
} else {
assert.NoError(t, err)
}
assert.Equal(t, tc.defaultInterface, defaultInterface)
assert.Equal(t, tc.defaultGateway, defaultGateway)
assert.Equal(t, tc.defaultSubnet, defaultSubnet)
assert.Equal(t, tc.localSubnet, localSubnet)
})
}
}
@@ -218,18 +291,8 @@ eth0 0002A8C0 0100000A 0003 0 0 0 00FFFFFF
}
}
func Test_CurrentIP(t *testing.T) {
func Test_VPNGatewayIP(t *testing.T) {
t.Parallel()
const exampleRouteData = `Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
tun0 00000000 050A090A 0003 0 0 0 00000080 0 0 0
eth0 00000000 0100000A 0003 0 0 0 00000000 0 0 0
eth0 0000000A 00000000 0001 0 0 0 00FFFFFF 0 0 0
tun0 010A090A 050A090A 0007 0 0 0 FFFFFFFF 0 0 0
tun0 050A090A 00000000 0005 0 0 0 FFFFFFFF 0 0 0
eth0 2194B05F 0100000A 0007 0 0 0 FFFFFFFF 0 0 0
tun0 00000080 050A090A 0003 0 0 0 00000080 0 0 0
eth0 0002A8C0 0100000A 0003 0 0 0 00FFFFFF 0 0 0
`
tests := map[string]struct {
defaultInterface string
data []byte
@@ -253,7 +316,7 @@ eth0 x
"found eth0": {
defaultInterface: "eth0",
data: []byte(exampleRouteData),
ip: net.IP{95, 176, 148, 33},
ip: net.IP{86, 105, 25, 66},
},
"not found tun0": {
defaultInterface: "tun0",