]> Cypherpunks.ru repositories - govpn.git/commitdiff
Merge branch 'develop' 3.5
authorSergey Matveev <stargrave@stargrave.org>
Sun, 23 Aug 2015 14:43:27 +0000 (17:43 +0300)
committerSergey Matveev <stargrave@stargrave.org>
Sun, 23 Aug 2015 14:43:27 +0000 (17:43 +0300)
Signed-off-by: Sergey Matveev <stargrave@stargrave.org>
46 files changed:
.gitmodules [new file with mode: 0644]
README
VERSION
common.mk
doc/client.texi
doc/cpr.texi
doc/developer.texi
doc/download.texi
doc/egd.texi
doc/example.texi
doc/govpn.texi
doc/identity.texi
doc/installation.texi
doc/keywords.texi [deleted file]
doc/media.texi [new file with mode: 0644]
doc/mtu.texi
doc/netproto.texi [new file with mode: 0644]
doc/news.texi
doc/overview.texi [deleted file]
doc/pake.texi
doc/precautions.texi
doc/proxy.texi [new file with mode: 0644]
doc/server.texi
doc/sources.texi
doc/thanks.texi
doc/timeout.texi
doc/todo.texi
doc/transport.texi
doc/user.texi
src/.gitignore [deleted file]
src/Makefile [deleted file]
src/github.com/agl/ed25519 [new submodule]
src/github.com/bigeagle/water [new submodule]
src/golang.org/x/crypto [new submodule]
src/govpn/cmd/govpn-client/main.go
src/govpn/cmd/govpn-client/proxy.go [new file with mode: 0644]
src/govpn/cmd/govpn-client/tcp.go [new file with mode: 0644]
src/govpn/cmd/govpn-client/udp.go [new file with mode: 0644]
src/govpn/cmd/govpn-server/main.go
src/govpn/cmd/govpn-server/proxy.go [new file with mode: 0644]
src/govpn/cmd/govpn-server/tcp.go [new file with mode: 0644]
src/govpn/cmd/govpn-server/udp.go [new file with mode: 0644]
src/govpn/handshake.go
src/govpn/transport.go
src/govpn/transport_test.go
utils/makedist.sh

diff --git a/.gitmodules b/.gitmodules
new file mode 100644 (file)
index 0000000..f2d6ae4
--- /dev/null
@@ -0,0 +1,9 @@
+[submodule "src/github.com/bigeagle/water"]
+       path = src/github.com/bigeagle/water
+       url = https://github.com/bigeagle/water.git
+[submodule "src/github.com/agl/ed25519"]
+       path = src/github.com/agl/ed25519
+       url = https://github.com/agl/ed25519.git
+[submodule "src/golang.org/x/crypto"]
+       path = src/golang.org/x/crypto
+       url = https://go.googlesource.com/crypto
diff --git a/README b/README
index 7fdd2e87e8c1d227e5a84bad6476aac5cabed460..6173be42fcacc5efa8ff620d25c297b79bd89572 100644 (file)
--- a/README
+++ b/README
@@ -1,11 +1,14 @@
 GoVPN is simple secure free software virtual private network daemon,
-aimed to be reviewable, secure, DPI-resistant, written on Go.
+aimed to be reviewable, secure, DPI/censorship-resistant, written on Go.
 
-It uses fast PAKE DH A-EKE for mutual strong zero-knowledge peers
-authentication. Data transport is encrypted, authenticated, hides
-message's length and timestamp. PFS property, resistance to dictionary
-attacks, replay attacks. Built-in heartbeating, rehandshaking, real-time
-statistics, IPv4/IPv6-compatibility. GNU/Linux and FreeBSD support.
+It uses fast strong password authenticated key agreement protocol with
+augmented mutual peers authentication (PAKE DH A-EKE). Encrypted,
+authenticated data transport that hides message's length and timestamps.
+Perfect forward secrecy property. Resistance to: offline dictionary
+attacks, replay attacks, client's passwords compromising and dictionary
+attacks on the server side. Built-in heartbeating, rehandshaking,
+real-time statistics. Ability to work through UDP, TCP and HTTP proxies.
+IPv4/IPv6-compatibility. GNU/Linux and FreeBSD support.
 
 GoVPN is free software: see the file COPYING for copying conditions.
 
@@ -20,6 +23,6 @@ subscription and archive access information, or send email with the
 subject "subscribe" to govpn-devel-request@lists.cypherpunks.ru.
 
 Development Git source code repository currently is located here:
-https://github.com/stargrave/govpn.git
+http://git.cypherpunks.ru/cgit.cgi/govpn.git/
 
 For futher information please read either doc/govpn.info or doc/govpn.texi.
diff --git a/VERSION b/VERSION
index 2f4b60750dc3500b0e4cf08f316a960a7ca42b40..5a958026daa3208cb329c403433beb56abd5c036 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-3.4
+3.5
index b2f01fe169577de58d7bfeae0ce8ab87d68e3f24..2ae9bb1fe89fff068f08bf8e9f3a7101f889dac8 100644 (file)
--- a/common.mk
+++ b/common.mk
@@ -1,4 +1,4 @@
-LDFLAGS = -X govpn.Version $(VERSION)
+LDFLAGS = -X govpn.Version=$(VERSION)
 PREFIX ?= /usr/local
 BINDIR = $(DESTDIR)$(PREFIX)/bin
 INFODIR = $(DESTDIR)$(PREFIX)/info
@@ -7,20 +7,17 @@ DOCDIR = $(DESTDIR)$(PREFIX)/share/doc/govpn
 
 all: govpn-client govpn-server govpn-verifier
 
-depends:
-       $(MAKE) -C src
-
-govpn-client: depends
+govpn-client:
        GOPATH=$(GOPATH) go build -ldflags "$(LDFLAGS)" govpn/cmd/govpn-client
 
-govpn-server: depends
+govpn-server:
        GOPATH=$(GOPATH) go build -ldflags "$(LDFLAGS)" govpn/cmd/govpn-server
 
-govpn-verifier: depends
+govpn-verifier:
        GOPATH=$(GOPATH) go build -ldflags "$(LDFLAGS)" govpn/cmd/govpn-verifier
 
 bench:
-       cd src/govpn ; GOPATH=$(GOPATH) GOMAXPROC=2 go test -bench .
+       cd src/govpn ; GOPATH=$(GOPATH) go test -bench .
 
 clean:
        rm -f govpn-client govpn-server govpn-verifier
index e2c26fd727b83089a079e0d1afb14b899ce2d18f..ec816c48f72d32fb76d28bca32cb94f05619a557 100644 (file)
@@ -1,11 +1,22 @@
 @node Client part
 @section Client part
 
-Except for common @code{-mtu}, @code{-stats}, @code{-egd} options client
-has the following ones:
+Except for common @code{-mtu}, @code{-stats}, @code{-egd}
+options client has the following ones:
 
 @table @code
 
+@item -proto
+@ref{Network transport} to use. Can be either @emph{udp} or @emph{tcp}.
+
+@item -proxy
+Use specified @emph{host:port} @ref{Proxy} server for accessing remote
+server.
+
+@item -proxy-auth
+Optional @emph{user:password} for HTTP Basic authorization on proxy
+server.
+
 @item -remote
 Address (@code{host:port} format) of remote server we need to connect to.
 
index 88339dbad43dbbbb1e898d7d39c038dc59a52ac4..cd7b48a3f5d0b1bcd384bb484ef4e38512f6f135 100644 (file)
@@ -1,5 +1,5 @@
 @node CPR
-@section CPR
+@section Constant Packet Rate
 
 Constant Packet Rate is used to hide fact of underlying payload packets
 appearance. In this mode daemon inserts necessary dummy packets and
index 5f85e00c4dad1cb6a088238549dc70bb56d531f5..7ccd9270a353fbb1c9dfb46afde4acb120ae7c38 100644 (file)
@@ -1,6 +1,8 @@
 @node Developer manual
 @unnumbered Developer manual
 
