mirror of
https://github.com/net-byte/go-gateway.git
synced 2024-04-21 12:21:40 +00:00
init
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
.vscode
|
||||
.idea
|
||||
@@ -0,0 +1,5 @@
|
||||
language: go
|
||||
go:
|
||||
- 1.18
|
||||
script:
|
||||
- go test -v ./...
|
||||
@@ -0,0 +1,20 @@
|
||||
The MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
# go-gateway
|
||||
|
||||
A simple library for discovering the IP address of the default gateway.
|
||||
|
||||
|
||||
[](https://travis-ci.org/net-byte/go-gateway)
|
||||
|
||||
Provides implementations for:
|
||||
|
||||
+ Linux
|
||||
+ MacOS
|
||||
+ Windows
|
||||
|
||||
Other platforms use an implementation that always returns an error.
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package gateway
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
var (
|
||||
errNoGateway = errors.New("no gateway found")
|
||||
errCantParse = errors.New("can't parse string output")
|
||||
errNotImplemented = errors.New("not implemented for OS: " + runtime.GOOS)
|
||||
)
|
||||
|
||||
// DiscoverGatewayIPv4 is the OS independent function to get the default ipv4 gateway
|
||||
func DiscoverGatewayIPv4() (ip net.IP, err error) {
|
||||
return discoverGatewayOSSpecificIPv4()
|
||||
}
|
||||
|
||||
// DiscoverGatewayIPv6 is the OS independent function to get the default ipv6 gateway
|
||||
func DiscoverGatewayIPv6() (ip net.IP, err error) {
|
||||
return discoverGatewayOSSpecificIPv6()
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
//go:build darwin
|
||||
// +build darwin
|
||||
|
||||
package gateway
|
||||
|
||||
import (
|
||||
"net"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
func discoverGatewayOSSpecificIPv4() (ip net.IP, err error) {
|
||||
ipstr := execCmd("sh", "-c", "route -n get default | grep 'gateway' | awk 'NR==1{print $2}'")
|
||||
ipv4 := net.ParseIP(ipstr)
|
||||
if ipv4 == nil {
|
||||
return nil, errCantParse
|
||||
}
|
||||
return ipv4, nil
|
||||
}
|
||||
|
||||
func discoverGatewayOSSpecificIPv6() (ip net.IP, err error) {
|
||||
ipstr := execCmd("sh", "-c", "route -6 -n get default | grep 'gateway' | awk 'NR==1{print $2}'")
|
||||
ipv6 := net.ParseIP(ipstr)
|
||||
if ipv6 == nil {
|
||||
return nil, errCantParse
|
||||
}
|
||||
return ipv6, nil
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
//go:build linux
|
||||
// +build linux
|
||||
|
||||
package gateway
|
||||
|
||||
import (
|
||||
"net"
|
||||
)
|
||||
|
||||
func discoverGatewayOSSpecificIPv4() (ip net.IP, err error) {
|
||||
ipstr := execCmd("sh", "-c", "route -n | grep 'UG[ \t]' | awk 'NR==1{print $2}'")
|
||||
ipv4 := net.ParseIP(ipstr)
|
||||
if ipv4 == nil {
|
||||
return nil, errCantParse
|
||||
}
|
||||
return ipv4, nil
|
||||
}
|
||||
|
||||
func discoverGatewayOSSpecificIPv6() (ip net.IP, err error) {
|
||||
ipstr := execCmd("sh", "-c", "route -6 -n | grep 'UG[ \t]' | awk 'NR==1{print $2}'")
|
||||
ipv6 := net.ParseIP(ipstr)
|
||||
if ipv6 == nil {
|
||||
return nil, errCantParse
|
||||
}
|
||||
return ipv6, nil
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
package gateway
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type windowsRouteStructIPv4 struct {
|
||||
Destination string
|
||||
Netmask string
|
||||
Gateway string
|
||||
Interface string
|
||||
Metric string
|
||||
}
|
||||
|
||||
type windowsRouteStructIPv6 struct {
|
||||
If string
|
||||
Metric string
|
||||
Destination string
|
||||
Gateway string
|
||||
}
|
||||
|
||||
func parseToWindowsRouteStructIPv4(output []byte) (windowsRouteStructIPv4, 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)
|
||||
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 windowsRouteStructIPv4{}, errNoGateway
|
||||
}
|
||||
|
||||
fields := strings.Fields(lines[idx+2])
|
||||
if len(fields) < 5 {
|
||||
return windowsRouteStructIPv4{}, errCantParse
|
||||
}
|
||||
|
||||
return windowsRouteStructIPv4{
|
||||
Destination: fields[0],
|
||||
Netmask: fields[1],
|
||||
Gateway: fields[2],
|
||||
Interface: fields[3],
|
||||
Metric: fields[4],
|
||||
}, nil
|
||||
}
|
||||
if strings.HasPrefix(line, "=======") {
|
||||
sep++
|
||||
continue
|
||||
}
|
||||
}
|
||||
return windowsRouteStructIPv4{}, errNoGateway
|
||||
}
|
||||
|
||||
func parseToWindowsRouteStructIPv6(output []byte) (windowsRouteStructIPv6, error) {
|
||||
|
||||
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 windowsRouteStructIPv6{}, errNoGateway
|
||||
}
|
||||
|
||||
fields := strings.Fields(lines[idx+2])
|
||||
if len(fields) < 5 {
|
||||
return windowsRouteStructIPv6{}, errCantParse
|
||||
}
|
||||
|
||||
return windowsRouteStructIPv6{
|
||||
If: fields[0],
|
||||
Metric: fields[1],
|
||||
Destination: fields[2],
|
||||
Gateway: fields[3],
|
||||
}, nil
|
||||
}
|
||||
if strings.HasPrefix(line, "=======") {
|
||||
sep++
|
||||
continue
|
||||
}
|
||||
}
|
||||
return windowsRouteStructIPv6{}, errNoGateway
|
||||
}
|
||||
|
||||
func parseWindowsGatewayIPv4(output []byte) (net.IP, error) {
|
||||
parsedOutput, err := parseToWindowsRouteStructIPv4(output)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ip := net.ParseIP(parsedOutput.Gateway)
|
||||
if ip == nil {
|
||||
return nil, errCantParse
|
||||
}
|
||||
return ip, nil
|
||||
}
|
||||
|
||||
func parseWindowsGatewayIPv6(output []byte) (net.IP, error) {
|
||||
parsedOutput, err := parseToWindowsRouteStructIPv6(output)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ip := net.ParseIP(parsedOutput.Gateway)
|
||||
if ip == nil {
|
||||
return nil, errCantParse
|
||||
}
|
||||
return ip, nil
|
||||
}
|
||||
|
||||
func execCmd(c string, args ...string) string {
|
||||
cmd := exec.Command(c, args...)
|
||||
out, err := cmd.Output()
|
||||
if err != nil {
|
||||
log.Println("failed to exec cmd:", err)
|
||||
}
|
||||
if len(out) == 0 {
|
||||
return ""
|
||||
}
|
||||
s := string(out)
|
||||
return strings.ReplaceAll(s, "\n", "")
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
//go:build !darwin && !linux && !windows && !solaris && !freebsd
|
||||
// +build !darwin,!linux,!windows,!solaris,!freebsd
|
||||
|
||||
package gateway
|
||||
|
||||
import (
|
||||
"net"
|
||||
)
|
||||
|
||||
func discoverGatewayOSSpecificIPv4() (ip net.IP, err error) {
|
||||
return ip, errNotImplemented
|
||||
}
|
||||
|
||||
func discoverGatewayOSSpecificIPv6() (ip net.IP, err error) {
|
||||
return ip, errNotImplemented
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package gateway
|
||||
|
||||
import (
|
||||
"net"
|
||||
"os/exec"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func discoverGatewayOSSpecificIPv4() (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 parseWindowsGatewayIPv4(output)
|
||||
}
|
||||
|
||||
func discoverGatewayOSSpecificIPv6() (ip net.IP, err error) {
|
||||
routeCmd := exec.Command("route", "print","-6" "::/0")
|
||||
routeCmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
|
||||
output, err := routeCmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return parseWindowsGatewayIPv6(output)
|
||||
}
|
||||
Reference in New Issue
Block a user