about summary refs log tree commit diff
path: root/src/docker.go
blob: 79cf67d1a7c3ff9654c3ba5bff816b90b26e710d (plain)
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
}