]> Cypherpunks.ru repositories - govpn.git/commitdiff
Merge branch 'develop' 7.1
authorSergey Matveev <stargrave@stargrave.org>
Tue, 24 Jan 2017 19:34:26 +0000 (22:34 +0300)
committerSergey Matveev <stargrave@stargrave.org>
Tue, 24 Jan 2017 19:34:26 +0000 (22:34 +0300)
52 files changed:
.gitmodules
NEWS [deleted symlink]
NEWS.RU [deleted symlink]
THANKS
VERSION
doc/download.texi
doc/index.texi
doc/installation.texi
doc/integrity.texi
doc/news.ru.texi
doc/news.texi
doc/sources.texi
doc/thanks.texi
src/cypherpunks.ru/govpn/aont/aont_test.go
src/cypherpunks.ru/govpn/aont/oaep.go
src/cypherpunks.ru/govpn/client/client.go [new file with mode: 0644]
src/cypherpunks.ru/govpn/client/proxy.go [moved from src/cypherpunks.ru/govpn/cmd/govpn-client/proxy.go with 61% similarity]
src/cypherpunks.ru/govpn/client/tcp.go [moved from src/cypherpunks.ru/govpn/cmd/govpn-client/tcp.go with 50% similarity]
src/cypherpunks.ru/govpn/client/udp.go [new file with mode: 0644]
src/cypherpunks.ru/govpn/cmd/govpn-client/main.go
src/cypherpunks.ru/govpn/cmd/govpn-client/udp.go [deleted file]
src/cypherpunks.ru/govpn/cmd/govpn-server/common.go
src/cypherpunks.ru/govpn/cmd/govpn-server/conf.go
src/cypherpunks.ru/govpn/cmd/govpn-server/main.go
src/cypherpunks.ru/govpn/cmd/govpn-server/proxy.go
src/cypherpunks.ru/govpn/cmd/govpn-server/tcp.go
src/cypherpunks.ru/govpn/cmd/govpn-server/udp.go
src/cypherpunks.ru/govpn/cmd/govpn-verifier/main.go
src/cypherpunks.ru/govpn/cnw/cnw.go
src/cypherpunks.ru/govpn/cnw/cnw_test.go
src/cypherpunks.ru/govpn/common.go
src/cypherpunks.ru/govpn/conf.go
src/cypherpunks.ru/govpn/egd.go
src/cypherpunks.ru/govpn/encless.go
src/cypherpunks.ru/govpn/encless_test.go
src/cypherpunks.ru/govpn/handshake.go
src/cypherpunks.ru/govpn/handshake_test.go
src/cypherpunks.ru/govpn/identity.go
src/cypherpunks.ru/govpn/logger.go
src/cypherpunks.ru/govpn/peer.go
src/cypherpunks.ru/govpn/peer_test.go
src/cypherpunks.ru/govpn/stats.go
src/cypherpunks.ru/govpn/tap.go
src/cypherpunks.ru/govpn/tap_freebsd.go
src/cypherpunks.ru/govpn/tap_linux.go
src/cypherpunks.ru/govpn/verifier.go
src/github.com/agl/ed25519
src/github.com/go-yaml/yaml [deleted submodule]
src/golang.org/x/crypto
src/gopkg.in/yaml.v2 [new submodule]
utils/makedist.sh
utils/news.sh [new file with mode: 0755]

index 82df1f7e8a594fcda48fccdf6d3c937b356e89fb..c837a039e17a5ea45e75cc416ebcd3cbe97f1dda 100644 (file)
@@ -7,9 +7,10 @@
 [submodule "src/golang.org/x/crypto"]
        path = src/golang.org/x/crypto
        url = https://go.googlesource.com/crypto
-[submodule "src/github.com/go-yaml/yaml"]
-       path = src/github.com/go-yaml/yaml
-       url = https://github.com/go-yaml/yaml.git
 [submodule "src/cypherpunks.ru/balloon"]
        path = src/cypherpunks.ru/balloon
        url = git://git.cypherpunks.ru/balloon.git
