about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authormaride <maride@darknebu.la>2018-09-04 11:09:04 +0200
committermaride <maride@darknebu.la>2018-09-04 11:09:04 +0200
commite7be7b3a847beddccc324067de6b0bfa24b3ef12 (patch)
treebfc40755646b473a4b3081dd5c6c46ac221a8a78 /src
parent82c922d557f6628043ab771cdf10e4da9546347d (diff)
parenta46cb83df474e5f9c9be35a0f4543f85bf9f03ee (diff)
Merge branch 'access'
Diffstat (limited to 'src')
-rw-r--r--src/access.go176
-rw-r--r--src/container.go44
-rw-r--r--src/docker.go25
-rw-r--r--src/http.go39
-rw-r--r--src/main.go5
5 files changed, 267 insertions, 22 deletions
diff --git a/src/access.go b/src/access.go
new file mode 100644
index 0000000..6f9cd73
--- /dev/null
+++ b/src/access.go
@@ -0,0 +1,176 @@
+package main
+
+import (
+	"bytes"
+	"errors"
+	"flag"
+	"fmt"
+	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/container"
+	"github.com/docker/docker/api/types/network"
+	"github.com/docker/go-connections/nat"
+	"net/http"
+	"time"
+)
+
+const(
+	vpnHostNetworkName = "vpnhostnet"
+)
+
+var vpnContainerID string
+var vpnNetworkID string
+var vpnHostNetworkID string
+var remoteAddress* string
+var remotePort* int
+
+func registerAccessFlags() {
+	remoteAddress = flag.String("vpnRemoteAddress", "", "The remote domain name or IP the VPN will run on")
+	remotePort = flag.Int("vpnRemotePort", 1194, "The port the VPN should listen on")
+}
+
+func startVPN() (err error) {
+	// Set up our context and Docker CLI connection
+	setupContext()
+	setupDockerCLI()
+	// Set up network
+	err = setupNetwork()
+
+	if(err != nil) {
+		return err
+	}
+
+	err = setupVPNHostNetwork()
+
+	if err != nil {
+		return err
+	}
+
+	// Create container
+	resp, err := dockerCli.ContainerCreate(dockerCtx, &container.Config{
+		Image: "circus-vpn",
+		Env: []string{
+			fmt.Sprintf("remoteAddress=%s", *remoteAddress),
+			fmt.Sprintf("remotePort=%d", *remotePort),
+		},
+		ExposedPorts: map[nat.Port]struct{}{
+			"1194/udp": {},
+		},
+	}, &container.HostConfig{
+		Privileged: true,
+		PortBindings: nat.PortMap{
+			"1194/udp": []nat.PortBinding{
+				{
+					HostIP: "0.0.0.0",
+					HostPort: "1194",
+				},
+			},
+		},
+	}, &network.NetworkingConfig{
+		EndpointsConfig: map[string]*network.EndpointSettings{
+			"startpoint": {
+				NetworkID: vpnHostNetworkID,
+			},
+		},
+	}, "")
+
+	if err != nil {
+		return err
+	}
+
+	// Attach container network to VPN container
+	err = dockerCli.NetworkConnect(dockerCtx, vpnNetworkID, resp.ID, &network.EndpointSettings{})
+	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 setupVPNHostNetwork() (error) {
+	setupContext()
+	setupDockerCLI()
+
+	if vpnHostNetworkID == "" {
+		response, err := dockerCli.NetworkCreate(dockerCtx, vpnHostNetworkName, types.NetworkCreate{
+			Internal: false,
+		})
+
+		if err != nil {
+			return err
+		}
+
+		vpnHostNetworkID = 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(bytes.Trim(buffer, "\x00")), nil
+}
diff --git a/src/container.go b/src/container.go
index 73912bf..c9a918f 100644
--- a/src/container.go
+++ b/src/container.go
@@ -1,39 +1,33 @@
 package main
 
 import (
-	"context"
-	"github.com/docker/docker/client"
-	"github.com/docker/docker/api/types/container"
-	"github.com/docker/docker/api/types"
 	"fmt"
+	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/api/types/container"
+	"github.com/docker/docker/api/types/network"
 	"time"
 )
 
+const (
+	VPNNetworkName = "circus-vpnnet"
+)
+
 type ChallengeContainer struct {
 	Challenge *Challenge
 	ContainerID string
 	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 context and Docker CLI connection
+	setupContext()
+	setupDockerCLI()
+	// Set up network
+	err = setupNetwork()
 
-	// Set up our Docker CLI connection if there is not already one
-	if dockerCli == nil {
-		dockerCli, err = client.NewEnvClient()
-
-		if err != nil {
-			return "", "", err
-		}
+	if err != nil {
+		return "", "", err
 	}
 
 	// Create container
@@ -41,7 +35,13 @@ func (cc ChallengeContainer) startContainer() (address string, containerID strin
 		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 +60,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..ae50632 100644
--- a/src/main.go
+++ b/src/main.go
@@ -11,11 +11,16 @@ func main() {
 	registerSessionFlags()
 	registerCredentialsFlags()
 	registerSeedFlags()
+	registerAccessFlags()
 	flag.Parse()
 
 	// 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