-
Notifications
You must be signed in to change notification settings - Fork 21
/
Copy pathremote.go
142 lines (120 loc) · 2.84 KB
/
remote.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
142
package sploit
import (
"bufio"
"bytes"
"errors"
"fmt"
"io"
"net"
"strconv"
)
// Remote is an interface for communicating over IP
type Remote struct {
HostPort string
Host string
Port uint16
C net.Conn
}
// NewRemote connects to the specified remote host and returns an initialized Remote instance
func NewRemote(protocol string, hostPort string) (*Remote, error) {
host, portString, err := net.SplitHostPort(hostPort)
if err != nil {
return nil, err
}
port, err := strconv.ParseUint(portString, 10, 16)
if err != nil {
return nil, err
}
c, err := net.Dial(protocol, hostPort)
if err != nil {
return nil, err
}
return &Remote{
HostPort: hostPort,
Host: host,
Port: uint16(port),
C: c,
}, nil
}
// Close is a Remote method for closing the connection if it's active
func (r *Remote) Close() {
if r.C != nil {
r.C.Close()
}
}
// RecvUntil is a Remote method for receiving data over IP until the specified sequence of bytes is detected
func (r *Remote) RecvUntil(needle []byte, drop bool) ([]byte, error) {
data := make([]byte, len(needle))
b := bufio.NewReader(r.C)
// Read needle-size
n, err := io.ReadFull(b, data)
if err != nil {
return nil, err
}
// Make sure it read the entire size of the needle
if n != len(needle) {
return nil, errors.New("RecvUntil truncated")
}
// Compare needle and received data and continue to read a byte at a time
idx := 0
for {
if bytes.Compare(data[idx:idx+len(needle)], needle) == 0 {
if drop == true {
return data[0 : len(data)-len(needle)], nil
}
return data, nil
}
byt, err := b.ReadByte()
if err != nil {
return nil, err
}
data = append(data, byt)
idx++
}
}
// RecvLine is a Remote method for receiving data over IP until a newline delimiter is detected
func (r *Remote) RecvLine() ([]byte, error) {
return r.RecvUntil([]byte("\n"), true)
}
// RecvN is a Remote method for receiving a specified number of bytes
func (r *Remote) RecvN(n int) ([]byte, error) {
b := make([]byte, n)
rn, err := r.C.Read(b)
if err != nil {
return nil, err
}
return b[:rn], nil
}
// Send is a Remote method for sending data over IP
func (r *Remote) Send(data []byte) (int, error) {
return r.C.Write(data)
}
// SendLine is a Remote method for sending data with a trailing newline character
func (r *Remote) SendLine(line []byte) (int, error) {
line = append(line, '\n')
return r.C.Write(line)
}
// Interactive is a Remote method that allows the user to interact with a remote process manually
func (r *Remote) Interactive() error {
go func() {
for {
data, err := r.RecvN(1)
if err != nil {
break
}
fmt.Printf("%c", data[0])
}
}()
for {
var line string
fmt.Scanln(&line)
if line == "_quit" {
fmt.Println("Exiting...")
return nil
}
_, err := r.SendLine([]byte(line))
if err != nil {
return err
}
}
}