diff --git a/.gitignore b/.gitignore
index 7f7476169986078971aef995fd16883f6c7afa55..ba7f950e18c75f5fbed00dde0a0564d2509a67f1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,3 @@
-bitmaskcfg
 *.swp
 *.swo
+./bitmaskcfg
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/cmd/bitmaskcfg/cmd/genConfig.go b/cmd/bitmaskcfg/cmd/genConfig.go
new file mode 100644
index 0000000000000000000000000000000000000000..beb47d0587176a85776a635b10ec2ded600940ef
--- /dev/null
+++ b/cmd/bitmaskcfg/cmd/genConfig.go
@@ -0,0 +1,116 @@
+/*
+Copyright © 2023 NAME HERE <EMAIL ADDRESS>
+*/
+package cmd
+
+import (
+	"flag"
+	"fmt"
+	"log"
+	"os"
+	"path/filepath"
+	"time"
+
+	"0xacab.org/leap/bitmask-core/pkg/bootstrap"
+	"github.com/spf13/cobra"
+	"github.com/spf13/pflag"
+	"github.com/spf13/viper"
+)
+
+var (
+	appName string = filepath.Base(os.Args[0])
+)
+
+// genConfigCmd represents the genConfig command
+var genConfigCmd = &cobra.Command{
+	Use:   "gen-config",
+	Short: "Generate a working configuration",
+	Long: `A longer description that spans multiple lines and likely contains examples
+and usage of using your command. For example:
+
+Blah blah.`,
+	Run: func(cmd *cobra.Command, args []string) {
+		generateOpenVPNConfig()
+	},
+}
+
+func init() {
+	flag.String(host, "", "Host serving menshen API")
+	flag.String(proxy, "", "Proxy (SOCKS5)")
+
+	flag.String(transport, "", "Filter gateway/bridges by transport (TCP/UDP)")
+	flag.String(port, "", "Filter gateway/bridges listening on this port")
+	flag.String(location, "", "Filter by location")
+	flag.String(introducerStr, "", "Use an obfuscated introducer")
+
+	pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
+	pflag.Parse()
+	viper.BindPFlags(pflag.CommandLine)
+
+	rootCmd.AddCommand(genConfigCmd)
+
+	// Here you will define your flags and configuration settings.
+
+	// Cobra supports Persistent Flags which will work for this command
+	// and all subcommands, e.g.:
+	// genConfigCmd.PersistentFlags().String("foo", "", "A help for foo")
+
+	// Cobra supports local flags which will only run when this command
+	// is called directly, e.g.:
+	// genConfigCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
+}
+
+func generateOpenVPNConfig() {
+	location := viper.GetString(location)
+	port := viper.GetString(port)
+	transport = viper.GetString(transport)
+
+	host := viper.GetString(host)
+	proxy := viper.GetString(proxy)
+
+	cfg := bootstrap.NewConfig()
+	cfg.Host = host
+	cfg.Proxy = proxy
+
+	if proxy != "" {
+		fmt.Println("using socks5:", proxy)
+	}
+
+	start := time.Now()
+
+	api := bootstrap.NewAPI(cfg)
+
+	// begin by attempting to geolocate our base network (CC)
+	api.DoGeolocationLookup()
+
+	// attempt to fetch service
+	if err := api.FetchService(); err != nil {
+		log.Fatal(err)
+	}
+
+	// request gateways
+	if location != "" || port != "" || transport != "" {
+		params := &bootstrap.GatewayParams{}
+		params.Location = location
+		params.Port = port
+		params.Transport = transport
+		if err := api.FetchAllGateways(params); err != nil {
+			log.Fatal(err)
+		}
+	} else {
+
+		if err := api.FetchAllGateways(nil); err != nil {
+			log.Fatal(err)
+		}
+	}
+	if err := api.FetchOpenVPNCert(); err != nil {
+		log.Fatal(err)
+	}
+	elapsed := time.Since(start)
+	log.Printf("bootstrap ok (took %s)\n", elapsed.Round(time.Second).String())
+	vpnCfg, err := api.SerializeConfig()
+	if err != nil {
+		log.Fatal(err)
+	}
+	fmt.Printf("%s\n", vpnCfg)
+}
diff --git a/cmd/bitmaskcfg/cmd/introducer.go b/cmd/bitmaskcfg/cmd/introducer.go
new file mode 100644
index 0000000000000000000000000000000000000000..070244333e7cc100ffbc8db5c3cafad72e2d9832
--- /dev/null
+++ b/cmd/bitmaskcfg/cmd/introducer.go
@@ -0,0 +1,65 @@
+/*
+Copyright © 2023 NAME HERE <EMAIL ADDRESS>
+*/
+package cmd
+
+import (
+	"fmt"
+	"log"
+	"os"
+
+	"0xacab.org/leap/bitmask-core/pkg/introducer"
+	qrcode "github.com/skip2/go-qrcode"
+	"github.com/spf13/cobra"
+)
+
+// introducerCmd represents the introducer command
+var introducerCmd = &cobra.Command{
+	Use:   "introducer",
+	Short: "A brief description of your command",
+	Long: `A longer description that spans multiple lines and likely contains examples
+and usage of using your command. For example:
+
+Cobra is a CLI library for Go that empowers applications.
+This application is a tool to generate the needed files
+to quickly create a Cobra application.`,
+	Run: func(cmd *cobra.Command, args []string) {
+		genQRForIntroducer(args)
+	},
+}
+
+func init() {
+	rootCmd.AddCommand(introducerCmd)
+	// introducerCmd.PersistentFlags().String("qrgen", "", "Generate a QR for this introducer")
+
+	// Here you will define your flags and configuration settings.
+
+	// Cobra supports Persistent Flags which will work for this command
+	// and all subcommands, e.g.:
+	// introducerCmd.PersistentFlags().String("foo", "", "A help for foo")
+
+	// Cobra supports local flags which will only run when this command
+	// is called directly, e.g.:
+	// introducerCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
+}
+
+func genQRForIntroducer(args []string) {
+	if len(args) != 1 {
+		fmt.Println("bitmaskcfg introducer <URL>")
+		os.Exit(1)
+	}
+	url := args[0]
+	_, err := introducer.NewIntroducerFromURL(url)
+	if err != nil {
+		log.Fatalf("not a valid introducer: %v", err)
+	}
+	qrCode, err := qrcode.New(url, qrcode.Medium)
+	if err != nil {
+		log.Fatalf("Could not generate QR code: %v", err)
+	}
+	fmt.Println()
+	fmt.Println("You can share the introducer with this QR code")
+	fmt.Println()
+	fmt.Println(qrCode.ToSmallString(false))
+	// TODO export to PNG too
+}
diff --git a/cmd/bitmaskcfg/cmd/locations.go b/cmd/bitmaskcfg/cmd/locations.go
new file mode 100644
index 0000000000000000000000000000000000000000..8cf533a1c44f15f747eeaf9feb540e709745093c
--- /dev/null
+++ b/cmd/bitmaskcfg/cmd/locations.go
@@ -0,0 +1,51 @@
+/*
+Copyright © 2023 atanarjuat <atanarjuat@riseup.net>
+*/
+package cmd
+
+import (
+	"fmt"
+	"log"
+
+	"0xacab.org/leap/bitmask-core/pkg/bootstrap"
+	"github.com/spf13/cobra"
+	"github.com/spf13/viper"
+)
+
+// locationsCmd represents the locations command
+var locationsCmd = &cobra.Command{
+	Use:   "locations",
+	Short: "List all known locations",
+	Long:  `Fetches a list of all the locations from the given host.`,
+	Run: func(cmd *cobra.Command, args []string) {
+		locations := getLocationList()
+		for idx, loc := range locations {
+			fmt.Printf("%d. %s\n", idx+1, loc)
+		}
+	},
+}
+
+func init() {
+	rootCmd.AddCommand(locationsCmd)
+}
+
+func getLocationList() []string {
+	host := viper.GetString(host)
+	introducer := viper.GetString(introducerStr)
+
+	cfg := bootstrap.NewConfig()
+	cfg.Host = host
+	cfg.Introducer = introducer
+
+	api := bootstrap.NewAPI(cfg)
+	if err := api.FetchService(); err != nil {
+		log.Fatal(err)
+	}
+	locationMap := api.Locations().(map[string]any)
+
+	locations := []string{}
+	for locname := range locationMap {
+		locations = append(locations, locname)
+	}
+	return locations
+}
diff --git a/cmd/bitmaskcfg/cmd/pick.go b/cmd/bitmaskcfg/cmd/pick.go
new file mode 100644
index 0000000000000000000000000000000000000000..322b3361dca040be70e920b5717b071b10925556
--- /dev/null
+++ b/cmd/bitmaskcfg/cmd/pick.go
@@ -0,0 +1,93 @@
+/*
+Copyright © 2023 NAME HERE <EMAIL ADDRESS>
+*/
+package cmd
+
+import (
+	"fmt"
+	"log"
+
+	"0xacab.org/leap/bitmask-core/pkg/bootstrap"
+	"0xacab.org/leap/bitmask-core/pkg/latency"
+	"github.com/spf13/cobra"
+	"github.com/spf13/viper"
+)
+
+// pickCmd represents the pick command
+var pickCmd = &cobra.Command{
+	Use:   "pick",
+	Short: "Pick the best location",
+	Long: `Perform a short comprobation (ICMP ping) and return the location that seems closer 
+to us in terms of latency.`,
+	Run: func(cmd *cobra.Command, args []string) {
+		fmt.Println("Picking best location...")
+		candidates := getGatewayForEachLocation()
+		best := pickBest(candidates)
+		for l, ipaddr := range candidates {
+			if best == ipaddr {
+				fmt.Printf("best: %s (%s)\n", l, best)
+				break
+			}
+		}
+	},
+}
+
+type loc string
+type ip string
+
+// getGatewayForEachLocation will call FetchAllGateways, and return one gateway
+// for each location. No error handling is done, no randomization, and the order
+// is always the first gateway found.
+func getGatewayForEachLocation() map[loc]ip {
+	ips := make(map[loc]ip)
+
+	host := viper.GetString(host)
+	cfg := bootstrap.NewConfig()
+	cfg.Host = host
+
+	api := bootstrap.NewAPI(cfg)
+	if err := api.FetchService(); err != nil {
+		log.Fatal(err)
+	}
+	param := &bootstrap.GatewayParams{
+		Transport: "udp",
+		Port:      "1194",
+	}
+	if err := api.FetchAllGateways(param); err != nil {
+		log.Fatal(err)
+	}
+	locationMap := api.Locations().(map[string]any)
+
+	for locname := range locationMap {
+		gateways, _ := api.GatewaysForLocation(locname)
+		//  picking the first one - we probably want to randomize,
+		// or ensure we're not testing an unhealthy or overloaded endpoint.
+		ips[loc(locname)] = ip(gateways[0].IPAddr)
+	}
+	return ips
+}
+
+// pickBest will select the best endpoint by the lower latency.
+func pickBest(candidates map[loc]ip) ip {
+	endpoints := []string{}
+	for _, ipaddr := range candidates {
+		endpoints = append(endpoints, string(ipaddr))
+	}
+
+	best := latency.PickBestEndpointByLatency(endpoints)
+	return ip(best)
+}
+
+func init() {
+	rootCmd.AddCommand(pickCmd)
+
+	// Here you will define your flags and configuration settings.
+
+	// Cobra supports Persistent Flags which will work for this command
+	// and all subcommands, e.g.:
+	// pickCmd.PersistentFlags().String("foo", "", "A help for foo")
+
+	// Cobra supports local flags which will only run when this command
+	// is called directly, e.g.:
+	// pickCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
+}
diff --git a/cmd/bitmaskcfg/cmd/root.go b/cmd/bitmaskcfg/cmd/root.go
new file mode 100644
index 0000000000000000000000000000000000000000..7ce2240f3b2645ef9b8c4d0e0f9840ef67349abb
--- /dev/null
+++ b/cmd/bitmaskcfg/cmd/root.go
@@ -0,0 +1,73 @@
+/*
+Copyright © Atarnajuat <atanarjuat@riseup.net>
+*/
+package cmd
+
+import (
+	"os"
+
+	"github.com/spf13/cobra"
+	"github.com/spf13/viper"
+)
+
+var (
+	// host is the variable for passing the base URL for the menshen API.
+	host = "host"
+
+	// use this socks proxy to fetch data
+	proxy = "socks5-proxy"
+
+	// introducer is an obfuscated introducer to contact the API
+	introducerStr = "introducer"
+
+	location  = "location"
+	port      = "port"
+	transport = "transport"
+
+	//cmdGen          = "gen"
+	//cmdListGateways = "list-gateways"
+)
+
+// rootCmd represents the base command when called without any subcommands
+var rootCmd = &cobra.Command{
+	Use:   "bitmaskcfg",
+	Short: "Generates working configuration for Bitmask, the LEAP VPN Client",
+	Long: `bitmaskcfg is a CLI tool to fetch a working configuration 
+from a LEAP VPN service.
+
+This application can be used to generate an openvpn config file,
+or to inspect the health of different endpoints.`,
+	// Uncomment the following line if your bare application
+	// has an action associated with it:
+	// Run: func(cmd *cobra.Command, args []string) { },
+}
+
+// Execute adds all child commands to the root command and sets flags appropriately.
+// This is called by main.main(). It only needs to happen once to the rootCmd.
+func Execute() {
+	err := rootCmd.Execute()
+	if err != nil {
+		os.Exit(1)
+	}
+}
+
+func init() {
+	viper.SetEnvPrefix("BITMASKCFG")
+	viper.AutomaticEnv()
+
+	// TODO host and proxy should be set as global (persistent?) cobra flags
+	/*
+		flag.String(host, "", "Host serving menshen API")
+		flag.String(proxy, "", "Proxy (SOCKS5)")
+		pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
+		pflag.Parse()
+		viper.BindPFlags(pflag.CommandLine)
+	*/
+
+	rootCmd.Flags().SortFlags = false
+	rootCmd.PersistentFlags().SortFlags = false
+
+	// Cobra also supports local flags, which will only run
+	// when this action is called directly.
+	// rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
+}
diff --git a/cmd/bitmaskcfg/main.go b/cmd/bitmaskcfg/main.go
new file mode 100644
index 0000000000000000000000000000000000000000..9c35ca54357ecbfc3b593d893dfa8f16a68bc62d
--- /dev/null
+++ b/cmd/bitmaskcfg/main.go
@@ -0,0 +1,10 @@
+/*
+Copyright © 2023 Atanarjuat The Fast Runner <atanarjuat@riseup.net>
+*/
+package main
+
+import "0xacab.org/leap/bitmask-core/cmd/bitmaskcfg/cmd"
+
+func main() {
+	cmd.Execute()
+}
diff --git a/go.mod b/go.mod
index 4def6f9d913f26c9e35216c9a8c9aa39887e634a..faacc91356af0e2e317d15aabfb585f25fc19926 100644
--- a/go.mod
+++ b/go.mod
@@ -12,6 +12,7 @@ require (
 	github.com/prometheus-community/pro-bing v0.3.0
 	github.com/refraction-networking/utls v1.3.3
 	github.com/sirupsen/logrus v1.4.2
+	github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
 	github.com/spf13/cobra v1.7.0
 	github.com/spf13/pflag v1.0.5
 	github.com/spf13/viper v1.16.0
diff --git a/go.sum b/go.sum
index 657818b9a978095264a7000a4ede20e0c023fe66..97b009d1b8d1320b1a4a2e6964edab029073e5c1 100644
--- a/go.sum
+++ b/go.sum
@@ -284,6 +284,8 @@ github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx
 github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
 github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
 github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
+github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
+github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
 github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM=
 github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ=
 github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA=