GO making multiple goroutines that use nmap - go

I'm trying to use Go's concurrency to create a script that runs multiple nmap scans with different options but whenever I try to run the program it exits after the 1st nmap scan completes. Is there a way to prevent this?
here's the code:
package main
import (
"syscall"
"os"
"os/exec"
"fmt"
)
func main(){
args1 := []string{"nmap","-sS","127.0.0.1"}
args2 := []string{"nmap","-sN","127.0.0.1"}
args3 := []string{"nmap","-sV","127.0.0.1"}
go funccmd(args1)
go funccmd(args2)
go funccmd(args3)
fmt.Scanln()
}
func funccmd(args []string){
env := os.Environ()
cmdpath, runErr := exec.LookPath("/usr/bin/nmap")
if runErr != nil {
panic(runErr)
}
execErr := syscall.Exec(cmdpath, args, env)
if execErr != nil {
panic(execErr)
}
}

Do not use syscall.Exec. That calls execve which replaces the current program with nmap. Use exec.Cmd to execute nmap instead.

Related

Capture SIGINT when running tests in GoLand IDE

When running tests from command line, capturing SIGINT works fine. However, is there a way to pass SIGINT signal to code when running tests from GoLand IDE?
When running from command line:
go test -v -run TestSth and then calling Ctrl + C it captures fine.
Example code:
EDIT: it seems my example code now captures SIGINT as intended (Goland 2022.3.2)
package main
import (
"fmt"
"os"
"os/signal"
"syscall"
"testing"
"time"
)
func TestMain(m *testing.M) {
terminate := make(chan os.Signal)
signal.Notify(terminate, syscall.SIGINT)
go func() {
<-terminate
fmt.Println()
fmt.Println("CAPTURED!!!") // want to get here when running tests from IDE
}()
exitCode := m.Run()
os.Exit(exitCode)
}
func TestSth(t *testing.T) {
time.Sleep(time.Second * 5)
}
Get the current process information by calling FindProcess on the current PID and signal the interrupt to it using Process.Signal
func TestSth(t *testing.T) {
go func() {
// Sleep added for demonstrative purposes, can be removed
time.Sleep(time.Second * 1)
p, err := os.FindProcess(os.Getpid())
if err != nil {
panic(err)
}
p.Signal(syscall.SIGINT)
}()
time.Sleep(time.Second * 5)
}

exec command every one minute and serve the output via http

I want to run a command in the Bash shell every one minute, and serve the output via http, on http://localhost:8080/feed
package main
import (
"fmt"
"os/exec"
)
func main() {
cmd := `<a piped command>`
out, err := exec.Command("bash", "-c", cmd).Output()
if err != nil {
fmt.Sprintf("Failed to execute command: %s", cmd)
}
fmt.Println(string(out))
}
UPDATE :
package main
import (
"fmt"
"log"
"net/http"
"os/exec"
)
func handler(w http.ResponseWriter, r *http.Request) {
cmd := `<a piped command>`
out, err := exec.Command("bash", "-c", cmd).Output()
if err != nil {
fmt.Sprintf("Failed to execute command: %s", cmd)
}
fmt.Fprintf(w, string(out))
}
func main() {
http.HandleFunc("/feed", handler)
log.Fatal(http.ListenAndServe(":8080", nil))
}
With the above code, the command is run every time http://localhost:8080/feed is accessed. How do I make it cache(?) the output of the command for one minute, and then run the command again only after the cache time is expired?
If output is not too big, you can keep it in memory variable.
I took approach to wait for result in case that script is executed (using mutex):
package main
import (
"fmt"
"net/http"
"os/exec"
"sync"
"time"
)
var LoopDelay = 60*time.Second
type Output struct {
sync.Mutex
content string
}
func main() {
var output *Output = new(Output)
go updateResult(output)
http.HandleFunc("/feed", initHandle(output))
err := http.ListenAndServe(":8080", nil)
if err != nil {
fmt.Println("ERROR", err)
}
}
func initHandle(output *Output) func(http.ResponseWriter, *http.Request) {
return func(respw http.ResponseWriter, req *http.Request) {
output.Lock()
defer output.Unlock()
_, err := respw.Write([]byte(output.content))
if err != nil {
fmt.Println("ERROR: Unable to write response: ", err)
}
}
}
func updateResult(output *Output) {
var execFn = func() { /* Extracted so that 'defer' executes at the end of loop iteration */
output.Lock()
defer output.Unlock()
command := exec.Command("bash", "-c", "date | nl ")
output1, err := command.CombinedOutput()
if err != nil {
output.content = err.Error()
} else {
output.content = string(output1)
}
}
for {
execFn()
time.Sleep(LoopDelay)
}
}
Executing
date; curl http://localhost:8080/feed
gives output (on multiple calls):
1 dimanche 13 octobre 2019, 09:41:40 (UTC+0200)
http-server-cmd-output> date; curl http://localhost:8080/feed
dimanche 13 octobre 2019, 09:42:05 (UTC+0200)
1 dimanche 13 octobre 2019, 09:41:40 (UTC+0200)
Few things to consider:
- Used 'date | nl' as command with pipe example
- If output too big, write to file
- Very likely it is good idea to keep mutex only for content update (no need to wait during script execution) - you can try to improve it
- Go routine may have variable (channel) to exit on signal (ex: when program ends)
EDIT: variable moved to main function
How do I make it cache(?) the output of the command for one minute,
and then run the command again only after the cache time is expired?
In below solution two goroutines are declared.
First goroutine loop until the context is done to execute the command at regular interval and send a copy to the second go routine.
The second routine, tries to get from the first goroutine, or distribute its value to other goroutines.
The http handler, third goroutine, only queries the value from the getter and does something with it.
The reason to use three routines instead of two in this example is to prevent blocking the http routines if the command is being executed. With that additional routines, http requests only wait for the synchronization to occur.
type state is a dummy struct to transport the values within channels.
We prevent race conditions because of two facts, the state is passed by value, cmd.Output() allocates a new buffer each time it runs.
To retrieve original command in the http handler, OP should build a custom error type and attach those information to the recorded error, within the http handler, OP should type assert the error to its custom type and get the specific details from there.
package main
import (
"context"
"fmt"
"log"
"net/http"
"os/exec"
"time"
)
type state struct {
out []byte
err error
}
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
set := make(chan state, 1)
go func() {
ticker := time.NewTicker(2 * time.Second)
cmd := []string{"date"}
s := state{}
s.out, s.err = exec.Command(cmd[0], cmd[1:]...).Output()
set <- s
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
s.out, s.err = exec.Command(cmd[0], cmd[1:]...).Output()
set <- s
}
}
}()
get := make(chan state)
go func() {
s := state{}
for {
select {
case <-ctx.Done():
return
case s = <-set: // get the fresh value, if any
case get <- s: // distribute your copy
}
}
}()
http.HandleFunc("/feed", func(w http.ResponseWriter, r *http.Request) {
state := <-get
if state.err != nil {
fmt.Printf("Failed to execute command: %v", state.err)
}
fmt.Fprintf(w, string(state.out))
})
log.Fatal(http.ListenAndServe(":8080", nil))
}
You could:
write the last command instance (the "string(out)") to a log file: see "Go/Golang write log to file"
serve that log file (and only the file) in a Go http server: see "How to serve a file to a specific URL path with the FileServer function in go/golang"
That way, any time you go to your server, you will get the last command output.
How do I make it cache(?) the output of the command for one minute, and then run the command again only after the cache time is expired?
By keeping the execution of the command separate from the command output being served.
That is why you must kept the two asynchronous, typically through a goroutine, a a time.NewTicker.
See "Is there a way to do repetitive tasks at intervals?"

