mirror of
				https://github.com/tailscale/tailscale.git
				synced 2025-11-04 00:55:11 +00:00 
			
		
		
		
	perl -i -npe 's,netaddr.IPPrefixFrom,netip.PrefixFrom,' $(git grep -l -F netaddr.)
    perl -i -npe 's,netaddr.IPPortFrom,netip.AddrPortFrom,' $(git grep -l -F netaddr. )
    perl -i -npe 's,netaddr.IPPrefix,netip.Prefix,g' $(git grep -l -F netaddr. )
    perl -i -npe 's,netaddr.IPPort,netip.AddrPort,g' $(git grep -l -F netaddr. )
    perl -i -npe 's,netaddr.IP\b,netip.Addr,g' $(git grep -l -F netaddr. )
    perl -i -npe 's,netaddr.IPv6Raw\b,netip.AddrFrom16,g' $(git grep -l -F netaddr. )
    goimports -w .
Then delete some stuff from the net/netaddr shim package which is no
longer neeed.
Updates #5162
Change-Id: Ia7a86893fe21c7e3ee1ec823e8aba288d4566cd8
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
		
	
		
			
				
	
	
		
			188 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			188 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Copyright (c) 2021 Tailscale Inc & AUTHORS All rights reserved.
 | 
						|
// Use of this source code is governed by a BSD-style
 | 
						|
// license that can be found in the LICENSE file.
 | 
						|
 | 
						|
package wgcfg
 | 
						|
 | 
						|
import (
 | 
						|
	"bufio"
 | 
						|
	"fmt"
 | 
						|
	"io"
 | 
						|
	"net"
 | 
						|
	"net/netip"
 | 
						|
	"strconv"
 | 
						|
	"strings"
 | 
						|
 | 
						|
	"go4.org/mem"
 | 
						|
	"tailscale.com/types/key"
 | 
						|
)
 | 
						|
 | 
						|
type ParseError struct {
 | 
						|
	why      string
 | 
						|
	offender string
 | 
						|
}
 | 
						|
 | 
						|
func (e *ParseError) Error() string {
 | 
						|
	return fmt.Sprintf("%s: %q", e.why, e.offender)
 | 
						|
}
 | 
						|
 | 
						|
func parseEndpoint(s string) (host string, port uint16, err error) {
 | 
						|
	i := strings.LastIndexByte(s, ':')
 | 
						|
	if i < 0 {
 | 
						|
		return "", 0, &ParseError{"Missing port from endpoint", s}
 | 
						|
	}
 | 
						|
	host, portStr := s[:i], s[i+1:]
 | 
						|
	if len(host) < 1 {
 | 
						|
		return "", 0, &ParseError{"Invalid endpoint host", host}
 | 
						|
	}
 | 
						|
	uport, err := strconv.ParseUint(portStr, 10, 16)
 | 
						|
	if err != nil {
 | 
						|
		return "", 0, err
 | 
						|
	}
 | 
						|
	hostColon := strings.IndexByte(host, ':')
 | 
						|
	if host[0] == '[' || host[len(host)-1] == ']' || hostColon > 0 {
 | 
						|
		err := &ParseError{"Brackets must contain an IPv6 address", host}
 | 
						|
		if len(host) > 3 && host[0] == '[' && host[len(host)-1] == ']' && hostColon > 0 {
 | 
						|
			maybeV6 := net.ParseIP(host[1 : len(host)-1])
 | 
						|
			if maybeV6 == nil || len(maybeV6) != net.IPv6len {
 | 
						|
				return "", 0, err
 | 
						|
			}
 | 
						|
		} else {
 | 
						|
			return "", 0, err
 | 
						|
		}
 | 
						|
		host = host[1 : len(host)-1]
 | 
						|
	}
 | 
						|
	return host, uint16(uport), nil
 | 
						|
}
 | 
						|
 | 
						|
// memROCut separates a mem.RO at the separator if it exists, otherwise
 | 
						|
// it returns two empty ROs and reports that it was not found.
 | 
						|
func memROCut(s mem.RO, sep byte) (before, after mem.RO, found bool) {
 | 
						|
	if i := mem.IndexByte(s, sep); i >= 0 {
 | 
						|
		return s.SliceTo(i), s.SliceFrom(i + 1), true
 | 
						|
	}
 | 
						|
	found = false
 | 
						|
	return
 | 
						|
}
 | 
						|
 | 
						|
// FromUAPI generates a Config from r.
 | 
						|
// r should be generated by calling device.IpcGetOperation;
 | 
						|
// it is not compatible with other uapi streams.
 | 
						|
