aboutsummaryrefslogblamecommitdiff
path: root/mapper.go
blob: 2c3cdabd98319333c3c18d6e9785c72cefd4c358 (plain) (tree)



























































































































































































































































































































































                                                                                                                                                                                                                                                                                                                                                              
package main

import (
	"encoding/base64"
	"fmt"
	"gopher-scan/scream"
	"regexp"
	"time"

	"github.com/lxn/walk"
	"github.com/lxn/walk/declarative"
)

// MapperScan struct mapper setting
type MapperScan struct {
	StrPort                int
	MasgUDP                []byte
	EndPort, Gortin, TmOut int
	Connection             bool
	HostStr                string
}

func runMapperDlg(owner walk.Form, defaultip string) (int, error) {
	var guimapview struct {
		dlg                           *walk.Dialog
		startsPB, cancelPB            *walk.PushButton
		valueEdit, pEdi               *walk.NumberEdit
		dbinder                       *walk.DataBinder
		endEdit, strEdit              *walk.NumberEdit
		slv, slx                      *walk.Slider
		mesgToUDPService              *walk.Composite
		mapLineEd, mapUDPmsg, stsLine *walk.LineEdit
		rsltTextBox                   *walk.TextEdit
		progsMapperBar                *walk.ProgressBar
		resultGrpBox, optionGrpBox    *walk.GroupBox
		stopscan                      int8
	}
	const regexSingle = `^(([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])$|^(([a-zA-Z]{1})|([a-zA-Z]{1}[a-zA-Z]{1})|([a-zA-Z]{1}[0-9]{1})|([0-9]{1}[a-zA-Z]{1})|([a-zA-Z0-9][a-zA-Z0-9-_]{1,61}[a-zA-Z0-9]))\.([a-zA-Z]{2,6}|[a-zA-Z0-9-]{2,30}\.[a-zA-Z]{2,3})$`
	settmapin := &MapperScan{
		Gortin:     32,
		TmOut:      1000,
		Connection: false,
		StrPort:    20,
		EndPort:    80,
		HostStr:    defaultip,
	}

	return declarative.Dialog{
		AssignTo:      &guimapview.dlg,
		FixedSize:     true,
		Title:         "IP Scanner Port Mapper",
		DefaultButton: &guimapview.startsPB,
		CancelButton:  &guimapview.cancelPB,
		MinSize:       declarative.Size{Width: 560, Height: 350},
		Layout:        declarative.VBox{},
		OnSizeChanged: func() {

		},
		Children: []declarative.Widget{
			declarative.GroupBox{
				AssignTo: &guimapview.optionGrpBox,
				Title:    "Port Mapper Settings",
				Layout:   declarative.VBox{},
				DataBinder: declarative.DataBinder{
					AssignTo:       &guimapview.dbinder,
					Name:           "Settmapin",
					DataSource:     settmapin,
					ErrorPresenter: declarative.ToolTipErrorPresenter{},
				},
				Children: []declarative.Widget{
					declarative.Composite{
						Layout: declarative.HBox{},
						Children: []declarative.Widget{
							declarative.GroupBox{
								Title:  "Host Address To Scan",
								Layout: declarative.Grid{Columns: 1},
								Children: []declarative.Widget{
									declarative.LineEdit{
										AssignTo:    &guimapview.mapLineEd,
										ToolTipText: "format: IPv4|Domain",
										CueBanner:   "IPv4 Or Domain To Scan ...",
										Text:        settmapin.HostStr,
										OnEditingFinished: func() {
											settmapin.HostStr = guimapview.mapLineEd.Text()
										},
									},
								},
							},
							declarative.RadioButtonGroupBox{
								Title:      "Port Type To Scan",
								Layout:     declarative.HBox{},
								DataMember: "Connection",
								Buttons: []declarative.RadioButton{
									{MaxSize: declarative.Size{Width: 60}, Text: "TCP", Value: false, OnClicked: func() { guimapview.mesgToUDPService.SetVisible(false) }},
									{MaxSize: declarative.Size{Width: 60}, Text: "UDP", Value: true, OnClicked: func() { guimapview.mesgToUDPService.SetVisible(true) }},
								},
							},
							declarative.GroupBox{
								Title:  "Port Range To Scan",
								Layout: declarative.Grid{Columns: 4},
								Children: []declarative.Widget{
									declarative.NumberEdit{
										AssignTo: &guimapview.strEdit,
										MaxSize:  declarative.Size{Width: 45},
										MinSize:  declarative.Size{Width: 45},
										Value:    declarative.Bind("StrPort"),
										MinValue: 1,
										MaxValue: 65535,
										OnValueChanged: func() {
											settmapin.StrPort = int(guimapview.strEdit.Value())
											guimapview.endEdit.SetRange(guimapview.strEdit.Value(), 65535)
										},
									},
									declarative.Label{
										Text: "To:",
									},
									declarative.NumberEdit{
										AssignTo: &guimapview.endEdit,
										MaxSize:  declarative.Size{Width: 45},
										MinSize:  declarative.Size{Width: 45},
										Value:    declarative.Bind("EndPort"),
										MaxValue: 65535,
									},
								},
							},
						},
					},
					declarative.Composite{
						AssignTo: &guimapview.mesgToUDPService,
						Visible:  false,
						Layout:   declarative.HBox{},
						Children: []declarative.Widget{
							declarative.GroupBox{
								Title:  "Message To Send To UDP Services",
								Layout: declarative.Grid{Columns: 1},
								Children: []declarative.Widget{
									declarative.LineEdit{
										AssignTo:    &guimapview.mapUDPmsg,
										ToolTipText: "because UDP protocol is connection-less, mapper can't actually determine if port is open or not\nso we have to send something to UDP ports and wait for response, if nothing came back, either port is close or UDP service is not interested in our message.",
										CueBanner:   "Base64 txt message ...",
										Text:        settmapin.MasgUDP,
										OnEditingFinished: func() {
											settmapin.MasgUDP = []byte(guimapview.mapUDPmsg.Text())
										},
									},
								},
							},
						},
					},
					declarative.Composite{
						Layout: declarative.HBox{},
						Children: []declarative.Widget{
							declarative.GroupBox{
								Title:  "Scan Timeout",
								Layout: declarative.Grid{Columns: 3},
								Children: []declarative.Widget{
									declarative.Label{
										Text: "Timeoute:",
									},
									declarative.Slider{
										AssignTo: &guimapview.slx,
										Value:    declarative.Bind("TmOut"),
										MaxValue: 8192,
										MinValue: 10,
										RowSpan:  2,
										MinSize:  declarative.Size{Width: 130},

										ToolTipText: "Timeout in milliseconds",

										OnValueChanged: func() {
											settmapin.TmOut = guimapview.slx.Value()
											guimapview.pEdi.SetValue(float64(settmapin.TmOut))

										},
									},
									declarative.NumberEdit{
										AssignTo: &guimapview.pEdi,
										Value:    declarative.Bind("TmOut", declarative.Range{Min: 10, Max: 8192}),
										MaxSize:  declarative.Size{Width: 45},
										MinSize:  declarative.Size{Width: 35},
										OnValueChanged: func() {
											settmapin.TmOut = int(guimapview.pEdi.Value())
											guimapview.slx.SetValue(int(settmapin.TmOut))
										},
									},
								},
							},
							declarative.GroupBox{
								Title:  "Performace Setting",
								Layout: declarative.Grid{Columns: 3},
								Children: []declarative.Widget{
									declarative.Label{
										Text:    "Threads:",
										MinSize: declarative.Size{Width: 48},
									},
									declarative.Slider{
										AssignTo: &guimapview.slv,
										Value:    declarative.Bind("Gortin"),
										MaxValue: 256,
										MinValue: 8,
										RowSpan:  2,
										MinSize:  declarative.Size{Width: 130},

										ToolTipText: "Number of threads (GreenThreads)",

										OnValueChanged: func() {
											settmapin.Gortin = guimapview.slv.Value()
											guimapview.valueEdit.SetValue(float64(settmapin.Gortin))

										},
									},
									declarative.NumberEdit{
										AssignTo: &guimapview.valueEdit,
										MaxSize:  declarative.Size{Width: 45},
										MinSize:  declarative.Size{Width: 35},
										Value:    declarative.Bind("Gortin", declarative.Range{Min: 8, Max: 256}),
										OnValueChanged: func() {
											settmapin.Gortin = int(guimapview.valueEdit.Value())
											guimapview.slv.SetValue(settmapin.Gortin)
										},
									},
								},
							},
						},
					},
				},
			},
			declarative.GroupBox{
				AssignTo: &guimapview.resultGrpBox,
				Visible:  false,
				Title:    "Port Scan Results",
				Layout:   declarative.Grid{Columns: 1},
				Children: []declarative.Widget{
					declarative.TextEdit{
						AssignTo:   &guimapview.rsltTextBox,
						VScroll:    true,
						ReadOnly:   true,
						Background: declarative.SolidColorBrush{Color: 1513239},
						TextColor:  31248,
					},
					declarative.ProgressBar{
						AssignTo:    &guimapview.progsMapperBar,
						MinValue:    0,
						MaxValue:    100,
						ToolTipText: "Progress Bar",
						MaxSize:     declarative.Size{Height: 19},
						Visible:     false,
					},
					declarative.LineEdit{
						AssignTo: &guimapview.stsLine,
						Visible:  false,
						ReadOnly: true,
					},
				},
			},
			declarative.Composite{
				Layout: declarative.HBox{},
				Children: []declarative.Widget{
					declarative.HSpacer{},
					declarative.PushButton{
						AssignTo: &guimapview.startsPB,
						Text:     "Start Scan",
						OnClicked: func() {
							if guimapview.stopscan == 0 {
								if err := guimapview.dbinder.Submit(); err != nil {
									return
								}
								if settmapin.HostStr == "" {
									guimapview.mapLineEd.SetFocus()
									return
								}
								if match, _ := regexp.MatchString(regexSingle, settmapin.HostStr); !match {
									walk.MsgBox(guimapview.dlg, "Host syntax error", "Invalid IPv4 or Domain address, format: IPv4|Domain\nExample: slc.snix.ir", walk.MsgBoxIconError)
									return
								}
								guimapview.stopscan = 1
								guimapview.startsPB.SetText("Stop Scan")

								if settmapin.Connection {
									var err error
									settmapin.MasgUDP, err = base64.StdEncoding.DecodeString(string(settmapin.MasgUDP))
									if err != nil {
										walk.MsgBox(guimapview.dlg, "Base64 Error", "Error in Decoding base64 message", walk.MsgBoxIconError)
									}

								}
								var portlist []int
								var jobdn, lenopen int
								for i := settmapin.StrPort; i <= settmapin.EndPort; i++ {
									portlist = append(portlist, i)
								}
								guimapview.optionGrpBox.SetVisible(false)
								guimapview.resultGrpBox.SetVisible(true)
								guimapview.progsMapperBar.SetVisible(true)
								guimapview.stsLine.SetVisible(true)
								guimapview.rsltTextBox.SetText(fmt.Sprintf("Starting Mapper (gips.snix.ir) at %v Interesting ports on %v --- %v\r\nPORT\t\tSTATE\t\tSERVICE\r\n", time.Now(), settmapin.HostStr, oprationStat(settmapin.HostStr)))
								ch := make(chan scream.ScanResults)
								go scream.CustomPscan(settmapin.HostStr, time.Duration(settmapin.TmOut)*time.Millisecond, int64(settmapin.Gortin), portlist, settmapin.MasgUDP, settmapin.Connection, ch)
								go func() {
									for i := range ch {
										if statpx, numb := i.StatInfo(); statpx {
											lenopen++
											guimapview.rsltTextBox.SetText(guimapview.rsltTextBox.Text() + fmt.Sprintf("%v/%v\t\t%v\t\t%v\r\n", numb, i.SigPort(), "open", i.PortInfo()))
										}
										jobdn++
										prcstatus := 100 - (float64(len(portlist)-jobdn)/float64(len(portlist)))*float64(100)
										guimapview.progsMapperBar.SetValue(int(prcstatus))
										guimapview.stsLine.SetText(fmt.Sprintf("Progress: %.2f%%\t\tTotal: %v\t\tChecked: %v\t\tOpen: %v", prcstatus, len(portlist), jobdn, lenopen))
									}
									guimapview.stopscan = 2
									guimapview.startsPB.SetText("Back To Scan")
									guimapview.startsPB.SetEnabled(true)
									guimapview.progsMapperBar.SetVisible(false)
									guimapview.stsLine.SetVisible(false)
									guimapview.progsMapperBar.SetValue(0)
									guimapview.stsLine.SetText("Progress: 0\t\tTotal: 0\t\tChecked: 0\t\tOpen: 0")

								}()
							} else if guimapview.stopscan == 1 {
								scream.StopChan <- struct{}{}
								guimapview.startsPB.SetEnabled(false)
							} else {
								guimapview.stopscan = 0
								guimapview.optionGrpBox.SetVisible(true)
								guimapview.resultGrpBox.SetVisible(false)
								guimapview.startsPB.SetText("Start Scan")

							}
						},
					},
					declarative.PushButton{
						AssignTo:  &guimapview.cancelPB,
						Text:      "Close",
						OnClicked: func() { guimapview.dlg.Cancel() },
					},
				},
			},
		},
	}.Run(owner)
}

func oprationStat(addr string) string {
	ipv4add, reptime, err := scream.PingHost(addr, 1)
	if err != nil {
		return fmt.Sprintf("Host %v Latency: %v", ipv4add, err)
	}
	return fmt.Sprintf("Host %v Latency: %v", ipv4add, reptime)
}

Snix LLC Git Repository Holder Copyright(C) 2022 All Rights Reserved Email To Snix.IR