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 }