about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authormaride <maride@darknebu.la>2018-08-23 11:46:23 +0200
committermaride <maride@darknebu.la>2018-08-23 11:46:23 +0200
commit8b65f91699cd474563c0abacc726a3d47961a78f (patch)
tree5d811fe2e5b0ddc7ecafdb9c1ee0343d91fa768e /src
parent82c922d557f6628043ab771cdf10e4da9546347d (diff)
Add VPN container and access
Diffstat (limited to 'src')
-rw-r--r--src/access.go111
-rw-r--r--src/container.go40
-rw-r--r--src/docker.go25
-rw-r--r--src/http.go39
-rw-r--r--src/main.go4
5 files changed, 197 insertions, 22 deletions
diff --git a/src/access.go b/src/access.go
new file mode 100644
index 0000000..6072025
--- /dev/null
+++ b/src/access.go
@@ -0,0 +1,111 @@
+package main
+
+import (
+	"github.com/docker/docker/api/types/container"
+	"github.com/docker/docker/api/types"
+	"time"
+	"errors"
+	"net/http"
+	"fmt"
+	"github.com/docker/docker/api/types/network"
+)
+
+var vpnContainerID string
+var vpnNetworkID string
+
+func startVPN() (err error) {
+	// Set up our context and Docker CLI connection
+	setupContext()
+	setupDockerCLI()
+	// Set up network
+	setupNetwork()
+
+	// Create container
+	resp, err := dockerCli.ContainerCreate(dockerCtx, &container.Config{
+		Image: "circus-vpn",
+	}, &container.HostConfig{
+		Privileged: true,
+	}, &network.NetworkingConfig{
+		EndpointsConfig: map[string]*network.EndpointSettings{
+			"endpoint": {
+				NetworkID: vpnNetworkID,
+			},
+		},
+	}, "")
+
+	if err != nil {
+		return err
+	}
+
+	// Start container
+	err = dockerCli.ContainerStart(dockerCtx, resp.ID, types.ContainerStartOptions{})
+	if err != nil {
+		return err
+	}
+
+	vpnContainerID = resp.ID
+
+	return nil
+}
+
+func stopVPN() {
+	setupContext()
+	setupDockerCLI()
+
+	timeout := time.Second * 5
+	dockerCli.ContainerStop(dockerCtx, vpnContainerID, &timeout)
+
+	vpnContainerID = ""
+}
+
+func setupNetwork() (error) {
+	setupContext()
+	setupDockerCLI()
+
+	if vpnNetworkID == "" {
+		response, err := dockerCli.NetworkCreate(dockerCtx, VPNNetworkName, types.NetworkCreate{
+			Internal: true,
+		})
+
+		if err != nil {
+			return err
+		}
+
+		vpnNetworkID = response.ID
+	}
+
+	return nil
+}
+
+func getCertificate() (string, error) {
+	if vpnContainerID == "" {
+		return "", errors.New("VPN container not up")
+	}
+
+	// Get IP of VPN container
+	inspectJSON, err := dockerCli.ContainerInspect(dockerCtx, vpnContainerID)
+	if err != nil {
+		return "", err
+	}
+
+	// get certificate
+	var certResponse *http.Response
+
+	for i := 0; i < 10; i++ {
+		certResponse, err = http.Get(fmt.Sprintf("http://%s:9999/", inspectJSON.NetworkSettings.Networks[VPNNetworkName].IPAddress))
+
+		if err == nil {
+			break
+		}
+		time.Sleep(time.Second)
+	}
+
+	if err != nil {
+		return "", err
+	}
+
+	buffer := make([]byte, 1024)
+	certResponse.Body.Read(buffer)
+
+	return string(buffer), nil
+}
diff --git a/src/container.go b/src/container.go
index 73912bf..5b2075b 100644
--- a/src/container.go
+++ b/src/container.go
@@ -1,12 +1,15 @@
 package main
 
 import (
-	"context"
-	"github.com/docker/docker/client"
 	"github.com/docker/docker/api/types/container"
 	"github.com/docker/docker/api/types"
 	"fmt"
 	"time"
+	"github.com/docker/docker/api/types/network"
+)
+
+const (
+	VPNNetworkName = "vpn-network"
 )
 
 type ChallengeContainer struct {
@@ -15,33 +18,26 @@ type ChallengeContainer struct {
 	IP string
 }
 
-var (
-	dockerCtx context.Context
-	dockerCli *client.Client
-)
-
 // Starts the container and returns its address and containerID if successful
 func (cc ChallengeContainer) startContainer() (address string, containerID string, err error) {
-	// Set up our context if there is none already set up
-	if dockerCtx == nil {
-		dockerCtx = context.Background()
-	}
-
-	// Set up our Docker CLI connection if there is not already one
-	if dockerCli == nil {
-		dockerCli, err = client.NewEnvClient()
-
-		if err != nil {
-			return "", "", err
-		}
-	}
+	// Set up our context and Docker CLI connection
+	setupContext()
+	setupDockerCLI()
+	// Set up network
+	setupNetwork()
 
 	// Create container
 	resp, err := dockerCli.ContainerCreate(dockerCtx, &container.Config{
 		Image: cc.Challenge.Container,
 		Env: []string{fmt.Sprintf("FLAG=%s", cc.Challenge.Flag)},
 		Tty: false,
-	}, nil, nil, "")
+	}, nil, &network.NetworkingConfig{
+		EndpointsConfig: map[string]*network.EndpointSettings{
+			VPNNetworkName: {
+				NetworkID: vpnNetworkID,
+			},
+		},
+	}, "")
 
 	if err != nil {
 		return "", "", err
@@ -60,7 +56,7 @@ func (cc ChallengeContainer) startContainer() (address string, containerID strin
 	}
 
 	// Return IP, Container ID and error
-	return inspectJSON.NetworkSettings.IPAddress, resp.ID,nil
+	return inspectJSON.NetworkSettings.Networks[VPNNetworkName].IPAddress, resp.ID,nil
 }
 
 // Stops the container with a timeout of one second
