@end itemize
GoVPN is written on @url{https://golang.org/, Go} programming language
-and you have to install Go compiler (1.5+ version is highly recommended,
-1.4 is the minimal sufficient): @code{lang/go} port in FreeBSD and
-@code{golang} package in most GNU/Linux distributions. @emph{Make} (BSD
-and GNU ones are fine) is recommended for convenient building.
-@url{https://www.gnu.org/software/texinfo/, Texinfo} (6.1+ version is
-recommended) is used for building documentation. Possibly you also need
-to install TUN/TAP interface utilities (depending on your operating
-system): @command{uml-utilities} package in most GNU/Linux distributions.
+and you have to install Go compiler 1.9+ version: @code{lang/go} port in
+FreeBSD and @code{golang} package in most GNU/Linux distributions.
+@emph{Make} (BSD and GNU ones are fine) is recommended for convenient
+building. @url{https://www.gnu.org/software/texinfo/, Texinfo} (6.1+
+version is recommended) is used for building documentation. Possibly you
+also need to install TUN/TAP interface utilities (depending on your
+operating system): @command{uml-utilities} package in most GNU/Linux
+distributions.
Get @ref{Tarballs, the tarball}, check its
@ref{Integrity, integrity and authenticity} and run @command{make}.
@node Новости
@section Новости
+@node Релиз 7.4
+@subsection Релиз 7.4
+@itemize
+@item Маленький рефакторинг. Минимальная необходимая версия Go 1.9.
+@item Обновлены зависимые криптографические библиотеки.
+@end itemize
+
@node Релиз 7.3
@subsection Релиз 7.3
@itemize
See also this page @ref{Новости, on russian}.
+@node Release 7.4
+@section Release 7.4
+@itemize
+@item Tiny refactoring. Go 1.9 is minimal required version.
+@item Dependant cryptographic libraries are updated.
+@end itemize
+
@node Release 7.3
@section Release 7.3
@itemize
# $FreeBSD$
PORTNAME= govpn
-PORTVERSION= 7.3
+PORTVERSION= 7.4
CATEGORIES= security
MASTER_SITES= http://www.govpn.info/download/
"fmt"
"net"
"os"
+ "sync"
"time"
"github.com/agl/ed25519"
type Client struct {
idsCache *govpn.MACCache
tap *govpn.TAP
- knownPeers govpn.KnownPeers
+ knownPeers sync.Map
statsPort net.Listener
timeouted chan struct{}
rehandshaking chan struct{}
c.Error <- fmt.Errorf("Can't listen on stats port: %s", err.Error())
return
}
- c.knownPeers = govpn.KnownPeers(make(map[string]**govpn.Peer))
go govpn.StatsProcessor(c.statsPort, &c.knownPeers)
}
continue
}
govpn.Printf(`[handshake-completed remote="%s"]`, c.config.RemoteAddress)
- c.knownPeers = govpn.KnownPeers(map[string]**govpn.Peer{c.config.RemoteAddress: &peer})
+ c.knownPeers.Store(c.config.RemoteAddress, &peer)
if c.firstUpCall {
go govpn.ScriptCall(c.config.UpPath, c.config.InterfaceName, c.config.RemoteAddress)
c.firstUpCall = false
continue
}
govpn.Printf(`[handshake-completed remote="%s"]`, c.config.RemoteAddress)
- c.knownPeers = govpn.KnownPeers(map[string]**govpn.Peer{c.config.RemoteAddress: &peer})
+ c.knownPeers.Store(c.config.RemoteAddress, &peer)
if c.firstUpCall {
go govpn.ScriptCall(c.config.UpPath, c.config.InterfaceName, c.config.RemoteAddress)
c.firstUpCall = false
}
var (
- handshakes map[string]*govpn.Handshake = make(map[string]*govpn.Handshake)
- hsLock sync.RWMutex
-
- peers = make(map[string]*PeerState)
- peersLock sync.RWMutex
-
- peersByID = make(map[govpn.PeerID]string)
- peersByIDLock sync.RWMutex
-
- knownPeers govpn.KnownPeers
- kpLock sync.RWMutex
+ handshakes sync.Map
+ peers sync.Map
+ peersByID sync.Map
+ knownPeers sync.Map
)
func callUp(peerID *govpn.PeerID, remoteAddr string) (string, error) {
log.Println(govpn.VersionGet())
confInit()
- knownPeers = govpn.KnownPeers(make(map[string]**govpn.Peer))
if *egdPath != "" {
log.Println("Using", *egdPath, "EGD")
select {
case <-termSignal:
govpn.BothPrintf(`[terminating bind="%s"]`, *bindAddr)
- for _, ps := range peers {
+ peers.Range(func(_, psI interface{}) bool {
+ ps := psI.(*PeerState)
govpn.ScriptCall(
confs[*ps.peer.ID].Down,
ps.tap.Name,
ps.peer.Addr,
)
- }
+ return true
+ })
break MainCycle
case <-hsHeartbeat:
now := time.Now()
- hsLock.Lock()
- for addr, hs := range handshakes {
+
+ handshakes.Range(func(addrI, hsI interface{}) bool {
+ addr := addrI.(string)
+ hs := hsI.(*govpn.Handshake)
if hs.LastPing.Add(timeout).Before(now) {
govpn.Printf(`[handshake-delete bind="%s" addr="%s"]`, *bindAddr, addr)
hs.Zero()
- delete(handshakes, addr)
+ handshakes.Delete(addr)
}
- }
- peersLock.Lock()
- peersByIDLock.Lock()
- kpLock.Lock()
- for addr, ps := range peers {
+ return true
+ })
+
+ peers.Range(func(addrI, psI interface{}) bool {
+ addr := addrI.(string)
+ ps := psI.(*PeerState)
ps.peer.BusyR.Lock()
needsDeletion = ps.peer.LastPing.Add(timeout).Before(now)
ps.peer.BusyR.Unlock()
*bindAddr,
ps.peer.ID.String(),
)
- delete(peers, addr)
- delete(knownPeers, addr)
- delete(peersByID, *ps.peer.ID)
+ peers.Delete(addr)
+ knownPeers.Delete(addr)
+ peersByID.Delete(*ps.peer.ID)
go govpn.ScriptCall(
confs[*ps.peer.ID].Down,
ps.tap.Name,
)
ps.terminator <- struct{}{}
}
- }
- hsLock.Unlock()
- peersLock.Unlock()
- peersByIDLock.Unlock()
- kpLock.Unlock()
+ return true
+ })
}
}
}
var peer *govpn.Peer
var tap *govpn.TAP
var conf *govpn.PeerConf
+ var addrPrev string
+ var peerPrevI interface{}
+ var peerPrev *PeerState
for {
if prev == len(buf) {
break
`[handshake-completed bind="%s" addr="%s" peer="%s"]`,
*bindAddr, addr, peerID.String(),
)
- peersByIDLock.RLock()
- addrPrev, exists := peersByID[*peer.ID]
- peersByIDLock.RUnlock()
- var peerPrev *PeerState
+ addrPrevI, exists := peersByID.Load(*peer.ID)
if exists {
- peersLock.Lock()
- peerPrev = peers[addrPrev]
- if peerPrev == nil {
- exists = false
- peersLock.Unlock()
+ addrPrev = addrPrevI.(string)
+ peerPrevI, exists = peers.Load(addrPrev)
+ if exists {
+ peerPrev = peerPrevI.(*PeerState)
+ exists = peerPrev == nil
}
}
if exists {
terminator: make(chan struct{}),
}
go govpn.PeerTapProcessor(ps.peer, ps.tap, ps.terminator)
- peersByIDLock.Lock()
- kpLock.Lock()
- delete(peers, addrPrev)
- delete(knownPeers, addrPrev)
- peers[addr] = ps
- knownPeers[addr] = &peer
- peersByID[*peer.ID] = addr
- peersLock.Unlock()
- peersByIDLock.Unlock()
- kpLock.Unlock()
+ peers.Delete(addrPrev)
+ peers.Store(addr, ps)
+ knownPeers.Delete(addrPrev)
+ knownPeers.Store(addr, &peer)
+ peersByID.Store(*peer.ID, addr)
govpn.Printf(
`[rehandshake-completed bind="%s" peer="%s"]`,
*bindAddr, peerID.String(),
terminator: make(chan struct{}, 1),
}
go govpn.PeerTapProcessor(ps.peer, ps.tap, ps.terminator)
- peersLock.Lock()
- peersByIDLock.Lock()
- kpLock.Lock()
- peers[addr] = ps
- peersByID[*peer.ID] = addr
- knownPeers[addr] = &peer
- peersLock.Unlock()
- peersByIDLock.Unlock()
- kpLock.Unlock()
+ peers.Store(addr, ps)
+ peersByID.Store(*peer.ID, addr)
+ knownPeers.Store(addr, &peer)
govpn.Printf(`[peer-created bind="%s" peer="%s"]`, *bindAddr, peerID.String())
}
break
var addr string
var n int
var err error
+ var exists bool
+ var psI interface{}
var ps *PeerState
+ var hsI interface{}
var hs *govpn.Handshake
+ var addrPrevI interface{}
var addrPrev string
- var exists bool
+ var peerPrevI interface{}
+ var peerPrev *PeerState
var peerID *govpn.PeerID
var conf *govpn.PeerConf
for {
}
addr = raddr.String()
- peersLock.RLock()
- ps, exists = peers[addr]
- peersLock.RUnlock()
+ psI, exists = peers.Load(addr)
if exists {
+ ps = psI.(*PeerState)
go func(peer *govpn.Peer, tap *govpn.TAP, buf []byte, n int) {
peer.PktProcess(buf[:n], tap, true)
udpBufs <- buf
continue
}
- hsLock.RLock()
- hs, exists = handshakes[addr]
- hsLock.RUnlock()
+ hsI, exists = handshakes.Load(addr)
if !exists {
peerID = idsCache.Find(buf[:n])
if peerID == nil {
)
hs.Server(buf[:n])
udpBufs <- buf
- hsLock.Lock()
- handshakes[addr] = hs
- hsLock.Unlock()
+ handshakes.Store(addr, hs)
continue
}
+ hs = hsI.(*govpn.Handshake)
peer := hs.Server(buf[:n])
if peer == nil {
udpBufs <- buf
*bindAddr, addr, peerID.String(),
)
hs.Zero()
- hsLock.Lock()
- delete(handshakes, addr)
- hsLock.Unlock()
+ handshakes.Delete(addr)
go func() {
udpBufs <- make([]byte, govpn.MTUMax)
udpBufs <- make([]byte, govpn.MTUMax)
}()
- peersByIDLock.RLock()
- addrPrev, exists = peersByID[*peer.ID]
- peersByIDLock.RUnlock()
- var peerPrev *PeerState
+ addrPrevI, exists = peersByID.Load(*peer.ID)
if exists {
- peersLock.Lock()
- peerPrev = peers[addrPrev]
- if peerPrev == nil {
- exists = false
- peersLock.Unlock()
+ addrPrev = addrPrevI.(string)
+ peerPrevI, exists = peers.Load(addrPrev)
+ if exists {
+ peerPrev = peerPrevI.(*PeerState)
+ exists = peerPrev == nil
}
}
if exists {
<-udpBufs
<-udpBufs
}(psNew.peer, psNew.tap, psNew.terminator)
- peersByIDLock.Lock()
- kpLock.Lock()
- delete(peers, addrPrev)
- delete(knownPeers, addrPrev)
- peers[addr] = psNew
- knownPeers[addr] = &peer
- peersByID[*peer.ID] = addr
- peersLock.Unlock()
- peersByIDLock.Unlock()
- kpLock.Unlock()
+ peers.Delete(addrPrev)
+ peers.Store(addr, psNew)
+ knownPeers.Delete(addrPrev)
+ knownPeers.Store(addr, &peer)
+ peersByID.Store(*peer.ID, addr)
govpn.Printf(
`[rehandshake-completed bind="%s" peer="%s"]`,
*bindAddr, peer.ID.String(),
<-udpBufs
<-udpBufs
}(psNew.peer, psNew.tap, psNew.terminator)
- peersLock.Lock()
- peersByIDLock.Lock()
- kpLock.Lock()
- peers[addr] = psNew
- knownPeers[addr] = &peer
- peersByID[*peer.ID] = addr
- peersLock.Unlock()
- peersByIDLock.Unlock()
- kpLock.Unlock()
+ peers.Store(addr, psNew)
+ knownPeers.Store(addr, &peer)
+ peersByID.Store(*peer.ID, addr)
govpn.Printf(
`[peer-created bind="%s" peer="%s"]`,
*bindAddr,
"encoding/json"
"log"
"net"
+ "sync"
"time"
)
RWTimeout = 10 * time.Second
)
-type KnownPeers map[string]**Peer
-
// StatsProcessor is assumed to be run in background. It accepts
// connection on statsPort, reads anything one send to them and show
// information about known peers in serialized JSON format. peers
// argument is a reference to the map with references to the peers as
// values. Map is used here because of ease of adding and removing
// elements in it.
-func StatsProcessor(statsPort net.Listener, peers *KnownPeers) {
+func StatsProcessor(statsPort net.Listener, peers *sync.Map) {
var conn net.Conn
var err error
var data []byte
conn.Read(buf)
conn.Write([]byte("HTTP/1.0 200 OK\r\nContent-Type: application/json\r\n\r\n"))
var peersList []*Peer
- for _, peer := range *peers {
- peersList = append(peersList, *peer)
- }
+ peers.Range(func(_, peerI interface{}) bool {
+ peersList = append(peersList, *peerI.(**Peer))
+ return true
+ })
data, err = json.Marshal(peersList)
if err != nil {
panic(err)