-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
wgcfg: new package #11
base: master
Are you sure you want to change the base?
Changes from 1 commit
d49f4e9
6679323
c4a8eab
900ae64
d5d7075
bad6ad6
33aaf34
786d87d
9f6251f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
Based on types and config parser from wireguard-windows. Signed-off-by: David Crawshaw <crawshaw@tailscale.com>
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
/* SPDX-License-Identifier: MIT | ||
* | ||
* Copyright (C) 2019 WireGuard LLC. All Rights Reserved. | ||
*/ | ||
|
||
// Package wgcfg has types and a parser for representing WireGuard config. | ||
package wgcfg | ||
|
||
import ( | ||
"fmt" | ||
"strings" | ||
) | ||
|
||
// Config is a wireguard configuration. | ||
type Config struct { | ||
Name string | ||
PrivateKey PrivateKey | ||
Addresses []CIDR | ||
ListenPort uint16 | ||
MTU uint16 | ||
DNS []IP | ||
Peers []Peer | ||
} | ||
|
||
type Peer struct { | ||
PublicKey Key | ||
PresharedKey SymmetricKey | ||
AllowedIPs []CIDR | ||
Endpoints []Endpoint | ||
PersistentKeepalive uint16 | ||
} | ||
|
||
type Endpoint struct { | ||
Host string | ||
Port uint16 | ||
} | ||
|
||
func (e *Endpoint) String() string { | ||
if strings.IndexByte(e.Host, ':') > 0 { | ||
return fmt.Sprintf("[%s]:%d", e.Host, e.Port) | ||
} | ||
return fmt.Sprintf("%s:%d", e.Host, e.Port) | ||
} | ||
|
||
func (e *Endpoint) IsEmpty() bool { | ||
return len(e.Host) == 0 | ||
} | ||
|
||
// Copy makes a deep copy of Config. | ||
// The result aliases no memory with the original. | ||
func (cfg Config) Copy() Config { | ||
res := cfg | ||
if res.Addresses != nil { | ||
res.Addresses = append([]CIDR{}, res.Addresses...) | ||
} | ||
if res.DNS != nil { | ||
res.DNS = append([]IP{}, res.DNS...) | ||
} | ||
peers := make([]Peer, 0, len(res.Peers)) | ||
for _, peer := range res.Peers { | ||
peers = append(peers, peer.Copy()) | ||
} | ||
res.Peers = peers | ||
return res | ||
} | ||
|
||
// Copy makes a deep copy of Peer. | ||
// The result aliases no memory with the original. | ||
func (peer Peer) Copy() Peer { | ||
res := peer | ||
if res.AllowedIPs != nil { | ||
res.AllowedIPs = append([]CIDR{}, res.AllowedIPs...) | ||
} | ||
if res.Endpoints != nil { | ||
res.Endpoints = append([]Endpoint{}, res.Endpoints...) | ||
} | ||
return res | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
package wgcfg | ||
|
||
import ( | ||
"fmt" | ||
"net" | ||
) | ||
|
||
// IP is an IPv4 or an IPv6 address. | ||
// | ||
// Internally the address is always represented in its IPv6 form. | ||
// IPv4 addresses use the IPv4-in-IPv6 syntax. | ||
type IP struct { | ||
Addr [16]byte | ||
} | ||
|
||
func (ip IP) String() string { return net.IP(ip.Addr[:]).String() } | ||
|
||
func (ip *IP) IP() net.IP { return net.IP(ip.Addr[:]) } | ||
func (ip *IP) Is6() bool { return !ip.Is4() } | ||
func (ip *IP) Is4() bool { | ||
return ip.Addr[0] == 0 && ip.Addr[1] == 0 && | ||
ip.Addr[2] == 0 && ip.Addr[3] == 0 && | ||
ip.Addr[4] == 0 && ip.Addr[5] == 0 && | ||
ip.Addr[6] == 0 && ip.Addr[7] == 0 && | ||
ip.Addr[8] == 0 && ip.Addr[9] == 0 && | ||
ip.Addr[10] == 0xff && ip.Addr[11] == 0xff | ||
} | ||
func (ip *IP) To4() []byte { | ||
if ip.Is4() { | ||
return ip.Addr[12:16] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ditto here. |
||
} else { | ||
return nil | ||
} | ||
} | ||
func (ip *IP) Equal(x *IP) bool { | ||
if ip == nil || x == nil { | ||
return false | ||
} | ||
// TODO: this isn't hard, write a more efficient implementation. | ||
return ip.IP().Equal(x.IP()) | ||
} | ||
|
||
func (ip IP) MarshalText() ([]byte, error) { | ||
return []byte(ip.String()), nil | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not super familiar here -- what's with the function name and signature? Can't we just have |
||
} | ||
|
||
func (ip *IP) UnmarshalText(text []byte) error { | ||
parsedIP := ParseIP(string(text)) | ||
if parsedIP == nil { | ||
return fmt.Errorf("wgcfg.IP: UnmarshalText: bad IP address %q", string(text)) | ||
} | ||
*ip = *parsedIP | ||
return nil | ||
} | ||
|
||
func IPv4(b0, b1, b2, b3 byte) (ip IP) { | ||
ip.Addr[10], ip.Addr[11] = 0xff, 0xff // IPv4-in-IPv6 prefix | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No. See objection above. |
||
ip.Addr[12] = b0 | ||
ip.Addr[13] = b1 | ||
ip.Addr[14] = b2 | ||
ip.Addr[15] = b3 | ||
return ip | ||
} | ||
|
||
// ParseIP parses the string representation of an address into an IP. | ||
// | ||
// It accepts IPv4 notation such as "1.2.3.4" and IPv6 notation like ""::0". | ||
// If the string is not a valid IP address, ParseIP returns nil. | ||
func ParseIP(s string) *IP { | ||
netIP := net.ParseIP(s) | ||
if netIP == nil { | ||
return nil | ||
} | ||
ip := new(IP) | ||
copy(ip.Addr[:], netIP.To16()) | ||
return ip | ||
} | ||
|
||
// CIDR is a compact IP address and subnet mask. | ||
type CIDR struct { | ||
IP IP | ||
Mask uint8 // 0-32 for IsIPv4, 4-128 for IsIPv6 | ||
} | ||
|
||
// ParseCIDR parses CIDR notation into a CIDR type. | ||
// Typical CIDR strings look like "192.168.1.0/24". | ||
func ParseCIDR(s string) (cidr *CIDR, err error) { | ||
netIP, netAddr, err := net.ParseCIDR(s) | ||
if err != nil { | ||
return nil, err | ||
} | ||
cidr = new(CIDR) | ||
copy(cidr.IP.Addr[:], netIP.To16()) | ||
ones, _ := netAddr.Mask.Size() | ||
cidr.Mask = uint8(ones) | ||
|
||
return cidr, nil | ||
} | ||
|
||
func (r CIDR) String() string { return r.IPNet().String() } | ||
|
||
func (r *CIDR) IPNet() *net.IPNet { | ||
bits := 128 | ||
if r.IP.Is4() { | ||
bits = 32 | ||
} | ||
return &net.IPNet{IP: r.IP.IP(), Mask: net.CIDRMask(int(r.Mask), bits)} | ||
} | ||
func (r *CIDR) Contains(ip *IP) bool { | ||
if r == nil || ip == nil { | ||
return false | ||
} | ||
// TODO: this isn't hard, write a more efficient implementation. | ||
return r.IPNet().Contains(ip.IP()) | ||
} | ||
|
||
func (r CIDR) MarshalText() ([]byte, error) { | ||
return []byte(r.String()), nil | ||
} | ||
|
||
func (r *CIDR) UnmarshalText(text []byte) error { | ||
cidr, err := ParseCIDR(string(text)) | ||
if err != nil { | ||
return fmt.Errorf("wgcfg.CIDR: UnmarshalText: %v", err) | ||
} | ||
*r = *cidr | ||
return nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See objection below.