gateway-1.0.16/0000775000175000017510000000000014731376046012604 5ustar nileshnileshgateway-1.0.16/tools/0000775000175000017510000000000014731376046013744 5ustar nileshnileshgateway-1.0.16/tools/generate-tables.sh0000775000175000017510000000144214731376046017346 0ustar nileshnilesh#!/usr/bin/env bash set -euo pipefail SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) FILE=${SCRIPT_DIR}/../test_route_tables.go TABLES=${SCRIPT_DIR}/../route-tables/*.txt consts=() cat < $FILE // Code generated by go generate package gateway EOF for rt in $(ls $TABLES) do name=$(echo $rt | awk 'BEGIN { FS = "/"} ; { print $NF }' | cut -d '.' -f 1) consts+=("\t${name} = \"${name}\"\n") done cat <> $FILE const ( $(echo -e ${consts[@]}) ) var routeTables = map[string][]byte { EOF for rt in $(ls $TABLES) do name=$(echo $rt | awk 'BEGIN { FS = "/"} ; { print $NF }' | cut -d '.' -f 1) echo -e "\t${name}: []byte(\`" >> $FILE cat $rt | sed 's/%/%%/g' >> $FILE echo -e "\`),\n" >> $FILE done echo "}" >> $FILE go fmt $FILE gateway-1.0.16/tools/check-cross-compile.sh0000775000175000017510000000075014731376046020137 0ustar nileshnilesh#!/usr/bin/env bash set -euo pipefail SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) TOP_DIR=${SCRIPT_DIR}/.. cd ${TOP_DIR} # Check that tests pass on local os / architecture. go test ./... # Check that the library builds on all supported OSs. # # Note that "plan9" is in this list to test gateway_unimplemented.go for os in "darwin" "dragonfly" "freebsd" "netbsd" "openbsd" "plan9" "solaris" "windows" do GOOS=${os} GOARCH=amd64 go build done gateway-1.0.16/test_route_tables.go0000664000175000017510000004070514731376046016670 0ustar nileshnilesh// Code generated by go generate package gateway const ( darwinBadRoute = "darwinBadRoute" darwinNoRoute = "darwinNoRoute" darwin = "darwin" freeBSDBadRoute = "freeBSDBadRoute" freeBSDNoRoute = "freeBSDNoRoute" freeBSD = "freeBSD" linuxNoRoute = "linuxNoRoute" linux = "linux" netBSDBadRoute = "netBSDBadRoute" netBSDNoRoute = "netBSDNoRoute" netBSD = "netBSD" randomData = "randomData" solarisBadRoute = "solarisBadRoute" solarisNoRoute = "solarisNoRoute" solaris = "solaris" solarisNoInterface = "solarisNoInterface" windowsBadRoute1 = "windowsBadRoute1" windowsBadRoute2 = "windowsBadRoute2" windowsLocalized = "windowsLocalized" windowsMultipleGateways = "windowsMultipleGateways" windowsNoDefaultRoute = "windowsNoDefaultRoute" windowsNoRoute = "windowsNoRoute" windows = "windows" ) var routeTables = map[string][]byte{ darwinBadRoute: []byte(` Routing tables Internet: Destination Gateway Flags Netif Expire default foo UGSg en0 10.88.88.0/24 link#1 U en0 10.88.88.148 link#1 UHS lo0 127.0.0.1 link#2 UH lo0 `), darwinNoRoute: []byte(` Routing tables Internet: Destination Gateway Flags Netif Expire 10.88.88.0/24 link#1 U en0 10.88.88.148 link#1 UHS lo0 127.0.0.1 link#2 UH lo0 `), darwin: []byte(` Routing tables Internet: Destination Gateway Flags Netif Expire default link#17 UCSg utun3 default 192.168.1.254 UGScIg en0 `), freeBSDBadRoute: []byte(` Routing tables Internet: Destination Gateway Flags Netif Expire default foo UGS ena0 10.88.88.0/24 link#1 U ena0 10.88.88.148 link#1 UHS lo0 127.0.0.1 link#2 UH lo0 `), freeBSDNoRoute: []byte(` Routing tables Internet: Destination Gateway Flags Netif Expire 10.88.88.0/24 link#1 U ena0 10.88.88.148 link#1 UHS lo0 127.0.0.1 link#2 UH lo0 `), freeBSD: []byte(` Routing tables Internet: Destination Gateway Flags Netif Expire default 10.88.88.2 UGS ena0 127.0.0.1 link#2 UH lo0 172.31.16.0/20 link#1 U ena0 172.31.29.64 link#1 UHS lo0 Internet6: Destination Gateway Flags Netif Expire ::/96 ::1 UGRS lo0 ::1 link#2 UHS lo0 ::ffff:0.0.0.0/96 ::1 UGRS lo0 fe80::/10 ::1 UGRS lo0 fe80::%%ena0/64 link#1 U ena0 fe80::4fc:21ff:feeb:60c5%%ena0 link#1 UHS lo0 fe80::%%lo0/64 link#2 U lo0 fe80::1%%lo0 link#2 UHS lo0 ff02::/16 ::1 UGRS lo0 `), linuxNoRoute: []byte(` Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT `), linux: []byte(` Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT wlp4s0 0000FEA9 00000000 0001 0 0 1000 0000FFFF 0 0 0 docker0 000011AC 00000000 0001 0 0 0 0000FFFF 0 0 0 docker_gwbridge 000012AC 00000000 0001 0 0 0 0000FFFF 0 0 0 wlp4s0 0008A8C0 00000000 0001 0 0 600 00FFFFFF 0 0 0 wlp4s0 00000000 0108A8C0 0003 0 0 600 00000000 0 0 0 `), netBSDBadRoute: []byte(` Routing tables Internet: Destination Gateway Flags Refs Use Mtu Interface default foo UG - - 9001 ena0 127/8 127.0.0.1 UGRS - - 33624 lo0 127.0.0.1 lo0 UHl - - 33624 lo0 `), netBSDNoRoute: []byte(` Routing tables Internet: Destination Gateway Flags Refs Use Mtu Interface 127/8 127.0.0.1 UGRS - - 33624 lo0 127.0.0.1 lo0 UHl - - 33624 lo0 172.31.16/20 link#1 UC - - 9001 ena0 172.31.22.254 link#1 UHl - - - lo0 172.31.16.1 06:fd:6a:57:a9:12 UHL - - - ena0 `), netBSD: []byte(` Routing tables Internet: Destination Gateway Flags Refs Use Mtu Interface default 172.31.16.1 UG - - 9001 ena0 127/8 127.0.0.1 UGRS - - 33624 lo0 127.0.0.1 lo0 UHl - - 33624 lo0 172.31.16/20 link#1 UC - - 9001 ena0 172.31.22.254 link#1 UHl - - - lo0 172.31.16.1 06:fd:6a:57:a9:12 UHL - - - ena0 Internet6: Destination Gateway Flags Refs Use Mtu Interface ::/104 ::1 UGRS - - 33624 lo0 ::/96 ::1 UGRS - - 33624 lo0 ::1 lo0 UHl - - 33624 lo0 ::127.0.0.0/104 ::1 UGRS - - 33624 lo0 ::224.0.0.0/100 ::1 UGRS - - 33624 lo0 ::255.0.0.0/104 ::1 UGRS - - 33624 lo0 ::ffff:0.0.0.0/96 ::1 UGRS - - 33624 lo0 2001:db8::/32 ::1 UGRS - - 33624 lo0 2002::/24 ::1 UGRS - - 33624 lo0 2002:7f00::/24 ::1 UGRS - - 33624 lo0 2002:e000::/20 ::1 UGRS - - 33624 lo0 2002:ff00::/24 ::1 UGRS - - 33624 lo0 fe80::/10 ::1 UGRS - - 33624 lo0 fe80::%%ena0/64 link#1 UC - - - ena0 fe80::9508:280a:c38e:4e4a link#1 UHl - - - lo0 fe80::%%lo0/64 fe80::1 U - - - lo0 fe80::1 lo0 UHl - - - lo0 ff01:1::/32 link#1 UC - - - ena0 ff01:2::/32 ::1 UC - - 33624 lo0 ff02::%%ena0/32 link#1 UC - - - ena0 ff02::%%lo0/32 ::1 UC - - 33624 lo0`), randomData: []byte(` test Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation `), solarisBadRoute: []byte(` Routing Table: IPv4 Destination Gateway Flags Ref Use Interface -------------------- -------------------- ----- ----- ---------- --------- default foo UG 2 76419 net0 127.0.0.1 127.0.0.1 UH 2 36 lo0 172.16.32.0 172.16.32.17 U 4 8100 net0 Routing Table: IPv6 Destination/Mask Gateway Flags Ref Use If --------------------------- --------------------------- ----- --- ------- ----- ::1 ::1 UH 3 75382 lo0 2001:470:deeb:32::/64 2001:470:deeb:32::17 U 3 2744 net0 fe80::/10 fe80::6082:52ff:fedc:7df0 U 3 8430 net0 `), solarisNoRoute: []byte(` Routing Table: IPv4 Destination Gateway Flags Ref Use Interface -------------------- -------------------- ----- ----- ---------- --------- 127.0.0.1 127.0.0.1 UH 2 36 lo0 172.16.32.0 172.16.32.17 U 4 8100 net0 Routing Table: IPv6 Destination/Mask Gateway Flags Ref Use If --------------------------- --------------------------- ----- --- ------- ----- ::1 ::1 UH 3 75382 lo0 2001:470:deeb:32::/64 2001:470:deeb:32::17 U 3 2744 net0 fe80::/10 fe80::6082:52ff:fedc:7df0 U 3 8430 net0 `), solaris: []byte(` Routing Table: IPv4 Destination Gateway Flags Ref Use Interface -------------------- -------------------- ----- ----- ---------- --------- default 172.16.32.1 UG 2 76419 net0 127.0.0.1 127.0.0.1 UH 2 36 lo0 172.16.32.0 172.16.32.17 U 4 8100 net0 Routing Table: IPv6 Destination/Mask Gateway Flags Ref Use If --------------------------- --------------------------- ----- --- ------- ----- ::1 ::1 UH 3 75382 lo0 2001:470:deeb:32::/64 2001:470:deeb:32::17 U 3 2744 net0 fe80::/10 fe80::6082:52ff:fedc:7df0 U 3 8430 net0 `), solarisNoInterface: []byte(` Routing Table: IPv4 Destination Gateway Flags Ref Use Interface -------------------- -------------------- ----- ----- ---------- --------- default 172.16.32.1 UG 49 681748414 127.0.0.1 127.0.0.1 UH 2 52832 lo0 172.16.32.0 172.16.32.17 U 5 1450483 net0 Routing Table: IPv6 Destination/Mask Gateway Flags Ref Use If --------------------------- --------------------------- ----- --- ------- ----- ::1 ::1 UH 2 966 lo0 fe80::/10 fe80::aabb:ccdd:1234:2 U 5 77620 net0 default fe80::aabb:ccdd:1234:1 UG 3 4092447 `), windowsBadRoute1: []byte(` =========================================================================== Interface List 8 ...00 12 3f a7 17 ba ...... Intel(R) PRO/100 VE Network Connection 1 ........................... Software Loopback Interface 1 =========================================================================== IPv4 Route Table =========================================================================== Active Routes: =========================================================================== Persistent Routes: `), windowsBadRoute2: []byte(` =========================================================================== Interface List 8 ...00 12 3f a7 17 ba ...... Intel(R) PRO/100 VE Network Connection 1 ........................... Software Loopback Interface 1 =========================================================================== IPv4 Route Table =========================================================================== Active Routes: Network Destination Netmask Gateway Interface Metric 0.0.0.0 0.0.0.0 foo 10.88.88.149 10 =========================================================================== Persistent Routes: `), windowsLocalized: []byte(` =========================================================================== Liste d'Interfaces 17...00 28 f8 39 61 6b ......Microsoft Wi-Fi Direct Virtual Adapter 1...........................Software Loopback Interface 1 =========================================================================== IPv4 Table de routage =========================================================================== Itinéraires actifs : Destination réseau Masque réseau Adr. passerelle Adr. interface Métrique 0.0.0.0 0.0.0.0 10.88.88.2 10.88.88.149 10 =========================================================================== Itinéraires persistants : Aucun`), windowsMultipleGateways: []byte(` =========================================================================== Interface List 19...00 05 9a 3c 7a 00 ......Cisco AnyConnect Secure Mobility Client Virtual Miniport Adapter for Windows x64 37...00 15 5d 0e 76 41 ......Hyper-V Virtual Ethernet Adapter 21...cc 15 31 1e 58 08 ......Microsoft Wi-Fi Direct Virtual Adapter 9...ce 15 31 1e 58 07 ......Microsoft Wi-Fi Direct Virtual Adapter #2 6...cc 15 31 1e 58 07 ......Intel(R) Wi-Fi 6 AX201 160MHz 17...cc 15 31 1e 58 0b ......Bluetooth Device (Personal Area Network) 1...........................Software Loopback Interface 1 =========================================================================== IPv4 Route Table =========================================================================== Active Routes: Network Destination Netmask Gateway Interface Metric 0.0.0.0 0.0.0.0 192.168.100.1 192.168.100.74 50 0.0.0.0 0.0.0.0 10.21.38.1 10.21.38.97 2 =========================================================================== Persistent Routes: None IPv6 Route Table =========================================================================== Active Routes: None Persistent Routes: None`), windowsNoDefaultRoute: []byte(` =========================================================================== Interface List 8 ...00 12 3f a7 17 ba ...... Intel(R) PRO/100 VE Network Connection 1 ........................... Software Loopback Interface 1 =========================================================================== IPv4 Route Table =========================================================================== Active Routes: Network Destination Netmask Gateway Interface Metric 127.0.0.0 255.0.0.0 On-link 127.0.0.1 331 127.0.0.1 255.255.255.255 On-link 127.0.0.1 331 127.255.255.255 255.255.255.255 On-link 127.0.0.1 331 =========================================================================== Persistent Routes: `), windowsNoRoute: []byte(` =========================================================================== Interface List 8 ...00 12 3f a7 17 ba ...... Intel(R) PRO/100 VE Network Connection 1 ........................... Software Loopback Interface 1 =========================================================================== IPv4 Route Table =========================================================================== Active Routes: `), windows: []byte(` =========================================================================== Interface List 8 ...00 12 3f a7 17 ba ...... Intel(R) PRO/100 VE Network Connection 1 ........................... Software Loopback Interface 1 =========================================================================== IPv4 Route Table =========================================================================== Active Routes: Network Destination Netmask Gateway Interface Metric 0.0.0.0 0.0.0.0 10.88.88.2 10.88.88.149 10 127.0.0.0 255.0.0.0 On-link 127.0.0.1 331 127.0.0.1 255.255.255.255 On-link 127.0.0.1 331 127.255.255.255 255.255.255.255 On-link 127.0.0.1 331 =========================================================================== Persistent Routes: `), } gateway-1.0.16/route-tables/0000775000175000017510000000000014731376046015212 5ustar nileshnileshgateway-1.0.16/route-tables/windowsNoRoute.txt0000664000175000017510000000063014731376046020760 0ustar nileshnilesh=========================================================================== Interface List 8 ...00 12 3f a7 17 ba ...... Intel(R) PRO/100 VE Network Connection 1 ........................... Software Loopback Interface 1 =========================================================================== IPv4 Route Table =========================================================================== Active Routes: gateway-1.0.16/route-tables/windowsNoDefaultRoute.txt0000664000175000017510000000144714731376046022274 0ustar nileshnilesh=========================================================================== Interface List 8 ...00 12 3f a7 17 ba ...... Intel(R) PRO/100 VE Network Connection 1 ........................... Software Loopback Interface 1 =========================================================================== IPv4 Route Table =========================================================================== Active Routes: Network Destination Netmask Gateway Interface Metric 127.0.0.0 255.0.0.0 On-link 127.0.0.1 331 127.0.0.1 255.255.255.255 On-link 127.0.0.1 331 127.255.255.255 255.255.255.255 On-link 127.0.0.1 331 =========================================================================== Persistent Routes: gateway-1.0.16/route-tables/windowsMultipleGateways.txt0000664000175000017510000000234514731376046022672 0ustar nileshnilesh=========================================================================== Interface List 19...00 05 9a 3c 7a 00 ......Cisco AnyConnect Secure Mobility Client Virtual Miniport Adapter for Windows x64 37...00 15 5d 0e 76 41 ......Hyper-V Virtual Ethernet Adapter 21...cc 15 31 1e 58 08 ......Microsoft Wi-Fi Direct Virtual Adapter 9...ce 15 31 1e 58 07 ......Microsoft Wi-Fi Direct Virtual Adapter #2 6...cc 15 31 1e 58 07 ......Intel(R) Wi-Fi 6 AX201 160MHz 17...cc 15 31 1e 58 0b ......Bluetooth Device (Personal Area Network) 1...........................Software Loopback Interface 1 =========================================================================== IPv4 Route Table =========================================================================== Active Routes: Network Destination Netmask Gateway Interface Metric 0.0.0.0 0.0.0.0 192.168.100.1 192.168.100.74 50 0.0.0.0 0.0.0.0 10.21.38.1 10.21.38.97 2 =========================================================================== Persistent Routes: None IPv6 Route Table =========================================================================== Active Routes: None Persistent Routes: Nonegateway-1.0.16/route-tables/windowsLocalized.txt0000664000175000017510000000125714731376046021301 0ustar nileshnilesh=========================================================================== Liste d'Interfaces 17...00 28 f8 39 61 6b ......Microsoft Wi-Fi Direct Virtual Adapter 1...........................Software Loopback Interface 1 =========================================================================== IPv4 Table de routage =========================================================================== Itinéraires actifs : Destination réseau Masque réseau Adr. passerelle Adr. interface Métrique 0.0.0.0 0.0.0.0 10.88.88.2 10.88.88.149 10 =========================================================================== Itinéraires persistants : Aucungateway-1.0.16/route-tables/windowsBadRoute2.txt0000664000175000017510000000122114731376046021151 0ustar nileshnilesh=========================================================================== Interface List 8 ...00 12 3f a7 17 ba ...... Intel(R) PRO/100 VE Network Connection 1 ........................... Software Loopback Interface 1 =========================================================================== IPv4 Route Table =========================================================================== Active Routes: Network Destination Netmask Gateway Interface Metric 0.0.0.0 0.0.0.0 foo 10.88.88.149 10 =========================================================================== Persistent Routes: gateway-1.0.16/route-tables/windowsBadRoute1.txt0000664000175000017510000000076714731376046021166 0ustar nileshnilesh=========================================================================== Interface List 8 ...00 12 3f a7 17 ba ...... Intel(R) PRO/100 VE Network Connection 1 ........................... Software Loopback Interface 1 =========================================================================== IPv4 Route Table =========================================================================== Active Routes: =========================================================================== Persistent Routes: gateway-1.0.16/route-tables/windows.txt0000664000175000017510000000156314731376046017452 0ustar nileshnilesh=========================================================================== Interface List 8 ...00 12 3f a7 17 ba ...... Intel(R) PRO/100 VE Network Connection 1 ........................... Software Loopback Interface 1 =========================================================================== IPv4 Route Table =========================================================================== Active Routes: Network Destination Netmask Gateway Interface Metric 0.0.0.0 0.0.0.0 10.88.88.2 10.88.88.149 10 127.0.0.0 255.0.0.0 On-link 127.0.0.1 331 127.0.0.1 255.255.255.255 On-link 127.0.0.1 331 127.255.255.255 255.255.255.255 On-link 127.0.0.1 331 =========================================================================== Persistent Routes: gateway-1.0.16/route-tables/solarisNoRoute.txt0000664000175000017510000000132214731376046020741 0ustar nileshnileshRouting Table: IPv4 Destination Gateway Flags Ref Use Interface -------------------- -------------------- ----- ----- ---------- --------- 127.0.0.1 127.0.0.1 UH 2 36 lo0 172.16.32.0 172.16.32.17 U 4 8100 net0 Routing Table: IPv6 Destination/Mask Gateway Flags Ref Use If --------------------------- --------------------------- ----- --- ------- ----- ::1 ::1 UH 3 75382 lo0 2001:470:deeb:32::/64 2001:470:deeb:32::17 U 3 2744 net0 fe80::/10 fe80::6082:52ff:fedc:7df0 U 3 8430 net0 gateway-1.0.16/route-tables/solarisNoInterface.txt0000664000175000017510000000141714731376046021550 0ustar nileshnileshRouting Table: IPv4 Destination Gateway Flags Ref Use Interface -------------------- -------------------- ----- ----- ---------- --------- default 172.16.32.1 UG 49 681748414 127.0.0.1 127.0.0.1 UH 2 52832 lo0 172.16.32.0 172.16.32.17 U 5 1450483 net0 Routing Table: IPv6 Destination/Mask Gateway Flags Ref Use If --------------------------- --------------------------- ----- --- ------- ----- ::1 ::1 UH 2 966 lo0 fe80::/10 fe80::aabb:ccdd:1234:2 U 5 77620 net0 default fe80::aabb:ccdd:1234:1 UG 3 4092447gateway-1.0.16/route-tables/solarisBadRoute.txt0000664000175000017510000000143014731376046021053 0ustar nileshnileshRouting Table: IPv4 Destination Gateway Flags Ref Use Interface -------------------- -------------------- ----- ----- ---------- --------- default foo UG 2 76419 net0 127.0.0.1 127.0.0.1 UH 2 36 lo0 172.16.32.0 172.16.32.17 U 4 8100 net0 Routing Table: IPv6 Destination/Mask Gateway Flags Ref Use If --------------------------- --------------------------- ----- --- ------- ----- ::1 ::1 UH 3 75382 lo0 2001:470:deeb:32::/64 2001:470:deeb:32::17 U 3 2744 net0 fe80::/10 fe80::6082:52ff:fedc:7df0 U 3 8430 net0 gateway-1.0.16/route-tables/solaris.txt0000664000175000017510000000143014731376046017425 0ustar nileshnileshRouting Table: IPv4 Destination Gateway Flags Ref Use Interface -------------------- -------------------- ----- ----- ---------- --------- default 172.16.32.1 UG 2 76419 net0 127.0.0.1 127.0.0.1 UH 2 36 lo0 172.16.32.0 172.16.32.17 U 4 8100 net0 Routing Table: IPv6 Destination/Mask Gateway Flags Ref Use If --------------------------- --------------------------- ----- --- ------- ----- ::1 ::1 UH 3 75382 lo0 2001:470:deeb:32::/64 2001:470:deeb:32::17 U 3 2744 net0 fe80::/10 fe80::6082:52ff:fedc:7df0 U 3 8430 net0 gateway-1.0.16/route-tables/randomData.txt0000664000175000017510000000026414731376046020027 0ustar nileshnileshtest Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation gateway-1.0.16/route-tables/netBSDNoRoute.txt0000664000175000017510000000072714731376046020414 0ustar nileshnileshRouting tables Internet: Destination Gateway Flags Refs Use Mtu Interface 127/8 127.0.0.1 UGRS - - 33624 lo0 127.0.0.1 lo0 UHl - - 33624 lo0 172.31.16/20 link#1 UC - - 9001 ena0 172.31.22.254 link#1 UHl - - - lo0 172.31.16.1 06:fd:6a:57:a9:12 UHL - - - ena0 gateway-1.0.16/route-tables/netBSDBadRoute.txt0000664000175000017510000000050414731376046020517 0ustar nileshnileshRouting tables Internet: Destination Gateway Flags Refs Use Mtu Interface default foo UG - - 9001 ena0 127/8 127.0.0.1 UGRS - - 33624 lo0 127.0.0.1 lo0 UHl - - 33624 lo0 gateway-1.0.16/route-tables/netBSD.txt0000664000175000017510000000552014731376046017074 0ustar nileshnileshRouting tables Internet: Destination Gateway Flags Refs Use Mtu Interface default 172.31.16.1 UG - - 9001 ena0 127/8 127.0.0.1 UGRS - - 33624 lo0 127.0.0.1 lo0 UHl - - 33624 lo0 172.31.16/20 link#1 UC - - 9001 ena0 172.31.22.254 link#1 UHl - - - lo0 172.31.16.1 06:fd:6a:57:a9:12 UHL - - - ena0 Internet6: Destination Gateway Flags Refs Use Mtu Interface ::/104 ::1 UGRS - - 33624 lo0 ::/96 ::1 UGRS - - 33624 lo0 ::1 lo0 UHl - - 33624 lo0 ::127.0.0.0/104 ::1 UGRS - - 33624 lo0 ::224.0.0.0/100 ::1 UGRS - - 33624 lo0 ::255.0.0.0/104 ::1 UGRS - - 33624 lo0 ::ffff:0.0.0.0/96 ::1 UGRS - - 33624 lo0 2001:db8::/32 ::1 UGRS - - 33624 lo0 2002::/24 ::1 UGRS - - 33624 lo0 2002:7f00::/24 ::1 UGRS - - 33624 lo0 2002:e000::/20 ::1 UGRS - - 33624 lo0 2002:ff00::/24 ::1 UGRS - - 33624 lo0 fe80::/10 ::1 UGRS - - 33624 lo0 fe80::%ena0/64 link#1 UC - - - ena0 fe80::9508:280a:c38e:4e4a link#1 UHl - - - lo0 fe80::%lo0/64 fe80::1 U - - - lo0 fe80::1 lo0 UHl - - - lo0 ff01:1::/32 link#1 UC - - - ena0 ff01:2::/32 ::1 UC - - 33624 lo0 ff02::%ena0/32 link#1 UC - - - ena0 ff02::%lo0/32 ::1 UC - - 33624 lo0gateway-1.0.16/route-tables/linuxNoRoute.txt0000664000175000017510000000010714731376046020424 0ustar nileshnileshIface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT gateway-1.0.16/route-tables/linux.txt0000664000175000017510000000053114731376046017111 0ustar nileshnileshIface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT wlp4s0 0000FEA9 00000000 0001 0 0 1000 0000FFFF 0 0 0 docker0 000011AC 00000000 0001 0 0 0 0000FFFF 0 0 0 docker_gwbridge 000012AC 00000000 0001 0 0 0 0000FFFF 0 0 0 wlp4s0 0008A8C0 00000000 0001 0 0 600 00FFFFFF 0 0 0 wlp4s0 00000000 0108A8C0 0003 0 0 600 00000000 0 0 0 gateway-1.0.16/route-tables/freeBSDNoRoute.txt0000664000175000017510000000037214731376046020543 0ustar nileshnileshRouting tables Internet: Destination Gateway Flags Netif Expire 10.88.88.0/24 link#1 U ena0 10.88.88.148 link#1 UHS lo0 127.0.0.1 link#2 UH lo0 gateway-1.0.16/route-tables/freeBSDBadRoute.txt0000664000175000017510000000046014731376046020653 0ustar nileshnileshRouting tables Internet: Destination Gateway Flags Netif Expire default foo UGS ena0 10.88.88.0/24 link#1 U ena0 10.88.88.148 link#1 UHS lo0 127.0.0.1 link#2 UH lo0 gateway-1.0.16/route-tables/freeBSD.txt0000664000175000017510000000214214731376046017224 0ustar nileshnileshRouting tables Internet: Destination Gateway Flags Netif Expire default 10.88.88.2 UGS ena0 127.0.0.1 link#2 UH lo0 172.31.16.0/20 link#1 U ena0 172.31.29.64 link#1 UHS lo0 Internet6: Destination Gateway Flags Netif Expire ::/96 ::1 UGRS lo0 ::1 link#2 UHS lo0 ::ffff:0.0.0.0/96 ::1 UGRS lo0 fe80::/10 ::1 UGRS lo0 fe80::%ena0/64 link#1 U ena0 fe80::4fc:21ff:feeb:60c5%ena0 link#1 UHS lo0 fe80::%lo0/64 link#2 U lo0 fe80::1%lo0 link#2 UHS lo0 ff02::/16 ::1 UGRS lo0 gateway-1.0.16/route-tables/darwinNoRoute.txt0000664000175000017510000000037214731376046020555 0ustar nileshnileshRouting tables Internet: Destination Gateway Flags Netif Expire 10.88.88.0/24 link#1 U en0 10.88.88.148 link#1 UHS lo0 127.0.0.1 link#2 UH lo0 gateway-1.0.16/route-tables/darwinBadRoute.txt0000664000175000017510000000046014731376046020665 0ustar nileshnileshRouting tables Internet: Destination Gateway Flags Netif Expire default foo UGSg en0 10.88.88.0/24 link#1 U en0 10.88.88.148 link#1 UHS lo0 127.0.0.1 link#2 UH lo0 gateway-1.0.16/route-tables/darwin.txt0000664000175000017510000000036114731376046017237 0ustar nileshnileshRouting tables Internet: Destination Gateway Flags Netif Expire default link#17 UCSg utun3 default 192.168.1.254 UGScIg en0 gateway-1.0.16/notes/0000775000175000017510000000000014731376046013734 5ustar nileshnileshgateway-1.0.16/notes/evidence.md0000664000175000017510000001542214731376046016044 0ustar nileshnilesh# Real world test outputs ## Test code ```go package main import ( "fmt" "lib/gateway" "runtime" ) func main() { fmt.Printf("OS: %s\n", runtime.GOOS) gw, err := gateway.DiscoverGateway() if err == nil { fmt.Printf("Gateway: %v\n", gw) } else { fmt.Printf("Gateway error: %s", err) } iface, err := gateway.DiscoverInterface() if err == nil { fmt.Printf("Iface: %v\n", iface) } else { fmt.Printf("Iface error: %s", err) } } ``` ## Darwin I don't have a Mac, nor am I prepared to pay $26 to spin one up in AWS (minimum charge 24 hours), but since it's using the same code path as the BSDs below and the unit tests work, I expect it to work. ## Solaris AWS doesn't have any Solaris instances I can find, however the same goes for unit tests as for Darwin. ## FreeBSD ``` ec2-user@freebsd:~/src/gateway-test $ go run test.go OS: freebsd Gateway: 172.31.32.1 Iface: 172.31.32.246 ec2-user@freebsd:~/src/gateway-test $ netstat -rn Routing tables Internet: Destination Gateway Flags Netif Expire default 172.31.32.1 UGS xn0 127.0.0.1 link#1 UH lo0 172.31.32.0/20 link#2 U xn0 172.31.32.246 link#2 UHS lo0 Internet6: Destination Gateway Flags Netif Expire ::/96 ::1 URS lo0 ::1 link#1 UHS lo0 ::ffff:0.0.0.0/96 ::1 URS lo0 fe80::/10 ::1 URS lo0 fe80::%lo0/64 link#1 U lo0 fe80::1%lo0 link#1 UHS lo0 fe80::%xn0/64 link#2 U xn0 fe80::8db:f4ff:fe5b:2fd3%xn0 link#2 UHS lo0 ff02::/16 ::1 URS lo0 ec2-user@freebsd:~/src/gateway-test $ ifconfig lo0: flags=8049 metric 0 mtu 16384 options=680003 inet6 ::1 prefixlen 128 inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1 inet 127.0.0.1 netmask 0xff000000 groups: lo nd6 options=21 xn0: flags=8843 metric 0 mtu 9001 options=503 ether 0a:db:f4:5b:2f:d3 inet6 fe80::8db:f4ff:fe5b:2fd3%xn0 prefixlen 64 scopeid 0x2 inet 172.31.32.246 netmask 0xfffff000 broadcast 172.31.47.255 media: Ethernet manual status: active nd6 options=23 ec2-user@freebsd:~/src/gateway-test $ uname -a FreeBSD freebsd 13.2-STABLE FreeBSD 13.2-STABLE stable/13-n256661-e9ad6b456b02 GENERIC amd64 ``` ## NetBSD ``` ip-172-31-22-132$ go run test.go OS: netbsd Gateway: 172.31.16.1 Iface: 172.31.22.132 ip-172-31-22-132$ netstat -rn Routing tables Internet: Destination Gateway Flags Refs Use Mtu Interface default 172.31.16.1 UG - - 9001 ena0 127/8 127.0.0.1 UGRS - - 33624 lo0 127.0.0.1 lo0 UHl - - 33624 lo0 172.31.16/20 link#1 UC - - 9001 ena0 172.31.22.132 link#1 UHl - - - lo0 172.31.16.1 06:fd:6a:57:a9:12 UHL - - - ena0 Internet6: Destination Gateway Flags Refs Use Mtu Interface ::/104 ::1 UGRS - - 33624 lo0 ::/96 ::1 UGRS - - 33624 lo0 ::1 lo0 UHl - - 33624 lo0 ::127.0.0.0/104 ::1 UGRS - - 33624 lo0 ::224.0.0.0/100 ::1 UGRS - - 33624 lo0 ::255.0.0.0/104 ::1 UGRS - - 33624 lo0 ::ffff:0.0.0.0/96 ::1 UGRS - - 33624 lo0 2001:db8::/32 ::1 UGRS - - 33624 lo0 2002::/24 ::1 UGRS - - 33624 lo0 2002:7f00::/24 ::1 UGRS - - 33624 lo0 2002:e000::/20 ::1 UGRS - - 33624 lo0 2002:ff00::/24 ::1 UGRS - - 33624 lo0 fe80::/10 ::1 UGRS - - 33624 lo0 fe80::%ena0/64 link#1 UC - - - ena0 fe80::b38c:bca1:ab84:2e97 link#1 UHl - - - lo0 fe80::%lo0/64 fe80::1 U - - - lo0 fe80::1 lo0 UHl - - - lo0 ff01:1::/32 link#1 UC - - - ena0 ff01:2::/32 ::1 UC - - 33624 lo0 ff02::%ena0/32 link#1 UC - - - ena0 ff02::%lo0/32 ::1 UC - - 33624 lo0 ip-172-31-22-132$ ifconfig ena0: flags=0x8843 mtu 1500 capabilities=0x200 enabled=0x200 ec_capabilities=0x4 ec_enabled=0 address: 06:74:f1:42:54:23 media: Ethernet autoselect status: active inet6 fe80::b38c:bca1:ab84:2e97%ena0/64 flags 0 scopeid 0x1 inet 172.31.22.132/20 broadcast 172.31.31.255 flags 0 lo0: flags=0x8049 mtu 33624 status: active inet6 ::1/128 flags 0x20 inet6 fe80::1%lo0/64 flags 0 scopeid 0x2 inet 127.0.0.1/8 flags 0 ip-172-31-22-132$ uname -a NetBSD ip-172-31-22-132.eu-west-1.compute.internal 9.99.100 NetBSD 9.99.100 (GENERIC64) #0: Sun Oct 2 23:36:41 UTC 2022 mkrepro@mkrepro.NetBSD.org:/usr/src/sys/arch/evbarm/compile/GENERIC64 evbarm ```gateway-1.0.16/net_interface.go0000664000175000017510000000104214731376046015736 0ustar nileshnileshpackage gateway import "net" // Wrapper for calls into the go "net" library that can be mocked for tests type interfaceGetter interface { InterfaceByName(name string) (*net.Interface, error) Addrs(iface *net.Interface) ([]net.Addr, error) } // Concrete implementation of above interface type intefaceGetterImpl struct{} func (*intefaceGetterImpl) InterfaceByName(name string) (*net.Interface, error) { return net.InterfaceByName(name) } func (*intefaceGetterImpl) Addrs(iface *net.Interface) ([]net.Addr, error) { return iface.Addrs() } gateway-1.0.16/mock_interfaceGetter.go0000664000175000017510000001002514731376046017255 0ustar nileshnilesh// Code generated by mockery v2.36.0. DO NOT EDIT. package gateway import ( net "net" mock "github.com/stretchr/testify/mock" ) // mockinterfaceGetter is an autogenerated mock type for the interfaceGetter type type mockinterfaceGetter struct { mock.Mock } type mockinterfaceGetter_Expecter struct { mock *mock.Mock } func (_m *mockinterfaceGetter) EXPECT() *mockinterfaceGetter_Expecter { return &mockinterfaceGetter_Expecter{mock: &_m.Mock} } // Addrs provides a mock function with given fields: iface func (_m *mockinterfaceGetter) Addrs(iface *net.Interface) ([]net.Addr, error) { ret := _m.Called(iface) var r0 []net.Addr var r1 error if rf, ok := ret.Get(0).(func(*net.Interface) ([]net.Addr, error)); ok { return rf(iface) } if rf, ok := ret.Get(0).(func(*net.Interface) []net.Addr); ok { r0 = rf(iface) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]net.Addr) } } if rf, ok := ret.Get(1).(func(*net.Interface) error); ok { r1 = rf(iface) } else { r1 = ret.Error(1) } return r0, r1 } // mockinterfaceGetter_Addrs_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Addrs' type mockinterfaceGetter_Addrs_Call struct { *mock.Call } // Addrs is a helper method to define mock.On call // - iface *net.Interface func (_e *mockinterfaceGetter_Expecter) Addrs(iface interface{}) *mockinterfaceGetter_Addrs_Call { return &mockinterfaceGetter_Addrs_Call{Call: _e.mock.On("Addrs", iface)} } func (_c *mockinterfaceGetter_Addrs_Call) Run(run func(iface *net.Interface)) *mockinterfaceGetter_Addrs_Call { _c.Call.Run(func(args mock.Arguments) { run(args[0].(*net.Interface)) }) return _c } func (_c *mockinterfaceGetter_Addrs_Call) Return(_a0 []net.Addr, _a1 error) *mockinterfaceGetter_Addrs_Call { _c.Call.Return(_a0, _a1) return _c } func (_c *mockinterfaceGetter_Addrs_Call) RunAndReturn(run func(*net.Interface) ([]net.Addr, error)) *mockinterfaceGetter_Addrs_Call { _c.Call.Return(run) return _c } // InterfaceByName provides a mock function with given fields: name func (_m *mockinterfaceGetter) InterfaceByName(name string) (*net.Interface, error) { ret := _m.Called(name) var r0 *net.Interface var r1 error if rf, ok := ret.Get(0).(func(string) (*net.Interface, error)); ok { return rf(name) } if rf, ok := ret.Get(0).(func(string) *net.Interface); ok { r0 = rf(name) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*net.Interface) } } if rf, ok := ret.Get(1).(func(string) error); ok { r1 = rf(name) } else { r1 = ret.Error(1) } return r0, r1 } // mockinterfaceGetter_InterfaceByName_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'InterfaceByName' type mockinterfaceGetter_InterfaceByName_Call struct { *mock.Call } // InterfaceByName is a helper method to define mock.On call // - name string func (_e *mockinterfaceGetter_Expecter) InterfaceByName(name interface{}) *mockinterfaceGetter_InterfaceByName_Call { return &mockinterfaceGetter_InterfaceByName_Call{Call: _e.mock.On("InterfaceByName", name)} } func (_c *mockinterfaceGetter_InterfaceByName_Call) Run(run func(name string)) *mockinterfaceGetter_InterfaceByName_Call { _c.Call.Run(func(args mock.Arguments) { run(args[0].(string)) }) return _c } func (_c *mockinterfaceGetter_InterfaceByName_Call) Return(_a0 *net.Interface, _a1 error) *mockinterfaceGetter_InterfaceByName_Call { _c.Call.Return(_a0, _a1) return _c } func (_c *mockinterfaceGetter_InterfaceByName_Call) RunAndReturn(run func(string) (*net.Interface, error)) *mockinterfaceGetter_InterfaceByName_Call { _c.Call.Return(run) return _c } // newMockinterfaceGetter creates a new instance of mockinterfaceGetter. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func newMockinterfaceGetter(t interface { mock.TestingT Cleanup(func()) }) *mockinterfaceGetter { mock := &mockinterfaceGetter{} mock.Mock.Test(t) t.Cleanup(func() { mock.AssertExpectations(t) }) return mock } gateway-1.0.16/go.sum0000664000175000017510000000251214731376046013737 0ustar nileshnileshgithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gateway-1.0.16/go.mod0000664000175000017510000000046614731376046013720 0ustar nileshnileshmodule github.com/jackpal/gateway go 1.21 require ( github.com/stretchr/testify v1.9.0 golang.org/x/net v0.33.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/stretchr/objx v0.5.2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) gateway-1.0.16/gateway_windows.go0000664000175000017510000000125314731376046016347 0ustar nileshnilesh// +build windows package gateway import ( "net" "os/exec" "syscall" ) func discoverGatewayOSSpecific() (ip net.IP, err error) { routeCmd := exec.Command("route", "print", "0.0.0.0") routeCmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true} output, err := routeCmd.CombinedOutput() if err != nil { return nil, err } return parseWindowsGatewayIP(output) } func discoverGatewayInterfaceOSSpecific() (ip net.IP, err error) { routeCmd := exec.Command("route", "print", "0.0.0.0") routeCmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true} output, err := routeCmd.CombinedOutput() if err != nil { return nil, err } return parseWindowsInterfaceIP(output) } gateway-1.0.16/gateway_unimplemented.go0000664000175000017510000000064014731376046017522 0ustar nileshnilesh//go:build !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd && !solaris && !windows // +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris,!windows package gateway import ( "net" ) func discoverGatewayOSSpecific() (ip net.IP, err error) { return ip, &ErrNotImplemented{} } func discoverGatewayInterfaceOSSpecific() (ip net.IP, err error) { return nil, &ErrNotImplemented{} } gateway-1.0.16/gateway_test.go0000664000175000017510000002067714731376046015647 0ustar nileshnilesh//go:generate tools/generate-tables.sh package gateway import ( "errors" "fmt" "net" "strings" "testing" "github.com/stretchr/testify/mock" ) // For tests where an IP is parsed directly from route table type ipTestCase struct { // Name of route table (tes_route_tables.go) tableName string // True if valid data expected ok bool // Dotted IP to assert ifaceIP string // Expected error, or nil if none expected expectedError error } // For tests where an interface name is parsed from route table type ifaceTestCase struct { // Name of route table (tes_route_tables.go) tableName string // Name of interface expected from route table ifaceName string // True if valid data expected ok bool // Dotted IP to assert ifaceIP string // Expected error, or nil if none expected expectedError error } func TestParseWindows(t *testing.T) { testcases := []ipTestCase{ {windows, true, "10.88.88.2", nil}, {windowsLocalized, true, "10.88.88.2", nil}, {windowsMultipleGateways, true, "10.21.38.1", nil}, {randomData, false, "", &ErrCantParse{}}, {windowsNoRoute, false, "", &ErrNoGateway{}}, {windowsNoDefaultRoute, false, "", &ErrNoGateway{}}, {windowsBadRoute1, false, "", &ErrCantParse{}}, {windowsBadRoute2, false, "", &ErrCantParse{}}, } t.Run("parseWindowsGatewayIP", func(t *testing.T) { testGatewayAddress(t, testcases, parseWindowsGatewayIP) }) // Note that even if the value in the gateway column is rubbish like "foo" // the interface name can still be looked up if the dest is 0.0.0.0 interfaceTestCases := []ipTestCase{ {windows, true, "10.88.88.149", nil}, {windowsLocalized, true, "10.88.88.149", nil}, {windowsMultipleGateways, true, "10.21.38.97", nil}, {randomData, false, "", &ErrCantParse{}}, {windowsNoRoute, false, "", &ErrNoGateway{}}, {windowsNoDefaultRoute, false, "", &ErrNoGateway{}}, {windowsBadRoute1, false, "", &ErrCantParse{}}, {windowsBadRoute2, true, "10.88.88.149", nil}, } t.Run("parseWindowsInterfaceIP", func(t *testing.T) { testGatewayAddress(t, interfaceTestCases, parseWindowsInterfaceIP) }) } func TestParseLinux(t *testing.T) { // Linux route tables are extracted from proc filesystem testcases := []ipTestCase{ {linux, true, "192.168.8.1", nil}, {linuxNoRoute, false, "", &ErrNoGateway{}}, } t.Run("parseLinuxGatewayIP", func(t *testing.T) { testGatewayAddress(t, testcases, parseLinuxGatewayIP) }) interfaceTestCases := []ifaceTestCase{ {linux, "wlp4s0", true, "192.168.2.1", nil}, {linuxNoRoute, "wlp4s0", false, "", &ErrNoGateway{}}, } t.Run("parseLinuxInterfaceIP", func(t *testing.T) { testInterfaceAddress(t, interfaceTestCases, parseLinuxInterfaceIPImpl) }) // ifData := []byte(`Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT // eth0 00000000 00000000 0001 0 0 1000 0000FFFF 0 0 0 // `) // interfaceTestCases := []testcase{ // {ifData, true, "192.168.8.238"}, // {noRoute, false, ""}, // } // to run interface test in your local computer, change eth0 with your default interface name, and change the expected IP to be your default IP // test(t, interfaceTestCases, parseLinuxInterfaceIP) } func TestParseUnix(t *testing.T) { // Unix route tables are extracted from netstat -rn testcases := []ipTestCase{ {darwin, true, "192.168.1.254", nil}, {freeBSD, true, "10.88.88.2", nil}, {netBSD, true, "172.31.16.1", nil}, {solaris, true, "172.16.32.1", nil}, {solarisNoInterface, true, "172.16.32.1", nil}, {randomData, false, "", &ErrCantParse{}}, {darwinNoRoute, false, "", &ErrNoGateway{}}, {darwinBadRoute, false, "", &ErrCantParse{}}, {freeBSDNoRoute, false, "", &ErrNoGateway{}}, {freeBSDBadRoute, false, "", &ErrCantParse{}}, {netBSDNoRoute, false, "", &ErrNoGateway{}}, {netBSDBadRoute, false, "", &ErrCantParse{}}, {solarisNoRoute, false, "", &ErrNoGateway{}}, {solarisBadRoute, false, "", &ErrCantParse{}}, } t.Run("parseUnixGatewayIP", func(t *testing.T) { testGatewayAddress(t, testcases, parseUnixGatewayIP) }) // Note that even if the value in the gateway column is rubbish like "foo" // the interface name can still be looked up if the dest is 0.0.0.0 interfaceTestCases := []ifaceTestCase{ {darwin, "en0", true, "192.168.1.254", nil}, {freeBSD, "ena0", true, "10.88.88.2", nil}, {netBSD, "ena0", true, "172.31.16.1", nil}, {solaris, "net0", true, "172.16.32.1", nil}, {solarisNoInterface, "", true, "172.16.32.1", nil}, {randomData, "", false, "", &ErrCantParse{}}, {darwinNoRoute, "", false, "", &ErrNoGateway{}}, {darwinBadRoute, "en0", true, "192.168.1.254", &ErrCantParse{}}, {freeBSDNoRoute, "", false, "", &ErrNoGateway{}}, {freeBSDBadRoute, "ena0", true, "10.88.88.2", nil}, {netBSDNoRoute, "", false, "", &ErrNoGateway{}}, {netBSDBadRoute, "ena0", true, "172.31.16.1", nil}, {solarisNoRoute, "", false, "", &ErrNoGateway{}}, {solarisBadRoute, "net0", true, "172.16.32.1", nil}, } t.Run("parseUnixInterfaceIP", func(t *testing.T) { testInterfaceAddress(t, interfaceTestCases, parseUnixInterfaceIPImpl) }) } func testGatewayAddress(t *testing.T, testcases []ipTestCase, fn func([]byte) (net.IP, error)) { for i, tc := range testcases { t.Run(tc.tableName, func(t *testing.T) { net, err := fn(routeTables[tc.tableName]) if tc.ok { if err != nil { t.Errorf("Unexpected error in test #%d: %v", i, err) } if net.String() != tc.ifaceIP { t.Errorf("Unexpected gateway address %v != %s", net, tc.ifaceIP) } } else if err == nil { t.Errorf("Unexpected nil error in test #%d", i) } else if errors.Is(err, tc.expectedError) { // Correct error was retured return } else { t.Errorf("Expected error of type %T, got %T", tc.expectedError, err) } }) } } func testInterfaceAddress(t *testing.T, testcases []ifaceTestCase, fn func([]byte, interfaceGetter) (net.IP, error)) { for i, tc := range testcases { mockGetter := newMockinterfaceGetter(t) if tc.ok { // If the test is exepected to pass, i.e. return an interface IP, // then these methods must be called with the given arguments. // // Mock assertions will ensure they are called (or not if they're not supposed to be) mockGetter.On("InterfaceByName", tc.ifaceName).Return(&net.Interface{}, nil) mockGetter.On("Addrs", mock.AnythingOfType("*net.Interface")).Return([]net.Addr{ &net.IPNet{ IP: net.ParseIP("fe80::42:66ff:fe89:8a6b"), Mask: net.IPMask{}, }, &net.IPNet{ IP: net.ParseIP(tc.ifaceIP), Mask: net.IPMask{}, }, }, nil) } t.Run(tc.tableName, func(t *testing.T) { net, err := fn(routeTables[tc.tableName], mockGetter) if tc.ok { if err != nil { t.Errorf("Unexpected error in test #%d: %v", i, err) } if net.String() != tc.ifaceIP { t.Errorf("Unexpected interface address %v != %s", net, tc.ifaceIP) } } else if err == nil { t.Errorf("Unexpected nil error in test #%d", i) } else if errors.Is(err, tc.expectedError) { // Correct error was retured return } else { t.Errorf("Expected error of type %T, got %T", tc.expectedError, err) } }) } } func TestFlagsContain(t *testing.T) { type testcase struct { flags string required []string expectectResult bool } testcases := []testcase{ {"UGS", []string{"U", "G"}, true}, {"UH", []string{"U", "G"}, false}, {"U", []string{"U", "G"}, false}, {"UHS", []string{"U", "G"}, false}, {"UHl", []string{"U", "G"}, false}, {"UGScIg", []string{"U", "G"}, true}, } for _, testcase := range testcases { t.Run(fmt.Sprintf("%s: %s is %v", testcase.flags, strings.Join(testcase.required, ","), testcase.expectectResult), func(t *testing.T) { if !flagsContain(testcase.flags, testcase.required...) == testcase.expectectResult { t.Errorf("Expected %s to contain %v", testcase.flags, testcase.required) } }) } } func TestDiscoverFields(t *testing.T) { type testcase struct { name string routeTable []byte } testcases := []testcase{ {"darwin", routeTables[darwin]}, {"FreeBSD", routeTables[freeBSD]}, {"NetBSD", routeTables[netBSD]}, {"Solaris", routeTables[solaris]}, {"Illumos", routeTables[solarisNoInterface]}, } for _, testcase := range testcases { t.Run(testcase.name, func(t *testing.T) { lineNo, _ := discoverFields(testcase.routeTable) if lineNo == -1 { t.Error("Could not parse route table fields") } }) } } func ExampleDiscoverGateway() { gateway, err := DiscoverGateway() if err != nil { fmt.Println(err) } else { fmt.Println("Gateway:", gateway.String()) } } gateway-1.0.16/gateway_solaris.go0000664000175000017510000000103314731376046016325 0ustar nileshnilesh//go:build solaris // +build solaris package gateway import ( "net" "os/exec" ) func readNetstat() ([]byte, error) { routeCmd := exec.Command("netstat", "-rn") return routeCmd.CombinedOutput() } func discoverGatewayOSSpecific() (ip net.IP, err error) { bytes, err := readNetstat() if err != nil { return nil, err } return parseUnixGatewayIP(bytes) } func discoverGatewayInterfaceOSSpecific() (ip net.IP, err error) { bytes, err := readNetstat() if err != nil { return nil, err } return parseUnixInterfaceIP(bytes) } gateway-1.0.16/gateway_parsers.go0000664000175000017510000002411214731376046016333 0ustar nileshnileshpackage gateway // References // * https://superuser.com/questions/622144/what-does-netstat-r-on-osx-tell-you-about-gateways // * https://man.freebsd.org/cgi/man.cgi?query=netstat&sektion=1 import ( "bufio" "bytes" "encoding/binary" "fmt" "net" "regexp" "slices" "strconv" "strings" ) const ( ns_destination = "Destination" ns_flags = "Flags" ns_netif = "Netif" ns_gateway = "Gateway" ns_interface = "Interface" ) type netstatFields map[string]int type windowsRouteStruct struct { // Dotted IP address Gateway string // Dotted IP address Interface string } type linuxRouteStruct struct { // Name of interface Iface string // big-endian hex string Gateway string } type unixRouteStruct struct { // Name of interface Iface string // Dotted IP address Gateway string } func fieldNum(name string, fields []string) int { // Return the zero-based index of given field in slice of field names for num, field := range fields { if name == field { return num } } return -1 } func discoverFields(output []byte) (int, netstatFields) { // Discover positions of fields of interest in netstat output nf := make(netstatFields, 4) outputLines := strings.Split(string(output), "\n") for lineNo, line := range outputLines { fields := strings.Fields(line) if len(fields) > 3 { d, f, g, netif, iface := fieldNum(ns_destination, fields), fieldNum(ns_flags, fields), fieldNum(ns_gateway, fields), fieldNum(ns_netif, fields), fieldNum(ns_interface, fields) if d >= 0 && f >= 0 && g >= 0 && (netif >= 0 || iface >= 0) { nf[ns_destination] = d nf[ns_flags] = f nf[ns_gateway] = g if iface > 0 { // NetBSD nf[ns_netif] = iface } else { // Other BSD/Solaris/Darwin nf[ns_netif] = netif } return lineNo, nf } } } // Unable to parse column headers return -1, nil } func flagsContain(flags string, flag ...string) bool { // Check route table flags field for existence of specific flags contain := true for _, f := range flag { contain = contain && strings.Contains(flags, f) } return contain } func parseToWindowsRouteStruct(output []byte) (windowsRouteStruct, error) { // Windows route output format is always like this: // =========================================================================== // Interface List // 8 ...00 12 3f a7 17 ba ...... Intel(R) PRO/100 VE Network Connection // 1 ........................... Software Loopback Interface 1 // =========================================================================== // IPv4 Route Table // =========================================================================== // Active Routes: // Network Destination Netmask Gateway Interface Metric // 0.0.0.0 0.0.0.0 192.168.1.1 192.168.1.100 20 // =========================================================================== // // Windows commands are localized, so we can't just look for "Active Routes:" string // I'm trying to pick the active route, // then jump 2 lines and get the row // Not using regex because output is quite standard from Windows XP to 8 (NEEDS TESTING) // // If multiple default gateways are present, then the one with the lowest metric is returned. type gatewayEntry struct { gateway string iface string metric int } ipRegex := regexp.MustCompile(`^(((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4})`) defaultRoutes := make([]gatewayEntry, 0, 2) lines := strings.Split(string(output), "\n") sep := 0 for idx, line := range lines { if sep == 3 { // We just entered the 2nd section containing "Active Routes:" if len(lines) <= idx+2 { return windowsRouteStruct{}, &ErrNoGateway{} } inputLine := lines[idx+2] if strings.HasPrefix(inputLine, "=======") { // End of routes break } fields := strings.Fields(inputLine) if len(fields) < 5 || !ipRegex.MatchString(fields[0]) { return windowsRouteStruct{}, &ErrCantParse{} } if fields[0] != "0.0.0.0" { // Routes to 0.0.0.0 are listed first // so we are done break } metric, err := strconv.Atoi(fields[4]) if err != nil { return windowsRouteStruct{}, err } defaultRoutes = append(defaultRoutes, gatewayEntry{ gateway: fields[2], iface: fields[3], metric: metric, }) } if strings.HasPrefix(line, "=======") { sep++ continue } } if sep == 0 { // We saw no separator lines, so input must have been garbage. return windowsRouteStruct{}, &ErrCantParse{} } if len(defaultRoutes) == 0 { return windowsRouteStruct{}, &ErrNoGateway{} } minDefaultRoute := slices.MinFunc(defaultRoutes, func(a, b gatewayEntry) int { return a.metric - b.metric }) return windowsRouteStruct{ Gateway: minDefaultRoute.gateway, Interface: minDefaultRoute.iface, }, nil } func parseToLinuxRouteStruct(output []byte) (linuxRouteStruct, error) { // parseLinuxProcNetRoute parses the route file located at /proc/net/route // and returns the IP address of the default gateway. The default gateway // is the one with Destination value of 0.0.0.0. // // The Linux route file has the following format: // // $ cat /proc/net/route // // Iface Destination Gateway Flags RefCnt Use Metric Mask // eno1 00000000 C900A8C0 0003 0 0 100 00000000 0 00 // eno1 0000A8C0 00000000 0001 0 0 100 00FFFFFF 0 00 const ( sep = "\t" // field separator destinationField = 1 // field containing hex destination address gatewayField = 2 // field containing hex gateway address maskField = 7 // field containing hex mask ) scanner := bufio.NewScanner(bytes.NewReader(output)) // Skip header line if !scanner.Scan() { err := scanner.Err() if err == nil { return linuxRouteStruct{}, &ErrNoGateway{} } return linuxRouteStruct{}, err } for scanner.Scan() { row := scanner.Text() tokens := strings.Split(row, sep) if len(tokens) < 11 { return linuxRouteStruct{}, &ErrInvalidRouteFileFormat{row: row} } // The default interface is the one that's 0 for both destination and mask. if !(tokens[destinationField] == "00000000" && tokens[maskField] == "00000000") { continue } return linuxRouteStruct{ Iface: tokens[0], Gateway: tokens[2], }, nil } return linuxRouteStruct{}, &ErrNoGateway{} } func parseWindowsGatewayIP(output []byte) (net.IP, error) { parsedOutput, err := parseToWindowsRouteStruct(output) if err != nil { return nil, err } ip := net.ParseIP(parsedOutput.Gateway) if ip == nil { return nil, &ErrCantParse{} } return ip, nil } func parseWindowsInterfaceIP(output []byte) (net.IP, error) { parsedOutput, err := parseToWindowsRouteStruct(output) if err != nil { return nil, err } ip := net.ParseIP(parsedOutput.Interface) if ip == nil { return nil, &ErrCantParse{} } return ip, nil } func parseLinuxGatewayIP(output []byte) (net.IP, error) { parsedStruct, err := parseToLinuxRouteStruct(output) if err != nil { return nil, err } // cast hex address to uint32 d, err := strconv.ParseUint(parsedStruct.Gateway, 16, 32) if err != nil { return nil, fmt.Errorf( "parsing default interface address field hex %q: %w", parsedStruct.Gateway, err, ) } // make net.IP address from uint32 ipd32 := make(net.IP, 4) binary.LittleEndian.PutUint32(ipd32, uint32(d)) return ipd32, nil } func parseLinuxInterfaceIP(output []byte) (net.IP, error) { // Return the first IPv4 address we encounter. return parseLinuxInterfaceIPImpl(output, &intefaceGetterImpl{}) } func parseLinuxInterfaceIPImpl(output []byte, ifaceGetter interfaceGetter) (net.IP, error) { // Mockable implemenation parsedStruct, err := parseToLinuxRouteStruct(output) if err != nil { return nil, err } return getInterfaceIP4(parsedStruct.Iface, ifaceGetter) } func parseUnixInterfaceIP(output []byte) (net.IP, error) { // Return the first IPv4 address we encounter. return parseUnixInterfaceIPImpl(output, &intefaceGetterImpl{}) } func parseUnixInterfaceIPImpl(output []byte, ifaceGetter interfaceGetter) (net.IP, error) { // Mockable implemenation parsedStruct, err := parseNetstatToRouteStruct(output) if err != nil { return nil, err } return getInterfaceIP4(parsedStruct.Iface, ifaceGetter) } func getInterfaceIP4(name string, ifaceGetter interfaceGetter) (net.IP, error) { // Given interface name and an interface to "net" package // lookup ip4 for the given interface iface, err := ifaceGetter.InterfaceByName(name) if err != nil { return nil, err } addrs, err := ifaceGetter.Addrs(iface) if err != nil { return nil, err } for _, addr := range addrs { ipnet, ok := addr.(*net.IPNet) if !ok { continue } ip := ipnet.IP.To4() if ip != nil { return ip, nil } } return nil, fmt.Errorf("no IPv4 address found for interface %v", name) } func parseUnixGatewayIP(output []byte) (net.IP, error) { // Extract default gateway IP from netstat route table parsedStruct, err := parseNetstatToRouteStruct(output) if err != nil { return nil, err } ip := net.ParseIP(parsedStruct.Gateway) if ip == nil { return nil, &ErrCantParse{} } return ip, nil } // Parse any netstat -rn output func parseNetstatToRouteStruct(output []byte) (unixRouteStruct, error) { startLine, nsFields := discoverFields(output) if startLine == -1 { // Unable to find required column headers in netstat output return unixRouteStruct{}, &ErrCantParse{} } outputLines := strings.Split(string(output), "\n") for lineNo, line := range outputLines { if lineNo <= startLine || strings.Contains(line, "-----") { // Skip until past column headers and heading underlines (solaris) continue } fields := strings.Fields(line) if len(fields) < 4 { // past route entries (got to end or blank line prior to ip6 entries) break } if fields[nsFields[ns_destination]] == "default" && flagsContain(fields[nsFields[ns_flags]], "U", "G") { iface := "" if ifaceIdx := nsFields[ns_netif]; ifaceIdx < len(fields) { iface = fields[nsFields[ns_netif]] } return unixRouteStruct{ Iface: iface, Gateway: fields[nsFields[ns_gateway]], }, nil } } return unixRouteStruct{}, &ErrNoGateway{} } gateway-1.0.16/gateway_linux.go0000664000175000017510000000142314731376046016013 0ustar nileshnilesh//go:build linux // +build linux package gateway import ( "fmt" "io" "net" "os" ) const ( // See http://man7.org/linux/man-pages/man8/route.8.html file = "/proc/net/route" ) func readRoutes() ([]byte, error) { f, err := os.Open(file) if err != nil { return nil, fmt.Errorf("can't access %s", file) } defer f.Close() bytes, err := io.ReadAll(f) if err != nil { return nil, fmt.Errorf("can't read %s", file) } return bytes, nil } func discoverGatewayOSSpecific() (ip net.IP, err error) { bytes, err := readRoutes() if err != nil { return nil, err } return parseLinuxGatewayIP(bytes) } func discoverGatewayInterfaceOSSpecific() (ip net.IP, err error) { bytes, err := readRoutes() if err != nil { return nil, err } return parseLinuxInterfaceIP(bytes) } gateway-1.0.16/gatewayForBSDs.go0000664000175000017510000000211514731376046015756 0ustar nileshnilesh//go:build darwin || dragonfly || freebsd || netbsd || openbsd package gateway import ( "net" "os/exec" "syscall" "golang.org/x/net/route" ) func readNetstat() ([]byte, error) { routeCmd := exec.Command("netstat", "-rn") return routeCmd.CombinedOutput() } func discoverGatewayOSSpecific() (ip net.IP, err error) { rib, err := route.FetchRIB(syscall.AF_INET, syscall.NET_RT_DUMP, 0) if err != nil { return nil, err } msgs, err := route.ParseRIB(syscall.NET_RT_DUMP, rib) if err != nil { return nil, err } for _, m := range msgs { switch m := m.(type) { case *route.RouteMessage: var ip net.IP switch sa := m.Addrs[syscall.RTAX_GATEWAY].(type) { case *route.Inet4Addr: ip = net.IPv4(sa.IP[0], sa.IP[1], sa.IP[2], sa.IP[3]) return ip, nil case *route.Inet6Addr: ip = make(net.IP, net.IPv6len) copy(ip, sa.IP[:]) return ip, nil } } } return nil, &ErrNoGateway{} } func discoverGatewayInterfaceOSSpecific() (ip net.IP, err error) { bytes, err := readNetstat() if err != nil { return nil, err } return parseUnixInterfaceIP(bytes) } gateway-1.0.16/gateway.go0000664000175000017510000000255714731376046014605 0ustar nileshnileshpackage gateway import ( "fmt" "net" "runtime" ) // ErrNoGateway is returned if a valid gateway entry was not // found in the route table. type ErrNoGateway struct{} // ErrCantParse is returned if the route table is garbage. type ErrCantParse struct{} // ErrNotImplemented is returned if your operating system // is not supported by this package. Please raise an issue // to request support. type ErrNotImplemented struct{} // ErrInvalidRouteFileFormat is returned if the format // of /proc/net/route is unexpected on Linux systems. // Please raise an issue. type ErrInvalidRouteFileFormat struct { row string } func (*ErrNoGateway) Error() string { return "no gateway found" } func (*ErrCantParse) Error() string { return "can't parse route table" } func (*ErrNotImplemented) Error() string { return "not implemented for OS: " + runtime.GOOS } func (e *ErrInvalidRouteFileFormat) Error() string { return fmt.Sprintf("invalid row %q in route file: doesn't have 11 fields", e.row) } // DiscoverGateway is the OS independent function to get the default gateway func DiscoverGateway() (ip net.IP, err error) { return discoverGatewayOSSpecific() } // DiscoverInterface is the OS independent function to call to get the default network interface IP that uses the default gateway func DiscoverInterface() (ip net.IP, err error) { return discoverGatewayInterfaceOSSpecific() } gateway-1.0.16/README.md0000664000175000017510000000431114731376046014062 0ustar nileshnilesh# gateway A simple library for discovering the IP address of the default gateway. Example: ```go package main import ( "fmt" "github.com/jackpal/gateway" ) func main() { gateway, err := gateway.DiscoverGateway() if err != nil { fmt.Println(err) } else { fmt.Println("Gateway:", gateway.String()) } } ``` Provides implementations for: + Darwin (macOS) + Dragonfly + FreeBSD + Linux + NetBSD + OpenBSD + Solaris and illumos + Windows Other platforms use an implementation that always returns an error. Pull requests for other OSs happily considered! ## Versions ### v1.0.16 Update x/net dependency. This was done to squelch a github security alert caused by depending upon an old version of x/net. ### v1.0.15 Update dependencies to latest versions. This was done to squelch a github security alert caused by depending upon an old version of x/net. This is the first time I've updated module versions, the tests pass, so hopefully everything's good. ### v1.0.14 + [Fix panic when interface not set in Solaris `netstat -rn` output.](https://github.com/jackpal/gateway/pull/42) ### v1.0.13 + Add tools/check-cross-compile.sh to check that the code compiles for various OSs. + Fix compilation errors exposed by tools/check-cross-compile.sh. ### v1.0.12 + If there are multiple default gateways, Windows now returns the gateway with the lowest metric. + Fix solaris build break. (In theory, IDK how to test this easily.) + Upgrade to golang 1.21 + Upgrade golang.org/x/net version, makes dependabot happy. Probably was not any actual security issue because gateway doesn't use any of the APIs of golang.org/x/net that had security issues. ### v1.0.11 + Implement DiscoverInterface for BSD-like OSes. ### v1.0.10 + Fix non-BSD-based builds. ### v1.0.9 + Add go.mod and go.sum files. + Use "golang.org/x/net/route" to implement all BSD variants. + As a side effect this adds support for Dragonfly and NetBSD. + Add example to README. + Remove broken continuous integration. ### v1.0.8 + Add support for OpenBSD + Linux parser now supports gateways with an IP address of 0.0.0.0 + Fall back to `netstat` on darwin systems if `route` fails. + Simplify Linux /proc/net/route parsers. gateway-1.0.16/LICENSE0000664000175000017510000000302414731376046013610 0ustar nileshnilesh// Copyright (c) 2010 Jack Palevich. All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. gateway-1.0.16/.mockery.yaml0000664000175000017510000000040614731376046015217 0ustar nileshnilesh# https://github.com/vektra/mockery with-expecter: true packages: github.com/jackpal/gateway: interfaces: interfaceGetter: config: mockName: "{{.Mock}}{{.InterfaceName}}" inpackage: true dir: "{{.InterfaceDir}}" gateway-1.0.16/.gitignore0000664000175000017510000000001614731376046014571 0ustar nileshnilesh.vscode .idea