func FromUAPI(r io.Reader) (*Config, error) {
 | 
						|
	cfg := new(Config)
 | 
						|
	var peer *Peer // current peer being operated on
 | 
						|
	deviceConfig := true
 | 
						|
 | 
						|
	scanner := bufio.NewScanner(r)
 | 
						|
	for scanner.Scan() {
 | 
						|
		line := mem.B(scanner.Bytes())
 | 
						|
		if line.Len() == 0 {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		key, value, ok := memROCut(line, '=')
 | 
						|
		if !ok {
 | 
						|
			return nil, fmt.Errorf("failed to cut line %q on =", line.StringCopy())
 | 
						|
		}
 | 
						|
		valueBytes := scanner.Bytes()[key.Len()+1:]
 | 
						|
 | 
						|
		if key.EqualString("public_key") {
 | 
						|
			if deviceConfig {
 | 
						|
				deviceConfig = false
 | 
						|
			}
 | 
						|
			// Load/create the peer we are now configuring.
 | 
						|
			var err error
 | 
						|
			peer, err = cfg.handlePublicKeyLine(valueBytes)
 | 
						|
			if err != nil {
 | 
						|
				return nil, err
 | 
						|
			}
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		var err error
 | 
						|
		if deviceConfig {
 | 
						|
			err = cfg.handleDeviceLine(key, value, valueBytes)
 | 
						|
		} else {
 | 
						|
			err = cfg.handlePeerLine(peer, key, value, valueBytes)
 | 
						|
		}
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if err := scanner.Err(); err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	return cfg, nil
 | 
						|
}
 | 
						|
 | 
						|
func (cfg *Config) handleDeviceLine(k, value mem.RO, valueBytes []byte) error {
 | 
						|
	switch {
 | 
						|
	case k.EqualString("private_key"):
 | 
						|
		// wireguard-go guarantees not to send zero value; private keys are already clamped.
 | 
						|
		var err error
 | 
						|
		cfg.PrivateKey, err = key.ParseNodePrivateUntyped(value)
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
	case k.EqualString("listen_port") || k.EqualString("fwmark"):
 | 
						|
	// ignore
 | 
						|
	default:
 | 
						|
		return fmt.Errorf("unexpected IpcGetOperation key: %q", k.StringCopy())
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (cfg *Config) handlePublicKeyLine(valueBytes []byte) (*Peer, error) {
 | 
						|
	p := Peer{}
 | 
						|
	var err error
 | 
						|
	p.PublicKey, err = key.ParseNodePublicUntyped(mem.B(valueBytes))
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	cfg.Peers = append(cfg.Peers, p)
 | 
						|
	return &cfg.Peers[len(cfg.Peers)-1], nil
 | 
						|
}
 | 
						|
 | 
						|
func (cfg *Config) handlePeerLine(peer *Peer, k, value mem.RO, valueBytes []byte) error {
 | 
						|
	switch {
 | 
						|
	case k.EqualString("endpoint"):
 | 
						|
		nk, err := key.ParseNodePublicUntyped(value)
 | 
						|
		if err != nil {
 | 
						|
			return fmt.Errorf("invalid endpoint %q for peer %q, expected a hex public key", value.StringCopy(), peer.PublicKey.ShortString())
 | 
						|
		}
 | 
						|
		// nk ought to equal peer.PublicKey.
 | 
						|
		// Under some rare circumstances, it might not. See corp issue #3016.
 | 
						|
		// Even if that happens, don't stop early, so that we can recover from it.
 | 
						|
		// Instead, note the value of nk so we can fix as needed.
 | 
						|
		peer.WGEndpoint = nk
 | 
						|
	case k.EqualString("persistent_keepalive_interval"):
 | 
						|
		n, err := mem.ParseUint(value, 10, 16)
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
		peer.PersistentKeepalive = uint16(n)
 | 
						|
	case k.EqualString("allowed_ip"):
 | 
						|
		ipp := netip.Prefix{}
 | 
						|
		err := ipp.UnmarshalText(valueBytes)
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
		peer.AllowedIPs = append(peer.AllowedIPs, ipp)
 | 
						|
	case k.EqualString("protocol_version"):
 | 
						|
		if !value.EqualString("1") {
 | 
						|
			return fmt.Errorf("invalid protocol version: %q", value.StringCopy())
 | 
						|
		}
 | 
						|
	case k.EqualString("replace_allowed_ips") ||
 | 
						|
		k.EqualString("preshared_key") ||
 | 
						|
		k.EqualString("last_handshake_time_sec") ||
 | 
						|
		k.EqualString("last_handshake_time_nsec") ||
 | 
						|
		k.EqualString("tx_bytes") ||
 | 
						|
		k.EqualString("rx_bytes"):
 | 
						|
	// ignore
 | 
						|
	default:
 | 
						|
		return fmt.Errorf("unexpected IpcGetOperation key: %q", k.StringCopy())
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 |