### **Updated Approach:**
- Use `github.com/songgao/water` to create a **TUN** interface.
- Use **UDP** to transfer encrypted packets.
- Use **ChaCha20-Poly1305** for encryption.
---
## **1. Install Dependencies**
```sh
go get github.com/songgao/water golang.org/x/crypto/chacha20poly1305
```
---
## **2. `tun.go` (TUN Interface Handler)**
This sets up a **TUN interface**.
```go
package main
import (
"fmt"
"log"
"github.com/songgao/water"
)
func createTUN(name string) *water.Interface {
config := water.Config{
DeviceType: water.TUN,
}
ifce, err := water.New(config)
if err != nil {
log.Fatalf("Failed to create TUN interface: %v", err)
}
fmt.Println("TUN interface created:", ifce.Name())
return ifce
}
```
---
## **3. `server.go` (VPN Server)**
- Creates a **TUN** interface (`vpn0`).
- Listens for UDP packets on `:51820`.
- **Decrypts** packets and writes them to the **TUN** interface.
```go
package main
import (
"crypto/rand"
"fmt"
"log"
"net"
"github.com/songgao/water"
"golang.org/x/crypto/chacha20poly1305"
)
var key = make([]byte, chacha20poly1305.KeySize)
func main() {
rand.Read(key) // Generate encryption key
tunDevice := createTUN("vpn0")
defer tunDevice.Close()
conn, err := net.ListenPacket("udp", ":51820")
if err != nil {
log.Fatalf("Failed to start UDP server: %v", err)
}
defer conn.Close()
aead, _ := chacha20poly1305.New(key)
buf := make([]byte, 1500)
fmt.Println("VPN Server listening on UDP 51820")
for {
n, addr, err := conn.ReadFrom(buf)
if err != nil {
log.Println("Read error:", err)
continue
}
nonceSize := aead.NonceSize()
if n < nonceSize {
continue
}
nonce, ciphertext := buf[:nonceSize], buf[nonceSize:n]
plaintext, err := aead.Open(nil, nonce, ciphertext, nil)
if err != nil {
log.Println("Decryption failed:", err)
continue
}
tunDevice.Write(plaintext) // Send decrypted data to TUN
fmt.Printf("Received %d bytes from %s\n", len(plaintext), addr)
}
}
```
---
## **4. `client.go` (VPN Client)**
- Creates a **TUN** interface (`vpn-client`).
- Captures packets from **TUN**.
- **Encrypts** them and sends them to the VPN server via **UDP**.
```go
package main
import (
"crypto/rand"
"fmt"
"log"
"net"
"github.com/songgao/water"
"golang.org/x/crypto/chacha20poly1305"
)
var key = make([]byte, chacha20poly1305.KeySize)
func main() {
rand.Read(key)
tunDevice := createTUN("vpn-client")
defer tunDevice.Close()
conn, err := net.Dial("udp", "SERVER_IP:51820") // Replace SERVER_IP
if err != nil {
log.Fatalf("Failed to connect: %v", err)
}
defer conn.Close()
aead, _ := chacha20poly1305.New(key)
packet := make([]byte, 1500)
for {
n, err := tunDevice.Read(packet)
if err != nil {
log.Println("TUN Read error:", err)
continue
}
nonce := make([]byte, aead.NonceSize())
rand.Read(nonce)
ciphertext := aead.Seal(nil, nonce, packet[:n], nil)
conn.Write(append(nonce, ciphertext...))
fmt.Printf("Sent %d encrypted bytes\n", len(ciphertext))
}
}
```
---
## **5. Running the VPN**
### **Step 1: Server Setup**
Run the server:
```sh
go run server.go
```
This creates `vpn0` and listens for **encrypted** packets.
### **Step 2: Client Setup**
On the client machine, replace `SERVER_IP` in `client.go` and run:
```sh
go run client.go
```
### **Step 3: Configure Routing**
**On the Server**: Enable forwarding:
```sh
sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
```
**On the Client**: Route traffic through the VPN:
```sh
ip route add 10.8.0.0/24 via vpn-client
```
---
## **6. Testing**
Try pinging from the **client**:
```sh
ping -I vpn-client 10.8.0.1
```
You should see **encrypted traffic** flowing.
---
## **Next Steps**
- **User authentication** (public keys).
- **Multi-client support** (track multiple clients).
- **NAT traversal** (STUN/TURN).
- **IPv6 support**.
Would you like help with **multi-client support** or **NAT traversal**? 🚀