Created
June 23, 2020 01:42
-
-
Save ancms2600/8676a135ad0ad143d596a097cc85bf34 to your computer and use it in GitHub Desktop.
Listening service, upon tcp connection, launches a process (once per connection) and pipes stdin/out/err back and forth. Used to make hosting simple netcat/telnet services easier (ie. during CTF competitions)
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
package main | |
import ( | |
"bufio" | |
"fmt" | |
"net" | |
"os" | |
"io" | |
"os/exec" | |
"time" | |
) | |
const ( | |
CONN_HOST = "0.0.0.0" | |
CONN_PORT = "3000" | |
CONN_TYPE = "tcp" | |
) | |
func main() { | |
l, err := net.Listen(CONN_TYPE, CONN_HOST+":"+CONN_PORT) | |
if err != nil { | |
fmt.Printf("%s Error listening: %s\n", ts(), err.Error()) | |
os.Exit(1) | |
} | |
defer l.Close() | |
process := os.Args[1] | |
fmt.Printf("%s Will run process: %s\n", ts(), process) | |
fmt.Printf("%s Listening on %s:%s\n", ts(), CONN_HOST, CONN_PORT) | |
for { | |
conn, err := l.Accept() | |
if err != nil { | |
fmt.Printf("%s Error accepting: %s\n", ts(), err.Error()) | |
os.Exit(1) | |
} | |
go handleRequest(conn, process) | |
} | |
} | |
func ts() string { | |
return time.Now().Format(time.RFC3339) | |
} | |
func handleRequest(conn net.Conn, process string) { | |
fmt.Printf("%s Client %s starting new process.\n", ts(), conn.RemoteAddr()) | |
serverCmd := exec.Command(process) | |
serverIn, err := serverCmd.StdinPipe() | |
if err != nil { | |
fmt.Printf("%s Error streaming process stdin: %s\n", ts(), err.Error()) | |
} | |
serverOut, err := serverCmd.StdoutPipe() | |
if err != nil { | |
fmt.Printf("%s Error streaming process stdout: %s\n", ts(), err.Error()) | |
} | |
serverErr, err := serverCmd.StderrPipe() | |
if err != nil { | |
fmt.Printf("%s Error streaming process stderr: %s\n", ts(), err.Error()) | |
} | |
err2 := serverCmd.Start() | |
if err2 != nil { | |
fmt.Printf("%s Error starting process: %s\n", ts(), err2.Error()) | |
} | |
go streamIn(conn, serverCmd, serverIn) | |
go streamOut(conn, serverCmd, serverOut) | |
go streamErr(conn, serverCmd, serverErr) | |
go timeout(conn, serverCmd); | |
serverCmd.Wait() | |
// allow time for stdout to flush over socket | |
time.Sleep(1 * time.Second) | |
serverIn.Close() | |
close(conn, serverCmd, "hangup"); | |
} | |
func timeout(conn net.Conn, cmd *exec.Cmd) { | |
time.Sleep(2 * time.Minute) | |
close(conn, cmd, "timeout"); | |
} | |
func close(conn net.Conn, cmd *exec.Cmd, reason string) { | |
err1 := conn.Close() | |
if err1 != nil { | |
// fmt.Printf("%s Error failed to kill process: %s\n", ts(), err.Error()) | |
} else { | |
fmt.Printf("%s Client %s socket closed by service. reason: %s\n", ts(), conn.RemoteAddr(), reason) | |
} | |
err := cmd.Process.Kill() | |
if err != nil { | |
// fmt.Printf("%s Error failed to kill process: %s\n", ts(), err.Error()) | |
} else { | |
fmt.Printf("%s Client %s process killed by service. reason: %s\n", ts(), conn.RemoteAddr(), reason) | |
} | |
} | |
func streamIn(conn net.Conn, cmd *exec.Cmd, serverIn io.WriteCloser) { | |
for { | |
buf := make([]byte, 1024) | |
_, err := conn.Read(buf) | |
if err != nil { | |
//fmt.Printf("%s Error reading user input from socket: %s\n", ts(), err.Error()) | |
break; | |
} | |
serverIn.Write(buf) | |
} | |
} | |
func streamOut(conn net.Conn, cmd *exec.Cmd, serverOut io.ReadCloser) { | |
scanner := bufio.NewScanner(serverOut) | |
scanner.Split(bufio.ScanBytes) | |
for scanner.Scan() { | |
m := scanner.Bytes() | |
conn.Write(m) | |
} | |
} | |
func streamErr(conn net.Conn, cmd *exec.Cmd, serverErr io.ReadCloser) { | |
scanner := bufio.NewScanner(serverErr) | |
scanner.Split(bufio.ScanBytes) | |
for scanner.Scan() { | |
m := scanner.Bytes() | |
conn.Write(m) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment