# twingate
Awesome zero-trust VPN that several of our clients have.  We're fans.

## Generate/install connector for a Proxmox LXC container
For our pentest dropboxes, we love using the [twingate-connector LXC](https://community-scripts.github.io/ProxmoxVE/scripts?id=twingate-connector).  

1. Run the install script (from Proxmox GUI, *not* SSH console).
2. From the Twingate admin console, click **Remote Networks > (click your remote network)** and under *Connectors* click **Add Connector**.
3. Click the connector (rename it if you want).
4. Under *Select a Deployment Method*, click **Proxmox** and then copy/paste the appropriate tokens into the LXC install.
5. Make sure for the network name, you choose a network name that is configured under `Network > Remote Networks`.

## Edit/refresh tokens
The tokens are stored here:
```
/etc/twingate/connector.conf
```

## Uninstall a twingate connector
```
sudo apt purge twingate-connector
```

## Uninstall a twingate *docker* connector
Get the image name (look under the *NAMES* column):

```
sudo docker ps -a
```

Stop it:
```
sudo docker rm twingate-unique-name-goes-here
```

Remove it:

```
sudo docker rm twingate-unique-name-goes-here
```

## Update twingate connector
```
sudo apt update
sudo apt install -yq twingate-connector
sudo systemctl restart twingate-connector
```

Check that the version got updated:

```
twingate-connector -V
```

*More info on the update process [here](https://www.twingate.com/docs/systemd-service)*

## Troubleshooting connectivity
If your twingate connector isn't phoning home, check out [this page](https://www.twingate.com/docs/connector-failures).

See what's happening in the logs:

```
journalctl -u twingate-connector -f
```

### Turn logging up
If the logs are kind of boring, [this page](https://help.twingate.com/hc/en-us/articles/4901034540189-Twingate-Connector-Logs/) well help you turn logging up to 11 (well, actually...*7*):

```
nano /etc/twingate/connector.conf

# Add this line:
echo "TWINGATE_LOG_LEVEL=7" | sudo tee -a /etc/twingate/connector.conf
```

Restart connector:

```
sudo systemctl restart twingate-connector
```

If things still aren't happy, review the [firewall logs](https://www.twingate.com/docs/firewall-failures).

## Scanning with nmap and other tools through the Twingate connector
After working with Twingate a while, I discovered that if you're connected via the VPN and try to nmap-scan a customer's network that is shared out as a resource via Twingate, the scan won't work.  [Here is why](https://help.twingate.com/articles/4186450837-tcp-ip-port-tests-or-scans-produce-inaccurate-results).  Basically this article recommends you do an application-level scan of endpoints to figure out what is truly open.

When I deploy a NUC into a customer environment and let's say only the Twingate connector checks in with IP `192.168.1.7`, I use a script like this to specify `192.168.1.0/24` and which ports I want to look for (like port `8006` for my Proxmox box):

```
#!/bin/bash

# Prompt for CIDR and ports
read -p "Enter target subnet in CIDR notation (e.g. 10.0.20.0/24): " cidr
read -p "Enter port(s) to scan, space-separated (e.g. 8006 443 22): " ports_input

# Parse CIDR
IFS='/' read -ra parts <<< "$cidr"
base_ip="${parts[0]}"
prefix="${parts[1]}"

# Parse octets
IFS='.' read -ra octets <<< "$base_ip"
IFS=' ' read -ra ports <<< "$ports_input"

# Scan functions
scan_range() {
  local sub=$1
  for i in $(seq 1 254); do
    ip="${sub}.$i"
    (
      if ping -c 1 -W 1 $ip &>/dev/null 2>&1 || \
         curl -sk --max-time 1 https://$ip -o /dev/null 2>/dev/null || \
         curl -sk --max-time 1 http://$ip -o /dev/null 2>/dev/null; then
        echo "ALIVE $ip"
      fi
    ) &
  done
}

scan_ports() {
  local sub=$1
  for i in $(seq 1 254); do
    ip="${sub}.$i"
    (
      hits=()
      for port in "${ports[@]}"; do
        result=$(curl -sk --max-time 2 https://$ip:$port -o /dev/null -w "%{http_code}" 2>/dev/null)
        if [ "$result" == "000" ]; then
          result=$(curl -sk --max-time 2 http://$ip:$port -o /dev/null -w "%{http_code}" 2>/dev/null)
        fi
        if [ "$result" != "000" ]; then
          hits+=("port $port (HTTP $result)")
        fi
      done
      if [ ${#hits[@]} -gt 0 ]; then
        echo "OPEN $ip => ${hits[*]}"
      fi
    ) &
  done
}

# Determine subnets to scan based on prefix
base="${octets[0]}.${octets[1]}"
third="${octets[2]}"

if [ "$prefix" -eq 24 ]; then
  subnets=("${base}.${third}")
elif [ "$prefix" -eq 23 ]; then
  subnets=("${base}.${third}" "${base}.$((third + 1))")
elif [ "$prefix" -eq 22 ]; then
  subnets=("${base}.${third}" "${base}.$((third + 1))" "${base}.$((third + 2))" "${base}.$((third + 3))")
else
  echo "Supported prefixes: /22, /23, /24"
  exit 1
fi

echo ""
echo "=== Phase 1: Finding live hosts on ${cidr} ==="
for sub in "${subnets[@]}"; do
  scan_range "$sub"
done
wait

echo ""
echo "=== Phase 2: Checking ports [${ports[*]}] on ${cidr} ==="
for sub in "${subnets[@]}"; do
  scan_ports "$sub"
done
wait
```
