-
Notifications
You must be signed in to change notification settings - Fork 1
/
analysis.go
108 lines (87 loc) · 2.93 KB
/
analysis.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
package reach
import (
"encoding/json"
"log"
)
// Analysis is the central structure of a Reach analysis. It describes what subjects were analyzed, what resources were retrieved, and a collection of network vectors between all source-to-destination pairings of subjects.
type Analysis struct {
Subjects []*Subject
Resources *ResourceCollection
NetworkVectors []NetworkVector
}
// NewAnalysis simply creates a new Analysis struct.
func NewAnalysis(subjects []*Subject, resources *ResourceCollection, networkVectors []NetworkVector) *Analysis {
return &Analysis{
Subjects: subjects,
Resources: resources,
NetworkVectors: networkVectors,
}
}
// ToJSON outputs the Analysis as a JSON string.
func (a *Analysis) ToJSON() string {
b, err := json.MarshalIndent(a, "", " ")
if err != nil {
log.Fatal(err)
}
return string(b)
}
// MergedTraffic gets the TrafficContent results of each of the analysis's network vectors and returns them as a merged TrafficContent.
func (a *Analysis) MergedTraffic() (TrafficContent, error) {
result := newTrafficContent()
for _, v := range a.NetworkVectors {
if t := v.Traffic; t != nil {
mergedTrafficContent, err := result.Merge(*t)
if err != nil {
return TrafficContent{}, err
}
result = mergedTrafficContent
}
}
return result, nil
}
// MergedReturnTraffic gets the return TrafficContent results of each of the analysis's network vectors and returns them as a merged TrafficContent.
func (a *Analysis) MergedReturnTraffic() (TrafficContent, error) {
result := newTrafficContent()
for _, v := range a.NetworkVectors {
if t := v.ReturnTraffic; t != nil {
mergedTrafficContent, err := result.Merge(*t)
if err != nil {
return TrafficContent{}, err
}
result = mergedTrafficContent
}
}
return result, nil
}
// PassesAssertReachable determines if the analysis implies the source can reach the destination over at least one protocol whose return path is unobstructed.
func (a Analysis) PassesAssertReachable() bool {
forwardTrafficCanReach := false
// For each vector, see if there is an obstructed path
for _, vector := range a.NetworkVectors {
if !vector.Traffic.None() {
forwardTrafficCanReach = true
for _, p := range vector.Traffic.Protocols() {
// is return path obstructed (at all) for this protocol?
if protocolReturnTraffic := vector.ReturnTraffic.protocol(p); !protocolReturnTraffic.complete() {
return false
}
}
}
}
if !forwardTrafficCanReach {
return false
}
return true
}
// PassesAssertNotReachable determines if the analysis implies the source has no way to send network traffic to the destination.
func (a Analysis) PassesAssertNotReachable() bool {
// Here, we want to be more careful / conservative. If any traffic can get out to destination, fail, regardless of return traffic.
forwardTraffic, err := a.MergedTraffic()
if err != nil {
return false
}
if !forwardTraffic.None() {
return false
}
return true
}