| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140 |
- package aerotun
- import (
- "bytes"
- "encoding/base64"
- "fmt"
- "golang.org/x/crypto/curve25519"
- "net"
- "net/netip"
- "regexp"
- "strconv"
- "strings"
- )
- var interfaceName = regexp.MustCompile(`^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,11}$`)
- func validateConfig(c *TunnelInstance) error {
- if c.Protocol == 0 {
- c.Protocol = 2
- }
- if c.Protocol != 2 && c.Protocol != 3 {
- return fmt.Errorf("unsupported AeroTUN version")
- }
- if c.Protocol == 3 {
- if _, err := decodeKey(c.PSK); err != nil {
- return err
- }
- priv, err := decodeKey(c.PrivateKey)
- if err != nil {
- return fmt.Errorf("invalid local identity key")
- }
- pub, err := curve25519.X25519(priv, curve25519.Basepoint)
- if err != nil {
- return err
- }
- c.PublicKey = base64.StdEncoding.EncodeToString(pub)
- if c.PeerPublicKey != "" || !c.Disabled {
- peer, err := decodeKey(c.PeerPublicKey)
- if err != nil || bytes.Equal(peer, pub) {
- return fmt.Errorf("a different pinned peer public key is required")
- }
- }
- if len(c.AllowedIPs) == 0 {
- return fmt.Errorf("v3 requires explicit allowed source IP prefixes")
- }
- for _, prefix := range c.AllowedIPs {
- if _, err := netip.ParsePrefix(prefix); err != nil {
- return fmt.Errorf("invalid allowed source IP prefix")
- }
- }
- }
- c.Mode = strings.ToLower(strings.TrimSpace(c.Mode))
- if c.Mode != "server" && c.Mode != "client" {
- return fmt.Errorf("mode must be server or client")
- }
- // Reserve three characters for the fallback endpoint suffix.
- if !interfaceName.MatchString(c.Name) {
- return fmt.Errorf("interface name must contain 1–12 letters, digits, dots, underscores or dashes")
- }
- if c.MTU == 0 {
- c.MTU = DefaultMTU
- }
- if c.MTU < 576 || c.MTU > 9000 {
- return fmt.Errorf("MTU must be between 576 and 9000")
- }
- if c.ListenPort == 0 && c.Mode == "server" {
- c.ListenPort = DefaultPort
- }
- if c.ListenPort < 0 || c.ListenPort > 65535 {
- return fmt.Errorf("invalid UDP listen port")
- }
- if len(c.PSK) < 32 {
- return fmt.Errorf("PSK must contain at least 32 characters; use Generate Key")
- }
- ip, _, err := net.ParseCIDR(c.LocalAddress)
- if err != nil || ip.IsUnspecified() || ip.IsMulticast() {
- return fmt.Errorf("local address must be a unicast IP in CIDR notation")
- }
- peer, err := peerIP(c.PeerAddress)
- if err != nil {
- return err
- }
- if peer != nil && ((ip.To4() == nil) != (peer.To4() == nil) || peer.Equal(ip)) {
- return fmt.Errorf("peer and local address must be distinct and use the same IP family")
- }
- if ip.To4() == nil && c.MTU < 1280 {
- return fmt.Errorf("IPv6 requires MTU of at least 1280")
- }
- if c.Mode == "client" && c.RemoteEndpoint == "" {
- return fmt.Errorf("client requires a remote endpoint")
- }
- if c.RemoteEndpoint != "" {
- host, port, err := net.SplitHostPort(c.RemoteEndpoint)
- p, portErr := strconv.Atoi(port)
- if err != nil || host == "" || portErr != nil || p < 1 || p > 65535 {
- return fmt.Errorf("remote endpoint must be host:port")
- }
- }
- if c.DefaultRoute && (c.Mode != "client" || c.RemoteEndpoint == "") {
- return fmt.Errorf("default route requires a client with a fixed remote endpoint")
- }
- return nil
- }
- func peerIP(s string) (net.IP, error) {
- if s == "" {
- return nil, nil
- }
- ip := net.ParseIP(s)
- if ip == nil {
- ip, _, _ = net.ParseCIDR(s)
- }
- if ip == nil || ip.IsUnspecified() || ip.IsMulticast() {
- return nil, fmt.Errorf("invalid peer IP address")
- }
- return ip, nil
- }
- func configurePeer(dev VirtualDevice, c TunnelInstance) error {
- peer, err := peerIP(c.PeerAddress)
- if err != nil {
- return err
- }
- if peer == nil {
- return nil
- }
- family := "-4"
- prefix := "/32"
- if peer.To4() == nil {
- family = "-6"
- prefix = "/128"
- }
- if _, err := runIP(family, "route", "add", peer.String()+prefix, "dev", dev.Name()); err != nil {
- return fmt.Errorf("peer route: %w", err)
- }
- // ARP is disabled on the veth fallback: explicitly map the peer to its local
- // endpoint MAC rather than relying on unresolved Ethernet neighbour discovery.
- if v, ok := dev.(*vethTun); ok {
- _, err = runIP(family, "neigh", "replace", peer.String(), "lladdr", net.HardwareAddr(v.epHwAddr[:]).String(), "nud", "permanent", "dev", dev.Name())
- }
- return err
- }
|