Compare commits

...

3 Commits

Author SHA1 Message Date
Your Name c353e76058 add 2025-07-27 22:55:43 +08:00
Your Name bc84b69ebc add 2025-07-27 22:55:38 +08:00
Your Name 557f266b3c test 2025-07-27 22:45:13 +08:00
8 changed files with 717 additions and 21 deletions
+15
View File
@@ -0,0 +1,15 @@
#!/usr/bin/env bash
# Automatically load the Nix flake development environment
use flake
# Add project-specific environment variables
export PROJECT_ROOT="$(pwd)"
export GOPATH="$PROJECT_ROOT/.go"
export GOBIN="$GOPATH/bin"
export GOCACHE="$PROJECT_ROOT/.gocache"
# Add Go bin to PATH
PATH_add "$GOBIN"
# Load any additional .env file if present
dotenv_if_exists
+49 -1
View File
@@ -1 +1,49 @@
wireguard-go # Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
# Test binary, built with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# Dependency directories (remove the comment below to include it)
# vendor/
# Go workspace file
go.work
# Development environment artifacts
.go/
.gocache/
.direnv/
result
result-*
# Editor directories and files
.vscode/
.idea/
*.swp
*.swo
*~
# OS generated files
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
# Air live reload
.air.toml
tmp/
# Local environment variables
.env
.env.local
+174
View File
@@ -0,0 +1,174 @@
run:
timeout: 5m
issues-exit-code: 1
tests: true
build-tags:
- integration
output:
format: colored-line-number
print-issued-lines: true
print-linter-name: true
linters-settings:
errcheck:
check-type-assertions: true
check-blank: true
gocyclo:
min-complexity: 15
gofmt:
simplify: true
goimports:
local-prefixes: golang.zx2c4.com/wireguard
golint:
min-confidence: 0.8
govet:
check-shadowing: true
enable-all: true
ineffassign:
check-exported: false
misspell:
locale: US
nakedret:
max-func-lines: 30
prealloc:
simple: true
range-loops: true
for-loops: false
unparam:
check-exported: false
unused:
check-exported: false
whitespace:
multi-if: false
multi-func: false
wsl:
strict-append: true
allow-assign-and-call: true
allow-multiline-assign: true
allow-cuddle-declarations: false
allow-trailing-comment: false
force-case-trailing-whitespace: 0
linters:
enable:
# Default linters
- errcheck
- gosimple
- govet
- ineffassign
- staticcheck
- typecheck
- unused
# Additional recommended linters
- asciicheck
- bodyclose
- cyclop
- dupl
- durationcheck
- errorlint
- exhaustive
- exportloopref
- forbidigo
- forcetypeassert
- gochecknoinits
- gocognit
- goconst
- gocritic
- gocyclo
- godot
- gofmt
- gofumpt
- goheader
- goimports
- gomnd
- gomoddirectives
- gomodguard
- goprintffuncname
- gosec
- grouper
- importas
- maintidx
- makezero
- misspell
- nakedret
- nestif
- nilerr
- nilnil
- noctx
- nolintlint
- prealloc
- predeclared
- promlinter
- revive
- rowserrcheck
- sqlclosecheck
- stylecheck
- tenv
- testpackage
- tparallel
- unconvert
- unparam
- wastedassign
- whitespace
disable:
- gochecknoglobals # Too restrictive for this codebase
- goerr113 # Error wrapping style is project-specific
- godox # TODO comments are fine
- lll # Line length is handled by formatter
- paralleltest # Not all tests need to be parallel
- wrapcheck # Error wrapping style is project-specific
- varnamelen # Variable naming style is project-specific
issues:
exclude-rules:
# Exclude some linters from running on tests files
- path: _test\.go
linters:
- gocyclo
- errcheck
- dupl
- gosec
- funlen
- goconst
- gocognit
- scopelint
- lll
# Exclude known false positives
- text: "weak cryptographic primitive"
linters:
- gosec
# Ignore certain GoDoc issues
- text: "should have a package comment"
linters:
- golint
- stylecheck
# Maximum issues count per one linter. Set to 0 to disable
max-issues-per-linter: 0
# Maximum count of issues with the same text. Set to 0 to disable
max-same-issues: 0
# Show only new issues created after git revision `REV`
new: false
# Fix issues automatically when possible
fix: false
+23 -17
View File
@@ -7,16 +7,13 @@ package conn
import ( import (
"fmt" "fmt"
"net"
"sync" "sync"
) )
// MultiPathBind implements Bind interface but sends packets through multiple network paths // MultiPathBind implements Bind interface and sends/receives packets through multiple network paths
type MultiPathBind struct { type MultiPathBind struct {
mu sync.RWMutex mu sync.RWMutex
binds []Bind binds []Bind
// Store the primary bind for receive operations (only one bind receives)
primaryBind Bind
} }
// NewMultiPathBind creates a new multi-path bind with multiple underlying binds // NewMultiPathBind creates a new multi-path bind with multiple underlying binds
@@ -27,40 +24,49 @@ func NewMultiPathBind(binds []Bind) *MultiPathBind {
return &MultiPathBind{ return &MultiPathBind{
binds: binds, binds: binds,
primaryBind: binds[0], // Use first bind as primary for receiving
} }
} }
// Open puts all binds into listening state // Open puts all binds into listening state and collects receive functions from all binds
func (mpb *MultiPathBind) Open(port uint16) (fns []ReceiveFunc, actualPort uint16, err error) { func (mpb *MultiPathBind) Open(port uint16) (fns []ReceiveFunc, actualPort uint16, err error) {
mpb.mu.Lock() mpb.mu.Lock()
defer mpb.mu.Unlock() defer mpb.mu.Unlock()
// Open primary bind first to get the actual port and receive functions // Open first bind to get the actual port
fns, actualPort, err = mpb.primaryBind.Open(port) var firstBindFns []ReceiveFunc
firstBindFns, actualPort, err = mpb.binds[0].Open(port)
if err != nil { if err != nil {
return nil, 0, fmt.Errorf("failed to open primary bind: %w", err) return nil, 0, fmt.Errorf("failed to open bind 0: %w", err)
} }
// Open additional binds on the same port // Collect receive functions from the first bind
fns = append(fns, firstBindFns...)
// Open additional binds on the same port and collect their receive functions
for i, bind := range mpb.binds[1:] { for i, bind := range mpb.binds[1:] {
_, bindPort, bindErr := bind.Open(actualPort) var bindFns []ReceiveFunc
if bindErr != nil { var bindPort uint16
bindFns, bindPort, err = bind.Open(actualPort)
if err != nil {
// If any bind fails, close already opened binds // If any bind fails, close already opened binds
mpb.primaryBind.Close() mpb.binds[0].Close()
for j := 0; j < i; j++ { for j := 0; j < i; j++ {
mpb.binds[j+1].Close() mpb.binds[j+1].Close()
} }
return nil, 0, fmt.Errorf("failed to open bind %d: %w", i+1, bindErr) return nil, 0, fmt.Errorf("failed to open bind %d: %w", i+1, err)
} }
// Verify all binds use the same port // Verify all binds use the same port
if bindPort != actualPort { if bindPort != actualPort {
mpb.primaryBind.Close() mpb.binds[0].Close()
for j := 0; j <= i; j++ { for j := 0; j <= i; j++ {
mpb.binds[j+1].Close() mpb.binds[j+1].Close()
} }
return nil, 0, fmt.Errorf("bind %d opened on different port %d vs %d", i+1, bindPort, actualPort) return nil, 0, fmt.Errorf("bind %d opened on different port %d vs %d", i+1, bindPort, actualPort)
} }
// Collect receive functions from this bind
fns = append(fns, bindFns...)
} }
return fns, actualPort, nil return fns, actualPort, nil
@@ -120,11 +126,11 @@ func (mpb *MultiPathBind) Send(bufs [][]byte, ep Endpoint) error {
return firstErr return firstErr
} }
// ParseEndpoint uses the primary bind to parse endpoints // ParseEndpoint uses the first bind to parse endpoints
func (mpb *MultiPathBind) ParseEndpoint(s string) (Endpoint, error) { func (mpb *MultiPathBind) ParseEndpoint(s string) (Endpoint, error) {
mpb.mu.RLock() mpb.mu.RLock()
defer mpb.mu.RUnlock() defer mpb.mu.RUnlock()
return mpb.primaryBind.ParseEndpoint(s) return mpb.binds[0].ParseEndpoint(s)
} }
// BatchSize returns the minimum batch size among all binds // BatchSize returns the minimum batch size among all binds
+247
View File
@@ -0,0 +1,247 @@
# WireGuard Go Development Environment
This repository includes a comprehensive Nix flake development environment with all the tools needed for efficient Go development.
## 🚀 Quick Start
### Prerequisites
- [Nix](https://nixos.org/download.html) with flakes enabled
- [direnv](https://direnv.net/) (optional but recommended)
### Setup
1. **Clone and enter the repository:**
```bash
git clone <repo-url>
cd wireguard-go
```
2. **Option A: Using direnv (Recommended)**
```bash
direnv allow
```
This will automatically load the development environment when you enter the directory.
3. **Option B: Manual activation**
```bash
nix develop
```
## 🔧 Included Tools
### Core Go Tools
- **Go 1.23.1** - Matching the project's go.mod
- **gopls** - Official Go Language Server for LSP support
### Code Quality
- **golangci-lint** - Comprehensive linter with 30+ linters enabled
- **staticcheck** - Advanced static analysis
- **gosec** - Security vulnerability scanner
- **govulncheck** - Official Go vulnerability scanner
- **gofumpt** - Stricter version of gofmt
### Development Tools
- **delve** - Go debugger
- **air** - Live reload for development
- **gotests** - Automatic test generation
- **gomodifytags** - Struct tag manipulation
- **impl** - Interface implementation generator
- **gotestsum** - Enhanced test output
### System Tools
- **wireguard-tools** - WireGuard utilities
- **iproute2** - Network configuration tools
- **iptables** - Firewall utilities
## 🎯 Quick Commands
### Development Workflow
```bash
# Install/update dependencies
go mod tidy
# Run comprehensive linting
golangci-lint run
# Check for security vulnerabilities
govulncheck ./...
# Run tests with coverage
go test -race -coverprofile=coverage.out ./...
# Generate tests for a package
gotests -all -w ./device
# Start live reload development server
air
# Format code with stricter rules
gofumpt -w .
```
### Building and Testing
```bash
# Build the project
go build .
# Run all tests
go test ./...
# Run tests with race detection
go test -race ./...
# Benchmark tests
go test -bench=. ./...
# Generate coverage report
go test -coverprofile=coverage.out ./... && go tool cover -html=coverage.out
```
### Debugging
```bash
# Start delve debugger
dlv debug
# Debug a specific test
dlv test ./device
```
## 📝 Editor Integration
### VS Code
A `.vscode/settings.json` is included with optimized settings for Go development:
- Automatic formatting with gofumpt
- Integrated linting with golangci-lint
- Proper LSP configuration
- Optimized file watching and exclusions
### Other Editors
For vim/neovim, emacs, or other editors that support LSP:
- Use `gopls` as the language server
- Point formatters to use `gofumpt` instead of `gofmt`
- Configure linting to use `golangci-lint`
## 🔍 Code Quality Configuration
### Linting
The included `.golangci.yml` enables 30+ linters with sensible defaults:
- Security checks (gosec, G-prefixed rules)
- Performance optimizations (prealloc, ineffassign)
- Style consistency (gofumpt, goimports)
- Bug prevention (errcheck, staticcheck)
### Pre-commit Hooks (Optional)
Consider setting up pre-commit hooks:
```bash
# Create .git/hooks/pre-commit
#!/bin/bash
set -e
golangci-lint run
go test ./...
govulncheck ./...
```
## 🌍 Environment Variables
The flake automatically sets up:
- `GOPATH="$PWD/.go"`
- `GOBIN="$PWD/.go/bin"`
- `GOCACHE="$PWD/.gocache"`
- `GO111MODULE=on`
- `CGO_ENABLED=1`
- `WG_COLOR_MODE=always`
## 🧪 Testing
### Running Tests
```bash
# All tests
go test ./...
# With race detection
go test -race ./...
# Verbose output
go test -v ./...
# Specific package
go test ./device
# With coverage
go test -coverprofile=coverage.out ./...
```
### Test Generation
```bash
# Generate tests for all functions in a package
gotests -all -w ./device
# Generate tests for specific functions
gotests -only FunctionName -w ./device
```
## 🔒 Security
### Vulnerability Scanning
```bash
# Scan for known vulnerabilities
govulncheck ./...
# Security-focused linting
gosec ./...
```
### WireGuard-Specific Security
The environment includes networking tools for testing:
- WireGuard tools for protocol testing
- Network namespace utilities
- Traffic analysis tools
## 📦 Building Packages
### Development Build
```bash
go build .
```
### Optimized Build
```bash
go build -ldflags="-w -s" .
```
### Using Nix to Build
```bash
# Build using the included Nix package
nix build
# The binary will be in ./result/bin/
```
## 🐛 Troubleshooting
### Common Issues
1. **"command not found" errors**
- Ensure you're in the flake environment: `nix develop`
- Or allow direnv: `direnv allow`
2. **Go module issues**
- Clean module cache: `go clean -modcache`
- Verify modules: `go mod verify`
3. **LSP not working**
- Restart your editor
- Check gopls is available: `which gopls`
- Verify Go version: `go version`
### Performance Tips
- Use `.gocache` for faster builds (already configured)
- Exclude build artifacts from file watchers
- Use `gotestsum` for faster test feedback
## 📚 Additional Resources
- [Go Documentation](https://golang.org/doc/)
- [WireGuard Protocol](https://www.wireguard.com/protocol/)
- [golangci-lint Documentation](https://golangci-lint.run/)
- [Delve Debugger](https://github.com/go-delve/delve)
-2
View File
@@ -8,7 +8,6 @@ package device
import ( import (
"fmt" "fmt"
"net" "net"
"runtime"
"golang.zx2c4.com/wireguard/conn" "golang.zx2c4.com/wireguard/conn"
"golang.zx2c4.com/wireguard/tun" "golang.zx2c4.com/wireguard/tun"
@@ -152,7 +151,6 @@ func ExampleMultiPathUsage(logger *Logger) {
// Example: Create multi-path device using specific interface names // Example: Create multi-path device using specific interface names
// This would send each packet through both eth0 and wlan0 // This would send each packet through both eth0 and wlan0
interfaceNames := []string{"eth0", "wlan0"}
// Note: You would need to create/configure your TUN device // Note: You would need to create/configure your TUN device
// tunDevice, err := tun.CreateTUN("wg0", 1420) // tunDevice, err := tun.CreateTUN("wg0", 1420)
Generated
+61
View File
@@ -0,0 +1,61 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1753432016,
"narHash": "sha256-cnL5WWn/xkZoyH/03NNUS7QgW5vI7D1i74g48qplCvg=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "6027c30c8e9810896b92429f0092f624f7b1aace",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}
+147
View File
@@ -0,0 +1,147 @@
{
description = "WireGuard Go development environment";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, flake-utils }:
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = nixpkgs.legacyPackages.${system};
# Go version matching go.mod
go = pkgs.go_1_23;
# Additional Go tools for development
goTools = with pkgs; [
# Core Go toolchain
go
# Language Server Protocol
gopls
# Formatting and imports
# gofmt
# goimports
gofumpt # Stricter gofmt
# Linting and static analysis
golangci-lint
gosec # Security checker
ineffassign
# Debugging
delve
# Code generation and refactoring
gotests # Generate tests
gomodifytags # Modify struct tags
impl # Generate interface implementations
govulncheck # Vulnerability scanner
# Build and development tools
air # Live reload
gotools # Various tools (guru, gorename, etc.)
# Testing and benchmarking
gotestsum # Pretty test output
# Documentation
# godoc
];
# System tools
systemTools = with pkgs; [
git
gnumake
direnv
nix-direnv
# Networking tools (useful for WireGuard development)
iproute2
iptables
wireguard-tools
# Text processing
jq
yq-go
# Shell and utilities
fish
ripgrep
fd
tree
];
in
{
devShells.default = pkgs.mkShell {
buildInputs = goTools ++ systemTools;
shellHook = ''
echo "🚀 WireGuard Go development environment loaded!"
echo "📦 Go version: $(go version)"
echo "🔧 Available tools:"
echo " LSP: gopls"
echo " Linting: golangci-lint, staticcheck, gosec"
echo " Formatting: gofmt, goimports, gofumpt"
echo " Debugging: delve (dlv)"
echo " Testing: gotests, gotestsum"
echo " Security: govulncheck"
echo " Live reload: air"
echo ""
echo "💡 Quick commands:"
echo " go mod tidy # Clean dependencies"
echo " golangci-lint run # Run all linters"
echo " govulncheck ./... # Check for vulnerabilities"
echo " gotests -all # Generate tests"
echo " air # Live reload server"
echo ""
# Set up Go environment
export GOPATH="$PWD/.go"
export GOBIN="$GOPATH/bin"
export PATH="$GOBIN:$PATH"
# Create necessary directories
mkdir -p "$GOPATH/bin"
# Set Go build cache to project directory
export GOCACHE="$PWD/.gocache"
mkdir -p "$GOCACHE"
# Ensure proper Go module mode
export GO111MODULE=on
# Development-friendly settings
export GOTOOLCHAIN="go1.23.1"
export CGO_ENABLED=1
# WireGuard specific
export WG_COLOR_MODE=always
'';
# Environment variables for tools
CGO_ENABLED = "1";
GO111MODULE = "on";
GOFLAGS = "-buildvcs=false"; # Disable VCS stamping for reproducible builds
};
# Optional: Create a package for the WireGuard binary
packages.default = pkgs.buildGoModule {
pname = "wireguard-go";
version = "0.0.0-dev";
src = ./.;
vendorHash = null; # Let Nix handle dependencies
meta = with pkgs.lib; {
description = "Userspace Go implementation of WireGuard";
homepage = "https://www.wireguard.com/";
license = licenses.mit;
platforms = platforms.linux ++ platforms.darwin;
};
};
});
}