mirror of
https://github.com/h44z/wg-portal.git
synced 2025-09-15 07:11:15 +00:00
V2 alpha - initial version (#172)
Initial alpha codebase for version 2 of WireGuard Portal. This version is considered unstable and incomplete (for example, no public REST API)! Use with care! Fixes/Implements the following issues: - OAuth support #154, #1 - New Web UI with internationalisation support #98, #107, #89, #62 - Postgres Support #49 - Improved Email handling #47, #119 - DNS Search Domain support #46 - Bugfixes #94, #48 --------- Co-authored-by: Fabian Wechselberger <wechselbergerf@hotmail.com>
This commit is contained in:
243
internal/domain/peer.go
Normal file
243
internal/domain/peer.go
Normal file
@@ -0,0 +1,243 @@
|
||||
package domain
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/h44z/wg-portal/internal"
|
||||
"net"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||
)
|
||||
|
||||
type PeerIdentifier string
|
||||
|
||||
func (i PeerIdentifier) IsPublicKey() bool {
|
||||
_, err := wgtypes.ParseKey(string(i))
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (i PeerIdentifier) ToPublicKey() wgtypes.Key {
|
||||
publicKey, _ := wgtypes.ParseKey(string(i))
|
||||
return publicKey
|
||||
}
|
||||
|
||||
type Peer struct {
|
||||
BaseModel
|
||||
|
||||
// WireGuard specific (for the [peer] section of the config file)
|
||||
|
||||
Endpoint StringConfigOption `gorm:"embedded;embeddedPrefix:endpoint_"` // the endpoint address
|
||||
EndpointPublicKey StringConfigOption `gorm:"embedded;embeddedPrefix:endpoint_pubkey_"` // the endpoint public key
|
||||
AllowedIPsStr StringConfigOption `gorm:"embedded;embeddedPrefix:allowed_ips_str_"` // all allowed ip subnets, comma seperated
|
||||
ExtraAllowedIPsStr string // all allowed ip subnets on the server side, comma seperated
|
||||
PresharedKey PreSharedKey // the pre-shared Key of the peer
|
||||
PersistentKeepalive IntConfigOption `gorm:"embedded;embeddedPrefix:persistent_keep_alive_"` // the persistent keep-alive interval
|
||||
|
||||
// WG Portal specific
|
||||
|
||||
DisplayName string // a nice display name/ description for the peer
|
||||
Identifier PeerIdentifier `gorm:"primaryKey;column:identifier"` // peer unique identifier
|
||||
UserIdentifier UserIdentifier `gorm:"index;column:user_identifier"` // the owner
|
||||
InterfaceIdentifier InterfaceIdentifier `gorm:"index;column:interface_identifier"` // the interface id
|
||||
Disabled *time.Time `gorm:"column:disabled"` // if this field is set, the peer is disabled
|
||||
DisabledReason string // the reason why the peer has been disabled
|
||||
ExpiresAt *time.Time `gorm:"column:expires_at"` // expiry dates for peers
|
||||
Notes string `form:"notes" binding:"omitempty"` // a note field for peers
|
||||
|
||||
// Interface settings for the peer, used to generate the [interface] section in the peer config file
|
||||
Interface PeerInterfaceConfig `gorm:"embedded"`
|
||||
}
|
||||
|
||||
func (p *Peer) IsDisabled() bool {
|
||||
return p.Disabled != nil
|
||||
}
|
||||
|
||||
func (p *Peer) IsExpired() bool {
|
||||
if p.ExpiresAt == nil {
|
||||
return false
|
||||
}
|
||||
if p.ExpiresAt.Before(time.Now()) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *Peer) CheckAliveAddress() string {
|
||||
if p.Interface.CheckAliveAddress != "" {
|
||||
return p.Interface.CheckAliveAddress
|
||||
}
|
||||
|
||||
if len(p.Interface.Addresses) > 0 {
|
||||
return p.Interface.Addresses[0].Addr // take the first peer address
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func (p *Peer) CopyCalculatedAttributes(src *Peer) {
|
||||
p.BaseModel = src.BaseModel
|
||||
}
|
||||
|
||||
func (p *Peer) GetConfigFileName() string {
|
||||
filename := ""
|
||||
reg := regexp.MustCompile("[^a-zA-Z0-9-_]+")
|
||||
|
||||
if p.DisplayName != "" {
|
||||
filename = p.DisplayName
|
||||
filename = strings.ReplaceAll(filename, " ", "_")
|
||||
filename = reg.ReplaceAllString(filename, "")
|
||||
filename = internal.TruncateString(filename, 16)
|
||||
filename += ".conf"
|
||||
} else {
|
||||
filename = fmt.Sprintf("wg_%s", internal.TruncateString(string(p.Identifier), 8))
|
||||
filename = reg.ReplaceAllString(filename, "")
|
||||
filename += ".conf"
|
||||
}
|
||||
|
||||
return filename
|
||||
}
|
||||
|
||||
func (p *Peer) ApplyInterfaceDefaults(in *Interface) {
|
||||
p.Endpoint.TrySetValue(in.PeerDefEndpoint)
|
||||
p.EndpointPublicKey.TrySetValue(in.PublicKey)
|
||||
p.AllowedIPsStr.TrySetValue(in.PeerDefAllowedIPsStr)
|
||||
p.PersistentKeepalive.TrySetValue(in.PeerDefPersistentKeepalive)
|
||||
p.Interface.DnsStr.TrySetValue(in.PeerDefDnsStr)
|
||||
p.Interface.DnsSearchStr.TrySetValue(in.PeerDefDnsSearchStr)
|
||||
p.Interface.Mtu.TrySetValue(in.PeerDefMtu)
|
||||
p.Interface.FirewallMark.TrySetValue(in.PeerDefFirewallMark)
|
||||
p.Interface.RoutingTable.TrySetValue(in.PeerDefRoutingTable)
|
||||
p.Interface.PreUp.TrySetValue(in.PeerDefPreUp)
|
||||
p.Interface.PostUp.TrySetValue(in.PeerDefPostUp)
|
||||
p.Interface.PreDown.TrySetValue(in.PeerDefPreDown)
|
||||
p.Interface.PostDown.TrySetValue(in.PeerDefPostDown)
|
||||
}
|
||||
|
||||
type PeerInterfaceConfig struct {
|
||||
KeyPair // private/public Key of the peer
|
||||
|
||||
Type InterfaceType `gorm:"column:iface_type"` // the interface type (server, client, any)
|
||||
|
||||
Addresses []Cidr `gorm:"many2many:peer_addresses;"` // the interface ip addresses
|
||||
CheckAliveAddress string `gorm:"column:check_alive_address"` // optional ip address or DNS name that is used for ping checks
|
||||
DnsStr StringConfigOption `gorm:"embedded;embeddedPrefix:iface_dns_str_"` // the dns server that should be set if the interface is up, comma separated
|
||||
DnsSearchStr StringConfigOption `gorm:"embedded;embeddedPrefix:iface_dns_search_str_"` // the dns search option string that should be set if the interface is up, will be appended to DnsStr
|
||||
Mtu IntConfigOption `gorm:"embedded;embeddedPrefix:iface_mtu_"` // the device MTU
|
||||
FirewallMark Int32ConfigOption `gorm:"embedded;embeddedPrefix:iface_firewall_mark_"` // a firewall mark
|
||||
RoutingTable StringConfigOption `gorm:"embedded;embeddedPrefix:iface_routing_table_"` // the routing table
|
||||
|
||||
PreUp StringConfigOption `gorm:"embedded;embeddedPrefix:iface_pre_up_"` // action that is executed before the device is up
|
||||
PostUp StringConfigOption `gorm:"embedded;embeddedPrefix:iface_post_up_"` // action that is executed after the device is up
|
||||
PreDown StringConfigOption `gorm:"embedded;embeddedPrefix:iface_pre_down_"` // action that is executed before the device is down
|
||||
PostDown StringConfigOption `gorm:"embedded;embeddedPrefix:iface_post_down_"` // action that is executed after the device is down
|
||||
}
|
||||
|
||||
func (p *PeerInterfaceConfig) AddressStr() string {
|
||||
return CidrsToString(p.Addresses)
|
||||
}
|
||||
|
||||
type PhysicalPeer struct {
|
||||
Identifier PeerIdentifier // peer unique identifier
|
||||
|
||||
Endpoint string // the endpoint address
|
||||
AllowedIPs []Cidr // all allowed ip subnets
|
||||
KeyPair // private/public Key of the peer, for imports it only contains the public key as the private key is not known to the server
|
||||
PresharedKey PreSharedKey // the pre-shared Key of the peer
|
||||
PersistentKeepalive int // the persistent keep-alive interval
|
||||
|
||||
LastHandshake time.Time
|
||||
ProtocolVersion int
|
||||
|
||||
BytesUpload uint64 // upload bytes are the number of bytes that the remote peer has sent to the server
|
||||
BytesDownload uint64 // upload bytes are the number of bytes that the remote peer has received from the server
|
||||
}
|
||||
|
||||
func (p PhysicalPeer) GetPresharedKey() *wgtypes.Key {
|
||||
if p.PresharedKey == "" {
|
||||
return nil
|
||||
}
|
||||
key, err := wgtypes.ParseKey(string(p.PresharedKey))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &key
|
||||
}
|
||||
|
||||
func (p PhysicalPeer) GetEndpointAddress() *net.UDPAddr {
|
||||
if p.Endpoint == "" {
|
||||
return nil
|
||||
}
|
||||
addr, err := net.ResolveUDPAddr("udp", p.Endpoint)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return addr
|
||||
}
|
||||
|
||||
func (p PhysicalPeer) GetPersistentKeepaliveTime() *time.Duration {
|
||||
if p.PersistentKeepalive == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
keepAliveDuration := time.Duration(p.PersistentKeepalive) * time.Second
|
||||
return &keepAliveDuration
|
||||
}
|
||||
|
||||
func (p PhysicalPeer) GetAllowedIPs() []net.IPNet {
|
||||
allowedIPs := make([]net.IPNet, len(p.AllowedIPs))
|
||||
for i, ip := range p.AllowedIPs {
|
||||
allowedIPs[i] = *ip.IpNet()
|
||||
}
|
||||
|
||||
return allowedIPs
|
||||
}
|
||||
|
||||
func ConvertPhysicalPeer(pp *PhysicalPeer) *Peer {
|
||||
peer := &Peer{
|
||||
Endpoint: StringConfigOption{Value: pp.Endpoint, Overridable: true},
|
||||
EndpointPublicKey: StringConfigOption{Value: "", Overridable: true},
|
||||
AllowedIPsStr: StringConfigOption{Value: "", Overridable: true},
|
||||
ExtraAllowedIPsStr: "",
|
||||
PresharedKey: pp.PresharedKey,
|
||||
PersistentKeepalive: IntConfigOption{Value: pp.PersistentKeepalive, Overridable: true},
|
||||
DisplayName: string(pp.Identifier),
|
||||
Identifier: pp.Identifier,
|
||||
UserIdentifier: "",
|
||||
InterfaceIdentifier: "",
|
||||
Disabled: nil,
|
||||
Interface: PeerInterfaceConfig{
|
||||
KeyPair: pp.KeyPair,
|
||||
},
|
||||
}
|
||||
|
||||
return peer
|
||||
}
|
||||
|
||||
func MergeToPhysicalPeer(pp *PhysicalPeer, p *Peer) {
|
||||
pp.Identifier = p.Identifier
|
||||
pp.Endpoint = p.Endpoint.GetValue()
|
||||
if p.Interface.Type == InterfaceTypeServer {
|
||||
allowedIPs, _ := CidrsFromString(p.AllowedIPsStr.GetValue())
|
||||
extraAllowedIPs, _ := CidrsFromString(p.ExtraAllowedIPsStr)
|
||||
pp.AllowedIPs = append(allowedIPs, extraAllowedIPs...)
|
||||
} else {
|
||||
allowedIPs := p.Interface.Addresses
|
||||
extraAllowedIPs, _ := CidrsFromString(p.ExtraAllowedIPsStr)
|
||||
pp.AllowedIPs = append(allowedIPs, extraAllowedIPs...)
|
||||
}
|
||||
pp.PresharedKey = p.PresharedKey
|
||||
pp.PublicKey = p.Interface.PublicKey
|
||||
pp.PersistentKeepalive = p.PersistentKeepalive.GetValue()
|
||||
}
|
||||
|
||||
type PeerCreationRequest struct {
|
||||
UserIdentifiers []string
|
||||
Suffix string
|
||||
}
|
Reference in New Issue
Block a user