-
Notifications
You must be signed in to change notification settings - Fork 231
/
level3.go
198 lines (185 loc) · 4.57 KB
/
level3.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
// Package lg provides looking glass methods for selected looking glasses
// Level3 Carrier Looking Glass ASN 3356
package lg
import (
"bufio"
"errors"
"html"
"io/ioutil"
"net/http"
"net/url"
"regexp"
"sort"
"strings"
)
const (
level3LGURL = "http://lookingglass.level3.net"
level3LGPing = "/ping/lg_ping_output.php"
level3LGTrace = "/traceroute/lg_tr_output.php"
level3LGBGP = "/bgp/lg_bgp_output.php"
)
// A Level3 represents a telia looking glass request
type Level3 struct {
Host string
CIDR string
IPv string
Count string
Node string
Nodes []string
}
var (
level3Nodes = map[string]string{"Los Angeles, CA": "ear1.lax1"}
level3DefaultNode = "Los Angeles, CA"
)
// sanitize removes html tags
func sanitize(b string) string {
re := regexp.MustCompile(`<br>`)
b = re.ReplaceAllString(b, "\n")
re = regexp.MustCompile(`<[^>]*>`)
b = re.ReplaceAllString(b, "")
return html.UnescapeString(b)
}
// Set configures host and ip version
func (p *Level3) Set(host, version string) {
if i := strings.Index(host, "/"); i > 0 {
p.Host = host[:i]
p.CIDR = host[i+1:]
} else {
p.Host = host
p.CIDR = "24"
}
p.IPv = version
p.Count = "5"
if p.Node == "" {
p.Node = level3DefaultNode
}
}
// GetDefaultNode returns telia default node
func (p *Level3) GetDefaultNode() string {
return level3DefaultNode
}
// GetNodes returns all level3 nodes (US and International)
func (p *Level3) GetNodes() []string {
// Memory cache
if len(p.Nodes) > 1 {
return p.Nodes
}
level3Nodes = p.FetchNodes()
var nodes []string
for node := range level3Nodes {
nodes = append(nodes, node)
}
sort.Strings(nodes)
p.Nodes = nodes
return nodes
}
// ChangeNode set new requested node
func (p *Level3) ChangeNode(node string) bool {
// Validate
for _, n := range p.Nodes {
if node == n {
p.Node = node
return true
}
}
return false
}
// Ping tries to connect Level3's ping looking glass through HTTP
// Returns the result
func (p *Level3) Ping() (string, error) {
// Basic validate
if p.Node == "NA" || len(p.Host) < 5 {
print("Invalid node or host/ip address")
return "", errors.New("error")
}
resp, err := http.PostForm(level3LGURL+level3LGPing,
url.Values{"count": {p.Count}, "size": {"64"}, "address": {p.Host}, "sitename": {level3Nodes[p.Node]}})
if err != nil {
return "", err
}
if resp.StatusCode != 200 {
return "", errors.New("error: level3 looking glass is not available")
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", err
}
r, _ := regexp.Compile(`</div></div>(?s)(.*?)</font></pre>`)
b := r.FindStringSubmatch(strings.Replace(string(body), "<br>", "\n", -1))
if len(b) > 0 {
return sanitize(b[1]), nil
}
return "", errors.New("error")
}
// Trace gets traceroute information from level3
func (p *Level3) Trace() chan string {
c := make(chan string)
resp, err := http.PostForm(level3LGURL+level3LGTrace,
url.Values{"address": {p.Host}, "sitename": {level3Nodes[p.Node]}})
if err != nil {
println(err)
}
go func() {
defer resp.Body.Close()
scanner := bufio.NewScanner(resp.Body)
for scanner.Scan() {
l := scanner.Text()
m, _ := regexp.MatchString(`(?i)(^traceroute|\s+\d{1,2})\s+`, l)
if m {
l = sanitize(l)
c <- l
}
}
close(c)
}()
return c
}
// BGP gets bgp information
func (p *Level3) BGP() chan string {
c := make(chan string)
resp, err := http.PostForm(level3LGURL+level3LGBGP,
url.Values{"address": {p.Host}, "length": {p.CIDR}, "sitename": {level3Nodes[p.Node]}})
if err != nil {
println(err.Error())
close(c)
}
go func() {
defer resp.Body.Close()
scanner := bufio.NewScanner(resp.Body)
for scanner.Scan() {
l := scanner.Text()
if m, _ := regexp.MatchString("Route results", l); !m {
continue
}
if i := strings.Index(l, "Route results"); i > 0 {
l = l[i:]
}
l = sanitize(l)
c <- l
}
close(c)
}()
return c
}
//FetchNodes returns all available nodes through HTTP
func (p *Level3) FetchNodes() map[string]string {
var nodes = make(map[string]string, 100)
resp, err := http.Get("http://lookingglass.level3.net/ping/lg_ping_main.php")
if err != nil {
println("error: level3 looking glass unreachable (1)")
return map[string]string{}
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
println("error: level3 looking glass unreachable (2)" + err.Error())
return map[string]string{}
}
r, _ := regexp.Compile(`(?i)<option value="(?s)([\w|\s|)(._-]+)">(?s)([a-z|\s|)(,._-]+)</option>`)
b := r.FindAllStringSubmatch(string(body), -1)
for _, v := range b {
nodes[v[2]] = v[1]
}
return nodes
}