123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250 |
- 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 [%#v].\n", n, buff[:n])
- }
- if err != nil {
- log.Println("Drain:", err)
- }
- conn.SetReadDeadline(time.Time{})
- }
|