360 lines
9.7 KiB
Markdown
360 lines
9.7 KiB
Markdown
# 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. |