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
|
package main
import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"strings"
"github.com/docker/docker/api/types"
"github.com/docker/docker/client"
)
const (
fixedDockerVersion = "1.38"
)
var (
dockerCtx context.Context
dockerCLI *client.Client
// store the amount of flags each user has found
userScore map[string]int
users []string // list of users
)
// Statistics stores companion statistics
type Statistics struct {
Challenges []struct {
Name string `json:"name"`
FoundFlag int64 `json:"foundFlag"`
FlagTries uint `json:"flagTries"`
} `json:"challenges"`
User string `json:"user"`
Score int `json:"score"`
}
func setupContext() {
if dockerCtx == nil {
dockerCtx = context.Background()
}
}
func setupDockerCLI() (err error) {
os.Setenv("DOCKER_API_VERSION", "1.27")
if dockerCLI == nil {
dockerCLI, err = client.NewEnvClient()
}
return err
}
func listDockerContainers() {
log.Println("listing the docker containers...")
// setup the context and the docker cli connection
setupContext()
setupDockerCLI()
// get a list of all networks
networks, err := dockerCLI.NetworkList(context.Background(), types.NetworkListOptions{})
if err != nil {
panic(err)
}
// get a list of all containers
containers, err := dockerCLI.ContainerList(context.Background(), types.ContainerListOptions{})
if err != nil {
panic(err)
}
// find the container names of the companion containers by iterating over
// all containers adding the containers containing the string "companion" in
// their names to the list of companion containers
var companionContainerNames []string
for _, container := range containers {
if strings.Contains(container.Image, "companion") {
companionContainerNames = append(companionContainerNames, container.Names[0][1:])
}
}
fmt.Printf("%#v\n\n", companionContainerNames)
// find the IPs of the companion containers by iterating over all networks,
// then iterating over all containers in the network and then testing if the
// container is part of the previously generated companion-containers-list.
var companionContainerIPs []string
for _, network := range networks {
if network.Name == "circus" {
for _, container := range network.Containers {
for _, name := range companionContainerNames {
if container.Name == name {
companionContainerIPs = append(companionContainerIPs, container.IPv4Address)
}
}
}
}
}
// print all ips found
for _, rawip := range companionContainerIPs {
// if the ip starts with 172, it's the right one!
if strings.Compare(rawip[0:3], "172") == 0 {
// strip the "/16" or so suffix (this might break, see the todo
// below...)
// TODO: strip everything after the slash and the slash
ip := rawip[:len(rawip)-3]
fmt.Printf("ip: %s\n\n", ip)
// get the stats from the container
statsJSON, err := getStats(ip, 8080)
if err != nil {
fmt.Println(err)
}
// unmarshal the json statistics into a golang struct
var statsGoStruct Statistics
err = json.Unmarshal([]byte(statsJSON), &statsGoStruct)
if err != nil {
fmt.Println("error: ", err)
}
// if the user is not in the users list, add the user to the users list
present := false
for _, user := range users {
if user == statsGoStruct.User {
present = true
}
}
if present == false {
users = append(users, statsGoStruct.User)
}
if userScore == nil {
userScore = make(map[string]int)
}
// update the score if the individual user
userScore[statsGoStruct.User] = statsGoStruct.Score
}
}
}
// getStats makes an http request to the container with the given ip and port
// returning the result of the request to the /api/getStats endpoint
func getStats(containerName string, containerPort uint16) (string, error) {
// define the url where the request should go
url := fmt.Sprintf("http://%s:%d/api/getStats", containerName, containerPort)
log.Printf("url: %s", url)
// make the request
resp, err := http.Get(url)
if err != nil {
return "", fmt.Errorf("could not make the http get request: %v", err)
}
defer resp.Body.Close()
// read the response body
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", fmt.Errorf("could not read the request body: %v", err)
}
// returns the stats
return string(body), nil
}
|