chore: initial commit of wgtool
This commit is contained in:
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.
|
||||
Reference in New Issue
Block a user