package main
import (
"bytes"
"context"
"encoding/base64"
"encoding/csv"
"fmt"
"gopher-scan/ifconfig"
"gopher-scan/scream"
"image/png"
"net"
"os"
"os/exec"
"regexp"
"runtime"
"sort"
"strings"
"sync"
"time"
"github.com/lxn/walk"
"github.com/lxn/walk/declarative"
"github.com/lxn/win"
"golang.org/x/sys/windows"
)
const regexRange string = "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\\/([0-9]|[1-2][0-9]|3[0-2]))$"
// HostStruct data type
type HostStruct struct {
Mac string
Cip string
Opt string
Ven string
Let string
Inf string
checked bool
}
var exdata [][]string
var mdata *VModel
var imdone = make(chan int8, 32)
var serachIndexCache serachIndexCacheType
// VModel struct to show data in gui windows
type VModel struct {
walk.TableModelBase
walk.SorterBase
sortColumn int
sortOrder walk.SortOrder
items []*HostStruct
}
type serachIndexCacheType struct {
search string
indexs []int
showit int64
}
// SerIPscan ... struct for ipscanner settings
type SerIPscan struct {
GreenThreads, Ptime int
Pscan1, Pscan2, Pscan3, Pscan4, Pscan5 scream.PortType
SysIPrange []string
NetBs, Pong, PscanTOF bool
}
var cachedSystemIconsForWidthAndDllIdx = make(map[widthAndDllIdx]*walk.Icon)
type widthAndDllIdx struct {
width int
idx int32
dll string
}
var globalmaingui struct {
pushBTS, pushDadd, pushSet, pushPause *walk.PushButton
mainwindowsUI *walk.MainWindow
statShowBox *walk.LineEdit
lineEdite, srchBox *walk.LineEdit
ipTB *walk.TableView
saveCSV, saveTXT, mapperAC *walk.Action
progsBar *walk.ProgressBar
apipAdd, stSp, pScan bool
}
func startMainGUIWindows() {
const (
mwsizew = 865
mwsizeh = 500
)
walk.AppendToWalkInit(func() {
walk.InteractionEffect, _ = walk.NewDropShadowEffect(walk.RGB(63, 63, 63))
walk.ValidationErrorEffect, _ = walk.NewBorderGlowEffect(walk.RGB(255, 0, 0))
})
// default setting
settings := &SerIPscan{GreenThreads: 32,
Pscan1: scream.PortType{Nm: 80, Tp: "TCP"},
Pscan2: scream.PortType{Nm: 443, Tp: "TCP"},
Pscan3: scream.PortType{Nm: 22, Tp: "TCP"},
Pscan4: scream.PortType{Nm: 3389, Tp: "TCP"},
Pscan5: scream.PortType{Nm: 445, Tp: "TCP"},
SysIPrange: ifconfig.Getsysrange(false),
PscanTOF: true,
Ptime: 1,
NetBs: true,
Pong: true,
}
declarative.MainWindow{
AssignTo: &globalmaingui.mainwindowsUI,
Visible: false,
Title: "Gopher IP Scan",
Layout: declarative.VBox{},
MenuItems: []declarative.MenuItem{
declarative.Menu{
Text: "&File",
Items: []declarative.MenuItem{
declarative.Action{
AssignTo: &globalmaingui.saveCSV,
Text: "Save in CSV",
Image: loadSystemIcon("shell32", 69, 16),
OnTriggered: func() {
if len(exdata) == 0 {
walk.MsgBox(globalmaingui.mainwindowsUI, "Empty ip scan table", "please start scan to fill the table ...\nthen try to save data in a file", walk.MsgBoxIconInformation)
return
}
fdlg := new(walk.FileDialog)
fdlg.Title = "Save To CSV File"
fdlg.Filter = "Comma-separated values file (*.csv)"
if ok, _ := fdlg.ShowSave(globalmaingui.mainwindowsUI); !ok {
return
}
if !strings.HasSuffix(fdlg.FilePath, ".csv") {
fdlg.FilePath += ".csv"
}
saveInCSV(createosfile(fdlg.FilePath))
},
},
declarative.Action{
AssignTo: &globalmaingui.saveTXT,
Text: "Save in TXT",
Image: loadSystemIcon("shell32", 258, 16),
OnTriggered: func() {
if len(exdata) == 0 {
walk.MsgBox(globalmaingui.mainwindowsUI, "Empty ip scan table", "please start scan to fill the table ...\nthen try to save data in a file", walk.MsgBoxIconInformation)
return
}
fdlg := new(walk.FileDialog)
fdlg.Title = "Save To TXT File"
fdlg.Filter = "Text file (*.txt)"
if ok, _ := fdlg.ShowSave(globalmaingui.mainwindowsUI); !ok {
return
}
if !strings.HasSuffix(fdlg.FilePath, ".txt") {
fdlg.FilePath += ".txt"
}
saveInTXT(createosfile(fdlg.FilePath))
},
},
declarative.Separator{},
declarative.Action{
Text: "Exit (Alt+F4)",
OnTriggered: func() { globalmaingui.mainwindowsUI.Close() },
Image: loadSystemIcon("netshell", 98, 16),
},
},
},
declarative.Menu{
Text: "&Tools",
Items: []declarative.MenuItem{
declarative.Action{
AssignTo: &globalmaingui.mapperAC,
Text: "Port Mapper",
OnTriggered: func() {
runMapperDlg(globalmaingui.mainwindowsUI, "")
},
Image: loadSystemIcon("shell32", 22, 16),
},
declarative.Action{
Text: "Remote SSH",
OnTriggered: func() {
startSSHsession(globalmaingui.mainwindowsUI, "")
},
Image: loadSystemIcon("shell32", 24, 16),
},
declarative.Action{
Text: "Wake On LAN",
OnTriggered: func() {
runWakeOnLanDg(globalmaingui.mainwindowsUI, "", "")
},
Image: loadSystemIcon("imageres", 96, 16),
},
},
},
declarative.Menu{
Text: "&Help",
Items: []declarative.MenuItem{
declarative.Action{
Text: "GitHub Page",
Image: loadSystemIcon("shell32", 242, 16),
OnTriggered: func() {
win.ShellExecute(globalmaingui.mainwindowsUI.Handle(), nil, windows.StringToUTF16Ptr("https://github.com/sina-ghaderi/gopher-scan"), nil, nil, win.SW_SHOWNORMAL)
},
},
declarative.Action{
Text: "Report a Bug",
Image: loadSystemIcon("shell32", 242, 16),
OnTriggered: func() {
win.ShellExecute(globalmaingui.mainwindowsUI.Handle(), nil, windows.StringToUTF16Ptr("https://github.com/Sina-Ghaderi/gopher-scan/issues/new"), nil, nil, win.SW_SHOWNORMAL)
},
},
declarative.Action{
Text: "About GIPS...",
Image: loadSystemIcon("shell32", 277, 16),
OnTriggered: func() {
runAboutDialog(globalmaingui.mainwindowsUI)
},
},
},
},
},
Children: []declarative.Widget{
declarative.GroupBox{
Title: "IP Scanner Actions",
Layout: declarative.Grid{Columns: 4},
Children: []declarative.Widget{
declarative.PushButton{
AssignTo: &globalmaingui.pushBTS,
MaxSize: declarative.Size{Width: 100},
Text: " Start Scan",
Image: loadSystemIcon("shell32", 137, 22),
ToolTipText: "Start/Stop Scan",
OnClicked: func() {
if !globalmaingui.stSp {
for _, i := range strings.Split(globalmaingui.lineEdite.Text(), ",") {
if len(globalmaingui.lineEdite.Text()) == 0 {
globalmaingui.lineEdite.SetFocus()
return
}
if match, _ := regexp.MatchString(regexRange, i); !match {
walk.MsgBox(globalmaingui.mainwindowsUI, "IP syntax error", "Invalid IPv4 address, format: IPv4/cidr,IPv4/cidr...\nExample: 192.168.1.0/24,172.16.0.0/16", walk.MsgBoxIconError)
return
}
}
settings.SysIPrange = ifconfig.RemoveDuplicates(strings.Split(globalmaingui.lineEdite.Text(), ","))
globalmaingui.stSp = true
mdata = new(VModel)
globalmaingui.ipTB.SetModel(mdata)
go scanstat(settings.SysIPrange)
go settings.winscream()
globalmaingui.pushBTS.SetText(" Stop Scan")
globalmaingui.pushBTS.SetImage(loadSystemIcon("comres", 10, 22))
globalmaingui.progsBar.SetVisible(true)
globalmaingui.statShowBox.SetVisible(true)
globalmaingui.pushDadd.SetEnabled(false)
globalmaingui.pushSet.SetEnabled(false)
globalmaingui.pushPause.SetEnabled(true)
globalmaingui.saveCSV.SetEnabled(false)
globalmaingui.saveTXT.SetEnabled(false)
globalmaingui.mapperAC.SetEnabled(false)
globalmaingui.lineEdite.SetReadOnly(true)
globalmaingui.srchBox.SetReadOnly(true)
globalmaingui.srchBox.SetText("Search in Result...")
serachIndexCache = serachIndexCacheType{}
} else {
globalmaingui.pushBTS.SetEnabled(false)
globalmaingui.pushPause.SetEnabled(false)
scream.StopChan <- struct{}{}
}
},
},
declarative.PushButton{
AssignTo: &globalmaingui.pushPause,
Enabled: false,
Image: loadSystemIcon("comres", 5, 22),
MaxSize: declarative.Size{Width: 100},
Text: " Pause Scan",
ToolTipText: "Pause runing scan",
OnClicked: func() {
if !globalmaingui.pScan {
globalmaingui.pushPause.SetEnabled(false)
scream.PauseChan <- struct{}{}
time.Sleep(time.Second) // too much click
globalmaingui.pushPause.SetText(" Continue")
globalmaingui.pScan = true
globalmaingui.pushPause.SetEnabled(true)
} else {
globalmaingui.pushPause.SetEnabled(false)
scream.ContChan <- struct{}{}
time.Sleep(time.Second) // ...
globalmaingui.pushPause.SetText(" Puase Scan")
globalmaingui.pScan = false
globalmaingui.pushPause.SetEnabled(true)
}
},
},
declarative.PushButton{
AssignTo: &globalmaingui.pushSet,
MaxSize: declarative.Size{Width: 100},
Image: loadSystemIcon("dsuiext", 35, 22),
Text: " Edit Settings",
ToolTipText: "Show IP scan settings",
OnClicked: func() {
runSettingsDG(globalmaingui.mainwindowsUI, settings)
},
},
declarative.PushButton{
AssignTo: &globalmaingui.pushDadd,
MaxSize: declarative.Size{Width: 100},
Image: loadSystemIcon("shell32", 164, 22),
Text: " IP Range",
ToolTipText: "Also scan Apipa and ... default addresses",
OnClicked: func() {
if !globalmaingui.apipAdd {
settings.SysIPrange = ifconfig.Getsysrange(true)
globalmaingui.lineEdite.SetText(fancyiprange(settings.SysIPrange))
globalmaingui.apipAdd = true
globalmaingui.pushDadd.SetText(" Del IP Range")
return
}
settings.SysIPrange = ifconfig.Getsysrange(false)
globalmaingui.lineEdite.SetText(fancyiprange(settings.SysIPrange))
globalmaingui.apipAdd = false
globalmaingui.pushDadd.SetText(" IP Range")
},
},
},
},
declarative.GroupBox{
Title: "IPv4 Range To Scan",
Layout: declarative.Grid{Columns: 2},
Children: []declarative.Widget{
declarative.LineEdit{
AssignTo: &globalmaingui.lineEdite,
Text: fancyiprange(settings.SysIPrange),
ToolTipText: "format: IPv4/cidr,IPv4/cidr,IPv4/cidr...",
CueBanner: "IPv4/cidr Network To Scan ... Example: 172.16.0.0/16,192.168.1.0/24,10.0.0.0/8",
},
declarative.LineEdit{
AssignTo: &globalmaingui.srchBox,
CueBanner: "Search in Result...",
ToolTipText: "press enter to find next",
MaxSize: declarative.Size{Width: 180},
OnKeyPress: func(key walk.Key) {
if key == walk.KeyReturn {
if len(globalmaingui.srchBox.Text()) == 0 {
return
}
rows := searchGrep(globalmaingui.srchBox.Text())
if len(rows) == 0 {
return
}
if int(serachIndexCache.showit) == len(serachIndexCache.indexs) {
serachIndexCache.showit = 0
}
globalmaingui.ipTB.SetCurrentIndex(serachIndexCache.indexs[serachIndexCache.showit])
serachIndexCache.showit++
}
},
},
},
},
declarative.GroupBox{
Title: "Scan Result Table",
Layout: declarative.Grid{Columns: 1},
Children: []declarative.Widget{
declarative.TableView{
AssignTo: &globalmaingui.ipTB,
AlternatingRowBG: false,
ColumnsOrderable: true,
CustomHeaderHeight: 21,
CustomRowHeight: 19,
Columns: []declarative.TableViewColumn{
{Title: "IP Address", Name: "Cip", Width: 110},
{Title: "Mac Address", Name: "Mac", Width: 110},
{Title: "Latency", Name: "Len", Width: 75},
{Title: "Manufacture", Name: "Ven", Width: 175},
{Title: "Open Ports", Name: "Opt", Width: 175, Format: "%v"},
{Title: "Additional Info", Name: "Inf", Width: 163, Format: "%v"},
},
},
declarative.ProgressBar{
AssignTo: &globalmaingui.progsBar,
MinValue: 0,
MaxValue: 100,
ToolTipText: "Progress Bar",
MaxSize: declarative.Size{Height: 19},
Visible: false,
},
declarative.LineEdit{
AssignTo: &globalmaingui.statShowBox,
Visible: false,
ReadOnly: true,
},
},
},
},
}.Create()
defaultStyle := win.GetWindowLong(globalmaingui.mainwindowsUI.Handle(), win.GWL_STYLE)
newStyle := defaultStyle &^ win.WS_THICKFRAME
win.SetWindowLong(globalmaingui.mainwindowsUI.Handle(), win.GWL_STYLE, newStyle)
xScreen := win.GetSystemMetrics(win.SM_CXSCREEN)
yScreen := win.GetSystemMetrics(win.SM_CYSCREEN)
win.SetWindowPos(
globalmaingui.mainwindowsUI.Handle(),
0,
(xScreen-mwsizew)/2,
(yScreen-mwsizeh)/2,
mwsizew,
mwsizeh,
win.SWP_FRAMECHANGED,
)
win.ShowWindow(globalmaingui.mainwindowsUI.Handle(), win.SW_SHOW)
contextMenu, _ := walk.NewMenu()
globalmaingui.ipTB.AddDisposable(contextMenu)
pingAction := walk.NewAction()
pingAction.SetText("Ping Address")
pingAction.SetImage(loadSystemIcon("shell32", 167, 16))
pingAction.Triggered().Attach(func() {
if globalmaingui.ipTB.CurrentIndex() < 0 {
walk.MsgBox(globalmaingui.mainwindowsUI, "Scan Is Runing", "ip scan is runing right now, please try this when scan is finished", walk.MsgBoxIconInformation)
return
}
if exeErr := exec.Command("cmd", "/c", "start", "ping", mdata.items[globalmaingui.ipTB.CurrentIndex()].Cip, "-t").Start(); exeErr != nil {
walk.MsgBox(globalmaingui.mainwindowsUI, "Internal System Err", fmt.Sprintf("%v", exeErr), walk.MsgBoxIconError)
return
}
})
contextMenu.Actions().Add(pingAction)
mstscAction := walk.NewAction()
mstscAction.SetText("Remote Desktop")
mstscAction.SetImage(loadSystemIcon("mstscax", 0, 16))
mstscAction.Triggered().Attach(func() {
if globalmaingui.ipTB.CurrentIndex() < 0 {
walk.MsgBox(globalmaingui.mainwindowsUI, "Scan Is Runing", "ip scan is runing right now, please try this when scan is finished", walk.MsgBoxIconInformation)
return
}
if exeErr := exec.Command("mstsc", "/v", mdata.items[globalmaingui.ipTB.CurrentIndex()].Cip).Start(); exeErr != nil {
walk.MsgBox(globalmaingui.mainwindowsUI, "Internal System Err", fmt.Sprintf("%v", exeErr), walk.MsgBoxIconError)
return
}
})
contextMenu.Actions().Add(mstscAction)
browseAction := walk.NewAction()
browseAction.SetText("Open in Browser")
browseAction.SetImage(loadSystemIcon("shell32", 242, 16))
browseAction.Triggered().Attach(func() {
if globalmaingui.ipTB.CurrentIndex() < 0 {
walk.MsgBox(globalmaingui.mainwindowsUI, "Scan Is Runing", "ip scan is runing right now, please try this when scan is finished", walk.MsgBoxIconInformation)
return
}
win.ShellExecute(globalmaingui.mainwindowsUI.Handle(), nil, windows.StringToUTF16Ptr("http://"+mdata.items[globalmaingui.ipTB.CurrentIndex()].Cip), nil, nil, win.SW_SHOWNORMAL)
})
contextMenu.Actions().Add(browseAction)
//
traceAction := walk.NewAction()
traceAction.SetText("Trace Address")
traceAction.SetImage(loadSystemIcon("shell32", 18, 16))
traceAction.Triggered().Attach(func() {
if globalmaingui.ipTB.CurrentIndex() < 0 {
walk.MsgBox(globalmaingui.mainwindowsUI, "Scan Is Runing", "ip scan is runing right now, please try this when scan is finished", walk.MsgBoxIconInformation)
return
}
if exeErr := exec.Command("cmd", "/c", "start", "tracert", mdata.items[globalmaingui.ipTB.CurrentIndex()].Cip).Start(); exeErr != nil {
walk.MsgBox(globalmaingui.mainwindowsUI, "Internal System Err", fmt.Sprintf("%v", exeErr), walk.MsgBoxIconError)
return
}
})
contextMenu.Actions().Add(traceAction)
ftpAction := walk.NewAction()
ftpAction.SetText("FTP File Share")
ftpAction.SetImage(loadSystemIcon("shell32", 164, 16))
ftpAction.Triggered().Attach(func() {
if globalmaingui.ipTB.CurrentIndex() < 0 {
walk.MsgBox(globalmaingui.mainwindowsUI, "Scan Is Runing", "ip scan is runing right now, please try this when scan is finished", walk.MsgBoxIconInformation)
return
}
if exeErr := exec.Command("cmd", "/c", `%windir%\explorer`, "ftp://"+mdata.items[globalmaingui.ipTB.CurrentIndex()].Cip).Start(); exeErr != nil {
walk.MsgBox(globalmaingui.mainwindowsUI, "Internal System Err", fmt.Sprintf("%v", exeErr), walk.MsgBoxIconError)
return
}
})
contextMenu.Actions().Add(ftpAction)
smbAction := walk.NewAction()
smbAction.SetText("SMB File Share")
smbAction.SetImage(loadSystemIcon("imageres", 137, 16))
smbAction.Triggered().Attach(func() {
if globalmaingui.ipTB.CurrentIndex() < 0 {
walk.MsgBox(globalmaingui.mainwindowsUI, "Scan Is Runing", "ip scan is runing right now, please try this when scan is finished", walk.MsgBoxIconInformation)
return
}
if exeErr := exec.Command("cmd", "/c", `%windir%\explorer`, `\\`+mdata.items[globalmaingui.ipTB.CurrentIndex()].Cip+`\`).Start(); exeErr != nil {
walk.MsgBox(globalmaingui.mainwindowsUI, "Internal System Err", fmt.Sprintf("%v", exeErr), walk.MsgBoxIconError)
return
}
})
contextMenu.Actions().Add(smbAction)
sshdAction := walk.NewAction()
sshdAction.SetText("Remote SSH")
sshdAction.SetImage(loadSystemIcon("shell32", 24, 16))
sshdAction.Triggered().Attach(func() {
if globalmaingui.ipTB.CurrentIndex() < 0 {
walk.MsgBox(globalmaingui.mainwindowsUI, "Scan Is Runing", "ip scan is runing right now, please try this when scan is finished", walk.MsgBoxIconInformation)
return
}
startSSHsession(globalmaingui.mainwindowsUI, mdata.items[globalmaingui.ipTB.CurrentIndex()].Cip)
})
contextMenu.Actions().Add(sshdAction)
mapAction := walk.NewAction()
mapAction.SetText("Run Port Mapper")
mapAction.SetImage(loadSystemIcon("shell32", 22, 16))
mapAction.Triggered().Attach(func() {
if globalmaingui.ipTB.CurrentIndex() < 0 {
walk.MsgBox(globalmaingui.mainwindowsUI, "Scan Is Runing", "ip scan is runing right now, please try this when scan is finished", walk.MsgBoxIconInformation)
return
}
if !globalmaingui.mapperAC.Enabled() {
walk.MsgBox(globalmaingui.mainwindowsUI, "Scan Is Runing", "ip scan is runing right now, please try this when scan is finished", walk.MsgBoxIconInformation)
return
}
runMapperDlg(globalmaingui.mainwindowsUI, mdata.items[globalmaingui.ipTB.CurrentIndex()].Cip)
})
contextMenu.Actions().Add(mapAction)
wakeAction := walk.NewAction()
wakeAction.SetText("Wake On LAN")
wakeAction.SetImage(loadSystemIcon("imageres", 96, 16))
wakeAction.Triggered().Attach(func() {
if globalmaingui.ipTB.CurrentIndex() < 0 {
walk.MsgBox(globalmaingui.mainwindowsUI, "Scan Is Runing", "ip scan is runing right now, please try this when scan is finished", walk.MsgBoxIconInformation)
return
}
runWakeOnLanDg(globalmaingui.mainwindowsUI, mdata.items[globalmaingui.ipTB.CurrentIndex()].Cip, mdata.items[globalmaingui.ipTB.CurrentIndex()].Mac)
})
contextMenu.Actions().Add(wakeAction)
globalmaingui.ipTB.SetContextMenu(contextMenu)
globalmaingui.ipTB.SetGridlines(true)
globalmaingui.mainwindowsUI.Run()
}
func fancyiprange(str []string) (nets string) {
for _, j := range str {
nets = fmt.Sprint(nets + j + ",")
}
if len(nets) > 0 {
nets = nets[:len(nets)-1]
}
return nets
}
func (p *SerIPscan) winscream() {
slclockmres := sync.Mutex{}
dummg := sync.WaitGroup{}
semap := scream.NewWeighted(int64(p.GreenThreads))
defer func() {
// Pack it up boys... we're done here
dummg.Wait()
globalmaingui.pushBTS.SetText(" Start Scan")
globalmaingui.pushBTS.SetImage(loadSystemIcon("shell32", 137, 22))
globalmaingui.pushPause.SetText(" Pause Scan")
globalmaingui.pushBTS.SetEnabled(true)
globalmaingui.pushDadd.SetEnabled(true)
globalmaingui.pushSet.SetEnabled(true)
globalmaingui.pushPause.SetEnabled(false)
globalmaingui.lineEdite.SetReadOnly(false)
globalmaingui.progsBar.SetVisible(false)
globalmaingui.statShowBox.SetVisible(false)
globalmaingui.saveCSV.SetEnabled(true)
globalmaingui.saveTXT.SetEnabled(true)
globalmaingui.mapperAC.SetEnabled(true)
globalmaingui.srchBox.SetReadOnly(false)
globalmaingui.srchBox.SetText("")
globalmaingui.stSp, globalmaingui.pScan = false, false
imdone <- 1
}()
startDomino := func(ipn string) {
defer semap.Release(1)
defer dummg.Done()
ip := net.ParseIP(ipn).To4()
fmc, err := scream.SendARP(ip)
if err == nil {
m := &HostStruct{Cip: ipn, Mac: fmc.String()}
iden, isthere := macven[strings.ToUpper(strings.Replace(fmc.String(), ":", "", -1)[0:6])]
if !p.NetBs {
m.Ven = "[N/A]"
} else if isthere {
m.Ven = iden
} else {
m.Ven = "Unknow Manufacture"
}
if p.PscanTOF {
for _, i := range scream.StartPscan(ipn, time.Duration(1*time.Second), 3, p.Pscan1, p.Pscan2, p.Pscan3, p.Pscan4, p.Pscan5) {
if i.Stat == "open" {
m.Opt += fmt.Sprintf("%v %v ", i.Number, strings.ToUpper(i.Ptype))
if websig, err := scream.DetectWeb(ipn, i.Number); err == nil {
m.Inf += fmt.Sprintf("%v (http --> %v) ", i.Number, websig)
}
}
}
}
if len(m.Opt) == 0 {
m.Opt = "[N/A]"
}
if len(m.Inf) == 0 {
m.Inf = "[N/A]"
}
if p.Pong {
_, reptime, err := scream.PingHost(ipn, p.Ptime)
if err != nil {
m.Let = "TimeOut"
} else {
m.Let = reptime.String()
}
} else {
m.Let = "[N/A]"
}
slclockmres.Lock()
mdata.items = append(mdata.items, m)
exdata = append(exdata, []string{m.Cip, m.Mac, m.Let, m.Ven, m.Opt, m.Inf})
mdata.PublishRowsReset()
globalmaingui.ipTB.EnsureItemVisible(len(mdata.items) - 1)
slclockmres.Unlock()
}
imdone <- 0
}
for _, iprange := range p.SysIPrange {
hosts, _ := scream.GetHosts(iprange)
for _, i := range hosts {
if signal, _ := semap.AcquireSnix(context.TODO(), 1); signal != 0 {
// oops!
return
}
dummg.Add(1)
go startDomino(i)
}
dummg.Wait()
}
}
func scanstat(allranges []string) {
var tasks, jobdn int
for _, iprange := range allranges {
hosts, _ := scream.GetHosts(iprange)
tasks += len(hosts)
}
for {
if cc, _ := <-imdone; cc == 0 {
jobdn++
prcstatus := 100 - (float64(tasks-jobdn)/float64(tasks))*float64(100)
globalmaingui.progsBar.SetValue(int(prcstatus))
globalmaingui.statShowBox.SetText(fmt.Sprintf("Progress: %.2f%%\t\tTotal: %v\t\tChecked: %v\t\tAlive: %v", prcstatus, tasks, jobdn, len(mdata.items)))
} else {
globalmaingui.progsBar.SetValue(0)
globalmaingui.statShowBox.SetText("Progress: 0\t\tTotal: 0\t\tChecked: 0\t\tAlive: 0")
return
}
}
}
// Items method returns Hosts data
func (m *VModel) Items() interface{} {
return m.items
}
// RowCount func for print out new stuff
func (m *VModel) RowCount() int {
return len(m.items)
}
// Checked func used for select row in tableview
func (m *VModel) Checked(row int) bool {
return m.items[row].checked
}
// Value func used for table indexing
func (m *VModel) Value(row, col int) interface{} {
item := m.items[row]
switch col {
case 1:
return item.Mac
case 0:
return item.Cip
case 4:
return item.Opt
case 3:
return item.Ven
case 2:
return item.Let
case 5:
return item.Inf
}
panic("Internal error: tableView Value func (unexpected column)")
}
// Sort is used for sorting data in table
func (m *VModel) Sort(col int, order walk.SortOrder) error {
m.sortColumn, m.sortOrder = col, order
sort.SliceStable(m.items, func(i, j int) bool {
a, b := m.items[i], m.items[j]
c := func(ls bool) bool {
if m.sortOrder == walk.SortAscending {
return ls
}
return !ls
}
switch m.sortColumn {
case 0:
return c(bytes.Compare(net.ParseIP(a.Cip), net.ParseIP(b.Cip)) < 0)
case 1:
maca, _ := net.ParseMAC(a.Mac)
macb, _ := net.ParseMAC(b.Mac)
return c(bytes.Compare(maca, macb) < 0)
case 2:
milet, _ := time.ParseDuration(a.Let)
mxlet, _ := time.ParseDuration(b.Let)
return c(milet < mxlet)
case 3:
return c(a.Ven < b.Ven)
case 4:
return c(a.Opt < b.Opt)
case 5:
return c(a.Inf < b.Inf)
}
panic("Internal error: Sort func in tableview")
})
return m.SorterBase.Sort(col, order)
}
func createosfile(filePath string) (*os.File, error) {
file, err := os.OpenFile(filePath, os.O_CREATE|os.O_WRONLY|os.O_EXCL, 0600)
if err != nil {
if os.IsExist(err) {
if walk.DlgCmdNo == walk.MsgBox(globalmaingui.mainwindowsUI, "Writing file failed", fmt.Sprintf("file ā%sā \nalready exists, do you want to overwrite it?", filePath), walk.MsgBoxYesNo|walk.MsgBoxDefButton2|walk.MsgBoxIconWarning) {
return nil, nil
}
}
}
file, err = os.Create(filePath)
if err != nil {
return nil, fmt.Errorf("%v", err)
}
return file, nil
}
func saveInCSV(file *os.File, ferr error) {
if file == nil && ferr == nil {
return
} else if ferr != nil {
walk.MsgBox(globalmaingui.mainwindowsUI, "OS file error", fmt.Sprint(ferr), walk.MsgBoxIconError)
return
} else if file == nil {
walk.MsgBox(globalmaingui.mainwindowsUI, "OS file error", "null file passed, can not access the file", walk.MsgBoxIconError)
return
}
w := csv.NewWriter(file)
for _, record := range exdata {
if err := w.Write(record); err != nil {
walk.MsgBox(globalmaingui.mainwindowsUI, "OS file error", fmt.Sprint(err), walk.MsgBoxIconError)
return
}
}
w.Flush()
if err := w.Error(); err != nil {
walk.MsgBox(globalmaingui.mainwindowsUI, "OS file error", fmt.Sprint(err), walk.MsgBoxIconError)
return
}
}
func saveInTXT(file *os.File, ferr error) {
if file == nil && ferr == nil {
return
} else if ferr != nil {
walk.MsgBox(globalmaingui.mainwindowsUI, "OS file error", fmt.Sprint(ferr), walk.MsgBoxIconError)
return
} else if file == nil {
walk.MsgBox(globalmaingui.mainwindowsUI, "OS file error", "null file passed, can not access the file", walk.MsgBoxIconError)
return
}
for _, record := range exdata {
for _, clumn := range record {
if _, err := fmt.Fprintf(file, "%v\t", clumn); err != nil {
walk.MsgBox(globalmaingui.mainwindowsUI, "OS file error", fmt.Sprint(err), walk.MsgBoxIconError)
return
}
}
if _, err := fmt.Fprint(file, "\n"); err != nil {
walk.MsgBox(globalmaingui.mainwindowsUI, "OS file error", fmt.Sprint(err), walk.MsgBoxIconError)
return
}
}
}
func runAboutDialog(form walk.Form) {
lgg := walk.NewVBoxLayout()
lgg.SetMargins(walk.Margins{HNear: 80, VNear: 20, HFar: 80, VFar: 20})
lgg.SetSpacing(10)
showingAboutDialog, err := walk.NewDialogWithFixedSize(form)
if err != nil {
return
}
defer func() {
showingAboutDialog = nil
}()
showingAboutDialog.SetTitle("About GIPS")
showingAboutDialog.SetLayout(lgg)
gipsLbl, err := walk.NewTextLabel(showingAboutDialog)
if err != nil {
return
}
blFont, _ := walk.NewFont("Segoe UI", 16, walk.FontBold)
gipsLbl.SetFont(blFont)
gipsLbl.SetTextAlignment(walk.AlignHCenterVNear)
gipsLbl.SetText("Gopher IP Scan")
addinfo, err := walk.NewTextLabel(showingAboutDialog)
if err != nil {
return
}
addinfo.SetTextAlignment(walk.AlignHCenterVNear)
addinfo.SetText(fmt.Sprintf("Gopher Version: 0.0.2-alpha\nGolang Version: %s\nOperating system: %s\nArchitecture: %s", strings.TrimPrefix(runtime.Version(), "go"), opRuningInfo(), runtime.GOARCH))
copyrightLbl, err := walk.NewTextLabel(showingAboutDialog)
if err != nil {
return
}
copyrightFont, _ := walk.NewFont("Segoe UI", 8, 0)
copyrightLbl.SetFont(copyrightFont)
copyrightLbl.SetTextAlignment(walk.AlignHCenterVNear)
copyrightLbl.SetText(fmt.Sprint("Copyright (c) 2020 slc.snix.ir, All rights reserved. \nDeveloped BY khokooli@gmail.com (github.com/sina-ghaderi)\nThis work is licensed under the terms of the MIT license."))
showingAboutDialog.Run()
}
func opRuningInfo() string {
win32sysInfo := windows.RtlGetVersion()
var winSysType string
switch win32sysInfo.ProductType {
case 3:
winSysType = " Server"
case 2:
winSysType = " Controller"
}
return fmt.Sprintf("Windows%s %d.%d.%d", winSysType, win32sysInfo.MajorVersion, win32sysInfo.MinorVersion, win32sysInfo.BuildNumber)
}
func loadSystemIcon(dll string, index int32, size int) (icon *walk.Icon) {
icon = cachedSystemIconsForWidthAndDllIdx[widthAndDllIdx{size, index, dll}]
if icon != nil {
return
}
icon, err := walk.NewIconFromSysDLLWithSize(dll, int(index), size)
if err == nil {
cachedSystemIconsForWidthAndDllIdx[widthAndDllIdx{size, index, dll}] = icon
} else {
// if icon can not be loaded
imgByte, _ := base64.StdEncoding.DecodeString("iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAvklEQVQ4T62TjQrCMAyEnf+i7/+ksg1lar6Qk1g2tsoKoaXNXe7atNmMj61tE00cv20eLJh/hhK0CehosQ9wJngFycNm1j4yAeBLUbksiALArdSIAPBtws7YNnY6yERwDulLOVDytOghkPTdUnTkoaKF4BTVywud40NFB4iLO8xlT5y7hVr/mcsVQICCfyy4Ai5P71/jxPthlWekKiquFeWpTiMN2XcNyZ0upOCqnyk7QA0/ki6lYdS631+o5A/m1C0o1nAPtQAAAABJRU5ErkJggg==")
imgEmrg, _ := png.Decode(bytes.NewReader(imgByte))
icon, _ := walk.NewIconFromImage(imgEmrg)
return icon
}
return
}
func searchGrep(pattern string) []int {
if pattern == serachIndexCache.search {
return serachIndexCache.indexs
}
serachIndexCache = serachIndexCacheType{}
serachIndexCache.search = pattern
for row := 0; row < globalmaingui.ipTB.TableModel().RowCount(); row++ {
found:
for clm := 0; clm <= 5; clm++ {
line := fmt.Sprint(globalmaingui.ipTB.TableModel().Value(row, clm))
if bytes.Contains([]byte(line), []byte(pattern)) {
serachIndexCache.indexs = append(serachIndexCache.indexs, row)
continue found
}
}
}
return serachIndexCache.indexs
}