-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
431 additions
and
101 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
.DEFAULT_GOAL := help | ||
|
||
.PHONY: setup | ||
setup: ## Resolve dependencies using Go Modules | ||
go mod download | ||
|
||
.PHONY: clean | ||
clean: ## Remove build artifact directory | ||
-rm -rfv arping-gui* | ||
|
||
.PHONY: lint | ||
lint: ## Run static code analysis | ||
command -v golint >/dev/null 2>&1 || { go get -u golang.org/x/lint/golint; } | ||
golint -set_exit_status ./... | ||
|
||
.PHONY: run | ||
run: ## Run app locally | ||
go run . -d | ||
|
||
.PHONY: build-linux | ||
build-linux: ## Build linux package | ||
command -v fyne >/dev/null 2>&1 || { go get -u fyne.io/fyne/cmd/fyne; } | ||
fyne package -os linux -icon icon.png -release | ||
|
||
.PHONY: build-mac | ||
build-mac: ## Build mac package | ||
command -v fyne >/dev/null 2>&1 || { go get -u fyne.io/fyne/cmd/fyne; } | ||
fyne package -os darwin -icon icon.png -release | ||
zip -r arping-gui_macos.zip arping-gui.app | ||
|
||
.PHONY: build-win | ||
build-win: ## Build windows package | ||
command -v fyne >/dev/null 2>&1 || { go get -u fyne.io/fyne/cmd/fyne; } | ||
fyne package -os windows -icon icon.png -release | ||
|
||
.PHONY: help | ||
help: | ||
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' |
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,70 @@ | ||
package main | ||
|
||
import ( | ||
"encoding/binary" | ||
"errors" | ||
"fmt" | ||
"net" | ||
"strings" | ||
) | ||
|
||
type adapter struct { | ||
name string | ||
ip string | ||
broadcast string | ||
} | ||
|
||
func adapters() ([]adapter, error) { | ||
var adapters []adapter | ||
interfaces, err := net.Interfaces() | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to collect network interface: %w", err) | ||
} | ||
for _, ifEntry := range interfaces { | ||
if ifEntry.HardwareAddr == nil || !strings.Contains(ifEntry.Flags.String(), "up") { | ||
continue // ignore odd or down adapters | ||
} | ||
addresses, err := ifEntry.Addrs() | ||
if err != nil || len(addresses) == 0 { | ||
continue // ignore unassigned adapters | ||
} | ||
for _, address := range addresses { | ||
if !strings.Contains(address.String(), ".") { | ||
continue | ||
} | ||
ip, n, err := net.ParseCIDR(address.String()) | ||
if err != nil { | ||
continue | ||
} | ||
broadcast := broadcast(n) | ||
adapters = append(adapters, adapter{ifEntry.Name, ip.String(), broadcast}) | ||
} | ||
} | ||
if len(adapters) == 0 { | ||
return nil, errors.New("no adapters available") | ||
} | ||
return adapters, nil | ||
} | ||
|
||
func broadcast(n *net.IPNet) string { | ||
bc := make(net.IP, len(n.IP.To4())) | ||
binary.BigEndian.PutUint32(bc, binary.BigEndian.Uint32(n.IP.To4())|^binary.BigEndian.Uint32(net.IP(n.Mask).To4())) | ||
return bc.String() | ||
} | ||
|
||
func adapterNames(adapters []adapter) []string { | ||
s := make([]string, len(adapters)) | ||
for i, a := range adapters { | ||
s[i] = fmt.Sprintf("%s [%s]", a.name, a.ip) | ||
} | ||
return s | ||
} | ||
|
||
func findAdapter(adapters []adapter, name string) adapter { | ||
for _, a := range adapters { | ||
if strings.HasPrefix(name, a.name) { | ||
return a | ||
} | ||
} | ||
return adapter{} | ||
} |
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 |
---|---|---|
@@ -1,116 +1,31 @@ | ||
package main | ||
|
||
import ( | ||
"errors" | ||
"os/exec" | ||
"regexp" | ||
"runtime" | ||
"strings" | ||
|
||
"fyne.io/fyne" | ||
"fyne.io/fyne/app" | ||
"fyne.io/fyne/dialog" | ||
"fyne.io/fyne/widget" | ||
) | ||
|
||
var macPattern = regexp.MustCompile("([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})") | ||
|
||
type enterEntry struct { | ||
widget.Entry | ||
tapped func() | ||
} | ||
|
||
func (e *enterEntry) setOnEnter(tapped func()) { | ||
e.tapped = tapped | ||
} | ||
|
||
func newEnterEntry() *enterEntry { | ||
entry := &enterEntry{} | ||
entry.ExtendBaseWidget(entry) | ||
return entry | ||
} | ||
|
||
func (e *enterEntry) KeyDown(key *fyne.KeyEvent) { | ||
switch key.Name { | ||
case fyne.KeyReturn: | ||
e.tapped() | ||
default: | ||
e.Entry.KeyDown(key) | ||
} | ||
} | ||
var ( | ||
macPattern = regexp.MustCompile("([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})") | ||
ipPattern = regexp.MustCompile("(?:[0-9]{1,3}\\.){3}[0-9]{1,3}") | ||
) | ||
|
||
func main() { | ||
a := app.New() | ||
w := a.NewWindow("arping-gui") | ||
macEntry := widget.NewEntry() | ||
var macCopyButton *widget.Button | ||
macCopyButton = widget.NewButton("Copy to clipboard", func() { | ||
w.Clipboard().SetContent(macEntry.Text) | ||
macCopyButton.Disable() | ||
macCopyButton.SetText("Copied!") | ||
}) | ||
macResult := widget.NewVBox( | ||
widget.NewLabel("MAC address:"), | ||
macEntry, | ||
macCopyButton, | ||
) | ||
macResult.Hide() | ||
ipEntry := newEnterEntry() | ||
ipEntry.SetPlaceHolder("ex. 192.168.1.1") | ||
var resolveButton *widget.Button | ||
resolveButton = widget.NewButton("Resolve", func() { | ||
resolveButton.Disable() | ||
resolveButton.SetText("Resolving...") | ||
defer func() { | ||
resolveButton.Enable() | ||
resolveButton.SetText("Resolve") | ||
}() | ||
mac, err := resolve(ipEntry.Text) | ||
if err != nil { | ||
macEntry.SetText("ERROR: " + err.Error()) | ||
} else { | ||
macEntry.SetText(mac) | ||
} | ||
macCopyButton.SetText("Copy to clipboard") | ||
macCopyButton.Enable() | ||
macResult.Show() | ||
}) | ||
ipEntry.setOnEnter(resolveButton.OnTapped) | ||
resolveButton.Disable() | ||
ipEntry.OnChanged = func(s string) { | ||
if len(s) > 0 { | ||
resolveButton.Enable() | ||
} else { | ||
resolveButton.Disable() | ||
} | ||
} | ||
w.SetContent(widget.NewVBox( | ||
widget.NewLabel("Target IP address:"), | ||
ipEntry, | ||
resolveButton, | ||
macResult, | ||
)) | ||
w.ShowAndRun() | ||
} | ||
|
||
func resolve(ip string) (string, error) { | ||
var pingCmd, arpCmd *exec.Cmd | ||
if runtime.GOOS == "windows" { | ||
pingCmd = exec.Command("ping", "-n", "1", ip) | ||
arpCmd = exec.Command("arp", "-a", ip) | ||
} else { | ||
pingCmd = exec.Command("ping", "-c", "1", ip) | ||
arpCmd = exec.Command("arp", ip) | ||
} | ||
if err := pingCmd.Run(); err != nil { | ||
return "", err | ||
} | ||
mac, err := arpCmd.Output() | ||
w.SetMainMenu(newMainMenu(a, w)) | ||
adapters, err := adapters() | ||
if err != nil { | ||
return "", err | ||
} | ||
matches := macPattern.FindAll(mac, -1) | ||
if len(matches) == 0 { | ||
return "", errors.New("no data") | ||
dialog.NewError(err, w) | ||
} | ||
return strings.ToLower(strings.ReplaceAll(string(matches[0]), "-", ":")), nil | ||
w.SetContent( | ||
widget.NewTabContainer( | ||
widget.NewTabItem("MAC to IP", newIP2MACTab(w, adapters)), | ||
widget.NewTabItem("IP to MAC", newMAC2IPTab(w, adapters)), | ||
), | ||
) | ||
w.ShowAndRun() | ||
} |
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,75 @@ | ||
package main | ||
|
||
import ( | ||
"bufio" | ||
"bytes" | ||
"errors" | ||
"os/exec" | ||
"runtime" | ||
"strings" | ||
) | ||
|
||
func ip2mac(ip string, adapter adapter) (string, error) { | ||
var pingCmd, arpCmd *exec.Cmd | ||
switch runtime.GOOS { | ||
case "windows": | ||
pingCmd = exec.Command("ping", "-n", "1", ip) | ||
arpCmd = exec.Command("arp", "-a", ip, "-N", adapter.ip) | ||
case "darwin": | ||
pingCmd = exec.Command("ping", "-b", adapter.name, "-c", "1", ip) | ||
arpCmd = exec.Command("arp", "-i", adapter.name, ip) | ||
default: | ||
pingCmd = exec.Command("ping", "-I", adapter.name, "-c", "1", ip) | ||
arpCmd = exec.Command("arp", "-i", adapter.name, ip) | ||
} | ||
if err := pingCmd.Run(); err != nil { | ||
return "", err | ||
} | ||
mac, err := arpCmd.Output() | ||
if err != nil { | ||
return "", err | ||
} | ||
matches := macPattern.FindAll(mac, -1) | ||
if len(matches) == 0 { | ||
return "", errors.New("no data") | ||
} | ||
return strings.ReplaceAll(strings.ToLower(string(matches[0])), "-", ":"), nil | ||
} | ||
|
||
func mac2ip(mac string, adapter adapter) (string, error) { | ||
var pingCmd, arpCmd *exec.Cmd | ||
switch runtime.GOOS { | ||
case "windows": | ||
mac = strings.ReplaceAll(strings.ToLower(mac), ":", "-") | ||
pingCmd = exec.Command("ping", "-n", "1", adapter.broadcast) | ||
arpCmd = exec.Command("arp", "-a", "-N", adapter.ip) | ||
case "darwin": | ||
mac = strings.ReplaceAll(strings.ToLower(mac), "-", ":") | ||
pingCmd = exec.Command("ping", "-b", adapter.name, "-c", "1", adapter.broadcast) | ||
arpCmd = exec.Command("arp", "-a", "-i", adapter.name) | ||
default: | ||
mac = strings.ReplaceAll(strings.ToLower(mac), "-", ":") | ||
pingCmd = exec.Command("ping", "-I", adapter.name, "-c", "1", adapter.broadcast, "-b") | ||
arpCmd = exec.Command("arp", "-a", "-i", adapter.name) | ||
} | ||
if err := pingCmd.Run(); err != nil { | ||
return "", err | ||
} | ||
arpOut, err := arpCmd.Output() | ||
if err != nil { | ||
return "", err | ||
} | ||
scanner := bufio.NewScanner(bytes.NewReader(arpOut)) | ||
for scanner.Scan() { | ||
line := scanner.Text() | ||
if !strings.Contains(line, mac) { | ||
continue | ||
} | ||
matches := ipPattern.FindAllString(line, -1) | ||
if len(matches) == 0 { | ||
return "", errors.New("no data") | ||
} | ||
return matches[0], nil | ||
} | ||
return "", errors.New("no data") | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.