diff --git a/src/docker.go b/src/docker.go
new file mode 100644
index 0000000..9bc667b
--- /dev/null
+++ b/src/docker.go
@@ -0,0 +1,25 @@
+package main
+
+import (
+	"github.com/docker/docker/client"
+	"context"
+)
+
+var (
+	dockerCtx context.Context
+	dockerCli *client.Client
+)
+
+func setupContext() {
+	if dockerCtx == nil {
+		dockerCtx = context.Background()
+	}
+}
+
+func setupDockerCLI() (err error) {
+	if dockerCli == nil {
+		dockerCli, err = client.NewEnvClient()
+	}
+
+	return err
+}
\ No newline at end of file
diff --git a/src/http.go b/src/http.go
index 287004f..c7ad213 100644
--- a/src/http.go
+++ b/src/http.go
@@ -30,10 +30,12 @@ func runHTTPServer() (error) {
 	r.HandleFunc("/login", loginPostHandler).Methods("POST")
 	r.HandleFunc("/logout", logoutHandler).Methods("POST")
 	r.HandleFunc("/challenges", challengesHandler).Methods("GET")
+	r.HandleFunc("/access", accessHandler).Methods("GET")
 	r.HandleFunc("/api/getChallenges", getChallengesHandler).Methods("GET")
 	r.HandleFunc("/api/submitFlag", submitFlagHandler).Methods("POST")
 	r.HandleFunc("/api/startContainer", startContainerHandler).Methods("POST")
 	r.HandleFunc("/api/stopContainer", stopContainerHandler).Methods("POST")
+	r.HandleFunc("/api/getAccess", getAccessHandler).Methods("GET")
 
 	address := fmt.Sprintf(":%d", *port)
 	return http.ListenAndServe(address, r)
@@ -163,6 +165,19 @@ func challengesHandler(w http.ResponseWriter, r *http.Request) {
 	}
 }
 
+// Host the access file
+func accessHandler(w http.ResponseWriter, r *http.Request) {
+	session, cookieNotFoundError := r.Cookie("session")
+
+	if cookieNotFoundError != nil || !isValidSession(session.Value) {
+		// either no session cookie found, or it contains an invalid session token. Redirect.
+		http.Redirect(w, r, "/login", http.StatusTemporaryRedirect)
+	} else {
+		// valid session token found, redirect to frontpage
+		readFileToResponse(w, "/access.html")
+	}
+}
+
 func getChallengesHandler(w http.ResponseWriter, r *http.Request) {
 	session, cookieNotFoundError := r.Cookie("session")
 
@@ -282,3 +297,27 @@ func stopContainerHandler(w http.ResponseWriter, r *http.Request) {
 		stopChallengeContainer(challengeName)
 	}
 }
+
+// Returns the configuration for the VPN
+func getAccessHandler(w http.ResponseWriter, r *http.Request) {
+	session, cookieNotFoundError := r.Cookie("session")
+
+	if cookieNotFoundError != nil || !isValidSession(session.Value) {
+		// either no session cookie found, or it contains an invalid session token. Redirect.
+		http.Redirect(w, r, "/login", http.StatusTemporaryRedirect)
+	} else {
+		// valid session token found, get credentials
+		credentials, err := getCertificate()
+		errorString := ""
+
+		if err != nil {
+			errorString = err.Error()
+		}
+
+		jsonAnswer, _ := json.Marshal(map[string]string{
+			"error": errorString,
+			"credentials": credentials,
+		})
+		w.Write([]byte(jsonAnswer))
+	}
+}
diff --git a/src/main.go b/src/main.go
index 9885957..a06ee66 100644
--- a/src/main.go
+++ b/src/main.go
@@ -16,6 +16,10 @@ func main() {
 	// Read challenges from file
 	getChallengesFromSeedFile()
 
+	// Start our VPN container and network
+	startVPN()
+	defer stopVPN()
+
 	// Run HTTP server
 	log.Fatalln(runHTTPServer())
 }
\ No newline at end of file