-
Notifications
You must be signed in to change notification settings - Fork 2
/
main.go
141 lines (119 loc) · 2.77 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package main
import (
"crypto/tls"
"fmt"
"io"
"net"
"os"
"github.com/UlisseMini/ngo/internal/exec"
"github.com/UlisseMini/ngo/internal/tlsconfig"
log "github.com/sirupsen/logrus"
)
// hostname for our tls certificate
const hostname = "ngo"
func main() {
// Parse commandline arguments (argsparser.go)
conf := parseArgs()
// connect
conn, err := connect(conf)
mustNot(err)
rw := io.ReadWriter(conn)
// if there is a command to execute over the connection
if conf.cmdStr != "" {
log.Infof("executing: %q over the connection", conf.cmdStr)
cmd := exec.Parse(conf.cmdStr)
exec.Exec(cmd, rw)
return
}
// Don't force handleConn to close the connection, i want to keep it
// as flexible as possible
func() {
defer conn.Close()
handleConn(conf, rw)
}()
}
func connect(conf config) (conn net.Conn, err error) {
if !conf.listen {
if conf.ssl {
// connect with ssl / tls
tlsconf := &tls.Config{InsecureSkipVerify: true}
conn, err := tls.Dial(conf.proto, conf.addr, tlsconf)
if err != nil {
return nil, err
}
return conn, nil
}
conn, err = net.DialTimeout(conf.proto, conf.addr, conf.timeout)
if err != nil {
return nil, err
}
// print the connected message (diferent depending on proto)
if conf.udp {
log.Infof("Sending to %s", conf.addr)
} else {
log.Infof("Connected to %s", conf.addr)
}
} else {
// listening
var l net.Listener
if conf.ssl {
config, err := tlsconfig.Get(hostname)
if err != nil {
return nil, fmt.Errorf("getting tlsconfig: %v", err)
}
l, err = tls.Listen(conf.proto, conf.addr, config)
if err != nil {
return nil, err
}
} else {
l, err = net.Listen(conf.proto, conf.addr)
if err != nil {
return nil, err
}
}
log.Infof("Listening on %s", conf.addr)
conn, err = l.Accept()
log.Infof("Connection from %s", conn.RemoteAddr().String())
if err != nil {
return nil, err
}
}
return conn, nil
}
// handleConn connects the two connections file descriptors.
// the i/o file descriptors are in conf
func handleConn(conf config, conn io.ReadWriter) (err error) {
done := make(chan error)
// connect conn to stdout
go func() {
n, err := io.Copy(conf.out, conn)
errPrint(err)
log.Debugf("Read %d bytes\n", n)
done <- err
}()
// connect stdin to conn
go func() {
n, err := io.Copy(conn, conf.in)
errPrint(err)
log.Debugf("Wrote %d bytes\n", n)
done <- err
}()
// wait for one of the goroutines to finish
err = <-done
log.Debugf("handleConn exiting: %#v", err)
return err
}
// errPrint prints an error using the Error logger
// if the error is not nil
func errPrint(err error) {
if err != nil {
log.Error(err)
}
}
// mustNot prints and exits the program on error.
func mustNot(err error) {
if err != nil {
log.Error(err)
os.Exit(1)
}
}