+[submodule "src/gopkg.in/yaml.v2"]
+       path = src/gopkg.in/yaml.v2
+       url = https://github.com/go-yaml/yaml.git
+       branch = v2
diff --git a/NEWS b/NEWS
deleted file mode 120000 (symlink)
index 8be52e4..0000000
--- a/NEWS
+++ /dev/null
@@ -1 +0,0 @@
-doc/news.texi
\ No newline at end of file
diff --git a/NEWS.RU b/NEWS.RU
deleted file mode 120000 (symlink)
index 85f9daf..0000000
--- a/NEWS.RU
+++ /dev/null
@@ -1 +0,0 @@
-doc/news.ru.texi
\ No newline at end of file
diff --git a/THANKS b/THANKS
index 38cc203cdb77d4fe31e2ef0e983142e8b4dd26e8..a7fe0af928a49fd277d4e7705927aa906c011744 100644 (file)
--- a/THANKS
+++ b/THANKS
@@ -1,7 +1,5 @@
-* Applied Cryptography (https://www.schneier.com/books/applied_cryptography/) (C) 1996 Bruce Schneier.
-* Strong Password-Only Authenticated Key Exchange (http://tnlandforms.us/cns05/speke.pdf) (C) 1996 David P. Jablon.
-* Augmented Encrypted Key Exchange (https://www.cs.columbia.edu/~smb/papers/aeke.pdf): a Password-Based Protocol Secure Against Dictionary Attacks and Password File Compromise (C) Steven M. Belloving, Michael Merrit.
-* Watson Ladd <watsonbladd@gmail.com> for suggestion of Elligator (http://elligator.cr.yp.to/) encoding.
-* Password Hashing Competition for Argon2 (https://password-hashing.net/#argon2).
-* Chaffing and Winnowing: Confidentiality without Encryption (http://people.csail.mit.edu/rivest/chaffing-980701.txt) (C) Ronald L. Rivest
-* Zhuoyun Wei <wzyboy@wzyboy.org> for AUR port maintaining and his documentation related fixes.
+* Watson Ladd <watsonbladd at gmail dot com> for suggestion of Elligator encoding.
+* Zhuoyun Wei <wzyboy at wzyboy dot org> for AUR port maintaining and
+  his documentation related fixes.
+* Bruno Clermont <bruno at robotinfra dot com> for finding serious bugs
+  and code refactoring
diff --git a/VERSION b/VERSION
index 4fedf1d20e15761409d6e4e3bf99c0beb499fdfe..0f0fefae5ac96803e7227191df7a6974709eb45d 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-7.0
+7.1
index 31977c66c2bea397f712c3aabd18b5118f1ad55a..60ac685c47490e505c9cacb845f514dad49ea58d 100644 (file)
@@ -5,9 +5,23 @@ You can obtain releases source code prepared tarballs from the links below
 (or use @url{https://sourceforge.net/projects/govpn/files/, Sourceforge mirror}).
 Do not forget to check tarball @ref{Integrity, integrity}.
 
+Tarballs include all necessary required libraries:
+
+@multitable @columnfractions .40 .20 .40
+@headitem Library @tab Platform @tab Licence
+@item @code{github.com/agl/ed25519} @tab All @tab BSD 3-Clause
+@item @code{github.com/bigeagle/water} @tab GNU/Linux @tab BSD 3-Clause
+@item @code{github.com/go-yaml/yaml} @tab All @tab Apache License 2.0 and MIT
+@item @code{golang.org/x/crypto} @tab All @tab BSD 3-Clause
+@end multitable
+
 @multitable {XXXXX} {XXXX KiB} {link sign} {xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}
 @headitem Version @tab Size @tab Tarball @tab SHA256 checksum
 
+@item @ref{Release 7.0, 7.0} @tab 287 KiB
+@tab @url{download/govpn-7.0.tar.xz, link} @url{download/govpn-7.0.tar.xz.sig, sign}
+@tab @code{DF85E42D F1228E8C FA5D582D AEF90553 23033630 E12B0B26 D7DEFBEB B25DBC4C}
+
 @item @ref{Release 6.0, 6.0} @tab 310 KiB
 @tab @url{download/govpn-6.0.tar.xz, link} @url{download/govpn-6.0.tar.xz.sig, sign}
 @tab @code{3ACAE3B9 884F3260 38FCA9CE 6A309DF6 71BE6386 1FB2058B C79AE7DC 2A1A1811}
index b962eacf8d83d27661cd3e1e4c0a67c00d6e125a..624abba1fc673dcfcf1708086573e5a026f6811f 100644 (file)
@@ -7,7 +7,7 @@ This manual is for GoVPN -- simple free software virtual private network
 daemon, aimed to be reviewable, secure, DPI/censorship-resistant,
 written on Go.
 
-Copyright @copyright{} 2014-2016 @email{stargrave@@stargrave.org, Sergey Matveev}
+Copyright @copyright{} 2014-2017 @email{stargrave@@stargrave.org, Sergey Matveev}
 
 @quotation
 Permission is granted to copy, distribute and/or modify this document
index 1443d7f95c8f752d3fd5e5d57a2b1694f9c956bb..9abc8229d6a215403f6ef11e9d0fe16ce38f4cc8 100644 (file)
@@ -18,17 +18,7 @@ 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): @code{uml-utilities} package in most GNU/Linux distributions.
-
-Included required libraries:
-
-@multitable @columnfractions .40 .20 .40
-@headitem Library @tab Platform @tab Licence
-@item @code{github.com/agl/ed25519} @tab All @tab BSD 3-Clause
-@item @code{github.com/bigeagle/water} @tab GNU/Linux @tab BSD 3-Clause
-@item @code{github.com/go-yaml/yaml} @tab All @tab LGPLv3 and MIT
-@item @code{golang.org/x/crypto} @tab All @tab BSD 3-Clause
-@end multitable
+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}.
@@ -43,8 +33,8 @@ binaries will be built in the current directory:
 % make -C govpn-2.3 all
 @end verbatim
 
-There is @code{install} target respecting @env{DESTDIR}. It will
-install binaries, info-documentation and utilities.
+There is @command{install} target respecting @env{DESTDIR}.
+It will install binaries, info-documentation and utilities.
 
 @menu
 * Prepared tarballs: Tarballs.
index b9bc1a1e60910a76ae8675f65e5176ca6e5635b5..5fda02f4ee259939ae6b7bc8f75aba38bc548546 100644 (file)
@@ -1,7 +1,7 @@
 @node Integrity
 @section Tarballs integrity check
 
-You @strong{have to} verify downloaded archives integrity and check
+You @strong{have to} check downloaded archives integrity and verify
 their signature to be sure that you have got trusted, untampered
 software. For integrity and authentication of downloaded binaries
 @url{https://www.gnupg.org/, The GNU Privacy Guard} is used. You must
index 81c3139d90748b163fe4a5e731bf1df1202c0d56..9f7ebf05438a07d4e20052d4e14cc2fdb4a14700 100644 (file)
@@ -1,6 +1,15 @@
 @node Новости
 @section Новости
 
+@node Релиз 7.1
+@subsection Релиз 7.1
+@itemize
+@item Исправлена ошибка в коде генерирования и определения идентификации
+клиента: параллельно работающие клиенты могут быть неправильно
+определены, не давая возможности их подсоединения и позволяя DPI
+выявлять GoVPN пакеты.
+@end itemize
+
 @node Релиз 7.0
 @subsection Релиз 7.0
 @itemize
@@ -75,8 +84,8 @@ up- и down- скрипты через переменные окружения.
 @node Релиз 5.4
 @subsection Релиз 5.4
 @itemize
-@item Добавлена возможность требования @ref{Timesync, синхронизации
-времени}. Она добавит временные метки в PRP аутентификацию сообщений
+@item Добавлена возможность требования синхронизации
+времени. Она добавит временные метки в PRP аутентификацию сообщений
 рукопожатия, не позволяя повторить ранее перехваченные пакеты и получить
 ответ от сервера, делая его видимым для DPI.
 @end itemize
@@ -111,15 +120,15 @@ stderr.
 @subsection Релиз 5.0
 @itemize
 
-@item Новый опциональный @ref{Encless, нешифрованный режим} работы.
+@item Новый опциональный нешифрованный режим работы.
 Технически к исходящим пакетам не применяются функции шифрования,
 поэтому вас не могут вынудить выдать ключи шифрования или привлечь к
 ответственности за использования шифрования.
-@item @ref{MTU} конфигурируются относительно каждого пользователя отдельно.
+@item MTU конфигурируются относительно каждого пользователя отдельно.
 @item Упрощённая схема дополнения полезной нагрузки, экономия в один байт.
 @item Возможность указать название TAP интерфейса явно, без
 использования up-скриптов.
-@item @command{govpn-verifier} утилита теперь может использовать @ref{EGD}.
+@item @command{govpn-verifier} утилита теперь может использовать EGD.
 @end itemize
 
 @node Релиз 4.2
@@ -152,9 +161,9 @@ stderr.
 @node Релиз 3.5
 @subsection Релиз 3.5
 @itemize
-@item Возможность использовать @ref{Network, TCP} сетевой транспорт.
+@item Возможность использовать TCP сетевой транспорт.
 Сервер можно слушать одновременно на UDP и TCP сокетах.
-@item Возможность использовать @ref{Proxy, HTTP прокси} (через CONNECT
+@item Возможность использовать HTTP прокси (через CONNECT
 метод) для доступа к серверу. Сервер может эмулировать поведение HTTP
 прокси.
 @item Обновлённая Poly1305 библиотека с исправлениями для ARM.
@@ -165,7 +174,7 @@ stderr.
 @node Релиз 3.4
 @subsection Релиз 3.4
 @itemize
-@item Возможность использовать внешний @ref{EGD} совместимый PRNG.
+@item Возможность использовать внешний EGD совместимый PRNG.
 Теперь вы можете использовать GoVPN даже на системах с плохим
 @file{/dev/random}.
 @item Опция @option{-noncediff} удалена. Она заменена на хранилище уже
@@ -303,9 +312,3 @@ A-EKE с PBKDF2 верификаторами устойчивы к атакам
 @itemize
 @item Поддержка FreeBSD.
 @end itemize
-
-@node Релиз 1.0
-@subsection Релиз 1.0
-@itemize
-@item Первый стабильный релиз.
-@end itemize
index 5a6db8f5113d93524668df0fae901f1c9ff612d7..21104e0006b478d5f6be8ea13aa67e80bc0ad741 100644 (file)
@@ -3,6 +3,14 @@
 
 See also this page @ref{Новости, on russian}.
 
+@node Release 7.1
+@section Release 7.1
+@itemize
+@item Fixed bug in client's identity generation and detection code:
+simultaneous clients may be incorrectly identified, preventing their
+connection establishing and allowing DPI to detect GoVPN packets.
+@end itemize
+
 @node Release 7.0
 @section Release 7.0
 @itemize
@@ -74,7 +82,7 @@ has some specific issues that caused panics on previous versions.
 @node Release 5.4
 @section Release 5.4
 @itemize
-@item Added optional @ref{Timesync, time synchronization} requirement.
+@item Added optional time synchronization requirement.
 It will add timestamps in handshake PRP authentication, disallowing to
 repeat captured packet and get reply from the server, making it visible
 to DPI.
@@ -107,15 +115,15 @@ with @emph{BLAKE2b} in handshake code.
 @node Release 5.0
 @section Release 5.0
 @itemize
-@item New optional @ref{Encless, encryptionless mode} of operation.
+@item New optional encryptionless mode of operation.
 Technically no encryption functions are applied for outgoing packets, so
 you can not be forced to reveal your encryption keys or sued for
 encryption usage.
-@item @ref{MTU}s are configured on per-user basis.
+@item MTUs are configured on per-user basis.
 @item Simplified payload padding scheme, saving one byte of data.
 @item Ability to specify TAP interface name explicitly without any
 up-scripts for convenience.
-@item @command{govpn-verifier} utility also can use @ref{EGD}.
+@item @command{govpn-verifier} utility also can use EGD.
 @end itemize
 
 @node Release 4.2
@@ -147,9 +155,9 @@ hidden. Now they are indistinguishable from transport messages.
 @node Release 3.5
 @section Release 3.5
 @itemize
-@item Ability to use @ref{Network, TCP} network transport.
+@item Ability to use TCP network transport.
 Server can listen on both UDP and TCP sockets.
-@item Ability to use @ref{Proxy, HTTP proxies} (through CONNECT method)
+@item Ability to use HTTP proxies (through CONNECT method)
 for accessing the server. Server can also emulate HTTP proxy behaviour.
 @item Updated Poly1305 library with ARM-related bugfixes.
 @item Go 1.5+ version is highly recommended because of performance
@@ -159,7 +167,7 @@ reasons.
 @node Release 3.4
 @section Release 3.4
 @itemize
-@item Ability to use external @ref{EGD}-compatible PRNGs. Now you are
+@item Ability to use external EGD-compatible PRNGs. Now you are
 able to use GoVPN even on systems with the bad @file{/dev/random},
 providing higher quality entropy from external sources.
 @item Removed @option{-noncediff} option. It is replaced with in-memory
@@ -298,9 +306,3 @@ consuming and resource heavy computations.
 @itemize
 @item FreeBSD support.
 @end itemize
-
-@node Release 1.0
-@section Release 1.0
-@itemize
-@item Initial stable release.
-@end itemize
index e7a13755b3fc8d9b44911ec4965e651fdbe66428..f3864ef47fef546637e4611d8133c097b0e08331 100644 (file)
@@ -3,8 +3,8 @@
 
 Development source code contains the latest version of the code. It may
 be buggy. It does not contain compiled documentation and dependent
-libraries source code. Because of that, it is not recommended for
-porters: use @ref{Tarballs} instead.
+libraries source code. Because of that, it is recommended for porters
+to use @ref{Tarballs, tarballs} instead.
 
 You can obtain it by cloning @url{http://git-scm.com/, Git}
 @url{http://git.cypherpunks.ru/cgit.cgi/govpn.git/log/, repository}
index 0a6757cf6069dfecaeaaf5987a8586353705313d..b0426dd907695bb41b3e1e8fcec2fc5917433c99 100644 (file)
@@ -4,12 +4,8 @@
 Thanks for contributions and suggestions to:
 
 @itemize
-@item @url{https://www.schneier.com/books/applied_cryptography/, Applied Cryptography} @copyright{} 1996 Bruce Schneier.
-@item @url{http://tnlandforms.us/cns05/speke.pdf, Strong Password-Only Authenticated Key Exchange} @copyright{} 1996 David P. Jablon.
-@item @url{https://www.cs.columbia.edu/~smb/papers/aeke.pdf, Augmented Encrypted Key Exchange}: a Password-Based Protocol Secure Against Dictionary Attacks and Password File Compromise @copyright{} Steven M. Belloving, Michael Merrit.
-@item @email{watsonbladd@@gmail.com, Watson Ladd} for suggestion of @url{http://elligator.cr.yp.to/, Elligator} encoding.
-@item @url{https://password-hashing.net/#argon2, Password Hashing Competition for Argon2}.
-@item @url{https://crypto.stanford.edu/balloon/, Balloon hashing}.
-@item @url{http://people.csail.mit.edu/rivest/chaffing-980701.txt, Chaffing and Winnowing: Confidentiality without Encryption} @copyright{} Ronald L. Rivest
-@item @email{wzyboy@@wzyboy.org, Zhuoyun Wei} for @url{https://aur.archlinux.org/packages/govpn/, AUR} port maintaining and his documentation related fixes.
+@item Watson Ladd for suggestion of @url{http://elligator.cr.yp.to/, Elligator} encoding.
+@item Zhuoyun Wei for @url{https://aur.archlinux.org/packages/govpn/, AUR} port
+maintaining and his documentation related fixes.
+@item Bruno Clermont for finding serious bugs and code refactoring.
 @end itemize
index 0ef140c2c407726531a21b951875a4ab0b2b5aa5..b586775bdd8650cf1e0105b6db58f11a2ca02499 100644 (file)
@@ -1,6 +1,6 @@
 /*
 GoVPN -- simple secure free software virtual private network daemon
-Copyright (C) 2014-2016 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2014-2017 Sergey Matveev <stargrave@stargrave.org>
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -27,7 +27,7 @@ import (
 )
 
 var (
-       testKey *[16]byte = new([16]byte)
+       testKey = new([16]byte)
 )
 
 func init() {
index 4b780ba427ed2e6f87e8d5724ed2488b4f8e8f17..b648ccb7e26695f2fab2581d2844c1684eb034b7 100644 (file)
@@ -1,6 +1,6 @@
 /*
 GoVPN -- simple secure free software virtual private network daemon
-Copyright (C) 2014-2016 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2014-2017 Sergey Matveev <stargrave@stargrave.org>
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -48,7 +48,7 @@ const (
 )
 
 var (
-       dummyNonce *[16]byte = new([16]byte)
+       dummyNonce = new([16]byte)
 )
 
 // Encode the data, produce AONT package. Data size will be larger than
diff --git a/src/cypherpunks.ru/govpn/client/client.go b/src/cypherpunks.ru/govpn/client/client.go
new file mode 100644 (file)
index 0000000..8102cc6
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+GoVPN -- simple secure free software virtual private network daemon
+Copyright (C) 2014-2017 Sergey Matveev <stargrave@stargrave.org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+package client
+
+import (
+       "errors"
+       "fmt"
+       "net"
+       "os"
+       "time"
+
+       "github.com/agl/ed25519"
+
+       "cypherpunks.ru/govpn"
+)
+
+type Protocol int
+
+const (
+       ProtocolUDP Protocol = iota
+       ProtocolTCP
+)
+
+type Configuration struct {
+       PrivateKey          *[ed25519.PrivateKeySize]byte
+       Peer                *govpn.PeerConf
+       Protocol            Protocol
+       InterfaceName       string
+       ProxyAddress        string
+       ProxyAuthentication string
+       RemoteAddress       string
+       UpPath              string
+       DownPath            string
+       StatsAddress        string
+       NoReconnect         bool
+       MTU                 int
+}
+
+func (c *Configuration) Validate() error {
+       if c.MTU > govpn.MTUMax {
+               return fmt.Errorf("Invalid MTU %d, maximum allowable is %d", c.MTU, govpn.MTUMax)
+       }
+       if len(c.RemoteAddress) == 0 {
+               return errors.New("Missing RemoteAddress")
+       }
+       if len(c.InterfaceName) == 0 {
+               return errors.New("Missing InterfaceName")
+       }
+       return nil
+}
+
+func (c *Configuration) isProxy() bool {
+       return len(c.ProxyAddress) > 0
+}
+
+type Client struct {
+       idsCache      *govpn.MACCache
+       tap           *govpn.TAP
+       knownPeers    govpn.KnownPeers
+       statsPort     net.Listener
+       timeouted     chan struct{}
+       rehandshaking chan struct{}
+       termination   chan struct{}
+       firstUpCall   bool
+       termSignal    chan os.Signal
+       config        Configuration
+
+       // Error channel receives any kind of routine errors
+       Error chan error
+}
+
+func (c *Client) MainCycle() {
+       var err error
+       c.tap, err = govpn.TAPListen(c.config.InterfaceName, c.config.MTU)
+       if err != nil {
+               c.Error <- fmt.Errorf("Can not listen on TUN/TAP interface: %s", err.Error())
+               return
+       }
+
+       if len(c.config.StatsAddress) > 0 {
+               c.statsPort, err = net.Listen("tcp", c.config.StatsAddress)
+               if err != nil {
+                       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)
+       }
+
+MainCycle:
+       for {
+               c.timeouted = make(chan struct{})
+               c.rehandshaking = make(chan struct{})
+               c.termination = make(chan struct{})
+               switch c.config.Protocol {
+               case ProtocolUDP:
+                       go c.startUDP()
+               case ProtocolTCP:
+                       if c.config.isProxy() {
+                               go c.proxyTCP()
+                       } else {
+                               go c.startTCP()
+                       }
+               }
+               select {
+               case <-c.termSignal:
+                       govpn.BothPrintf(`[finish remote="%s"]`, c.config.RemoteAddress)
+                       c.termination <- struct{}{}
+                       // empty value signals that everything is fine
+                       c.Error <- nil
+                       break MainCycle
+               case <-c.timeouted:
+                       if c.config.NoReconnect {
+                               break MainCycle
+                       }
+                       govpn.BothPrintf(`[sleep seconds="%d"]`, c.config.Peer.Timeout/time.Second)
+                       time.Sleep(c.config.Peer.Timeout)
+               case <-c.rehandshaking:
+               }
+               close(c.timeouted)
+               close(c.rehandshaking)
+               close(c.termination)
+       }
+       if _, err = govpn.ScriptCall(
+               c.config.DownPath,
+               c.config.InterfaceName,
+               c.config.RemoteAddress,
+       ); err != nil {
+               c.Error <- err
+       }
+}
+
+func NewClient(conf Configuration, verifier *govpn.Verifier, termSignal chan os.Signal) *Client {
+       client := Client{
+               idsCache:    govpn.NewMACCache(),
+               firstUpCall: true,
+               config:      conf,
+               termSignal:  termSignal,
+               Error:       make(chan error, 1),
+       }
+       confs := map[govpn.PeerID]*govpn.PeerConf{*verifier.ID: conf.Peer}
+       client.idsCache.Update(&confs)
+       return &client
+}
similarity index 61%
rename from src/cypherpunks.ru/govpn/cmd/govpn-client/proxy.go
rename to src/cypherpunks.ru/govpn/client/proxy.go
index 0a6729c1dd7ca99ae0ce8f66bc4793ace0bd8a3e..be7d1149fa3e4d44e257a195fe92151c11e8ec8d 100644 (file)
@@ -1,6 +1,6 @@
 /*
 GoVPN -- simple secure free software virtual private network daemon
-Copyright (C) 2014-2016 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2014-2017 Sergey Matveev <stargrave@stargrave.org>
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -16,32 +16,34 @@ You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-package main
+package client
 
 import (
        "bufio"
        "encoding/base64"
-       "log"
+       "fmt"
        "net"
        "net/http"
 
        "cypherpunks.ru/govpn"
 )
 
-func proxyTCP(timeouted, rehandshaking, termination chan struct{}) {
-       proxyAddr, err := net.ResolveTCPAddr("tcp", *proxyAddr)
+func (c *Client) proxyTCP() {
+       proxyAddr, err := net.ResolveTCPAddr("tcp", c.config.ProxyAddress)
        if err != nil {
-               log.Fatalln("Can not resolve proxy address:", err)
+               c.Error <- err
+               return
        }
        conn, err := net.DialTCP("tcp", nil, proxyAddr)
        if err != nil {
-               log.Fatalln("Can not connect to proxy:", err)
+               c.Error <- err
+               return
        }
-       req := "CONNECT " + *remoteAddr + " HTTP/1.1\n"
-       req += "Host: " + *remoteAddr + "\n"
-       if *proxyAuth != "" {
+       req := "CONNECT " + c.config.ProxyAddress + " HTTP/1.1\n"
+       req += "Host: " + c.config.ProxyAddress + "\n"
+       if c.config.ProxyAuthentication != "" {
                req += "Proxy-Authorization: Basic "
-               req += base64.StdEncoding.EncodeToString([]byte(*proxyAuth)) + "\n"
+               req += base64.StdEncoding.EncodeToString([]byte(c.config.ProxyAuthentication)) + "\n"
        }
        req += "\n"
        conn.Write([]byte(req))
@@ -50,8 +52,9 @@ func proxyTCP(timeouted, rehandshaking, termination chan struct{}) {
                &http.Request{Method: "CONNECT"},
        )
        if err != nil || resp.StatusCode != http.StatusOK {
-               log.Fatalln("Unexpected response from proxy")
+               c.Error <- fmt.Errorf("Unexpected response from proxy: %s", err.Error())
+               return
        }
-       govpn.Printf(`[proxy-connected remote="%s" addr="%s"]`, *remoteAddr, *proxyAddr)
-       go handleTCP(conn, timeouted, rehandshaking, termination)
+       govpn.Printf(`[proxy-connected remote="%s" addr="%s"]`, c.config.RemoteAddress, *proxyAddr)
+       go c.handleTCP(conn)
 }
similarity index 50%
rename from src/cypherpunks.ru/govpn/cmd/govpn-client/tcp.go
rename to src/cypherpunks.ru/govpn/client/tcp.go
index 57a412d31d687772c691fa2dc07cb7a65ddf8946..40d81ca818081789c3a9f87ac4e4a2f063c63a76 100644 (file)
@@ -1,6 +1,6 @@
 /*
 GoVPN -- simple secure free software virtual private network daemon
-Copyright (C) 2014-2016 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2014-2017 Sergey Matveev <stargrave@stargrave.org>
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -16,11 +16,11 @@ You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-package main
+package client
 
 import (
        "bytes"
-       "log"
+       "fmt"
        "net"
        "sync/atomic"
        "time"
@@ -28,22 +28,24 @@ import (
        "cypherpunks.ru/govpn"
 )
 
-func startTCP(timeouted, rehandshaking, termination chan struct{}) {
-       remote, err := net.ResolveTCPAddr("tcp", *remoteAddr)
+func (c *Client) startTCP() {
+       remote, err := net.ResolveTCPAddr("tcp", c.config.RemoteAddress)
        if err != nil {
-               log.Fatalln("Can not resolve remote address:", err)
+               c.Error <- fmt.Errorf("Can not resolve remote address: %s", err)
+               return
        }
        conn, err := net.DialTCP("tcp", nil, remote)
        if err != nil {
-               log.Fatalln("Can not connect to address:", err)
+               c.Error <- fmt.Errorf("Can not connect to address: %s", err)
+               return
        }
-       govpn.Printf(`[connected remote="%s"]`, *remoteAddr)
-       handleTCP(conn, timeouted, rehandshaking, termination)
+       govpn.Printf(`[connected remote="%s"]`, c.config.RemoteAddress)
+       c.handleTCP(conn)
 }
 
-func handleTCP(conn *net.TCPConn, timeouted, rehandshaking, termination chan struct{}) {
-       hs := govpn.HandshakeStart(*remoteAddr, conn, conf)
-       buf := make([]byte, 2*(govpn.EnclessEnlargeSize+*mtu)+*mtu)
+func (c *Client) handleTCP(conn *net.TCPConn) {
+       hs := govpn.HandshakeStart(c.config.RemoteAddress, conn, c.config.Peer)
+       buf := make([]byte, 2*(govpn.EnclessEnlargeSize+c.config.MTU)+c.config.MTU)
        var n int
        var err error
        var prev int
@@ -52,27 +54,30 @@ func handleTCP(conn *net.TCPConn, timeouted, rehandshaking, termination chan str
 HandshakeCycle:
        for {
                select {
-               case <-termination:
+               case <-c.termination:
                        break HandshakeCycle
                default:
                }
                if prev == len(buf) {
-                       govpn.Printf(`[packet-timeouted remote="%s"]`, *remoteAddr)
-                       timeouted <- struct{}{}
+                       govpn.Printf(`[packet-timeouted remote="%s"]`, c.config.RemoteAddress)
+                       c.timeouted <- struct{}{}
                        break HandshakeCycle
                }
 
-               conn.SetReadDeadline(time.Now().Add(time.Duration(timeout) * time.Second))
+               if err = conn.SetReadDeadline(time.Now().Add(c.config.Peer.Timeout)); err != nil {
+                       c.Error <- err
+                       break HandshakeCycle
+               }
                n, err = conn.Read(buf[prev:])
                if err != nil {
-                       govpn.Printf(`[connection-timeouted remote="%s"]`, *remoteAddr)
-                       timeouted <- struct{}{}
+                       govpn.Printf(`[connection-timeouted remote="%s"]`, c.config.RemoteAddress)
+                       c.timeouted <- struct{}{}
                        break HandshakeCycle
                }
 
                prev += n
-               peerId := idsCache.Find(buf[:prev])
-               if peerId == nil {
+               peerID := c.idsCache.Find(buf[:prev])
+               if peerID == nil {
                        continue
                }
                peer = hs.Client(buf[:prev])
@@ -80,15 +85,15 @@ HandshakeCycle:
                if peer == nil {
                        continue
                }
-               govpn.Printf(`[handshake-completed remote="%s"]`, *remoteAddr)
-               knownPeers = govpn.KnownPeers(map[string]**govpn.Peer{*remoteAddr: &peer})
-               if firstUpCall {
-                       go govpn.ScriptCall(*upPath, *ifaceName, *remoteAddr)
-                       firstUpCall = false
+               govpn.Printf(`[handshake-completed remote="%s"]`, c.config.RemoteAddress)
+               c.knownPeers = govpn.KnownPeers(map[string]**govpn.Peer{c.config.RemoteAddress: &peer})
+               if c.firstUpCall {
+                       go govpn.ScriptCall(c.config.UpPath, c.config.InterfaceName, c.config.RemoteAddress)
+                       c.firstUpCall = false
                }
                hs.Zero()
                terminator = make(chan struct{})
-               go govpn.PeerTapProcessor(peer, tap, terminator)
+               go govpn.PeerTapProcessor(peer, c.tap, terminator)
                break HandshakeCycle
        }
        if hs != nil {
@@ -103,20 +108,23 @@ HandshakeCycle:
 TransportCycle:
        for {
                select {
-               case <-termination:
+               case <-c.termination:
                        break TransportCycle
                default:
                }
                if prev == len(buf) {
-                       govpn.Printf(`[packet-timeouted remote="%s"]`, *remoteAddr)
-                       timeouted <- struct{}{}
+                       govpn.Printf(`[packet-timeouted remote="%s"]`, c.config.RemoteAddress)
+                       c.timeouted <- struct{}{}
+                       break TransportCycle
+               }
+               if err = conn.SetReadDeadline(time.Now().Add(c.config.Peer.Timeout)); err != nil {
+                       c.Error <- err
                        break TransportCycle
                }
-               conn.SetReadDeadline(time.Now().Add(time.Duration(timeout) * time.Second))
                n, err = conn.Read(buf[prev:])
                if err != nil {
-                       govpn.Printf(`[connection-timeouted remote="%s"]`, *remoteAddr)
-                       timeouted <- struct{}{}
+                       govpn.Printf(`[connection-timeouted remote="%s"]`, c.config.RemoteAddress)
+                       c.timeouted <- struct{}{}
                        break TransportCycle
                }
                prev += n
@@ -128,14 +136,14 @@ TransportCycle:
                if i == -1 {
                        continue
                }
-               if !peer.PktProcess(buf[:i+govpn.NonceSize], tap, false) {
-                       govpn.Printf(`[packet-unauthenticated remote="%s"]`, *remoteAddr)
-                       timeouted <- struct{}{}
+               if !peer.PktProcess(buf[:i+govpn.NonceSize], c.tap, false) {
+                       govpn.Printf(`[packet-unauthenticated remote="%s"]`, c.config.RemoteAddress)
+                       c.timeouted <- struct{}{}
                        break TransportCycle
                }
                if atomic.LoadUint64(&peer.BytesIn)+atomic.LoadUint64(&peer.BytesOut) > govpn.MaxBytesPerKey {
-                       govpn.Printf(`[rehandshake-required remote="%s"]`, *remoteAddr)
-                       rehandshaking <- struct{}{}
+                       govpn.Printf(`[rehandshake-required remote="%s"]`, c.config.RemoteAddress)
+                       c.rehandshaking <- struct{}{}
                        break TransportCycle
                }
                copy(buf, buf[i+govpn.NonceSize:prev])
@@ -146,5 +154,7 @@ TransportCycle:
                terminator <- struct{}{}
        }
        peer.Zero()
-       conn.Close()
+       if err = conn.Close(); err != nil {
+               c.Error <- err
+       }
 }
diff --git a/src/cypherpunks.ru/govpn/client/udp.go b/src/cypherpunks.ru/govpn/client/udp.go
new file mode 100644 (file)
index 0000000..bb7045a
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+GoVPN -- simple secure free software virtual private network daemon
+Copyright (C) 2014-2017 Sergey Matveev <stargrave@stargrave.org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+package client
+
+import (
+       "fmt"
+       "net"
+       "sync/atomic"
+       "time"
+
+       "cypherpunks.ru/govpn"
+)
+
+func (c *Client) startUDP() {
+       remote, err := net.ResolveUDPAddr("udp", c.config.RemoteAddress)
+       if err != nil {
+               c.Error <- fmt.Errorf("Can not resolve remote address: %s", err)
+               return
+       }
+       conn, err := net.DialUDP("udp", nil, remote)
+       if err != nil {
+               c.Error <- fmt.Errorf("Can not connect remote address: %s", err)
+               return
+       }
+       govpn.Printf(`[connected remote="%s"]`, c.config.RemoteAddress)
+
+       hs := govpn.HandshakeStart(c.config.RemoteAddress, conn, c.config.Peer)
+       buf := make([]byte, c.config.MTU*2)
+       var n int
+       var timeouts int
+       var peer *govpn.Peer
+       var terminator chan struct{}
+       timeout := int(c.config.Peer.Timeout.Seconds())
+MainCycle:
+       for {
+               select {
+               case <-c.termination:
+                       break MainCycle
+               default:
+               }
+
+               if err = conn.SetReadDeadline(time.Now().Add(time.Second)); err != nil {
+                       c.Error <- err
+                       break MainCycle
+               }
+               n, err = conn.Read(buf)
+               if timeouts == timeout {
+                       govpn.Printf(`[connection-timeouted remote="%s"]`, c.config.RemoteAddress)
+                       c.timeouted <- struct{}{}
+                       break
+               }
+               if err != nil {
+                       timeouts++
+                       continue
+               }
+               if peer != nil {
+                       if peer.PktProcess(buf[:n], c.tap, true) {
+                               timeouts = 0
+                       } else {
+                               govpn.Printf(`[packet-unauthenticated remote="%s"]`, c.config.RemoteAddress)
+                               timeouts++
+                       }
+                       if atomic.LoadUint64(&peer.BytesIn)+atomic.LoadUint64(&peer.BytesOut) > govpn.MaxBytesPerKey {
+                               govpn.Printf(`[rehandshake-required remote="%s"]`, c.config.RemoteAddress)
+                               c.rehandshaking <- struct{}{}
+                               break MainCycle
+                       }
+                       continue
+               }
+               if c.idsCache.Find(buf[:n]) == nil {
+                       govpn.Printf(`[identity-invalid remote="%s"]`, c.config.RemoteAddress)
+                       continue
+               }
+               timeouts = 0
+               peer = hs.Client(buf[:n])
+               if peer == nil {
+                       continue
+               }
+               govpn.Printf(`[handshake-completed remote="%s"]`, c.config.RemoteAddress)
+               c.knownPeers = govpn.KnownPeers(map[string]**govpn.Peer{c.config.RemoteAddress: &peer})
+               if c.firstUpCall {
+                       go govpn.ScriptCall(c.config.UpPath, c.config.InterfaceName, c.config.RemoteAddress)
+                       c.firstUpCall = false
+               }
+               hs.Zero()
+               terminator = make(chan struct{})
+               go govpn.PeerTapProcessor(peer, c.tap, terminator)
+       }
+       if terminator != nil {
+               terminator <- struct{}{}
+       }
+       if hs != nil {
+               hs.Zero()
+       }
+       if err = conn.Close(); err != nil {
+               c.Error <- err
+       }
+}
index 36ff72a113e6ac0db3e809e90af6954fb57f9f6c..8fcd988ecc8c6d1bb8bf3a688482df4751fa8c28 100644 (file)
@@ -1,6 +1,6 @@
 /*
 GoVPN -- simple secure free software virtual private network daemon
-Copyright (C) 2014-2016 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2014-2017 Sergey Matveev <stargrave@stargrave.org>
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -23,46 +23,41 @@ import (
        "flag"
        "fmt"
        "log"
-       "net"
        "os"
        "os/signal"
        "time"
 
        "cypherpunks.ru/govpn"
-)
-
-var (
-       remoteAddr  = flag.String("remote", "", "Remote server address")
-       proto       = flag.String("proto", "udp", "Protocol to use: udp or tcp")
-       ifaceName   = flag.String("iface", "tap0", "TUN/TAP network interface")
-       verifierRaw = flag.String("verifier", "", "Verifier")
-       keyPath     = flag.String("key", "", "Path to passphrase file")
-       upPath      = flag.String("up", "", "Path to up-script")
-       downPath    = flag.String("down", "", "Path to down-script")
-       stats       = flag.String("stats", "", "Enable stats retrieving on host:port")
-       proxyAddr   = flag.String("proxy", "", "Use HTTP proxy on host:port")
-       proxyAuth   = flag.String("proxy-auth", "", "user:password Basic proxy auth")
-       mtu         = flag.Int("mtu", govpn.MTUDefault, "MTU of TUN/TAP interface")
-       timeoutP    = flag.Int("timeout", 60, "Timeout seconds")
-       timeSync    = flag.Int("timesync", 0, "Time synchronization requirement")
-       noreconnect = flag.Bool("noreconnect", false, "Disable reconnection after timeout")
-       noisy       = flag.Bool("noise", false, "Enable noise appending")
-       encless     = flag.Bool("encless", false, "Encryptionless mode")
-       cpr         = flag.Int("cpr", 0, "Enable constant KiB/sec out traffic rate")
-       egdPath     = flag.String("egd", "", "Optional path to EGD socket")
-       syslog      = flag.Bool("syslog", false, "Enable logging to syslog")
-       version     = flag.Bool("version", false, "Print version information")
-       warranty    = flag.Bool("warranty", false, "Print warranty information")
-
-       conf        *govpn.PeerConf
-       tap         *govpn.TAP
-       timeout     int
-       firstUpCall bool = true
-       knownPeers  govpn.KnownPeers
-       idsCache    *govpn.MACCache
+       "cypherpunks.ru/govpn/client"
 )
 
 func main() {
+       var (
+               remoteAddr  = flag.String("remote", "", "Remote server address")
+               proto       = flag.String("proto", "udp", "Protocol to use: udp or tcp")
+               ifaceName   = flag.String("iface", "tap0", "TUN/TAP network interface")
+               verifierRaw = flag.String("verifier", "", "Verifier")
+               keyPath     = flag.String("key", "", "Path to passphrase file")
+               upPath      = flag.String("up", "", "Path to up-script")
+               downPath    = flag.String("down", "", "Path to down-script")
+               stats       = flag.String("stats", "", "Enable stats retrieving on host:port")
+               proxyAddr   = flag.String("proxy", "", "Use HTTP proxy on host:port")
+               proxyAuth   = flag.String("proxy-auth", "", "user:password Basic proxy auth")
+               mtu         = flag.Int("mtu", govpn.MTUDefault, "MTU of TUN/TAP interface")
+               timeoutP    = flag.Int("timeout", 60, "Timeout seconds")
+               timeSync    = flag.Int("timesync", 0, "Time synchronization requirement")
+               noreconnect = flag.Bool("noreconnect", false, "Disable reconnection after timeout")
+               noisy       = flag.Bool("noise", false, "Enable noise appending")
+               encless     = flag.Bool("encless", false, "Encryptionless mode")
+               cpr         = flag.Int("cpr", 0, "Enable constant KiB/sec out traffic rate")
+               egdPath     = flag.String("egd", "", "Optional path to EGD socket")
+               syslog      = flag.Bool("syslog", false, "Enable logging to syslog")
+               version     = flag.Bool("version", false, "Print version information")
+               warranty    = flag.Bool("warranty", false, "Print warranty information")
+               protocol    client.Protocol
+               err         error
+       )
+
        flag.Parse()
        if *warranty {
                fmt.Println(govpn.Warranty)
@@ -72,72 +67,74 @@ func main() {
                fmt.Println(govpn.VersionGet())
                return
        }
-       timeout = *timeoutP
-       var err error
        log.SetFlags(log.Ldate | log.Lmicroseconds | log.Lshortfile)
 
-       if *mtu > govpn.MTUMax {
-               log.Fatalln("Maximum allowable MTU is", govpn.MTUMax)
-       }
        if *egdPath != "" {
                log.Println("Using", *egdPath, "EGD")
                govpn.EGDInit(*egdPath)
        }
 
-       if *proxyAddr != "" {
-               *proto = "tcp"
-       }
-       if !(*proto == "udp" || *proto == "tcp") {
+       switch *proto {
+       case "udp":
+               protocol = client.ProtocolUDP
+       case "tcp":
+               protocol = client.ProtocolTCP
+       default:
                log.Fatalln("Unknown protocol specified")
        }
+
+       if *proxyAddr != "" && protocol == client.ProtocolUDP {
+               log.Fatalln("HTTP proxy is supported only in TCP mode")
+       }
+
        if *verifierRaw == "" {
-               log.Fatalln("No verifier specified")
+               log.Fatalln("-verifier is required")
        }
        verifier, err := govpn.VerifierFromString(*verifierRaw)
        if err != nil {
-               log.Fatalln(err)
+               log.Fatalln("Invalid -verifier:", err)
        }
        key, err := govpn.KeyRead(*keyPath)
        if err != nil {
-               log.Fatalln("Unable to read the key", err)
+               log.Fatalln("Invalid -key:", err)
        }
        priv := verifier.PasswordApply(key)
        if *encless {
-               if *proto != "tcp" {
+               if protocol != client.ProtocolTCP {
                        log.Fatalln("Currently encryptionless mode works only with TCP")
                }
                *noisy = true
        }
-       conf = &govpn.PeerConf{
-               Id:       verifier.Id,
-               Iface:    *ifaceName,
-               MTU:      *mtu,
-               Timeout:  time.Second * time.Duration(timeout),
-               TimeSync: *timeSync,
-               Noise:    *noisy,
-               CPR:      *cpr,
-               Encless:  *encless,
-               Verifier: verifier,
-               DSAPriv:  priv,
+       conf := client.Configuration{
+               PrivateKey: priv,
+               Peer: &govpn.PeerConf{
+                       ID:       verifier.ID,
+                       Iface:    *ifaceName,
+                       MTU:      *mtu,
+                       Timeout:  time.Second * time.Duration(*timeoutP),
+                       TimeSync: *timeSync,
+                       Noise:    *noisy,
+                       CPR:      *cpr,
+                       Encless:  *encless,
+                       Verifier: verifier,
+                       DSAPriv:  priv,
+               },
+               Protocol:            protocol,
+               InterfaceName:       *ifaceName,
+               ProxyAddress:        *proxyAddr,
+               ProxyAuthentication: *proxyAuth,
+               RemoteAddress:       *remoteAddr,
+               UpPath:              *upPath,
+               DownPath:            *downPath,
+               StatsAddress:        *stats,
+               NoReconnect:         *noreconnect,
+               MTU:                 *mtu,
        }
-       idsCache = govpn.NewMACCache()
-       confs := map[govpn.PeerId]*govpn.PeerConf{*verifier.Id: conf}
-       idsCache.Update(&confs)
-       log.Println(govpn.VersionGet())
-
-       tap, err = govpn.TAPListen(*ifaceName, *mtu)
-       if err != nil {
-               log.Fatalln("Can not listen on TUN/TAP interface:", err)
+       if err = conf.Validate(); err != nil {
+               log.Fatalln("Invalid settings:", err)
        }
 
-       if *stats != "" {
-               log.Println("Stats are going to listen on", *stats)
-               statsPort, err := net.Listen("tcp", *stats)
-               if err != nil {
-                       log.Fatalln("Can not listen on stats port:", err)
-               }
-               go govpn.StatsProcessor(statsPort, &knownPeers)
-       }
+       log.Println(govpn.VersionGet())
 
        if *syslog {
                govpn.SyslogEnable()
@@ -145,38 +142,9 @@ func main() {
 
        termSignal := make(chan os.Signal, 1)
        signal.Notify(termSignal, os.Interrupt, os.Kill)
-
-MainCycle:
-       for {
-               timeouted := make(chan struct{})
-               rehandshaking := make(chan struct{})
-               termination := make(chan struct{})
-               switch *proto {
-               case "udp":
-                       go startUDP(timeouted, rehandshaking, termination)
-               case "tcp":
-                       if *proxyAddr != "" {
-                               go proxyTCP(timeouted, rehandshaking, termination)
-                       } else {
-                               go startTCP(timeouted, rehandshaking, termination)
-                       }
-               }
-               select {
-               case <-termSignal:
-                       govpn.BothPrintf(`[finish remote="%s"]`, *remoteAddr)
-                       termination <- struct{}{}
-                       break MainCycle
-               case <-timeouted:
-                       if *noreconnect {
-                               break MainCycle
-                       }
-                       govpn.BothPrintf(`[sleep seconds="%d"]`, timeout)
-                       time.Sleep(time.Second * time.Duration(timeout))
-               case <-rehandshaking:
-               }
-               close(timeouted)
-               close(rehandshaking)
-               close(termination)
+       c := client.NewClient(conf, verifier, termSignal)
+       go c.MainCycle()
+       if err = <-c.Error; err != nil {
+               log.Fatalln(err)
        }
-       govpn.ScriptCall(*downPath, *ifaceName, *remoteAddr)
 }
diff --git a/src/cypherpunks.ru/govpn/cmd/govpn-client/udp.go b/src/cypherpunks.ru/govpn/cmd/govpn-client/udp.go
deleted file mode 100644 (file)
index 96dbfba..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
-GoVPN -- simple secure free software virtual private network daemon
-Copyright (C) 2014-2016 Sergey Matveev <stargrave@stargrave.org>
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-package main
-
-import (
-       "log"
-       "net"
-       "sync/atomic"
-       "time"
-
-       "cypherpunks.ru/govpn"
-)
-
-func startUDP(timeouted, rehandshaking, termination chan struct{}) {
-       remote, err := net.ResolveUDPAddr("udp", *remoteAddr)
-       if err != nil {
-               log.Fatalln("Can not resolve remote address:", err)
-       }
-       conn, err := net.DialUDP("udp", nil, remote)
-       if err != nil {
-               log.Fatalln("Can not listen on UDP:", err)
-       }
-       govpn.Printf(`[connected remote="%s"]`, *remoteAddr)
-
-       hs := govpn.HandshakeStart(*remoteAddr, conn, conf)
-       buf := make([]byte, *mtu*2)
-       var n int
-       var timeouts int
-       var peer *govpn.Peer
-       var terminator chan struct{}
-MainCycle:
-       for {
-               select {
-               case <-termination:
-                       break MainCycle
-               default:
-               }
-
-               conn.SetReadDeadline(time.Now().Add(time.Second))
-               n, err = conn.Read(buf)
-               if timeouts == timeout {
-                       govpn.Printf(`[connection-timeouted remote="%s"]`, *remoteAddr)
-                       timeouted <- struct{}{}
-                       break
-               }
-               if err != nil {
-                       timeouts++
-                       continue
-               }
-               if peer != nil {
-                       if peer.PktProcess(buf[:n], tap, true) {
-                               timeouts = 0
-                       } else {
-                               govpn.Printf(`[packet-unauthenticated remote="%s"]`, *remoteAddr)
-                               timeouts++
-                       }
-                       if atomic.LoadUint64(&peer.BytesIn)+atomic.LoadUint64(&peer.BytesOut) > govpn.MaxBytesPerKey {
-                               govpn.Printf(`[rehandshake-required remote="%s"]`, *remoteAddr)
-                               rehandshaking <- struct{}{}
-                               break MainCycle
-                       }
-                       continue
-               }
-               if idsCache.Find(buf[:n]) == nil {
-                       govpn.Printf(`[identity-invalid remote="%s"]`, *remoteAddr)
-                       continue
-               }
-               timeouts = 0
-               peer = hs.Client(buf[:n])
-               if peer == nil {
-                       continue
-               }
-               govpn.Printf(`[handshake-completed remote="%s"]`, *remoteAddr)
-               knownPeers = govpn.KnownPeers(map[string]**govpn.Peer{*remoteAddr: &peer})
-               if firstUpCall {
-                       go govpn.ScriptCall(*upPath, *ifaceName, *remoteAddr)
-                       firstUpCall = false
-               }
-               hs.Zero()
-               terminator = make(chan struct{})
-               go govpn.PeerTapProcessor(peer, tap, terminator)
-       }
-       if terminator != nil {
-               terminator <- struct{}{}
-       }
-       if hs != nil {
-               hs.Zero()
-       }
-       conn.Close()
-}
index 7c2dd41e7602a42a7225e8fd74331dcc2df0ffaf..f18d34b420c964a644dcbc4ae76170c1672e8800 100644 (file)
@@ -1,6 +1,6 @@
 /*
 GoVPN -- simple secure free software virtual private network daemon
-Copyright (C) 2014-2016 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2014-2017 Sergey Matveev <stargrave@stargrave.org>
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -35,22 +35,27 @@ var (
        handshakes map[string]*govpn.Handshake = make(map[string]*govpn.Handshake)
        hsLock     sync.RWMutex
 
-       peers     map[string]*PeerState = make(map[string]*PeerState)
+       peers     = make(map[string]*PeerState)
        peersLock sync.RWMutex
 
-       peersById     map[govpn.PeerId]string = make(map[govpn.PeerId]string)
-       peersByIdLock sync.RWMutex
+       peersByID     = make(map[govpn.PeerID]string)
+       peersByIDLock sync.RWMutex
 
        knownPeers govpn.KnownPeers
        kpLock     sync.RWMutex
 )
 
-func callUp(peerId *govpn.PeerId, remoteAddr string) (string, error) {
-       ifaceName := confs[*peerId].Iface
-       if confs[*peerId].Up != "" {
-               result, err := govpn.ScriptCall(confs[*peerId].Up, ifaceName, remoteAddr)
+func callUp(peerID *govpn.PeerID, remoteAddr string) (string, error) {
+       ifaceName := confs[*peerID].Iface
+       if confs[*peerID].Up != "" {
+               result, err := govpn.ScriptCall(confs[*peerID].Up, ifaceName, remoteAddr)
                if err != nil {
-                       govpn.Printf(`[script-failed bind="%s" path="%s" err="%s"]`, *bindAddr, confs[*peerId].Up, err)
+                       govpn.Printf(
+                               `[script-failed bind="%s" path="%s" err="%s"]`,
+                               *bindAddr,
+                               confs[*peerID].Up,
+                               err,
+                       )
                        return "", err
                }
                if ifaceName == "" {
@@ -62,7 +67,7 @@ func callUp(peerId *govpn.PeerId, remoteAddr string) (string, error) {
                }
        }
        if ifaceName == "" {
-               govpn.Printf(`[tap-failed bind="%s" peer="%s"]`, *bindAddr, *peerId)
+               govpn.Printf(`[tap-failed bind="%s" peer="%s"]`, *bindAddr, *peerID)
        }
        return ifaceName, nil
 }
index ea61c813f22494be3b469b9736f24c99ef436df6..62eca02437fa6135046345d0aa92c974a39c7e30 100644 (file)
@@ -1,6 +1,6 @@
 /*
 GoVPN -- simple secure free software virtual private network daemon
-Copyright (C) 2014-2016 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2014-2017 Sergey Matveev <stargrave@stargrave.org>
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -24,7 +24,7 @@ import (
        "log"
        "time"
 
-       "github.com/go-yaml/yaml"
+       "gopkg.in/yaml.v2"
 
        "cypherpunks.ru/govpn"
 )
@@ -34,11 +34,11 @@ const (
 )
 
 var (
-       confs    map[govpn.PeerId]*govpn.PeerConf
+       confs    map[govpn.PeerID]*govpn.PeerConf
        idsCache *govpn.MACCache
 )
 
-func confRead() (*map[govpn.PeerId]*govpn.PeerConf, error) {
+func confRead() (*map[govpn.PeerID]*govpn.PeerConf, error) {
        data, err := ioutil.ReadFile(*confPath)
        if err != nil {
                return nil, err
@@ -49,7 +49,7 @@ func confRead() (*map[govpn.PeerId]*govpn.PeerConf, error) {
                return nil, err
        }
 
-       confs := make(map[govpn.PeerId]*govpn.PeerConf, len(*confsRaw))
+       confs := make(map[govpn.PeerID]*govpn.PeerConf, len(*confsRaw))
        for name, pc := range *confsRaw {
                verifier, err := govpn.VerifierFromString(pc.VerifierRaw)
                if err != nil {
@@ -67,7 +67,7 @@ func confRead() (*map[govpn.PeerId]*govpn.PeerConf, error) {
                }
                conf := govpn.PeerConf{
                        Verifier: verifier,
-                       Id:       verifier.Id,
+                       ID:       verifier.ID,
                        Name:     name,
                        Iface:    pc.Iface,
                        MTU:      pc.MTU,
@@ -82,7 +82,7 @@ func confRead() (*map[govpn.PeerId]*govpn.PeerConf, error) {
                        pc.TimeoutInt = govpn.TimeoutDefault
                }
                conf.Timeout = time.Second * time.Duration(pc.TimeoutInt)
-               confs[*verifier.Id] = &conf
+               confs[*verifier.ID] = &conf
        }
        return &confs, nil
 }
index 68a0172f40ca42b2df66fae78a2d414ac4cf45b9..2beb396f6958409a2cf0f27f9e938e6a76558d47 100644 (file)
@@ -1,6 +1,6 @@
 /*
 GoVPN -- simple secure free software virtual private network daemon
-Copyright (C) 2014-2016 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2014-2017 Sergey Matveev <stargrave@stargrave.org>
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -108,7 +108,7 @@ MainCycle:
                        govpn.BothPrintf(`[terminating bind="%s"]`, *bindAddr)
                        for _, ps := range peers {
                                govpn.ScriptCall(
-                                       confs[*ps.peer.Id].Down,
+                                       confs[*ps.peer.ID].Down,
                                        ps.tap.Name,
                                        ps.peer.Addr,
                                )
@@ -125,7 +125,7 @@ MainCycle:
                                }
                        }
                        peersLock.Lock()
-                       peersByIdLock.Lock()
+                       peersByIDLock.Lock()
                        kpLock.Lock()
                        for addr, ps := range peers {
                                ps.peer.BusyR.Lock()
@@ -135,9 +135,9 @@ MainCycle:
                                        govpn.Printf(`[peer-delete bind="%s" peer="%s"]`, *bindAddr, ps.peer)
                                        delete(peers, addr)
                                        delete(knownPeers, addr)
-                                       delete(peersById, *ps.peer.Id)
+                                       delete(peersByID, *ps.peer.ID)
                                        go govpn.ScriptCall(
-                                               confs[*ps.peer.Id].Down,
+                                               confs[*ps.peer.ID].Down,
                                                ps.tap.Name,
                                                ps.peer.Addr,
                                        )
@@ -146,7 +146,7 @@ MainCycle:
                        }
                        hsLock.Unlock()
                        peersLock.Unlock()
-                       peersByIdLock.Unlock()
+                       peersByIDLock.Unlock()
                        kpLock.Unlock()
                }
        }
index 02c1f0f53addb30708cdace82e756c8edc71ed26..87e3455e13b700d5ce288791f83744816e44d368 100644 (file)
@@ -1,6 +1,6 @@
 /*
 GoVPN -- simple secure free software virtual private network daemon
-Copyright (C) 2014-2016 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2014-2017 Sergey Matveev <stargrave@stargrave.org>
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
index bfb4709771e5cdc8680aea9ada107a5bae908c69..c36da3fed3ca02f8610a7ff9040b679f3e4b3981 100644 (file)
@@ -1,6 +1,6 @@
 /*
 GoVPN -- simple secure free software virtual private network daemon
-Copyright (C) 2014-2016 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2014-2017 Sergey Matveev <stargrave@stargrave.org>
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -71,16 +71,16 @@ func handleTCP(conn net.Conn) {
                        break
                }
                prev += n
-               peerId := idsCache.Find(buf[:prev])
-               if peerId == nil {
+               peerID := idsCache.Find(buf[:prev])
+               if peerID == nil {
                        continue
                }
                if hs == nil {
-                       conf = confs[*peerId]
+                       conf = confs[*peerID]
                        if conf == nil {
                                govpn.Printf(
                                        `[conf-get-failed bind="%s" peer="%s"]`,
-                                       *bindAddr, peerId.String(),
+                                       *bindAddr, peerID.String(),
                                )
                                break
                        }
@@ -94,11 +94,11 @@ func handleTCP(conn net.Conn) {
                hs.Zero()
                govpn.Printf(
                        `[handshake-completed bind="%s" addr="%s" peer="%s"]`,
-                       *bindAddr, addr, peerId.String(),
+                       *bindAddr, addr, peerID.String(),
                )
-               peersByIdLock.RLock()
-               addrPrev, exists := peersById[*peer.Id]
-               peersByIdLock.RUnlock()
+               peersByIDLock.RLock()
+               addrPrev, exists := peersByID[*peer.ID]
+               peersByIDLock.RUnlock()
                if exists {
                        peersLock.Lock()
                        peers[addrPrev].terminator <- struct{}{}
@@ -109,22 +109,22 @@ func handleTCP(conn net.Conn) {
                                terminator: make(chan struct{}),
                        }
                        go govpn.PeerTapProcessor(ps.peer, ps.tap, ps.terminator)
-                       peersByIdLock.Lock()
+                       peersByIDLock.Lock()
                        kpLock.Lock()
                        delete(peers, addrPrev)
                        delete(knownPeers, addrPrev)
                        peers[addr] = ps
                        knownPeers[addr] = &peer
-                       peersById[*peer.Id] = addr
+                       peersByID[*peer.ID] = addr
                        peersLock.Unlock()
-                       peersByIdLock.Unlock()
+                       peersByIDLock.Unlock()
                        kpLock.Unlock()
                        govpn.Printf(
                                `[rehandshake-completed bind="%s" peer="%s"]`,
-                               *bindAddr, peerId.String(),
+                               *bindAddr, peerID.String(),
                        )
                } else {
-                       ifaceName, err := callUp(peer.Id, peer.Addr)
+                       ifaceName, err := callUp(peer.ID, peer.Addr)
                        if err != nil {
                                peer = nil
                                break
@@ -133,7 +133,7 @@ func handleTCP(conn net.Conn) {
                        if err != nil {
                                govpn.Printf(
                                        `[tap-failed bind="%s" peer="%s" err="%s"]`,
-                                       *bindAddr, peerId.String(), err,
+                                       *bindAddr, peerID.String(), err,
                                )
                                peer = nil
                                break
@@ -145,15 +145,15 @@ func handleTCP(conn net.Conn) {
                        }
                        go govpn.PeerTapProcessor(ps.peer, ps.tap, ps.terminator)
                        peersLock.Lock()
-                       peersByIdLock.Lock()
+                       peersByIDLock.Lock()
                        kpLock.Lock()
                        peers[addr] = ps
-                       peersById[*peer.Id] = addr
+                       peersByID[*peer.ID] = addr
                        knownPeers[addr] = &peer
                        peersLock.Unlock()
-                       peersByIdLock.Unlock()
+                       peersByIDLock.Unlock()
                        kpLock.Unlock()
-                       govpn.Printf(`[peer-created bind="%s" peer="%s"]`, *bindAddr, peerId.String())
+                       govpn.Printf(`[peer-created bind="%s" peer="%s"]`, *bindAddr, peerID.String())
                }
                break
        }
@@ -188,7 +188,7 @@ func handleTCP(conn net.Conn) {
                if !peer.PktProcess(buf[:i+govpn.NonceSize], tap, false) {
                        govpn.Printf(
                                `[packet-unauthenticated bind="%s" addr="%s" peer="%s"]`,
-                               *bindAddr, addr, peer.Id.String(),
+                               *bindAddr, addr, peer.ID.String(),
                        )
                        break
                }
index 98993d30a18e5204a2f8c733c9cf8ddeea5d07c9..cdcfb56996cc8492106f3f20797f315d8caa70df 100644 (file)
@@ -1,6 +1,6 @@
 /*
 GoVPN -- simple secure free software virtual private network daemon
-Copyright (C) 2014-2016 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2014-2017 Sergey Matveev <stargrave@stargrave.org>
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -36,7 +36,7 @@ func (c UDPSender) Write(data []byte) (int, error) {
 
 var (
        // Buffers for UDP parallel processing
-       udpBufs chan []byte = make(chan []byte, 1<<8)
+       udpBufs = make(chan []byte, 1<<8)
 )
 
 func startUDP() {
@@ -61,8 +61,7 @@ func startUDP() {
                var hs *govpn.Handshake
                var addrPrev string
                var exists bool
-               var peerId *govpn.PeerId
-               var peer *govpn.Peer
+               var peerID *govpn.PeerID
                var conf *govpn.PeerConf
                for {
                        buf = <-udpBufs
@@ -76,29 +75,54 @@ func startUDP() {
                        peersLock.RLock()
                        ps, exists = peers[addr]
                        peersLock.RUnlock()
-                       if !exists {
-                               goto CheckHandshake
+                       if exists {
+                               go func(peer *govpn.Peer, tap *govpn.TAP, buf []byte, n int) {
+                                       peer.PktProcess(buf[:n], tap, true)
+                                       udpBufs <- buf
+                               }(ps.peer, ps.tap, buf, n)
+                               continue
                        }
-                       go func(ps *govpn.Peer, tap *govpn.TAP, buf []byte, n int) {
-                               peer.PktProcess(buf[:n], tap, true)
-                               udpBufs <- buf
-                       }(ps.peer, ps.tap, buf, n)
-                       continue
-               CheckHandshake:
+
                        hsLock.RLock()
                        hs, exists = handshakes[addr]
                        hsLock.RUnlock()
                        if !exists {
-                               goto CheckID
+                               peerID = idsCache.Find(buf[:n])
+                               if peerID == nil {
+                                       govpn.Printf(`[identity-unknown bind="%s" addr="%s"]`, *bindAddr, addr)
+                                       udpBufs <- buf
+                                       continue
+                               }
+                               conf = confs[*peerID]
+                               if conf == nil {
+                                       govpn.Printf(
+                                               `[conf-get-failed bind="%s" peer="%s"]`,
+                                               *bindAddr, peerID.String(),
+                                       )
+                                       udpBufs <- buf
+                                       continue
+                               }
+                               hs := govpn.NewHandshake(
+                                       addr,
+                                       UDPSender{conn: conn, addr: raddr},
+                                       conf,
+                               )
+                               hs.Server(buf[:n])
+                               udpBufs <- buf
+                               hsLock.Lock()
+                               handshakes[addr] = hs
+                               hsLock.Unlock()
+                               continue
                        }
-                       peer = hs.Server(buf[:n])
+
+                       peer := hs.Server(buf[:n])
                        if peer == nil {
-                               goto Finished
+                               udpBufs <- buf
+                               continue
                        }
-
                        govpn.Printf(
                                `[handshake-completed bind="%s" addr="%s" peer="%s"]`,
-                               *bindAddr, addr, peerId.String(),
+                               *bindAddr, addr, peerID.String(),
                        )
                        hs.Zero()
                        hsLock.Lock()
@@ -109,39 +133,39 @@ func startUDP() {
                                udpBufs <- make([]byte, govpn.MTUMax)
                                udpBufs <- make([]byte, govpn.MTUMax)
                        }()
-                       peersByIdLock.RLock()
-                       addrPrev, exists = peersById[*peer.Id]
-                       peersByIdLock.RUnlock()
+                       peersByIDLock.RLock()
+                       addrPrev, exists = peersByID[*peer.ID]
+                       peersByIDLock.RUnlock()
                        if exists {
                                peersLock.Lock()
                                peers[addrPrev].terminator <- struct{}{}
-                               ps = &PeerState{
+                               psNew := &PeerState{
                                        peer:       peer,
                                        tap:        peers[addrPrev].tap,
                                        terminator: make(chan struct{}),
                                }
-                               go func(ps PeerState) {
-                                       govpn.PeerTapProcessor(ps.peer, ps.tap, ps.terminator)
+                               go func(peer *govpn.Peer, tap *govpn.TAP, terminator chan struct{}) {
+                                       govpn.PeerTapProcessor(peer, tap, terminator)
                                        <-udpBufs
                                        <-udpBufs
-                               }(*ps)
-                               peersByIdLock.Lock()
+                               }(psNew.peer, psNew.tap, psNew.terminator)
+                               peersByIDLock.Lock()
                                kpLock.Lock()
                                delete(peers, addrPrev)
                                delete(knownPeers, addrPrev)
-                               peers[addr] = ps
+                               peers[addr] = psNew
                                knownPeers[addr] = &peer
-                               peersById[*peer.Id] = addr
+                               peersByID[*peer.ID] = addr
                                peersLock.Unlock()
-                               peersByIdLock.Unlock()
+                               peersByIDLock.Unlock()
                                kpLock.Unlock()
                                govpn.Printf(
                                        `[rehandshake-completed bind="%s" peer="%s"]`,
-                                       *bindAddr, peer.Id.String(),
+                                       *bindAddr, peer.ID.String(),
                                )
                        } else {
                                go func(addr string, peer *govpn.Peer) {
-                                       ifaceName, err := callUp(peer.Id, peer.Addr)
+                                       ifaceName, err := callUp(peer.ID, peer.Addr)
                                        if err != nil {
                                                return
                                        }
@@ -149,57 +173,32 @@ func startUDP() {
                                        if err != nil {
                                                govpn.Printf(
                                                        `[tap-failed bind="%s" peer="%s" err="%s"]`,
-                                                       *bindAddr, peer.Id.String(), err,
+                                                       *bindAddr, peer.ID.String(), err,
                                                )
                                                return
                                        }
-                                       ps = &PeerState{
+                                       psNew := &PeerState{
                                                peer:       peer,
                                                tap:        tap,
                                                terminator: make(chan struct{}),
                                        }
-                                       go func(ps PeerState) {
-                                               govpn.PeerTapProcessor(ps.peer, ps.tap, ps.terminator)
+                                       go func(peer *govpn.Peer, tap *govpn.TAP, terminator chan struct{}) {
+                                               govpn.PeerTapProcessor(peer, tap, terminator)
                                                <-udpBufs
                                                <-udpBufs
-                                       }(*ps)
+                                       }(psNew.peer, psNew.tap, psNew.terminator)
                                        peersLock.Lock()
-                                       peersByIdLock.Lock()
+                                       peersByIDLock.Lock()
                                        kpLock.Lock()
-                                       peers[addr] = ps
+                                       peers[addr] = psNew
                                        knownPeers[addr] = &peer
-                                       peersById[*peer.Id] = addr
+                                       peersByID[*peer.ID] = addr
                                        peersLock.Unlock()
-                                       peersByIdLock.Unlock()
+                                       peersByIDLock.Unlock()
                                        kpLock.Unlock()
-                                       govpn.Printf(`[peer-created bind="%s" peer="%s"]`, *bindAddr, peer.Id.String())
+                                       govpn.Printf(`[peer-created bind="%s" peer="%s"]`, *bindAddr, peer.ID.String())
                                }(addr, peer)
                        }
-                       goto Finished
-               CheckID:
-                       peerId = idsCache.Find(buf[:n])
-                       if peerId == nil {
-                               govpn.Printf(`[identity-unknown bind="%s" addr="%s"]`, *bindAddr, addr)
-                               goto Finished
-                       }
-                       conf = confs[*peerId]
-                       if conf == nil {
-                               govpn.Printf(
-                                       `[conf-get-failed bind="%s" peer="%s"]`,
-                                       *bindAddr, peerId.String(),
-                               )
-                               goto Finished
-                       }
-                       hs = govpn.NewHandshake(
-                               addr,
-                               UDPSender{conn: conn, addr: raddr},
-                               conf,
-                       )
-                       hs.Server(buf[:n])
-                       hsLock.Lock()
-                       handshakes[addr] = hs
-                       hsLock.Unlock()
-               Finished:
                        udpBufs <- buf
                }
        }()
index a83f9d15f18f75ea73a0951fd119db26940ba9df..aac36bafb664d5bce876f60bd25a9d105eaa216e 100644 (file)
@@ -1,6 +1,6 @@
 /*
 GoVPN -- simple secure free software virtual private network daemon
-Copyright (C) 2014-2016 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2014-2017 Sergey Matveev <stargrave@stargrave.org>
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -62,7 +62,7 @@ func main() {
                if _, err = io.ReadFull(govpn.Rand, id[:]); err != nil {
                        log.Fatalln(err)
                }
-               pid := govpn.PeerId(*id)
+               pid := govpn.PeerID(*id)
                v := govpn.VerifierNew(*sOpt, *tOpt, *pOpt, &pid)
                v.PasswordApply(key)
                fmt.Println(v.LongForm())
index c5d41a635afb3440558f19b3c351ccc1035a0229..eaf0958b1cbdbc7d17fd213fd3abde1c81363c02 100644 (file)
@@ -1,6 +1,6 @@
 /*
 GoVPN -- simple secure free software virtual private network daemon
-Copyright (C) 2014-2016 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2014-2017 Sergey Matveev <stargrave@stargrave.org>
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
index cbb28e98efa1d325c2222ed47b64280ef2881aa1..29e408f42405a6a0936b4e70f4c3bd84057e52f4 100644 (file)
@@ -1,6 +1,6 @@
 /*
 GoVPN -- simple secure free software virtual private network daemon
-Copyright (C) 2014-2016 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2014-2017 Sergey Matveev <stargrave@stargrave.org>
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -28,7 +28,7 @@ import (
 )
 
 var (
-       testKey *[32]byte = new([32]byte)
+       testKey = new([32]byte)
 )
 
 func init() {
index 98137c1c3bc4e5e91744c1c8fb22b87c12afb613..030794c726a5d13ba47a97d286ef237c4262519e 100644 (file)
@@ -1,6 +1,6 @@
 /*
 GoVPN -- simple secure free software virtual private network daemon
-Copyright (C) 2014-2016 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2014-2017 Sergey Matveev <stargrave@stargrave.org>
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
index c8232d64b047a91644b47111b8cf6db8384613b0..7a9c4b8ce6ba00da4c9bad96e84eeeac10b17ee7 100644 (file)
@@ -1,6 +1,6 @@
 /*
 GoVPN -- simple secure free software virtual private network daemon
-Copyright (C) 2014-2016 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2014-2017 Sergey Matveev <stargrave@stargrave.org>
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -25,7 +25,7 @@ import (
 )
 
 type PeerConf struct {
-       Id          *PeerId       `yaml:"-"`
+       ID          *PeerID       `yaml:"-"`
        Name        string        `yaml:"name"`
        Iface       string        `yaml:"iface"`
        MTU         int           `yaml:"mtu"`
index 3d0b7918b26044353c83a408fbdb1b7d4c0750a8..f54c1168d11e0ce4287090e0079678414443316a 100644 (file)
@@ -1,6 +1,6 @@
 /*
 GoVPN -- simple secure free software virtual private network daemon
-Copyright (C) 2014-2016 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2014-2017 Sergey Matveev <stargrave@stargrave.org>
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -25,7 +25,7 @@ import (
 )
 
 var (
-       Rand io.Reader = rand.Reader
+       Rand = rand.Reader
 )
 
 type EGDRand string
index bd42f1d5729349e1a4c3bf6fe2bb813445ee6249..966a2dde65aac3498de3dddcebd5c8f5b1f7d9fe 100644 (file)
@@ -1,6 +1,6 @@
 /*
 GoVPN -- simple secure free software virtual private network daemon
-Copyright (C) 2014-2016 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2014-2017 Sergey Matveev <stargrave@stargrave.org>
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
index fc00d2708d753735bb501e3886c1ee8d4df1cde5..e0c78c4bc6655353150a4b198fb86718850f239c 100644 (file)
@@ -1,6 +1,6 @@
 /*
 GoVPN -- simple secure free software virtual private network daemon
-Copyright (C) 2014-2016 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2014-2017 Sergey Matveev <stargrave@stargrave.org>
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -27,7 +27,7 @@ import (
 )
 
 var (
-       testKey *[32]byte = new([32]byte)
+       testKey = new([32]byte)
 )
 
 func init() {
index a3ef2b5cf536397c176678d38c8fcd4fff70d1d8..a824acef902629fcb16515eb8011f6294e00519f 100644 (file)
@@ -1,6 +1,6 @@
 /*
 GoVPN -- simple secure free software virtual private network daemon
-Copyright (C) 2014-2016 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2014-2017 Sergey Matveev <stargrave@stargrave.org>
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -132,7 +132,7 @@ func NewHandshake(addr string, conn io.Writer, conf *PeerConf) *Handshake {
 }
 
 // Generate ID tag from client identification and data.
-func idTag(id *PeerId, timeSync int, data []byte) []byte {
+func idTag(id *PeerID, timeSync int, data []byte) []byte {
        enc := make([]byte, 8)
        copy(enc, data)
        AddTimeSync(timeSync, enc)
@@ -141,13 +141,13 @@ func idTag(id *PeerId, timeSync int, data []byte) []byte {
                panic(err)
        }
        mac.Write(enc)
-       mac.Sum(enc[:0])
-       return enc
+       sum := mac.Sum(nil)
+       return sum[len(sum)-8:]
 }
 
 // Start handshake's procedure from the client. It is the entry point
-// for starting the handshake procedure. // First handshake packet
-// will be sent immediately.
+// for starting the handshake procedure.
+// First handshake packet will be sent immediately.
 func HandshakeStart(addr string, conn io.Writer, conf *PeerConf) *Handshake {
        state := NewHandshake(addr, conn, conf)
        var dhPubRepr *[32]byte
@@ -174,7 +174,7 @@ func HandshakeStart(addr string, conn io.Writer, conf *PeerConf) *Handshake {
                chacha20.XORKeyStream(enc, enc, state.rNonce, state.dsaPubH)
        }
        data := append(state.rNonce[8:], enc...)
-       data = append(data, idTag(state.Conf.Id, state.Conf.TimeSync, state.rNonce[8:])...)
+       data = append(data, idTag(state.Conf.ID, state.Conf.TimeSync, state.rNonce[8:])...)
        state.conn.Write(data)
        return state
 }
@@ -260,7 +260,7 @@ func (h *Handshake) Server(data []byte) *Peer {
 
                // Send that to client
                h.conn.Write(append(encPub, append(
-                       encRs, idTag(h.Conf.Id, h.Conf.TimeSync, encPub)...,
+                       encRs, idTag(h.Conf.ID, h.Conf.TimeSync, encPub)...,
                )...))
                h.LastPing = time.Now()
        } else
@@ -316,7 +316,7 @@ func (h *Handshake) Server(data []byte) *Peer {
                } else {
                        chacha20.XORKeyStream(enc, enc, h.rNonceNext(2), h.key)
                }
-               h.conn.Write(append(enc, idTag(h.Conf.Id, h.Conf.TimeSync, enc)...))
+               h.conn.Write(append(enc, idTag(h.Conf.ID, h.Conf.TimeSync, enc)...))
 
                // Switch peer
                peer := newPeer(
@@ -416,7 +416,7 @@ func (h *Handshake) Client(data []byte) *Peer {
                }
 
                // Send that to server
-               h.conn.Write(append(enc, idTag(h.Conf.Id, h.Conf.TimeSync, enc)...))
+               h.conn.Write(append(enc, idTag(h.Conf.ID, h.Conf.TimeSync, enc)...))
                h.LastPing = time.Now()
        } else
        // ENC(K, R+2, RC) + IDtag
index bbe9841b8e2b8fa14d0087a2f8a49b81d88943d0..077146583c654c5fb726aaab70e03430b14cf104 100644 (file)
@@ -1,6 +1,6 @@
 /*
 GoVPN -- simple secure free software virtual private network daemon
-Copyright (C) 2014-2016 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2014-2017 Sergey Matveev <stargrave@stargrave.org>
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -24,7 +24,7 @@ import (
 
 func TestHandshakeSymmetric(t *testing.T) {
        // initial values are taken from peer_test.go's init()
-       v := VerifierNew(1<<10, 1<<4, 1, &testPeerId)
+       v := VerifierNew(1<<10, 1<<4, 1, &testPeerID)
        testConf.Verifier = v
        testConf.DSAPriv = v.PasswordApply("does not matter")
        hsS := NewHandshake("server", Dummy{&testCt}, testConf)
@@ -41,7 +41,7 @@ func TestHandshakeSymmetric(t *testing.T) {
 
 func TestHandshakeNoiseSymmetric(t *testing.T) {
        // initial values are taken from peer_test.go's init()
-       v := VerifierNew(1<<10, 1<<4, 1, &testPeerId)
+       v := VerifierNew(1<<10, 1<<4, 1, &testPeerID)
        testConf.Verifier = v
        testConf.DSAPriv = v.PasswordApply("does not matter")
        testConf.Noise = true
@@ -59,7 +59,7 @@ func TestHandshakeNoiseSymmetric(t *testing.T) {
 }
 func TestHandshakeEnclessSymmetric(t *testing.T) {
        // initial values are taken from peer_test.go's init()
-       v := VerifierNew(1<<10, 1<<4, 1, &testPeerId)
+       v := VerifierNew(1<<10, 1<<4, 1, &testPeerID)
        testConf.Verifier = v
        testConf.DSAPriv = v.PasswordApply("does not matter")
        testConf.Encless = true
index ece2dfcf0bb2131fd4c4a48c8467d39230728837..262bca658be887c4b779dacef6b503ecbaf66b96 100644 (file)
@@ -1,6 +1,6 @@
 /*
 GoVPN -- simple secure free software virtual private network daemon
-Copyright (C) 2014-2016 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2014-2017 Sergey Matveev <stargrave@stargrave.org>
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -34,13 +34,13 @@ const (
        IDSize = 128 / 8
 )
 
-type PeerId [IDSize]byte
+type PeerID [IDSize]byte
 
-func (id PeerId) String() string {
+func (id PeerID) String() string {
        return base64.RawStdEncoding.EncodeToString(id[:])
 }
 
-func (id PeerId) MarshalJSON() ([]byte, error) {
+func (id PeerID) MarshalJSON() ([]byte, error) {
        return []byte(`"` + id.String() + `"`), nil
 }
 
@@ -51,18 +51,18 @@ type MACAndTimeSync struct {
 }
 
 type MACCache struct {
-       cache map[PeerId]*MACAndTimeSync
+       cache map[PeerID]*MACAndTimeSync
        l     sync.RWMutex
 }
 
 func NewMACCache() *MACCache {
-       return &MACCache{cache: make(map[PeerId]*MACAndTimeSync)}
+       return &MACCache{cache: make(map[PeerID]*MACAndTimeSync)}
 }
 
 // Remove disappeared keys, add missing ones with initialized MACs.
-func (mc *MACCache) Update(peers *map[PeerId]*PeerConf) {
+func (mc *MACCache) Update(peers *map[PeerID]*PeerConf) {
        mc.l.Lock()
-       for pid, _ := range mc.cache {
+       for pid := range mc.cache {
                if _, exists := (*peers)[pid]; !exists {
                        log.Println("Cleaning key:", pid)
                        delete(mc.cache, pid)
@@ -101,11 +101,12 @@ func AddTimeSync(ts int, data []byte) {
 // Try to find peer's identity (that equals to MAC)
 // by taking first blocksize sized bytes from data at the beginning
 // as plaintext and last bytes as cyphertext.
-func (mc *MACCache) Find(data []byte) *PeerId {
+func (mc *MACCache) Find(data []byte) *PeerID {
        if len(data) < 8*2 {
                return nil
        }
        buf := make([]byte, 8)
+       sum := make([]byte, 32)
        mc.l.RLock()
        for pid, mt := range mc.cache {
                copy(buf, data)
@@ -113,10 +114,10 @@ func (mc *MACCache) Find(data []byte) *PeerId {
                mt.l.Lock()
                mt.mac.Reset()
                mt.mac.Write(buf)
-               mt.mac.Sum(buf[:0])
+               mt.mac.Sum(sum[:0])
                mt.l.Unlock()
-               if subtle.ConstantTimeCompare(buf, data[len(data)-8:]) == 1 {
-                       ppid := PeerId(pid)
+               if subtle.ConstantTimeCompare(sum[len(sum)-8:], data[len(data)-8:]) == 1 {
+                       ppid := PeerID(pid)
                        mc.l.RUnlock()
                        return &ppid
                }
index b110ce3e55553fb91c6a8e1d4bbb2fd41f5afadb..48a32356d928b6f07ba461628c868bee90f437d8 100644 (file)
@@ -1,6 +1,6 @@
 /*
 GoVPN -- simple secure free software virtual private network daemon
-Copyright (C) 2014-2016 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2014-2017 Sergey Matveev <stargrave@stargrave.org>
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
index 22c893c80fb51d3bb0bb1affbfa395e32a137257..e43dc9c75c235f54dcf206209e17b62105cde430 100644 (file)
@@ -1,6 +1,6 @@
 /*
 GoVPN -- simple secure free software virtual private network daemon
-Copyright (C) 2014-2016 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2014-2017 Sergey Matveev <stargrave@stargrave.org>
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -56,13 +56,15 @@ func newNonces(key *[32]byte, i uint64) chan *[NonceSize]byte {
        if err != nil {
                panic(err)
        }
+       sum := make([]byte, mac.Size())
        nonces := make(chan *[NonceSize]byte, NonceBucketSize*3)
        go func() {
                for {
                        buf := new([NonceSize]byte)
                        binary.BigEndian.PutUint64(buf[:], i)
                        mac.Write(buf[:])
-                       mac.Sum(buf[:0])
+                       mac.Sum(sum[0:])
+                       copy(buf[:], sum)
                        nonces <- buf
                        mac.Reset()
                        i += 2
@@ -86,7 +88,7 @@ type Peer struct {
 
        // Basic
        Addr string
-       Id   *PeerId
+       ID   *PeerID
        Conn io.Writer `json:"-"`
 
        // Traffic behaviour
@@ -96,7 +98,7 @@ type Peer struct {
        Encless     bool
        MTU         int
 
-       key *[SSize]byte `json:"-"`
+       key *[SSize]byte
 
        // Timers
        Timeout     time.Duration `json:"-"`
@@ -133,7 +135,7 @@ type Peer struct {
 }
 
 func (p *Peer) String() string {
-       return p.Id.String() + ":" + p.Addr
+       return p.ID.String() + ":" + p.Addr
 }
 
 // Zero peer's memory state.
@@ -183,7 +185,7 @@ func newPeer(isClient bool, addr string, conn io.Writer, conf *PeerConf, key *[S
 
        peer := Peer{
                Addr: addr,
-               Id:   conf.Id,
+               ID:   conf.ID,
                Conn: conn,
 
                NoiseEnable: noiseEnable,
index 18bd5feada92d165033b0b8da0336b834f08822d..6c16469f18c008298918d43f34e902fd965dacec 100644 (file)
@@ -1,6 +1,6 @@
 /*
 GoVPN -- simple secure free software virtual private network daemon
-Copyright (C) 2014-2016 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2014-2017 Sergey Matveev <stargrave@stargrave.org>
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -28,7 +28,7 @@ var (
        testPeer   *Peer
        testPt     []byte
        testCt     []byte
-       testPeerId PeerId
+       testPeerID PeerID
        testConf   *PeerConf
 )
 
@@ -45,9 +45,9 @@ func (d Dummy) Write(b []byte) (int, error) {
 
 func init() {
        id := new([IDSize]byte)
-       testPeerId = PeerId(*id)
+       testPeerID = PeerID(*id)
        testConf = &PeerConf{
-               Id:      &testPeerId,
+               ID:      &testPeerID,
                MTU:     MTUDefault,
                Timeout: time.Second * time.Duration(TimeoutDefault),
        }
index 1d956742607071447999665b39bd53a4db1dd2e2..c8ea6223e655912e60e6623344838174a7f6a718 100644 (file)
@@ -1,6 +1,6 @@
 /*
 GoVPN -- simple secure free software virtual private network daemon
-Copyright (C) 2014-2016 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2014-2017 Sergey Matveev <stargrave@stargrave.org>
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
index 9010c55b6c3a89eb0b224298c74c4aa002c5aa0b..faf88ba9f6b9e1db4359ab792fad59ca5acbf5a5 100644 (file)
@@ -1,6 +1,6 @@
 /*
 GoVPN -- simple secure free software virtual private network daemon
-Copyright (C) 2014-2016 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2014-2017 Sergey Matveev <stargrave@stargrave.org>
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
index 157c583c76f1b5ffd28cb0ac1bf8a1c933474465..03d4554fce9a5973744684646a74645c5d09c772 100644 (file)
@@ -2,7 +2,7 @@
 
 /*
 GoVPN -- simple secure free software virtual private network daemon
-Copyright (C) 2014-2016 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2014-2017 Sergey Matveev <stargrave@stargrave.org>
 */
 
 package govpn
index 8c5e883760a2bcafda219acc37a39c1a57b2eacd..388853d817e58ef2d2726fff707636a4828d4b00 100644 (file)
@@ -2,7 +2,7 @@
 
 /*
 GoVPN -- simple secure free software virtual private network daemon
-Copyright (C) 2014-2016 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2014-2017 Sergey Matveev <stargrave@stargrave.org>
 */
 
 package govpn
index 832fafe2dacf4981ee3ffc39e20aa5cde77d3a68..8be6ea7ac62c1f25e1d2222d4176c7465b7b1c71 100644 (file)
@@ -1,6 +1,6 @@
 /*
 GoVPN -- simple secure free software virtual private network daemon
-Copyright (C) 2014-2016 Sergey Matveev <stargrave@stargrave.org>
+Copyright (C) 2014-2017 Sergey Matveev <stargrave@stargrave.org>
 
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -45,14 +45,14 @@ type Verifier struct {
        S   int
        T   int
        P   int
-       Id  *PeerId
+       ID  *PeerID
        Pub *[ed25519.PublicKeySize]byte
 }
 
 // Generate new verifier for given peer, with specified password and
 // hashing parameters.
-func VerifierNew(s, t, p int, id *PeerId) *Verifier {
-       return &Verifier{S: s, T: t, P: p, Id: id}
+func VerifierNew(s, t, p int, id *PeerID) *Verifier {
+       return &Verifier{S: s, T: t, P: p, ID: id}
 }
 
 func blake2bKeyless() hash.Hash {
@@ -66,7 +66,7 @@ func blake2bKeyless() hash.Hash {
 // Apply the password: create Ed25519 keypair based on it, save public
 // key in verifier.
 func (v *Verifier) PasswordApply(password string) *[ed25519.PrivateKeySize]byte {
-       r := balloon.H(blake2bKeyless, []byte(password), v.Id[:], v.S, v.T, v.P)
+       r := balloon.H(blake2bKeyless, []byte(password), v.ID[:], v.S, v.T, v.P)
        defer SliceZero(r)
        src := bytes.NewBuffer(r)
        pub, prv, err := ed25519.GenerateKey(src)
@@ -95,8 +95,8 @@ func VerifierFromString(input string) (*Verifier, error) {
        v := Verifier{S: s, T: t, P: p}
        id := new([IDSize]byte)
        copy(id[:], salt)
-       pid := PeerId(*id)
-       v.Id = &pid
+       pid := PeerID(*id)
+       v.ID = &pid
        if len(ss) == 5 {
                pub, err := base64.RawStdEncoding.DecodeString(ss[4])
                if err != nil {
@@ -113,7 +113,7 @@ func VerifierFromString(input string) (*Verifier, error) {
 func (v *Verifier) ShortForm() string {
        return fmt.Sprintf(
                "$balloon$s=%d,t=%d,p=%d$%s",
-               v.S, v.T, v.P, base64.RawStdEncoding.EncodeToString(v.Id[:]),
+               v.S, v.T, v.P, base64.RawStdEncoding.EncodeToString(v.ID[:]),
        )
 }
 
index 278e1ec8e8a6e017cd07577924d6766039146ced..5312a61534124124185d41f09206b9fef1d88403 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 278e1ec8e8a6e017cd07577924d6766039146ced
+Subproject commit 5312a61534124124185d41f09206b9fef1d88403
diff --git a/src/github.com/go-yaml/yaml b/src/github.com/go-yaml/yaml
deleted file mode 160000 (submodule)
index e4d366f..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit e4d366fc3c7938e2958e662b4258c7a89e1f0e3e
index b2fa06b6af4b7c9bfeb8569ab7b17f04550717bf..41d678d1df78cd0410143162dff954e6dc09300f 160000 (submodule)
@@ -1 +1 @@
-Subproject commit b2fa06b6af4b7c9bfeb8569ab7b17f04550717bf
+Subproject commit 41d678d1df78cd0410143162dff954e6dc09300f
diff --git a/src/gopkg.in/yaml.v2 b/src/gopkg.in/yaml.v2
new file mode 160000 (submodule)
index 0000000..a5b47d3
--- /dev/null
@@ -0,0 +1 @@
+Subproject commit a5b47d31c556af34a302ce5d659e6fea44d90de0
index f890c3a99c0f6e8240e9535b383d938792ffee3e..deff7783b9c02017ea73e84547bfacc5002d987d 100755 (executable)
@@ -10,7 +10,7 @@ repos="
     src/cypherpunks.ru/balloon
     src/github.com/agl/ed25519
     src/github.com/bigeagle/water
-    src/github.com/go-yaml/yaml
+    src/gopkg.in/yaml.v2
     src/golang.org/x/crypto
 "
 for repo in $repos; do
@@ -44,11 +44,13 @@ You can obtain releases source code prepared tarballs on
 @url{http://www.govpn.info/}.
 EOF
 make -C doc
-rm -r doc/.well-known doc/govpn.html/.well-known
+./utils/news.sh
+rm -r doc/.well-known doc/govpn.html/.well-known utils/news.sh
 
 rm utils/makedist.sh
 find . -name .git -type d | xargs rm -fr
 find . -name .gitignore -delete
+rm .gitmodules
 
 cd ..
 tar cvf govpn-"$release".tar govpn-"$release"
@@ -154,7 +156,7 @@ SHA256 хэш: $hash
 Идентификатор GPG ключа: 0xF2F59045FFE2F4A1 GoVPN releases <releases@govpn.info>
 Отпечаток: D269 9B73 3C41 2068 D8DA  656E F2F5 9045 FFE2 F4A1
 
-Пожалуйста все вопросы касающиеся использования GoVPN, отчёты об ошибках
+Пожалуйста, все вопросы касающиеся использования GoVPN, отчёты об ошибках
 и патчи отправляйте в govpn-devel почтовую рассылку:
 https://lists.cypherpunks.ru/pipermail/govpn-devel/
 EOF
diff --git a/utils/news.sh b/utils/news.sh
new file mode 100755 (executable)
index 0000000..9064312
--- /dev/null
@@ -0,0 +1,33 @@
+#!/bin/sh -ex
+
+texi=`mktemp`
+
+cat > $texi <<EOF
+\input texinfo
+@documentencoding UTF-8
+@settitle NEWS
+
+@node News
+@unnumbered News
+
+`sed -n '5,$p' < doc/news.texi`
+
+@bye
+EOF
+makeinfo --plaintext -o NEWS $texi
+
+cat > $texi <<EOF
+\input texinfo
+@documentencoding UTF-8
+@settitle NEWS.RU
+
+@node Новости
+@unnumbered Новости
+
+`sed -n '3,$p' < doc/news.ru.texi | sed 's/^@subsection/@section/'`
+
+@bye
+EOF
+makeinfo --plaintext -o NEWS.RU $texi
+
+rm -f $texi