-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* fix: add execution permissions to run-dockr test * feat: add find command * feat: use goroutines to process hosts * chore: bump version to 1.3.0-rc3 * feat: blacklist WSL interface * docs: cover new command * docs: describe even more the find command * docs: add examples
- Loading branch information
Showing
7 changed files
with
316 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
/* | ||
Copyright © 2021 NAME HERE <EMAIL ADDRESS> | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
package cmd | ||
|
||
import ( | ||
"fmt" | ||
"net" | ||
"sync" | ||
"time" | ||
|
||
"github.com/spf13/cobra" | ||
"github.com/sralloza/rpi-provisioner/ssh" | ||
) | ||
|
||
type FindArgs struct { | ||
subnet string | ||
user string | ||
password string | ||
live bool | ||
time bool | ||
port int | ||
timeout int | ||
} | ||
|
||
func NewFindCommand() *cobra.Command { | ||
args := FindArgs{} | ||
var findCmd = &cobra.Command{ | ||
Use: "find", | ||
Short: "Find your raspberry pi in your local network", | ||
Long: `Find your raspberry pi in your local network using SSH.`, | ||
RunE: func(cmd *cobra.Command, posArgs []string) error { | ||
if err := findHost(args); err != nil { | ||
return err | ||
} | ||
return nil | ||
}, | ||
} | ||
findCmd.Flags().StringVar(&args.subnet, "subnet", "", "Subnet to find the raspberry") | ||
findCmd.Flags().StringVar(&args.user, "user", "pi", "User to login via ssh") | ||
findCmd.Flags().StringVar(&args.password, "password", "raspberry", "Password to login via ssh") | ||
findCmd.Flags().IntVar(&args.port, "port", 22, "Port to connect via ssh") | ||
findCmd.Flags().BoolVar(&args.live, "live", false, "Print valid hosts right after found") | ||
findCmd.Flags().BoolVar(&args.time, "time", false, "Show hosts processing time") | ||
findCmd.Flags().IntVar(&args.timeout, "timeout", 1, "Timeout in ns to wait in ssh connections") | ||
return findCmd | ||
} | ||
|
||
func findHost(args FindArgs) error { | ||
CIDR := args.subnet | ||
if CIDR == "" { | ||
defaultCDIR, err := getDefaultCDIR() | ||
if err != nil { | ||
return err | ||
} | ||
CIDR = defaultCDIR | ||
} | ||
|
||
fmt.Printf("Getting IP addresses from CIDR %v...\n", CIDR) | ||
ipv4List, err := getIpsFromCIDR(CIDR) | ||
if err != nil { | ||
return err | ||
} | ||
fmt.Printf("Found %d IP addresses\n", len(ipv4List)) | ||
|
||
fmt.Println("Validating IP addresses...") | ||
start := time.Now() | ||
finder := Finder{totalIPs: ipv4List, findArgs: args} | ||
validIPs := finder.findValidSSHHosts() | ||
if args.time { | ||
elapsed := time.Since(start) | ||
fmt.Printf("Done (%s)\n", elapsed) | ||
} else { | ||
fmt.Println("Done") | ||
} | ||
|
||
fmt.Printf("Valid ips: %v\n", validIPs) | ||
return nil | ||
} | ||
|
||
type Finder struct { | ||
mu sync.Mutex | ||
wg sync.WaitGroup | ||
totalIPs []net.IP | ||
validIPs []net.IP | ||
findArgs FindArgs | ||
} | ||
|
||
func (f *Finder) findValidSSHHosts() []net.IP { | ||
for _, ip := range f.totalIPs { | ||
f.wg.Add(1) | ||
go f.checkSSHConnection(ip) | ||
} | ||
f.wg.Wait() | ||
return f.validIPs | ||
} | ||
|
||
func (f *Finder) checkSSHConnection(ipv4Addr net.IP) { | ||
defer f.wg.Done() | ||
connection := ssh.SSHConnection{ | ||
Password: f.findArgs.password, | ||
UseSSHKey: false, | ||
Debug: false, | ||
Timeout: 1, | ||
} | ||
addr := fmt.Sprintf("%v:%d", ipv4Addr, f.findArgs.port) | ||
err := connection.Connect(f.findArgs.user, addr) | ||
if err == nil { | ||
f.mu.Lock() | ||
f.validIPs = append(f.validIPs, ipv4Addr) | ||
if f.findArgs.live { | ||
fmt.Printf("Found valid host: %v\n", ipv4Addr) | ||
} | ||
f.mu.Unlock() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
package cmd | ||
|
||
import ( | ||
"encoding/binary" | ||
"errors" | ||
"fmt" | ||
"net" | ||
) | ||
|
||
var BlacklistedInterfaces = []string{"vEthernet (WSL)"} | ||
|
||
func getIpsFromCIDR(CIDR string) ([]net.IP, error) { | ||
_, ipv4Net, err := net.ParseCIDR(CIDR) | ||
|
||
if err != nil { | ||
return []net.IP{}, fmt.Errorf("error paring CIDR: %w", err) | ||
} | ||
|
||
// convert IPNet struct mask and address to uint32 | ||
// network is BigEndian | ||
mask := binary.BigEndian.Uint32(ipv4Net.Mask) | ||
start := binary.BigEndian.Uint32(ipv4Net.IP) | ||
|
||
// find the final address | ||
finish := (start & mask) | (mask ^ 0xffffffff) | ||
ips := []net.IP{} | ||
|
||
// loop through addresses as uint32 | ||
for i := start; i <= finish; i++ { | ||
// convert back to net.IP | ||
ip := make(net.IP, 4) | ||
binary.BigEndian.PutUint32(ip, i) | ||
ips = append(ips, ip) | ||
} | ||
|
||
return ips, nil | ||
} | ||
|
||
func getDefaultCDIR() (string, error) { | ||
localIP, err := LocalIP() | ||
if err != nil { | ||
return "", fmt.Errorf("error getting local IP: %w", err) | ||
} | ||
return fmt.Sprintf("%v/24", localIP), nil | ||
} | ||
|
||
func isInterfaceBlacklisted(iName string) bool { | ||
for _, blacklistedName := range BlacklistedInterfaces { | ||
if blacklistedName == iName { | ||
return true | ||
} | ||
} | ||
return false | ||
} | ||
|
||
// LocalIP get the host machine local IP address | ||
func LocalIP() (net.IP, error) { | ||
ifaces, err := net.Interfaces() | ||
if err != nil { | ||
return nil, fmt.Errorf("error getting interfaces: %w", err) | ||
} | ||
|
||
for _, i := range ifaces { | ||
if isInterfaceBlacklisted(i.Name) { | ||
continue | ||
} | ||
addrs, err := i.Addrs() | ||
if err != nil { | ||
return nil, fmt.Errorf("error getting interface addresses: %w", err) | ||
} | ||
|
||
for _, addr := range addrs { | ||
var ip net.IP | ||
switch v := addr.(type) { | ||
case *net.IPNet: | ||
ip = v.IP | ||
case *net.IPAddr: | ||
ip = v.IP | ||
} | ||
|
||
if isPrivateIP(ip) { | ||
return ip, nil | ||
} | ||
} | ||
} | ||
|
||
return nil, errors.New("error getting local IP") | ||
} | ||
|
||
func isPrivateIP(ip net.IP) bool { | ||
var privateIPBlocks []*net.IPNet | ||
for _, cidr := range []string{ | ||
// don't check loopback ips | ||
//"127.0.0.0/8", // IPv4 loopback | ||
//"::1/128", // IPv6 loopback | ||
//"fe80::/10", // IPv6 link-local | ||
"10.0.0.0/8", // RFC1918 | ||
"172.16.0.0/12", // RFC1918 | ||
"192.168.0.0/16", // RFC1918 | ||
} { | ||
_, block, _ := net.ParseCIDR(cidr) | ||
privateIPBlocks = append(privateIPBlocks, block) | ||
} | ||
|
||
for _, block := range privateIPBlocks { | ||
if block.Contains(ip) { | ||
return true | ||
} | ||
} | ||
|
||
return false | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.