forked from NEU-SNS/revtrvp
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathicmp_main.go
246 lines (219 loc) · 6.49 KB
/
icmp_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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
package main
import (
"fmt"
"github.com/NEU-SNS/revtrvp/log"
"github.com/NEU-SNS/revtrvp/util"
"net"
"os"
"strconv"
"strings"
"time"
dm "github.com/NEU-SNS/revtrvp/datamodel"
opt "github.com/rhansen2/ipv4optparser"
"golang.org/x/net/icmp"
"golang.org/x/net/ipv4"
)
const (
// ID is the ICMDPID magic number
ID = 0xf0f1
// SEQ is the ICMP seq number magic number
SEQ = 0xf2f3
)
var (
dummy ipv4.ICMPType
icmpProtocolNum = dummy.Protocol()
)
var (
// ErrorNotICMPEcho is returned when the probe is not of the right type
ErrorNotICMPEcho = fmt.Errorf("Received Non ICMP Probe")
// ErrorNonSpoofedProbe is returned when the probe is not spoofed
ErrorNonSpoofedProbe = fmt.Errorf("Received ICMP Probe that was not spoofed")
// ErrorSpoofedProbeNoID is returned when the probe has no ID
ErrorSpoofedProbeNoID = fmt.Errorf("Received a spoofed probe with no id")
// ErrorNoSpooferIP is returned when there is no spoofer ip in the packet
ErrorNoSpooferIP = fmt.Errorf("No spoofer IP found in packet")
// ErrorFailedToParseOptions is returned when there was an error parsing options
ErrorFailedToParseOptions = fmt.Errorf("Failed to parse IPv4 options")
// ErrorFailedToConvertOption is returned when there is an issue converting an option
ErrorFailedToConvertOption = fmt.Errorf("Failed to convert IPv4 option")
// ErrorSpooferIP is returned when the spoofer ip is invalid
ErrorSpooferIP = fmt.Errorf("Failed to convert spoofer ip")
// ErrorReadError is returned when there is an error reading from the icmp monitoring conn
ErrorReadError = fmt.Errorf("Failed to read from conn")
)
func makeID(a, b, c, d byte) uint32 {
var id uint32
id |= uint32(a) << 24
id |= uint32(b) << 16
id |= uint32(c) << 8
id |= uint32(d)
return id
}
func makeRecordRoute(rr opt.RecordRouteOption) (dm.RecordRoute, error) {
rec := dm.RecordRoute{}
for _, r := range rr.Routes {
rec.Hops = append(rec.Hops, uint32(r))
}
return rec, nil
}
func makeTimestamp(ts opt.TimeStampOption) (dm.TimeStamp, error) {
time := dm.TimeStamp{}
time.Type = dm.TSType(ts.Flags)
for _, st := range ts.Stamps {
nst := dm.Stamp{Time: uint32(st.Time), Ip: uint32(st.Addr)}
time.Stamps = append(time.Stamps, &nst)
}
return time, nil
}
func getProbe(conn *ipv4.RawConn) (error) {
// 1500 should be good because we're sending small packets and its the standard MTU
pBuf := make([]byte, 1500)
probe := &dm.Probe{}
// Try and get a packet
header, pload, _, err := conn.ReadFrom(pBuf)
if err != nil {
return ErrorReadError
}
now := time.Now().Format("2006_01_02_15_04")
// Directory structure is MLab specific, where MLab's Pusher service sends everything to Google Cloud Storage.
fname := "/var/spool/revtr/traffic/spooflistener_" + now + ".log"
logf, errf := os.OpenFile(fname, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
defer logf.Close()
if errf != nil {
log.Error(errf)
}
// Parse the payload for ICMP stuff
if _, errf := logf.WriteString("Got packet, parsing payload for ICMP stuff\n"); errf != nil {
log.Error(errf)
}
mess, err := icmp.ParseMessage(icmpProtocolNum, pload)
if err != nil {
return err
}
if echo, ok := mess.Body.(*icmp.Echo); ok {
if _, errf := logf.WriteString("Checking if ID (" + strconv.Itoa(echo.ID) + ") and SEQ (" + strconv.Itoa(echo.Seq) + ") are correct values.\n"); errf != nil {
log.Error(errf)
}
if echo.ID != ID || echo.Seq != SEQ {
return ErrorNonSpoofedProbe
}
if len(echo.Data) < 8 {
return ErrorSpoofedProbeNoID
}
// GetIP of spoofer out of packet
ip := net.IPv4(echo.Data[0],
echo.Data[1],
echo.Data[2],
echo.Data[3])
if ip == nil {
return ErrorNoSpooferIP
}
if _, errf := logf.WriteString("get IP of spoofer out of packet: " + ip.String() + "\n" ); errf != nil {
log.Error(errf)
}
log.Debug("Got packet, parsing payload for ICMP stuff")
// Get the Id out of the data
id := makeID(echo.Data[4], echo.Data[5], echo.Data[6], echo.Data[7])
probe.ProbeId = id
probe.SpooferIp, err = util.IPtoInt32(ip)
if err != nil {
return ErrorSpooferIP
}
probe.Dst, err = util.IPtoInt32(header.Dst)
probe.Src, err = util.IPtoInt32(header.Src)
if _, errf := logf.WriteString("Src: " + header.Src.String() + " and Dst: " + header.Dst.String() + "\n" ); errf != nil {
log.Error(errf)
}
// Parse the options
options, err := opt.Parse(header.Options)
if err != nil {
return ErrorFailedToParseOptions
}
probe.SeqNum = uint32(echo.Seq)
probe.Id = uint32(echo.ID)
for _, option := range options {
switch option.Type {
case opt.RecordRoute:
if _, errf := logf.WriteString("Case RecordRoute\n"); errf != nil {
log.Error(errf)
}
rr, err := option.ToRecordRoute()
if err != nil {
return ErrorFailedToConvertOption
}
rec, err := makeRecordRoute(rr)
if err != nil {
return ErrorFailedToConvertOption
}
probe.RR = &rec
case opt.InternetTimestamp:
if _, errf := logf.WriteString("Case Timestamp\n"); errf != nil {
log.Error(errf)
}
ts, err := option.ToTimeStamp()
if err != nil {
return ErrorFailedToConvertOption
}
nts, err := makeTimestamp(ts)
if err != nil {
return ErrorFailedToConvertOption
}
probe.Ts = &nts
}
}
}
return ErrorNotICMPEcho
}
// GetBindAddr gets the IP of the eth0 like address
// (!!MLab specific!!: use net1 because eth0 is private)
func GetBindAddr() (string, error) {
ifaces, err := net.Interfaces()
if err != nil {
return "", err
}
for _, iface := range ifaces {
if strings.Contains(iface.Name, "net1") &&
uint(iface.Flags)&uint(net.FlagUp) > 0 {
addrs, err := iface.Addrs()
if err != nil {
return "", err
}
addr := addrs[0]
ip, _, err := net.ParseCIDR(addr.String())
if err != nil {
return "", err
}
return ip.String(), nil
}
}
return "", fmt.Errorf("Didn't find net1 interface")
}
func reconnect(addr string) (*ipv4.RawConn, error) {
pc, err := net.ListenPacket(fmt.Sprintf("ip4:%d", icmpProtocolNum), addr)
if err != nil {
return nil, err
}
return ipv4.NewRawConn(pc)
}
func main_x(){
addr, _ := GetBindAddr()
now := time.Now().Format("2006_01_02_15_04")
fname := "/var/spool/revtr/traffic/addr_config" + now
logf, errf := os.OpenFile(fname, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
defer logf.Close()
if errf != nil {
log.Error(errf)
}
if _, errf := logf.WriteString("addr is: " + addr); errf != nil {
log.Error(errf)
}
c, err := reconnect(addr)
if err != nil {
fmt.Println("error")
return
}
for {
fmt.Println("Listening for a new probe.")
getProbe(c)
}
}