syncthing/lib/nat/structs.go

132 lines
3.1 KiB
Go

// Copyright (C) 2015 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
package nat
import (
"fmt"
"net"
"time"
"github.com/syncthing/syncthing/lib/sync"
)
type MappingChangeSubscriber func()
type Mapping struct {
protocol Protocol
ipVersion IPVersion
address Address
extAddresses map[string][]Address // NAT ID -> Address
expires time.Time
subscribers []MappingChangeSubscriber
mut sync.RWMutex
}
func (m *Mapping) setAddressLocked(id string, addresses []Address) {
l.Infof("New external port opened: external %s address(es) %v to local address %s.", m.protocol, addresses, m.address)
m.extAddresses[id] = addresses
}
func (m *Mapping) removeAddressLocked(id string) {
addresses, ok := m.extAddresses[id]
if ok {
l.Infof("Removing external open port: %s address(es) %v for gateway %s.", m.protocol, addresses, id)
delete(m.extAddresses, id)
}
}
func (m *Mapping) clearAddresses() {
m.mut.Lock()
change := len(m.extAddresses) > 0
for id, addr := range m.extAddresses {
l.Debugf("Clearing mapping %s: ID: %s Address: %s", m, id, addr)
delete(m.extAddresses, id)
}
m.expires = time.Time{}
m.mut.Unlock()
if change {
m.notify()
}
}
func (m *Mapping) notify() {
m.mut.RLock()
for _, subscriber := range m.subscribers {
subscriber()
}
m.mut.RUnlock()
}
func (m *Mapping) Protocol() Protocol {
return m.protocol
}
func (m *Mapping) Address() Address {
return m.address
}
func (m *Mapping) ExternalAddresses() []Address {
m.mut.RLock()
addrs := make([]Address, 0, len(m.extAddresses))
for _, addr := range m.extAddresses {
addrs = append(addrs, addr...)
}
m.mut.RUnlock()
return addrs
}
func (m *Mapping) OnChanged(subscribed MappingChangeSubscriber) {
m.mut.Lock()
m.subscribers = append(m.subscribers, subscribed)
m.mut.Unlock()
}
func (m *Mapping) String() string {
return fmt.Sprintf("%s/%s", m.address, m.protocol)
}
func (m *Mapping) GoString() string {
return m.String()
}
// Checks if the mappings local IP address matches the IP address of the gateway
// For example, if we are explicitly listening on 192.168.0.12, there is no
// point trying to acquire a mapping on a gateway to which the local IP is
// 10.0.0.1. Fallback to true if any of the IPs is not there.
func (m *Mapping) validGateway(ip net.IP) bool {
if m.address.IP == nil || ip == nil || m.address.IP.IsUnspecified() || ip.IsUnspecified() {
return true
}
return m.address.IP.Equal(ip)
}
// Address is essentially net.TCPAddr yet is more general, and has a few helper
// methods which reduce boilerplate code.
type Address struct {
IP net.IP
Port int
}
func (a Address) Equal(b Address) bool {
return a.Port == b.Port && a.IP.Equal(b.IP)
}
func (a Address) String() string {
var ipStr string
if a.IP == nil {
ipStr = net.IPv4zero.String()
} else {
ipStr = a.IP.String()
}
return net.JoinHostPort(ipStr, fmt.Sprintf("%d", a.Port))
}
func (a Address) GoString() string {
return a.String()
}