chore: initial commit of wgtool
This commit is contained in:
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
*.log
|
||||||
|
node_modules/
|
||||||
|
.venv/
|
||||||
10
CURRENT_WORKING/aza.conf
Normal file
10
CURRENT_WORKING/aza.conf
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
[Interface]
|
||||||
|
PrivateKey = UI7XeN/0WGCziv68Vt3hlPGYWB1dwZN7+N2C4Y2y91o=
|
||||||
|
Address = 10.8.0.2/24
|
||||||
|
|
||||||
|
# Zion (central server)
|
||||||
|
[Peer]
|
||||||
|
PublicKey = 2ztJbrN1x1NWanzPGLiKL19ZkdOhm5Y7WeKEWBT5cyg=
|
||||||
|
AllowedIPs = 10.8.0.0/24
|
||||||
|
Endpoint = ugh.im:51820
|
||||||
|
PersistentKeepalive = 60
|
||||||
81
CURRENT_WORKING/cth.conf
Normal file
81
CURRENT_WORKING/cth.conf
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
[Interface]
|
||||||
|
Address = 10.8.0.10/24
|
||||||
|
ListenPort = 53535
|
||||||
|
PrivateKey = UDr1aohdSWGMEy1F6v0GoC7JNgVHbwA8Dz//7E2xQHM=
|
||||||
|
|
||||||
|
#pix66
|
||||||
|
[Peer]
|
||||||
|
PublicKey = hguz42G5S8EV3NmkORc6eiBWb+V9Z6oBdiXVnAcqvmI=
|
||||||
|
AllowedIPs = 10.8.0.6/32
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#Cth
|
||||||
|
#[Peer]
|
||||||
|
#PublicKey = NBktXKy1s0n2lIlIMODvOqKNwAtYdoZH5feKt5P43i0=
|
||||||
|
#AllowedIPs = 10.8.0.10/32
|
||||||
|
|
||||||
|
#Aza
|
||||||
|
#[Peer]
|
||||||
|
#PublicKey = qmTKA257DLOrfhk5Zw8RyRmBSonmm6epbloT0P0ZWDc=
|
||||||
|
#AllowedIPs = 10.8.0.2/32
|
||||||
|
|
||||||
|
#Nyar
|
||||||
|
[Peer]
|
||||||
|
PublicKey = 2BA7L1oJP1tK6dIUNHMgcZmOmYmlyPRe2RaBqfUsEWo=
|
||||||
|
AllowedIPs = 10.8.0.20/32
|
||||||
|
|
||||||
|
#Galaxy
|
||||||
|
#[Peer]
|
||||||
|
#PublicKey = QBNt00VSedxPlq3ZvsdYaqIcbudCAyxv9TG65aPVZzM=
|
||||||
|
#AllowedIPs = 10.8.0.99/32
|
||||||
|
|
||||||
|
#nanocube
|
||||||
|
#[Peer]
|
||||||
|
#PublicKey = /ZImoATDIS0e0N08CD7mqWbhtGlSnynpPuY04Ed4Zyc=
|
||||||
|
#AllowedIPs = 10.8.0.7/32
|
||||||
|
|
||||||
|
#jupiter
|
||||||
|
#[Peer]
|
||||||
|
#PublicKey = YIFQ43ULk/YoCgOv3SBU6+MOrbxd+mlvaw9rT8uoNmw=
|
||||||
|
#AllowedIPs = 10.8.0.42/32
|
||||||
|
|
||||||
|
#HASS
|
||||||
|
#[Peer]
|
||||||
|
#PublicKey = C+Poz/7DaXCxe4HZiL6D5cld4jMt5o1gBq3iPiBzrg0=
|
||||||
|
#AllowedIPs = 10.8.0.8/32
|
||||||
|
|
||||||
|
#framebot
|
||||||
|
#[Peer]
|
||||||
|
#PublicKey = loS3yZapqmt6lP53Q+s4EvUzw6FmwgZC8jzgLluJ1Es=
|
||||||
|
#AllowedIPs = 10.8.0.40/32
|
||||||
|
|
||||||
|
|
||||||
|
[Peer]
|
||||||
|
PublicKey = 2ztJbrN1x1NWanzPGLiKL19ZkdOhm5Y7WeKEWBT5cyg=
|
||||||
|
AllowedIPs = 10.8.0.0/24
|
||||||
|
Endpoint = ugh.im:51820
|
||||||
|
PersistentKeepalive = 25
|
||||||
|
|
||||||
|
|
||||||
|
#[Peer]
|
||||||
|
#PublicKey = 2BA7L1oJP1tK6dIUNHMgcZmOmYmlyPRe2RaBqfUsEWo=
|
||||||
|
#AllowedIPs = 10.8.0.20/32
|
||||||
|
#PersistentKeepalive = 25
|
||||||
|
|
||||||
|
#jupiter
|
||||||
|
#[Peer]
|
||||||
|
#PublicKey = YIFQ43ULk/YoCgOv3SBU6+MOrbxd+mlvaw9rT8uoNmw=
|
||||||
|
#AllowedIPs = 10.8.0.42/32
|
||||||
|
|
||||||
|
|
||||||
|
#Galaxy
|
||||||
|
#[Peer]
|
||||||
|
#PublicKey = QBNt00VSedxPlq3ZvsdYaqIcbudCAyxv9TG65aPVZzM=
|
||||||
|
#AllowedIPs = 10.8.0.99/32
|
||||||
|
#Endpoint = galaxyspin.space:54382
|
||||||
|
#PersistentKeepalive = 25
|
||||||
16
CURRENT_WORKING/galaxy.conf
Normal file
16
CURRENT_WORKING/galaxy.conf
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
[Interface]
|
||||||
|
PrivateKey = sHEHZQ3AdUTLG56yeHdmZVuXrivB9P+40Fw0oWHF3Fg=
|
||||||
|
Address = 10.8.0.99/24
|
||||||
|
ListenPort = 54382
|
||||||
|
|
||||||
|
# Zion peer (central server) - for access to entire network
|
||||||
|
[Peer]
|
||||||
|
PublicKey = 2ztJbrN1x1NWanzPGLiKL19ZkdOhm5Y7WeKEWBT5cyg=
|
||||||
|
AllowedIPs = 10.8.0.0/24
|
||||||
|
Endpoint = ugh.im:51820
|
||||||
|
PersistentKeepalive = 25
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
25
CURRENT_WORKING/nyan.conf
Normal file
25
CURRENT_WORKING/nyan.conf
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
[Interface]
|
||||||
|
PrivateKey = sLx3sor9gxhk7T2MIS3g50wzSZBrlVUG+NlXk47jEH4=
|
||||||
|
Address = 10.8.0.20/24
|
||||||
|
|
||||||
|
# Zion peer (central server) - for access to entire network
|
||||||
|
[Peer]
|
||||||
|
PublicKey = 2ztJbrN1x1NWanzPGLiKL19ZkdOhm5Y7WeKEWBT5cyg=
|
||||||
|
AllowedIPs = 10.8.0.0/24
|
||||||
|
Endpoint = ugh.im:51820
|
||||||
|
PersistentKeepalive = 25
|
||||||
|
|
||||||
|
#CTH
|
||||||
|
[Peer]
|
||||||
|
PublicKey = NBktXKy1s0n2lIlIMODvOqKNwAtYdoZH5feKt5P43i0=
|
||||||
|
AllowedIPs = 10.8.0.10/32
|
||||||
|
Endpoint = aw2cd67.glddns.com:53535
|
||||||
|
PersistentKeepalive = 25
|
||||||
|
|
||||||
|
|
||||||
|
#Galaxy
|
||||||
|
#[Peer]
|
||||||
|
#PublicKey = QBNt00VSedxPlq3ZvsdYaqIcbudCAyxv9TG65aPVZzM=
|
||||||
|
#AllowedIPs = 10.8.0.99/32
|
||||||
|
#Endpoint = galaxyspin.space:54382
|
||||||
|
#PersistentKeepalive = 25
|
||||||
48
CURRENT_WORKING/zion.conf
Normal file
48
CURRENT_WORKING/zion.conf
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
[Interface]
|
||||||
|
Address = 10.8.0.1/24
|
||||||
|
ListenPort = 51820
|
||||||
|
PrivateKey = UJvsfv6iQPAW9Wnc81bK0o3IIHX86kGb+24dUTuGFnA=
|
||||||
|
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE; ip route add 10.8.0.0/24 dev wg0 2>/dev/null || true
|
||||||
|
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE; ip route del 10.8.0.0/24 dev wg0 2>/dev/null || true
|
||||||
|
|
||||||
|
#Cth
|
||||||
|
[Peer]
|
||||||
|
PublicKey = NBktXKy1s0n2lIlIMODvOqKNwAtYdoZH5feKt5P43i0=
|
||||||
|
AllowedIPs = 10.8.0.10/32
|
||||||
|
|
||||||
|
#Aza
|
||||||
|
[Peer]
|
||||||
|
PublicKey = qmTKA257DLOrfhk5Zw8RyRmBSonmm6epbloT0P0ZWDc=
|
||||||
|
AllowedIPs = 10.8.0.2/32
|
||||||
|
|
||||||
|
#Nyar
|
||||||
|
[Peer]
|
||||||
|
PublicKey = 2BA7L1oJP1tK6dIUNHMgcZmOmYmlyPRe2RaBqfUsEWo=
|
||||||
|
AllowedIPs = 10.8.0.20/32
|
||||||
|
|
||||||
|
#Galaxy
|
||||||
|
[Peer]
|
||||||
|
PublicKey = QBNt00VSedxPlq3ZvsdYaqIcbudCAyxv9TG65aPVZzM=
|
||||||
|
AllowedIPs = 10.8.0.99/32
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#nanocube
|
||||||
|
[Peer]
|
||||||
|
PublicKey = /ZImoATDIS0e0N08CD7mqWbhtGlSnynpPuY04Ed4Zyc=
|
||||||
|
AllowedIPs = 10.8.0.7/32
|
||||||
|
|
||||||
|
#jupiter
|
||||||
|
[Peer]
|
||||||
|
PublicKey = YIFQ43ULk/YoCgOv3SBU6+MOrbxd+mlvaw9rT8uoNmw=
|
||||||
|
AllowedIPs = 10.8.0.42/32
|
||||||
|
|
||||||
|
#HASS
|
||||||
|
[Peer]
|
||||||
|
PublicKey = C+Poz/7DaXCxe4HZiL6D5cld4jMt5o1gBq3iPiBzrg0=
|
||||||
|
AllowedIPs = 10.8.0.8/32
|
||||||
|
|
||||||
|
#framebot
|
||||||
|
[Peer]
|
||||||
|
PublicKey = loS3yZapqmt6lP53Q+s4EvUzw6FmwgZC8jzgLluJ1Es=
|
||||||
|
AllowedIPs = 10.8.0.40/32
|
||||||
360
GO_VS_BASH_ANALYSIS.md
Normal file
360
GO_VS_BASH_ANALYSIS.md
Normal file
@@ -0,0 +1,360 @@
|
|||||||
|
# Go vs Bash Implementation Analysis
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This document compares the bash implementation (`wireguard_setup.sh`) with the Go implementation (`wireguard_setup.go`) and identifies key improvements and advantages of the Go version.
|
||||||
|
|
||||||
|
## Key Improvements in Go Version
|
||||||
|
|
||||||
|
### 1. **Type Safety and Error Handling**
|
||||||
|
|
||||||
|
**Bash Version:**
|
||||||
|
```bash
|
||||||
|
# Basic string validation
|
||||||
|
if [ -z "$NODE_NAME" ]; then
|
||||||
|
print_error "Node name cannot be empty"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
```
|
||||||
|
|
||||||
|
**Go Version:**
|
||||||
|
```go
|
||||||
|
// Strong typing with structured validation
|
||||||
|
func validateHostname(hostname string) error {
|
||||||
|
if hostname == "" {
|
||||||
|
return fmt.Errorf("hostname cannot be empty")
|
||||||
|
}
|
||||||
|
if len(hostname) > 63 {
|
||||||
|
return fmt.Errorf("hostname too long (max 63 characters)")
|
||||||
|
}
|
||||||
|
hostnameRegex := regexp.MustCompile(`^[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]$|^[a-zA-Z0-9]$`)
|
||||||
|
if !hostnameRegex.MatchString(hostname) {
|
||||||
|
return fmt.Errorf("invalid hostname format. Use alphanumeric characters and hyphens only")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Advantages:**
|
||||||
|
- Compile-time error checking
|
||||||
|
- Structured error handling with context
|
||||||
|
- Type safety prevents runtime errors
|
||||||
|
- Better validation with regex patterns
|
||||||
|
|
||||||
|
### 2. **Configuration Management**
|
||||||
|
|
||||||
|
**Bash Version:**
|
||||||
|
```bash
|
||||||
|
# Hardcoded values scattered throughout
|
||||||
|
ZION_PUBLIC_KEY="2ztJbrN1x1NWanzPGLiKL19ZkdOhm5Y7WeKEWBT5cyg="
|
||||||
|
ZION_ENDPOINT="ugh.im:51820"
|
||||||
|
ZION_ALLOWED_IPS="10.8.0.0/24"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Go Version:**
|
||||||
|
```go
|
||||||
|
// Structured configuration with type safety
|
||||||
|
type ZionConfig struct {
|
||||||
|
PublicKey string `json:"public_key"`
|
||||||
|
Endpoint string `json:"endpoint"`
|
||||||
|
Peers map[string]string `json:"peers"` // name -> public_key
|
||||||
|
}
|
||||||
|
|
||||||
|
var zionConfig = ZionConfig{
|
||||||
|
PublicKey: "2ztJbrN1x1NWanzPGLiKL19ZkdOhm5Y7WeKEWBT5cyg=",
|
||||||
|
Endpoint: "ugh.im:51820",
|
||||||
|
Peers: map[string]string{
|
||||||
|
"Cth": "NBktXKy1s0n2lIlIMODvOqKNwAtYdoZH5feKt5P43i0=",
|
||||||
|
"Aza": "qmTKA257DLOrfhk5Zw8RyRmBSonmm6epbloT0P0ZWDc=",
|
||||||
|
// ... more peers
|
||||||
|
},
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Advantages:**
|
||||||
|
- Centralized configuration management
|
||||||
|
- JSON serialization support
|
||||||
|
- Type-safe access to configuration
|
||||||
|
- Easy to extend and maintain
|
||||||
|
|
||||||
|
### 3. **IP Address Validation**
|
||||||
|
|
||||||
|
**Bash Version:**
|
||||||
|
```bash
|
||||||
|
# Basic regex validation
|
||||||
|
validate_ip() {
|
||||||
|
local ip=$1
|
||||||
|
if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/[0-9]{1,2}$ ]]; then
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Go Version:**
|
||||||
|
```go
|
||||||
|
func validateIP(ip string) error {
|
||||||
|
if ip == "" {
|
||||||
|
return fmt.Errorf("IP address cannot be empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if it's in the expected range
|
||||||
|
if !ipRegex.MatchString(ip) {
|
||||||
|
return fmt.Errorf("IP should be in 10.8.0.x range for NextGen network")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate IP format using net package
|
||||||
|
parsedIP := net.ParseIP(ip)
|
||||||
|
if parsedIP == nil {
|
||||||
|
return fmt.Errorf("invalid IP address format")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for conflicts with existing peers
|
||||||
|
for peerName, peerIP := range map[string]string{
|
||||||
|
"Zion": "10.8.0.1",
|
||||||
|
"Cth": "10.8.0.10",
|
||||||
|
// ... more peers
|
||||||
|
} {
|
||||||
|
if ip == peerIP {
|
||||||
|
return fmt.Errorf("IP %s is already in use by %s", ip, peerName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Advantages:**
|
||||||
|
- Uses Go's `net` package for proper IP validation
|
||||||
|
- Checks for IP conflicts with existing peers
|
||||||
|
- More comprehensive validation
|
||||||
|
- Better error messages
|
||||||
|
|
||||||
|
### 4. **Key Generation**
|
||||||
|
|
||||||
|
**Bash Version:**
|
||||||
|
```bash
|
||||||
|
# Relies on external wg command
|
||||||
|
PRIVATE_KEY=$(wg genkey)
|
||||||
|
PUBLIC_KEY=$(echo "$PRIVATE_KEY" | wg pubkey)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Go Version:**
|
||||||
|
```go
|
||||||
|
func generateWireGuardKeys() (string, string, error) {
|
||||||
|
// Generate private key
|
||||||
|
privateKeyBytes := make([]byte, 32)
|
||||||
|
if _, err := rand.Read(privateKeyBytes); err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure the key is valid for curve25519
|
||||||
|
privateKeyBytes[0] &= 248
|
||||||
|
privateKeyBytes[31] &= 127
|
||||||
|
privateKeyBytes[31] |= 64
|
||||||
|
|
||||||
|
// Generate public key using curve25519
|
||||||
|
var publicKeyBytes [32]byte
|
||||||
|
curve25519.ScalarBaseMult(&publicKeyBytes, (*[32]byte)(privateKeyBytes))
|
||||||
|
|
||||||
|
privateKey := base64.StdEncoding.EncodeToString(privateKeyBytes[:])
|
||||||
|
publicKey := base64.StdEncoding.EncodeToString(publicKeyBytes[:])
|
||||||
|
|
||||||
|
return privateKey, publicKey, nil
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Advantages:**
|
||||||
|
- No external dependencies for key generation
|
||||||
|
- Uses cryptographically secure random number generator
|
||||||
|
- Proper curve25519 key generation
|
||||||
|
- Better error handling
|
||||||
|
|
||||||
|
### 5. **File Operations**
|
||||||
|
|
||||||
|
**Bash Version:**
|
||||||
|
```bash
|
||||||
|
# Basic file operations
|
||||||
|
cat > "$CONFIG_FILE" << EOF
|
||||||
|
[Interface]
|
||||||
|
PrivateKey = $PRIVATE_KEY
|
||||||
|
Address = $IP_ADDRESS
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
**Go Version:**
|
||||||
|
```go
|
||||||
|
// Structured file operations with error handling
|
||||||
|
func generateConfig(hostname, ipAddress, privateKey, routingMode string) string {
|
||||||
|
var config strings.Builder
|
||||||
|
|
||||||
|
// Interface section
|
||||||
|
config.WriteString("[Interface]\n")
|
||||||
|
config.WriteString(fmt.Sprintf("Address = %s/24\n", ipAddress))
|
||||||
|
config.WriteString(fmt.Sprintf("PrivateKey = %s\n", privateKey))
|
||||||
|
|
||||||
|
// Add ListenPort for static servers
|
||||||
|
if port, exists := staticServers[ipAddress]; exists {
|
||||||
|
config.WriteString(fmt.Sprintf("ListenPort = %s\n", port))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add DNS for full tunnel mode
|
||||||
|
if routingMode == "full_tunnel" {
|
||||||
|
config.WriteString("DNS = 1.1.1.1, 8.8.8.8\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zion peer (always enabled)
|
||||||
|
config.WriteString("\n# Zion (central server)\n")
|
||||||
|
config.WriteString("[Peer]\n")
|
||||||
|
config.WriteString(fmt.Sprintf("PublicKey = %s\n", zionConfig.PublicKey))
|
||||||
|
// ... more configuration
|
||||||
|
|
||||||
|
return config.String()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Advantages:**
|
||||||
|
- Uses `strings.Builder` for efficient string concatenation
|
||||||
|
- Structured configuration generation
|
||||||
|
- Better memory efficiency
|
||||||
|
- Type-safe operations
|
||||||
|
|
||||||
|
### 6. **User Input Handling**
|
||||||
|
|
||||||
|
**Bash Version:**
|
||||||
|
```bash
|
||||||
|
# Basic input with limited validation
|
||||||
|
read -p "Enter node name (e.g., aza, cth, galaxy): " NODE_NAME
|
||||||
|
if [ -z "$NODE_NAME" ]; then
|
||||||
|
print_error "Node name cannot be empty"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
```
|
||||||
|
|
||||||
|
**Go Version:**
|
||||||
|
```go
|
||||||
|
func getUserInput(prompt string, validator func(string) error) string {
|
||||||
|
reader := bufio.NewReader(os.Stdin)
|
||||||
|
for {
|
||||||
|
fmt.Print(prompt)
|
||||||
|
input, _ := reader.ReadString('\n')
|
||||||
|
input = strings.TrimSpace(input)
|
||||||
|
|
||||||
|
if err := validator(input); err != nil {
|
||||||
|
printError(err.Error())
|
||||||
|
fmt.Print("Continue anyway? (y/N): ")
|
||||||
|
response, _ := reader.ReadString('\n')
|
||||||
|
response = strings.TrimSpace(strings.ToLower(response))
|
||||||
|
if response == "y" || response == "yes" {
|
||||||
|
return input
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return input
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Advantages:**
|
||||||
|
- Function-based validation
|
||||||
|
- Better error recovery
|
||||||
|
- Consistent input handling
|
||||||
|
- More flexible validation logic
|
||||||
|
|
||||||
|
### 7. **JSON Configuration Export**
|
||||||
|
|
||||||
|
**Go Version Only:**
|
||||||
|
```go
|
||||||
|
type WGConfig struct {
|
||||||
|
Hostname string `json:"hostname"`
|
||||||
|
IPAddress string `json:"ip_address"`
|
||||||
|
PrivateKey string `json:"private_key"`
|
||||||
|
PublicKey string `json:"public_key"`
|
||||||
|
RoutingMode string `json:"routing_mode"`
|
||||||
|
Generated string `json:"generated"`
|
||||||
|
ScriptVer string `json:"script_version"`
|
||||||
|
RunningRoot bool `json:"running_as_root"`
|
||||||
|
ZionPeer bool `json:"zion_peer_added"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Automatic JSON serialization
|
||||||
|
infoData, err := json.MarshalIndent(wgConfig, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
printError(fmt.Sprintf("Failed to marshal config: %v", err))
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Advantages:**
|
||||||
|
- Structured data export
|
||||||
|
- Easy integration with other tools
|
||||||
|
- Machine-readable configuration
|
||||||
|
- Better debugging and logging
|
||||||
|
|
||||||
|
## Performance Comparison
|
||||||
|
|
||||||
|
### Memory Usage
|
||||||
|
- **Bash**: Higher memory usage due to string operations and external commands
|
||||||
|
- **Go**: More efficient memory usage with `strings.Builder` and structured data
|
||||||
|
|
||||||
|
### Execution Speed
|
||||||
|
- **Bash**: Slower due to external command calls (`wg genkey`, `wg pubkey`)
|
||||||
|
- **Go**: Faster with native key generation and optimized string operations
|
||||||
|
|
||||||
|
### Dependencies
|
||||||
|
- **Bash**: Requires external tools (`wg`, `wg-quick`, `bash`)
|
||||||
|
- **Go**: Single binary with minimal runtime dependencies
|
||||||
|
|
||||||
|
## Maintainability
|
||||||
|
|
||||||
|
### Code Organization
|
||||||
|
- **Bash**: Functions scattered throughout, harder to maintain
|
||||||
|
- **Go**: Structured with clear separation of concerns
|
||||||
|
|
||||||
|
### Error Handling
|
||||||
|
- **Bash**: Basic error checking with exit codes
|
||||||
|
- **Go**: Comprehensive error handling with context
|
||||||
|
|
||||||
|
### Testing
|
||||||
|
- **Bash**: Difficult to unit test
|
||||||
|
- **Go**: Easy to unit test with structured functions
|
||||||
|
|
||||||
|
## Security Improvements
|
||||||
|
|
||||||
|
### Key Generation
|
||||||
|
- **Bash**: Relies on external `wg` command
|
||||||
|
- **Go**: Uses cryptographically secure random number generator
|
||||||
|
|
||||||
|
### Input Validation
|
||||||
|
- **Bash**: Basic regex validation
|
||||||
|
- **Go**: Comprehensive validation with multiple checks
|
||||||
|
|
||||||
|
### File Operations
|
||||||
|
- **Bash**: Basic file operations
|
||||||
|
- **Go**: Proper error handling and atomic operations
|
||||||
|
|
||||||
|
## Cross-Platform Compatibility
|
||||||
|
|
||||||
|
### Distribution
|
||||||
|
- **Bash**: Requires bash shell and external tools
|
||||||
|
- **Go**: Single binary that works on any platform
|
||||||
|
|
||||||
|
### Dependencies
|
||||||
|
- **Bash**: Platform-specific package managers
|
||||||
|
- **Go**: No external dependencies
|
||||||
|
|
||||||
|
## Conclusion
|
||||||
|
|
||||||
|
The Go implementation provides significant improvements over the bash version:
|
||||||
|
|
||||||
|
1. **Better Type Safety**: Compile-time error checking prevents runtime issues
|
||||||
|
2. **Improved Error Handling**: Structured error handling with context
|
||||||
|
3. **Enhanced Validation**: More comprehensive input validation
|
||||||
|
4. **Better Performance**: Native key generation and optimized operations
|
||||||
|
5. **Easier Maintenance**: Structured code with clear separation of concerns
|
||||||
|
6. **Cross-Platform**: Single binary with no external dependencies
|
||||||
|
7. **Better Security**: Cryptographically secure operations
|
||||||
|
8. **Structured Output**: JSON configuration export for integration
|
||||||
|
|
||||||
|
The Go version is more suitable for production use, especially in environments where reliability, security, and maintainability are important.
|
||||||
121
README.md
Normal file
121
README.md
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
## wgtool (WireGuard helper CLI)
|
||||||
|
|
||||||
|
wgtool streamlines creating and validating WireGuard configs, and generating a ready-to-paste Zion peer block.
|
||||||
|
|
||||||
|
### Features
|
||||||
|
- Generate WireGuard configs with sensible defaults
|
||||||
|
- Validate single configs or all .conf files in a directory
|
||||||
|
- Print a Zion-ready [Peer] snippet for adding new nodes
|
||||||
|
- Generate private keys (derive public key with `wg pubkey`)
|
||||||
|
|
||||||
|
### Commands
|
||||||
|
- `generate`: Create a config and write keys
|
||||||
|
- `validate`: Lint a config file or all `.conf` files in a directory
|
||||||
|
- `zion-peer`: Print a `[Peer]` block for Zion’s `wg0.conf`
|
||||||
|
- `keys`: Print a private key
|
||||||
|
- `version`: Show tool version
|
||||||
|
|
||||||
|
### Defaults and endpoints
|
||||||
|
- Adds one default peer in generated configs:
|
||||||
|
- Zion (central server)
|
||||||
|
- PublicKey: `2ztJbrN1x1NWanzPGLiKL19ZkdOhm5Y7WeKEWBT5cyg=`
|
||||||
|
- Endpoint: `ugh.im:51820`
|
||||||
|
- AllowedIPs:
|
||||||
|
- `wg_only`: `10.8.0.0/24`
|
||||||
|
- `full_tunnel`: `0.0.0.0/0, ::/0`
|
||||||
|
- PersistentKeepalive: `25`
|
||||||
|
|
||||||
|
### generate
|
||||||
|
Create a config into `wireguard_configs/` and output keys alongside it. Missing flags are prompted interactively unless `--yes` is used.
|
||||||
|
|
||||||
|
Flags:
|
||||||
|
- `--hostname` Node name (e.g., `aza`)
|
||||||
|
- `--ip` Node IP in `10.8.0.x`
|
||||||
|
- `--interface` Interface name (default `wg0`)
|
||||||
|
- `--routing` `wg_only` | `full_tunnel` (default `wg_only`)
|
||||||
|
- `--out` Output directory (default `wireguard_configs`)
|
||||||
|
- `--force` Overwrite without prompt
|
||||||
|
- `--yes` Non-interactive (assume yes)
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
```bash
|
||||||
|
./wgtool generate
|
||||||
|
./wgtool generate --hostname aza --ip 10.8.0.30 --interface wg0 --routing wg_only --out wireguard_configs --yes
|
||||||
|
./wgtool generate --hostname aza --ip 10.8.0.30 --routing full_tunnel --yes
|
||||||
|
```
|
||||||
|
|
||||||
|
Outputs:
|
||||||
|
- `wireguard_configs/wg0.conf`
|
||||||
|
- `wireguard_configs/<hostname>_private.key`
|
||||||
|
- Derive public key: `echo "<PrivateKey>" | wg pubkey`
|
||||||
|
|
||||||
|
### validate
|
||||||
|
Validate a config file or every `.conf` in a directory.
|
||||||
|
|
||||||
|
Flags:
|
||||||
|
- `--target` Path to a file or directory
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
```bash
|
||||||
|
./wgtool validate --target wireguard_configs/wg0.conf
|
||||||
|
./wgtool validate --target wireguard_configs
|
||||||
|
```
|
||||||
|
|
||||||
|
Checks include:
|
||||||
|
- Presence of `[Interface]`
|
||||||
|
- `PrivateKey` and CIDR `Address`
|
||||||
|
- Peer `PublicKey` format
|
||||||
|
- `AllowedIPs` as valid CIDRs
|
||||||
|
|
||||||
|
### zion-peer
|
||||||
|
Print a `[Peer]` block to add into Zion’s `/etc/wireguard/wg0.conf` for a new node.
|
||||||
|
|
||||||
|
Flags:
|
||||||
|
- `--name` Node name
|
||||||
|
- `--pub` Node public key (44-char base64 ending with `=`)
|
||||||
|
- `--ip` Node IP in `10.8.0.x` (host address)
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```bash
|
||||||
|
./wgtool zion-peer --name aza --pub ABCDEFG...= --ip 10.8.0.30
|
||||||
|
```
|
||||||
|
|
||||||
|
### keys
|
||||||
|
Generate and print a private key.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```bash
|
||||||
|
./wgtool keys
|
||||||
|
# derive pub
|
||||||
|
echo "<PrivateKey>" | wg pubkey
|
||||||
|
```
|
||||||
|
|
||||||
|
### Quick start
|
||||||
|
1) Create a config and keys
|
||||||
|
```bash
|
||||||
|
./wgtool generate --hostname mynode --ip 10.8.0.30 --yes
|
||||||
|
```
|
||||||
|
|
||||||
|
2) Validate the config
|
||||||
|
```bash
|
||||||
|
./wgtool validate --target wireguard_configs/wg0.conf
|
||||||
|
```
|
||||||
|
|
||||||
|
3) Give Zion your peer details
|
||||||
|
```bash
|
||||||
|
./wgtool zion-peer --name mynode --pub $(echo "<PrivateKey>" | wg pubkey) --ip 10.8.0.30
|
||||||
|
```
|
||||||
|
|
||||||
|
4) Install and enable (on your node)
|
||||||
|
```bash
|
||||||
|
sudo cp wireguard_configs/wg0.conf /etc/wireguard/
|
||||||
|
sudo chmod 600 /etc/wireguard/wg0.conf
|
||||||
|
sudo systemctl enable --now wg-quick@wg0
|
||||||
|
```
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
- IPs are enforced in the `10.8.0.x` range.
|
||||||
|
- In `full_tunnel` mode DNS is set to `1.1.1.1, 8.8.8.8`.
|
||||||
|
- Overwrites are blocked unless `--force` or confirmed interactively.
|
||||||
|
|
||||||
|
|
||||||
138
SCRIPT_IMPROVEMENTS.md
Normal file
138
SCRIPT_IMPROVEMENTS.md
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
# WireGuard Script Improvements Summary
|
||||||
|
|
||||||
|
This document outlines the errors found and optimizations made to the WireGuard setup scripts.
|
||||||
|
|
||||||
|
## Scripts Analyzed
|
||||||
|
|
||||||
|
1. `generate_zion_peer.sh` - Zion peer configuration generator
|
||||||
|
2. `wireguard_setup.sh` - Interactive WireGuard setup script
|
||||||
|
3. `wireguard_setup.go` - Go-based WireGuard setup tool
|
||||||
|
|
||||||
|
## Issues Found and Fixed
|
||||||
|
|
||||||
|
### 1. generate_zion_peer.sh
|
||||||
|
|
||||||
|
#### Issues Fixed:
|
||||||
|
- **Shebang**: Changed from `/bin/bash` to `/usr/bin/env bash` for better portability
|
||||||
|
- **Error handling**: Added `set -euo pipefail` for stricter error handling
|
||||||
|
- **IP validation**: Improved regex to properly validate 10.8.0.x format and exclude reserved addresses
|
||||||
|
- **Public key validation**: Enhanced validation for WireGuard public keys (44 character base64)
|
||||||
|
- **Input sanitization**: Added validation for node names
|
||||||
|
- **Configuration loading**: Added ability to load Zion config from file with fallback to hardcoded values
|
||||||
|
|
||||||
|
#### Optimizations Added:
|
||||||
|
- **Command line options**: Added `-c/--config` and `-h/--help` flags
|
||||||
|
- **Dynamic config loading**: Script now attempts to read Zion configuration from `CURRENT_WORKING/zion.conf`
|
||||||
|
- **Better error messages**: More descriptive error messages with specific validation failures
|
||||||
|
- **Safe fallbacks**: Graceful degradation when configuration files are not available
|
||||||
|
|
||||||
|
### 2. wireguard_setup.sh
|
||||||
|
|
||||||
|
#### Issues Fixed:
|
||||||
|
- **Shebang**: Changed from `/bin/bash` to `/usr/bin/env bash`
|
||||||
|
- **Error handling**: Added `set -euo pipefail` for stricter error handling
|
||||||
|
- **IP validation**: Completely rewrote validation function to properly check IP format and subnet
|
||||||
|
- **Port validation**: Enhanced port validation with warnings for privileged ports
|
||||||
|
- **Public key validation**: Added validation for WireGuard public keys
|
||||||
|
- **Network interface detection**: Added automatic detection of network interfaces instead of hardcoded `eth0`
|
||||||
|
- **File permissions**: Added proper file permission setting (600) for security
|
||||||
|
- **Variable scope**: Fixed variable scoping issues and made variables local where appropriate
|
||||||
|
|
||||||
|
#### Optimizations Added:
|
||||||
|
- **Configuration file support**: Added `-c/--config` option for custom Zion config files
|
||||||
|
- **Safe filename creation**: Added function to sanitize user input for filenames
|
||||||
|
- **Network interface detection**: Automatic detection of available network interfaces
|
||||||
|
- **Better validation loops**: Improved input validation with retry logic
|
||||||
|
- **Enhanced error messages**: More descriptive error messages and warnings
|
||||||
|
- **Fedora support**: Added Fedora package installation instructions
|
||||||
|
|
||||||
|
### 3. wireguard_setup.go
|
||||||
|
|
||||||
|
#### Issues Fixed:
|
||||||
|
- **Deprecated packages**: Replaced `ioutil` with `os` package (Go 1.16+ compatibility)
|
||||||
|
- **Version bump**: Updated script version to 2.4
|
||||||
|
|
||||||
|
#### Optimizations Added:
|
||||||
|
- **Modern Go**: Uses current Go standard library practices
|
||||||
|
- **Better error handling**: More comprehensive error checking throughout
|
||||||
|
|
||||||
|
## Security Improvements
|
||||||
|
|
||||||
|
### File Permissions
|
||||||
|
- All WireGuard configuration files now use 600 permissions (owner read/write only)
|
||||||
|
- Private keys are properly secured with restrictive permissions
|
||||||
|
|
||||||
|
### Input Validation
|
||||||
|
- Enhanced validation for all user inputs
|
||||||
|
- Sanitization of filenames and node names
|
||||||
|
- Proper IP address format and range validation
|
||||||
|
- WireGuard public key format validation
|
||||||
|
|
||||||
|
### Error Handling
|
||||||
|
- Stricter error handling with `set -euo pipefail` in bash scripts
|
||||||
|
- Better error messages for debugging
|
||||||
|
- Graceful fallbacks when configuration files are missing
|
||||||
|
|
||||||
|
## Portability Improvements
|
||||||
|
|
||||||
|
### Shebang
|
||||||
|
- Changed from hardcoded `/bin/bash` to `/usr/bin/env bash`
|
||||||
|
- Better compatibility across different Unix-like systems
|
||||||
|
|
||||||
|
### Network Interface Detection
|
||||||
|
- Automatic detection of network interfaces instead of hardcoded names
|
||||||
|
- Support for various interface naming conventions (eth0, ens33, ens160, enp0s3, eno1)
|
||||||
|
|
||||||
|
### Configuration Management
|
||||||
|
- External configuration file support
|
||||||
|
- Fallback to hardcoded values when files are not available
|
||||||
|
- Better separation of configuration and logic
|
||||||
|
|
||||||
|
## User Experience Improvements
|
||||||
|
|
||||||
|
### Better Help
|
||||||
|
- Enhanced usage messages with examples
|
||||||
|
- Command line option support
|
||||||
|
- More descriptive error messages
|
||||||
|
|
||||||
|
### Input Validation
|
||||||
|
- Real-time validation with retry loops
|
||||||
|
- Clear error messages explaining what went wrong
|
||||||
|
- Suggestions for correct input formats
|
||||||
|
|
||||||
|
### Configuration Preview
|
||||||
|
- Show generated configuration before saving
|
||||||
|
- Clear instructions for next steps
|
||||||
|
- Integration instructions for Zion server
|
||||||
|
|
||||||
|
## Compatibility Notes
|
||||||
|
|
||||||
|
### Go Version
|
||||||
|
- The Go script now requires Go 1.16 or later due to `os.WriteFile` usage
|
||||||
|
- Replaced deprecated `ioutil.WriteFile` with `os.WriteFile`
|
||||||
|
|
||||||
|
### Bash Version
|
||||||
|
- Bash scripts now use stricter error handling
|
||||||
|
- May require bash 4.0+ for some features
|
||||||
|
- Tested with bash 4.4+ and 5.0+
|
||||||
|
|
||||||
|
### System Requirements
|
||||||
|
- All scripts now properly check for WireGuard tools
|
||||||
|
- Better package installation instructions for various distributions
|
||||||
|
- Network interface detection works on most Linux distributions
|
||||||
|
|
||||||
|
## Testing Recommendations
|
||||||
|
|
||||||
|
1. **Test on different distributions**: Ubuntu, CentOS, Fedora, Arch
|
||||||
|
2. **Test with different bash versions**: Ensure compatibility with older systems
|
||||||
|
3. **Test network interface detection**: Various interface naming schemes
|
||||||
|
4. **Test error conditions**: Missing dependencies, invalid inputs, permission issues
|
||||||
|
5. **Test configuration loading**: With and without Zion config files
|
||||||
|
|
||||||
|
## Future Improvements
|
||||||
|
|
||||||
|
1. **Configuration file format**: Consider YAML or TOML for better readability
|
||||||
|
2. **Logging**: Add proper logging with different verbosity levels
|
||||||
|
3. **Testing**: Add unit tests for validation functions
|
||||||
|
4. **CI/CD**: Add automated testing and linting
|
||||||
|
5. **Documentation**: Add man pages and more detailed usage examples
|
||||||
339
SETUP_GUIDE.md
Normal file
339
SETUP_GUIDE.md
Normal file
@@ -0,0 +1,339 @@
|
|||||||
|
# WireGuard Configuration Setup Guide
|
||||||
|
|
||||||
|
This guide provides a complete solution for creating WireGuard VPN configurations based on the patterns found in the `TESTING/` directory.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
The solution consists of three main components:
|
||||||
|
|
||||||
|
1. **`wireguard_setup.sh`** - Main interactive setup script
|
||||||
|
2. **`validate_config.sh`** - Configuration validation tool
|
||||||
|
3. **`example_setup.sh`** - Example automation script
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
### 1. Run the Setup Script
|
||||||
|
```bash
|
||||||
|
./wireguard_setup.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
The script will guide you through:
|
||||||
|
- Generating private/public key pairs
|
||||||
|
- Setting up node configuration (client or server)
|
||||||
|
- Adding peers to your configuration
|
||||||
|
- Creating configuration files
|
||||||
|
|
||||||
|
### 2. Validate Your Configuration
|
||||||
|
```bash
|
||||||
|
./validate_config.sh wireguard_configs/your_node.conf
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Deploy the Configuration
|
||||||
|
```bash
|
||||||
|
sudo cp wireguard_configs/your_node.conf /etc/wireguard/
|
||||||
|
sudo chmod 600 /etc/wireguard/your_node.conf
|
||||||
|
sudo wg-quick up your_node
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration Patterns
|
||||||
|
|
||||||
|
Based on the `TESTING/` directory analysis, there are three main configuration types:
|
||||||
|
|
||||||
|
### 1. Client Configuration (aza.conf, galaxy.conf)
|
||||||
|
```ini
|
||||||
|
[Interface]
|
||||||
|
PrivateKey = <private_key>
|
||||||
|
Address = 10.8.0.x/24
|
||||||
|
|
||||||
|
[Peer]
|
||||||
|
PublicKey = <server_public_key>
|
||||||
|
AllowedIPs = 10.8.0.0/24
|
||||||
|
Endpoint = server.example.com:51820
|
||||||
|
PersistentKeepalive = 25
|
||||||
|
```
|
||||||
|
|
||||||
|
**Use case**: Simple client connecting to a central server (Zion included as default peer)
|
||||||
|
|
||||||
|
### 2. Server Configuration (zion.conf)
|
||||||
|
```ini
|
||||||
|
[Interface]
|
||||||
|
Address = 10.8.0.1/24
|
||||||
|
ListenPort = 51820
|
||||||
|
PrivateKey = <private_key>
|
||||||
|
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
|
||||||
|
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
|
||||||
|
|
||||||
|
[Peer]
|
||||||
|
PublicKey = <client_public_key>
|
||||||
|
AllowedIPs = 10.8.0.x/32
|
||||||
|
```
|
||||||
|
|
||||||
|
**Use case**: Central hub server that routes traffic between clients
|
||||||
|
|
||||||
|
### 3. Hybrid Configuration (cth.conf, nyan.conf)
|
||||||
|
```ini
|
||||||
|
[Interface]
|
||||||
|
Address = 10.8.0.x/24
|
||||||
|
ListenPort = <port>
|
||||||
|
PrivateKey = <private_key>
|
||||||
|
|
||||||
|
[Peer]
|
||||||
|
PublicKey = <server_public_key>
|
||||||
|
AllowedIPs = 10.8.0.0/24
|
||||||
|
Endpoint = server.example.com:51820
|
||||||
|
PersistentKeepalive = 25
|
||||||
|
|
||||||
|
[Peer]
|
||||||
|
PublicKey = <direct_peer_public_key>
|
||||||
|
AllowedIPs = 10.8.0.y/32
|
||||||
|
Endpoint = peer.example.com:port
|
||||||
|
PersistentKeepalive = 25
|
||||||
|
```
|
||||||
|
|
||||||
|
**Use case**: Node that connects to central server AND has direct peer connections
|
||||||
|
|
||||||
|
## Network Topology Examples
|
||||||
|
|
||||||
|
### Star Topology (Most Common)
|
||||||
|
```
|
||||||
|
zion (10.8.0.1) - Central Server
|
||||||
|
├── aza (10.8.0.2) - Client
|
||||||
|
├── cth (10.8.0.10) - Hybrid
|
||||||
|
├── galaxy (10.8.0.99) - Client
|
||||||
|
└── nyan (10.8.0.20) - Client
|
||||||
|
```
|
||||||
|
|
||||||
|
### Mesh Topology
|
||||||
|
```
|
||||||
|
zion (10.8.0.1) - Hub
|
||||||
|
├── cth (10.8.0.10) - Hybrid
|
||||||
|
│ └── nyan (10.8.0.20) - Direct peer
|
||||||
|
└── galaxy (10.8.0.99) - Client
|
||||||
|
```
|
||||||
|
|
||||||
|
## Script Features
|
||||||
|
|
||||||
|
### Main Setup Script (`wireguard_setup.sh`)
|
||||||
|
|
||||||
|
**Features:**
|
||||||
|
- Interactive step-by-step configuration
|
||||||
|
- Automatic key generation
|
||||||
|
- Input validation (IP addresses, ports, keys)
|
||||||
|
- Support for client, server, and hybrid configurations
|
||||||
|
- File overwrite protection to prevent accidental data loss
|
||||||
|
- Colored output for better readability
|
||||||
|
- Automatic summary file generation
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
```bash
|
||||||
|
# Basic usage
|
||||||
|
./wireguard_setup.sh
|
||||||
|
|
||||||
|
# Custom output directory
|
||||||
|
./wireguard_setup.sh --dir /path/to/output
|
||||||
|
|
||||||
|
# Show help
|
||||||
|
./wireguard_setup.sh --help
|
||||||
|
```
|
||||||
|
|
||||||
|
### Validation Script (`validate_config.sh`)
|
||||||
|
|
||||||
|
**Features:**
|
||||||
|
- Validates WireGuard configuration syntax
|
||||||
|
- Checks file permissions
|
||||||
|
- Validates key formats, IP addresses, ports
|
||||||
|
- Supports single file or directory validation
|
||||||
|
- Detailed error reporting
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
```bash
|
||||||
|
# Validate single file
|
||||||
|
./validate_config.sh wireguard_configs/test.conf
|
||||||
|
|
||||||
|
# Validate all files in directory
|
||||||
|
./validate_config.sh wireguard_configs/
|
||||||
|
|
||||||
|
# Validate TESTING directory
|
||||||
|
./validate_config.sh TESTING/
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example Script (`example_setup.sh`)
|
||||||
|
|
||||||
|
**Features:**
|
||||||
|
- Demonstrates automated configuration creation
|
||||||
|
- Pre-configured examples for client and server setups
|
||||||
|
- Useful for testing and learning
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
```bash
|
||||||
|
# Create client example
|
||||||
|
./example_setup.sh client
|
||||||
|
|
||||||
|
# Create server example
|
||||||
|
./example_setup.sh server
|
||||||
|
```
|
||||||
|
|
||||||
|
## Step-by-Step Configuration Process
|
||||||
|
|
||||||
|
### For a Client Node (like aza.conf)
|
||||||
|
|
||||||
|
1. **Run the setup script:**
|
||||||
|
```bash
|
||||||
|
./wireguard_setup.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Follow the prompts:**
|
||||||
|
- Node name: `aza`
|
||||||
|
- IP address: `10.8.0.2/24`
|
||||||
|
- Server mode: `n` (no)
|
||||||
|
- Add peer: `y` (yes)
|
||||||
|
- Peer name: `zion`
|
||||||
|
- Peer public key: `<zion_public_key>`
|
||||||
|
- Allowed IPs: `10.8.0.0/24`
|
||||||
|
- Has endpoint: `y` (yes)
|
||||||
|
- Endpoint: `ugh.im:51820`
|
||||||
|
- Keepalive: `25`
|
||||||
|
- Add more peers: `n` (no)
|
||||||
|
|
||||||
|
3. **Deploy:**
|
||||||
|
```bash
|
||||||
|
sudo cp wireguard_configs/aza.conf /etc/wireguard/
|
||||||
|
sudo chmod 600 /etc/wireguard/aza.conf
|
||||||
|
sudo wg-quick up aza
|
||||||
|
```
|
||||||
|
|
||||||
|
### For a Server Node (like zion.conf)
|
||||||
|
|
||||||
|
1. **Run the setup script:**
|
||||||
|
```bash
|
||||||
|
./wireguard_setup.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Follow the prompts:**
|
||||||
|
- Node name: `zion`
|
||||||
|
- IP address: `10.8.0.1/24`
|
||||||
|
- Server mode: `y` (yes)
|
||||||
|
- Listen port: `51820`
|
||||||
|
- Add peers: `y` (yes)
|
||||||
|
- Add each client as a peer (no endpoints needed)
|
||||||
|
|
||||||
|
3. **Deploy:**
|
||||||
|
```bash
|
||||||
|
sudo cp wireguard_configs/zion.conf /etc/wireguard/
|
||||||
|
sudo chmod 600 /etc/wireguard/zion.conf
|
||||||
|
sudo wg-quick up zion
|
||||||
|
```
|
||||||
|
|
||||||
|
## Security Best Practices
|
||||||
|
|
||||||
|
1. **Key Management:**
|
||||||
|
- Never share private keys
|
||||||
|
- Use unique keys for each node
|
||||||
|
- Store keys securely
|
||||||
|
|
||||||
|
2. **File Permissions:**
|
||||||
|
- Set config files to 600 permissions
|
||||||
|
- Restrict access to configuration files
|
||||||
|
|
||||||
|
3. **Network Security:**
|
||||||
|
- Use strong, unique keys
|
||||||
|
- Configure appropriate firewall rules
|
||||||
|
- Monitor network traffic
|
||||||
|
|
||||||
|
4. **Deployment:**
|
||||||
|
- Test configurations before production
|
||||||
|
- Use validation script to check syntax
|
||||||
|
- Keep backups of configurations
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Common Issues
|
||||||
|
|
||||||
|
1. **"wg command not found"**
|
||||||
|
```bash
|
||||||
|
# Install WireGuard tools
|
||||||
|
sudo apt install wireguard # Ubuntu/Debian
|
||||||
|
sudo yum install wireguard-tools # CentOS/RHEL
|
||||||
|
sudo pacman -S wireguard-tools # Arch
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **"Permission denied"**
|
||||||
|
```bash
|
||||||
|
# Set correct permissions
|
||||||
|
sudo chmod 600 /etc/wireguard/your_config.conf
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Connection issues**
|
||||||
|
```bash
|
||||||
|
# Check WireGuard status
|
||||||
|
sudo wg show
|
||||||
|
|
||||||
|
# Check interface
|
||||||
|
ip link show wg0
|
||||||
|
|
||||||
|
# Check routing
|
||||||
|
ip route show
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Validation errors**
|
||||||
|
```bash
|
||||||
|
# Run validation script
|
||||||
|
./validate_config.sh your_config.conf
|
||||||
|
```
|
||||||
|
|
||||||
|
### Debugging Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check WireGuard status
|
||||||
|
sudo wg show
|
||||||
|
|
||||||
|
# Check interface status
|
||||||
|
ip link show wg0
|
||||||
|
|
||||||
|
# Check routing table
|
||||||
|
ip route show
|
||||||
|
|
||||||
|
# Check firewall rules
|
||||||
|
sudo iptables -L -n -v
|
||||||
|
|
||||||
|
# Check system logs
|
||||||
|
sudo journalctl -u wg-quick@your_interface
|
||||||
|
```
|
||||||
|
|
||||||
|
## File Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
wireguard/
|
||||||
|
├── wireguard_setup.sh # Main setup script
|
||||||
|
├── validate_config.sh # Validation tool
|
||||||
|
├── example_setup.sh # Example automation
|
||||||
|
├── README.md # Main documentation
|
||||||
|
├── SETUP_GUIDE.md # This guide
|
||||||
|
├── TESTING/ # Example configurations
|
||||||
|
│ ├── aza.conf # Client example
|
||||||
|
│ ├── cth.conf # Hybrid example
|
||||||
|
│ ├── galaxy.conf # Client example
|
||||||
|
│ ├── nyan.conf # Hybrid example
|
||||||
|
│ └── zion.conf # Server example
|
||||||
|
└── wireguard_configs/ # Generated configurations
|
||||||
|
├── your_node.conf
|
||||||
|
└── your_node_summary.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
1. **Test the scripts** with the example configurations
|
||||||
|
2. **Create your own configurations** using the interactive script
|
||||||
|
3. **Validate your configurations** before deployment
|
||||||
|
4. **Deploy and test** your WireGuard network
|
||||||
|
5. **Monitor and maintain** your VPN setup
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
For issues or questions:
|
||||||
|
1. Check the troubleshooting section
|
||||||
|
2. Run the validation script on your configurations
|
||||||
|
3. Review the example configurations in the `TESTING/` directory
|
||||||
|
4. Check WireGuard documentation and community resources
|
||||||
|
|
||||||
|
The scripts are designed to be self-documenting and include extensive error checking to help you create valid configurations quickly and safely.
|
||||||
10
TESTING/aza.conf
Normal file
10
TESTING/aza.conf
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
[Interface]
|
||||||
|
PrivateKey = UI7XeN/0WGCziv68Vt3hlPGYWB1dwZN7+N2C4Y2y91o=
|
||||||
|
Address = 10.8.0.2/24
|
||||||
|
|
||||||
|
# Zion (central server)
|
||||||
|
[Peer]
|
||||||
|
PublicKey = 2ztJbrN1x1NWanzPGLiKL19ZkdOhm5Y7WeKEWBT5cyg=
|
||||||
|
AllowedIPs = 10.8.0.0/24
|
||||||
|
Endpoint = ugh.im:51820
|
||||||
|
PersistentKeepalive = 60
|
||||||
81
TESTING/cth.conf
Normal file
81
TESTING/cth.conf
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
[Interface]
|
||||||
|
Address = 10.8.0.10/24
|
||||||
|
ListenPort = 53535
|
||||||
|
PrivateKey = UDr1aohdSWGMEy1F6v0GoC7JNgVHbwA8Dz//7E2xQHM=
|
||||||
|
|
||||||
|
#pix66
|
||||||
|
[Peer]
|
||||||
|
PublicKey = HLBlKuzxTGTkyXSp/mlzRCnFR+mesP8UDF+QsqFLxVY=
|
||||||
|
AllowedIPs = 10.8.0.6/32
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#Cth
|
||||||
|
#[Peer]
|
||||||
|
#PublicKey = NBktXKy1s0n2lIlIMODvOqKNwAtYdoZH5feKt5P43i0=
|
||||||
|
#AllowedIPs = 10.8.0.10/32
|
||||||
|
|
||||||
|
#Aza
|
||||||
|
#[Peer]
|
||||||
|
#PublicKey = qmTKA257DLOrfhk5Zw8RyRmBSonmm6epbloT0P0ZWDc=
|
||||||
|
#AllowedIPs = 10.8.0.2/32
|
||||||
|
|
||||||
|
#Nyar
|
||||||
|
[Peer]
|
||||||
|
PublicKey = 2BA7L1oJP1tK6dIUNHMgcZmOmYmlyPRe2RaBqfUsEWo=
|
||||||
|
AllowedIPs = 10.8.0.20/32
|
||||||
|
|
||||||
|
#Galaxy
|
||||||
|
#[Peer]
|
||||||
|
#PublicKey = QBNt00VSedxPlq3ZvsdYaqIcbudCAyxv9TG65aPVZzM=
|
||||||
|
#AllowedIPs = 10.8.0.99/32
|
||||||
|
|
||||||
|
#nanocube
|
||||||
|
#[Peer]
|
||||||
|
#PublicKey = /ZImoATDIS0e0N08CD7mqWbhtGlSnynpPuY04Ed4Zyc=
|
||||||
|
#AllowedIPs = 10.8.0.7/32
|
||||||
|
|
||||||
|
#jupiter
|
||||||
|
#[Peer]
|
||||||
|
#PublicKey = YIFQ43ULk/YoCgOv3SBU6+MOrbxd+mlvaw9rT8uoNmw=
|
||||||
|
#AllowedIPs = 10.8.0.42/32
|
||||||
|
|
||||||
|
#HASS
|
||||||
|
#[Peer]
|
||||||
|
#PublicKey = C+Poz/7DaXCxe4HZiL6D5cld4jMt5o1gBq3iPiBzrg0=
|
||||||
|
#AllowedIPs = 10.8.0.8/32
|
||||||
|
|
||||||
|
#framebot
|
||||||
|
#[Peer]
|
||||||
|
#PublicKey = loS3yZapqmt6lP53Q+s4EvUzw6FmwgZC8jzgLluJ1Es=
|
||||||
|
#AllowedIPs = 10.8.0.40/32
|
||||||
|
|
||||||
|
|
||||||
|
[Peer]
|
||||||
|
PublicKey = 2ztJbrN1x1NWanzPGLiKL19ZkdOhm5Y7WeKEWBT5cyg=
|
||||||
|
AllowedIPs = 10.8.0.0/24
|
||||||
|
Endpoint = ugh.im:51820
|
||||||
|
PersistentKeepalive = 25
|
||||||
|
|
||||||
|
|
||||||
|
#[Peer]
|
||||||
|
#PublicKey = 2BA7L1oJP1tK6dIUNHMgcZmOmYmlyPRe2RaBqfUsEWo=
|
||||||
|
#AllowedIPs = 10.8.0.20/32
|
||||||
|
#PersistentKeepalive = 25
|
||||||
|
|
||||||
|
#jupiter
|
||||||
|
#[Peer]
|
||||||
|
#PublicKey = YIFQ43ULk/YoCgOv3SBU6+MOrbxd+mlvaw9rT8uoNmw=
|
||||||
|
#AllowedIPs = 10.8.0.42/32
|
||||||
|
|
||||||
|
|
||||||
|
#Galaxy
|
||||||
|
#[Peer]
|
||||||
|
#PublicKey = QBNt00VSedxPlq3ZvsdYaqIcbudCAyxv9TG65aPVZzM=
|
||||||
|
#AllowedIPs = 10.8.0.99/32
|
||||||
|
#Endpoint = galaxyspin.space:54382
|
||||||
|
#PersistentKeepalive = 25
|
||||||
16
TESTING/galaxy.conf
Normal file
16
TESTING/galaxy.conf
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
[Interface]
|
||||||
|
PrivateKey = sHEHZQ3AdUTLG56yeHdmZVuXrivB9P+40Fw0oWHF3Fg=
|
||||||
|
Address = 10.8.0.99/24
|
||||||
|
ListenPort = 54382
|
||||||
|
|
||||||
|
# Zion peer (central server) - for access to entire network
|
||||||
|
[Peer]
|
||||||
|
PublicKey = 2ztJbrN1x1NWanzPGLiKL19ZkdOhm5Y7WeKEWBT5cyg=
|
||||||
|
AllowedIPs = 10.8.0.0/24
|
||||||
|
Endpoint = ugh.im:51820
|
||||||
|
PersistentKeepalive = 25
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
25
TESTING/nyan.conf
Normal file
25
TESTING/nyan.conf
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
[Interface]
|
||||||
|
PrivateKey = sLx3sor9gxhk7T2MIS3g50wzSZBrlVUG+NlXk47jEH4=
|
||||||
|
Address = 10.8.0.20/24
|
||||||
|
|
||||||
|
# Zion peer (central server) - for access to entire network
|
||||||
|
[Peer]
|
||||||
|
PublicKey = 2ztJbrN1x1NWanzPGLiKL19ZkdOhm5Y7WeKEWBT5cyg=
|
||||||
|
AllowedIPs = 10.8.0.0/24
|
||||||
|
Endpoint = ugh.im:51820
|
||||||
|
PersistentKeepalive = 25
|
||||||
|
|
||||||
|
#CTH
|
||||||
|
[Peer]
|
||||||
|
PublicKey = NBktXKy1s0n2lIlIMODvOqKNwAtYdoZH5feKt5P43i0=
|
||||||
|
AllowedIPs = 10.8.0.10/32
|
||||||
|
Endpoint = aw2cd67.glddns.com:53535
|
||||||
|
PersistentKeepalive = 25
|
||||||
|
|
||||||
|
|
||||||
|
#Galaxy
|
||||||
|
#[Peer]
|
||||||
|
#PublicKey = QBNt00VSedxPlq3ZvsdYaqIcbudCAyxv9TG65aPVZzM=
|
||||||
|
#AllowedIPs = 10.8.0.99/32
|
||||||
|
#Endpoint = galaxyspin.space:54382
|
||||||
|
#PersistentKeepalive = 25
|
||||||
48
TESTING/zion.conf
Normal file
48
TESTING/zion.conf
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
[Interface]
|
||||||
|
Address = 10.8.0.1/24
|
||||||
|
ListenPort = 51820
|
||||||
|
PrivateKey = UJvsfv6iQPAW9Wnc81bK0o3IIHX86kGb+24dUTuGFnA=
|
||||||
|
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE; ip route add 10.8.0.0/24 dev wg0 2>/dev/null || true
|
||||||
|
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE; ip route del 10.8.0.0/24 dev wg0 2>/dev/null || true
|
||||||
|
|
||||||
|
#Cth
|
||||||
|
[Peer]
|
||||||
|
PublicKey = NBktXKy1s0n2lIlIMODvOqKNwAtYdoZH5feKt5P43i0=
|
||||||
|
AllowedIPs = 10.8.0.10/32
|
||||||
|
|
||||||
|
#Aza
|
||||||
|
[Peer]
|
||||||
|
PublicKey = qmTKA257DLOrfhk5Zw8RyRmBSonmm6epbloT0P0ZWDc=
|
||||||
|
AllowedIPs = 10.8.0.2/32
|
||||||
|
|
||||||
|
#Nyar
|
||||||
|
[Peer]
|
||||||
|
PublicKey = 2BA7L1oJP1tK6dIUNHMgcZmOmYmlyPRe2RaBqfUsEWo=
|
||||||
|
AllowedIPs = 10.8.0.20/32
|
||||||
|
|
||||||
|
#Galaxy
|
||||||
|
[Peer]
|
||||||
|
PublicKey = QBNt00VSedxPlq3ZvsdYaqIcbudCAyxv9TG65aPVZzM=
|
||||||
|
AllowedIPs = 10.8.0.99/32
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#nanocube
|
||||||
|
[Peer]
|
||||||
|
PublicKey = /ZImoATDIS0e0N08CD7mqWbhtGlSnynpPuY04Ed4Zyc=
|
||||||
|
AllowedIPs = 10.8.0.7/32
|
||||||
|
|
||||||
|
#jupiter
|
||||||
|
[Peer]
|
||||||
|
PublicKey = YIFQ43ULk/YoCgOv3SBU6+MOrbxd+mlvaw9rT8uoNmw=
|
||||||
|
AllowedIPs = 10.8.0.42/32
|
||||||
|
|
||||||
|
#HASS
|
||||||
|
[Peer]
|
||||||
|
PublicKey = C+Poz/7DaXCxe4HZiL6D5cld4jMt5o1gBq3iPiBzrg0=
|
||||||
|
AllowedIPs = 10.8.0.8/32
|
||||||
|
|
||||||
|
#framebot
|
||||||
|
[Peer]
|
||||||
|
PublicKey = loS3yZapqmt6lP53Q+s4EvUzw6FmwgZC8jzgLluJ1Es=
|
||||||
|
AllowedIPs = 10.8.0.40/32
|
||||||
188
ZION_INTEGRATION.md
Normal file
188
ZION_INTEGRATION.md
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
# Zion Integration Guide
|
||||||
|
|
||||||
|
This guide explains how the WireGuard setup script integrates with the Zion central server configuration.
|
||||||
|
|
||||||
|
## Zion Server Configuration
|
||||||
|
|
||||||
|
Based on the `CURRENT_WORKING/zion.conf` file, Zion is configured as:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[Interface]
|
||||||
|
Address = 10.8.0.1/24
|
||||||
|
ListenPort = 51820
|
||||||
|
PrivateKey = UJvsfv6iQPAW9Wnc81bK0o3IIHX86kGb+24dUTuGFnA=
|
||||||
|
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE; ip route add 10.8.0.0/24 dev wg0 2>/dev/null || true
|
||||||
|
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE; ip route del 10.8.0.0/24 dev wg0 2>/dev/null || true
|
||||||
|
```
|
||||||
|
|
||||||
|
## Zion Public Key for Clients
|
||||||
|
|
||||||
|
All client configurations use Zion's public key:
|
||||||
|
```
|
||||||
|
2ztJbrN1x1NWanzPGLiKL19ZkdOhm5Y7WeKEWBT5cyg=
|
||||||
|
```
|
||||||
|
|
||||||
|
## Current Zion Peers
|
||||||
|
|
||||||
|
Zion currently has these peers configured:
|
||||||
|
|
||||||
|
| Node | IP Address | Public Key |
|
||||||
|
|------|------------|------------|
|
||||||
|
| Cth | 10.8.0.10 | NBktXKy1s0n2lIlIMODvOqKNwAtYdoZH5feKt5P43i0= |
|
||||||
|
| Aza | 10.8.0.2 | qmTKA257DLOrfhk5Zw8RyRmBSonmm6epbloT0P0ZWDc= |
|
||||||
|
| Nyar | 10.8.0.20 | 2BA7L1oJP1tK6dIUNHMgcZmOmYmlyPRe2RaBqfUsEWo= |
|
||||||
|
| Galaxy | 10.8.0.99 | QBNt00VSedxPlq3ZvsdYaqIcbudCAyxv9TG65aPVZzM= |
|
||||||
|
| nanocube | 10.8.0.7 | /ZImoATDIS0e0N08CD7mqWbhtGlSnynpPuY04Ed4Zyc= |
|
||||||
|
| jupiter | 10.8.0.42 | YIFQ43ULk/YoCgOv3SBU6+MOrbxd+mlvaw9rT8uoNmw= |
|
||||||
|
| HASS | 10.8.0.8 | C+Poz/7DaXCxe4HZiL6D5cld4jMt5o1gBq3iPiBzrg0= |
|
||||||
|
| framebot | 10.8.0.40 | loS3yZapqmt6lP53Q+s4EvUzw6FmwgZC8jzgLluJ1Es= |
|
||||||
|
|
||||||
|
## Adding New Nodes to Zion
|
||||||
|
|
||||||
|
When you create a new node using the setup script, you need to add it to Zion's configuration.
|
||||||
|
|
||||||
|
### Method 1: Using the Helper Script
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./generate_zion_peer.sh <node_name> <public_key> <ip_address>
|
||||||
|
```
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```bash
|
||||||
|
./generate_zion_peer.sh mynode ABC123def456ghi789jkl012mno345pqr678stu901vwx234yz567890= 10.8.0.30
|
||||||
|
```
|
||||||
|
|
||||||
|
### Method 2: Manual Addition
|
||||||
|
|
||||||
|
Add the following to Zion's `/etc/wireguard/wg0.conf`:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
# your_node_name
|
||||||
|
[Peer]
|
||||||
|
PublicKey = your_public_key_here
|
||||||
|
AllowedIPs = your_ip_address/32
|
||||||
|
```
|
||||||
|
|
||||||
|
## Zion Configuration File Location
|
||||||
|
|
||||||
|
Zion's configuration is located at:
|
||||||
|
```
|
||||||
|
/etc/wireguard/wg0.conf
|
||||||
|
```
|
||||||
|
|
||||||
|
## Adding a New Peer to Zion
|
||||||
|
|
||||||
|
1. **Get the new node's information** from the setup script output:
|
||||||
|
- Node name
|
||||||
|
- Public key
|
||||||
|
- IP address
|
||||||
|
|
||||||
|
2. **Edit Zion's configuration**:
|
||||||
|
```bash
|
||||||
|
sudo nano /etc/wireguard/wg0.conf
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Add the peer section** at the end of the file:
|
||||||
|
```ini
|
||||||
|
# your_node_name
|
||||||
|
[Peer]
|
||||||
|
PublicKey = your_public_key_here
|
||||||
|
AllowedIPs = your_ip_address/32
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Save and restart Zion's WireGuard**:
|
||||||
|
```bash
|
||||||
|
sudo systemctl restart wg-quick@wg0
|
||||||
|
```
|
||||||
|
|
||||||
|
## Client Configuration Pattern
|
||||||
|
|
||||||
|
All client configurations follow this pattern:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[Interface]
|
||||||
|
PrivateKey = <client_private_key>
|
||||||
|
Address = <client_ip>/24
|
||||||
|
|
||||||
|
# Zion (central server)
|
||||||
|
[Peer]
|
||||||
|
PublicKey = 2ztJbrN1x1NWanzPGLiKL19ZkdOhm5Y7WeKEWBT5cyg=
|
||||||
|
AllowedIPs = 10.8.0.0/24
|
||||||
|
Endpoint = ugh.im:51820
|
||||||
|
PersistentKeepalive = 25
|
||||||
|
```
|
||||||
|
|
||||||
|
## Network Topology
|
||||||
|
|
||||||
|
```
|
||||||
|
zion (10.8.0.1) - Central Server
|
||||||
|
├── aza (10.8.0.2) - Client
|
||||||
|
├── cth (10.8.0.10) - Hybrid
|
||||||
|
├── galaxy (10.8.0.99) - Client
|
||||||
|
├── nyan (10.8.0.20) - Client
|
||||||
|
├── nanocube (10.8.0.7) - Client
|
||||||
|
├── jupiter (10.8.0.42) - Client
|
||||||
|
├── HASS (10.8.0.8) - Client
|
||||||
|
├── framebot (10.8.0.40) - Client
|
||||||
|
└── your_new_node (10.8.0.x) - Client
|
||||||
|
```
|
||||||
|
|
||||||
|
## Setup Script Integration
|
||||||
|
|
||||||
|
The `wireguard_setup.sh` script:
|
||||||
|
|
||||||
|
1. **Automatically includes Zion** as the default peer for all new nodes
|
||||||
|
2. **Uses the correct Zion public key** from the CURRENT_WORKING configuration
|
||||||
|
3. **Provides clear instructions** for updating Zion's configuration
|
||||||
|
4. **Generates the exact peer configuration** needed for Zion
|
||||||
|
5. **Includes Zion's current peer structure** for reference
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Common Issues
|
||||||
|
|
||||||
|
1. **Connection fails after adding peer to Zion**
|
||||||
|
- Ensure Zion's WireGuard was restarted: `sudo systemctl restart wg-quick@wg0`
|
||||||
|
- Check Zion's logs: `sudo journalctl -u wg-quick@wg0 -f`
|
||||||
|
|
||||||
|
2. **IP address conflicts**
|
||||||
|
- Check if the IP is already in use by another peer
|
||||||
|
- Use a different IP in the 10.8.0.x range
|
||||||
|
|
||||||
|
3. **Public key format issues**
|
||||||
|
- Ensure the public key is exactly 44 characters long
|
||||||
|
- Check for any extra spaces or characters
|
||||||
|
|
||||||
|
### Verification Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check Zion's WireGuard status
|
||||||
|
sudo wg show wg0
|
||||||
|
|
||||||
|
# Check Zion's configuration
|
||||||
|
sudo cat /etc/wireguard/wg0.conf
|
||||||
|
|
||||||
|
# Check Zion's systemd service
|
||||||
|
sudo systemctl status wg-quick@wg0
|
||||||
|
|
||||||
|
# Check Zion's logs
|
||||||
|
sudo journalctl -u wg-quick@wg0 -f
|
||||||
|
```
|
||||||
|
|
||||||
|
## Security Notes
|
||||||
|
|
||||||
|
1. **Zion's private key** should never be shared
|
||||||
|
2. **Client public keys** are safe to share and add to Zion
|
||||||
|
3. **IP addresses** should be unique within the 10.8.0.x range
|
||||||
|
4. **File permissions** should be 600 for all WireGuard configs
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
After setting up a new node:
|
||||||
|
|
||||||
|
1. Run the setup script: `./wireguard_setup.sh`
|
||||||
|
2. Use the helper script to generate Zion peer config: `./generate_zion_peer.sh`
|
||||||
|
3. Add the peer to Zion's configuration
|
||||||
|
4. Restart Zion's WireGuard
|
||||||
|
5. Start the new node's WireGuard
|
||||||
|
6. Test connectivity between nodes
|
||||||
482
cmd/wgtool/main.go
Normal file
482
cmd/wgtool/main.go
Normal file
@@ -0,0 +1,482 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/base64"
|
||||||
|
"errors"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/curve25519"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
toolVersion = "1.0.0"
|
||||||
|
|
||||||
|
colorRed = "\033[0;31m"
|
||||||
|
colorGreen = "\033[0;32m"
|
||||||
|
colorYellow = "\033[1;33m"
|
||||||
|
colorBlue = "\033[0;34m"
|
||||||
|
colorReset = "\033[0m"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ipCIDRRegex = regexp.MustCompile(`^[0-9]{1,3}(\.[0-9]{1,3}){3}/[0-9]{1,2}$`)
|
||||||
|
ipWGRangeRegex = regexp.MustCompile(`^10\.8\.0\.[0-9]{1,3}$`)
|
||||||
|
hostRegex = regexp.MustCompile(`^[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]$|^[a-zA-Z0-9]$`)
|
||||||
|
keyRegex = regexp.MustCompile(`^[A-Za-z0-9+/]{43}=$`)
|
||||||
|
)
|
||||||
|
|
||||||
|
func info(msg string) { fmt.Printf("%s[INFO]%s %s\n", colorGreen, colorReset, msg) }
|
||||||
|
func warn(msg string) { fmt.Printf("%s[WARN]%s %s\n", colorYellow, colorReset, msg) }
|
||||||
|
func fail(msg string) { fmt.Printf("%s[ERROR]%s %s\n", colorRed, colorReset, msg) }
|
||||||
|
func head(title string) {
|
||||||
|
fmt.Printf("%s================================%s\n", colorBlue, colorReset)
|
||||||
|
fmt.Printf("%s%s%s\n", colorBlue, title, colorReset)
|
||||||
|
fmt.Printf("%s================================%s\n", colorBlue, colorReset)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============= Shared validation helpers =============
|
||||||
|
func validateHostname(s string) error {
|
||||||
|
if s == "" {
|
||||||
|
return errors.New("hostname cannot be empty")
|
||||||
|
}
|
||||||
|
if len(s) > 63 {
|
||||||
|
return errors.New("hostname too long (max 63 chars)")
|
||||||
|
}
|
||||||
|
if !hostRegex.MatchString(s) {
|
||||||
|
return errors.New("invalid hostname format")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateIPHost(s string) error {
|
||||||
|
if !ipWGRangeRegex.MatchString(s) {
|
||||||
|
return errors.New("IP must be in 10.8.0.x range")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateCIDR(s string) error {
|
||||||
|
if !ipCIDRRegex.MatchString(s) {
|
||||||
|
return errors.New("invalid CIDR (x.x.x.x/y)")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateWGKey(s string) error {
|
||||||
|
if !keyRegex.MatchString(s) {
|
||||||
|
return errors.New("invalid WireGuard key format")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============= Key generation =============
|
||||||
|
func generateKeys() (string, string, error) {
|
||||||
|
priv := make([]byte, 32)
|
||||||
|
if _, err := rand.Read(priv); err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
// curve25519 clamping
|
||||||
|
priv[0] &= 248
|
||||||
|
priv[31] &= 127
|
||||||
|
priv[31] |= 64
|
||||||
|
// Derive public key using curve25519
|
||||||
|
// Use the same approach as wg: ScalarBaseMult on clamped private key
|
||||||
|
var privArr [32]byte
|
||||||
|
copy(privArr[:], priv)
|
||||||
|
var pubArr [32]byte
|
||||||
|
// defer import here to avoid top-level dependency note in comments
|
||||||
|
pubArr = derivePublicKey(privArr)
|
||||||
|
return base64.StdEncoding.EncodeToString(priv), base64.StdEncoding.EncodeToString(pubArr[:]), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// derivePublicKey performs curve25519 base point multiplication.
|
||||||
|
// Implemented via a tiny wrapper so we can keep generateKeys concise.
|
||||||
|
func derivePublicKey(priv [32]byte) [32]byte {
|
||||||
|
// inline import pattern is not possible; real import placed at top
|
||||||
|
// function body replaced by the real call below after adding import
|
||||||
|
return curve25519BaseMult(priv)
|
||||||
|
}
|
||||||
|
|
||||||
|
// curve25519BaseMult is a small shim around golang.org/x/crypto/curve25519.ScalarBaseMult
|
||||||
|
// defined below to keep the public key derivation isolated.
|
||||||
|
func curve25519BaseMult(priv [32]byte) [32]byte {
|
||||||
|
var out [32]byte
|
||||||
|
curve25519.ScalarBaseMult(&out, &priv)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============= Config generation =============
|
||||||
|
type genOptions struct {
|
||||||
|
hostname string
|
||||||
|
ip string
|
||||||
|
iface string
|
||||||
|
routing string // wg_only | full_tunnel
|
||||||
|
outDir string
|
||||||
|
force bool
|
||||||
|
nonInteractive bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func runGenerate(args []string) int {
|
||||||
|
fs := flag.NewFlagSet("generate", flag.ContinueOnError)
|
||||||
|
fs.SetOutput(new(strings.Builder))
|
||||||
|
opts := genOptions{}
|
||||||
|
fs.StringVar(&opts.hostname, "hostname", "", "Node hostname (e.g. aza)")
|
||||||
|
fs.StringVar(&opts.ip, "ip", "", "Node IP (10.8.0.x)")
|
||||||
|
fs.StringVar(&opts.iface, "interface", "wg0", "Interface name (e.g. wg0)")
|
||||||
|
fs.StringVar(&opts.routing, "routing", "wg_only", "Routing mode: wg_only | full_tunnel")
|
||||||
|
fs.StringVar(&opts.outDir, "out", "wireguard_configs", "Output directory for configs")
|
||||||
|
fs.BoolVar(&opts.force, "force", false, "Overwrite existing files without prompt")
|
||||||
|
fs.BoolVar(&opts.nonInteractive, "yes", false, "Non-interactive mode (assume yes)")
|
||||||
|
if err := fs.Parse(args); err != nil {
|
||||||
|
fail(err.Error())
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interactive fallback for missing fields
|
||||||
|
reader := bufio.NewReader(os.Stdin)
|
||||||
|
if opts.hostname == "" {
|
||||||
|
fmt.Print("Enter hostname: ")
|
||||||
|
s, _ := reader.ReadString('\n')
|
||||||
|
opts.hostname = strings.TrimSpace(s)
|
||||||
|
}
|
||||||
|
if err := validateHostname(opts.hostname); err != nil {
|
||||||
|
fail(err.Error())
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.ip == "" {
|
||||||
|
fmt.Print("Enter IP (10.8.0.x): ")
|
||||||
|
s, _ := reader.ReadString('\n')
|
||||||
|
opts.ip = strings.TrimSpace(s)
|
||||||
|
}
|
||||||
|
if err := validateIPHost(opts.ip); err != nil {
|
||||||
|
fail(err.Error())
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.iface == "" {
|
||||||
|
opts.iface = "wg0"
|
||||||
|
}
|
||||||
|
if opts.routing != "wg_only" && opts.routing != "full_tunnel" {
|
||||||
|
fail("routing must be wg_only or full_tunnel")
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.MkdirAll(opts.outDir, 0755); err != nil {
|
||||||
|
fail(err.Error())
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
priv, pub, err := generateKeys()
|
||||||
|
if err != nil {
|
||||||
|
fail(fmt.Sprintf("failed to generate keys: %v", err))
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build config
|
||||||
|
var b strings.Builder
|
||||||
|
// Header with public key and instructions for peers
|
||||||
|
b.WriteString("# ================================================\n")
|
||||||
|
b.WriteString("# Node: " + opts.hostname + "\n")
|
||||||
|
b.WriteString("# PublicKey: " + pub + "\n")
|
||||||
|
b.WriteString("#\n")
|
||||||
|
b.WriteString("# Add this peer to Zion (/etc/wireguard/wg0.conf):\n")
|
||||||
|
b.WriteString("# [Peer]\n")
|
||||||
|
b.WriteString("# PublicKey = " + pub + "\n")
|
||||||
|
b.WriteString("# AllowedIPs = " + opts.ip + "/32\n")
|
||||||
|
b.WriteString("# ================================================\n\n")
|
||||||
|
|
||||||
|
b.WriteString("[Interface]\n")
|
||||||
|
// Default /24
|
||||||
|
b.WriteString(fmt.Sprintf("Address = %s/24\n", opts.ip))
|
||||||
|
b.WriteString(fmt.Sprintf("PrivateKey = %s\n", priv))
|
||||||
|
if opts.routing == "full_tunnel" {
|
||||||
|
b.WriteString("DNS = 1.1.1.1, 8.8.8.8\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default Zion peer (from scripts)
|
||||||
|
b.WriteString("\n# Zion (central server)\n")
|
||||||
|
b.WriteString("[Peer]\n")
|
||||||
|
b.WriteString("PublicKey = 2ztJbrN1x1NWanzPGLiKL19ZkdOhm5Y7WeKEWBT5cyg=\n")
|
||||||
|
if opts.routing == "full_tunnel" {
|
||||||
|
b.WriteString("AllowedIPs = 0.0.0.0/0, ::/0\n")
|
||||||
|
} else {
|
||||||
|
b.WriteString("AllowedIPs = 10.8.0.0/24\n")
|
||||||
|
}
|
||||||
|
b.WriteString("Endpoint = ugh.im:51820\n")
|
||||||
|
b.WriteString("PersistentKeepalive = 25\n")
|
||||||
|
|
||||||
|
confFilename := fmt.Sprintf("%s_%s.conf", opts.hostname, opts.iface)
|
||||||
|
confPath := filepath.Join(opts.outDir, confFilename)
|
||||||
|
if _, err := os.Stat(confPath); err == nil && !(opts.force || opts.nonInteractive) {
|
||||||
|
warn(fmt.Sprintf("%s exists", confPath))
|
||||||
|
fmt.Print("Overwrite? (y/N): ")
|
||||||
|
ans, _ := reader.ReadString('\n')
|
||||||
|
ans = strings.ToLower(strings.TrimSpace(ans))
|
||||||
|
if ans != "y" && ans != "yes" {
|
||||||
|
fail("aborted")
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := os.WriteFile(confPath, []byte(b.String()), 0600); err != nil {
|
||||||
|
fail(err.Error())
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save keys for convenience
|
||||||
|
_ = os.WriteFile(filepath.Join(opts.outDir, opts.hostname+"_private.key"), []byte(priv), 0600)
|
||||||
|
if pub != "" {
|
||||||
|
_ = os.WriteFile(filepath.Join(opts.outDir, opts.hostname+"_public.key"), []byte(pub), 0600)
|
||||||
|
}
|
||||||
|
|
||||||
|
info(fmt.Sprintf("config written: %s", confPath))
|
||||||
|
info("set permissions: chmod 600 <file>")
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============= Validator (parity with validate_config.sh) =============
|
||||||
|
func validateConfigFile(path string) (int, int) {
|
||||||
|
data, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
fail(fmt.Sprintf("%s: %v", path, err))
|
||||||
|
return 1, 0
|
||||||
|
}
|
||||||
|
lines := strings.Split(string(data), "\n")
|
||||||
|
inInterface := false
|
||||||
|
inPeer := false
|
||||||
|
hasInterface := false
|
||||||
|
hasPriv := false
|
||||||
|
hasAddr := false
|
||||||
|
errs := 0
|
||||||
|
warns := 0
|
||||||
|
|
||||||
|
printPath := func() { head("Validating: " + path) }
|
||||||
|
printPath()
|
||||||
|
|
||||||
|
for _, raw := range lines {
|
||||||
|
line := strings.TrimSpace(raw)
|
||||||
|
if line == "" || strings.HasPrefix(line, "#") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if line == "[Interface]" {
|
||||||
|
inInterface, inPeer, hasInterface = true, false, true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if line == "[Peer]" {
|
||||||
|
inInterface, inPeer = false, true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if inInterface {
|
||||||
|
if strings.HasPrefix(line, "PrivateKey=") || strings.HasPrefix(line, "PrivateKey =") {
|
||||||
|
value := strings.TrimSpace(strings.TrimPrefix(strings.ReplaceAll(line, " ", ""), "PrivateKey="))
|
||||||
|
if validateWGKey(value) == nil {
|
||||||
|
info("valid private key")
|
||||||
|
} else {
|
||||||
|
fail("invalid private key")
|
||||||
|
errs++
|
||||||
|
}
|
||||||
|
if validateWGKey(value) == nil {
|
||||||
|
hasPriv = true
|
||||||
|
}
|
||||||
|
} else if strings.HasPrefix(line, "Address=") || strings.HasPrefix(line, "Address =") {
|
||||||
|
value := strings.TrimSpace(strings.TrimPrefix(strings.ReplaceAll(line, " ", ""), "Address="))
|
||||||
|
if validateCIDR(value) == nil {
|
||||||
|
info("valid address " + value)
|
||||||
|
} else {
|
||||||
|
fail("invalid address " + value)
|
||||||
|
errs++
|
||||||
|
}
|
||||||
|
if validateCIDR(value) == nil {
|
||||||
|
hasAddr = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if inPeer {
|
||||||
|
if strings.HasPrefix(line, "PublicKey=") || strings.HasPrefix(line, "PublicKey =") {
|
||||||
|
value := strings.TrimSpace(strings.TrimPrefix(strings.ReplaceAll(line, " ", ""), "PublicKey="))
|
||||||
|
if validateWGKey(value) == nil {
|
||||||
|
info("valid peer public key")
|
||||||
|
} else {
|
||||||
|
fail("invalid peer public key")
|
||||||
|
errs++
|
||||||
|
}
|
||||||
|
} else if strings.HasPrefix(line, "AllowedIPs=") || strings.HasPrefix(line, "AllowedIPs =") {
|
||||||
|
value := strings.TrimSpace(strings.TrimPrefix(strings.ReplaceAll(line, " ", ""), "AllowedIPs="))
|
||||||
|
ips := strings.Split(value, ",")
|
||||||
|
for _, ip := range ips {
|
||||||
|
if validateCIDR(strings.TrimSpace(ip)) == nil {
|
||||||
|
info("valid allowed IP " + strings.TrimSpace(ip))
|
||||||
|
} else {
|
||||||
|
fail("invalid allowed IP " + strings.TrimSpace(ip))
|
||||||
|
errs++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !hasInterface {
|
||||||
|
fail("missing [Interface] section")
|
||||||
|
errs++
|
||||||
|
}
|
||||||
|
if !hasPriv {
|
||||||
|
fail("missing PrivateKey in [Interface]")
|
||||||
|
errs++
|
||||||
|
}
|
||||||
|
if !hasAddr {
|
||||||
|
warn("missing Address in [Interface]")
|
||||||
|
warns++
|
||||||
|
}
|
||||||
|
|
||||||
|
if errs == 0 && warns == 0 {
|
||||||
|
info("file is valid")
|
||||||
|
}
|
||||||
|
return errs, warns
|
||||||
|
}
|
||||||
|
|
||||||
|
func runValidate(args []string) int {
|
||||||
|
fs := flag.NewFlagSet("validate", flag.ContinueOnError)
|
||||||
|
fs.SetOutput(new(strings.Builder))
|
||||||
|
var target string
|
||||||
|
fs.StringVar(&target, "target", "", "Config file or directory to validate")
|
||||||
|
if err := fs.Parse(args); err != nil {
|
||||||
|
fail(err.Error())
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
if target == "" {
|
||||||
|
if fs.NArg() > 0 {
|
||||||
|
target = fs.Arg(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if target == "" {
|
||||||
|
fail("provide a file or directory via --target or arg")
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
st, err := os.Stat(target)
|
||||||
|
if err != nil {
|
||||||
|
fail(err.Error())
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
if st.Mode().IsRegular() {
|
||||||
|
errs, _ := validateConfigFile(target)
|
||||||
|
if errs > 0 {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
if st.IsDir() {
|
||||||
|
totalErr := 0
|
||||||
|
_ = filepath.Walk(target, func(path string, info os.FileInfo, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if info.IsDir() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if strings.HasSuffix(strings.ToLower(info.Name()), ".conf") {
|
||||||
|
e, _ := validateConfigFile(path)
|
||||||
|
totalErr += e
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if totalErr > 0 {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
fail("target must be file or directory")
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============= Zion peer snippet =============
|
||||||
|
func runZionPeer(args []string) int {
|
||||||
|
fs := flag.NewFlagSet("zion-peer", flag.ContinueOnError)
|
||||||
|
fs.SetOutput(new(strings.Builder))
|
||||||
|
var name, pub, ip string
|
||||||
|
fs.StringVar(&name, "name", "", "Node name")
|
||||||
|
fs.StringVar(&pub, "pub", "", "WireGuard public key")
|
||||||
|
fs.StringVar(&ip, "ip", "", "Node IP (10.8.0.x)")
|
||||||
|
if err := fs.Parse(args); err != nil {
|
||||||
|
fail(err.Error())
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
if name == "" || pub == "" || ip == "" {
|
||||||
|
fail("--name, --pub and --ip are required")
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
if err := validateHostname(name); err != nil {
|
||||||
|
fail(err.Error())
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
if err := validateWGKey(pub); err != nil {
|
||||||
|
fail(err.Error())
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
if err := validateIPHost(ip); err != nil {
|
||||||
|
fail(err.Error())
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
head("Add the following to Zion's /etc/wireguard/wg0.conf")
|
||||||
|
fmt.Println("# " + name)
|
||||||
|
fmt.Println("[Peer]")
|
||||||
|
fmt.Println("PublicKey = " + pub)
|
||||||
|
fmt.Println("AllowedIPs = " + ip + "/32")
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============= Keys only =============
|
||||||
|
func runKeys(args []string) int {
|
||||||
|
fs := flag.NewFlagSet("keys", flag.ContinueOnError)
|
||||||
|
fs.SetOutput(new(strings.Builder))
|
||||||
|
if err := fs.Parse(args); err != nil {
|
||||||
|
fail(err.Error())
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
priv, _, err := generateKeys()
|
||||||
|
if err != nil {
|
||||||
|
fail(err.Error())
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
fmt.Println("PrivateKey:", priv)
|
||||||
|
fmt.Println("(Use 'wg pubkey' to derive PublicKey safely)")
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============= Main =============
|
||||||
|
func main() {
|
||||||
|
if len(os.Args) < 2 {
|
||||||
|
fmt.Printf("wgtool %s\n", toolVersion)
|
||||||
|
fmt.Println("Commands: generate, validate, zion-peer, keys, version")
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
sub := os.Args[1]
|
||||||
|
args := os.Args[2:]
|
||||||
|
switch sub {
|
||||||
|
case "generate":
|
||||||
|
os.Exit(runGenerate(args))
|
||||||
|
case "validate":
|
||||||
|
os.Exit(runValidate(args))
|
||||||
|
case "zion-peer":
|
||||||
|
os.Exit(runZionPeer(args))
|
||||||
|
case "keys":
|
||||||
|
os.Exit(runKeys(args))
|
||||||
|
case "version", "--version", "-v":
|
||||||
|
fmt.Println("wgtool", toolVersion)
|
||||||
|
os.Exit(0)
|
||||||
|
default:
|
||||||
|
fail("unknown command: " + sub)
|
||||||
|
fmt.Println("Available: generate, validate, zion-peer, keys, version")
|
||||||
|
os.Exit(2)
|
||||||
|
}
|
||||||
|
}
|
||||||
1
cmd/wgtool/wireguard_configs/janus_private.key
Normal file
1
cmd/wgtool/wireguard_configs/janus_private.key
Normal file
@@ -0,0 +1 @@
|
|||||||
|
eGcfpLXTadC99k7rj8G07zrDLarKoolA30lMYo/MSG0=
|
||||||
1
cmd/wgtool/wireguard_configs/janus_public.key
Normal file
1
cmd/wgtool/wireguard_configs/janus_public.key
Normal file
@@ -0,0 +1 @@
|
|||||||
|
ltEo/ohm4EvJyXhFtnHPjHrpOW3v5mwxgw9m9uzjNmE=
|
||||||
20
cmd/wgtool/wireguard_configs/janus_wg0.conf
Normal file
20
cmd/wgtool/wireguard_configs/janus_wg0.conf
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# ================================================
|
||||||
|
# Node: janus
|
||||||
|
# PublicKey: ltEo/ohm4EvJyXhFtnHPjHrpOW3v5mwxgw9m9uzjNmE=
|
||||||
|
#
|
||||||
|
# Add this peer to Zion (/etc/wireguard/wg0.conf):
|
||||||
|
# [Peer]
|
||||||
|
# PublicKey = ltEo/ohm4EvJyXhFtnHPjHrpOW3v5mwxgw9m9uzjNmE=
|
||||||
|
# AllowedIPs = 10.8.0.250/32
|
||||||
|
# ================================================
|
||||||
|
|
||||||
|
[Interface]
|
||||||
|
Address = 10.8.0.250/24
|
||||||
|
PrivateKey = eGcfpLXTadC99k7rj8G07zrDLarKoolA30lMYo/MSG0=
|
||||||
|
|
||||||
|
# Zion (central server)
|
||||||
|
[Peer]
|
||||||
|
PublicKey = 2ztJbrN1x1NWanzPGLiKL19ZkdOhm5Y7WeKEWBT5cyg=
|
||||||
|
AllowedIPs = 0.0.0.0/0
|
||||||
|
Endpoint = ugh.im:51820
|
||||||
|
PersistentKeepalive = 25
|
||||||
1
cmd/wgtool/wireguard_configs/mawlz_private.key
Normal file
1
cmd/wgtool/wireguard_configs/mawlz_private.key
Normal file
@@ -0,0 +1 @@
|
|||||||
|
OB4zaSdrZkSgtQZUQlkSB9x++RQAvxgOSEHEUswY6Hs=
|
||||||
1
cmd/wgtool/wireguard_configs/mawlz_public.key
Normal file
1
cmd/wgtool/wireguard_configs/mawlz_public.key
Normal file
@@ -0,0 +1 @@
|
|||||||
|
tVHvPWUDAd3xhoZKo0iJ5G5wOIQIdGNNXDG0cV0djxo=
|
||||||
20
cmd/wgtool/wireguard_configs/mawlz_wg0.conf
Normal file
20
cmd/wgtool/wireguard_configs/mawlz_wg0.conf
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# ================================================
|
||||||
|
# Node: mawlz
|
||||||
|
# PublicKey: tVHvPWUDAd3xhoZKo0iJ5G5wOIQIdGNNXDG0cV0djxo=
|
||||||
|
#
|
||||||
|
# Add this peer to Zion (/etc/wireguard/wg0.conf):
|
||||||
|
# [Peer]
|
||||||
|
# PublicKey = tVHvPWUDAd3xhoZKo0iJ5G5wOIQIdGNNXDG0cV0djxo=
|
||||||
|
# AllowedIPs = 10.8.0.16/32
|
||||||
|
# ================================================
|
||||||
|
|
||||||
|
[Interface]
|
||||||
|
Address = 10.8.0.16/24
|
||||||
|
PrivateKey = OB4zaSdrZkSgtQZUQlkSB9x++RQAvxgOSEHEUswY6Hs=
|
||||||
|
|
||||||
|
# Zion (central server)
|
||||||
|
[Peer]
|
||||||
|
PublicKey = 2ztJbrN1x1NWanzPGLiKL19ZkdOhm5Y7WeKEWBT5cyg=
|
||||||
|
AllowedIPs = 10.8.0.0/24
|
||||||
|
Endpoint = ugh.im:51820
|
||||||
|
PersistentKeepalive = 25
|
||||||
1
cmd/wgtool/wireguard_configs/morph_private.key
Normal file
1
cmd/wgtool/wireguard_configs/morph_private.key
Normal file
@@ -0,0 +1 @@
|
|||||||
|
6H0y0Cov9x65ctmjz5IHFD9DIMlWZeYlxh3BZVlDHkU=
|
||||||
1
cmd/wgtool/wireguard_configs/morph_public.key
Normal file
1
cmd/wgtool/wireguard_configs/morph_public.key
Normal file
@@ -0,0 +1 @@
|
|||||||
|
oNVVqJZoL6AY/0bDl5EPEfW62v0zptK4Bk5BnBEFJwE=
|
||||||
27
cmd/wgtool/wireguard_configs/morph_wg0.conf
Normal file
27
cmd/wgtool/wireguard_configs/morph_wg0.conf
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# ================================================
|
||||||
|
# Node: morph
|
||||||
|
# PublicKey: oNVVqJZoL6AY/0bDl5EPEfW62v0zptK4Bk5BnBEFJwE=
|
||||||
|
#
|
||||||
|
# Add this peer to Zion (/etc/wireguard/wg0.conf):
|
||||||
|
# [Peer]
|
||||||
|
# PublicKey = oNVVqJZoL6AY/0bDl5EPEfW62v0zptK4Bk5BnBEFJwE=
|
||||||
|
# AllowedIPs = 10.8.0.21/32
|
||||||
|
# ================================================
|
||||||
|
|
||||||
|
[Interface]
|
||||||
|
Address = 10.8.0.21/24
|
||||||
|
PrivateKey = 6H0y0Cov9x65ctmjz5IHFD9DIMlWZeYlxh3BZVlDHkU=
|
||||||
|
|
||||||
|
#CTH
|
||||||
|
[Peer]
|
||||||
|
PublicKey = NBktXKy1s0n2lIlIMODvOqKNwAtYdoZH5feKt5P43i0=
|
||||||
|
AllowedIPs = 10.8.0.10/32
|
||||||
|
Endpoint = aw2cd67.glddns.com:53535
|
||||||
|
PersistentKeepalive = 25
|
||||||
|
|
||||||
|
# Zion (central server)
|
||||||
|
#[Peer]
|
||||||
|
#PublicKey = 2ztJbrN1x1NWanzPGLiKL19ZkdOhm5Y7WeKEWBT5cyg=
|
||||||
|
#AllowedIPs = 10.8.0.0/24
|
||||||
|
#Endpoint = ugh.im:51820
|
||||||
|
#PersistentKeepalive = 25
|
||||||
1
cmd/wgtool/wireguard_configs/morpheus_private.key
Normal file
1
cmd/wgtool/wireguard_configs/morpheus_private.key
Normal file
@@ -0,0 +1 @@
|
|||||||
|
eBQiIcOLaM4A2jgRHUjWrQtev+jR0l4ZjF3GMfOXQ0M=
|
||||||
1
cmd/wgtool/wireguard_configs/virtual_private.key
Normal file
1
cmd/wgtool/wireguard_configs/virtual_private.key
Normal file
@@ -0,0 +1 @@
|
|||||||
|
4CVAy2F3QlKZnHV+6fo4GM/cuGt3XU6BElq11IzfJ3w=
|
||||||
1
cmd/wgtool/wireguard_configs/virtual_public.key
Normal file
1
cmd/wgtool/wireguard_configs/virtual_public.key
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Wk099hP8kJ3wRgOwo+QCiaDTR1tSDdYwM5E9qI6Cw0w=
|
||||||
20
cmd/wgtool/wireguard_configs/virtual_wg0.conf
Normal file
20
cmd/wgtool/wireguard_configs/virtual_wg0.conf
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# ================================================
|
||||||
|
# Node: virtual
|
||||||
|
# PublicKey: Wk099hP8kJ3wRgOwo+QCiaDTR1tSDdYwM5E9qI6Cw0w=
|
||||||
|
#
|
||||||
|
# Add this peer to Zion (/etc/wireguard/wg0.conf):
|
||||||
|
# [Peer]
|
||||||
|
# PublicKey = Wk099hP8kJ3wRgOwo+QCiaDTR1tSDdYwM5E9qI6Cw0w=
|
||||||
|
# AllowedIPs = 10.8.0.94/32
|
||||||
|
# ================================================
|
||||||
|
|
||||||
|
[Interface]
|
||||||
|
Address = 10.8.0.94/24
|
||||||
|
PrivateKey = 4CVAy2F3QlKZnHV+6fo4GM/cuGt3XU6BElq11IzfJ3w=
|
||||||
|
|
||||||
|
# Zion (central server)
|
||||||
|
[Peer]
|
||||||
|
PublicKey = 2ztJbrN1x1NWanzPGLiKL19ZkdOhm5Y7WeKEWBT5cyg=
|
||||||
|
AllowedIPs = 10.8.0.0/24
|
||||||
|
Endpoint = ugh.im:51820
|
||||||
|
PersistentKeepalive = 25
|
||||||
20
cmd/wgtool/wireguard_configs/wg0.conf
Normal file
20
cmd/wgtool/wireguard_configs/wg0.conf
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# ================================================
|
||||||
|
# Node: morph
|
||||||
|
# PublicKey: 49bN/KGsiqFmHxItli8ySiDPgeTc9Lh+vQA4BJBa/2k=
|
||||||
|
#
|
||||||
|
# Add this peer to Zion (/etc/wireguard/wg0.conf):
|
||||||
|
# [Peer]
|
||||||
|
# PublicKey = 49bN/KGsiqFmHxItli8ySiDPgeTc9Lh+vQA4BJBa/2k=
|
||||||
|
# AllowedIPs = 10.8.0.21/32
|
||||||
|
# ================================================
|
||||||
|
|
||||||
|
[Interface]
|
||||||
|
Address = 10.8.0.21/24
|
||||||
|
PrivateKey = YLMDjNlIevvmoK7dpsRVe3iIce/JdZg7aSZAJcEwWlE=
|
||||||
|
|
||||||
|
# Zion (central server)
|
||||||
|
[Peer]
|
||||||
|
PublicKey = 2ztJbrN1x1NWanzPGLiKL19ZkdOhm5Y7WeKEWBT5cyg=
|
||||||
|
AllowedIPs = 10.8.0.0/24
|
||||||
|
Endpoint = ugh.im:51820
|
||||||
|
PersistentKeepalive = 25
|
||||||
105
example_setup.sh
Executable file
105
example_setup.sh
Executable file
@@ -0,0 +1,105 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Example WireGuard Setup Script
|
||||||
|
# This demonstrates how to use the main setup script with predefined values
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
NC='\033[0m'
|
||||||
|
|
||||||
|
print_status() {
|
||||||
|
echo -e "${GREEN}[INFO]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_header() {
|
||||||
|
echo -e "${BLUE}================================${NC}"
|
||||||
|
echo -e "${BLUE}$1${NC}"
|
||||||
|
echo -e "${BLUE}================================${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Example: Creating a client configuration similar to aza.conf
|
||||||
|
create_client_example() {
|
||||||
|
print_header "Creating Client Configuration Example"
|
||||||
|
|
||||||
|
# Create a temporary input file for the main script
|
||||||
|
cat > /tmp/wg_input.txt << 'EOF'
|
||||||
|
test_client
|
||||||
|
10.8.0.5/24
|
||||||
|
n
|
||||||
|
y
|
||||||
|
n
|
||||||
|
EOF
|
||||||
|
|
||||||
|
print_status "Running setup script with client configuration..."
|
||||||
|
echo "This will create a client configuration similar to aza.conf"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Run the main script with the example inputs
|
||||||
|
./wireguard_setup.sh < /tmp/wg_input.txt
|
||||||
|
|
||||||
|
# Clean up
|
||||||
|
rm -f /tmp/wg_input.txt
|
||||||
|
|
||||||
|
print_status "Client example configuration created!"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Example: Creating a server configuration similar to zion.conf
|
||||||
|
create_server_example() {
|
||||||
|
print_header "Creating Server Configuration Example"
|
||||||
|
|
||||||
|
# Create a temporary input file for the main script
|
||||||
|
cat > /tmp/wg_input.txt << 'EOF'
|
||||||
|
test_server
|
||||||
|
10.8.0.1/24
|
||||||
|
y
|
||||||
|
51820
|
||||||
|
n
|
||||||
|
EOF
|
||||||
|
|
||||||
|
print_status "Running setup script with server configuration..."
|
||||||
|
echo "This will create a server configuration similar to zion.conf"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Run the main script with the example inputs
|
||||||
|
./wireguard_setup.sh < /tmp/wg_input.txt
|
||||||
|
|
||||||
|
# Clean up
|
||||||
|
rm -f /tmp/wg_input.txt
|
||||||
|
|
||||||
|
print_status "Server example configuration created!"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Show usage
|
||||||
|
show_usage() {
|
||||||
|
echo "Usage: $0 [OPTION]"
|
||||||
|
echo ""
|
||||||
|
echo "Options:"
|
||||||
|
echo " client Create a client configuration example"
|
||||||
|
echo " server Create a server configuration example"
|
||||||
|
echo " help Show this help message"
|
||||||
|
echo ""
|
||||||
|
echo "Examples:"
|
||||||
|
echo " $0 client # Creates a client config like aza.conf"
|
||||||
|
echo " $0 server # Creates a server config like zion.conf"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main logic
|
||||||
|
case "${1:-help}" in
|
||||||
|
client)
|
||||||
|
create_client_example
|
||||||
|
;;
|
||||||
|
server)
|
||||||
|
create_server_example
|
||||||
|
;;
|
||||||
|
help|--help|-h)
|
||||||
|
show_usage
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
print_error "Unknown option: $1"
|
||||||
|
show_usage
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
223
generate_zion_peer.sh
Executable file
223
generate_zion_peer.sh
Executable file
@@ -0,0 +1,223 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Zion Peer Configuration Generator
|
||||||
|
# This script generates the exact peer configuration needed for Zion
|
||||||
|
|
||||||
|
set -euo pipefail # Exit on error, undefined vars, pipe failures
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
NC='\033[0m'
|
||||||
|
|
||||||
|
# Configuration file for peer information
|
||||||
|
CONFIG_FILE="$(dirname "$0")/CURRENT_WORKING/zion.conf"
|
||||||
|
|
||||||
|
print_status() {
|
||||||
|
echo -e "${GREEN}[INFO]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_warning() {
|
||||||
|
echo -e "${YELLOW}[WARNING]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_error() {
|
||||||
|
echo -e "${RED}[ERROR]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_header() {
|
||||||
|
echo -e "${BLUE}================================${NC}"
|
||||||
|
echo -e "${BLUE}Zion Peer Configuration Generator${NC}"
|
||||||
|
echo -e "${BLUE}================================${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Validate IP address format and range
|
||||||
|
validate_ip() {
|
||||||
|
local ip="$1"
|
||||||
|
|
||||||
|
# Check basic format
|
||||||
|
if [[ ! $ip =~ ^10\.8\.0\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$ ]]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Extract last octet
|
||||||
|
local last_octet="${ip##*.}"
|
||||||
|
|
||||||
|
# Check if IP is in reserved ranges
|
||||||
|
if [[ $last_octet -eq 0 ]] || [[ $last_octet -eq 1 ]] || [[ $last_octet -eq 255 ]]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Validate WireGuard public key format
|
||||||
|
validate_public_key() {
|
||||||
|
local key="$1"
|
||||||
|
|
||||||
|
# WireGuard keys are base64 encoded and exactly 44 characters long
|
||||||
|
if [[ ! $key =~ ^[A-Za-z0-9+/]{43}=$ ]]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Load Zion configuration if available
|
||||||
|
load_zion_config() {
|
||||||
|
if [[ -f "$CONFIG_FILE" ]]; then
|
||||||
|
print_status "Found Zion configuration file: $CONFIG_FILE"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
print_warning "Zion configuration file not found: $CONFIG_FILE"
|
||||||
|
print_warning "Using hardcoded peer information"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
show_usage() {
|
||||||
|
echo "Usage: $0 <node_name> <public_key> <ip_address>"
|
||||||
|
echo ""
|
||||||
|
echo "Arguments:"
|
||||||
|
echo " node_name - Name of the node (e.g., mynode)"
|
||||||
|
echo " public_key - WireGuard public key (base64 encoded)"
|
||||||
|
echo " ip_address - IP address in 10.8.0.x format"
|
||||||
|
echo ""
|
||||||
|
echo "Example:"
|
||||||
|
echo " $0 mynode ABC123... 10.8.0.30"
|
||||||
|
echo ""
|
||||||
|
echo "This will generate the peer configuration to add to Zion's /etc/wireguard/wg0.conf"
|
||||||
|
echo ""
|
||||||
|
echo "Options:"
|
||||||
|
echo " -c, --config FILE Use custom Zion config file"
|
||||||
|
echo " -h, --help Show this help message"
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
local config_file="$CONFIG_FILE"
|
||||||
|
|
||||||
|
# Parse command line options
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case $1 in
|
||||||
|
-c|--config)
|
||||||
|
config_file="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-h|--help)
|
||||||
|
show_usage
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
-*)
|
||||||
|
print_error "Unknown option: $1"
|
||||||
|
show_usage
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
print_header
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
if [[ $# -ne 3 ]]; then
|
||||||
|
print_error "Incorrect number of arguments"
|
||||||
|
show_usage
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local NODE_NAME="$1"
|
||||||
|
local PUBLIC_KEY="$2"
|
||||||
|
local IP_ADDRESS="$3"
|
||||||
|
|
||||||
|
# Validate node name
|
||||||
|
if [[ ! $NODE_NAME =~ ^[a-zA-Z0-9][a-zA-Z0-9_-]*[a-zA-Z0-9]$ ]] && [[ $NODE_NAME != [a-zA-Z0-9] ]]; then
|
||||||
|
print_error "Invalid node name format. Use alphanumeric characters, hyphens, and underscores only"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Validate IP address
|
||||||
|
if ! validate_ip "$IP_ADDRESS"; then
|
||||||
|
print_error "IP address must be in 10.8.0.x format (x cannot be 0, 1, or 255)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Validate public key
|
||||||
|
if ! validate_public_key "$PUBLIC_KEY"; then
|
||||||
|
print_error "Invalid WireGuard public key format"
|
||||||
|
print_error "Expected: 44 character base64 string ending with ="
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_status "Generating Zion peer configuration for: $NODE_NAME"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
echo "Add the following to Zion's /etc/wireguard/wg0.conf:"
|
||||||
|
echo "----------------------------------------"
|
||||||
|
echo "# $NODE_NAME"
|
||||||
|
echo "[Peer]"
|
||||||
|
echo "PublicKey = $PUBLIC_KEY"
|
||||||
|
echo "AllowedIPs = $IP_ADDRESS/32"
|
||||||
|
echo "----------------------------------------"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
print_warning "After adding this to Zion's config:"
|
||||||
|
echo "1. Save the file"
|
||||||
|
echo "2. Restart Zion's WireGuard: sudo systemctl restart wg-quick@wg0"
|
||||||
|
echo "3. Start the new node's WireGuard: sudo wg-quick up $NODE_NAME"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Try to load Zion config, fall back to hardcoded if not available
|
||||||
|
if ! load_zion_config; then
|
||||||
|
# Show hardcoded peer structure
|
||||||
|
echo "Zion's current peer structure (add your peer at the end):"
|
||||||
|
echo "----------------------------------------"
|
||||||
|
echo "#Cth"
|
||||||
|
echo "[Peer]"
|
||||||
|
echo "PublicKey = NBktXKy1s0n2lIlIMODvOqKNwAtYdoZH5feKt5P43i0="
|
||||||
|
echo "AllowedIPs = 10.8.0.10/32"
|
||||||
|
echo ""
|
||||||
|
echo "#Aza"
|
||||||
|
echo "[Peer]"
|
||||||
|
echo "PublicKey = qmTKA257DLOrfhk5Zw8RyRmBSonmm6epbloT0P0ZWDc="
|
||||||
|
echo "AllowedIPs = 10.8.0.2/32"
|
||||||
|
echo ""
|
||||||
|
echo "#Nyar"
|
||||||
|
echo "[Peer]"
|
||||||
|
echo "PublicKey = 2BA7L1oJP1tK6dIUNHMgcZmOmYmlyPRe2RaBqfUsEWo="
|
||||||
|
echo "AllowedIPs = 10.8.0.20/32"
|
||||||
|
echo ""
|
||||||
|
echo "#Galaxy"
|
||||||
|
echo "[Peer]"
|
||||||
|
echo "PublicKey = QBNt00VSedxPlq3ZvsdYaqIcbudCAyxv9TG65aPVZzM="
|
||||||
|
echo "AllowedIPs = 10.8.0.99/32"
|
||||||
|
echo ""
|
||||||
|
echo "# Add your peer here:"
|
||||||
|
echo "# $NODE_NAME"
|
||||||
|
echo "# [Peer]"
|
||||||
|
echo "# PublicKey = $PUBLIC_KEY"
|
||||||
|
echo "# AllowedIPs = $IP_ADDRESS/32"
|
||||||
|
echo "----------------------------------------"
|
||||||
|
else
|
||||||
|
# Parse and display current peers from config file
|
||||||
|
print_status "Current peers in Zion configuration:"
|
||||||
|
echo "----------------------------------------"
|
||||||
|
if grep -E "^#.*" "$config_file" | grep -E "^#[A-Za-z]" | head -10; then
|
||||||
|
echo ""
|
||||||
|
echo "# Add your peer here:"
|
||||||
|
echo "# $NODE_NAME"
|
||||||
|
echo "# [Peer]"
|
||||||
|
echo "# PublicKey = $PUBLIC_KEY"
|
||||||
|
echo "# AllowedIPs = $IP_ADDRESS/32"
|
||||||
|
else
|
||||||
|
print_warning "No peer sections found in Zion config"
|
||||||
|
fi
|
||||||
|
echo "----------------------------------------"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Run main function
|
||||||
|
main "$@"
|
||||||
5
go.mod
Normal file
5
go.mod
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
module wireguard-setup
|
||||||
|
|
||||||
|
go 1.24.5
|
||||||
|
|
||||||
|
require golang.org/x/crypto v0.40.0
|
||||||
2
go.sum
Normal file
2
go.sum
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
|
||||||
|
golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
|
||||||
206
scripting/README.md
Normal file
206
scripting/README.md
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
# NPM Log Analysis Tools
|
||||||
|
|
||||||
|
High-performance security analysis tools for NPM (Nginx Proxy Manager) logs.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This repository contains two versions of the NPM log analyzer:
|
||||||
|
|
||||||
|
1. **Bash Version** (`npm-log-analyzer.sh`) - Interactive menu-driven tool
|
||||||
|
2. **Go Version** (`npm-log-analyzer.go`) - High-performance command-line tool
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
### Security Pattern Detection
|
||||||
|
- **Critical Attacks**: SQL injection, XSS, shell/RCE, webshell uploads
|
||||||
|
- **High Priority**: Path traversal, WordPress hunting, backup harvesting
|
||||||
|
- **Reconnaissance**: Robots.txt requests, vulnerability scanners, error spam
|
||||||
|
- **Advanced**: SSRF, LFI/RFI, deserialization, template injection
|
||||||
|
|
||||||
|
### Analysis Capabilities
|
||||||
|
- Real-time log processing
|
||||||
|
- IP address analysis and geolocation
|
||||||
|
- Attack pattern counting and categorization
|
||||||
|
- Comprehensive reporting
|
||||||
|
- Performance optimization for large log files
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
### Go Version (Recommended)
|
||||||
|
```bash
|
||||||
|
# Build and run
|
||||||
|
make go
|
||||||
|
|
||||||
|
# Or manually
|
||||||
|
go build -o npm-log-analyzer-go npm-log-analyzer.go
|
||||||
|
./npm-log-analyzer-go
|
||||||
|
```
|
||||||
|
|
||||||
|
### Bash Version
|
||||||
|
```bash
|
||||||
|
# Make executable and run
|
||||||
|
chmod +x npm-log-analyzer.sh
|
||||||
|
./npm-log-analyzer.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
## Performance Comparison
|
||||||
|
|
||||||
|
| Feature | Go Version | Bash Version |
|
||||||
|
|---------|------------|--------------|
|
||||||
|
| **Speed** | ~85 seconds for 260MB logs | ~2-3 minutes |
|
||||||
|
| **Memory** | Efficient streaming | Higher memory usage |
|
||||||
|
| **Features** | Command-line focused | Interactive menu |
|
||||||
|
| **Dependencies** | Single binary | Requires bash, grep, etc. |
|
||||||
|
| **Gzip Support** | ✅ Native | ❌ Limited |
|
||||||
|
|
||||||
|
## Recent Analysis Results
|
||||||
|
|
||||||
|
From the latest Go analysis (260MB of logs):
|
||||||
|
|
||||||
|
### Critical Findings
|
||||||
|
- **SQL Injection Attempts**: 378
|
||||||
|
- **Shell/RCE Attempts**: 2,693
|
||||||
|
- **Error Spam (404/403)**: 4,855
|
||||||
|
|
||||||
|
### Top Attack Sources
|
||||||
|
- **169.150.203.13**: 45,278 requests (suspicious high volume)
|
||||||
|
- **135.181.143.221**: 9,229 requests
|
||||||
|
- **97.120.203.58**: 3,405 requests
|
||||||
|
|
||||||
|
### Analysis Statistics
|
||||||
|
- **Processed Files**: 98
|
||||||
|
- **Total Lines**: 105,568
|
||||||
|
- **Unique IPs**: 959
|
||||||
|
- **Duration**: ~85 seconds
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
### Log Directory
|
||||||
|
Both tools expect NPM logs at: `/opt/stacks/npm/data/logs`
|
||||||
|
|
||||||
|
### Output Directory
|
||||||
|
Reports are saved to: `./npmlogs`
|
||||||
|
|
||||||
|
### Attack Patterns
|
||||||
|
Patterns are defined in the source code and can be customized:
|
||||||
|
|
||||||
|
```go
|
||||||
|
// Go version
|
||||||
|
var AttackPatterns = map[string]string{
|
||||||
|
"sql_injection": `union|select|insert|drop|delete`,
|
||||||
|
"xss": `<script|javascript:|onload=|onerror=`,
|
||||||
|
// ... more patterns
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Bash version
|
||||||
|
declare -A ATTACK_PATTERNS=(
|
||||||
|
["sql_injection"]="union|select|insert|drop|delete"
|
||||||
|
["xss"]="<script|javascript:|onload=|onerror="
|
||||||
|
# ... more patterns
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage Examples
|
||||||
|
|
||||||
|
### Go Version
|
||||||
|
```bash
|
||||||
|
# Quick analysis
|
||||||
|
./npm-log-analyzer-go
|
||||||
|
|
||||||
|
# Build for different platforms
|
||||||
|
GOOS=linux GOARCH=amd64 go build -o npm-analyzer-linux npm-log-analyzer.go
|
||||||
|
```
|
||||||
|
|
||||||
|
### Bash Version
|
||||||
|
```bash
|
||||||
|
# Interactive menu
|
||||||
|
./npm-log-analyzer.sh
|
||||||
|
|
||||||
|
# Quick analysis only
|
||||||
|
echo "1" | ./npm-log-analyzer.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
## Makefile Targets
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make build-go # Build Go version
|
||||||
|
make run-go # Build and run Go version
|
||||||
|
make go # Alias for run-go
|
||||||
|
make run-bash # Run Bash version
|
||||||
|
make bash # Alias for run-bash
|
||||||
|
make benchmark # Compare performance
|
||||||
|
make clean # Clean build artifacts
|
||||||
|
make help # Show all targets
|
||||||
|
```
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
### Go Version
|
||||||
|
- Go 1.16+ (for native gzip support)
|
||||||
|
- No external dependencies
|
||||||
|
|
||||||
|
### Bash Version
|
||||||
|
- Bash 4.0+
|
||||||
|
- grep, find, awk, curl
|
||||||
|
- Read access to `/opt/stacks/npm/data/logs`
|
||||||
|
|
||||||
|
## Security Considerations
|
||||||
|
|
||||||
|
1. **Log Access**: Both tools require read access to NPM logs
|
||||||
|
2. **Network Access**: IP geolocation requires internet access (optional)
|
||||||
|
3. **File Permissions**: Output directories need write permissions
|
||||||
|
4. **Large Files**: Processing 260MB+ logs requires sufficient memory
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Common Issues
|
||||||
|
|
||||||
|
**"Log directory not accessible"**
|
||||||
|
```bash
|
||||||
|
# Check if NPM is running
|
||||||
|
ls -la /opt/stacks/npm/data/logs/
|
||||||
|
|
||||||
|
# Check permissions
|
||||||
|
sudo ls -la /opt/stacks/npm/data/logs/
|
||||||
|
```
|
||||||
|
|
||||||
|
**"No output generated"**
|
||||||
|
- Large log files take time to process
|
||||||
|
- Go version is much faster for large files
|
||||||
|
- Check available memory and disk space
|
||||||
|
|
||||||
|
**"Permission denied"**
|
||||||
|
```bash
|
||||||
|
# Make scripts executable
|
||||||
|
chmod +x npm-log-analyzer.sh
|
||||||
|
chmod +x npm-log-analyzer-go
|
||||||
|
|
||||||
|
# Check output directory permissions
|
||||||
|
mkdir -p ./npmlogs
|
||||||
|
chmod 755 ./npmlogs
|
||||||
|
```
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
### Adding New Patterns
|
||||||
|
1. Edit the pattern definitions in the source code
|
||||||
|
2. Test with sample log data
|
||||||
|
3. Update documentation
|
||||||
|
|
||||||
|
### Performance Optimization
|
||||||
|
- Go version uses buffered I/O and streaming
|
||||||
|
- Bash version uses grep with timeouts
|
||||||
|
- Both versions filter internal IPs automatically
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This project is open source. Feel free to modify and distribute.
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
1. Test both versions with your log data
|
||||||
|
2. Report any issues or performance problems
|
||||||
|
3. Suggest new attack patterns or features
|
||||||
|
4. Submit pull requests for improvements
|
||||||
101
scripting/ROUTING_MODE_DOCUMENTATION.md
Normal file
101
scripting/ROUTING_MODE_DOCUMENTATION.md
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
# WireGuard Easy Setup - Routing Mode Documentation
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
The `wgez-setup.sh` script now supports two different traffic routing modes:
|
||||||
|
|
||||||
|
1. **WireGuard-only mode** (default)
|
||||||
|
2. **Full tunnel mode**
|
||||||
|
|
||||||
|
## Routing Modes
|
||||||
|
|
||||||
|
### WireGuard-only Mode
|
||||||
|
- **Purpose**: Only route WireGuard network traffic (10.8.0.x) through the VPN
|
||||||
|
- **AllowedIPs**: `10.8.0.0/24`
|
||||||
|
- **DNS**: None (uses system DNS)
|
||||||
|
- **Internet Traffic**: Bypasses VPN, uses regular internet connection
|
||||||
|
- **Use Case**: When you want to access WireGuard network resources but keep regular internet traffic separate
|
||||||
|
|
||||||
|
### Full Tunnel Mode
|
||||||
|
- **Purpose**: Route ALL internet traffic through the VPN
|
||||||
|
- **AllowedIPs**: `0.0.0.0/0, ::/0`
|
||||||
|
- **DNS**: `1.1.1.1, 8.8.8.8` (Cloudflare and Google DNS)
|
||||||
|
- **Internet Traffic**: All traffic goes through VPN
|
||||||
|
- **Use Case**: When you want complete privacy/anonymity or need to bypass network restrictions
|
||||||
|
|
||||||
|
## Configuration Differences
|
||||||
|
|
||||||
|
### WireGuard-only Configuration
|
||||||
|
```ini
|
||||||
|
[Interface]
|
||||||
|
Address = 10.8.0.6/24
|
||||||
|
PrivateKey = <private_key>
|
||||||
|
|
||||||
|
[Peer]
|
||||||
|
PublicKey = <zion_public_key>
|
||||||
|
AllowedIPs = 10.8.0.0/24
|
||||||
|
Endpoint = ugh.im:51820
|
||||||
|
PersistentKeepalive = 60
|
||||||
|
```
|
||||||
|
|
||||||
|
### Full Tunnel Configuration
|
||||||
|
```ini
|
||||||
|
[Interface]
|
||||||
|
Address = 10.8.0.6/24
|
||||||
|
PrivateKey = <private_key>
|
||||||
|
DNS = 1.1.1.1, 8.8.8.8
|
||||||
|
|
||||||
|
[Peer]
|
||||||
|
PublicKey = <zion_public_key>
|
||||||
|
AllowedIPs = 0.0.0.0/0, ::/0
|
||||||
|
Endpoint = ugh.im:51820
|
||||||
|
PersistentKeepalive = 60
|
||||||
|
```
|
||||||
|
|
||||||
|
## Endpoint Requirements
|
||||||
|
|
||||||
|
### WireGuard-only Mode
|
||||||
|
- **Zion Server**: No special requirements
|
||||||
|
- **Client**: Standard WireGuard configuration
|
||||||
|
|
||||||
|
### Full Tunnel Mode
|
||||||
|
- **Zion Server**: Must have proper NAT/iptables rules
|
||||||
|
- **Required Zion Configuration**:
|
||||||
|
```bash
|
||||||
|
# Enable IP forwarding
|
||||||
|
echo 'net.ipv4.ip_forward=1' | sudo tee -a /etc/sysctl.conf
|
||||||
|
sudo sysctl -p
|
||||||
|
|
||||||
|
# Add NAT rules (if not already present)
|
||||||
|
sudo iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE
|
||||||
|
sudo iptables -A FORWARD -i wg0 -j ACCEPT
|
||||||
|
sudo iptables -A FORWARD -o wg0 -j ACCEPT
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
1. Run the setup script: `./wgez-setup.sh`
|
||||||
|
2. Choose option 2 (Generate keys + complete config)
|
||||||
|
3. Select routing mode:
|
||||||
|
- Option 1: WireGuard traffic only
|
||||||
|
- Option 2: All traffic through VPN
|
||||||
|
4. Follow the generated instructions
|
||||||
|
|
||||||
|
## Important Notes
|
||||||
|
|
||||||
|
- **Full tunnel mode** requires the Zion server to have proper NAT configuration
|
||||||
|
- **WireGuard-only mode** is safer and doesn't require endpoint changes
|
||||||
|
- The script automatically provides endpoint-specific instructions for full tunnel mode
|
||||||
|
- Routing mode is saved in the JSON info file for reference
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Full Tunnel Not Working
|
||||||
|
1. Check Zion's iptables rules: `sudo iptables -t nat -L POSTROUTING`
|
||||||
|
2. Verify IP forwarding is enabled: `cat /proc/sys/net/ipv4/ip_forward`
|
||||||
|
3. Check WireGuard interface status: `sudo wg show`
|
||||||
|
|
||||||
|
### DNS Issues in Full Tunnel
|
||||||
|
- The script configures DNS servers (1.1.1.1, 8.8.8.8)
|
||||||
|
- If DNS doesn't work, check if Zion allows DNS traffic
|
||||||
|
- Consider adding DNS-specific iptables rules if needed
|
||||||
695
scripting/wgez-setup.go
Normal file
695
scripting/wgez-setup.go
Normal file
@@ -0,0 +1,695 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/curve25519"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Colors for terminal output
|
||||||
|
const (
|
||||||
|
Red = "\033[0;31m"
|
||||||
|
Green = "\033[0;32m"
|
||||||
|
Yellow = "\033[1;33m"
|
||||||
|
Blue = "\033[0;34m"
|
||||||
|
Reset = "\033[0m"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Configuration structs
|
||||||
|
type WGConfig struct {
|
||||||
|
Hostname string `json:"hostname"`
|
||||||
|
IPAddress string `json:"ip_address"`
|
||||||
|
PrivateKey string `json:"private_key"`
|
||||||
|
PublicKey string `json:"public_key"`
|
||||||
|
RoutingMode string `json:"routing_mode"`
|
||||||
|
Generated string `json:"generated"`
|
||||||
|
ScriptVer string `json:"script_version"`
|
||||||
|
RunningRoot bool `json:"running_as_root"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type StaticServer struct {
|
||||||
|
IP string
|
||||||
|
Port string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Global variables
|
||||||
|
var (
|
||||||
|
staticServers = map[string]string{
|
||||||
|
"10.8.0.1": "51820",
|
||||||
|
"10.8.0.10": "53535",
|
||||||
|
"10.8.0.99": "54382",
|
||||||
|
}
|
||||||
|
|
||||||
|
peers = map[string]Peer{
|
||||||
|
"zion": {
|
||||||
|
Name: "Zion peer (central server) - for access to entire network",
|
||||||
|
PublicKey: "2ztJbrN1x1NWanzPGLiKL19ZkdOhm5Y7WeKEWBT5cyg=",
|
||||||
|
Endpoint: "ugh.im:51820",
|
||||||
|
Keepalive: 25,
|
||||||
|
},
|
||||||
|
"cthulhu": {
|
||||||
|
Name: "Cthulhu (optional if port 53 is also forwarded to bypass firewalls)",
|
||||||
|
PublicKey: "NBktXKy1s0n2lIlIMODvOqKNwAtYdoZH5feKt5P43i0=",
|
||||||
|
AllowedIPs: "10.8.0.10/32",
|
||||||
|
Endpoint: "aw2cd67.glddns.com:53535",
|
||||||
|
Keepalive: 25,
|
||||||
|
},
|
||||||
|
"galaxy": {
|
||||||
|
Name: "Galaxy (located in Europe, NL)",
|
||||||
|
PublicKey: "QBNt00VSedxPlq3ZvsdYaqIcbudCAyxv9TG65aPVZzM=",
|
||||||
|
AllowedIPs: "10.8.0.99/32",
|
||||||
|
Endpoint: "galaxyspin.space:54382",
|
||||||
|
Keepalive: 25,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
type Peer struct {
|
||||||
|
Name string
|
||||||
|
PublicKey string
|
||||||
|
AllowedIPs string
|
||||||
|
Endpoint string
|
||||||
|
Keepalive int
|
||||||
|
}
|
||||||
|
|
||||||
|
// Utility functions
|
||||||
|
func printStatus(message string) {
|
||||||
|
fmt.Printf("%s[INFO]%s %s\n", Green, Reset, message)
|
||||||
|
}
|
||||||
|
|
||||||
|
func printWarning(message string) {
|
||||||
|
fmt.Printf("%s[WARNING]%s %s\n", Yellow, Reset, message)
|
||||||
|
}
|
||||||
|
|
||||||
|
func printError(message string) {
|
||||||
|
fmt.Printf("%s[ERROR]%s %s\n", Red, Reset, message)
|
||||||
|
}
|
||||||
|
|
||||||
|
func printHeader() {
|
||||||
|
fmt.Printf("%s================================%s\n", Blue, Reset)
|
||||||
|
fmt.Printf("%s NextGen WireGuard Easy Setup %s\n", Blue, Reset)
|
||||||
|
fmt.Printf("%s================================%s\n", Blue, Reset)
|
||||||
|
fmt.Println()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validation functions
|
||||||
|
func validateHostname(hostname string) error {
|
||||||
|
if hostname == "" {
|
||||||
|
return fmt.Errorf("hostname cannot be empty")
|
||||||
|
}
|
||||||
|
if len(hostname) > 63 {
|
||||||
|
return fmt.Errorf("hostname too long (max 63 characters)")
|
||||||
|
}
|
||||||
|
// Basic alphanumeric and hyphen validation
|
||||||
|
for _, char := range hostname {
|
||||||
|
if !((char >= 'a' && char <= 'z') || (char >= 'A' && char <= 'Z') ||
|
||||||
|
(char >= '0' && char <= '9') || char == '-') {
|
||||||
|
return fmt.Errorf("invalid hostname format. Use alphanumeric characters and hyphens only")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateIP(ip string) error {
|
||||||
|
if ip == "" {
|
||||||
|
return fmt.Errorf("IP address cannot be empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
parts := strings.Split(ip, ".")
|
||||||
|
if len(parts) != 4 {
|
||||||
|
return fmt.Errorf("invalid IP format")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, part := range parts {
|
||||||
|
num, err := strconv.Atoi(part)
|
||||||
|
if err != nil || num < 0 || num > 255 {
|
||||||
|
return fmt.Errorf("invalid IP octet: %s", part)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if it's in the expected range
|
||||||
|
if !strings.HasPrefix(ip, "10.8.0.") && !strings.HasPrefix(ip, "10.0.0.") {
|
||||||
|
printWarning("IP should be in 10.8.0.x or 10.0.0.x range for NextGen network")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateInterfaceName(iface string) error {
|
||||||
|
if iface == "" {
|
||||||
|
return fmt.Errorf("interface name cannot be empty")
|
||||||
|
}
|
||||||
|
if len(iface) > 15 {
|
||||||
|
return fmt.Errorf("interface name too long (max 15 characters)")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if starts with letter and contains only alphanumeric
|
||||||
|
if len(iface) == 0 || !((iface[0] >= 'a' && iface[0] <= 'z') || (iface[0] >= 'A' && iface[0] <= 'Z')) {
|
||||||
|
return fmt.Errorf("interface name must start with a letter")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, char := range iface {
|
||||||
|
if !((char >= 'a' && char <= 'z') || (char >= 'A' && char <= 'Z') || (char >= '0' && char <= '9')) {
|
||||||
|
return fmt.Errorf("interface name can only contain letters and numbers")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// User input functions
|
||||||
|
func getUserInput(prompt string, validator func(string) error) string {
|
||||||
|
reader := bufio.NewReader(os.Stdin)
|
||||||
|
for {
|
||||||
|
fmt.Print(prompt)
|
||||||
|
input, _ := reader.ReadString('\n')
|
||||||
|
input = strings.TrimSpace(input)
|
||||||
|
|
||||||
|
if err := validator(input); err != nil {
|
||||||
|
printError(err.Error())
|
||||||
|
fmt.Print("Continue anyway? (y/N): ")
|
||||||
|
response, _ := reader.ReadString('\n')
|
||||||
|
response = strings.TrimSpace(strings.ToLower(response))
|
||||||
|
if response == "y" || response == "yes" {
|
||||||
|
return input
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return input
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getDirectoryInput(prompt, defaultDir string) string {
|
||||||
|
reader := bufio.NewReader(os.Stdin)
|
||||||
|
for {
|
||||||
|
fmt.Printf("%s [%s]: ", prompt, defaultDir)
|
||||||
|
input, _ := reader.ReadString('\n')
|
||||||
|
input = strings.TrimSpace(input)
|
||||||
|
|
||||||
|
if input == "" {
|
||||||
|
input = defaultDir
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if directory exists
|
||||||
|
if _, err := os.Stat(input); os.IsNotExist(err) {
|
||||||
|
fmt.Printf("Directory '%s' doesn't exist. Create it? (Y/n): ", input)
|
||||||
|
response, _ := reader.ReadString('\n')
|
||||||
|
response = strings.TrimSpace(strings.ToLower(response))
|
||||||
|
if response == "n" || response == "no" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.MkdirAll(input, 0755); err != nil {
|
||||||
|
printError(fmt.Sprintf("Failed to create directory '%s': %v", input, err))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if directory is writable
|
||||||
|
if info, err := os.Stat(input); err == nil {
|
||||||
|
if info.Mode()&0200 == 0 {
|
||||||
|
printError(fmt.Sprintf("Directory '%s' is not writable", input))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return input
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WireGuard key generation
|
||||||
|
func generateWireGuardKeys() (string, string, error) {
|
||||||
|
// Generate private key
|
||||||
|
privateKeyBytes := make([]byte, 32)
|
||||||
|
if _, err := rand.Read(privateKeyBytes); err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure the key is valid for curve25519
|
||||||
|
privateKeyBytes[0] &= 248
|
||||||
|
privateKeyBytes[31] &= 127
|
||||||
|
privateKeyBytes[31] |= 64
|
||||||
|
|
||||||
|
// Generate public key
|
||||||
|
var publicKeyBytes [32]byte
|
||||||
|
curve25519.ScalarBaseMult(&publicKeyBytes, (*[32]byte)(privateKeyBytes))
|
||||||
|
|
||||||
|
privateKey := base64.StdEncoding.EncodeToString(privateKeyBytes[:])
|
||||||
|
publicKey := base64.StdEncoding.EncodeToString(publicKeyBytes[:])
|
||||||
|
|
||||||
|
return privateKey, publicKey, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configuration generation
|
||||||
|
func generateConfig(hostname, ipAddress, privateKey, routingMode string) string {
|
||||||
|
var config strings.Builder
|
||||||
|
|
||||||
|
// Interface section
|
||||||
|
config.WriteString("[Interface]\n")
|
||||||
|
config.WriteString(fmt.Sprintf("Address = %s/24\n", ipAddress))
|
||||||
|
config.WriteString(fmt.Sprintf("PrivateKey = %s\n", privateKey))
|
||||||
|
|
||||||
|
// Add ListenPort for static servers
|
||||||
|
if port, exists := staticServers[ipAddress]; exists {
|
||||||
|
config.WriteString(fmt.Sprintf("ListenPort = %s\n", port))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add DNS for full tunnel mode
|
||||||
|
if routingMode == "full_tunnel" {
|
||||||
|
config.WriteString("DNS = 1.1.1.1, 8.8.8.8\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zion peer (always enabled)
|
||||||
|
config.WriteString("\n#Zion peer (central server) - for access to entire network\n")
|
||||||
|
config.WriteString("[Peer]\n")
|
||||||
|
config.WriteString(fmt.Sprintf("PublicKey = %s\n", peers["zion"].PublicKey))
|
||||||
|
|
||||||
|
// Set AllowedIPs based on routing mode
|
||||||
|
if routingMode == "full_tunnel" {
|
||||||
|
config.WriteString("AllowedIPs = 0.0.0.0/0, ::/0\n")
|
||||||
|
} else {
|
||||||
|
config.WriteString("AllowedIPs = 10.8.0.0/24\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
config.WriteString(fmt.Sprintf("Endpoint = %s\n", peers["zion"].Endpoint))
|
||||||
|
config.WriteString(fmt.Sprintf("PersistentKeepalive = %d\n", peers["zion"].Keepalive))
|
||||||
|
|
||||||
|
// Optional peers (commented out)
|
||||||
|
config.WriteString("\n#Cthulhu (optional if port 53 is also forwarded to bypass firewalls)\n")
|
||||||
|
config.WriteString("#[Peer]\n")
|
||||||
|
config.WriteString(fmt.Sprintf("#PublicKey = %s\n", peers["cthulhu"].PublicKey))
|
||||||
|
config.WriteString(fmt.Sprintf("#AllowedIPs = %s\n", peers["cthulhu"].AllowedIPs))
|
||||||
|
config.WriteString(fmt.Sprintf("#Endpoint = %s\n", peers["cthulhu"].Endpoint))
|
||||||
|
config.WriteString(fmt.Sprintf("#PersistentKeepalive = %d\n", peers["cthulhu"].Keepalive))
|
||||||
|
|
||||||
|
config.WriteString("\n#Galaxy (located in Europe, NL)\n")
|
||||||
|
config.WriteString("#[Peer]\n")
|
||||||
|
config.WriteString(fmt.Sprintf("#PublicKey = %s\n", peers["galaxy"].PublicKey))
|
||||||
|
config.WriteString(fmt.Sprintf("#AllowedIPs = %s\n", peers["galaxy"].AllowedIPs))
|
||||||
|
config.WriteString(fmt.Sprintf("#Endpoint = %s\n", peers["galaxy"].Endpoint))
|
||||||
|
config.WriteString(fmt.Sprintf("#PersistentKeepalive = %d\n", peers["galaxy"].Keepalive))
|
||||||
|
|
||||||
|
return config.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check dependencies
|
||||||
|
func checkDependencies() error {
|
||||||
|
deps := []string{"wg", "wg-quick"}
|
||||||
|
|
||||||
|
for _, dep := range deps {
|
||||||
|
if _, err := exec.LookPath(dep); err != nil {
|
||||||
|
return fmt.Errorf("missing dependency: %s", dep)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if running as root
|
||||||
|
func isRunningAsRoot() bool {
|
||||||
|
return os.Geteuid() == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main function
|
||||||
|
func main() {
|
||||||
|
printHeader()
|
||||||
|
|
||||||
|
// Check if running as root
|
||||||
|
runningAsRoot := isRunningAsRoot()
|
||||||
|
|
||||||
|
var wgDir string
|
||||||
|
if runningAsRoot {
|
||||||
|
wgDir = "/etc/wireguard"
|
||||||
|
printStatus("Running as root - using system directories")
|
||||||
|
printStatus(fmt.Sprintf("WireGuard directory: %s", wgDir))
|
||||||
|
} else {
|
||||||
|
wgDir = "."
|
||||||
|
printWarning("Not running as root - using current directory")
|
||||||
|
printStatus(fmt.Sprintf("WireGuard directory: %s", wgDir))
|
||||||
|
printWarning("You'll need to manually copy config files to /etc/wireguard/ later")
|
||||||
|
}
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
// Check dependencies
|
||||||
|
if err := checkDependencies(); err != nil {
|
||||||
|
printError(err.Error())
|
||||||
|
printStatus("Install with: apt install wireguard-tools")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get directory for non-root users
|
||||||
|
if !runningAsRoot {
|
||||||
|
fmt.Printf("%sStep 1: Directory Selection%s\n", Blue, Reset)
|
||||||
|
fmt.Println()
|
||||||
|
printStatus("Choose where to save WireGuard files:")
|
||||||
|
fmt.Printf(" - Current directory: %s\n", wgDir)
|
||||||
|
fmt.Printf(" - Home directory: %s\n", os.Getenv("HOME"))
|
||||||
|
fmt.Println(" - Custom directory")
|
||||||
|
fmt.Println()
|
||||||
|
wgDir = getDirectoryInput("Enter directory path for WireGuard files", wgDir)
|
||||||
|
fmt.Println()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get hostname
|
||||||
|
stepNum := "2"
|
||||||
|
if !runningAsRoot {
|
||||||
|
stepNum = "2"
|
||||||
|
} else {
|
||||||
|
stepNum = "1"
|
||||||
|
}
|
||||||
|
fmt.Printf("%sStep %s: Node Information%s\n", Blue, stepNum, Reset)
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
hostname := getUserInput("Enter hostname for this node: ", validateHostname)
|
||||||
|
|
||||||
|
// Get IP address
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Println("Available IP ranges:")
|
||||||
|
fmt.Println(" - 10.8.0.x (recommended for NextGen network)")
|
||||||
|
fmt.Println(" - 10.0.0.x (alternative range)")
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
ipAddress := getUserInput("Enter IP address for this node (e.g., 10.8.0.30): ", validateIP)
|
||||||
|
|
||||||
|
// Get interface name
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Println("Interface name options:")
|
||||||
|
fmt.Println(" - wg0 (default, most common)")
|
||||||
|
fmt.Println(" - wg1, wg2, etc. (if wg0 is already in use)")
|
||||||
|
fmt.Println(" - Custom name (e.g., nextgen, vpn, etc.)")
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
interfaceName := getUserInput("Enter interface name (default: wg0): ", validateInterfaceName)
|
||||||
|
if interfaceName == "" {
|
||||||
|
interfaceName = "wg0"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configuration options
|
||||||
|
fmt.Println()
|
||||||
|
if !runningAsRoot {
|
||||||
|
stepNum = "3"
|
||||||
|
} else {
|
||||||
|
stepNum = "2"
|
||||||
|
}
|
||||||
|
fmt.Printf("%sStep %s: Configuration Options%s\n", Blue, stepNum, Reset)
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Println("Choose an option:")
|
||||||
|
fmt.Println("1. Generate keys only (manual config creation)")
|
||||||
|
fmt.Println("2. Generate keys + complete config (recommended)")
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
reader := bufio.NewReader(os.Stdin)
|
||||||
|
var configChoice string
|
||||||
|
for {
|
||||||
|
fmt.Print("Enter your choice (1 or 2): ")
|
||||||
|
configChoice, _ = reader.ReadString('\n')
|
||||||
|
configChoice = strings.TrimSpace(configChoice)
|
||||||
|
if configChoice == "1" || configChoice == "2" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
printError("Invalid choice. Please enter 1 or 2.")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Traffic routing options
|
||||||
|
var routingMode string
|
||||||
|
if configChoice == "2" {
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Println("Traffic routing options:")
|
||||||
|
fmt.Println("1. WireGuard traffic only (10.8.0.x network only)")
|
||||||
|
fmt.Println("2. All traffic through VPN (full tunnel)")
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Println("Note: Full tunnel routes ALL internet traffic through the VPN.")
|
||||||
|
fmt.Println(" WireGuard-only keeps your regular internet traffic separate.")
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
var routingChoice string
|
||||||
|
for {
|
||||||
|
fmt.Print("Enter your choice (1 or 2): ")
|
||||||
|
routingChoice, _ = reader.ReadString('\n')
|
||||||
|
routingChoice = strings.TrimSpace(routingChoice)
|
||||||
|
if routingChoice == "1" || routingChoice == "2" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
printError("Invalid choice. Please enter 1 or 2.")
|
||||||
|
}
|
||||||
|
|
||||||
|
if routingChoice == "1" {
|
||||||
|
routingMode = "wg_only"
|
||||||
|
printStatus("Selected: WireGuard traffic only")
|
||||||
|
} else {
|
||||||
|
routingMode = "full_tunnel"
|
||||||
|
printStatus("Selected: All traffic through VPN")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printStatus(fmt.Sprintf("Starting setup for %s (%s)...", hostname, ipAddress))
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
// Create directories
|
||||||
|
if err := os.MkdirAll(wgDir, 0755); err != nil {
|
||||||
|
printError(fmt.Sprintf("Failed to create directory: %v", err))
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate keys
|
||||||
|
printStatus("Generating WireGuard keys...")
|
||||||
|
privateKey, publicKey, err := generateWireGuardKeys()
|
||||||
|
if err != nil {
|
||||||
|
printError(fmt.Sprintf("Failed to generate keys: %v", err))
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save keys
|
||||||
|
privateKeyFile := filepath.Join(wgDir, fmt.Sprintf("%s_private.key", hostname))
|
||||||
|
publicKeyFile := filepath.Join(wgDir, fmt.Sprintf("%s_public.key", hostname))
|
||||||
|
|
||||||
|
if err := ioutil.WriteFile(privateKeyFile, []byte(privateKey), 0600); err != nil {
|
||||||
|
printError(fmt.Sprintf("Failed to save private key: %v", err))
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ioutil.WriteFile(publicKeyFile, []byte(publicKey), 0600); err != nil {
|
||||||
|
printError(fmt.Sprintf("Failed to save public key: %v", err))
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
printStatus("Keys generated successfully!")
|
||||||
|
fmt.Printf(" Private key: %s\n", privateKeyFile)
|
||||||
|
fmt.Printf(" Public key: %s\n", publicKeyFile)
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
// Display node information
|
||||||
|
if !runningAsRoot {
|
||||||
|
stepNum = "4"
|
||||||
|
} else {
|
||||||
|
stepNum = "3"
|
||||||
|
}
|
||||||
|
fmt.Printf("%sStep %s: Node Information%s\n", Blue, stepNum, Reset)
|
||||||
|
fmt.Println("==========================================")
|
||||||
|
fmt.Printf("HOSTNAME: %s\n", hostname)
|
||||||
|
fmt.Printf("IP ADDRESS: %s\n", ipAddress)
|
||||||
|
fmt.Printf("PRIVATE KEY: %s\n", privateKey)
|
||||||
|
fmt.Printf("PUBLIC KEY: %s\n", publicKey)
|
||||||
|
fmt.Println("==========================================")
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
// Save structured info
|
||||||
|
infoFile := filepath.Join(wgDir, fmt.Sprintf("%s_wg_info.json", hostname))
|
||||||
|
if runningAsRoot {
|
||||||
|
infoFile = filepath.Join("/tmp", fmt.Sprintf("%s_wg_info.json", hostname))
|
||||||
|
}
|
||||||
|
|
||||||
|
wgConfig := WGConfig{
|
||||||
|
Hostname: hostname,
|
||||||
|
IPAddress: ipAddress,
|
||||||
|
PrivateKey: privateKey,
|
||||||
|
PublicKey: publicKey,
|
||||||
|
RoutingMode: routingMode,
|
||||||
|
Generated: time.Now().Format(time.RFC3339),
|
||||||
|
ScriptVer: "2.2",
|
||||||
|
RunningRoot: runningAsRoot,
|
||||||
|
}
|
||||||
|
|
||||||
|
infoData, err := json.MarshalIndent(wgConfig, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
printError(fmt.Sprintf("Failed to marshal config: %v", err))
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ioutil.WriteFile(infoFile, infoData, 0600); err != nil {
|
||||||
|
printError(fmt.Sprintf("Failed to save info file: %v", err))
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
printStatus(fmt.Sprintf("Information saved to: %s", infoFile))
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
// Generate complete config if requested
|
||||||
|
if configChoice == "2" {
|
||||||
|
configFile := filepath.Join(wgDir, fmt.Sprintf("%s.conf", interfaceName))
|
||||||
|
|
||||||
|
printStatus(fmt.Sprintf("Generating complete %s.conf...", interfaceName))
|
||||||
|
configContent := generateConfig(hostname, ipAddress, privateKey, routingMode)
|
||||||
|
|
||||||
|
if err := ioutil.WriteFile(configFile, []byte(configContent), 0600); err != nil {
|
||||||
|
printError(fmt.Sprintf("Failed to write config file: %v", err))
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
printStatus(fmt.Sprintf("Config written to: %s", configFile))
|
||||||
|
if runningAsRoot {
|
||||||
|
printStatus("Permissions set to 600")
|
||||||
|
}
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
// Next steps
|
||||||
|
if !runningAsRoot {
|
||||||
|
stepNum = "5"
|
||||||
|
} else {
|
||||||
|
stepNum = "4"
|
||||||
|
}
|
||||||
|
fmt.Printf("%sStep %s: Next Steps%s\n", Blue, stepNum, Reset)
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
if runningAsRoot {
|
||||||
|
printStatus("Ready to start WireGuard:")
|
||||||
|
fmt.Printf(" systemctl enable --now wg-quick@%s\n", interfaceName)
|
||||||
|
} else {
|
||||||
|
printWarning("To enable WireGuard (requires root):")
|
||||||
|
fmt.Printf(" sudo cp %s /etc/wireguard/\n", configFile)
|
||||||
|
fmt.Printf(" sudo chmod 600 /etc/wireguard/%s.conf\n", interfaceName)
|
||||||
|
fmt.Printf(" sudo systemctl enable --now wg-quick@%s\n", interfaceName)
|
||||||
|
}
|
||||||
|
fmt.Println()
|
||||||
|
printWarning("IMPORTANT: Update other nodes with this peer info:")
|
||||||
|
fmt.Printf(" PublicKey = %s\n", publicKey)
|
||||||
|
fmt.Printf(" AllowedIPs = %s/32\n", ipAddress)
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
// Config preview
|
||||||
|
fmt.Printf("%sConfig Preview:%s\n", Blue, Reset)
|
||||||
|
fmt.Println("----------------------------------------")
|
||||||
|
lines := strings.Split(configContent, "\n")
|
||||||
|
for i, line := range lines {
|
||||||
|
if i >= 5 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
fmt.Println(line)
|
||||||
|
}
|
||||||
|
fmt.Printf(" [... and %d total lines]\n", len(lines))
|
||||||
|
fmt.Println("----------------------------------------")
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
// Full tunnel instructions
|
||||||
|
if routingMode == "full_tunnel" {
|
||||||
|
fmt.Println()
|
||||||
|
printWarning("FULL TUNNEL MODE DETECTED - Endpoint Changes Required:")
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Println("Since this node will route ALL traffic through the VPN, you need to:")
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Println("1. Update Zion's config (/etc/wireguard/wg0.conf) to allow this peer:")
|
||||||
|
fmt.Println(" - Add the peer section as shown above")
|
||||||
|
fmt.Println(" - Ensure Zion has proper iptables rules for NAT/masquerading")
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Println("2. Check Zion's iptables rules (run on Zion server):")
|
||||||
|
fmt.Println(" sudo iptables -t nat -L POSTROUTING")
|
||||||
|
fmt.Println(" sudo iptables -L FORWARD")
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Println("3. If Zion doesn't have proper NAT rules, add them:")
|
||||||
|
fmt.Println(" sudo iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE")
|
||||||
|
fmt.Println(" sudo iptables -A FORWARD -i wg0 -j ACCEPT")
|
||||||
|
fmt.Println(" sudo iptables -A FORWARD -o wg0 -j ACCEPT")
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Println("4. Enable IP forwarding on Zion (if not already enabled):")
|
||||||
|
fmt.Println(" echo 'net.ipv4.ip_forward=1' | sudo tee -a /etc/sysctl.conf")
|
||||||
|
fmt.Println(" sudo sysctl -p")
|
||||||
|
fmt.Println()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zion update instructions
|
||||||
|
fmt.Printf("%s========================================%s\n", Red, Reset)
|
||||||
|
fmt.Printf("%s !!! NOW UPDATE ZION SERVER !!! %s\n", Red, Reset)
|
||||||
|
fmt.Printf("%s========================================%s\n", Red, Reset)
|
||||||
|
fmt.Println()
|
||||||
|
printWarning("You MUST add this peer to Zion's config (/etc/wireguard/wg0.conf):")
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Printf("%s#%s%s\n", Yellow, hostname, Reset)
|
||||||
|
fmt.Printf("%s[Peer]%s\n", Yellow, Reset)
|
||||||
|
fmt.Printf("%sPublicKey = %s%s\n", Yellow, publicKey, Reset)
|
||||||
|
fmt.Printf("%sAllowedIPs = %s/32%s\n", Yellow, ipAddress, Reset)
|
||||||
|
fmt.Println()
|
||||||
|
printWarning("After updating Zion, restart its WireGuard:")
|
||||||
|
fmt.Println(" systemctl restart wg-quick@wg0")
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
if runningAsRoot {
|
||||||
|
printWarning("Then restart this node's WireGuard:")
|
||||||
|
fmt.Printf(" systemctl restart wg-quick@%s\n", interfaceName)
|
||||||
|
} else {
|
||||||
|
printWarning("Then restart this node's WireGuard:")
|
||||||
|
fmt.Printf(" sudo systemctl restart wg-quick@%s\n", interfaceName)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Manual config generation path
|
||||||
|
if !runningAsRoot {
|
||||||
|
stepNum = "5"
|
||||||
|
} else {
|
||||||
|
stepNum = "4"
|
||||||
|
}
|
||||||
|
fmt.Printf("%sStep %s: Next Steps%s\n", Blue, stepNum, Reset)
|
||||||
|
fmt.Println()
|
||||||
|
printStatus("Keys generated successfully!")
|
||||||
|
fmt.Printf(" Private key: %s\n", privateKeyFile)
|
||||||
|
fmt.Printf(" Public key: %s\n", publicKeyFile)
|
||||||
|
fmt.Println()
|
||||||
|
printWarning("Next steps:")
|
||||||
|
fmt.Printf(" - Create %s.conf manually using the keys above\n", interfaceName)
|
||||||
|
fmt.Printf(" - Copy config to %s\n", filepath.Join(wgDir, fmt.Sprintf("%s.conf", interfaceName)))
|
||||||
|
if runningAsRoot {
|
||||||
|
fmt.Printf(" - Set permissions: chmod 600 %s\n", filepath.Join(wgDir, fmt.Sprintf("%s.conf", interfaceName)))
|
||||||
|
fmt.Printf(" - Enable/start: systemctl enable --now wg-quick@%s\n", interfaceName)
|
||||||
|
} else {
|
||||||
|
fmt.Printf(" - Copy to system: sudo cp %s /etc/wireguard/\n", filepath.Join(wgDir, fmt.Sprintf("%s.conf", interfaceName)))
|
||||||
|
fmt.Printf(" - Set permissions: sudo chmod 600 /etc/wireguard/%s.conf\n", interfaceName)
|
||||||
|
fmt.Printf(" - Enable/start: sudo systemctl enable --now wg-quick@%s\n", interfaceName)
|
||||||
|
}
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Printf("%s========================================%s\n", Red, Reset)
|
||||||
|
fmt.Printf("%s !!! NOW UPDATE ZION SERVER !!! %s\n", Red, Reset)
|
||||||
|
fmt.Printf("%s========================================%s\n", Red, Reset)
|
||||||
|
fmt.Println()
|
||||||
|
printWarning("You MUST add this peer to Zion's config (/etc/wireguard/wg0.conf):")
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Printf("%s#%s%s\n", Yellow, hostname, Reset)
|
||||||
|
fmt.Printf("%s[Peer]%s\n", Yellow, Reset)
|
||||||
|
fmt.Printf("%sPublicKey = %s%s\n", Yellow, publicKey, Reset)
|
||||||
|
fmt.Printf("%sAllowedIPs = %s/32%s\n", Yellow, ipAddress, Reset)
|
||||||
|
fmt.Println()
|
||||||
|
printWarning("After updating Zion, restart its WireGuard:")
|
||||||
|
fmt.Println(" systemctl restart wg-quick@wg0")
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
if runningAsRoot {
|
||||||
|
printWarning("Then restart this node's WireGuard:")
|
||||||
|
fmt.Printf(" systemctl restart wg-quick@%s\n", interfaceName)
|
||||||
|
} else {
|
||||||
|
printWarning("Then restart this node's WireGuard:")
|
||||||
|
fmt.Printf(" sudo systemctl restart wg-quick@%s\n", interfaceName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println()
|
||||||
|
printStatus(fmt.Sprintf("Setup complete for %s!", hostname))
|
||||||
|
fmt.Println()
|
||||||
|
}
|
||||||
739
scripting/wgez-setup.sh
Normal file
739
scripting/wgez-setup.sh
Normal file
@@ -0,0 +1,739 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# NextGen WireGuard Easy Setup Script (wgez-setup.sh)
|
||||||
|
# Interactive setup script for new WireGuard nodes
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Colors for better UX
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
NC='\033[0m'
|
||||||
|
|
||||||
|
# Globals
|
||||||
|
SCRIPT_DIR="${BASH_SOURCE[0]%/*}"
|
||||||
|
SCRIPT_DIR="$(cd "$SCRIPT_DIR" && pwd)"
|
||||||
|
|
||||||
|
# Determine if running as root and set appropriate directories
|
||||||
|
if [[ $EUID -eq 0 ]]; then
|
||||||
|
WG_DIR="/etc/wireguard"
|
||||||
|
BACKUP_DIR="$WG_DIR/backups"
|
||||||
|
RUNNING_AS_ROOT=true
|
||||||
|
else
|
||||||
|
WG_DIR="$(pwd)"
|
||||||
|
BACKUP_DIR="$WG_DIR/backups"
|
||||||
|
RUNNING_AS_ROOT=false
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Logging
|
||||||
|
log_file="/var/log/wgez-setup.log"
|
||||||
|
if [[ "$RUNNING_AS_ROOT" == "false" ]]; then
|
||||||
|
log_file="$WG_DIR/wgez-setup.log"
|
||||||
|
fi
|
||||||
|
exec 19> >(exec cat >&2)
|
||||||
|
exec 20> >(exec tee -a "$log_file" >&2)
|
||||||
|
BASH_XTRACEFD=20
|
||||||
|
|
||||||
|
print_status() {
|
||||||
|
echo -e "${GREEN}[INFO]${NC} $1" | tee -a "$log_file"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_warning() {
|
||||||
|
echo -e "${YELLOW}[WARNING]${NC} $1" | tee -a "$log_file"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_error() {
|
||||||
|
echo -e "${RED}[ERROR]${NC} $1" | tee -a "$log_file"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_header() {
|
||||||
|
echo -e "${BLUE}================================${NC}"
|
||||||
|
echo -e "${BLUE} NextGen WireGuard Easy Setup ${NC}"
|
||||||
|
echo -e "${BLUE}================================${NC}"
|
||||||
|
echo ""
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
local exit_code=$?
|
||||||
|
if [[ $exit_code -ne 0 ]]; then
|
||||||
|
print_error "Script failed with exit code $exit_code"
|
||||||
|
if [[ -f "/tmp/${HOSTNAME:-unknown}_wg_info.json" ]]; then
|
||||||
|
rm -f "/tmp/${HOSTNAME}_wg_info.json"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
exit $exit_code
|
||||||
|
}
|
||||||
|
|
||||||
|
# Enhanced validation functions
|
||||||
|
validate_hostname() {
|
||||||
|
local hostname="$1"
|
||||||
|
if [[ -z "$hostname" ]]; then
|
||||||
|
print_error "Hostname cannot be empty"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
if [[ ! "$hostname" =~ ^[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]$|^[a-zA-Z0-9]$ ]]; then
|
||||||
|
print_error "Invalid hostname format. Use alphanumeric characters and hyphens only."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
if [[ ${#hostname} -gt 63 ]]; then
|
||||||
|
print_error "Hostname too long (max 63 characters)"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
validate_ip() {
|
||||||
|
local ip="$1"
|
||||||
|
local octets
|
||||||
|
|
||||||
|
if [[ -z "$ip" ]]; then
|
||||||
|
print_error "IP address cannot be empty"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
IFS='.' read -ra octets <<< "$ip"
|
||||||
|
if [[ ${#octets[@]} -ne 4 ]]; then
|
||||||
|
print_error "Invalid IP format"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
for octet in "${octets[@]}"; do
|
||||||
|
if ! [[ "$octet" =~ ^[0-9]+$ ]] || [[ $octet -gt 255 ]] || [[ $octet -lt 0 ]]; then
|
||||||
|
print_error "Invalid IP octet: $octet"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ ! "$ip" =~ ^10\.(8|0)\.0\.[0-9]{1,3}$ ]]; then
|
||||||
|
print_warning "IP should be in 10.8.0.x or 10.0.0.x range for NextGen network"
|
||||||
|
return 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
validate_interface_name() {
|
||||||
|
local interface="$1"
|
||||||
|
|
||||||
|
if [[ -z "$interface" ]]; then
|
||||||
|
print_error "Interface name cannot be empty"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! "$interface" =~ ^[a-zA-Z][a-zA-Z0-9]*$ ]]; then
|
||||||
|
print_error "Invalid interface name. Use letters and numbers only, starting with a letter."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ${#interface} -gt 15 ]]; then
|
||||||
|
print_error "Interface name too long (max 15 characters)"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if interface already exists (only if running as root)
|
||||||
|
if [[ "$RUNNING_AS_ROOT" == "true" ]] && ip link show "$interface" &>/dev/null; then
|
||||||
|
print_warning "Interface '$interface' already exists"
|
||||||
|
return 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if config file already exists
|
||||||
|
if [[ -f "$WG_DIR/${interface}.conf" ]]; then
|
||||||
|
print_warning "Config file '$WG_DIR/${interface}.conf' already exists"
|
||||||
|
return 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
check_ip_conflict() {
|
||||||
|
local ip="$1"
|
||||||
|
local config_file="$2"
|
||||||
|
|
||||||
|
# Check if IP is already in use on network
|
||||||
|
if ping -c1 -W1 "$ip" &>/dev/null; then
|
||||||
|
print_warning "IP $ip appears to be in use on the network"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check existing WireGuard configs
|
||||||
|
if [[ -f "$config_file" ]] && grep -q "Address = $ip" "$config_file"; then
|
||||||
|
print_warning "IP $ip already configured in existing WireGuard config"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
check_dependencies() {
|
||||||
|
local deps=("wg" "wg-quick")
|
||||||
|
local missing=()
|
||||||
|
|
||||||
|
for dep in "${deps[@]}"; do
|
||||||
|
if ! command -v "$dep" &>/dev/null; then
|
||||||
|
missing+=("$dep")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ ${#missing[@]} -gt 0 ]]; then
|
||||||
|
print_error "Missing dependencies: ${missing[*]}"
|
||||||
|
print_status "Install with: apt install wireguard-tools"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Only check systemctl if running as root
|
||||||
|
if [[ "$RUNNING_AS_ROOT" == "true" ]] && ! command -v "systemctl" &>/dev/null; then
|
||||||
|
print_error "Missing dependency: systemctl"
|
||||||
|
print_status "Install with: apt install systemd"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
backup_existing_config() {
|
||||||
|
local config_file="$1"
|
||||||
|
if [[ -f "$config_file" ]]; then
|
||||||
|
mkdir -p "$BACKUP_DIR"
|
||||||
|
local config_name=$(basename "$config_file")
|
||||||
|
local backup_file="$BACKUP_DIR/${config_name}.backup.$(date +%Y%m%d_%H%M%S)"
|
||||||
|
cp "$config_file" "$backup_file"
|
||||||
|
print_status "Existing config backed up to: $backup_file"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
get_user_input() {
|
||||||
|
local prompt="$1"
|
||||||
|
local var_name="$2"
|
||||||
|
local validator="$3"
|
||||||
|
local value
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
read -p "$prompt" value
|
||||||
|
if $validator "$value"; then
|
||||||
|
eval "$var_name='$value'"
|
||||||
|
break
|
||||||
|
elif [[ $? -eq 2 ]]; then
|
||||||
|
read -p "Continue anyway? (y/N): " -n 1 -r
|
||||||
|
echo
|
||||||
|
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||||
|
eval "$var_name='$value'"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
get_directory_input() {
|
||||||
|
local prompt="$1"
|
||||||
|
local var_name="$2"
|
||||||
|
local default_dir="$3"
|
||||||
|
local directory
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
read -p "$prompt [$default_dir]: " directory
|
||||||
|
if [[ -z "$directory" ]]; then
|
||||||
|
directory="$default_dir"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create directory if it doesn't exist
|
||||||
|
if [[ ! -d "$directory" ]]; then
|
||||||
|
read -p "Directory '$directory' doesn't exist. Create it? (Y/n): " -n 1 -r
|
||||||
|
echo
|
||||||
|
if [[ $REPLY =~ ^[Nn]$ ]]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if ! mkdir -p "$directory" 2>/dev/null; then
|
||||||
|
print_error "Failed to create directory '$directory'"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if directory is writable
|
||||||
|
if [[ ! -w "$directory" ]]; then
|
||||||
|
print_error "Directory '$directory' is not writable"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
eval "$var_name='$directory'"
|
||||||
|
break
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
generate_config() {
|
||||||
|
local hostname="$1"
|
||||||
|
local ip_address="$2"
|
||||||
|
local private_key="$3"
|
||||||
|
local routing_mode="${4:-wg_only}"
|
||||||
|
|
||||||
|
# Define static servers
|
||||||
|
local -A static_servers=(
|
||||||
|
["10.8.0.1"]="51820"
|
||||||
|
["10.8.0.10"]="53535"
|
||||||
|
["10.8.0.99"]="54382"
|
||||||
|
)
|
||||||
|
|
||||||
|
local config_content="[Interface]
|
||||||
|
Address = $ip_address/24
|
||||||
|
PrivateKey = $private_key"
|
||||||
|
|
||||||
|
# Add ListenPort for static servers
|
||||||
|
local is_static_server=false
|
||||||
|
if [[ -n "${static_servers[$ip_address]:-}" ]]; then
|
||||||
|
is_static_server=true
|
||||||
|
config_content="$config_content
|
||||||
|
ListenPort = ${static_servers[$ip_address]}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Add DNS for full tunnel mode
|
||||||
|
if [[ "$routing_mode" == "full_tunnel" ]]; then
|
||||||
|
config_content="$config_content
|
||||||
|
DNS = 1.1.1.1, 8.8.8.8"
|
||||||
|
fi
|
||||||
|
|
||||||
|
config_content="$config_content
|
||||||
|
|
||||||
|
#Zion peer (central server) - for access to entire network
|
||||||
|
[Peer]
|
||||||
|
PublicKey = 2ztJbrN1x1NWanzPGLiKL19ZkdOhm5Y7WeKEWBT5cyg="
|
||||||
|
|
||||||
|
# Set AllowedIPs based on routing mode
|
||||||
|
if [[ "$routing_mode" == "full_tunnel" ]]; then
|
||||||
|
config_content="$config_content
|
||||||
|
AllowedIPs = 0.0.0.0/0, ::/0"
|
||||||
|
else
|
||||||
|
config_content="$config_content
|
||||||
|
AllowedIPs = 10.8.0.0/24"
|
||||||
|
fi
|
||||||
|
|
||||||
|
config_content="$config_content
|
||||||
|
Endpoint = ugh.im:51820"
|
||||||
|
|
||||||
|
# Set keepalive value (25 for all peers as per new configuration)
|
||||||
|
config_content="$config_content
|
||||||
|
PersistentKeepalive = 25"
|
||||||
|
|
||||||
|
config_content="$config_content
|
||||||
|
|
||||||
|
#Cthulhu (optional if port 53 is also forwarded to bypass firewalls)
|
||||||
|
#[Peer]
|
||||||
|
#PublicKey = NBktXKy1s0n2lIlIMODvOqKNwAtYdoZH5feKt5P43i0=
|
||||||
|
#AllowedIPs = 10.8.0.10/32
|
||||||
|
#Endpoint = aw2cd67.glddns.com:53535"
|
||||||
|
|
||||||
|
config_content="$config_content
|
||||||
|
#PersistentKeepalive = 25"
|
||||||
|
|
||||||
|
config_content="$config_content
|
||||||
|
|
||||||
|
#Galaxy (located in Europe, NL)
|
||||||
|
#[Peer]
|
||||||
|
#PublicKey = QBNt00VSedxPlq3ZvsdYaqIcbudCAyxv9TG65aPVZzM=
|
||||||
|
#AllowedIPs = 10.8.0.99/32
|
||||||
|
#Endpoint = galaxyspin.space:54382"
|
||||||
|
|
||||||
|
config_content="$config_content
|
||||||
|
#PersistentKeepalive = 25"
|
||||||
|
|
||||||
|
echo "$config_content"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_progress() {
|
||||||
|
local step="$1"
|
||||||
|
local total="$2"
|
||||||
|
echo -e "${BLUE}[$step/$total]${NC} $3"
|
||||||
|
}
|
||||||
|
|
||||||
|
validate_config() {
|
||||||
|
local config_file="$1"
|
||||||
|
if ! wg-quick strip "$config_file" >/dev/null 2>&1; then
|
||||||
|
print_error "Generated config has syntax errors"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
check_network_connectivity() {
|
||||||
|
if ! ping -c1 -W3 8.8.8.8 &>/dev/null; then
|
||||||
|
print_warning "No internet connectivity detected"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
print_header
|
||||||
|
|
||||||
|
# Check if running as root and inform user
|
||||||
|
if [[ "$RUNNING_AS_ROOT" == "true" ]]; then
|
||||||
|
print_status "Running as root - using system directories"
|
||||||
|
print_status "WireGuard directory: $WG_DIR"
|
||||||
|
else
|
||||||
|
print_warning "Not running as root - using current directory"
|
||||||
|
print_status "WireGuard directory: $WG_DIR"
|
||||||
|
print_warning "You'll need to manually copy config files to /etc/wireguard/ later"
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Check dependencies
|
||||||
|
if ! check_dependencies; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get directory for non-root users
|
||||||
|
if [[ "$RUNNING_AS_ROOT" == "false" ]]; then
|
||||||
|
echo -e "${BLUE}Step 1: Directory Selection${NC}"
|
||||||
|
echo ""
|
||||||
|
print_status "Choose where to save WireGuard files:"
|
||||||
|
echo " - Current directory: $(pwd)"
|
||||||
|
echo " - Home directory: $HOME"
|
||||||
|
echo " - Custom directory"
|
||||||
|
echo ""
|
||||||
|
get_directory_input "Enter directory path for WireGuard files" WG_DIR "$(pwd)"
|
||||||
|
BACKUP_DIR="$WG_DIR/backups"
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get hostname
|
||||||
|
echo -e "${BLUE}Step $([[ "$RUNNING_AS_ROOT" == "false" ]] && echo "2" || echo "1"): Node Information${NC}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
get_user_input "Enter hostname for this node: " HOSTNAME validate_hostname
|
||||||
|
|
||||||
|
# Get IP address
|
||||||
|
echo ""
|
||||||
|
echo "Available IP ranges:"
|
||||||
|
echo " - 10.8.0.x (recommended for NextGen network)"
|
||||||
|
echo " - 10.0.0.x (alternative range)"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
get_user_input "Enter IP address for this node (e.g., 10.8.0.30): " IP_ADDRESS validate_ip
|
||||||
|
|
||||||
|
# Get interface name
|
||||||
|
echo ""
|
||||||
|
echo "Interface name options:"
|
||||||
|
echo " - wg0 (default, most common)"
|
||||||
|
echo " - wg1, wg2, etc. (if wg0 is already in use)"
|
||||||
|
echo " - Custom name (e.g., nextgen, vpn, etc.)"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
get_user_input "Enter interface name (default: wg0): " INTERFACE_NAME validate_interface_name
|
||||||
|
if [[ -z "$INTERFACE_NAME" ]]; then
|
||||||
|
INTERFACE_NAME="wg0"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Set config file path
|
||||||
|
CONFIG_FILE="$WG_DIR/${INTERFACE_NAME}.conf"
|
||||||
|
|
||||||
|
# Check for IP conflicts
|
||||||
|
if ! check_ip_conflict "$IP_ADDRESS" "$CONFIG_FILE"; then
|
||||||
|
read -p "Continue anyway? (y/N): " -n 1 -r
|
||||||
|
echo
|
||||||
|
[[ ! $REPLY =~ ^[Yy]$ ]] && exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if keys already exist
|
||||||
|
if [[ -f "$WG_DIR/${HOSTNAME}_private.key" ]]; then
|
||||||
|
print_warning "Keys for $HOSTNAME already exist!"
|
||||||
|
read -p "Overwrite? (y/N): " -n 1 -r
|
||||||
|
echo
|
||||||
|
[[ ! $REPLY =~ ^[Yy]$ ]] && exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Configuration options
|
||||||
|
echo ""
|
||||||
|
echo -e "${BLUE}Step $([[ "$RUNNING_AS_ROOT" == "false" ]] && echo "3" || echo "2"): Configuration Options${NC}"
|
||||||
|
echo ""
|
||||||
|
echo "Choose an option:"
|
||||||
|
echo "1. Generate keys only (manual config creation)"
|
||||||
|
echo "2. Generate keys + complete ${INTERFACE_NAME}.conf (recommended)"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
read -p "Enter your choice (1 or 2): " CONFIG_CHOICE
|
||||||
|
if [[ "$CONFIG_CHOICE" == "1" || "$CONFIG_CHOICE" == "2" ]]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
print_error "Invalid choice. Please enter 1 or 2."
|
||||||
|
done
|
||||||
|
|
||||||
|
# Traffic routing options (only if generating complete config)
|
||||||
|
if [[ "$CONFIG_CHOICE" == "2" ]]; then
|
||||||
|
echo ""
|
||||||
|
echo "Traffic routing options:"
|
||||||
|
echo "1. WireGuard traffic only (10.8.0.x network only)"
|
||||||
|
echo "2. All traffic through VPN (full tunnel)"
|
||||||
|
echo ""
|
||||||
|
echo "Note: Full tunnel routes ALL internet traffic through the VPN."
|
||||||
|
echo " WireGuard-only keeps your regular internet traffic separate."
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
read -p "Enter your choice (1 or 2): " ROUTING_CHOICE
|
||||||
|
if [[ "$ROUTING_CHOICE" == "1" || "$ROUTING_CHOICE" == "2" ]]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
print_error "Invalid choice. Please enter 1 or 2."
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ "$ROUTING_CHOICE" == "1" ]]; then
|
||||||
|
ROUTING_MODE="wg_only"
|
||||||
|
print_status "Selected: WireGuard traffic only"
|
||||||
|
else
|
||||||
|
ROUTING_MODE="full_tunnel"
|
||||||
|
print_status "Selected: All traffic through VPN"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_status "Starting setup for $HOSTNAME ($IP_ADDRESS)..."
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Create directories
|
||||||
|
mkdir -p "$WG_DIR" "$BACKUP_DIR"
|
||||||
|
cd "$WG_DIR"
|
||||||
|
|
||||||
|
# Set secure permissions (only if running as root)
|
||||||
|
if [[ "$RUNNING_AS_ROOT" == "true" ]]; then
|
||||||
|
umask 077
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_status "Generating WireGuard keys..."
|
||||||
|
PRIVATE_KEY=$(wg genkey)
|
||||||
|
PUBLIC_KEY=$(echo "$PRIVATE_KEY" | wg pubkey)
|
||||||
|
|
||||||
|
# Save keys
|
||||||
|
printf "%s\n%s\n" "$PRIVATE_KEY" "$PUBLIC_KEY" > "${HOSTNAME}_keys.tmp"
|
||||||
|
mv "${HOSTNAME}_keys.tmp" "${HOSTNAME}_private.key"
|
||||||
|
echo "$PUBLIC_KEY" > "${HOSTNAME}_public.key"
|
||||||
|
|
||||||
|
# Set permissions (only if running as root)
|
||||||
|
if [[ "$RUNNING_AS_ROOT" == "true" ]]; then
|
||||||
|
chmod 600 "${HOSTNAME}_private.key" "${HOSTNAME}_public.key"
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_status "Keys generated successfully!"
|
||||||
|
echo " Private key: $WG_DIR/${HOSTNAME}_private.key"
|
||||||
|
echo " Public key: $WG_DIR/${HOSTNAME}_public.key"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
echo -e "${BLUE}Step $([[ "$RUNNING_AS_ROOT" == "false" ]] && echo "4" || echo "3"): Node Information${NC}"
|
||||||
|
echo "=========================================="
|
||||||
|
echo "HOSTNAME: $HOSTNAME"
|
||||||
|
echo "IP ADDRESS: $IP_ADDRESS"
|
||||||
|
echo "PRIVATE KEY: $PRIVATE_KEY"
|
||||||
|
echo "PUBLIC KEY: $PUBLIC_KEY"
|
||||||
|
echo "=========================================="
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Save structured info
|
||||||
|
INFO_FILE="/tmp/${HOSTNAME}_wg_info.json"
|
||||||
|
if [[ "$RUNNING_AS_ROOT" == "false" ]]; then
|
||||||
|
INFO_FILE="$WG_DIR/${HOSTNAME}_wg_info.json"
|
||||||
|
fi
|
||||||
|
cat > "$INFO_FILE" << EOF
|
||||||
|
{
|
||||||
|
"hostname": "$HOSTNAME",
|
||||||
|
"ip_address": "$IP_ADDRESS",
|
||||||
|
"private_key": "$PRIVATE_KEY",
|
||||||
|
"public_key": "$PUBLIC_KEY",
|
||||||
|
"routing_mode": "${ROUTING_MODE:-wg_only}",
|
||||||
|
"generated": "$(date -Iseconds)",
|
||||||
|
"script_version": "2.2",
|
||||||
|
"running_as_root": $RUNNING_AS_ROOT
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
print_status "Information saved to: $INFO_FILE"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Generate complete config if requested
|
||||||
|
if [[ "$CONFIG_CHOICE" == "2" ]]; then
|
||||||
|
backup_existing_config "$CONFIG_FILE"
|
||||||
|
|
||||||
|
print_status "Generating complete ${INTERFACE_NAME}.conf..."
|
||||||
|
generate_config "$HOSTNAME" "$IP_ADDRESS" "$PRIVATE_KEY" "$ROUTING_MODE" > "$CONFIG_FILE"
|
||||||
|
|
||||||
|
# Set permissions (only if running as root)
|
||||||
|
if [[ "$RUNNING_AS_ROOT" == "true" ]]; then
|
||||||
|
chmod 600 "$CONFIG_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_status "Config written to: $CONFIG_FILE"
|
||||||
|
if [[ "$RUNNING_AS_ROOT" == "true" ]]; then
|
||||||
|
print_status "Permissions set to 600"
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
echo -e "${BLUE}Step $([[ "$RUNNING_AS_ROOT" == "false" ]] && echo "5" || echo "4"): Next Steps${NC}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
if [[ "$RUNNING_AS_ROOT" == "true" ]]; then
|
||||||
|
print_status "Ready to start WireGuard:"
|
||||||
|
echo " systemctl enable --now wg-quick@${INTERFACE_NAME}"
|
||||||
|
else
|
||||||
|
print_warning "To enable WireGuard (requires root):"
|
||||||
|
echo " sudo cp $CONFIG_FILE /etc/wireguard/"
|
||||||
|
echo " sudo chmod 600 /etc/wireguard/${INTERFACE_NAME}.conf"
|
||||||
|
echo " sudo systemctl enable --now wg-quick@${INTERFACE_NAME}"
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
print_warning "IMPORTANT: Update other nodes with this peer info:"
|
||||||
|
echo " PublicKey = $PUBLIC_KEY"
|
||||||
|
echo " AllowedIPs = $IP_ADDRESS/32"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
echo -e "${BLUE}Config Preview:${NC}"
|
||||||
|
echo "----------------------------------------"
|
||||||
|
head -5 "$CONFIG_FILE"
|
||||||
|
echo " [... and $(wc -l < "$CONFIG_FILE" | tr -d ' ') total lines]"
|
||||||
|
echo "----------------------------------------"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
if [[ "$RUNNING_AS_ROOT" == "true" ]]; then
|
||||||
|
print_status "Configuration complete! To start WireGuard:"
|
||||||
|
echo " systemctl enable --now wg-quick@${INTERFACE_NAME}"
|
||||||
|
echo ""
|
||||||
|
print_status "To check status:"
|
||||||
|
echo " wg show ${INTERFACE_NAME}"
|
||||||
|
echo " systemctl status wg-quick@${INTERFACE_NAME}"
|
||||||
|
echo ""
|
||||||
|
print_status "To view logs:"
|
||||||
|
echo " journalctl -u wg-quick@${INTERFACE_NAME} -f"
|
||||||
|
else
|
||||||
|
print_status "Configuration complete! To enable WireGuard:"
|
||||||
|
echo " sudo cp $CONFIG_FILE /etc/wireguard/"
|
||||||
|
echo " sudo chmod 600 /etc/wireguard/${INTERFACE_NAME}.conf"
|
||||||
|
echo " sudo systemctl enable --now wg-quick@${INTERFACE_NAME}"
|
||||||
|
echo ""
|
||||||
|
print_status "To check status (requires root):"
|
||||||
|
echo " sudo wg show ${INTERFACE_NAME}"
|
||||||
|
echo " sudo systemctl status wg-quick@${INTERFACE_NAME}"
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
echo -e "${RED}========================================${NC}"
|
||||||
|
echo -e "${RED} !!! NOW UPDATE ZION SERVER !!! ${NC}"
|
||||||
|
echo -e "${RED}========================================${NC}"
|
||||||
|
echo ""
|
||||||
|
print_warning "You MUST add this peer to Zion's config (/etc/wireguard/wg0.conf):"
|
||||||
|
echo ""
|
||||||
|
echo -e "${YELLOW}#$HOSTNAME${NC}"
|
||||||
|
echo -e "${YELLOW}[Peer]${NC}"
|
||||||
|
echo -e "${YELLOW}PublicKey = $PUBLIC_KEY${NC}"
|
||||||
|
echo -e "${YELLOW}AllowedIPs = $IP_ADDRESS/32${NC}"
|
||||||
|
echo ""
|
||||||
|
print_warning "After updating Zion, restart its WireGuard:"
|
||||||
|
echo " systemctl restart wg-quick@wg0"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Add endpoint-specific instructions for full tunnel mode
|
||||||
|
if [[ "$ROUTING_MODE" == "full_tunnel" ]]; then
|
||||||
|
echo ""
|
||||||
|
print_warning "FULL TUNNEL MODE DETECTED - Endpoint Changes Required:"
|
||||||
|
echo ""
|
||||||
|
echo "Since this node will route ALL traffic through the VPN, you need to:"
|
||||||
|
echo ""
|
||||||
|
echo "1. Update Zion's config (/etc/wireguard/wg0.conf) to allow this peer:"
|
||||||
|
echo " - Add the peer section as shown above"
|
||||||
|
echo " - Ensure Zion has proper iptables rules for NAT/masquerading"
|
||||||
|
echo ""
|
||||||
|
echo "2. Check Zion's iptables rules (run on Zion server):"
|
||||||
|
echo " sudo iptables -t nat -L POSTROUTING"
|
||||||
|
echo " sudo iptables -L FORWARD"
|
||||||
|
echo ""
|
||||||
|
echo "3. If Zion doesn't have proper NAT rules, add them:"
|
||||||
|
echo " sudo iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE"
|
||||||
|
echo " sudo iptables -A FORWARD -i wg0 -j ACCEPT"
|
||||||
|
echo " sudo iptables -A FORWARD -o wg0 -j ACCEPT"
|
||||||
|
echo ""
|
||||||
|
echo "4. Enable IP forwarding on Zion (if not already enabled):"
|
||||||
|
echo " echo 'net.ipv4.ip_forward=1' | sudo tee -a /etc/sysctl.conf"
|
||||||
|
echo " sudo sysctl -p"
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$RUNNING_AS_ROOT" == "true" ]]; then
|
||||||
|
print_warning "Then restart this node's WireGuard:"
|
||||||
|
echo " systemctl restart wg-quick@${INTERFACE_NAME}"
|
||||||
|
else
|
||||||
|
print_warning "Then restart this node's WireGuard:"
|
||||||
|
echo " sudo systemctl restart wg-quick@${INTERFACE_NAME}"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo -e "${BLUE}Step $([[ "$RUNNING_AS_ROOT" == "false" ]] && echo "5" || echo "4"): Next Steps${NC}"
|
||||||
|
echo ""
|
||||||
|
print_status "Keys generated successfully!"
|
||||||
|
echo " Private key: $WG_DIR/${HOSTNAME}_private.key"
|
||||||
|
echo " Public key: $WG_DIR/${HOSTNAME}_public.key"
|
||||||
|
echo ""
|
||||||
|
print_warning "Next steps:"
|
||||||
|
echo " - Create ${INTERFACE_NAME}.conf manually using the keys above"
|
||||||
|
echo " - Copy config to $CONFIG_FILE"
|
||||||
|
if [[ "$RUNNING_AS_ROOT" == "true" ]]; then
|
||||||
|
echo " - Set permissions: chmod 600 $CONFIG_FILE"
|
||||||
|
echo " - Enable/start: systemctl enable --now wg-quick@${INTERFACE_NAME}"
|
||||||
|
else
|
||||||
|
echo " - Copy to system: sudo cp $CONFIG_FILE /etc/wireguard/"
|
||||||
|
echo " - Set permissions: sudo chmod 600 /etc/wireguard/${INTERFACE_NAME}.conf"
|
||||||
|
echo " - Enable/start: sudo systemctl enable --now wg-quick@${INTERFACE_NAME}"
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
echo -e "${RED}========================================${NC}"
|
||||||
|
echo -e "${RED} !!! NOW UPDATE ZION SERVER !!! ${NC}"
|
||||||
|
echo -e "${RED}========================================${NC}"
|
||||||
|
echo ""
|
||||||
|
print_warning "You MUST add this peer to Zion's config (/etc/wireguard/wg0.conf):"
|
||||||
|
echo ""
|
||||||
|
echo -e "${YELLOW}#$HOSTNAME${NC}"
|
||||||
|
echo -e "${YELLOW}[Peer]${NC}"
|
||||||
|
echo -e "${YELLOW}PublicKey = $PUBLIC_KEY${NC}"
|
||||||
|
echo -e "${YELLOW}AllowedIPs = $IP_ADDRESS/32${NC}"
|
||||||
|
echo ""
|
||||||
|
print_warning "After updating Zion, restart its WireGuard:"
|
||||||
|
echo " systemctl restart wg-quick@wg0"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Add endpoint-specific instructions for full tunnel mode (manual path)
|
||||||
|
if [[ "${ROUTING_MODE:-wg_only}" == "full_tunnel" ]]; then
|
||||||
|
echo ""
|
||||||
|
print_warning "FULL TUNNEL MODE DETECTED - Endpoint Changes Required:"
|
||||||
|
echo ""
|
||||||
|
echo "Since this node will route ALL traffic through the VPN, you need to:"
|
||||||
|
echo ""
|
||||||
|
echo "1. Update Zion's config (/etc/wireguard/wg0.conf) to allow this peer:"
|
||||||
|
echo " - Add the peer section as shown above"
|
||||||
|
echo " - Ensure Zion has proper iptables rules for NAT/masquerading"
|
||||||
|
echo ""
|
||||||
|
echo "2. Check Zion's iptables rules (run on Zion server):"
|
||||||
|
echo " sudo iptables -t nat -L POSTROUTING"
|
||||||
|
echo " sudo iptables -L FORWARD"
|
||||||
|
echo ""
|
||||||
|
echo "3. If Zion doesn't have proper NAT rules, add them:"
|
||||||
|
echo " sudo iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE"
|
||||||
|
echo " sudo iptables -A FORWARD -i wg0 -j ACCEPT"
|
||||||
|
echo " sudo iptables -A FORWARD -o wg0 -j ACCEPT"
|
||||||
|
echo ""
|
||||||
|
echo "4. Enable IP forwarding on Zion (if not already enabled):"
|
||||||
|
echo " echo 'net.ipv4.ip_forward=1' | sudo tee -a /etc/sysctl.conf"
|
||||||
|
echo " sudo sysctl -p"
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$RUNNING_AS_ROOT" == "true" ]]; then
|
||||||
|
print_warning "Then restart this node's WireGuard:"
|
||||||
|
echo " systemctl restart wg-quick@${INTERFACE_NAME}"
|
||||||
|
else
|
||||||
|
print_warning "Then restart this node's WireGuard:"
|
||||||
|
echo " sudo systemctl restart wg-quick@${INTERFACE_NAME}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
print_status "Setup complete for $HOSTNAME!"
|
||||||
|
print_status "Log file available at: $log_file"
|
||||||
|
echo ""
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
74
test_overwrite_protection.sh
Executable file
74
test_overwrite_protection.sh
Executable file
@@ -0,0 +1,74 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Test script to demonstrate file overwrite protection
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
NC='\033[0m'
|
||||||
|
|
||||||
|
print_status() {
|
||||||
|
echo -e "${GREEN}[INFO]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_warning() {
|
||||||
|
echo -e "${YELLOW}[WARNING]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_header() {
|
||||||
|
echo -e "${BLUE}================================${NC}"
|
||||||
|
echo -e "${BLUE}$1${NC}"
|
||||||
|
echo -e "${BLUE}================================${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_header "Testing File Overwrite Protection"
|
||||||
|
|
||||||
|
echo "This test will demonstrate the file overwrite protection feature."
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Create a test configuration file first
|
||||||
|
print_status "Creating a test configuration file..."
|
||||||
|
mkdir -p wireguard_configs
|
||||||
|
echo "# Test configuration" > wireguard_configs/test_node.conf
|
||||||
|
echo "This is a test file" >> wireguard_configs/test_node.conf
|
||||||
|
|
||||||
|
print_status "Test file created: wireguard_configs/test_node.conf"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Test 1: Try to create a configuration with the same name (should prompt for overwrite)
|
||||||
|
print_header "Test 1: Attempting to create configuration with existing name"
|
||||||
|
|
||||||
|
echo "Now we'll try to create a configuration with the same name 'test_node'"
|
||||||
|
echo "The script should detect the existing file and ask if you want to overwrite it."
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Create test input that will trigger the overwrite prompt
|
||||||
|
cat > /tmp/test_overwrite_input.txt << 'EOF'
|
||||||
|
test_node
|
||||||
|
10.8.0.5/24
|
||||||
|
n
|
||||||
|
n
|
||||||
|
n
|
||||||
|
EOF
|
||||||
|
|
||||||
|
print_status "Running setup script..."
|
||||||
|
echo "When prompted, you can choose:"
|
||||||
|
echo " 'y' to overwrite the existing file"
|
||||||
|
echo " 'n' to cancel the operation"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Run the setup script
|
||||||
|
./wireguard_setup.sh < /tmp/test_overwrite_input.txt
|
||||||
|
|
||||||
|
# Clean up
|
||||||
|
rm -f /tmp/test_overwrite_input.txt
|
||||||
|
|
||||||
|
print_status "Test completed!"
|
||||||
|
echo ""
|
||||||
|
echo "The script should have:"
|
||||||
|
echo "1. Detected the existing test_node.conf file"
|
||||||
|
echo "2. Asked if you wanted to overwrite it"
|
||||||
|
echo "3. Either overwritten it (if you chose 'y') or cancelled (if you chose 'n')"
|
||||||
58
test_zion_peer.sh
Executable file
58
test_zion_peer.sh
Executable file
@@ -0,0 +1,58 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Test script to demonstrate Zion default peer feature
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
NC='\033[0m'
|
||||||
|
|
||||||
|
print_status() {
|
||||||
|
echo -e "${GREEN}[INFO]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_header() {
|
||||||
|
echo -e "${BLUE}================================${NC}"
|
||||||
|
echo -e "${BLUE}$1${NC}"
|
||||||
|
echo -e "${BLUE}================================${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_header "Testing Zion Default Peer Feature"
|
||||||
|
|
||||||
|
echo "This test will create a client configuration with Zion as the default peer."
|
||||||
|
echo "The script will automatically include Zion's connection details."
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Create test input for a client configuration
|
||||||
|
cat > /tmp/test_zion_input.txt << 'EOF'
|
||||||
|
test_client
|
||||||
|
10.8.0.5/24
|
||||||
|
n
|
||||||
|
y
|
||||||
|
n
|
||||||
|
EOF
|
||||||
|
|
||||||
|
print_status "Running setup script with test configuration..."
|
||||||
|
echo "Input will be:"
|
||||||
|
echo " Node name: test_client"
|
||||||
|
echo " IP: 10.8.0.5/24"
|
||||||
|
echo " Server mode: n (no)"
|
||||||
|
echo " Add Zion: y (yes)"
|
||||||
|
echo " Add additional peers: n (no)"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Run the setup script
|
||||||
|
./wireguard_setup.sh < /tmp/test_zion_input.txt
|
||||||
|
|
||||||
|
# Clean up
|
||||||
|
rm -f /tmp/test_zion_input.txt
|
||||||
|
|
||||||
|
print_status "Test completed! Check wireguard_configs/test_client.conf"
|
||||||
|
echo ""
|
||||||
|
echo "The generated configuration should include Zion as a peer with:"
|
||||||
|
echo " Public Key: 2ztJbrN1x1NWanzPGLiKL19ZkdOhm5Y7WeKEWBT5cyg="
|
||||||
|
echo " Endpoint: ugh.im:51820"
|
||||||
|
echo " Allowed IPs: 10.8.0.0/24"
|
||||||
|
echo " Persistent Keepalive: 25"
|
||||||
295
validate_config.sh
Executable file
295
validate_config.sh
Executable file
@@ -0,0 +1,295 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# WireGuard Configuration Validator
|
||||||
|
# This script validates WireGuard configuration files for common issues
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
NC='\033[0m'
|
||||||
|
|
||||||
|
print_status() {
|
||||||
|
echo -e "${GREEN}[PASS]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_warning() {
|
||||||
|
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_error() {
|
||||||
|
echo -e "${RED}[FAIL]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_header() {
|
||||||
|
echo -e "${BLUE}================================${NC}"
|
||||||
|
echo -e "${BLUE}$1${NC}"
|
||||||
|
echo -e "${BLUE}================================${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to validate IP address format
|
||||||
|
validate_ip() {
|
||||||
|
local ip=$1
|
||||||
|
if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/[0-9]{1,2}$ ]]; then
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to validate port number
|
||||||
|
validate_port() {
|
||||||
|
local port=$1
|
||||||
|
if [[ $port =~ ^[0-9]+$ ]] && [ $port -ge 1 ] && [ $port -le 65535 ]; then
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to validate WireGuard key format
|
||||||
|
validate_wg_key() {
|
||||||
|
local key=$1
|
||||||
|
# WireGuard keys are base64 encoded and typically 44 characters long
|
||||||
|
if [[ $key =~ ^[A-Za-z0-9+/]{43}=$ ]]; then
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to validate endpoint format
|
||||||
|
validate_endpoint() {
|
||||||
|
local endpoint=$1
|
||||||
|
if [[ $endpoint =~ ^[a-zA-Z0-9.-]+:[0-9]+$ ]]; then
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to validate a single configuration file
|
||||||
|
validate_config_file() {
|
||||||
|
local config_file=$1
|
||||||
|
local errors=0
|
||||||
|
local warnings=0
|
||||||
|
|
||||||
|
print_header "Validating: $config_file"
|
||||||
|
|
||||||
|
if [ ! -f "$config_file" ]; then
|
||||||
|
print_error "Configuration file not found: $config_file"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check file permissions
|
||||||
|
local perms=$(stat -c %a "$config_file")
|
||||||
|
if [ "$perms" != "600" ]; then
|
||||||
|
print_warning "File permissions should be 600, current: $perms"
|
||||||
|
((warnings++))
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Parse the configuration file
|
||||||
|
local in_interface=0
|
||||||
|
local in_peer=0
|
||||||
|
local has_interface=0
|
||||||
|
local has_private_key=0
|
||||||
|
local has_address=0
|
||||||
|
local peer_count=0
|
||||||
|
|
||||||
|
while IFS= read -r line; do
|
||||||
|
# Skip comments and empty lines
|
||||||
|
if [[ $line =~ ^[[:space:]]*# ]] || [[ -z "${line// }" ]]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for Interface section
|
||||||
|
if [[ $line =~ ^\[Interface\] ]]; then
|
||||||
|
in_interface=1
|
||||||
|
in_peer=0
|
||||||
|
has_interface=1
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for Peer section
|
||||||
|
if [[ $line =~ ^\[Peer\] ]]; then
|
||||||
|
in_interface=0
|
||||||
|
in_peer=1
|
||||||
|
((peer_count++))
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Parse Interface section
|
||||||
|
if [ $in_interface -eq 1 ]; then
|
||||||
|
if [[ $line =~ ^PrivateKey[[:space:]]*=[[:space:]]*(.+)$ ]]; then
|
||||||
|
local private_key="${BASH_REMATCH[1]}"
|
||||||
|
if validate_wg_key "$private_key"; then
|
||||||
|
print_status "Valid private key found"
|
||||||
|
has_private_key=1
|
||||||
|
else
|
||||||
|
print_error "Invalid private key format"
|
||||||
|
((errors++))
|
||||||
|
fi
|
||||||
|
elif [[ $line =~ ^Address[[:space:]]*=[[:space:]]*(.+)$ ]]; then
|
||||||
|
local address="${BASH_REMATCH[1]}"
|
||||||
|
if validate_ip "$address"; then
|
||||||
|
print_status "Valid address: $address"
|
||||||
|
has_address=1
|
||||||
|
else
|
||||||
|
print_error "Invalid address format: $address"
|
||||||
|
((errors++))
|
||||||
|
fi
|
||||||
|
elif [[ $line =~ ^ListenPort[[:space:]]*=[[:space:]]*(.+)$ ]]; then
|
||||||
|
local port="${BASH_REMATCH[1]}"
|
||||||
|
if validate_port "$port"; then
|
||||||
|
print_status "Valid listen port: $port"
|
||||||
|
else
|
||||||
|
print_error "Invalid listen port: $port"
|
||||||
|
((errors++))
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Parse Peer section
|
||||||
|
if [ $in_peer -eq 1 ]; then
|
||||||
|
if [[ $line =~ ^PublicKey[[:space:]]*=[[:space:]]*(.+)$ ]]; then
|
||||||
|
local public_key="${BASH_REMATCH[1]}"
|
||||||
|
if validate_wg_key "$public_key"; then
|
||||||
|
print_status "Valid peer public key"
|
||||||
|
else
|
||||||
|
print_error "Invalid peer public key format"
|
||||||
|
((errors++))
|
||||||
|
fi
|
||||||
|
elif [[ $line =~ ^AllowedIPs[[:space:]]*=[[:space:]]*(.+)$ ]]; then
|
||||||
|
local allowed_ips="${BASH_REMATCH[1]}"
|
||||||
|
# Split multiple IPs if present
|
||||||
|
IFS=',' read -ra IP_ARRAY <<< "$allowed_ips"
|
||||||
|
for ip in "${IP_ARRAY[@]}"; do
|
||||||
|
ip=$(echo "$ip" | xargs) # Trim whitespace
|
||||||
|
if validate_ip "$ip"; then
|
||||||
|
print_status "Valid allowed IP: $ip"
|
||||||
|
else
|
||||||
|
print_error "Invalid allowed IP format: $ip"
|
||||||
|
((errors++))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
elif [[ $line =~ ^Endpoint[[:space:]]*=[[:space:]]*(.+)$ ]]; then
|
||||||
|
local endpoint="${BASH_REMATCH[1]}"
|
||||||
|
if validate_endpoint "$endpoint"; then
|
||||||
|
print_status "Valid endpoint: $endpoint"
|
||||||
|
else
|
||||||
|
print_error "Invalid endpoint format: $endpoint"
|
||||||
|
((errors++))
|
||||||
|
fi
|
||||||
|
elif [[ $line =~ ^PersistentKeepalive[[:space:]]*=[[:space:]]*(.+)$ ]]; then
|
||||||
|
local keepalive="${BASH_REMATCH[1]}"
|
||||||
|
if validate_port "$keepalive"; then
|
||||||
|
print_status "Valid persistent keepalive: $keepalive"
|
||||||
|
else
|
||||||
|
print_error "Invalid persistent keepalive: $keepalive"
|
||||||
|
((errors++))
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done < "$config_file"
|
||||||
|
|
||||||
|
# Check required fields
|
||||||
|
if [ $has_interface -eq 0 ]; then
|
||||||
|
print_error "Missing [Interface] section"
|
||||||
|
((errors++))
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $has_private_key -eq 0 ]; then
|
||||||
|
print_error "Missing PrivateKey in [Interface] section"
|
||||||
|
((errors++))
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $has_address -eq 0 ]; then
|
||||||
|
print_error "Missing Address in [Interface] section"
|
||||||
|
((errors++))
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $peer_count -eq 0 ]; then
|
||||||
|
print_warning "No [Peer] sections found"
|
||||||
|
((warnings++))
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Summary
|
||||||
|
echo ""
|
||||||
|
if [ $errors -eq 0 ] && [ $warnings -eq 0 ]; then
|
||||||
|
print_status "Configuration file is valid!"
|
||||||
|
return 0
|
||||||
|
elif [ $errors -eq 0 ]; then
|
||||||
|
print_warning "Configuration file has $warnings warning(s)"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
print_error "Configuration file has $errors error(s) and $warnings warning(s)"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to validate all config files in a directory
|
||||||
|
validate_directory() {
|
||||||
|
local dir=$1
|
||||||
|
local total_errors=0
|
||||||
|
local total_files=0
|
||||||
|
|
||||||
|
print_header "Validating all config files in: $dir"
|
||||||
|
|
||||||
|
if [ ! -d "$dir" ]; then
|
||||||
|
print_error "Directory not found: $dir"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
for config_file in "$dir"/*.conf; do
|
||||||
|
if [ -f "$config_file" ]; then
|
||||||
|
((total_files++))
|
||||||
|
if ! validate_config_file "$config_file"; then
|
||||||
|
((total_errors++))
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ $total_files -eq 0 ]; then
|
||||||
|
print_warning "No .conf files found in $dir"
|
||||||
|
else
|
||||||
|
print_header "Validation Summary"
|
||||||
|
echo "Total files: $total_files"
|
||||||
|
echo "Files with errors: $total_errors"
|
||||||
|
echo "Files without errors: $((total_files - total_errors))"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Show usage
|
||||||
|
show_usage() {
|
||||||
|
echo "Usage: $0 [OPTIONS] <config_file_or_directory>"
|
||||||
|
echo ""
|
||||||
|
echo "Options:"
|
||||||
|
echo " -h, --help Show this help message"
|
||||||
|
echo ""
|
||||||
|
echo "Examples:"
|
||||||
|
echo " $0 wireguard_configs/test.conf # Validate single file"
|
||||||
|
echo " $0 wireguard_configs/ # Validate all files in directory"
|
||||||
|
echo " $0 TESTING/ # Validate TESTING directory"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main logic
|
||||||
|
if [ $# -eq 0 ] || [[ $1 =~ ^- ]]; then
|
||||||
|
show_usage
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
target=$1
|
||||||
|
|
||||||
|
if [ -f "$target" ]; then
|
||||||
|
validate_config_file "$target"
|
||||||
|
elif [ -d "$target" ]; then
|
||||||
|
validate_directory "$target"
|
||||||
|
else
|
||||||
|
print_error "Target not found: $target"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
1
wireguard_configs/cachybot_private.key
Normal file
1
wireguard_configs/cachybot_private.key
Normal file
@@ -0,0 +1 @@
|
|||||||
|
6Ag2qgqY85gMrp9gvbqjSAM6jJIGQds737HDfKnTM0s=
|
||||||
1
wireguard_configs/cachybot_public.key
Normal file
1
wireguard_configs/cachybot_public.key
Normal file
@@ -0,0 +1 @@
|
|||||||
|
fqtkYEqAOBXQzmUGVNSloLawNyrVIOqV/Vv2FvVmrho=
|
||||||
20
wireguard_configs/cachybot_wg0.conf
Normal file
20
wireguard_configs/cachybot_wg0.conf
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# ================================================
|
||||||
|
# Node: cachybot
|
||||||
|
# PublicKey: fqtkYEqAOBXQzmUGVNSloLawNyrVIOqV/Vv2FvVmrho=
|
||||||
|
#
|
||||||
|
# Add this peer to Zion (/etc/wireguard/wg0.conf):
|
||||||
|
# [Peer]
|
||||||
|
# PublicKey = fqtkYEqAOBXQzmUGVNSloLawNyrVIOqV/Vv2FvVmrho=
|
||||||
|
# AllowedIPs = 10.8.0.26/32
|
||||||
|
# ================================================
|
||||||
|
|
||||||
|
[Interface]
|
||||||
|
Address = 10.8.0.26/24
|
||||||
|
PrivateKey = 6Ag2qgqY85gMrp9gvbqjSAM6jJIGQds737HDfKnTM0s=
|
||||||
|
|
||||||
|
# Zion (central server)
|
||||||
|
[Peer]
|
||||||
|
PublicKey = 2ztJbrN1x1NWanzPGLiKL19ZkdOhm5Y7WeKEWBT5cyg=
|
||||||
|
AllowedIPs = 10.8.0.0/24
|
||||||
|
Endpoint = ugh.im:51820
|
||||||
|
PersistentKeepalive = 25
|
||||||
1
wireguard_configs/leviathan_private.key
Normal file
1
wireguard_configs/leviathan_private.key
Normal file
@@ -0,0 +1 @@
|
|||||||
|
CAco1G1O4Ffd6x8a5CDRpxMK35iO5JM/BkxKeC+Pu0c=
|
||||||
1
wireguard_configs/leviathan_public.key
Normal file
1
wireguard_configs/leviathan_public.key
Normal file
@@ -0,0 +1 @@
|
|||||||
|
GEVjkJgHTvMRr9ka92dafoq1b8fPZ3HZyo2FgBsoqkE=
|
||||||
20
wireguard_configs/leviathan_wg0.conf
Normal file
20
wireguard_configs/leviathan_wg0.conf
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# ================================================
|
||||||
|
# Node: leviathan
|
||||||
|
# PublicKey: GEVjkJgHTvMRr9ka92dafoq1b8fPZ3HZyo2FgBsoqkE=
|
||||||
|
#
|
||||||
|
# Add this peer to Zion (/etc/wireguard/wg0.conf):
|
||||||
|
# [Peer]
|
||||||
|
# PublicKey = GEVjkJgHTvMRr9ka92dafoq1b8fPZ3HZyo2FgBsoqkE=
|
||||||
|
# AllowedIPs = 10.8.0.24/32
|
||||||
|
# ================================================
|
||||||
|
|
||||||
|
[Interface]
|
||||||
|
Address = 10.8.0.24/24
|
||||||
|
PrivateKey = CAco1G1O4Ffd6x8a5CDRpxMK35iO5JM/BkxKeC+Pu0c=
|
||||||
|
|
||||||
|
# Zion (central server)
|
||||||
|
[Peer]
|
||||||
|
PublicKey = 2ztJbrN1x1NWanzPGLiKL19ZkdOhm5Y7WeKEWBT5cyg=
|
||||||
|
AllowedIPs = 10.8.0.0/24
|
||||||
|
Endpoint = ugh.im:51820
|
||||||
|
PersistentKeepalive = 25
|
||||||
1
wireguard_configs/nano_private.key
Normal file
1
wireguard_configs/nano_private.key
Normal file
@@ -0,0 +1 @@
|
|||||||
|
CFh3Ksl6IXmnv+oku/o1vJDSnfC0F9LMZS9Zb/hWGk8=
|
||||||
1
wireguard_configs/nano_public.key
Normal file
1
wireguard_configs/nano_public.key
Normal file
@@ -0,0 +1 @@
|
|||||||
|
FGrMAZPCUiQsFHW55PhkNr9AliR4+sw3uRLTbcilmFc=
|
||||||
20
wireguard_configs/nano_wg0.conf
Normal file
20
wireguard_configs/nano_wg0.conf
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# ================================================
|
||||||
|
# Node: nano
|
||||||
|
# PublicKey: FGrMAZPCUiQsFHW55PhkNr9AliR4+sw3uRLTbcilmFc=
|
||||||
|
#
|
||||||
|
# Add this peer to Zion (/etc/wireguard/wg0.conf):
|
||||||
|
# [Peer]
|
||||||
|
# PublicKey = FGrMAZPCUiQsFHW55PhkNr9AliR4+sw3uRLTbcilmFc=
|
||||||
|
# AllowedIPs = 10.8.0.26/32
|
||||||
|
# ================================================
|
||||||
|
|
||||||
|
[Interface]
|
||||||
|
Address = 10.8.0.26/24
|
||||||
|
PrivateKey = CFh3Ksl6IXmnv+oku/o1vJDSnfC0F9LMZS9Zb/hWGk8=
|
||||||
|
|
||||||
|
# Zion (central server)
|
||||||
|
[Peer]
|
||||||
|
PublicKey = 2ztJbrN1x1NWanzPGLiKL19ZkdOhm5Y7WeKEWBT5cyg=
|
||||||
|
AllowedIPs = 10.8.0.0/24
|
||||||
|
Endpoint = ugh.im:51820
|
||||||
|
PersistentKeepalive = 25
|
||||||
12
wireguard_configs/pix66.conf
Normal file
12
wireguard_configs/pix66.conf
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
[Interface]
|
||||||
|
PrivateKey = iKNfR2fY/zI2mc8EDToXGrTR2mPOyMn1MY5/3Wq80HY=
|
||||||
|
Address = 10.8.0.6/32
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#CTH
|
||||||
|
[Peer]
|
||||||
|
PublicKey = NBktXKy1s0n2lIlIMODvOqKNwAtYdoZH5feKt5P43i0=
|
||||||
|
AllowedIPs = 10.8.0.10/24
|
||||||
|
Endpoint = aw2cd67.glddns.com:53535
|
||||||
|
PersistentKeepalive = 25
|
||||||
22
wireguard_configs/pix66_summary.txt
Normal file
22
wireguard_configs/pix66_summary.txt
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
WireGuard Configuration Summary for pix66
|
||||||
|
===============================================
|
||||||
|
|
||||||
|
Node Name: pix66
|
||||||
|
IP Address: 10.8.0.66/32
|
||||||
|
|
||||||
|
|
||||||
|
Your Public Key: hguz42G5S8EV3NmkORc6eiBWb+V9Z6oBdiXVnAcqvmI=
|
||||||
|
Your Private Key: iKNfR2fY/zI2mc8EDToXGrTR2mPOyMn1MY5/3Wq80HY=
|
||||||
|
|
||||||
|
Configuration File: wireguard_configs/pix66.conf
|
||||||
|
|
||||||
|
Commands to use:
|
||||||
|
- Start: sudo wg-quick up pix66
|
||||||
|
- Stop: sudo wg-quick down pix66
|
||||||
|
- Status: sudo wg show
|
||||||
|
|
||||||
|
Remember to:
|
||||||
|
1. Keep your private key secure
|
||||||
|
2. Share your public key with peers
|
||||||
|
3. Add peer public keys to your configuration
|
||||||
|
4. Set proper file permissions: chmod 600 wireguard_configs/pix66.conf
|
||||||
1
wireguard_configs/pixel6_private.key
Normal file
1
wireguard_configs/pixel6_private.key
Normal file
@@ -0,0 +1 @@
|
|||||||
|
yK7AJfrfs6INevH2AZUWpCrltYqe81Pc+mZ/LJsInVc=
|
||||||
1
wireguard_configs/pixel6_public.key
Normal file
1
wireguard_configs/pixel6_public.key
Normal file
@@ -0,0 +1 @@
|
|||||||
|
KHXrXOsLwYr8iDXXB/E0AVVG2EKFQKCGLY8aLniOUl4=
|
||||||
11
wireguard_configs/pixel6_wg_info.json
Normal file
11
wireguard_configs/pixel6_wg_info.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"hostname": "pixel6",
|
||||||
|
"ip_address": "10.8.0.6",
|
||||||
|
"private_key": "yK7AJfrfs6INevH2AZUWpCrltYqe81Pc+mZ/LJsInVc=",
|
||||||
|
"public_key": "KHXrXOsLwYr8iDXXB/E0AVVG2EKFQKCGLY8aLniOUl4=",
|
||||||
|
"routing_mode": "full_tunnel",
|
||||||
|
"interface": "pixwg0",
|
||||||
|
"generated": "2025-08-10T05:59:41-07:00",
|
||||||
|
"script_version": "3.0.0",
|
||||||
|
"running_as_root": false
|
||||||
|
}
|
||||||
859
wireguard_setup.go
Normal file
859
wireguard_setup.go
Normal file
@@ -0,0 +1,859 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/curve25519"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Colors for terminal output
|
||||||
|
const (
|
||||||
|
Red = "\033[0;31m"
|
||||||
|
Green = "\033[0;32m"
|
||||||
|
Yellow = "\033[1;33m"
|
||||||
|
Blue = "\033[0;34m"
|
||||||
|
Reset = "\033[0m"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Script constants
|
||||||
|
const (
|
||||||
|
ScriptVersion = "3.0.0"
|
||||||
|
DefaultPort = "51820"
|
||||||
|
MaxHostname = 63
|
||||||
|
MaxInterface = 15
|
||||||
|
)
|
||||||
|
|
||||||
|
// WireGuard peer configuration
|
||||||
|
type WireGuardPeer struct {
|
||||||
|
Name string
|
||||||
|
PublicKey string
|
||||||
|
AllowedIPs string
|
||||||
|
Endpoint string
|
||||||
|
PersistentKeepalive int
|
||||||
|
Description string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Node configuration
|
||||||
|
type NodeConfig struct {
|
||||||
|
Hostname string `json:"hostname"`
|
||||||
|
IPAddress string `json:"ip_address"`
|
||||||
|
PrivateKey string `json:"private_key"`
|
||||||
|
PublicKey string `json:"public_key"`
|
||||||
|
RoutingMode string `json:"routing_mode"`
|
||||||
|
Interface string `json:"interface"`
|
||||||
|
Generated string `json:"generated"`
|
||||||
|
ScriptVer string `json:"script_version"`
|
||||||
|
RunningRoot bool `json:"running_as_root"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Application state
|
||||||
|
type AppState struct {
|
||||||
|
ForceMode bool
|
||||||
|
RunningAsRoot bool
|
||||||
|
WGDirectory string
|
||||||
|
StepCounter int
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default peers - automatically included in every config
|
||||||
|
var defaultPeers = []WireGuardPeer{
|
||||||
|
{
|
||||||
|
Name: "Zion",
|
||||||
|
PublicKey: "2ztJbrN1x1NWanzPGLiKL19ZkdOhm5Y7WeKEWBT5cyg=",
|
||||||
|
AllowedIPs: "10.8.0.0/24",
|
||||||
|
Endpoint: "ugh.im:51820",
|
||||||
|
PersistentKeepalive: 25,
|
||||||
|
Description: "Central server (always included)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "CTH",
|
||||||
|
PublicKey: "NBktXKy1s0n2lIlIMODvOqKNwAtYdoZH5feKt5P43i0=",
|
||||||
|
AllowedIPs: "10.8.0.10/32",
|
||||||
|
Endpoint: "aw2cd67.glddns.com:53535",
|
||||||
|
PersistentKeepalive: 25,
|
||||||
|
Description: "Secondary server (always included)",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reserved IP addresses
|
||||||
|
var reservedIPs = map[string]string{
|
||||||
|
"10.8.0.1": "Zion",
|
||||||
|
"10.8.0.10": "CTH",
|
||||||
|
"10.8.0.2": "Aza",
|
||||||
|
"10.8.0.20": "Nyar",
|
||||||
|
"10.8.0.99": "Galaxy",
|
||||||
|
"10.8.0.7": "nanocube",
|
||||||
|
"10.8.0.42": "jupiter",
|
||||||
|
"10.8.0.8": "HASS",
|
||||||
|
"10.8.0.40": "framebot",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Static server ports
|
||||||
|
var staticServerPorts = map[string]string{
|
||||||
|
"10.8.0.1": "51820", // Zion
|
||||||
|
"10.8.0.10": "53535", // CTH
|
||||||
|
"10.8.0.99": "54382", // Galaxy
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validation regexes
|
||||||
|
var (
|
||||||
|
ipRegex = regexp.MustCompile(`^10\.8\.0\.\d{1,3}$`)
|
||||||
|
hostnameRegex = regexp.MustCompile(`^[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]$|^[a-zA-Z0-9]$`)
|
||||||
|
interfaceRegex = regexp.MustCompile(`^[a-zA-Z][a-zA-Z0-9]*$`)
|
||||||
|
keyRegex = regexp.MustCompile(`^[A-Za-z0-9+/]{43}=$`)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Utility functions
|
||||||
|
func step(n int, msg string) {
|
||||||
|
fmt.Printf("%sStep %d:%s %s\n", Blue, n, Reset, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func printStatus(message string) {
|
||||||
|
fmt.Printf("%s[INFO]%s %s\n", Green, Reset, message)
|
||||||
|
}
|
||||||
|
|
||||||
|
func printWarning(message string) {
|
||||||
|
fmt.Printf("%s[WARNING]%s %s\n", Yellow, Reset, message)
|
||||||
|
}
|
||||||
|
|
||||||
|
func printError(message string) {
|
||||||
|
fmt.Printf("%s[ERROR]%s %s\n", Red, Reset, message)
|
||||||
|
}
|
||||||
|
|
||||||
|
func printHeader(title string) {
|
||||||
|
fmt.Printf("%s================================%s\n", Blue, Reset)
|
||||||
|
fmt.Printf("%s%s%s\n", Blue, title, Reset)
|
||||||
|
fmt.Printf("%s================================%s\n", Blue, Reset)
|
||||||
|
fmt.Println()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validation functions
|
||||||
|
func validateHostname(hostname string) error {
|
||||||
|
if hostname == "" {
|
||||||
|
return fmt.Errorf("hostname cannot be empty")
|
||||||
|
}
|
||||||
|
if len(hostname) > MaxHostname {
|
||||||
|
return fmt.Errorf("hostname too long (max %d characters)", MaxHostname)
|
||||||
|
}
|
||||||
|
if !hostnameRegex.MatchString(hostname) {
|
||||||
|
return fmt.Errorf("invalid hostname format. Use alphanumeric characters and hyphens only")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateIP(ip string) error {
|
||||||
|
if ip == "" {
|
||||||
|
return fmt.Errorf("IP address cannot be empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ipRegex.MatchString(ip) {
|
||||||
|
return fmt.Errorf("IP should be in 10.8.0.x range for NextGen network")
|
||||||
|
}
|
||||||
|
|
||||||
|
if parsedIP := net.ParseIP(ip); parsedIP == nil {
|
||||||
|
return fmt.Errorf("invalid IP address format")
|
||||||
|
}
|
||||||
|
|
||||||
|
if peerName, exists := reservedIPs[ip]; exists {
|
||||||
|
return fmt.Errorf("IP %s is already reserved for %s", ip, peerName)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateInterface(name string) error {
|
||||||
|
if name == "" {
|
||||||
|
return nil // Allow empty for default
|
||||||
|
}
|
||||||
|
if len(name) > MaxInterface {
|
||||||
|
return fmt.Errorf("interface name too long (max %d characters)", MaxInterface)
|
||||||
|
}
|
||||||
|
if !interfaceRegex.MatchString(name) {
|
||||||
|
return fmt.Errorf("interface name must start with a letter and contain only letters and numbers")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateWireGuardKey(key string) error {
|
||||||
|
if key == "" {
|
||||||
|
return fmt.Errorf("key cannot be empty")
|
||||||
|
}
|
||||||
|
if !keyRegex.MatchString(key) {
|
||||||
|
return fmt.Errorf("invalid WireGuard key format")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// User input functions
|
||||||
|
func getUserInput(prompt string, validator func(string) error, forceMode bool) string {
|
||||||
|
reader := bufio.NewReader(os.Stdin)
|
||||||
|
for {
|
||||||
|
fmt.Print(prompt)
|
||||||
|
input, _ := reader.ReadString('\n')
|
||||||
|
input = strings.TrimSpace(input)
|
||||||
|
|
||||||
|
if err := validator(input); err != nil {
|
||||||
|
if forceMode {
|
||||||
|
printWarning(fmt.Sprintf("Validation failed: %s, but continuing due to force mode", err.Error()))
|
||||||
|
return input
|
||||||
|
}
|
||||||
|
printError(err.Error())
|
||||||
|
fmt.Print("Continue anyway? (y/N): ")
|
||||||
|
response, _ := reader.ReadString('\n')
|
||||||
|
response = strings.TrimSpace(strings.ToLower(response))
|
||||||
|
if response == "y" || response == "yes" {
|
||||||
|
return input
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return input
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getDirectoryInput(prompt, defaultDir string, forceMode bool) string {
|
||||||
|
reader := bufio.NewReader(os.Stdin)
|
||||||
|
for {
|
||||||
|
fmt.Printf("%s [%s]: ", prompt, defaultDir)
|
||||||
|
input, _ := reader.ReadString('\n')
|
||||||
|
input = strings.TrimSpace(input)
|
||||||
|
|
||||||
|
if input == "" {
|
||||||
|
input = defaultDir
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if directory exists
|
||||||
|
if _, err := os.Stat(input); os.IsNotExist(err) {
|
||||||
|
if forceMode {
|
||||||
|
if err := os.MkdirAll(input, 0755); err != nil {
|
||||||
|
printError(fmt.Sprintf("Failed to create directory '%s': %v", input, err))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmt.Printf("Directory '%s' doesn't exist. Create it? (Y/n): ", input)
|
||||||
|
response, _ := reader.ReadString('\n')
|
||||||
|
response = strings.TrimSpace(strings.ToLower(response))
|
||||||
|
if response == "n" || response == "no" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.MkdirAll(input, 0755); err != nil {
|
||||||
|
printError(fmt.Sprintf("Failed to create directory '%s': %v", input, err))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if directory is writable
|
||||||
|
if info, err := os.Stat(input); err == nil {
|
||||||
|
if info.Mode()&0200 == 0 {
|
||||||
|
printError(fmt.Sprintf("Directory '%s' is not writable", input))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return input
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getYesNoInput(prompt string, defaultYes bool, forceMode bool) bool {
|
||||||
|
if forceMode {
|
||||||
|
return defaultYes
|
||||||
|
}
|
||||||
|
|
||||||
|
reader := bufio.NewReader(os.Stdin)
|
||||||
|
for {
|
||||||
|
if defaultYes {
|
||||||
|
fmt.Printf("%s (Y/n): ", prompt)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("%s (y/N): ", prompt)
|
||||||
|
}
|
||||||
|
input, _ := reader.ReadString('\n')
|
||||||
|
input = strings.TrimSpace(strings.ToLower(input))
|
||||||
|
|
||||||
|
if input == "" {
|
||||||
|
return defaultYes
|
||||||
|
}
|
||||||
|
if input == "y" || input == "yes" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if input == "n" || input == "no" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
printError("Please enter 'y' or 'n'")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getChoice(prompt string, choices []string, forceMode bool) int {
|
||||||
|
if forceMode && len(choices) > 0 {
|
||||||
|
return 1 // Default to first choice in force mode
|
||||||
|
}
|
||||||
|
|
||||||
|
reader := bufio.NewReader(os.Stdin)
|
||||||
|
for {
|
||||||
|
fmt.Println(prompt)
|
||||||
|
for i, choice := range choices {
|
||||||
|
fmt.Printf("%d. %s\n", i+1, choice)
|
||||||
|
}
|
||||||
|
fmt.Print("Enter your choice: ")
|
||||||
|
input, _ := reader.ReadString('\n')
|
||||||
|
input = strings.TrimSpace(input)
|
||||||
|
|
||||||
|
if choice, err := strconv.Atoi(input); err == nil && choice >= 1 && choice <= len(choices) {
|
||||||
|
return choice
|
||||||
|
}
|
||||||
|
printError(fmt.Sprintf("Invalid choice. Please enter a number between 1 and %d.", len(choices)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WireGuard key generation (safe version)
|
||||||
|
func generateWireGuardKeys() (string, string, error) {
|
||||||
|
// Generate private key
|
||||||
|
privateKeyBytes := make([]byte, 32)
|
||||||
|
if _, err := rand.Read(privateKeyBytes); err != nil {
|
||||||
|
return "", "", fmt.Errorf("failed to generate random bytes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure the key is valid for curve25519
|
||||||
|
privateKeyBytes[0] &= 248
|
||||||
|
privateKeyBytes[31] &= 127
|
||||||
|
privateKeyBytes[31] |= 64
|
||||||
|
|
||||||
|
// Generate public key (safe conversion)
|
||||||
|
var privateKeyArray [32]byte
|
||||||
|
copy(privateKeyArray[:], privateKeyBytes)
|
||||||
|
|
||||||
|
var publicKeyBytes [32]byte
|
||||||
|
curve25519.ScalarBaseMult(&publicKeyBytes, &privateKeyArray)
|
||||||
|
|
||||||
|
privateKey := base64.StdEncoding.EncodeToString(privateKeyBytes[:])
|
||||||
|
publicKey := base64.StdEncoding.EncodeToString(publicKeyBytes[:])
|
||||||
|
|
||||||
|
return privateKey, publicKey, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configuration generation
|
||||||
|
func generateConfig(hostname, ipAddress, privateKey, routingMode, interfaceName string) string {
|
||||||
|
var config strings.Builder
|
||||||
|
|
||||||
|
// Interface section
|
||||||
|
config.WriteString("[Interface]\n")
|
||||||
|
config.WriteString(fmt.Sprintf("Address = %s/24\n", ipAddress))
|
||||||
|
config.WriteString(fmt.Sprintf("PrivateKey = %s\n", privateKey))
|
||||||
|
|
||||||
|
// Add ListenPort for static servers
|
||||||
|
if port, exists := staticServerPorts[ipAddress]; exists {
|
||||||
|
config.WriteString(fmt.Sprintf("ListenPort = %s\n", port))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add DNS for full tunnel mode
|
||||||
|
if routingMode == "full_tunnel" {
|
||||||
|
config.WriteString("DNS = 1.1.1.1, 8.8.8.8\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add default peers
|
||||||
|
for _, peer := range defaultPeers {
|
||||||
|
config.WriteString(fmt.Sprintf("\n# %s (%s)\n", peer.Name, peer.Description))
|
||||||
|
config.WriteString("[Peer]\n")
|
||||||
|
config.WriteString(fmt.Sprintf("PublicKey = %s\n", peer.PublicKey))
|
||||||
|
|
||||||
|
// Set AllowedIPs based on routing mode
|
||||||
|
if routingMode == "full_tunnel" {
|
||||||
|
config.WriteString("AllowedIPs = 0.0.0.0/0, ::/0\n")
|
||||||
|
} else {
|
||||||
|
config.WriteString(fmt.Sprintf("AllowedIPs = %s\n", peer.AllowedIPs))
|
||||||
|
}
|
||||||
|
|
||||||
|
config.WriteString(fmt.Sprintf("Endpoint = %s\n", peer.Endpoint))
|
||||||
|
config.WriteString(fmt.Sprintf("PersistentKeepalive = %d\n", peer.PersistentKeepalive))
|
||||||
|
}
|
||||||
|
|
||||||
|
return config.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate peer configuration for Zion
|
||||||
|
func generateZionPeerConfig(hostname, publicKey, ipAddress string) string {
|
||||||
|
var config strings.Builder
|
||||||
|
config.WriteString(fmt.Sprintf("# %s\n", hostname))
|
||||||
|
config.WriteString("[Peer]\n")
|
||||||
|
config.WriteString(fmt.Sprintf("PublicKey = %s\n", publicKey))
|
||||||
|
config.WriteString(fmt.Sprintf("AllowedIPs = %s/32\n", ipAddress))
|
||||||
|
return config.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// System checks
|
||||||
|
func checkDependencies() error {
|
||||||
|
deps := []string{"wg", "wg-quick"}
|
||||||
|
|
||||||
|
for _, dep := range deps {
|
||||||
|
if _, err := exec.LookPath(dep); err != nil {
|
||||||
|
return fmt.Errorf("missing dependency: %s", dep)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isRunningAsRoot() bool {
|
||||||
|
return os.Geteuid() == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkFileExists(filepath string, forceMode bool) bool {
|
||||||
|
if _, err := os.Stat(filepath); err == nil {
|
||||||
|
if forceMode {
|
||||||
|
printWarning(fmt.Sprintf("File '%s' already exists, overwriting due to force mode", filepath))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
printWarning(fmt.Sprintf("File '%s' already exists", filepath))
|
||||||
|
return getYesNoInput("Do you want to overwrite it?", false, false)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display instructions
|
||||||
|
func displayZionInstructions(hostname, publicKey, ipAddress string) {
|
||||||
|
printHeader("IMPORTANT: Update Zion Server Configuration")
|
||||||
|
fmt.Println()
|
||||||
|
printWarning("You MUST add this peer to Zion's configuration file:")
|
||||||
|
fmt.Println(" /etc/wireguard/wg0.conf")
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
fmt.Println("Add the following peer section to Zion's config:")
|
||||||
|
fmt.Println("----------------------------------------")
|
||||||
|
fmt.Println(generateZionPeerConfig(hostname, publicKey, ipAddress))
|
||||||
|
fmt.Println("----------------------------------------")
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
printWarning("After updating Zion's config:")
|
||||||
|
fmt.Println("1. Save the file")
|
||||||
|
fmt.Println("2. Restart Zion's WireGuard: sudo systemctl restart wg-quick@wg0")
|
||||||
|
fmt.Println("3. Then start this node's WireGuard: sudo wg-quick up " + hostname)
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
// Show Zion's current configuration structure
|
||||||
|
fmt.Println("Zion's current configuration structure:")
|
||||||
|
fmt.Println("----------------------------------------")
|
||||||
|
fmt.Println("[Interface]")
|
||||||
|
fmt.Println("Address = 10.8.0.1/24")
|
||||||
|
fmt.Println("ListenPort = 51820")
|
||||||
|
fmt.Println("PrivateKey = <zion_private_key>")
|
||||||
|
fmt.Println("PostUp = <iptables_rules>")
|
||||||
|
fmt.Println("PostDown = <iptables_rules>")
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
// Show existing peers
|
||||||
|
for name, pubKey := range map[string]string{
|
||||||
|
"Cth": "NBktXKy1s0n2lIlIMODvOqKNwAtYdoZH5feKt5P43i0=",
|
||||||
|
"Aza": "qmTKA257DLOrfhk5Zw8RyRmBSonmm6epbloT0P0ZWDc=",
|
||||||
|
"Nyar": "2BA7L1oJP1tK6dIUNHMgcZmOmYmlyPRe2RaBqfUsEWo=",
|
||||||
|
"Galaxy": "QBNt00VSedxPlq3ZvsdYaqIcbudCAyxv9TG65aPVZzM=",
|
||||||
|
"nanocube": "/ZImoATDIS0e0N08CD7mqWbhtGlSnynpPuY04Ed4Zyc=",
|
||||||
|
"jupiter": "YIFQ43ULk/YoCgOv3SBU6+MOrbxd+mlvaw9rT8uoNmw=",
|
||||||
|
"HASS": "C+Poz/7DaXCxe4HZiL6D5cld4jMt5o1gBq3iPiBzrg0=",
|
||||||
|
"framebot": "loS3yZapqmt6lP53Q+s4EvUzw6FmwgZC8jzgLluJ1Es=",
|
||||||
|
} {
|
||||||
|
fmt.Printf("#%s\n", name)
|
||||||
|
fmt.Println("[Peer]")
|
||||||
|
fmt.Printf("PublicKey = %s\n", pubKey)
|
||||||
|
fmt.Printf("AllowedIPs = 10.8.0.x/32\n")
|
||||||
|
fmt.Println()
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("# Add your peer here:")
|
||||||
|
fmt.Printf("# %s\n", hostname)
|
||||||
|
fmt.Println("# [Peer]")
|
||||||
|
fmt.Printf("# PublicKey = %s\n", publicKey)
|
||||||
|
fmt.Printf("# AllowedIPs = %s/32\n", ipAddress)
|
||||||
|
fmt.Println("----------------------------------------")
|
||||||
|
fmt.Println()
|
||||||
|
}
|
||||||
|
|
||||||
|
func displayFullTunnelInstructions() {
|
||||||
|
fmt.Println()
|
||||||
|
printWarning("FULL TUNNEL MODE DETECTED - Endpoint Changes Required:")
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Println("Since this node will route ALL traffic through the VPN, you need to:")
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Println("1. Update Zion's config (/etc/wireguard/wg0.conf) to allow this peer:")
|
||||||
|
fmt.Println(" - Add the peer section as shown above")
|
||||||
|
fmt.Println(" - Ensure Zion has proper iptables rules for NAT/masquerading")
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Println("2. Check Zion's iptables rules (run on Zion server):")
|
||||||
|
fmt.Println(" sudo iptables -t nat -L POSTROUTING")
|
||||||
|
fmt.Println(" sudo iptables -L FORWARD")
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Println("3. If Zion doesn't have proper NAT rules, add them:")
|
||||||
|
fmt.Println(" sudo iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE")
|
||||||
|
fmt.Println(" sudo iptables -A FORWARD -i wg0 -j ACCEPT")
|
||||||
|
fmt.Println(" sudo iptables -A FORWARD -o wg0 -j ACCEPT")
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Println("4. Enable IP forwarding on Zion (if not already enabled):")
|
||||||
|
fmt.Println(" echo 'net.ipv4.ip_forward=1' | sudo tee -a /etc/sysctl.conf")
|
||||||
|
fmt.Println(" sudo sysctl -p")
|
||||||
|
fmt.Println()
|
||||||
|
}
|
||||||
|
|
||||||
|
func displayNextSteps(hostname, interfaceName, publicKey, ipAddress, routingMode string, runningAsRoot bool) {
|
||||||
|
step(4, "Next Steps")
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
if runningAsRoot {
|
||||||
|
printStatus("Ready to start WireGuard:")
|
||||||
|
fmt.Printf(" systemctl enable --now wg-quick@%s\n", interfaceName)
|
||||||
|
} else {
|
||||||
|
printWarning("To enable WireGuard (requires root):")
|
||||||
|
fmt.Printf(" sudo cp %s /etc/wireguard/\n", filepath.Join("wireguard_configs", fmt.Sprintf("%s.conf", interfaceName)))
|
||||||
|
fmt.Printf(" sudo chmod 600 /etc/wireguard/%s.conf\n", interfaceName)
|
||||||
|
fmt.Printf(" sudo systemctl enable --now wg-quick@%s\n", interfaceName)
|
||||||
|
}
|
||||||
|
fmt.Println()
|
||||||
|
printWarning("IMPORTANT: Update other nodes with this peer info:")
|
||||||
|
fmt.Printf(" PublicKey = %s\n", publicKey)
|
||||||
|
fmt.Printf(" AllowedIPs = %s/32\n", ipAddress)
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
if routingMode == "full_tunnel" {
|
||||||
|
displayFullTunnelInstructions()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zion update instructions
|
||||||
|
fmt.Printf("%s========================================%s\n", Red, Reset)
|
||||||
|
fmt.Printf("%s !!! NOW UPDATE ZION SERVER !!! %s\n", Red, Reset)
|
||||||
|
fmt.Printf("%s========================================%s\n", Red, Reset)
|
||||||
|
fmt.Println()
|
||||||
|
printWarning("You MUST add this peer to Zion's config (/etc/wireguard/wg0.conf):")
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Printf("%s#%s%s\n", Yellow, hostname, Reset)
|
||||||
|
fmt.Printf("%s[Peer]%s\n", Yellow, Reset)
|
||||||
|
fmt.Printf("%sPublicKey = %s%s\n", Yellow, publicKey, Reset)
|
||||||
|
fmt.Printf("%sAllowedIPs = %s/32%s\n", Yellow, ipAddress, Reset)
|
||||||
|
fmt.Println()
|
||||||
|
printWarning("After updating Zion, restart its WireGuard:")
|
||||||
|
fmt.Println(" systemctl restart wg-quick@wg0")
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
if runningAsRoot {
|
||||||
|
printWarning("Then restart this node's WireGuard:")
|
||||||
|
fmt.Printf(" systemctl restart wg-quick@%s\n", interfaceName)
|
||||||
|
} else {
|
||||||
|
printWarning("Then restart this node's WireGuard:")
|
||||||
|
fmt.Printf(" sudo systemctl restart wg-quick@%s\n", interfaceName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main function
|
||||||
|
func main() {
|
||||||
|
// Parse command line flags
|
||||||
|
var forceMode bool
|
||||||
|
flag.BoolVar(&forceMode, "force", false, "Skip confirmations and use defaults")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
// Initialize application state
|
||||||
|
state := &AppState{
|
||||||
|
ForceMode: forceMode,
|
||||||
|
RunningAsRoot: isRunningAsRoot(),
|
||||||
|
StepCounter: 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
printHeader("WireGuard Configuration Setup v" + ScriptVersion)
|
||||||
|
fmt.Println("This script will help you create WireGuard keys and configuration files.")
|
||||||
|
fmt.Println("Based on the CURRENT_WORKING configuration with Zion as central server.")
|
||||||
|
fmt.Println("Default peers (Zion & CTH) will be automatically included.")
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
if forceMode {
|
||||||
|
printWarning("Force mode enabled - skipping confirmations and using defaults")
|
||||||
|
fmt.Println()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine WireGuard directory
|
||||||
|
if state.RunningAsRoot {
|
||||||
|
state.WGDirectory = "/etc/wireguard"
|
||||||
|
printStatus("Running as root - using system directories")
|
||||||
|
printStatus(fmt.Sprintf("WireGuard directory: %s", state.WGDirectory))
|
||||||
|
} else {
|
||||||
|
state.WGDirectory = "wireguard_configs"
|
||||||
|
printWarning("Not running as root - using current directory")
|
||||||
|
printStatus(fmt.Sprintf("WireGuard directory: %s", state.WGDirectory))
|
||||||
|
printWarning("You'll need to manually copy config files to /etc/wireguard/ later")
|
||||||
|
}
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
// Check dependencies
|
||||||
|
if err := checkDependencies(); err != nil {
|
||||||
|
printError(err.Error())
|
||||||
|
printStatus("Install with: apt install wireguard-tools")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get directory for non-root users
|
||||||
|
if !state.RunningAsRoot {
|
||||||
|
step(state.StepCounter, "Directory Selection")
|
||||||
|
state.StepCounter++
|
||||||
|
printStatus("Choose where to save WireGuard files:")
|
||||||
|
fmt.Printf(" - Current directory: %s\n", state.WGDirectory)
|
||||||
|
fmt.Printf(" - Home directory: %s\n", os.Getenv("HOME"))
|
||||||
|
fmt.Println(" - Custom directory")
|
||||||
|
fmt.Println()
|
||||||
|
state.WGDirectory = getDirectoryInput("Enter directory path for WireGuard files", state.WGDirectory, forceMode)
|
||||||
|
fmt.Println()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create directory
|
||||||
|
if err := os.MkdirAll(state.WGDirectory, 0755); err != nil {
|
||||||
|
printError(fmt.Sprintf("Failed to create directory: %v", err))
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get node information
|
||||||
|
step(state.StepCounter, "Node Information")
|
||||||
|
state.StepCounter++
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
hostname := getUserInput("Enter hostname for this node: ", validateHostname, forceMode)
|
||||||
|
|
||||||
|
// Get IP address
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Println("Available IP ranges:")
|
||||||
|
fmt.Println(" - 10.8.0.x (recommended for NextGen network)")
|
||||||
|
fmt.Println(" - 10.0.0.x (alternative range)")
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
ipAddress := getUserInput("Enter IP address for this node (e.g., 10.8.0.30): ", validateIP, forceMode)
|
||||||
|
|
||||||
|
// Get interface name
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Println("Interface name options:")
|
||||||
|
fmt.Println(" - wg0 (default, most common)")
|
||||||
|
fmt.Println(" - wg1, wg2, etc. (if wg0 is already in use)")
|
||||||
|
fmt.Println(" - Custom name (e.g., nextgen, vpn, etc.)")
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
interfaceName := getUserInput("Enter interface name (default: wg0): ", validateInterface, forceMode)
|
||||||
|
if interfaceName == "" {
|
||||||
|
interfaceName = "wg0"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if configuration file already exists
|
||||||
|
configFile := filepath.Join(state.WGDirectory, fmt.Sprintf("%s.conf", interfaceName))
|
||||||
|
if !checkFileExists(configFile, forceMode) {
|
||||||
|
printError("Operation cancelled. Please choose a different interface name or remove the existing file.")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configuration options
|
||||||
|
fmt.Println()
|
||||||
|
step(state.StepCounter, "Configuration Options")
|
||||||
|
state.StepCounter++
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Println("Choose an option:")
|
||||||
|
fmt.Println("1. Generate keys only (manual config creation)")
|
||||||
|
fmt.Println("2. Generate keys + complete config (recommended)")
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
var configChoice int
|
||||||
|
if forceMode {
|
||||||
|
configChoice = 2 // Default to complete config in force mode
|
||||||
|
printStatus("Force mode: Using complete config generation")
|
||||||
|
} else {
|
||||||
|
configChoice = getChoice("Enter your choice:", []string{"Generate keys only", "Generate keys + complete config"}, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Traffic routing options
|
||||||
|
var routingMode string
|
||||||
|
if configChoice == 2 {
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Println("Traffic routing options:")
|
||||||
|
fmt.Println("1. WireGuard traffic only (10.8.0.x network only)")
|
||||||
|
fmt.Println("2. All traffic through VPN (full tunnel)")
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Println("Note: Full tunnel routes ALL internet traffic through the VPN.")
|
||||||
|
fmt.Println(" WireGuard-only keeps your regular internet traffic separate.")
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
var routingChoice int
|
||||||
|
if forceMode {
|
||||||
|
routingChoice = 1 // Default to WireGuard-only in force mode
|
||||||
|
printStatus("Force mode: Using WireGuard-only routing")
|
||||||
|
} else {
|
||||||
|
routingChoice = getChoice("Enter your choice:", []string{"WireGuard traffic only", "All traffic through VPN"}, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
if routingChoice == 1 {
|
||||||
|
routingMode = "wg_only"
|
||||||
|
printStatus("Selected: WireGuard traffic only")
|
||||||
|
} else {
|
||||||
|
routingMode = "full_tunnel"
|
||||||
|
printStatus("Selected: All traffic through VPN")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printStatus(fmt.Sprintf("Starting setup for %s (%s)...", hostname, ipAddress))
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
// Generate keys
|
||||||
|
printStatus("Generating WireGuard keys...")
|
||||||
|
privateKey, publicKey, err := generateWireGuardKeys()
|
||||||
|
if err != nil {
|
||||||
|
printError(fmt.Sprintf("Failed to generate keys: %v", err))
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save keys
|
||||||
|
privateKeyFile := filepath.Join(state.WGDirectory, fmt.Sprintf("%s_private.key", hostname))
|
||||||
|
publicKeyFile := filepath.Join(state.WGDirectory, fmt.Sprintf("%s_public.key", hostname))
|
||||||
|
|
||||||
|
if err := os.WriteFile(privateKeyFile, []byte(privateKey), 0600); err != nil {
|
||||||
|
printError(fmt.Sprintf("Failed to save private key: %v", err))
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.WriteFile(publicKeyFile, []byte(publicKey), 0600); err != nil {
|
||||||
|
printError(fmt.Sprintf("Failed to save public key: %v", err))
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
printStatus("Keys generated successfully!")
|
||||||
|
fmt.Printf(" Private key: %s\n", privateKeyFile)
|
||||||
|
fmt.Printf(" Public key: %s\n", publicKeyFile)
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
// Display node information
|
||||||
|
step(state.StepCounter, "Node Information")
|
||||||
|
state.StepCounter++
|
||||||
|
fmt.Println("==========================================")
|
||||||
|
fmt.Printf("HOSTNAME: %s\n", hostname)
|
||||||
|
fmt.Printf("IP ADDRESS: %s\n", ipAddress)
|
||||||
|
fmt.Printf("PRIVATE KEY: %s\n", privateKey)
|
||||||
|
fmt.Printf("PUBLIC KEY: %s\n", publicKey)
|
||||||
|
fmt.Printf("INTERFACE: %s\n", interfaceName)
|
||||||
|
fmt.Printf("ROUTING MODE: %s\n", routingMode)
|
||||||
|
fmt.Println("==========================================")
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
// Save structured info
|
||||||
|
infoFile := filepath.Join(state.WGDirectory, fmt.Sprintf("%s_wg_info.json", hostname))
|
||||||
|
if state.RunningAsRoot {
|
||||||
|
infoFile = filepath.Join("/tmp", fmt.Sprintf("%s_wg_info.json", hostname))
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeConfig := NodeConfig{
|
||||||
|
Hostname: hostname,
|
||||||
|
IPAddress: ipAddress,
|
||||||
|
PrivateKey: privateKey,
|
||||||
|
PublicKey: publicKey,
|
||||||
|
RoutingMode: routingMode,
|
||||||
|
Interface: interfaceName,
|
||||||
|
Generated: time.Now().Format(time.RFC3339),
|
||||||
|
ScriptVer: ScriptVersion,
|
||||||
|
RunningRoot: state.RunningAsRoot,
|
||||||
|
}
|
||||||
|
|
||||||
|
infoData, err := json.MarshalIndent(nodeConfig, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
printError(fmt.Sprintf("Failed to marshal config: %v", err))
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.WriteFile(infoFile, infoData, 0600); err != nil {
|
||||||
|
printError(fmt.Sprintf("Failed to save info file: %v", err))
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
printStatus(fmt.Sprintf("Information saved to: %s", infoFile))
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
// Generate complete config if requested
|
||||||
|
if configChoice == 2 {
|
||||||
|
printStatus(fmt.Sprintf("Generating complete %s.conf...", interfaceName))
|
||||||
|
configContent := generateConfig(hostname, ipAddress, privateKey, routingMode, interfaceName)
|
||||||
|
|
||||||
|
if err := os.WriteFile(configFile, []byte(configContent), 0600); err != nil {
|
||||||
|
printError(fmt.Sprintf("Failed to write config file: %v", err))
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
printStatus(fmt.Sprintf("Config written to: %s", configFile))
|
||||||
|
if state.RunningAsRoot {
|
||||||
|
printStatus("Permissions set to 600")
|
||||||
|
}
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
// Display Zion integration instructions
|
||||||
|
displayZionInstructions(hostname, publicKey, ipAddress)
|
||||||
|
|
||||||
|
// Display next steps
|
||||||
|
displayNextSteps(hostname, interfaceName, publicKey, ipAddress, routingMode, state.RunningAsRoot)
|
||||||
|
|
||||||
|
// Config preview
|
||||||
|
fmt.Printf("%sConfig Preview:%s\n", Blue, Reset)
|
||||||
|
fmt.Println("----------------------------------------")
|
||||||
|
lines := strings.Split(configContent, "\n")
|
||||||
|
for i, line := range lines {
|
||||||
|
if i >= 8 { // Show more lines to include default peers
|
||||||
|
break
|
||||||
|
}
|
||||||
|
fmt.Println(line)
|
||||||
|
}
|
||||||
|
fmt.Printf(" [... and %d total lines]\n", len(lines))
|
||||||
|
fmt.Println("----------------------------------------")
|
||||||
|
fmt.Println()
|
||||||
|
} else {
|
||||||
|
// Manual config generation path
|
||||||
|
step(state.StepCounter, "Next Steps")
|
||||||
|
state.StepCounter++
|
||||||
|
fmt.Println()
|
||||||
|
printStatus("Keys generated successfully!")
|
||||||
|
fmt.Printf(" Private key: %s\n", privateKeyFile)
|
||||||
|
fmt.Printf(" Public key: %s\n", publicKeyFile)
|
||||||
|
fmt.Println()
|
||||||
|
printWarning("Next steps:")
|
||||||
|
fmt.Printf(" - Create %s.conf manually using the keys above\n", interfaceName)
|
||||||
|
fmt.Printf(" - Copy config to %s\n", filepath.Join(state.WGDirectory, fmt.Sprintf("%s.conf", interfaceName)))
|
||||||
|
if state.RunningAsRoot {
|
||||||
|
fmt.Printf(" - Set permissions: chmod 600 %s\n", filepath.Join(state.WGDirectory, fmt.Sprintf("%s.conf", interfaceName)))
|
||||||
|
fmt.Printf(" - Enable/start: systemctl enable --now wg-quick@%s\n", interfaceName)
|
||||||
|
} else {
|
||||||
|
fmt.Printf(" - Copy to system: sudo cp %s /etc/wireguard/\n", filepath.Join(state.WGDirectory, fmt.Sprintf("%s.conf", interfaceName)))
|
||||||
|
fmt.Printf(" - Set permissions: sudo chmod 600 /etc/wireguard/%s.conf\n", interfaceName)
|
||||||
|
fmt.Printf(" - Enable/start: sudo systemctl enable --now wg-quick@%s\n", interfaceName)
|
||||||
|
}
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Printf("%s========================================%s\n", Red, Reset)
|
||||||
|
fmt.Printf("%s !!! NOW UPDATE ZION SERVER !!! %s\n", Red, Reset)
|
||||||
|
fmt.Printf("%s========================================%s\n", Red, Reset)
|
||||||
|
fmt.Println()
|
||||||
|
printWarning("You MUST add this peer to Zion's config (/etc/wireguard/wg0.conf):")
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Printf("%s#%s%s\n", Yellow, hostname, Reset)
|
||||||
|
fmt.Printf("%s[Peer]%s\n", Yellow, Reset)
|
||||||
|
fmt.Printf("%sPublicKey = %s%s\n", Yellow, publicKey, Reset)
|
||||||
|
fmt.Printf("%sAllowedIPs = %s/32%s\n", Yellow, ipAddress, Reset)
|
||||||
|
fmt.Println()
|
||||||
|
printWarning("After updating Zion, restart its WireGuard:")
|
||||||
|
fmt.Println(" systemctl restart wg-quick@wg0")
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
if state.RunningAsRoot {
|
||||||
|
printWarning("Then restart this node's WireGuard:")
|
||||||
|
fmt.Printf(" systemctl restart wg-quick@%s\n", interfaceName)
|
||||||
|
} else {
|
||||||
|
printWarning("Then restart this node's WireGuard:")
|
||||||
|
fmt.Printf(" sudo systemctl restart wg-quick@%s\n", interfaceName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println()
|
||||||
|
printStatus(fmt.Sprintf("Setup complete for %s!", hostname))
|
||||||
|
fmt.Println()
|
||||||
|
}
|
||||||
518
wireguard_setup.sh
Executable file
518
wireguard_setup.sh
Executable file
@@ -0,0 +1,518 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# WireGuard Setup Script
|
||||||
|
# This script guides users through creating WireGuard keys and configuration files
|
||||||
|
|
||||||
|
set -euo pipefail # Exit on error, undefined vars, pipe failures
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
# Configuration file for Zion settings
|
||||||
|
ZION_CONFIG_FILE="$(dirname "$0")/CURRENT_WORKING/zion.conf"
|
||||||
|
|
||||||
|
# Function to print colored output
|
||||||
|
print_status() {
|
||||||
|
echo -e "${GREEN}[INFO]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_warning() {
|
||||||
|
echo -e "${YELLOW}[WARNING]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_error() {
|
||||||
|
echo -e "${RED}[ERROR]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_header() {
|
||||||
|
echo -e "${BLUE}================================${NC}"
|
||||||
|
echo -e "${BLUE}$1${NC}"
|
||||||
|
echo -e "${BLUE}================================${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to check if command exists
|
||||||
|
command_exists() {
|
||||||
|
command -v "$1" >/dev/null 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to validate IP address with subnet
|
||||||
|
validate_ip() {
|
||||||
|
local ip=$1
|
||||||
|
|
||||||
|
# Check if input contains subnet
|
||||||
|
if [[ ! $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/[0-9]{1,2}$ ]]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Extract IP and subnet parts
|
||||||
|
local ip_part="${ip%/*}"
|
||||||
|
local subnet="${ip#*/}"
|
||||||
|
|
||||||
|
# Validate subnet
|
||||||
|
if [[ ! $subnet =~ ^[0-9]+$ ]] || [ "$subnet" -lt 1 ] || [ "$subnet" -gt 32 ]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Validate each octet
|
||||||
|
IFS='.' read -ra OCTETS <<< "$ip_part"
|
||||||
|
if [ ${#OCTETS[@]} -ne 4 ]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
for octet in "${OCTETS[@]}"; do
|
||||||
|
if [[ ! $octet =~ ^[0-9]+$ ]] || [ "$octet" -lt 0 ] || [ "$octet" -gt 255 ]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to validate port number
|
||||||
|
validate_port() {
|
||||||
|
local port=$1
|
||||||
|
|
||||||
|
if [[ ! $port =~ ^[0-9]+$ ]]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$port" -lt 1 ] || [ "$port" -gt 65535 ]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for common reserved ports
|
||||||
|
if [ "$port" -le 1024 ]; then
|
||||||
|
print_warning "Port $port is in privileged range (1-1024). You may need root access."
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to validate WireGuard public key
|
||||||
|
validate_public_key() {
|
||||||
|
local key=$1
|
||||||
|
|
||||||
|
# WireGuard keys are base64 encoded and exactly 44 characters long
|
||||||
|
if [[ ! $key =~ ^[A-Za-z0-9+/]{43}=$ ]]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to detect network interface
|
||||||
|
detect_network_interface() {
|
||||||
|
# Try to detect the main network interface
|
||||||
|
local interface
|
||||||
|
|
||||||
|
# Check for common interface names
|
||||||
|
for name in eth0 ens33 ens160 enp0s3 eno1; do
|
||||||
|
if ip link show "$name" >/dev/null 2>&1; then
|
||||||
|
interface="$name"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Fallback to first non-loopback interface
|
||||||
|
if [ -z "$interface" ]; then
|
||||||
|
interface=$(ip route | grep default | awk '{print $5}' | head -1)
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "$interface"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to load Zion configuration
|
||||||
|
load_zion_config() {
|
||||||
|
if [[ -f "$ZION_CONFIG_FILE" ]]; then
|
||||||
|
print_status "Found Zion configuration file: $ZION_CONFIG_FILE"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
print_warning "Zion configuration file not found: $ZION_CONFIG_FILE"
|
||||||
|
print_warning "Using hardcoded Zion configuration"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to create safe filename
|
||||||
|
safe_filename() {
|
||||||
|
local name="$1"
|
||||||
|
# Replace invalid characters with underscores
|
||||||
|
echo "$name" | sed 's/[^a-zA-Z0-9._-]/_/g'
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main setup function
|
||||||
|
main() {
|
||||||
|
print_header "WireGuard Configuration Setup"
|
||||||
|
echo "This script will help you create WireGuard keys and configuration files."
|
||||||
|
echo "Based on the CURRENT_WORKING configuration with Zion as central server."
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Check if wg command exists
|
||||||
|
if ! command_exists wg; then
|
||||||
|
print_error "WireGuard tools not found. Please install WireGuard first:"
|
||||||
|
echo " Ubuntu/Debian: sudo apt install wireguard"
|
||||||
|
echo " CentOS/RHEL: sudo yum install wireguard-tools"
|
||||||
|
echo " Arch: sudo pacman -S wireguard-tools"
|
||||||
|
echo " Fedora: sudo dnf install wireguard-tools"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create output directory
|
||||||
|
OUTPUT_DIR="wireguard_configs"
|
||||||
|
mkdir -p "$OUTPUT_DIR"
|
||||||
|
print_status "Created output directory: $OUTPUT_DIR"
|
||||||
|
|
||||||
|
# Step 1: Generate keys
|
||||||
|
print_header "Step 1: Generate WireGuard Keys"
|
||||||
|
|
||||||
|
echo "Generating private and public keys..."
|
||||||
|
PRIVATE_KEY=$(wg genkey)
|
||||||
|
PUBLIC_KEY=$(echo "$PRIVATE_KEY" | wg pubkey)
|
||||||
|
|
||||||
|
print_status "Keys generated successfully!"
|
||||||
|
echo "Private Key: $PRIVATE_KEY"
|
||||||
|
echo "Public Key: $PUBLIC_KEY"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Step 2: Get configuration details
|
||||||
|
print_header "Step 2: Configuration Details"
|
||||||
|
|
||||||
|
# Get node name
|
||||||
|
local node_name
|
||||||
|
while true; do
|
||||||
|
read -p "Enter node name (e.g., aza, cth, galaxy): " node_name
|
||||||
|
node_name=$(safe_filename "$node_name")
|
||||||
|
|
||||||
|
if [ -n "$node_name" ]; then
|
||||||
|
break
|
||||||
|
else
|
||||||
|
print_error "Node name cannot be empty"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Check if configuration file already exists
|
||||||
|
CONFIG_FILE="$OUTPUT_DIR/${node_name}.conf"
|
||||||
|
if [ -f "$CONFIG_FILE" ]; then
|
||||||
|
print_warning "Configuration file '$CONFIG_FILE' already exists."
|
||||||
|
read -p "Do you want to overwrite it? (y/n): " OVERWRITE_FILE
|
||||||
|
if [[ ! $OVERWRITE_FILE =~ ^[Yy]$ ]]; then
|
||||||
|
print_error "Operation cancelled. Please choose a different node name or remove the existing file."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
print_status "Will overwrite existing configuration file."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get IP address
|
||||||
|
local ip_address
|
||||||
|
while true; do
|
||||||
|
read -p "Enter IP address with subnet (e.g., 10.8.0.2/24): " ip_address
|
||||||
|
if validate_ip "$ip_address"; then
|
||||||
|
break
|
||||||
|
else
|
||||||
|
print_error "Invalid IP address format. Use format: x.x.x.x/y"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Ask if this is a server (listening) or client
|
||||||
|
read -p "Is this a server that will listen for connections? (y/n): " IS_SERVER
|
||||||
|
local listen_port
|
||||||
|
if [[ $IS_SERVER =~ ^[Yy]$ ]]; then
|
||||||
|
while true; do
|
||||||
|
read -p "Enter listen port (1-65535): " listen_port
|
||||||
|
if validate_port "$listen_port"; then
|
||||||
|
break
|
||||||
|
else
|
||||||
|
print_error "Invalid port number. Must be between 1-65535"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Step 3: Create configuration file
|
||||||
|
print_header "Step 3: Create Configuration File"
|
||||||
|
|
||||||
|
# Create the configuration file
|
||||||
|
cat > "$CONFIG_FILE" << EOF
|
||||||
|
[Interface]
|
||||||
|
PrivateKey = $PRIVATE_KEY
|
||||||
|
Address = $ip_address
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Add listen port if it's a server
|
||||||
|
if [[ $IS_SERVER =~ ^[Yy]$ ]]; then
|
||||||
|
echo "ListenPort = $listen_port" >> "$CONFIG_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Add PostUp/PostDown rules for server (Zion-like configuration)
|
||||||
|
if [[ $IS_SERVER =~ ^[Yy]$ ]]; then
|
||||||
|
local network_interface
|
||||||
|
network_interface=$(detect_network_interface)
|
||||||
|
|
||||||
|
if [ -n "$network_interface" ]; then
|
||||||
|
print_status "Detected network interface: $network_interface"
|
||||||
|
else
|
||||||
|
print_warning "Could not detect network interface, using 'eth0'"
|
||||||
|
network_interface="eth0"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "" >> "$CONFIG_FILE"
|
||||||
|
echo "# Server configuration - enable IP forwarding" >> "$CONFIG_FILE"
|
||||||
|
echo "PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o $network_interface -j MASQUERADE; ip route add 10.8.0.0/24 dev wg0 2>/dev/null || true" >> "$CONFIG_FILE"
|
||||||
|
echo "PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o $network_interface -j MASQUERADE; ip route del 10.8.0.0/24 dev wg0 2>/dev/null || true" >> "$CONFIG_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_status "Configuration file created: $CONFIG_FILE"
|
||||||
|
|
||||||
|
# Step 4: Add peers
|
||||||
|
print_header "Step 4: Add Peers"
|
||||||
|
|
||||||
|
# Zion default peer information (from CURRENT_WORKING/zion.conf)
|
||||||
|
local ZION_PUBLIC_KEY="2ztJbrN1x1NWanzPGLiKL19ZkdOhm5Y7WeKEWBT5cyg="
|
||||||
|
local ZION_ENDPOINT="ugh.im:51820"
|
||||||
|
local ZION_ALLOWED_IPS="10.8.0.0/24"
|
||||||
|
|
||||||
|
# Try to load Zion config, fall back to hardcoded if not available
|
||||||
|
if ! load_zion_config; then
|
||||||
|
print_warning "Using hardcoded Zion configuration"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Ask if user wants to add Zion as default peer (unless this IS Zion)
|
||||||
|
if [[ "$node_name" != "zion" ]]; then
|
||||||
|
echo "Zion is the central server for this network."
|
||||||
|
read -p "Do you want to add Zion as a peer? (y/n, default: y): " ADD_ZION
|
||||||
|
ADD_ZION=${ADD_ZION:-y}
|
||||||
|
|
||||||
|
if [[ $ADD_ZION =~ ^[Yy]$ ]]; then
|
||||||
|
echo ""
|
||||||
|
echo "Adding Zion as peer with default settings:"
|
||||||
|
echo " Public Key: $ZION_PUBLIC_KEY"
|
||||||
|
echo " Endpoint: $ZION_ENDPOINT"
|
||||||
|
echo " Allowed IPs: $ZION_ALLOWED_IPS"
|
||||||
|
echo " Persistent Keepalive: 25"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Add Zion peer to configuration
|
||||||
|
echo "" >> "$CONFIG_FILE"
|
||||||
|
echo "# Zion (central server)" >> "$CONFIG_FILE"
|
||||||
|
echo "[Peer]" >> "$CONFIG_FILE"
|
||||||
|
echo "PublicKey = $ZION_PUBLIC_KEY" >> "$CONFIG_FILE"
|
||||||
|
echo "AllowedIPs = $ZION_ALLOWED_IPS" >> "$CONFIG_FILE"
|
||||||
|
echo "Endpoint = $ZION_ENDPOINT" >> "$CONFIG_FILE"
|
||||||
|
echo "PersistentKeepalive = 25" >> "$CONFIG_FILE"
|
||||||
|
|
||||||
|
print_status "Added Zion as default peer"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Add additional peers
|
||||||
|
while true; do
|
||||||
|
read -p "Do you want to add additional peers? (y/n): " ADD_PEER
|
||||||
|
if [[ ! $ADD_PEER =~ ^[Yy]$ ]]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
local peer_name
|
||||||
|
read -p "Enter peer name (e.g., aza, cth, galaxy): " peer_name
|
||||||
|
peer_name=$(safe_filename "$peer_name")
|
||||||
|
|
||||||
|
local peer_public_key
|
||||||
|
while true; do
|
||||||
|
read -p "Enter peer public key: " peer_public_key
|
||||||
|
if validate_public_key "$peer_public_key"; then
|
||||||
|
break
|
||||||
|
else
|
||||||
|
print_error "Invalid WireGuard public key format"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
local peer_allowed_ips
|
||||||
|
while true; do
|
||||||
|
read -p "Enter allowed IPs for this peer (e.g., 10.8.0.1/32 or 10.8.0.0/24): " peer_allowed_ips
|
||||||
|
if validate_ip "$peer_allowed_ips"; then
|
||||||
|
break
|
||||||
|
else
|
||||||
|
print_error "Invalid IP address format. Use format: x.x.x.x/y"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Ask if this peer has an endpoint (for clients connecting to servers)
|
||||||
|
read -p "Does this peer have an endpoint? (y/n): " HAS_ENDPOINT
|
||||||
|
if [[ $HAS_ENDPOINT =~ ^[Yy]$ ]]; then
|
||||||
|
read -p "Enter endpoint (host:port): " PEER_ENDPOINT
|
||||||
|
local peer_keepalive
|
||||||
|
read -p "Enter persistent keepalive (seconds, default 25): " peer_keepalive
|
||||||
|
peer_keepalive=${peer_keepalive:-25}
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Add peer to configuration
|
||||||
|
echo "" >> "$CONFIG_FILE"
|
||||||
|
echo "# $peer_name" >> "$CONFIG_FILE"
|
||||||
|
echo "[Peer]" >> "$CONFIG_FILE"
|
||||||
|
echo "PublicKey = $peer_public_key" >> "$CONFIG_FILE"
|
||||||
|
echo "AllowedIPs = $peer_allowed_ips" >> "$CONFIG_FILE"
|
||||||
|
|
||||||
|
if [[ $HAS_ENDPOINT =~ ^[Yy]$ ]]; then
|
||||||
|
echo "Endpoint = $PEER_ENDPOINT" >> "$CONFIG_FILE"
|
||||||
|
echo "PersistentKeepalive = $peer_keepalive" >> "$CONFIG_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_status "Added peer: $peer_name"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Set proper file permissions
|
||||||
|
chmod 600 "$CONFIG_FILE"
|
||||||
|
print_status "Set file permissions to 600 (owner read/write only)"
|
||||||
|
|
||||||
|
# Step 5: Display results
|
||||||
|
print_header "Step 5: Setup Complete"
|
||||||
|
|
||||||
|
print_status "Configuration file created: $CONFIG_FILE"
|
||||||
|
print_status "Your public key: $PUBLIC_KEY"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Zion update instructions
|
||||||
|
print_header "IMPORTANT: Update Zion Server Configuration"
|
||||||
|
echo ""
|
||||||
|
print_warning "You MUST add this peer to Zion's configuration file:"
|
||||||
|
echo " /etc/wireguard/wg0.conf"
|
||||||
|
echo ""
|
||||||
|
echo "Add the following peer section to Zion's config:"
|
||||||
|
echo "----------------------------------------"
|
||||||
|
echo "# $node_name"
|
||||||
|
echo "[Peer]"
|
||||||
|
echo "PublicKey = $PUBLIC_KEY"
|
||||||
|
echo "AllowedIPs = ${ip_address%/*}/32"
|
||||||
|
echo "----------------------------------------"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Show Zion's current configuration structure
|
||||||
|
if ! load_zion_config; then
|
||||||
|
echo "Zion's current configuration structure:"
|
||||||
|
echo "----------------------------------------"
|
||||||
|
echo "[Interface]"
|
||||||
|
echo "Address = 10.8.0.1/24"
|
||||||
|
echo "ListenPort = 51820"
|
||||||
|
echo "PrivateKey = <zion_private_key>"
|
||||||
|
echo "PostUp = <iptables_rules>"
|
||||||
|
echo "PostDown = <iptables_rules>"
|
||||||
|
echo ""
|
||||||
|
echo "#Cth"
|
||||||
|
echo "[Peer]"
|
||||||
|
echo "PublicKey = NBktXKy1s0n2lIlIMODvOqKNwAtYdoZH5feKt5P43i0="
|
||||||
|
echo "AllowedIPs = 10.8.0.10/32"
|
||||||
|
echo ""
|
||||||
|
echo "#Aza"
|
||||||
|
echo "[Peer]"
|
||||||
|
echo "PublicKey = qmTKA257DLOrfhk5Zw8RyRmBSonmm6epbloT0P0ZWDc="
|
||||||
|
echo "AllowedIPs = 10.8.0.2/32"
|
||||||
|
echo ""
|
||||||
|
echo "# Add your peer section here:"
|
||||||
|
echo "# $node_name"
|
||||||
|
echo "# [Peer]"
|
||||||
|
echo "# PublicKey = $PUBLIC_KEY"
|
||||||
|
echo "# AllowedIPs = ${ip_address%/*}/32"
|
||||||
|
echo "----------------------------------------"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
print_warning "After updating Zion's config:"
|
||||||
|
echo "1. Save the file"
|
||||||
|
echo "2. Restart Zion's WireGuard: sudo systemctl restart wg-quick@wg0"
|
||||||
|
echo "3. Then start this node's WireGuard: sudo wg-quick up ${node_name}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Show the configuration file
|
||||||
|
echo "Your configuration file contents:"
|
||||||
|
echo "----------------------------------------"
|
||||||
|
cat "$CONFIG_FILE"
|
||||||
|
echo "----------------------------------------"
|
||||||
|
|
||||||
|
# Create a summary file
|
||||||
|
SUMMARY_FILE="$OUTPUT_DIR/${node_name}_summary.txt"
|
||||||
|
if [ -f "$SUMMARY_FILE" ]; then
|
||||||
|
print_warning "Summary file '$SUMMARY_FILE' already exists and will be overwritten."
|
||||||
|
fi
|
||||||
|
cat > "$SUMMARY_FILE" << EOF
|
||||||
|
WireGuard Configuration Summary for $node_name
|
||||||
|
===============================================
|
||||||
|
|
||||||
|
Node Name: $node_name
|
||||||
|
IP Address: $ip_address
|
||||||
|
$(if [[ $IS_SERVER =~ ^[Yy]$ ]]; then echo "Listen Port: $listen_port"; fi)
|
||||||
|
|
||||||
|
Your Public Key: $PUBLIC_KEY
|
||||||
|
Your Private Key: $PRIVATE_KEY
|
||||||
|
|
||||||
|
Configuration File: $CONFIG_FILE
|
||||||
|
|
||||||
|
Commands to use:
|
||||||
|
- Start: sudo wg-quick up ${node_name}
|
||||||
|
- Stop: sudo wg-quick down ${node_name}
|
||||||
|
- Status: sudo wg show
|
||||||
|
|
||||||
|
ZION SERVER UPDATE REQUIRED:
|
||||||
|
===========================
|
||||||
|
You MUST add this peer to Zion's configuration file (/etc/wireguard/wg0.conf):
|
||||||
|
|
||||||
|
# $node_name
|
||||||
|
[Peer]
|
||||||
|
PublicKey = $PUBLIC_KEY
|
||||||
|
AllowedIPs = ${ip_address%/*}/32
|
||||||
|
|
||||||
|
After updating Zion's config:
|
||||||
|
1. Save the file
|
||||||
|
2. Restart Zion's WireGuard: sudo systemctl restart wg-quick@wg0
|
||||||
|
3. Then start this node's WireGuard: sudo wg-quick up ${node_name}
|
||||||
|
|
||||||
|
Remember to:
|
||||||
|
1. Keep your private key secure
|
||||||
|
2. Update Zion's configuration with your public key
|
||||||
|
3. Set proper file permissions: chmod 600 $CONFIG_FILE
|
||||||
|
4. Restart both Zion and this node after configuration changes
|
||||||
|
EOF
|
||||||
|
|
||||||
|
print_status "Summary saved to: $SUMMARY_FILE"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to show usage
|
||||||
|
show_usage() {
|
||||||
|
echo "Usage: $0 [OPTIONS]"
|
||||||
|
echo ""
|
||||||
|
echo "Options:"
|
||||||
|
echo " -h, --help Show this help message"
|
||||||
|
echo " -d, --dir DIR Set output directory (default: wireguard_configs)"
|
||||||
|
echo " -c, --config Use custom Zion config file"
|
||||||
|
echo ""
|
||||||
|
echo "This script will interactively guide you through creating WireGuard"
|
||||||
|
echo "keys and configuration files."
|
||||||
|
}
|
||||||
|
|
||||||
|
# Parse command line arguments
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case $1 in
|
||||||
|
-h|--help)
|
||||||
|
show_usage
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
-d|--dir)
|
||||||
|
OUTPUT_DIR="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-c|--config)
|
||||||
|
ZION_CONFIG_FILE="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
print_error "Unknown option: $1"
|
||||||
|
show_usage
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# Run main function
|
||||||
|
main "$@"
|
||||||
Reference in New Issue
Block a user