How to run variable as shell script file

I need to run a variable as shell script file in golang. I tried like below code
package main
import (
"fmt"
"os/exec"
)
func main() {
var namespaceYaml string = `#!/bin/bash
docker verson`
out, err := exec.Command(namespaceYaml).Output()
fmt.Println(err, string(out))
}
But I cannot get any result. I cannot find where is the mistake.
Please anyone to fix this issue. Thanks in advance.
From official doc:
func Command(name string, arg ...string) *Cmd
Command returns the Cmd struct to execute the named program with the given arguments.
Try this:
package main
import (
"fmt"
"os/exec"
)
func main() {
out, err := exec.Command("docker", "version").Output()
if err != nil {
log.Fatal(err)
}
fmt.Printf("Docker version is: %s\n", out)
}
Useful links for further details:
exec
examples
Note: make sure docker is installed on your machine.

Go exec.Command() - run command which contains pipe

The following works and prints the command output:
out, err := exec.Command("ps", "cax").Output()
but this one fails (with exit status 1):
out, err := exec.Command("ps", "cax | grep myapp").Output()
Any suggestions?
Passing everything to bash works, but here's a more idiomatic way of doing it.
package main
import (
"fmt"
"os/exec"
)
func main() {
grep := exec.Command("grep", "redis")
ps := exec.Command("ps", "cax")
// Get ps's stdout and attach it to grep's stdin.
pipe, _ := ps.StdoutPipe()
defer pipe.Close()
grep.Stdin = pipe
// Run ps first.
ps.Start()
// Run and get the output of grep.
res, _ := grep.Output()
fmt.Println(string(res))
}
You could do:
out, err := exec.Command("bash", "-c", "ps cax | grep myapp").Output()
In this specific case, you don't really need a pipe, a Go can grep as well:
package main
import (
"bufio"
"bytes"
"os/exec"
"strings"
)
func main() {
c, b := exec.Command("go", "env"), new(bytes.Buffer)
c.Stdout = b
c.Run()
s := bufio.NewScanner(b)
for s.Scan() {
if strings.Contains(s.Text(), "CACHE") {
println(s.Text())
}
}
}

Communication with other Go process

I have a program that reads a filename from the console and executes go run filename.go.
// main.go
package main
import (
"bufio"
"fmt"
"log"
"os"
"os/exec"
)
func main() {
console := bufio.NewReader(os.Stdin)
fmt.Print("Enter a filename: ")
input, err := console.ReadString('\n')
if err != nil {
log.Fatalln(err)
}
input = input[:len(input)-1]
gorun := exec.Command("go", "run", input)
result, err := gorun.Output()
if err != nil {
log.Println(err)
}
fmt.Println("---", input, "Result ---")
fmt.Println(string(result))
}
In the same directory, I have another file like this.
// hello.go
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}
When I input "hello.go" in the console, that file is run, and its output gets returned to the parent Go process. However, I have another program like this.
// count.go
package main
import (
"fmt"
"time"
)
func main() {
i := 0
for {
time.Sleep(time.Second)
i++
fmt.Println(i)
}
}
Except, because this program never returns, my parent process is left hanging forever. Is there a way to communicate with different Go processes? I'm thinking something like channels for goroutines, but for processes. I need to be able to receive live stdout from the child process.
The problem I'm trying to solve is dynamically executing Go programs from a directory. Go files will be added, removed, and modified daily. I'm kind of trying to make something like Go Playgrounds. The main process is a webserver serving webpages, so I can't shut it down all the time to modify code.
Don't use go run, you need to do what go run is doing yourself to have the go program be a direct child of your server process.
Using go build -o path_to/binary source_file.go will give you more control. Then you can can directly execute and communicate with the resulting binary.

Resources