|
@@ -0,0 +1,250 @@
|
|
|
|
+package main
|
|
|
|
+
|
|
|
|
+import (
|
|
|
|
+ "flag"
|
|
|
|
+ "fmt"
|
|
|
|
+ "log"
|
|
|
|
+ "net"
|
|
|
|
+ "os"
|
|
|
|
+ "os/exec"
|
|
|
|
+ "strconv"
|
|
|
|
+ "strings"
|
|
|
|
+ "time"
|
|
|
|
+)
|
|
|
|
+
|
|
|
|
+const (
|
|
|
|
+ connHost = "0.0.0.0"
|
|
|
|
+ connPort = "8080"
|
|
|
|
+ connType = "tcp"
|
|
|
|
+)
|
|
|
|
+
|
|
|
|
+func main() {
|
|
|
|
+ var port int
|
|
|
|
+ var drain int
|
|
|
|
+ var cp437 bool
|
|
|
|
+
|
|
|
|
+ flag.IntVar(&port, "p", 0, "Port number to listen on")
|
|
|
|
+ flag.IntVar(&drain, "d", 2, "Drain seconds")
|
|
|
|
+ flag.BoolVar(&cp437, "c", false, "Force CP437 translation")
|
|
|
|
+ flag.Parse()
|
|
|
|
+
|
|
|
|
+ if port == 0 && flag.NArg() != 1 {
|
|
|
|
+ fmt.Println("I need a Port and a commandline to execute.")
|
|
|
|
+ flag.PrintDefaults()
|
|
|
|
+ os.Exit(2)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fmt.Println("Starting " + connType + " server on " + connHost + ":" + strconv.Itoa(port))
|
|
|
|
+ l, err := net.Listen("tcp", "0.0.0.0:"+strconv.Itoa(port))
|
|
|
|
+ if err != nil {
|
|
|
|
+ log.Println("Error listening:", err)
|
|
|
|
+ os.Exit(1)
|
|
|
|
+ }
|
|
|
|
+ defer l.Close()
|
|
|
|
+
|
|
|
|
+ for {
|
|
|
|
+ var c net.Conn
|
|
|
|
+ var err error
|
|
|
|
+
|
|
|
|
+ c, err = l.Accept()
|
|
|
|
+ if err != nil {
|
|
|
|
+ log.Println("Error connecting:", err)
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ go Connection(c, drain, flag.Arg(0), cp437)
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func Conn_to_File(conn net.Conn) *os.File {
|
|
|
|
+ var tcpconn *net.TCPConn = conn.(*net.TCPConn)
|
|
|
|
+
|
|
|
|
+ // This creates a duplicate fd, but once closed -- the fd gets reused!
|
|
|
|
+ var conn_file *os.File
|
|
|
|
+ // var err error
|
|
|
|
+ conn_file, _ = tcpconn.File()
|
|
|
|
+
|
|
|
|
+ return conn_file
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func ReadFrom_WriteTo(read net.Conn, write net.Conn, closed *bool) {
|
|
|
|
+ var buff []byte = make([]byte, 128)
|
|
|
|
+ var n int
|
|
|
|
+ var err error
|
|
|
|
+
|
|
|
|
+ defer func() {
|
|
|
|
+ read.Close()
|
|
|
|
+ write.Close()
|
|
|
|
+ if !*closed {
|
|
|
|
+ log.Println("*Closed*")
|
|
|
|
+ *closed = true
|
|
|
|
+ }
|
|
|
|
+ }()
|
|
|
|
+
|
|
|
|
+ for {
|
|
|
|
+ n, err = read.Read(buff)
|
|
|
|
+ if err != nil {
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ n, err = write.Write(buff[:n])
|
|
|
|
+ if err != nil {
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func ReadFrom_WriteToCP437(read net.Conn, write net.Conn, closed *bool) {
|
|
|
|
+ var buff []byte = make([]byte, 128)
|
|
|
|
+ var n int
|
|
|
|
+ var err error
|
|
|
|
+
|
|
|
|
+ defer func() {
|
|
|
|
+ read.Close()
|
|
|
|
+ write.Close()
|
|
|
|
+ if !*closed {
|
|
|
|
+ log.Println("*Closed*")
|
|
|
|
+ *closed = true
|
|
|
|
+ }
|
|
|
|
+ }()
|
|
|
|
+
|
|
|
|
+ for {
|
|
|
|
+ n, err = read.Read(buff)
|
|
|
|
+ if err != nil {
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ var line = string(buff[:n])
|
|
|
|
+
|
|
|
|
+ // This does convert everything to unicode
|
|
|
|
+ // syncterm doesn't like it (because it doesn't understand
|
|
|
|
+ // unicode!)
|
|
|
|
+ // The "door" detects CP437 (not unicode)
|
|
|
|
+
|
|
|
|
+ // This would allow a CP437 door to run as unicode.
|
|
|
|
+ n, err = write.Write([]byte(CP437_to_Unicode(line)))
|
|
|
|
+ if err != nil {
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func StartProxy(live net.Conn, monitor net.Conn, closed *bool, cp437 bool) {
|
|
|
|
+ go ReadFrom_WriteTo(live, monitor, closed)
|
|
|
|
+
|
|
|
|
+ if cp437 {
|
|
|
|
+ go ReadFrom_WriteToCP437(monitor, live, closed)
|
|
|
|
+ } else {
|
|
|
|
+ go ReadFrom_WriteTo(monitor, live, closed)
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ Read from live, write to server.
|
|
|
|
+ Read from server, write to live.
|
|
|
|
+*/
|
|
|
|
+func setup_monitor(live net.Conn, closed *bool, cp437 bool) (monitor net.Conn) {
|
|
|
|
+ var err error
|
|
|
|
+ var tempsock net.Listener
|
|
|
|
+
|
|
|
|
+ tempsock, err = net.Listen("tcp", "127.0.0.1:0")
|
|
|
|
+ if err != nil {
|
|
|
|
+ panic(err)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // I only need address for making the connection.
|
|
|
|
+ // Get address of listening socket
|
|
|
|
+ var address string
|
|
|
|
+ address = tempsock.Addr().String()
|
|
|
|
+
|
|
|
|
+ monitor, err = net.Dial("tcp", address)
|
|
|
|
+
|
|
|
|
+ if err != nil {
|
|
|
|
+ panic(err)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ var server net.Conn
|
|
|
|
+ server, err = tempsock.Accept()
|
|
|
|
+ if err != nil {
|
|
|
|
+ panic(err)
|
|
|
|
+ }
|
|
|
|
+ tempsock.Close()
|
|
|
|
+
|
|
|
|
+ *closed = false
|
|
|
|
+ // monitor established - forward live <-> monitor
|
|
|
|
+ go StartProxy(live, server, closed, cp437)
|
|
|
|
+
|
|
|
|
+ return monitor
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func Connection(conn net.Conn, drain int, cmd string, cp437 bool) {
|
|
|
|
+ log.Println("Client " + conn.RemoteAddr().String() + " connected.")
|
|
|
|
+
|
|
|
|
+ // Configure telnet connection to work
|
|
|
|
+ // local echo off, handle CRNL.
|
|
|
|
+ conn.Write([]byte("\xff\xfb\x01\xff\xfb\x03\xff\xfd\x10"))
|
|
|
|
+ Drain(conn, drain)
|
|
|
|
+
|
|
|
|
+ var closed bool
|
|
|
|
+ var proxy net.Conn
|
|
|
|
+ proxy = setup_monitor(conn, &closed, cp437)
|
|
|
|
+
|
|
|
|
+ // Write out dropfile
|
|
|
|
+ var conn_file *os.File = Conn_to_File(proxy)
|
|
|
|
+ var handle int = 3
|
|
|
|
+ var err error
|
|
|
|
+ var fp *os.File
|
|
|
|
+ fp, err = os.Create("door32.sys")
|
|
|
|
+ if err != nil {
|
|
|
|
+ log.Println("os.Create:", err)
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ fmt.Fprintf(fp, "2\n%d\n38400\nFake Door32\n1\nBugz Laundry\nBugz\n100\n120\n1\n1\n", handle)
|
|
|
|
+ fp.Close()
|
|
|
|
+
|
|
|
|
+ var parts []string = strings.Split(cmd, " ")
|
|
|
|
+ var Exe *exec.Cmd = exec.Command(parts[0], parts[1:]...)
|
|
|
|
+ Exe.ExtraFiles = make([]*os.File, 1)
|
|
|
|
+ Exe.ExtraFiles[0] = conn_file
|
|
|
|
+
|
|
|
|
+ Exe.Stderr = os.Stderr
|
|
|
|
+ Exe.Stdout = os.Stdout
|
|
|
|
+
|
|
|
|
+ err = Exe.Start()
|
|
|
|
+ if err != nil {
|
|
|
|
+ log.Println("exec.Cmd.Start():", err)
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ log.Println("Door running..." + conn.RemoteAddr().String())
|
|
|
|
+ // Add a timeout here - to make sure the door isn't hung.
|
|
|
|
+ // Is there a way to detect if the conn is disconnected?
|
|
|
|
+
|
|
|
|
+ err = Exe.Wait()
|
|
|
|
+ if err != nil {
|
|
|
|
+ log.Println("exec.Cmd.Wait():", err)
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if closed {
|
|
|
|
+ log.Println("Closed!")
|
|
|
|
+ }
|
|
|
|
+ log.Println("Door ended..." + conn.RemoteAddr().String())
|
|
|
|
+ conn_file.Close()
|
|
|
|
+ proxy.Close()
|
|
|
|
+
|
|
|
|
+ conn.Write([]byte("\r\nWelcome back...\r\n"))
|
|
|
|
+ conn.Close()
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func Drain(conn net.Conn, drain int) {
|
|
|
|
+ conn.SetReadDeadline(time.Now().Add(time.Second * time.Duration(drain)))
|
|
|
|
+ var buff []byte = make([]byte, 32)
|
|
|
|
+ var n int
|
|
|
|
+ var err error
|
|
|
|
+ n, err = conn.Read(buff)
|
|
|
|
+ if n > 0 {
|
|
|
|
+ log.Printf("Drained %d bytes.\n", n)
|
|
|
|
+ }
|
|
|
|
+ if err != nil {
|
|
|
|
+ log.Println("Drain:", err)
|
|
|
|
+ }
|
|
|
|
+ conn.SetReadDeadline(time.Time{})
|
|
|
|
+}
|