+Pay attention how to get @ref{Development source code}.
+
 @table @asis
 @item Nonce and identity encryption
 @url{http://143.53.36.235:8080/tea.htm, XTEA}.
@@ -17,9 +19,10 @@ and @url{http://ed25519.cr.yp.to/, Ed25519}.
 @url{https://en.wikipedia.org/wiki/PBKDF2, PBKDF2} based on
 @url{https://en.wikipedia.org/wiki/SHA-2, SHA-512}.
 @item Packet overhead
-26 bytes per packet.
+26 bytes per packet. Two more bytes in TCP mode.
 @item Handshake overhead
-4 UDP (2 from client, 2 from server) packets, 264 bytes total payload.
+4 UDP (2 from client, 2 from server) packets (round-trips for TCP),
+264 bytes total payload (8 bytes more in TCP mode).
 @item Entropy required
 832 bits in average on client, 832 bits in average on server side per
 handshake.
index 83abb667b808e364500024d78d0e7f24ebb8463b..124ea632da1b5c914cef72f4544648c71f066dfc 100644 (file)
@@ -6,44 +6,46 @@ You can obtain releases source code prepared tarballs from the links below:
 @multitable {XXXXX} {XXXX KiB} {link sign} {xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}
 @headitem Version @tab Size @tab Tarball @tab SHA256 checksum
 
-@item 1.5 @tab 19 KiB
-@tab @url{download/govpn-1.5.tar.xz, link} @url{download/govpn-1.5.tar.xz.sig, sign}
-@tab @code{715b07d4d1ea4396c3e37014ca65ec3768818423521f3c12e7200b6edca48c31}
+@item 3.4 @tab 175 KiB
+@tab @url{download/govpn-3.4.tar.xz, link} @url{download/govpn-3.4.tar.xz.sig, sign}
+@tab @code{266612a7f8faa6ceb2955ed611c0c21872776306f4eaad5b785145bbb0390c82}
 
-@item 2.0 @tab 31 KiB
-@tab @url{download/govpn-2.0.tar.xz, link} @url{download/govpn-2.0.tar.xz.sig, sign}
-@tab @code{d43be1248d6a46ba8ca75be2fdab5e3d8b0660fb9df9b6d87cfa3973722b42be}
+@item 3.3 @tab 175 KiB
+@tab @url{download/govpn-3.3.tar.xz, link} @url{download/govpn-3.3.tar.xz.sig, sign}
+@tab @code{1834a057215324f49d6272b2beb89f1532105156f7e853eae855659992ac0c84}
 
-@item 2.2 @tab 32 KiB
-@tab @url{download/govpn-2.2.tar.xz, link} @url{download/govpn-2.2.tar.xz.sig, sign}
-@tab @code{5745278bce8b9a3bd7ec1636507bbce8c17ba1d79f1568e2f3681b7a90bbe6e1}
+@item 3.2 @tab 174 KiB
+@tab @url{download/govpn-3.2.tar.xz, link} @url{download/govpn-3.2.tar.xz.sig, sign}
+@tab @code{388e98d6adef5ebf3431b0d48419f54d2e2064c657de67e23c669ebcf273126d}
 
-@item 2.3 @tab 34 KiB
-@tab @url{download/govpn-2.3.tar.xz, link} @url{download/govpn-2.3.tar.xz.sig, sign}
-@tab @code{92986ec6d6da107c6cc1143659e5a154cd19b8f2ede5fa7f5ccc4525ae468e97}
+@item 3.1 @tab 54 KiB
+@tab @url{download/govpn-3.1.tar.xz, link} @url{download/govpn-3.1.tar.xz.sig, sign}
+@tab @code{4034a67eb472e33760ed1783ca871f531c3a6be99b9bd6213f4f83c1147c344b}
+
+@item 3.0 @tab 53 KiB
+@tab @url{download/govpn-3.0.tar.xz, link} @url{download/govpn-3.0.tar.xz.sig, sign}
+@tab @code{12579c5c3cccfe73c66b5893335bc70c42d7b13b8e94c7751ec65d421eaff9a5}
 
 @item 2.4 @tab 42 KiB
 @tab @url{download/govpn-2.4.tar.xz, link} @url{download/govpn-2.4.tar.xz.sig, sign}
 @tab @code{df45225bac2384c5eed73c5cdb05dc3581495e08d365317beb03a2487d46b98c}
 
-@item 3.0 @tab 53 KiB
-@tab @url{download/govpn-3.0.tar.xz, link} @url{download/govpn-3.0.tar.xz.sig, sign}
-@tab @code{12579c5c3cccfe73c66b5893335bc70c42d7b13b8e94c7751ec65d421eaff9a5}
+@item 2.3 @tab 34 KiB
+@tab @url{download/govpn-2.3.tar.xz, link} @url{download/govpn-2.3.tar.xz.sig, sign}
+@tab @code{92986ec6d6da107c6cc1143659e5a154cd19b8f2ede5fa7f5ccc4525ae468e97}
 
-@item 3.1 @tab 54 KiB
-@tab @url{download/govpn-3.1.tar.xz, link} @url{download/govpn-3.1.tar.xz.sig, sign}
-@tab @code{4034a67eb472e33760ed1783ca871f531c3a6be99b9bd6213f4f83c1147c344b}
+@item 2.2 @tab 32 KiB
+@tab @url{download/govpn-2.2.tar.xz, link} @url{download/govpn-2.2.tar.xz.sig, sign}
+@tab @code{5745278bce8b9a3bd7ec1636507bbce8c17ba1d79f1568e2f3681b7a90bbe6e1}
 
-@item 3.2 @tab 174 KiB
-@tab @url{download/govpn-3.2.tar.xz, link} @url{download/govpn-3.2.tar.xz.sig, sign}
-@tab @code{388e98d6adef5ebf3431b0d48419f54d2e2064c657de67e23c669ebcf273126d}
+@item 2.0 @tab 31 KiB
+@tab @url{download/govpn-2.0.tar.xz, link} @url{download/govpn-2.0.tar.xz.sig, sign}
+@tab @code{d43be1248d6a46ba8ca75be2fdab5e3d8b0660fb9df9b6d87cfa3973722b42be}
 
-@item 3.3 @tab 175 KiB
-@tab @url{download/govpn-3.3.tar.xz, link} @url{download/govpn-3.3.tar.xz.sig, sign}
-@tab @code{1834a057215324f49d6272b2beb89f1532105156f7e853eae855659992ac0c84}
+@item 1.5 @tab 19 KiB
+@tab @url{download/govpn-1.5.tar.xz, link} @url{download/govpn-1.5.tar.xz.sig, sign}
+@tab @code{715b07d4d1ea4396c3e37014ca65ec3768818423521f3c12e7200b6edca48c31}
 
 @end multitable
 
 Also you can try its @ref{Contacts, .onion} version.
-Sourceforge.net also provides mirror for the files above:
-@url{http://sourceforge.net/projects/govpn/files/}.
index 77d34bf1e1906cf5e618e5047069ee89c6077b6c..62d1d87a2e73c60d6e5085844e7156c07d3981b9 100644 (file)
@@ -1,5 +1,5 @@
 @node EGD
-@section EGD
+@section Entropy Gathering Daemon
 
 Overall security mainly depends on client side:
 @ref{PAKE, good passphrase} and cryprographically good pseudo random
index 129b10f290e7abf3e055307d260054b7a8cc3b11..a2e417394bae8f72f5ff759130d30780626bd64c 100644 (file)
@@ -17,18 +17,11 @@ is 1432.
 @strong{Install}. At first you must @ref{Installation, install} this
 software: download, check the signature, compile.
 
-Do not forget about setting @code{GOMAXPROC} environment variable for
-using more than one CPU on both sides:
-
-@example
-% export GOMAXPROC=4
-@end example
-
 @strong{Prepare the server}. Create the new client, named (for example)
 "Alice":
 
 @example
-% ./utils/newclient.sh Alice
+server% ./utils/newclient.sh Alice
 Place verifier to peers/6d4ac605ce8dc37c2f0bf21cb542a713/verifier
 @end example
 
@@ -38,11 +31,11 @@ Place verifier to peers/6d4ac605ce8dc37c2f0bf21cb542a713/verifier
 identity:
 
 @example
-% ./utils/storekey.sh /tmp/passphrase
+client% ./utils/storekey.sh /tmp/passphrase
 Enter passphrase:[my secure passphrase is here]
-% govpn-verifier -id 6d4ac605ce8dc37c2f0bf21cb542a713 -key /tmp/passphrase
+client% govpn-verifier -id 6d4ac605ce8dc37c2f0bf21cb542a713 -key /tmp/passphrase
 562556cc9ecf0019b4cf45bcdf42706944ae9b3ac7c73ad299d83f2d5a169c55
-% rm /tmp/passphrase
+client% rm /tmp/passphrase
 @end example
 
 "562556cc9ecf0019b4cf45bcdf42706944ae9b3ac7c73ad299d83f2d5a169c55" --
@@ -51,7 +44,7 @@ this is verifier itself.
 @strong{Save verifier on server}.
 
 @example
-% cat > peers/6d4ac605ce8dc37c2f0bf21cb542a713/verifier <<EOF
+server% cat > peers/6d4ac605ce8dc37c2f0bf21cb542a713/verifier <<EOF
 562556cc9ecf0019b4cf45bcdf42706944ae9b3ac7c73ad299d83f2d5a169c55
 EOF
 @end example
index c8fa79c4fa7a05010c2fc1d0502c7112b300fd3d..c4cd8c9a82bae4acdc2007f1e638818f427a5f23 100644 (file)
@@ -5,7 +5,8 @@
 
 @copying
 This manual is for GoVPN -- simple secure free software virtual private
-network (VPN) daemon, written entirely on Go programming language.
+network daemon, aimed to be reviewable, secure, DPI/censorship-resistant,
+written on Go.
 
 Copyright @copyright{} 2014-2015 @email{stargrave@@stargrave.org, Sergey Matveev}
 
@@ -14,7 +15,7 @@ Permission is granted to copy, distribute and/or modify this document
 under the terms of the GNU Free Documentation License, Version 1.3
 or any later version published by the Free Software Foundation;
 with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
-A copy of the license is included below.
+A copy of the license is included in the section entitled "Copying conditions".
 @end quotation
 @end copying
 
@@ -22,18 +23,68 @@ A copy of the license is included below.
 @top GoVPN
 
 GoVPN is simple secure free software virtual private network daemon,
-aimed to be reviewable, secure, DPI-resistant, written on Go.
+aimed to be reviewable, secure and
+@url{https://en.wikipedia.org/wiki/Deep_packet_inspection, DPI}/censorship-resistant.
 
-It uses fast PAKE DH A-EKE for mutual strong zero-knowledge peers
-authentication. Data transport is encrypted, authenticated, hides
-message's length and timestamp. PFS property, resistance to dictionary
-attacks, replay attacks. Built-in heartbeating, rehandshaking, real-time
-statistics, IPv4/IPv6-compatibility. GNU/Linux and FreeBSD support.
+@itemize @bullet
+@item
+Copylefted free software: licensed under
+@url{https://www.gnu.org/licenses/gpl-3.0.html, GPLv3+}.
+@item
+Fast strong @ref{PAKE, password authenticated} augmented key agreement
+(PAKE DH A-EKE) @ref{Handshake protocol, handshake}.
+@item
+Mutual two-side zero-knowledge peers authentication.
+@item
+@ref{Verifier structure, Augmented authentication tokens} resistant to
+offline dictionary attacks. An attacker can not masquerade a client
+even with server password verifiers compromising.
+@item
+Encrypted and authenticated @ref{Transport protocol, payload transport}
+with 128-bit @ref{Developer manual, security margin} state-of-the-art
+cryptography and censorship resistance (indistinguishability from noise).
+@item
+@url{https://en.wikipedia.org/wiki/Forward_secrecy, Perfect forward secrecy}
+property.
+@item
+Replay attack protection (using one-time MACs).
+@item
+Built-in rehandshake (session key rotation) and heartbeat features.
+@item
+Ability to hide payload packets length with the @ref{Noise, noise} data.
+@item
+Ability to hide payload timestamps with @ref{CPR, constant packet rate}
+traffic.
+@item
+Compatible with @url{http://egd.sourceforge.net/, EGD} (entropy
+gathering daemon) PRNGs.
+@item
+Several simultaneous clients support with per-client configuration
+options. Clients have pre-established @ref{Identity, identity} invisible
+for third-parties (they are anonymous).
+@item
+Uses @url{https://en.wikipedia.org/wiki/TAP_(network_driver), TAP}
+underlying network interfaces.
+@item
+Can use @ref{Network transport, UDP and TCP} or HTTP @ref{Proxy, proxies}
+for accessing the server.
+@item
+Fully IPv4 and IPv6 compatible.
+@item
+Optional built-in HTTP-server for retrieving
+@ref{Stats, statistics} information about known connected peers in
+@url{http://json.org/, JSON} format.
+@item
+Written on on @url{http://golang.org/, Go} programming language with
+simple code that can be read and reviewed.
+@item
+@url{https://www.gnu.org/, GNU}/Linux and
+@url{http://www.freebsd.org/, FreeBSD} support.
+@end itemize
 
-@include keywords.texi
+@include media.texi
 
 @menu
-* Overview::
 * News::
 * Installation::
 * Precautions::
@@ -45,7 +96,6 @@ statistics, IPv4/IPv6-compatibility. GNU/Linux and FreeBSD support.
 * TODO::
 @end menu
 
-@include overview.texi
 @include news.texi
 @include installation.texi
 @include precautions.texi
index 3288d2ef55eeae508c4b4bc992bd97b88ac44c84..cb3061f4b0abc11accfed9a1f6e0195990a8ab59 100644 (file)
@@ -4,3 +4,10 @@
 Client's identity is 128-bit string. It is not secret, so can be
 transmitted and stored in the clear. However handshake applies PRP on it
 to make DPI and deanonymization much harder to success.
+
+@example
+% ./utils/newclient.sh doesnotmatter
+Place verifier to peers/6d4ac605ce8dc37c2f0bf21cb542a713/verifier
+@end example
+
+"6d4ac605ce8dc37c2f0bf21cb542a713" is client's identity.
index 3f5bde6eeefa6a0379be8b9d5d396c8c8c08191c..3d496e3ead62c6a7fc6af5bd219463e7002958d7 100644 (file)
@@ -1,10 +1,15 @@
 @node Installation
 @unnumbered Installation
 
-GoVPN is written on @url{http://golang.org/, Go programming language},
+GoVPN is written on Go programming language and you have to install Go
+compiler (1.5+ version is highly recommended): @code{lang/go} port in
+FreeBSD and @code{golang} package in most GNU/Linux distributions.
 @emph{Make} is recommended for convenient building.
-@url{https://www.gnu.org/software/texinfo/, Texinfo}
-is used for building documentation.
+@url{https://www.gnu.org/software/texinfo/, Texinfo} 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:
 
@@ -15,18 +20,10 @@ Included required libraries:
 @item @code{github.com/bigeagle/water} @tab GNU/Linux @tab BSD 3-Clause
 @end multitable
 
-Get the tarball and run @code{make}.
+Get @ref{Prepared tarballs, the tarball}, check its
+@ref{Tarballs integrity check, authenticity} and run @code{make}.
 @emph{govpn-client}, @emph{govpn-server}, @emph{govpn-verifier}
-binaries will be build in the current directory.
-
-As a prerequisite you must install Go compiler and possibly TUN/TAP
-interfaces utilities:
-
-@itemize @bullet
-@item @code{lang/go} port in FreeBSD.
-@item @code{golang} and @code{uml-utilities} packages in GNU/Linux
-distributions.
-@end itemize
+binaries will be built in the current directory:
 
 @example
 % wget http://www.cypherpunks.ru/govpn/download/govpn-2.3.tar.xz
diff --git a/doc/keywords.texi b/doc/keywords.texi
deleted file mode 100644 (file)
index a365ce5..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-Some keywords describing this project: encryption, authentication, key
-exchange, EKE, Diffie-Hellman, DH, DH-EKE, Augmented EKE, A-EKE,
-security, encrypted key exchange, 128-bit margin, DPI, censorship,
-resistance, free software, GPLv3+, reviewability, easy, simple,
-Curve25519, Ed25519, Elligator, SHA-512, Salsa20, Poly1305, AEAD, XTEA,
-PBKDF2, PRP, signatures, asymmetric cryptography, zero-knowledge
-password proof, PAKE, password, passphrase, password authenticated key
-exchange, perfect forward secrecy, PFS, MAC, nonce, verifier,
-rehandshake, heartbeat, replay attack, MiTM, length hiding, timestamps
-hiding, noise, constant traffic, constant packet rate, CPR, EGD,
-entropy, TAP, TAP, VPN, GNU, Linux, FreeBSD, IPv6, dictionary attack,
-mutual authentication, simultaneous clients, JSON, HTTP-server,
-statistics, PRNG, traffic analysis, Go, golang.
diff --git a/doc/media.texi b/doc/media.texi
new file mode 100644 (file)
index 0000000..c69d35a
--- /dev/null
@@ -0,0 +1,7 @@
+In the media:
+
+@itemize @bullet
+@item @url{http://habrahabr.ru/company/ivi/blog/256365/, Реализуем безопасный VPN-протокол} (on russian)
+@item @url{http://habrahabr.ru/company/ivi/blog/257431/, Реализуем ещё более безопасный VPN-протокол} (on russian)
+@item @url{http://www.linuxspace.org/archives/9449, Установка и настройка безопасного VPN-демона GoVPN 3.2} (on russian)
+@end itemize
index e8c5c228c670b9e402f9f4b1a9f32d2696711d4a..ef0db05ebc6343fb7ff403eccf09983ad6afd952 100644 (file)
@@ -1,5 +1,5 @@
 @node MTU
-@section MTU
+@section Maximum Transmission Unit
 
 MTU command line argument is maximum allowable size of outgoing GoVPN's
 packets. It varies and depends on your environment, so probably has to
diff --git a/doc/netproto.texi b/doc/netproto.texi
new file mode 100644 (file)
index 0000000..083e833
--- /dev/null
@@ -0,0 +1,10 @@
+@node Network transport
+@section Network transport
+
+You can use either UDP or TCP underlying network transport protocols.
+
+TCP consumes more traffic: two additional bytes per packet. Also it is
+has more complex and slightly slower code. Moreover because of packet
+loss and TCP reliability it can lead to "meltdown" effect: significant
+performance decrease of underlying TCP connections. So generally TCP is
+not advisable for VPNs, but it can help with some nasty firewalls.
index d3a9ab13a56cb511b7afdea17373fd83efa65282..9eacc0f9129eda41e25616d26437ede13076505a 100644 (file)
@@ -3,6 +3,17 @@
 
 @table @strong
 
+@item Release 3.5
+@itemize @bullet
+@item Ability to use @ref{Network transport, TCP} network transport.
+Server can listen on both UDP and TCP sockets.
+@item Ability to use @ref{Proxy, 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
+reasons.
+@end itemize
+
 @item Release 3.4
 @itemize @bullet
 @item Ability to use external @ref{EGD}-compatible PRNGs. Now you are
diff --git a/doc/overview.texi b/doc/overview.texi
deleted file mode 100644 (file)
index 23ba75d..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-@node Overview
-@unnumbered Overview
-
-GoVPN is simple secure virtual private network daemon, written entirely
-on @url{http://golang.org/, Go programming language}.
-
-Reviewability, high 128-bit security margin and
-@url{https://en.wikipedia.org/wiki/Deep_packet_inspection, DPI}
-censorship resistance in mind in free software solution are the main
-goals for that daemon. Most modern widespread protocols and their
-implementations in software are too complex to be reviewed, analyzed and
-modified.
-
-@ref{Developer manual, State off art cryptography technologies}. Strong
-mutual authenticated key exchange is invulnerable to man-in-the middle
-attachs.
-@url{https://en.wikipedia.org/wiki/Forward_secrecy, Perfect forward secrecy}
-property guarantees that compromising of long-term authentication keys
-does not lead to previously captured traffic decrypting.
-Compromising of peers password files on server side won't allow attacker
-to masquerade as the client, because of asymmetric @strong{verifiers}
-usage, resistant to dictionary attacks. Rehandshaking ensures session
-keys rotation. One-time keys MAC authentication protects against
-@url{https://en.wikipedia.org/wiki/Replay_attack, replay attacks}.
-
-Server can work with several clients simultaneously. Each client is
-@strong{identified} by 128-bit key, that does not leak during handshake
-and each client stays @strong{anonymous} for MiTM and DPI. All settings
-are applied per-peer separately.
-
-Optional ability to hide payload packets lengths by appending
-@strong{noise} to them during transmission. Ability to generate constant
-packet rate traffic (@strong{CPR}) that will hide even the fact of
-packets appearance, their timestamps.
-
-The only platform specific requirement is TAP network interface support.
-API to that kind of device is different, OS dependent and non portable.
-So only a few operating systems is officially supported. Author has no
-proprietary software to work with, so currently there is lack of either
-popular Microsoft Windows or Apple OS X support.
-
-@itemize @bullet
-@item
-Copylefted free software: licensed under
-@url{https://www.gnu.org/licenses/gpl-3.0.html, GPLv3+}
-@item
-Works with @url{https://en.wikipedia.org/wiki/TAP_(network_driver), TAP}
-network interfaces on top of UDP entirely
-@item
-@url{https://www.gnu.org/, GNU}/Linux and
-@url{http://www.freebsd.org/, FreeBSD} support.
-@item IPv6 compatible.
-@item Encrypted and authenticated payload transport.
-@item Relatively fast handshake.
-@item Password-authenticated key exchange.
-@item Server-side password verifiers are secure against dictionary
-attacks.
-@item Attacker can not masquerade a client even with password files
-compromising.
-@item Replay attack protection.
-@item Perfect forward secrecy property.
-@item Mutual two-side authentication.
-@item Zero knowledge authentication.
-@item Built-in rehandshake and heartbeat features.
-@item Several simultaneous clients support.
-@item Per-client configuration options.
-@item Hiding of payload packets length with noise.
-@item Hiding of payload packets timestamps with constant packet rate
-traffic.
-@item Optional built-in HTTP-server for retrieving information about
-known connected peers in @url{http://json.org/, JSON} format.
-@item Compatibility with @url{http://egd.sourceforge.net/, EGD} PRNGs.
-@end itemize
index 535165e463206d8de7eb3b8720164bffcc936b92..e96ad1ae8f9784117e99bee5b2a2b8e314afbc82 100644 (file)
@@ -1,5 +1,5 @@
 @node PAKE
-@section PAKE
+@section Password Authenticated Key Agreement
 
 Previously we used pre-shared high-entropy long-term static key for
 client-server authentication. Is is secure, but not convenient for some
index 0539822893cd83d64bec34431b6c73c588c69438..fad882d6b411e0f2f74d1473888a897ba4b94e69 100644 (file)
@@ -9,7 +9,7 @@ passphrases. Also remember to keep passphrase in temporary file and read
 it securely as described in @ref{Verifier}.
 
 @item
-You must @strong{never} use one key for multiple clients.
+You must @strong{never} use the same key for multiple clients.
 
 @item
 You must use @strong{cryptographically good} pseudo random number
diff --git a/doc/proxy.texi b/doc/proxy.texi
new file mode 100644 (file)
index 0000000..0e99035
--- /dev/null
@@ -0,0 +1,23 @@
+@node Proxy
+@section Proxy
+
+You can proxy your requests through HTTP using CONNECT method. This can
+help if you are only allowed to access outside world through HTTP proxy
+server.
+
+Server has @emph{-proxy} option allowing to listen on specified port and
+accept HTTP request. All of them will be treated as a CONNECT method
+switching to raw TCP mode. You can make POST request and server will
+anyway switch to raw TCP mode. You are not forced to use this option:
+any external HTTP proxy server can be used.
+
+Client has @emph{-proxy} option forcing it to connect to proxy and send
+CONNECT method. Optionally it can be authenticated on it using
+@emph{-proxy-auth} HTTP Basic method.
+
+@example
+% govpn-client [...] -proto tcp \
+    -remote "$REMOTE_ADDR":1194 \
+    -proxy 192.168.55.1:8888 \
+    -proxy-auth mylogin:password
+@end example
index 989a8a8a8f8e17f0964a7e15a36d82aed7d3fa4f..e86d86a3b5155f3f8430553084f61e35b1299683 100644 (file)
@@ -5,10 +5,19 @@ Except for common @code{-mtu}, @code{-stats}, @code{-egd} options server
 has the following ones:
 
 @table @code
+
+@item -proto
+@ref{Network transport} to use. Can be @emph{udp}, @emph{tcp} or @emph{all}.
+
 @item -bind
 Address (@code{host:port} format) we must bind to.
+
 @item -peers
 Path to the directory containing peers information, database.
+
+@item -proxy
+Start trivial HTTP @ref{Proxy} server on specified @emph{host:port}.
+
 @end table
 
 Peers directory must contain subdirectories with the names of client's
index e8b6fed9214d4b21e42074b27a2942d247135444..3b7e02cf613aae84fa5fa9e1ae65252886bd4f3a 100644 (file)
@@ -1,21 +1,28 @@
 @node Development source code
 @section Development source code
 
-Development source 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.
+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{Prepared tarballs} instead.
 
-You can obtain it by cloning Git repository:
-@code{git clone https://github.com/stargrave/govpn.git}.
-@code{src} directory has makefile that will download necessary dependent
-library versions.
+You can obtain it by cloning Git repository and fetching dependent
+libraries source code as git submodules:
+
+@example
+% git clone git://git.cypherpunks.ru/govpn.git govpn
+% cd govpn
+% git checkout develop
+% git submodule update --init
+@end example
 
 Also there is mirror of dependent libraries for safety if their native
 repositories will be unavailable (they are seldom updated):
 
 @multitable @columnfractions .50 .50
 @headitem Software/library @tab Mirror
-@item @code{govpn} @tab @url{git://git.cypherpunks.ru/govpn.git}
+@item @code{govpn} @tab @url{https://github.com/stargrave/govpn.git}
 @item @code{golang.org/x/crypto} @tab @url{git://git.cypherpunks.ru/crypto.git}
 @item @code{github.com/agl/ed25519} @tab @url{git://git.cypherpunks.ru/ed25519.git}
+@item @code{github.com/bigeagle/water} @tab @url{git://git.cypherpunks.ru/water.git}
 @end multitable
index 5d68d1c217af2b4d01ae73a1b19db86e90da6ea2..b50bc9c789daa824648d57efff24ca9d6f662dfb 100644 (file)
@@ -1,6 +1,8 @@
 @node Thanks
 @unnumbered Thanks
 
+Thanks for contributions and suggestions to:
+
 @itemize @bullet
 @item
 @url{https://www.schneier.com/books/applied_cryptography/, Applied Cryptography}
index e750177b3aa4f6c2e61093cffa0f5dffb746891f..0f2e2dbf43257272a35fe387068aca35d38e345d 100644 (file)
@@ -12,3 +12,7 @@ the time, even if there is no traffic in corresponding TAP interfaces.
 @strong{Beware}: this consumes traffic.
 
 Stale peers and handshake states are cleaned up every timeout period.
+
+This applies to TCP connections too: relatively much time can pass until
+we understand that remote TCP peer is suddenly died and did not
+normally terminate connection.
index 93b95f11d10150646a4caaa11cb87b30278be906..f8064cfa8902dc4bb01dd2e4c54f0541e63a49b0 100644 (file)
@@ -4,7 +4,6 @@
 @itemize
 @item Ability to tunnel only specified TCP connections, without full
   featured VPN solution. Similar to ssh -R.
-@item Ability to work over HTTP, WebSockets and something similar.
 @item Ability to noise handshake packets sizes.
 @item Increase performance.
 @item Randomize ports usage.
index cdbe7aecfa47365502a5ffdd0dc811d1c262d90b..51dc9de50a03eb6bae6ab8d228144ea7eca31221 100644 (file)
@@ -2,37 +2,41 @@
 @section Transport protocol
 
 @verbatim
-ENCn(SERIAL) + ENC(KEY, ENCn(SERIAL), DATA_SIZE+DATA+NOISE) +
+[PktLen] + ENCn(SERIAL) + ENC(KEY, ENCn(SERIAL), DATA_SIZE+DATA+NOISE) +
     AUTH(ENCn(SERIAL) + ENC(KEY, ENCn(SERIAL), DATA_SIZE+DATA+NOISE))
 @end verbatim
 
 All transport and handshake messages are indistinguishable from
-pseudo random noise.
+pseudo random noise, except when using TCP connections.
+
+@code{PktLen} is used only with TCP connections. It is big-endian
+@emph{uint16} length of the whole packet (except @code{PktLen} itself).
 
 @code{SERIAL} is message's serial number. Odds are reserved for
-client(→server) messages, evens for server(→client) messages.
+client(->server) messages, evens for server(->client) messages.
 
 @code{ENCn} is XTEA block cipher algorithm used here as PRP (pseudo
-random permutation) to randomize, obfuscate @code{SERIAL}. Plaintext
+random permutation function) to obfuscate @code{SERIAL}. Plaintext
 @code{SERIAL} state is kept in peers internal state, but encrypted
 before transmission. XTEA is compact and fast enough. Salsa20 is PRF
-function and requires much more code to create PRP from it. XTEA's
-encryption key is the first 128-bit of Salsa20's output with established
-common key and zero nonce (message nonces start from 1).
+function and requires much more code to create PRP from it.
+
+XTEA's encryption key is the first 128-bit of Salsa20's output with
+established common key and zero nonce (message nonces start from 1).
+
+@code{ENC} is Salsa20 stream cipher, with established session @code{KEY}
+and obfuscated @code{SERIAL} used as a nonce. First 256 bits of
+Salsa20's output is used as Poly1305 authentication key, next 256 bits
+are ignored. All remaining output is XORed with the data, encrypting it.
 
-Encrypted @code{SERIAL} is used as a nonce for @code{DATA} encryption:
-encryption key is different during each handshake, so (key, nonce) pair
-is always used only once. @code{ENC} is Salsa20 cipher, with established
-session @code{KEY} and encrypted @code{SERIAL} used as a nonce.
-@code{DATA_SIZE} is @emph{uint16} storing length of the @code{DATA}.
+@code{DATA_SIZE} is big-endian @emph{uint16} storing length of the
+@code{DATA}.
 
 @code{NOISE} is optional. It is just some junk data, intended to fill up
 packet to MTU size. This is useful for concealing payload packets length.
 
 @code{AUTH} is Poly1305 authentication function. First 256 bits of
-Salsa20 output are used as a one-time key for @code{AUTH}. Next 256 bits
-of Salsa20 are ignored. All remaining output is XORed with the data,
-encrypting it.
+Salsa20 output are used as a one-time key for @code{AUTH}.
 
 To prevent replay attacks we must remember received @code{SERIAL}s and
 if meet one, then drop it. Basically we could just store latest number
index 3702f8488b7c5a005e7b003cbcb9b466e7b62b93..0d237a0130aeae9b7ec3d6ecea833172c42e663a 100644 (file)
@@ -4,16 +4,22 @@
 Announcements about updates and new releases can be found in @ref{Contacts}.
 
 GoVPN is split into two pieces: client and server. Each of them work on
-top of UDP and TAP virtual network interfaces. GoVPN is just a
+top of UDP/TCP and TAP virtual network interfaces. GoVPN is just a
 tunnelling of Ethernet frames, nothing less, nothing more. All you
 IP-related network management is not touched by VPN at all. You can
 automate it using up and down shell scripts.
 
+What network performance can user expect? For example single
+@emph{Intel i5-2450M 2.5 GHz} core on @emph{FreeBSD 10.2 amd64}
+with @emph{Go 1.5} gives 435 Mbps TCP (over UDP) throughput.
+
 @menu
 * EGD:: Entropy gathering daemon
 * Identity::
 * PAKE:: Password Authenticated Key Agreement
 * Timeout::
+* Network transport::
+* Proxy::
 * MTU:: Maximum Transmission Unit
 * Stats::
 * Noise::
@@ -28,6 +34,8 @@ automate it using up and down shell scripts.
 @include identity.texi
 @include pake.texi
 @include timeout.texi
+@include netproto.texi
+@include proxy.texi
 @include mtu.texi
 @include stats.texi
 @include noise.texi
diff --git a/src/.gitignore b/src/.gitignore
deleted file mode 100644 (file)
index 1fb92d9..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-github.com
-golang.org
diff --git a/src/Makefile b/src/Makefile
deleted file mode 100644 (file)
index 452b23f..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-GIT ?= git
-
-all: golang.org/x/crypto github.com/agl/ed25519 github.com/bigeagle/water
-
-github.com/bigeagle/water:
-       mkdir -p github.com/bigeagle
-       $(GIT) clone https://github.com/bigeagle/water.git github.com/bigeagle/water
-       cd github.com/bigeagle/water && $(GIT) checkout --force 36aebfeb35da4f1f6a975726716c6fc563c5c495
-
-github.com/agl/ed25519:
-       mkdir -p github.com/agl
-       $(GIT) clone https://github.com/agl/ed25519.git github.com/agl/ed25519
-       cd github.com/agl/ed25519 && $(GIT) checkout --force d2b94fd789ea21d12fac1a4443dd3a3f79cda72c
-
-golang.org/x/crypto:
-       mkdir -p golang.org/x
-       $(GIT) clone https://go.googlesource.com/crypto golang.org/x/crypto
-       cd golang.org/x/crypto && $(GIT) checkout --force 24ffb5feb3312a39054178a4b0a4554fc2201248
diff --git a/src/github.com/agl/ed25519 b/src/github.com/agl/ed25519
new file mode 160000 (submodule)
index 0000000..d2b94fd
--- /dev/null
@@ -0,0 +1 @@
+Subproject commit d2b94fd789ea21d12fac1a4443dd3a3f79cda72c
diff --git a/src/github.com/bigeagle/water b/src/github.com/bigeagle/water
new file mode 160000 (submodule)
index 0000000..36aebfe
--- /dev/null
@@ -0,0 +1 @@
+Subproject commit 36aebfeb35da4f1f6a975726716c6fc563c5c495
diff --git a/src/golang.org/x/crypto b/src/golang.org/x/crypto
new file mode 160000 (submodule)
index 0000000..81bf771
--- /dev/null
@@ -0,0 +1 @@
+Subproject commit 81bf7719a6b7ce9b665598222362b50122dfc13b
index 9b6567763ecea2e8f1787c9230f7f712aea0a78a..7f32b6c1a5af998b003c2ad45caef7b97a22d5bb 100644 (file)
@@ -21,6 +21,7 @@ package main
 
 import (
        "flag"
+       "io"
        "log"
        "net"
        "os"
@@ -32,12 +33,15 @@ import (
 
 var (
        remoteAddr = flag.String("remote", "", "Remote server address")
+       proto      = flag.String("proto", "udp", "Protocol to use: udp or tcp")
        ifaceName  = flag.String("iface", "tap0", "TAP network interface")
        IDRaw      = flag.String("id", "", "Client identification")
        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", 1452, "MTU for outgoing packets")
        timeoutP   = flag.Int("timeout", 60, "Timeout seconds")
        noisy      = flag.Bool("noise", false, "Enable noise appending")
@@ -74,17 +78,20 @@ func main() {
        }
        govpn.PeersInitDummy(id, conf)
 
-       bind, err := net.ResolveUDPAddr("udp", "0.0.0.0:0")
-       if err != nil {
-               log.Fatalln("Can not resolve address:", err)
-       }
-       conn, err := net.ListenUDP("udp", bind)
-       if err != nil {
-               log.Fatalln("Can not listen on UDP:", err)
-       }
-       remote, err := net.ResolveUDPAddr("udp", *remoteAddr)
-       if err != nil {
-               log.Fatalln("Can not resolve remote address:", err)
+       var conn io.Writer
+       var sink chan []byte
+       var ready chan struct{}
+       switch *proto {
+       case "udp":
+               conn, sink, ready = startUDP()
+       case "tcp":
+               if *proxyAddr != "" {
+                       conn, sink, ready = proxyTCP()
+               } else {
+                       conn, sink, ready = startTCP()
+               }
+       default:
+               log.Fatalln("Unknown protocol specified")
        }
 
        tap, ethSink, ethReady, _, err := govpn.TAPListen(
@@ -95,17 +102,16 @@ func main() {
        if err != nil {
                log.Fatalln("Can not listen on TAP interface:", err)
        }
-       udpSink, udpBuf, udpReady := govpn.ConnListen(conn)
 
        timeouts := 0
        firstUpCall := true
        var peer *govpn.Peer
        var ethPkt []byte
-       var udpPkt govpn.UDPPkt
-       var udpPktData []byte
-       knownPeers := govpn.KnownPeers(map[string]**govpn.Peer{remote.String(): &peer})
+       var pkt []byte
+       knownPeers := govpn.KnownPeers(map[string]**govpn.Peer{*remoteAddr: &peer})
 
        log.Println(govpn.VersionGet())
+       log.Println("Connected to", *proto, *remoteAddr)
        log.Println("Max MTU on TAP interface:", govpn.TAPMaxMTU())
        if *stats != "" {
                log.Println("Stats are going to listen on", *stats)
@@ -120,14 +126,14 @@ func main() {
        signal.Notify(termSignal, os.Interrupt, os.Kill)
 
        log.Println("Starting handshake")
-       handshake := govpn.HandshakeStart(conf, conn, remote)
+       handshake := govpn.HandshakeStart(*remoteAddr, conn, conf)
 
 MainCycle:
        for {
                if peer != nil && (peer.BytesIn+peer.BytesOut) > govpn.MaxBytesPerKey {
                        peer.Zero()
                        peer = nil
-                       handshake = govpn.HandshakeStart(conf, conn, remote)
+                       handshake = govpn.HandshakeStart(*remoteAddr, conn, conf)
                        log.Println("Rehandshaking")
                }
                select {
@@ -140,30 +146,24 @@ MainCycle:
                                }
                                continue
                        }
-                       peer.EthProcess(ethPkt, conn, ethReady)
-               case udpPkt = <-udpSink:
+                       peer.EthProcess(ethPkt, ethReady)
+               case pkt = <-sink:
                        timeouts++
                        if timeouts >= timeout {
                                break MainCycle
                        }
-                       if udpPkt.Addr == nil {
-                               udpReady <- struct{}{}
+                       if pkt == nil {
+                               ready <- struct{}{}
                                continue
                        }
 
-                       udpPktData = udpBuf[:udpPkt.Size]
                        if peer == nil {
-                               if udpPkt.Addr.String() != remote.String() {
-                                       udpReady <- struct{}{}
-                                       log.Println("Unknown handshake message")
-                                       continue
-                               }
-                               if govpn.IDsCache.Find(udpPktData) == nil {
+                               if govpn.IDsCache.Find(pkt) == nil {
                                        log.Println("Invalid identity in handshake packet")
-                                       udpReady <- struct{}{}
+                                       ready <- struct{}{}
                                        continue
                                }
-                               if p := handshake.Client(conn, udpPktData); p != nil {
+                               if p := handshake.Client(pkt); p != nil {
                                        log.Println("Handshake completed")
                                        if firstUpCall {
                                                go govpn.ScriptCall(*upPath, *ifaceName)
@@ -173,14 +173,14 @@ MainCycle:
                                        handshake.Zero()
                                        handshake = nil
                                }
-                               udpReady <- struct{}{}
+                               ready <- struct{}{}
                                continue
                        }
                        if peer == nil {
-                               udpReady <- struct{}{}
+                               ready <- struct{}{}
                                continue
                        }
-                       if peer.UDPProcess(udpPktData, tap, udpReady) {
+                       if peer.PktProcess(pkt, tap, ready) {
                                timeouts = 0
                        }
                }
diff --git a/src/govpn/cmd/govpn-client/proxy.go b/src/govpn/cmd/govpn-client/proxy.go
new file mode 100644 (file)
index 0000000..678a5ae
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+GoVPN -- simple secure free software virtual private network daemon
+Copyright (C) 2014-2015 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 (
+       "bufio"
+       "encoding/base64"
+       "io"
+       "log"
+       "net"
+       "net/http"
+)
+
+func proxyTCP() (io.Writer, chan []byte, chan struct{}) {
+       proxyAddr, err := net.ResolveTCPAddr("tcp", *proxyAddr)
+       if err != nil {
+               log.Fatalln("Can not resolve proxy address:", err)
+       }
+       conn, err := net.DialTCP("tcp", nil, proxyAddr)
+       if err != nil {
+               log.Fatalln("Can not connect to proxy:", err)
+       }
+       req := "CONNECT " + *remoteAddr + " HTTP/1.1\n"
+       req += "Host: " + *remoteAddr + "\n"
+       if *proxyAuth != "" {
+               req += "Proxy-Authorization: Basic "
+               req += base64.StdEncoding.EncodeToString([]byte(*proxyAuth)) + "\n"
+       }
+       req += "\n"
+       conn.Write([]byte(req))
+       resp, err := http.ReadResponse(
+               bufio.NewReader(conn),
+               &http.Request{Method: "CONNECT"},
+       )
+       if err != nil || resp.StatusCode != http.StatusOK {
+               log.Fatalln("Unexpected response from proxy")
+       }
+       sink := make(chan []byte)
+       ready := make(chan struct{})
+       go handleTCP(conn, sink, ready)
+       go func() { ready <- struct{}{} }()
+       return TCPSender{conn}, sink, ready
+}
diff --git a/src/govpn/cmd/govpn-client/tcp.go b/src/govpn/cmd/govpn-client/tcp.go
new file mode 100644 (file)
index 0000000..373789a
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+GoVPN -- simple secure free software virtual private network daemon
+Copyright (C) 2014-2015 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 (
+       "encoding/binary"
+       "io"
+       "log"
+       "net"
+
+       "govpn"
+)
+
+// TCPSender prepends size prefix to each outgoing packet.
+type TCPSender struct {
+       conn *net.TCPConn
+}
+
+func (c TCPSender) Write(data []byte) (int, error) {
+       size := make([]byte, 2)
+       binary.BigEndian.PutUint16(size, uint16(len(data)))
+       return c.conn.Write(append(size, data...))
+}
+
+func startTCP() (io.Writer, chan []byte, chan struct{}) {
+       remote, err := net.ResolveTCPAddr("tcp", *remoteAddr)
+       if err != nil {
+               log.Fatalln("Can not resolve remote address:", err)
+       }
+       c, err := net.DialTCP("tcp", nil, remote)
+       conn := TCPSender{c}
+       if err != nil {
+               log.Fatalln("Can not connect TCP:", err)
+       }
+       sink := make(chan []byte)
+       ready := make(chan struct{})
+       go handleTCP(c, sink, ready)
+       go func() { ready <- struct{}{} }()
+       return conn, sink, ready
+}
+
+func handleTCP(conn *net.TCPConn, sink chan []byte, ready chan struct{}) {
+       var err error
+       var n int
+       var sizeNbuf int
+       sizeBuf := make([]byte, 2)
+       var sizeNeed uint16
+       var bufN uint16
+       buf := make([]byte, govpn.MTU)
+       for {
+               <-ready
+               if sizeNbuf != 2 {
+                       n, err = conn.Read(sizeBuf[sizeNbuf:2])
+                       if err != nil {
+                               break
+                       }
+                       sizeNbuf += n
+                       if sizeNbuf != 2 {
+                               sink <- nil
+                               continue
+                       }
+                       sizeNeed = binary.BigEndian.Uint16(sizeBuf)
+                       if int(sizeNeed) > govpn.MTU-2 {
+                               log.Println("Invalid TCP size, skipping")
+                               sizeNbuf = 0
+                               sink <- nil
+                               continue
+                       }
+                       bufN = 0
+               }
+       ReadMore:
+               if sizeNeed != bufN {
+                       n, err = conn.Read(buf[bufN:sizeNeed])
+                       if err != nil {
+                               break
+                       }
+                       bufN += uint16(n)
+                       goto ReadMore
+               }
+               sizeNbuf = 0
+               sink <- buf[:sizeNeed]
+       }
+}
diff --git a/src/govpn/cmd/govpn-client/udp.go b/src/govpn/cmd/govpn-client/udp.go
new file mode 100644 (file)
index 0000000..103ed6d
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+GoVPN -- simple secure free software virtual private network daemon
+Copyright (C) 2014-2015 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 (
+       "io"
+       "log"
+       "net"
+       "time"
+
+       "govpn"
+)
+
+func startUDP() (io.Writer, chan []byte, chan struct{}) {
+       remote, err := net.ResolveUDPAddr("udp", *remoteAddr)
+       if err != nil {
+               log.Fatalln("Can not resolve remote address:", err)
+       }
+       c, err := net.DialUDP("udp", nil, remote)
+       conn := io.Writer(c)
+       if err != nil {
+               log.Fatalln("Can not listen on UDP:", err)
+       }
+       sink := make(chan []byte)
+       ready := make(chan struct{})
+       go func() {
+               buf := make([]byte, govpn.MTU)
+               var n int
+               var err error
+               for {
+                       <-ready
+                       c.SetReadDeadline(time.Now().Add(time.Second))
+                       n, err = c.Read(buf)
+                       if err != nil {
+                               sink <- nil
+                               continue
+                       }
+                       sink <- buf[:n]
+               }
+       }()
+       ready <- struct{}{}
+       return conn, sink, ready
+}
index 9fb7ae1edf7d9225c6504ee1d89da65515857f18..37135b9155d09df6314df3db11a7ec1d8ed43602 100644 (file)
@@ -22,6 +22,7 @@ package main
 import (
        "bytes"
        "flag"
+       "io"
        "log"
        "net"
        "os"
@@ -34,12 +35,21 @@ import (
 
 var (
        bindAddr  = flag.String("bind", "[::]:1194", "Bind to address")
+       proto     = flag.String("proto", "udp", "Protocol to use: udp, tcp or all")
        peersPath = flag.String("peers", "peers", "Path to peers keys directory")
        stats     = flag.String("stats", "", "Enable stats retrieving on host:port")
+       proxy     = flag.String("proxy", "", "Enable HTTP proxy on host:port")
        mtu       = flag.Int("mtu", 1452, "MTU for outgoing packets")
        egdPath   = flag.String("egd", "", "Optional path to EGD socket")
 )
 
+type Pkt struct {
+       addr  string
+       conn  io.Writer
+       data  []byte
+       ready chan struct{}
+}
+
 type PeerReadyEvent struct {
        peer  *govpn.Peer
        iface string
@@ -78,8 +88,8 @@ type EthEvent struct {
 func main() {
        flag.Parse()
        timeout := time.Second * time.Duration(govpn.TimeoutDefault)
-       var err error
        log.SetFlags(log.Ldate | log.Lmicroseconds | log.Lshortfile)
+       log.Println(govpn.VersionGet())
 
        govpn.MTU = *mtu
        govpn.PeersInit(*peersPath)
@@ -89,15 +99,18 @@ func main() {
                govpn.EGDInit(*egdPath)
        }
 
-       bind, err := net.ResolveUDPAddr("udp", *bindAddr)
-       if err != nil {
-               log.Fatalln("Can not resolve bind address:", err)
+       sink := make(chan Pkt)
+       switch *proto {
+       case "udp":
+               startUDP(sink)
+       case "tcp":
+               startTCP(sink)
+       case "all":
+               startUDP(sink)
+               startTCP(sink)
+       default:
+               log.Fatalln("Unknown protocol specified")
        }
-       conn, err := net.ListenUDP("udp", bind)
-       if err != nil {
-               log.Fatalln("Can listen on UDP:", err)
-       }
-       udpSink, udpBuf, udpReady := govpn.ConnListen(conn)
 
        termSignal := make(chan os.Signal, 1)
        signal.Notify(termSignal, os.Interrupt, os.Kill)
@@ -105,7 +118,6 @@ func main() {
        hsHeartbeat := time.Tick(timeout)
        go func() { <-hsHeartbeat }()
 
-       var addr string
        var state *govpn.Handshake
        var peerState *PeerState
        var peer *govpn.Peer
@@ -115,15 +127,13 @@ func main() {
        peerReadySink := make(chan PeerReadyEvent)
        knownPeers := govpn.KnownPeers(make(map[string]**govpn.Peer))
        var peerReady PeerReadyEvent
-       var udpPkt govpn.UDPPkt
-       var udpPktData []byte
+       var pkt Pkt
        var ethEvent EthEvent
        var peerId *govpn.PeerId
        var peerConf *govpn.PeerConf
        var handshakeProcessForce bool
        ethSink := make(chan EthEvent)
 
-       log.Println(govpn.VersionGet())
        log.Println("Max MTU on TAP interface:", govpn.TAPMaxMTU())
        if *stats != "" {
                log.Println("Stats are going to listen on", *stats)
@@ -133,6 +143,9 @@ func main() {
                }
                go govpn.StatsProcessor(statsPort, &knownPeers)
        }
+       if *proxy != "" {
+               go proxyStart(sink)
+       }
        log.Println("Server started")
 
 MainCycle:
@@ -175,15 +188,14 @@ MainCycle:
                                state.peer.Zero()
                                break
                        }
-                       addr = peerReady.peer.Addr.String()
                        state := NewPeerState(peerReady.peer, peerReady.iface)
                        if state == nil {
                                continue
                        }
-                       peers[addr] = state
-                       knownPeers[addr] = &peerReady.peer
-                       states[addr].Zero()
-                       delete(states, addr)
+                       peers[peerReady.peer.Addr] = state
+                       knownPeers[peerReady.peer.Addr] = &peerReady.peer
+                       states[peerReady.peer.Addr].Zero()
+                       delete(states, peerReady.peer.Addr)
                        log.Println("Registered interface", peerReady.iface, "with peer", peer)
                        go func(state *PeerState) {
                                for data := range state.sink {
@@ -195,43 +207,43 @@ MainCycle:
                                }
                        }(state)
                case ethEvent = <-ethSink:
-                       if s, exists := peers[ethEvent.peer.Addr.String()]; !exists || s.peer != ethEvent.peer {
+                       if s, exists := peers[ethEvent.peer.Addr]; !exists || s.peer != ethEvent.peer {
                                continue
                        }
-                       ethEvent.peer.EthProcess(ethEvent.data, conn, ethEvent.ready)
-               case udpPkt = <-udpSink:
-                       if udpPkt.Addr == nil {
-                               udpReady <- struct{}{}
+                       ethEvent.peer.EthProcess(ethEvent.data, ethEvent.ready)
+               case pkt = <-sink:
+                       if pkt.data == nil {
+                               pkt.ready <- struct{}{}
                                continue
                        }
-                       udpPktData = udpBuf[:udpPkt.Size]
-                       addr = udpPkt.Addr.String()
                        handshakeProcessForce = false
                HandshakeProcess:
-                       if _, exists = peers[addr]; handshakeProcessForce || !exists {
-                               peerId = govpn.IDsCache.Find(udpPktData)
+                       if _, exists = peers[pkt.addr]; handshakeProcessForce || !exists {
+                               peerId = govpn.IDsCache.Find(pkt.data)
                                if peerId == nil {
-                                       log.Println("Unknown identity from", addr)
-                                       udpReady <- struct{}{}
+                                       log.Println("Unknown identity from", pkt.addr)
+                                       pkt.ready <- struct{}{}
                                        continue
                                }
                                peerConf = peerId.Conf()
                                if peerConf == nil {
                                        log.Println("Can not get peer configuration", peerId.String())
-                                       udpReady <- struct{}{}
+                                       pkt.ready <- struct{}{}
                                        continue
                                }
-                               state, exists = states[addr]
+                               state, exists = states[pkt.addr]
                                if !exists {
-                                       state = govpn.HandshakeNew(udpPkt.Addr, peerConf)
-                                       states[addr] = state
+                                       state = govpn.HandshakeNew(pkt.addr, pkt.conn, peerConf)
+                                       states[pkt.addr] = state
                                }
-                               peer = state.Server(conn, udpPktData)
+                               peer = state.Server(pkt.data)
                                if peer != nil {
                                        log.Println("Peer handshake finished", peer)
-                                       if _, exists = peers[addr]; exists {
+                                       if _, exists = peers[pkt.addr]; exists {
                                                go func() {
-                                                       peerReadySink <- PeerReadyEvent{peer, peers[addr].tap.Name}
+                                                       peerReadySink <- PeerReadyEvent{
+                                                               peer, peers[pkt.addr].tap.Name,
+                                                       }
                                                }()
                                        } else {
                                                go func() {
@@ -250,18 +262,18 @@ MainCycle:
                                        }
                                }
                                if !handshakeProcessForce {
-                                       udpReady <- struct{}{}
+                                       pkt.ready <- struct{}{}
                                }
                                continue
                        }
-                       peerState, exists = peers[addr]
+                       peerState, exists = peers[pkt.addr]
                        if !exists {
-                               udpReady <- struct{}{}
+                               pkt.ready <- struct{}{}
                                continue
                        }
                        // If it fails during processing, then try to work with it
                        // as with handshake packet
-                       if !peerState.peer.UDPProcess(udpPktData, peerState.tap, udpReady) {
+                       if !peerState.peer.PktProcess(pkt.data, peerState.tap, pkt.ready) {
                                handshakeProcessForce = true
                                goto HandshakeProcess
                        }
diff --git a/src/govpn/cmd/govpn-server/proxy.go b/src/govpn/cmd/govpn-server/proxy.go
new file mode 100644 (file)
index 0000000..f1e8419
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+GoVPN -- simple secure free software virtual private network daemon
+Copyright (C) 2014-2015 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/http"
+)
+
+type proxyHandler struct {
+       sink chan Pkt
+}
+
+func (p proxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+       conn, _, err := w.(http.Hijacker).Hijack()
+       if err != nil {
+               log.Println("Hijacking failed:", err.Error())
+               return
+       }
+       conn.Write([]byte("HTTP/1.0 200 OK\n\n"))
+       ready := make(chan struct{}, 1)
+       go handleTCP(conn, p.sink, ready)
+       ready <- struct{}{}
+
+}
+
+func proxyStart(sink chan Pkt) {
+       log.Println("HTTP proxy listening on:", *proxy)
+       s := &http.Server{
+               Addr:    *proxy,
+               Handler: proxyHandler{sink},
+       }
+       log.Println("HTTP proxy result:", s.ListenAndServe())
+}
diff --git a/src/govpn/cmd/govpn-server/tcp.go b/src/govpn/cmd/govpn-server/tcp.go
new file mode 100644 (file)
index 0000000..42467d6
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+GoVPN -- simple secure free software virtual private network daemon
+Copyright (C) 2014-2015 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 (
+       "encoding/binary"
+       "log"
+       "net"
+
+       "govpn"
+)
+
+type TCPSender struct {
+       conn net.Conn
+}
+
+func (c TCPSender) Write(data []byte) (int, error) {
+       size := make([]byte, 2)
+       binary.BigEndian.PutUint16(size, uint16(len(data)))
+       return c.conn.Write(append(size, data...))
+}
+
+func startTCP(sink chan Pkt) {
+       bind, err := net.ResolveTCPAddr("tcp", *bindAddr)
+       if err != nil {
+               log.Fatalln("Can not resolve bind address:", err)
+       }
+       listener, err := net.ListenTCP("tcp", bind)
+       if err != nil {
+               log.Fatalln("Can not listen on TCP:", err)
+       }
+       log.Println("Listening on TCP", *bindAddr)
+       go func() {
+               for {
+                       conn, _ := listener.AcceptTCP()
+                       ready := make(chan struct{}, 1)
+                       go handleTCP(conn, sink, ready)
+                       ready <- struct{}{}
+               }
+       }()
+}
+
+func handleTCP(conn net.Conn, sink chan Pkt, ready chan struct{}) {
+       addr := conn.RemoteAddr().String()
+       var err error
+       var n int
+       var sizeNbuf int
+       sizeBuf := make([]byte, 2)
+       var sizeNeed uint16
+       var bufN uint16
+       buf := make([]byte, govpn.MTU)
+       for {
+               <-ready
+               if sizeNbuf != 2 {
+                       n, err = conn.Read(sizeBuf[sizeNbuf:2])
+                       if err != nil {
+                               break
+                       }
+                       sizeNbuf += n
+                       if sizeNbuf != 2 {
+                               sink <- Pkt{ready: ready}
+                               continue
+                       }
+                       sizeNeed = binary.BigEndian.Uint16(sizeBuf)
+                       if int(sizeNeed) > govpn.MTU-2 {
+                               log.Println("Invalid TCP size, skipping")
+                               sizeNbuf = 0
+                               sink <- Pkt{ready: ready}
+                               continue
+                       }
+                       bufN = 0
+               }
+       ReadMore:
+               if sizeNeed != bufN {
+                       n, err = conn.Read(buf[bufN:sizeNeed])
+                       if err != nil {
+                               break
+                       }
+                       bufN += uint16(n)
+                       goto ReadMore
+               }
+               sizeNbuf = 0
+               sink <- Pkt{
+                       addr,
+                       TCPSender{conn},
+                       buf[:sizeNeed],
+                       ready,
+               }
+       }
+}
diff --git a/src/govpn/cmd/govpn-server/udp.go b/src/govpn/cmd/govpn-server/udp.go
new file mode 100644 (file)
index 0000000..c2d6e96
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+GoVPN -- simple secure free software virtual private network daemon
+Copyright (C) 2014-2015 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"
+       "time"
+
+       "govpn"
+)
+
+type UDPSender struct {
+       conn *net.UDPConn
+       addr *net.UDPAddr
+}
+
+func (c UDPSender) Write(data []byte) (int, error) {
+       return c.conn.WriteToUDP(data, c.addr)
+}
+
+func startUDP(sink chan Pkt) {
+       bind, err := net.ResolveUDPAddr("udp", *bindAddr)
+       ready := make(chan struct{})
+       if err != nil {
+               log.Fatalln("Can not resolve bind address:", err)
+       }
+       lconn, err := net.ListenUDP("udp", bind)
+       if err != nil {
+               log.Fatalln("Can not listen on UDP:", err)
+       }
+       log.Println("Listening on UDP", *bindAddr)
+       go func() {
+               buf := make([]byte, govpn.MTU)
+               var n int
+               var raddr *net.UDPAddr
+               var err error
+               for {
+                       <-ready
+                       lconn.SetReadDeadline(time.Now().Add(time.Second))
+                       n, raddr, err = lconn.ReadFromUDP(buf)
+                       if err != nil {
+                               sink <- Pkt{ready: ready}
+                               continue
+                       }
+                       sink <- Pkt{
+                               raddr.String(),
+                               UDPSender{lconn, raddr},
+                               buf[:n],
+                               ready,
+                       }
+               }
+       }()
+       ready <- struct{}{}
+}
index 61b5b4f67dfe1f50fdb37d3c12ca032c62f8ce16..3e3d0d62b0417281f4128ecf750f0e5793012555 100644 (file)
@@ -22,8 +22,8 @@ import (
        "crypto/rand"
        "crypto/subtle"
        "encoding/binary"
+       "io"
        "log"
-       "net"
        "time"
 
        "github.com/agl/ed25519"
@@ -40,7 +40,8 @@ const (
 )
 
 type Handshake struct {
-       addr     *net.UDPAddr
+       addr     string
+       conn     io.Writer
        LastPing time.Time
        Conf     *PeerConf
        dsaPubH  *[ed25519.PublicKeySize]byte
@@ -133,9 +134,10 @@ func dhKeyGen(priv, pub *[32]byte) *[32]byte {
 }
 
 // Create new handshake state.
-func HandshakeNew(addr *net.UDPAddr, conf *PeerConf) *Handshake {
+func HandshakeNew(addr string, conn io.Writer, conf *PeerConf) *Handshake {
        state := Handshake{
                addr:     addr,
+               conn:     conn,
                LastPing: time.Now(),
                Conf:     conf,
        }
@@ -157,11 +159,10 @@ func idTag(id *PeerId, data []byte) []byte {
 }
 
 // Start handshake's procedure from the client. It is the entry point
-// for starting the handshake procedure. You have to specify outgoing
-// conn address, remote's addr address, our own peer configuration.
-// First handshake packet will be sent immediately.
-func HandshakeStart(conf *PeerConf, conn *net.UDPConn, addr *net.UDPAddr) *Handshake {
-       state := HandshakeNew(addr, conf)
+// for starting the handshake procedure. // First handshake packet
+// will be sent immediately.
+func HandshakeStart(addr string, conn io.Writer, conf *PeerConf) *Handshake {
+       state := HandshakeNew(addr, conn, conf)
 
        var dhPubRepr *[32]byte
        state.dhPriv, dhPubRepr = dhKeypairGen()
@@ -174,17 +175,16 @@ func HandshakeStart(conf *PeerConf, conn *net.UDPConn, addr *net.UDPAddr) *Hands
        salsa20.XORKeyStream(enc, dhPubRepr[:], state.rNonce[:], state.dsaPubH)
        data := append(state.rNonce[:], enc...)
        data = append(data, idTag(state.Conf.Id, state.rNonce[:])...)
-       conn.WriteToUDP(data, addr)
+       state.conn.Write(data)
        return state
 }
 
 // Process handshake message on the server side.
 // This function is intended to be called on server's side.
-// Our outgoing conn connection and received data are required.
 // If this is the final handshake message, then new Peer object
 // will be created and used as a transport. If no mutually
 // authenticated Peer is ready, then return nil.
-func (h *Handshake) Server(conn *net.UDPConn, data []byte) *Peer {
+func (h *Handshake) Server(data []byte) *Peer {
        // R + ENC(H(DSAPub), R, El(CDHPub)) + IDtag
        if len(data) == 48 && h.rNonce == nil {
                // Generate DH keypair
@@ -222,7 +222,7 @@ func (h *Handshake) Server(conn *net.UDPConn, data []byte) *Peer {
                salsa20.XORKeyStream(encRs, append(h.rServer[:], h.sServer[:]...), h.rNonce[:], h.key)
 
                // Send that to client
-               conn.WriteToUDP(append(encPub, append(encRs, idTag(h.Conf.Id, encPub)...)...), h.addr)
+               h.conn.Write(append(encPub, append(encRs, idTag(h.Conf.Id, encPub)...)...))
                h.LastPing = time.Now()
        } else
        // ENC(K, R+1, RS + RC + SC + Sign(DSAPriv, K)) + IDtag
@@ -249,11 +249,12 @@ func (h *Handshake) Server(conn *net.UDPConn, data []byte) *Peer {
                // Send final answer to client
                enc := make([]byte, RSize)
                salsa20.XORKeyStream(enc, dec[RSize:RSize+RSize], h.rNonceNext(2), h.key)
-               conn.WriteToUDP(append(enc, idTag(h.Conf.Id, enc)...), h.addr)
+               h.conn.Write(append(enc, idTag(h.Conf.Id, enc)...))
 
                // Switch peer
                peer := newPeer(
                        h.addr,
+                       h.conn,
                        h.Conf,
                        0,
                        keyFromSecrets(h.sServer[:], dec[RSize+RSize:RSize+RSize+SSize]))
@@ -267,12 +268,10 @@ func (h *Handshake) Server(conn *net.UDPConn, data []byte) *Peer {
 
 // Process handshake message on the client side.
 // This function is intended to be called on client's side.
-// Our outgoing conn connection, authentication
-// key and received data are required.
 // If this is the final handshake message, then new Peer object
 // will be created and used as a transport. If no mutually
 // authenticated Peer is ready, then return nil.
-func (h *Handshake) Client(conn *net.UDPConn, data []byte) *Peer {
+func (h *Handshake) Client(data []byte) *Peer {
        switch len(data) {
        case 80: // ENC(H(DSAPub), R+1, El(SDHPub)) + ENC(K, R, RS + SS) + IDtag
                if h.key != nil {
@@ -313,7 +312,7 @@ func (h *Handshake) Client(conn *net.UDPConn, data []byte) *Peer {
                                        append(h.sClient[:], sign[:]...)...)...), h.rNonceNext(1), h.key)
 
                // Send that to server
-               conn.WriteToUDP(append(enc, idTag(h.Conf.Id, enc)...), h.addr)
+               h.conn.Write(append(enc, idTag(h.Conf.Id, enc)...))
                h.LastPing = time.Now()
        case 16: // ENC(K, R+2, RC) + IDtag
                if h.key == nil {
@@ -330,7 +329,7 @@ func (h *Handshake) Client(conn *net.UDPConn, data []byte) *Peer {
                }
 
                // Switch peer
-               peer := newPeer(h.addr, h.Conf, 1, keyFromSecrets(h.sServer[:], h.sClient[:]))
+               peer := newPeer(h.addr, h.conn, h.Conf, 1, keyFromSecrets(h.sServer[:], h.sClient[:]))
                h.LastPing = time.Now()
                return peer
        default:
index 2f5a345e57a6f5c1dd9034f7885408ff886db64b..23f04ddda4949c3782cb8429b312f1f8bcb22f73 100644 (file)
@@ -21,7 +21,6 @@ package govpn
 import (
        "encoding/binary"
        "io"
-       "net"
        "time"
 
        "golang.org/x/crypto/poly1305"
@@ -42,14 +41,10 @@ const (
        TimeoutHeartbeat = 4
 )
 
-type UDPPkt struct {
-       Addr *net.UDPAddr
-       Size int
-}
-
 type Peer struct {
-       Addr *net.UDPAddr
+       Addr string
        Id   *PeerId
+       Conn io.Writer
 
        // Traffic behaviour
        NoiseEnable bool
@@ -98,7 +93,7 @@ type Peer struct {
 }
 
 func (p *Peer) String() string {
-       return p.Id.String() + ":" + p.Addr.String()
+       return p.Id.String() + ":" + p.Addr
 }
 
 // Zero peer's memory state.
@@ -184,35 +179,6 @@ func TAPListen(ifaceName string, timeout time.Duration, cpr int) (*TAP, chan []b
        return tap, sink, sinkReady, sinkTerminate, nil
 }
 
-// Create UDP listening goroutine.
-// This function takes already listening UDP socket and a buffer where
-// all UDP packet data will be saved, channel where information about
-// remote address and number of written bytes are stored, and a channel
-// used to tell that buffer is ready to be overwritten.
-func ConnListen(conn *net.UDPConn) (chan UDPPkt, []byte, chan struct{}) {
-       buf := make([]byte, MTU)
-       sink := make(chan UDPPkt)
-       sinkReady := make(chan struct{})
-       go func(conn *net.UDPConn) {
-               var n int
-               var addr *net.UDPAddr
-               var err error
-               for {
-                       <-sinkReady
-                       conn.SetReadDeadline(time.Now().Add(time.Second))
-                       n, addr, err = conn.ReadFromUDP(buf)
-                       if err != nil {
-                               // This is needed for ticking the timeouts counter outside
-                               sink <- UDPPkt{nil, 0}
-                               continue
-                       }
-                       sink <- UDPPkt{addr, n}
-               }
-       }(conn)
-       sinkReady <- struct{}{}
-       return sink, buf, sinkReady
-}
-
 func newNonceCipher(key *[32]byte) *xtea.Cipher {
        nonceKey := make([]byte, 16)
        salsa20.XORKeyStream(
@@ -235,7 +201,7 @@ func cprCycleCalculate(rate int) time.Duration {
        return time.Second / time.Duration(rate*(1<<10)/MTU)
 }
 
-func newPeer(addr *net.UDPAddr, conf *PeerConf, nonce int, key *[SSize]byte) *Peer {
+func newPeer(addr string, conn io.Writer, conf *PeerConf, nonce int, key *[SSize]byte) *Peer {
        now := time.Now()
        timeout := conf.Timeout
        cprCycle := cprCycleCalculate(conf.CPR)
@@ -248,6 +214,7 @@ func newPeer(addr *net.UDPAddr, conf *PeerConf, nonce int, key *[SSize]byte) *Pe
        }
        peer := Peer{
                Addr:         addr,
+               Conn:         conn,
                Timeout:      timeout,
                Established:  now,
                LastPing:     now,
@@ -270,23 +237,22 @@ func newPeer(addr *net.UDPAddr, conf *PeerConf, nonce int, key *[SSize]byte) *Pe
 }
 
 // Process incoming UDP packet.
-// udpPkt is received data, related to the peer tap interface and
 // ConnListen'es synchronization channel used to tell him that he is
 // free to receive new packets. Authenticated and decrypted packets
 // will be written to the interface immediately (except heartbeat ones).
-func (p *Peer) UDPProcess(udpPkt []byte, tap io.Writer, ready chan struct{}) bool {
-       p.size = len(udpPkt)
+func (p *Peer) PktProcess(data []byte, tap io.Writer, ready chan struct{}) bool {
+       p.size = len(data)
        copy(p.buf, Emptiness)
-       copy(p.tag[:], udpPkt[p.size-poly1305.TagSize:])
-       copy(p.buf[S20BS:], udpPkt[NonceSize:p.size-poly1305.TagSize])
+       copy(p.tag[:], data[p.size-poly1305.TagSize:])
+       copy(p.buf[S20BS:], data[NonceSize:p.size-poly1305.TagSize])
        salsa20.XORKeyStream(
                p.buf[:S20BS+p.size-poly1305.TagSize],
                p.buf[:S20BS+p.size-poly1305.TagSize],
-               udpPkt[:NonceSize],
+               data[:NonceSize],
                p.Key,
        )
        copy(p.keyAuth[:], p.buf[:SSize])
-       if !poly1305.Verify(p.tag, udpPkt[:p.size-poly1305.TagSize], p.keyAuth) {
+       if !poly1305.Verify(p.tag, data[:p.size-poly1305.TagSize], p.keyAuth) {
                ready <- struct{}{}
                p.FramesUnauth++
                return false
@@ -297,7 +263,7 @@ func (p *Peer) UDPProcess(udpPkt []byte, tap io.Writer, ready chan struct{}) boo
        // Check from the oldest bucket, as in most cases this will result
        // in constant time check.
        // If Bucket0 is filled, then it becomes Bucket1.
-       p.NonceCipher.Decrypt(p.buf, udpPkt[:NonceSize])
+       p.NonceCipher.Decrypt(p.buf, data[:NonceSize])
        ready <- struct{}{}
        p.nonceRecv, _ = binary.Uvarint(p.buf[:NonceSize])
        if _, p.nonceFound = p.nonceBucket1[p.NonceRecv]; p.nonceFound {
@@ -331,25 +297,20 @@ func (p *Peer) UDPProcess(udpPkt []byte, tap io.Writer, ready chan struct{}) boo
        return true
 }
 
-type WriteToUDPer interface {
-       WriteToUDP([]byte, *net.UDPAddr) (int, error)
-}
-
 // Process incoming Ethernet packet.
-// ethPkt is received data, conn is our outgoing connection.
 // ready channel is TAPListen's synchronization channel used to tell him
 // that he is free to receive new packets. Encrypted and authenticated
 // packets will be sent to remote Peer side immediately.
-func (p *Peer) EthProcess(ethPkt []byte, conn WriteToUDPer, ready chan struct{}) {
+func (p *Peer) EthProcess(data []byte, ready chan struct{}) {
        p.now = time.Now()
-       p.size = len(ethPkt)
+       p.size = len(data)
        // If this heartbeat is necessary
        if p.size == 0 && !p.LastSent.Add(p.Timeout).Before(p.now) {
                return
        }
        copy(p.buf, Emptiness)
        if p.size > 0 {
-               copy(p.buf[S20BS+PktSizeSize:], ethPkt)
+               copy(p.buf[S20BS+PktSizeSize:], data)
                ready <- struct{}{}
                binary.PutUvarint(p.buf[S20BS:S20BS+PktSizeSize], uint64(p.size))
                p.BytesPayloadOut += int64(p.size)
@@ -383,5 +344,5 @@ func (p *Peer) EthProcess(ethPkt []byte, conn WriteToUDPer, ready chan struct{})
                }
        }
        p.LastSent = p.now
-       conn.WriteToUDP(append(p.frame, p.tag[:]...), p.Addr)
+       p.Conn.Write(append(p.frame, p.tag[:]...))
 }
index 45f4d01cb6b6997bd871b7d9b6a5df29c87894d0..5809a9f4425a0a12a1edcacb38f276a5f8cf9ee2 100644 (file)
@@ -1,7 +1,6 @@
 package govpn
 
 import (
-       "net"
        "testing"
        "time"
 )
@@ -10,16 +9,24 @@ var (
        peer       *Peer
        plaintext  []byte
        ready      chan struct{}
-       dummy      = &Dummy{}
        ciphertext []byte
-       addr       *net.UDPAddr
        peerId     *PeerId
        conf       *PeerConf
 )
 
+type Dummy struct{
+       dst *[]byte
+}
+
+func (d Dummy) Write(b []byte) (int, error) {
+       if d.dst != nil {
+               *d.dst = b
+       }
+       return len(b), nil
+}
+
 func init() {
        MTU = 1500
-       addr, _ = net.ResolveUDPAddr("udp", "[::1]:1")
        peerId, _ = IDDecode("ffffffffffffffffffffffffffffffff")
        conf = &PeerConf{
                Id:          peerId,
@@ -27,7 +34,7 @@ func init() {
                NoiseEnable: false,
                CPR:         0,
        }
-       peer = newPeer(addr, conf, 128, new([SSize]byte))
+       peer = newPeer("foo", Dummy{&ciphertext}, conf, 128, new([SSize]byte))
        plaintext = make([]byte, 789)
        ready = make(chan struct{})
        go func() {
@@ -37,33 +44,22 @@ func init() {
        }()
 }
 
-type Dummy struct{}
-
-func (d *Dummy) WriteToUDP(b []byte, addr *net.UDPAddr) (int, error) {
-       ciphertext = b
-       return len(b), nil
-}
-
-func (d *Dummy) Write(p []byte) (n int, err error) {
-       return len(p), nil
-}
-
 func BenchmarkEnc(b *testing.B) {
        b.ResetTimer()
        for i := 0; i < b.N; i++ {
                peer.NonceOur = 128
-               peer.EthProcess(plaintext, dummy, ready)
+               peer.EthProcess(plaintext, ready)
        }
 }
 
 func BenchmarkDec(b *testing.B) {
-       peer.EthProcess(plaintext, dummy, ready)
-       peer = newPeer(addr, conf, 128, new([SSize]byte))
+       peer.EthProcess(plaintext, ready)
+       peer = newPeer("foo", Dummy{nil}, conf, 128, new([SSize]byte))
        b.ResetTimer()
        for i := 0; i < b.N; i++ {
                peer.nonceBucket0 = make(map[uint64]struct{}, 1)
                peer.nonceBucket1 = make(map[uint64]struct{}, 1)
-               if !peer.UDPProcess(ciphertext, dummy, ready) {
+               if !peer.PktProcess(ciphertext, Dummy{nil}, ready) {
                        b.Fail()
                }
        }
index e40814222704b3474c8c8535215ae03251210bfb..00ba9ac90bbb3ce36a1682d6cd844414bb92c7dd 100755 (executable)
@@ -6,8 +6,14 @@ release=$1
 [ -n "$release" ]
 
 git clone . $tmp/govpn-$release
+for repo in src/github.com/bigeagle/water src/github.com/agl/ed25519 src/golang.org/x/crypto; do
+    git clone $repo $tmp/govpn-$release/$repo
+done
+cd $tmp/govpn-$release
+git checkout $release
+git submodule update --init
+
 cat > $tmp/includes <<EOF
-github.com
 golang.org/x/crypto/AUTHORS
 golang.org/x/crypto/CONTRIBUTORS
 golang.org/x/crypto/LICENSE
@@ -19,11 +25,10 @@ golang.org/x/crypto/poly1305
 golang.org/x/crypto/salsa20
 golang.org/x/crypto/xtea
 EOF
-tar cfCI - src $tmp/includes | tar xfC - $tmp/govpn-$release/src
-rm $tmp/includes
-
-cd $tmp/govpn-$release
-git checkout $release
+tar cfCI - src $tmp/includes | tar xfC - $tmp
+rm -fr src/golang.org
+mv $tmp/golang.org src/
+rm -fr $tmp/golang.org $tmp/includes
 
 cat > doc/download.texi <<EOF
 @node Prepared tarballs
@@ -40,5 +45,5 @@ find . -name .gitignore -delete
 cd ..
 tar cvf govpn-"$release".tar govpn-"$release"
 xz -9 govpn-"$release".tar
-gpg --detach-sign --sign --local-user FFE2F4A1 govpn-"$release".tar.xz
+gpg --detach-sign --sign --local-user F2F59045FFE2F4A1 govpn-"$release".tar.xz
 mv $tmp/govpn-"$release".tar.xz $tmp/govpn-"$release".tar.xz.sig $cur/doc/govpn.html/download