Merge remote-tracking branch 'mweinelt/tinc-gui' into 1.1
authorGuus Sliepen <guus@tinc-vpn.org>
Sun, 17 Jan 2016 22:29:23 +0000 (23:29 +0100)
committerGuus Sliepen <guus@tinc-vpn.org>
Sun, 17 Jan 2016 22:29:23 +0000 (23:29 +0100)
20 files changed:
THANKS
bash_completion.d/tinc
configure.ac
doc/tinc.conf.5.in
doc/tinc.texi
m4/miniupnpc.m4 [new file with mode: 0644]
src/Makefile.am
src/ed25519/fe.c
src/ed25519/fixedint.h
src/ed25519/ge.c
src/ed25519/sc.c
src/net_packet.c
src/net_setup.c
src/net_socket.c
src/node.c
src/protocol_key.c
src/route.c
src/tincctl.c
src/upnp.c [new file with mode: 0644]
src/upnp.h [new file with mode: 0644]

diff --git a/THANKS b/THANKS
index d1ee6b4..77a04e4 100644 (file)
--- a/THANKS
+++ b/THANKS
@@ -27,6 +27,7 @@ We would like to thank the following people for their contributions to tinc:
 * Gary Kessler and Claudia Gonzalez
 * Grzegorz Dymarek
 * Hans Bayle
+* Harvest
 * Ivo van Dong
 * James Cook
 * James MacLean
@@ -34,8 +35,10 @@ We would like to thank the following people for their contributions to tinc:
 * Jason Harper
 * Jason Livesay
 * Jelle de Jong
+* Jeroen Domburg
 * Jeroen Ubbink
 * Jerome Etienne
+* Jo-Philipp Wich
 * Jochen Voss
 * Julien Muchembled
 * Lavrans Laading
@@ -56,19 +59,24 @@ We would like to thank the following people for their contributions to tinc:
 * Mesar Hameed
 * Michael Tokarev
 * Miles Nordin
+* Murat Donmez
 * Nick Hibma
 * Nick Patavalis
 * Paul Littlefield
 * Philipp Babel
 * Robert van der Meulen
 * Rumko
+* Sam Bryan
+* Samuel Thibault
 * Saverio Proto
 * Scott Lamb
 * Steffan Karger
+* Stig Fagrell
 * Sven-Haegar Koch
 * Teemu Kiviniemi
 * Thomas Tsiakalakis
 * Timothy Redaelli
+* Tomasz Fortuna
 * Tomislav Čohar
 * Tommy Arnkværn
 * Tonnerre Lombard
@@ -78,6 +86,7 @@ We would like to thank the following people for their contributions to tinc:
 * William A. Kennington III
 * William McArthur
 * Wouter van Heyst
+* 戴 鸣
 
 And everyone we forgot (if we did, please let us know). Thank you!
 
index 48512dd..d21aef3 100644 (file)
@@ -4,7 +4,7 @@ _tinc() {
        cur="${COMP_WORDS[COMP_CWORD]}"
        prev="${COMP_WORDS[COMP_CWORD-1]}"
        opts="-c -d -D -K -n -o -L -R -U --config --no-detach --debug --net --option --mlock --logfile --pidfile --chroot --user --help --version"
-       confvars="Address AddressFamily BindToAddress BindToInterface Broadcast BroadcastSubnet Cipher ClampMSS Compression ConnectTo DecrementTTL Device DeviceStandby DeviceType Digest DirectOnly Ed25519PrivateKeyFile Ed25519PublicKey Ed25519PublicKeyFile ExperimentalProtocol Forwarding GraphDumpFile Hostnames IffOneQueue IndirectData Interface KeyExpire ListenAddress LocalDiscovery MACExpire MACLength MaxOutputBufferSize MaxTimeout Mode MTUInfoInterval Name PMTU PMTUDiscovery PingInterval PingTimeout Port PriorityInheritance PrivateKeyFile ProcessPriority Proxy PublicKeyFile ReplayWindow StrictSubnets Subnet TCPOnly TunnelServer UDPDiscovery UDPDiscoveryKeepaliveInterval UDPDiscoveryInterval UDPDiscoveryTimeout UDPInfoInterval UDPRcvBuf UDPSndBuf VDEGroup VDEPort Weight"
+       confvars="Address AddressFamily BindToAddress BindToInterface Broadcast BroadcastSubnet Cipher ClampMSS Compression ConnectTo DecrementTTL Device DeviceStandby DeviceType Digest DirectOnly Ed25519PrivateKeyFile Ed25519PublicKey Ed25519PublicKeyFile ExperimentalProtocol Forwarding GraphDumpFile Hostnames IffOneQueue IndirectData Interface KeyExpire ListenAddress LocalDiscovery MACExpire MACLength MaxOutputBufferSize MaxTimeout Mode MTUInfoInterval Name PMTU PMTUDiscovery PingInterval PingTimeout Port PriorityInheritance PrivateKeyFile ProcessPriority Proxy PublicKeyFile ReplayWindow StrictSubnets Subnet TCPOnly TunnelServer UDPDiscovery UDPDiscoveryKeepaliveInterval UDPDiscoveryInterval UDPDiscoveryTimeout UDPInfoInterval UDPRcvBuf UDPSndBuf UPnP UPnPDiscoverWait UPnPRefreshPeriod VDEGroup VDEPort Weight"
        commands="add connect debug del disconnect dump edit export export-all generate-ed25519-keys generate-keys generate-rsa-keys get help import info init invite join list log network pcap pid purge reload restart retry set start stop top version"
 
        case ${prev} in
index a57957e..89957ac 100644 (file)
@@ -67,7 +67,9 @@ case $host_os in
   *mingw*)
     mingw=true
     AC_DEFINE(HAVE_MINGW, 1, [MinGW])
-    LIBS="$LIBS -lws2_32 -lgdi32 -lcrypt32"
+    LIBS="$LIBS -lws2_32 -lgdi32 -lcrypt32 -liphlpapi"
+    LDFLAGS="$LDFLAGS -static"
+    CPPFLAGS="$CPPFLAGS -DMINIUPNP_STATICLIB"
   ;;
   *)
     AC_MSG_ERROR("Unknown operating system.")
@@ -196,7 +198,7 @@ AC_CHECK_TYPES([socklen_t, struct ether_header, struct arphdr, struct ether_arp,
 
 dnl Checks for library functions.
 AC_TYPE_SIGNAL
-AC_CHECK_FUNCS([asprintf daemon fchmod flock ftime fork get_current_dir_name gettimeofday mlockall putenv random select strdup strerror strsignal strtol system time usleep unsetenv vsyslog writev],
+AC_CHECK_FUNCS([asprintf daemon fchmod flock ftime fork get_current_dir_name gettimeofday mlockall putenv random recvmmsg select strdup strerror strsignal strtol system time usleep unsetenv vsyslog writev],
   [], [], [#include "$srcdir/src/have.h"]
 )
 
@@ -247,6 +249,9 @@ AS_IF([test "x$enable_legacy_protocol" != "xno"],
 AM_CONDITIONAL(OPENSSL, test -n "$openssl")
 AM_CONDITIONAL(GCRYPT, test -n "$gcrypt")
 
+tinc_MINIUPNPC
+AM_CONDITIONAL(MINIUPNPC, test "x$enable_miniupnpc" = "xyes")
+
 dnl Check if support for jumbograms is requested
 AC_ARG_ENABLE(jumbograms,
   AS_HELP_STRING([--enable-jumbograms], [enable support for jumbograms (packets up to 9000 bytes)]),
index 71b5ec6..30af25d 100644 (file)
@@ -510,6 +510,17 @@ Note: this setting can have a significant impact on performance, especially raw
 Sets the socket send buffer size for the UDP socket, in bytes.
 If set to zero, the default buffer size will be used by the operating system.
 Note: this setting can have a significant impact on performance, especially raw throughput.
+.It Va UPnP Li = yes | udponly | no Po no Pc
+If this option is enabled then tinc will search for UPnP-IGD devices on the local network.
+It will then create and maintain port mappings for tinc's listening TCP and UDP ports.
+If set to "udponly", tinc will only create a mapping for its UDP (data) port, not for its TCP (metaconnection) port.
+Note that tinc must have been built with miniupnpc support for this feature to be available.
+Furthermore, be advised that enabling this can have security implications, because the miniupnpc library that
+tinc uses might not be well-hardened with regard to malicious UPnP replies.
+.It Va UPnPDiscoverWait Li = Ar seconds Pq 5
+The amount of time to wait for replies when probing the local network for UPnP devices.
+.It Va UPnPRefreshPeriod Li = Ar seconds Pq 60
+How often tinc will re-add the port mapping, in case it gets reset on the UPnP device. This also controls the duration of the port mapping itself, which will be set to twice that duration.
 .El
 .Sh HOST CONFIGURATION FILES
 The host configuration files contain all information needed
index e939784..ed55446 100644 (file)
@@ -1269,6 +1269,24 @@ Sets the socket send buffer size for the UDP socket, in bytes.
 If set to zero, the default buffer size will be used by the operating system.
 Note: this setting can have a significant impact on performance, especially raw throughput.
 
+@cindex UPnP
+@item UPnP = <yes|udponly|no> (no)
+If this option is enabled then tinc will search for UPnP-IGD devices on the local network.
+It will then create and maintain port mappings for tinc's listening TCP and UDP ports.
+If set to "udponly", tinc will only create a mapping for its UDP (data) port, not for its TCP (metaconnection) port.
+Note that tinc must have been built with miniupnpc support for this feature to be available.
+Furthermore, be advised that enabling this can have security implications, because the miniupnpc library that
+tinc uses might not be well-hardened with regard to malicious UPnP replies.
+
+@cindex UPnPDiscoverWait
+@item UPnPDiscoverWait = <seconds> (5)
+The amount of time to wait for replies when probing the local network for UPnP devices.
+
+@cindex UPnPRefreshPeriod
+@item UPnPRefreshPeriod = <seconds> (5)
+How often tinc will re-add the port mapping, in case it gets reset on the UPnP device.
+This also controls the duration of the port mapping itself, which will be set to twice that duration.
+
 @end table
 
 
diff --git a/m4/miniupnpc.m4 b/m4/miniupnpc.m4
new file mode 100644 (file)
index 0000000..c2aca29
--- /dev/null
@@ -0,0 +1,40 @@
+dnl Check to find the miniupnpc headers/libraries
+
+AC_DEFUN([tinc_MINIUPNPC],
+[
+  AC_ARG_ENABLE([miniupnpc],
+    AS_HELP_STRING([--enable-miniupnpc], [enable miniupnpc support]))
+  AS_IF([test "x$enable_miniupnpc" = "xyes"], [
+  AC_DEFINE(HAVE_MINIUPNPC, 1, [have miniupnpc support])
+    AC_ARG_WITH(miniupnpc,
+      AS_HELP_STRING([--with-miniupnpc=DIR], [miniupnpc base directory, or:]),
+      [miniupnpc="$withval"
+       CPPFLAGS="$CPPFLAGS -I$withval/include"
+       LDFLAGS="$LDFLAGS -L$withval/lib"]
+    )
+
+    AC_ARG_WITH(miniupnpc-include,
+      AS_HELP_STRING([--with-miniupnpc-include=DIR], [miniupnpc headers directory]),
+      [miniupnpc_include="$withval"
+       CPPFLAGS="$CPPFLAGS -I$withval"]
+    )
+
+    AC_ARG_WITH(miniupnpc-lib,
+      AS_HELP_STRING([--with-miniupnpc-lib=DIR], [miniupnpc library directory]),
+      [miniupnpc_lib="$withval"
+       LDFLAGS="$LDFLAGS -L$withval"]
+    )
+
+    AC_CHECK_HEADERS(miniupnpc/miniupnpc.h,
+      [],
+      [AC_MSG_ERROR("miniupnpc header files not found."); break]
+    )
+
+    AC_CHECK_LIB(miniupnpc, upnpDiscover,
+      [MINIUPNPC_LIBS="$LIBS -lminiupnpc"],
+      [AC_MSG_ERROR("miniupnpc libraries not found.")]
+    )
+  ])
+
+  AC_SUBST(MINIUPNPC_LIBS)
+])
index 63af709..035717b 100644 (file)
@@ -251,6 +251,12 @@ sptps_speed_SOURCES += \
 endif
 endif
 
+if MINIUPNPC
+tincd_SOURCES += upnp.h upnp.c
+tincd_LDADD = $(MINIUPNPC_LIBS)
+tincd_LDFLAGS = -pthread
+endif
+
 tinc_LDADD = $(READLINE_LIBS) $(CURSES_LIBS)
 sptps_speed_LDADD = -lrt
 
index 448e3e9..1c459f4 100644 (file)
@@ -8,9 +8,9 @@
 static uint64_t load_3(const unsigned char *in) {
     uint64_t result;
 
-    result = (uint64_t) in[0];
-    result |= ((uint64_t) in[1]) << 8;
-    result |= ((uint64_t) in[2]) << 16;
+    result = in[0];
+    result |= shlu64(in[1], 8);
+    result |= shlu64(in[2], 16);
 
     return result;
 }
@@ -18,10 +18,10 @@ static uint64_t load_3(const unsigned char *in) {
 static uint64_t load_4(const unsigned char *in) {
     uint64_t result;
 
-    result = (uint64_t) in[0];
-    result |= ((uint64_t) in[1]) << 8;
-    result |= ((uint64_t) in[2]) << 16;
-    result |= ((uint64_t) in[3]) << 24;
+    result = in[0];
+    result |= shlu64(in[1], 8);
+    result |= shlu64(in[2], 16);
+    result |= shlu64(in[3], 24);
     
     return result;
 }
@@ -316,47 +316,47 @@ void fe_frombytes(fe h, const unsigned char *s) {
     int64_t carry8;
     int64_t carry9;
 
-    carry9 = (h9 + (int64_t) (1 << 24)) >> 25;
+    carry9 = (h9 + (1L << 24)) >> 25;
     h0 += carry9 * 19;
-    h9 -= carry9 << 25;
-    carry1 = (h1 + (int64_t) (1 << 24)) >> 25;
+    h9 -= shl64(carry9, 25);
+    carry1 = (h1 + (1L << 24)) >> 25;
     h2 += carry1;
-    h1 -= carry1 << 25;
-    carry3 = (h3 + (int64_t) (1 << 24)) >> 25;
+    h1 -= shl64(carry1, 25);
+    carry3 = (h3 + (1L << 24)) >> 25;
     h4 += carry3;
-    h3 -= carry3 << 25;
-    carry5 = (h5 + (int64_t) (1 << 24)) >> 25;
+    h3 -= shl64(carry3, 25);
+    carry5 = (h5 + (1L << 24)) >> 25;
     h6 += carry5;
-    h5 -= carry5 << 25;
-    carry7 = (h7 + (int64_t) (1 << 24)) >> 25;
+    h5 -= shl64(carry5, 25);
+    carry7 = (h7 + (1L << 24)) >> 25;
     h8 += carry7;
-    h7 -= carry7 << 25;
-    carry0 = (h0 + (int64_t) (1 << 25)) >> 26;
+    h7 -= shl64(carry7, 25);
+    carry0 = (h0 + (1L << 25)) >> 26;
     h1 += carry0;
-    h0 -= carry0 << 26;
-    carry2 = (h2 + (int64_t) (1 << 25)) >> 26;
+    h0 -= shl64(carry0, 26);
+    carry2 = (h2 + (1L << 25)) >> 26;
     h3 += carry2;
-    h2 -= carry2 << 26;
-    carry4 = (h4 + (int64_t) (1 << 25)) >> 26;
+    h2 -= shl64(carry2, 26);
+    carry4 = (h4 + (1L << 25)) >> 26;
     h5 += carry4;
-    h4 -= carry4 << 26;
-    carry6 = (h6 + (int64_t) (1 << 25)) >> 26;
+    h4 -= shl64(carry4, 26);
+    carry6 = (h6 + (1L << 25)) >> 26;
     h7 += carry6;
-    h6 -= carry6 << 26;
-    carry8 = (h8 + (int64_t) (1 << 25)) >> 26;
+    h6 -= shl64(carry6, 26);
+    carry8 = (h8 + (1L << 25)) >> 26;
     h9 += carry8;
-    h8 -= carry8 << 26;
+    h8 -= shl64(carry8, 26);
 
-    h[0] = (int32_t) h0;
-    h[1] = (int32_t) h1;
-    h[2] = (int32_t) h2;
-    h[3] = (int32_t) h3;
-    h[4] = (int32_t) h4;
-    h[5] = (int32_t) h5;
-    h[6] = (int32_t) h6;
-    h[7] = (int32_t) h7;
-    h[8] = (int32_t) h8;
-    h[9] = (int32_t) h9;
+    h[0] = h0;
+    h[1] = h1;
+    h[2] = h2;
+    h[3] = h3;
+    h[4] = h4;
+    h[5] = h5;
+    h[6] = h6;
+    h[7] = h7;
+    h[8] = h8;
+    h[9] = h9;
 }
 
 
@@ -709,48 +709,48 @@ void fe_mul(fe h, const fe f, const fe g) {
     int64_t carry8;
     int64_t carry9;
 
-    carry0 = (h0 + (int64_t) (1 << 25)) >> 26;
+    carry0 = (h0 + (1L << 25)) >> 26;
     h1 += carry0;
-    h0 -= carry0 << 26;
-    carry4 = (h4 + (int64_t) (1 << 25)) >> 26;
+    h0 -= shl64(carry0, 26);
+    carry4 = (h4 + (1L << 25)) >> 26;
     h5 += carry4;
-    h4 -= carry4 << 26;
+    h4 -= shl64(carry4, 26);
 
-    carry1 = (h1 + (int64_t) (1 << 24)) >> 25;
+    carry1 = (h1 + (1L << 24)) >> 25;
     h2 += carry1;
-    h1 -= carry1 << 25;
-    carry5 = (h5 + (int64_t) (1 << 24)) >> 25;
+    h1 -= shl64(carry1, 25);
+    carry5 = (h5 + (1L << 24)) >> 25;
     h6 += carry5;
-    h5 -= carry5 << 25;
+    h5 -= shl64(carry5, 25);
 
-    carry2 = (h2 + (int64_t) (1 << 25)) >> 26;
+    carry2 = (h2 + (1L << 25)) >> 26;
     h3 += carry2;
-    h2 -= carry2 << 26;
-    carry6 = (h6 + (int64_t) (1 << 25)) >> 26;
+    h2 -= shl64(carry2, 26);
+    carry6 = (h6 + (1L << 25)) >> 26;
     h7 += carry6;
-    h6 -= carry6 << 26;
+    h6 -= shl64(carry6, 26);
 
-    carry3 = (h3 + (int64_t) (1 << 24)) >> 25;
+    carry3 = (h3 + (1L << 24)) >> 25;
     h4 += carry3;
-    h3 -= carry3 << 25;
-    carry7 = (h7 + (int64_t) (1 << 24)) >> 25;
+    h3 -= shl64(carry3, 25);
+    carry7 = (h7 + (1L << 24)) >> 25;
     h8 += carry7;
-    h7 -= carry7 << 25;
+    h7 -= shl64(carry7, 25);
 
-    carry4 = (h4 + (int64_t) (1 << 25)) >> 26;
+    carry4 = (h4 + (1L << 25)) >> 26;
     h5 += carry4;
-    h4 -= carry4 << 26;
-    carry8 = (h8 + (int64_t) (1 << 25)) >> 26;
+    h4 -= shl64(carry4, 26);
+    carry8 = (h8 + (1L << 25)) >> 26;
     h9 += carry8;
-    h8 -= carry8 << 26;
+    h8 -= shl64(carry8, 26);
 
-    carry9 = (h9 + (int64_t) (1 << 24)) >> 25;
+    carry9 = (h9 + (1L << 24)) >> 25;
     h0 += carry9 * 19;
-    h9 -= carry9 << 25;
+    h9 -= shl64(carry9, 25);
 
-    carry0 = (h0 + (int64_t) (1 << 25)) >> 26;
+    carry0 = (h0 + (1L << 25)) >> 26;
     h1 += carry0;
-    h0 -= carry0 << 26;
+    h0 -= shl64(carry0, 26);
 
     h[0] = (int32_t) h0;
     h[1] = (int32_t) h1;
@@ -808,17 +808,17 @@ void fe_mul121666(fe h, fe f) {
     int64_t carry8;
     int64_t carry9;
 
-    carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
-    carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
-    carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
-    carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
-    carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+    carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= shl64(carry9, 25);
+    carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= shl64(carry1, 25);
+    carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= shl64(carry3, 25);
+    carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= shl64(carry5, 25);
+    carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= shl64(carry7, 25);
 
-    carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
-    carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
-    carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
-    carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
-    carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+    carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= shl64(carry0, 26);
+    carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= shl64(carry2, 26);
+    carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= shl64(carry4, 26);
+    carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= shl64(carry6, 26);
+    carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= shl64(carry8, 26);
 
     h[0] = h0;
     h[1] = h1;
@@ -1078,42 +1078,42 @@ void fe_sq(fe h, const fe f) {
     int64_t carry7;
     int64_t carry8;
     int64_t carry9;
-    carry0 = (h0 + (int64_t) (1 << 25)) >> 26;
+    carry0 = (h0 + (1L << 25)) >> 26;
     h1 += carry0;
-    h0 -= carry0 << 26;
-    carry4 = (h4 + (int64_t) (1 << 25)) >> 26;
+    h0 -= shl64(carry0, 26);
+    carry4 = (h4 + (1L << 25)) >> 26;
     h5 += carry4;
-    h4 -= carry4 << 26;
-    carry1 = (h1 + (int64_t) (1 << 24)) >> 25;
+    h4 -= shl64(carry4, 26);
+    carry1 = (h1 + (1L << 24)) >> 25;
     h2 += carry1;
-    h1 -= carry1 << 25;
-    carry5 = (h5 + (int64_t) (1 << 24)) >> 25;
+    h1 -= shl64(carry1, 25);
+    carry5 = (h5 + (1L << 24)) >> 25;
     h6 += carry5;
-    h5 -= carry5 << 25;
-    carry2 = (h2 + (int64_t) (1 << 25)) >> 26;
+    h5 -= shl64(carry5, 25);
+    carry2 = (h2 + (1L << 25)) >> 26;
     h3 += carry2;
-    h2 -= carry2 << 26;
-    carry6 = (h6 + (int64_t) (1 << 25)) >> 26;
+    h2 -= shl64(carry2, 26);
+    carry6 = (h6 + (1L << 25)) >> 26;
     h7 += carry6;
-    h6 -= carry6 << 26;
-    carry3 = (h3 + (int64_t) (1 << 24)) >> 25;
+    h6 -= shl64(carry6, 26);
+    carry3 = (h3 + (1L << 24)) >> 25;
     h4 += carry3;
-    h3 -= carry3 << 25;
-    carry7 = (h7 + (int64_t) (1 << 24)) >> 25;
+    h3 -= shl64(carry3, 25);
+    carry7 = (h7 + (1L << 24)) >> 25;
     h8 += carry7;
-    h7 -= carry7 << 25;
-    carry4 = (h4 + (int64_t) (1 << 25)) >> 26;
+    h7 -= shl64(carry7, 25);
+    carry4 = (h4 + (1L << 25)) >> 26;
     h5 += carry4;
-    h4 -= carry4 << 26;
-    carry8 = (h8 + (int64_t) (1 << 25)) >> 26;
+    h4 -= shl64(carry4, 26);
+    carry8 = (h8 + (1L << 25)) >> 26;
     h9 += carry8;
-    h8 -= carry8 << 26;
-    carry9 = (h9 + (int64_t) (1 << 24)) >> 25;
+    h8 -= shl64(carry8, 26);
+    carry9 = (h9 + (1L << 24)) >> 25;
     h0 += carry9 * 19;
-    h9 -= carry9 << 25;
-    carry0 = (h0 + (int64_t) (1 << 25)) >> 26;
+    h9 -= shl64(carry9, 25);
+    carry0 = (h0 + (1L << 25)) >> 26;
     h1 += carry0;
-    h0 -= carry0 << 26;
+    h0 -= shl64(carry0, 26);
     h[0] = (int32_t) h0;
     h[1] = (int32_t) h1;
     h[2] = (int32_t) h2;
@@ -1251,42 +1251,42 @@ void fe_sq2(fe h, const fe f) {
     h7 += h7;
     h8 += h8;
     h9 += h9;
-    carry0 = (h0 + (int64_t) (1 << 25)) >> 26;
+    carry0 = (h0 + (1L << 25)) >> 26;
     h1 += carry0;
-    h0 -= carry0 << 26;
-    carry4 = (h4 + (int64_t) (1 << 25)) >> 26;
+    h0 -= shl64(carry0, 26);
+    carry4 = (h4 + (1L << 25)) >> 26;
     h5 += carry4;
-    h4 -= carry4 << 26;
-    carry1 = (h1 + (int64_t) (1 << 24)) >> 25;
+    h4 -= shl64(carry4, 26);
+    carry1 = (h1 + (1L << 24)) >> 25;
     h2 += carry1;
-    h1 -= carry1 << 25;
-    carry5 = (h5 + (int64_t) (1 << 24)) >> 25;
+    h1 -= shl64(carry1, 25);
+    carry5 = (h5 + (1L << 24)) >> 25;
     h6 += carry5;
-    h5 -= carry5 << 25;
-    carry2 = (h2 + (int64_t) (1 << 25)) >> 26;
+    h5 -= shl64(carry5, 25);
+    carry2 = (h2 + (1L << 25)) >> 26;
     h3 += carry2;
-    h2 -= carry2 << 26;
-    carry6 = (h6 + (int64_t) (1 << 25)) >> 26;
+    h2 -= shl64(carry2, 26);
+    carry6 = (h6 + (1L << 25)) >> 26;
     h7 += carry6;
-    h6 -= carry6 << 26;
-    carry3 = (h3 + (int64_t) (1 << 24)) >> 25;
+    h6 -= shl64(carry6, 26);
+    carry3 = (h3 + (1L << 24)) >> 25;
     h4 += carry3;
-    h3 -= carry3 << 25;
-    carry7 = (h7 + (int64_t) (1 << 24)) >> 25;
+    h3 -= shl64(carry3, 25);
+    carry7 = (h7 + (1L << 24)) >> 25;
     h8 += carry7;
-    h7 -= carry7 << 25;
-    carry4 = (h4 + (int64_t) (1 << 25)) >> 26;
+    h7 -= shl64(carry7, 25);
+    carry4 = (h4 + (1L << 25)) >> 26;
     h5 += carry4;
-    h4 -= carry4 << 26;
-    carry8 = (h8 + (int64_t) (1 << 25)) >> 26;
+    h4 -= shl64(carry4, 26);
+    carry8 = (h8 + (1L << 25)) >> 26;
     h9 += carry8;
-    h8 -= carry8 << 26;
-    carry9 = (h9 + (int64_t) (1 << 24)) >> 25;
+    h8 -= shl64(carry8, 26);
+    carry9 = (h9 + (1L << 24)) >> 25;
     h0 += carry9 * 19;
-    h9 -= carry9 << 25;
-    carry0 = (h0 + (int64_t) (1 << 25)) >> 26;
+    h9 -= shl64(carry9, 25);
+    carry0 = (h0 + (1L << 25)) >> 26;
     h1 += carry0;
-    h0 -= carry0 << 26;
+    h0 -= shl64(carry0, 26);
     h[0] = (int32_t) h0;
     h[1] = (int32_t) h1;
     h[2] = (int32_t) h2;
@@ -1421,33 +1421,33 @@ void fe_tobytes(unsigned char *s, const fe h) {
     /* Goal: Output h-2^255 q, which is between 0 and 2^255-20. */
     carry0 = h0 >> 26;
     h1 += carry0;
-    h0 -= carry0 << 26;
+    h0 -= shl32(carry0, 26);
     carry1 = h1 >> 25;
     h2 += carry1;
-    h1 -= carry1 << 25;
+    h1 -= shl32(carry1, 25);
     carry2 = h2 >> 26;
     h3 += carry2;
-    h2 -= carry2 << 26;
+    h2 -= shl32(carry2, 26);
     carry3 = h3 >> 25;
     h4 += carry3;
-    h3 -= carry3 << 25;
+    h3 -= shl32(carry3, 25);
     carry4 = h4 >> 26;
     h5 += carry4;
-    h4 -= carry4 << 26;
+    h4 -= shl32(carry4, 26);
     carry5 = h5 >> 25;
     h6 += carry5;
-    h5 -= carry5 << 25;
+    h5 -= shl32(carry5, 25);
     carry6 = h6 >> 26;
     h7 += carry6;
-    h6 -= carry6 << 26;
+    h6 -= shl32(carry6, 26);
     carry7 = h7 >> 25;
     h8 += carry7;
-    h7 -= carry7 << 25;
+    h7 -= shl32(carry7, 25);
     carry8 = h8 >> 26;
     h9 += carry8;
-    h8 -= carry8 << 26;
+    h8 -= shl32(carry8, 26);
     carry9 = h9 >> 25;
-    h9 -= carry9 << 25;
+    h9 -= shl32(carry9, 25);
 
     /* h10 = carry9 */
     /*
@@ -1459,32 +1459,32 @@ void fe_tobytes(unsigned char *s, const fe h) {
     s[0] = (unsigned char) (h0 >> 0);
     s[1] = (unsigned char) (h0 >> 8);
     s[2] = (unsigned char) (h0 >> 16);
-    s[3] = (unsigned char) ((h0 >> 24) | (h1 << 2));
+    s[3] = (unsigned char) ((h0 >> 24) | shl32(h1, 2));
     s[4] = (unsigned char) (h1 >> 6);
     s[5] = (unsigned char) (h1 >> 14);
-    s[6] = (unsigned char) ((h1 >> 22) | (h2 << 3));
+    s[6] = (unsigned char) ((h1 >> 22) | shl32(h2, 3));
     s[7] = (unsigned char) (h2 >> 5);
     s[8] = (unsigned char) (h2 >> 13);
-    s[9] = (unsigned char) ((h2 >> 21) | (h3 << 5));
+    s[9] = (unsigned char) ((h2 >> 21) | shl32(h3, 5));
     s[10] = (unsigned char) (h3 >> 3);
     s[11] = (unsigned char) (h3 >> 11);
-    s[12] = (unsigned char) ((h3 >> 19) | (h4 << 6));
+    s[12] = (unsigned char) ((h3 >> 19) | shl32(h4, 6));
     s[13] = (unsigned char) (h4 >> 2);
     s[14] = (unsigned char) (h4 >> 10);
     s[15] = (unsigned char) (h4 >> 18);
     s[16] = (unsigned char) (h5 >> 0);
     s[17] = (unsigned char) (h5 >> 8);
     s[18] = (unsigned char) (h5 >> 16);
-    s[19] = (unsigned char) ((h5 >> 24) | (h6 << 1));
+    s[19] = (unsigned char) ((h5 >> 24) | shl32(h6, 1));
     s[20] = (unsigned char) (h6 >> 7);
     s[21] = (unsigned char) (h6 >> 15);
-    s[22] = (unsigned char) ((h6 >> 23) | (h7 << 3));
+    s[22] = (unsigned char) ((h6 >> 23) | shl32(h7, 3));
     s[23] = (unsigned char) (h7 >> 5);
     s[24] = (unsigned char) (h7 >> 13);
-    s[25] = (unsigned char) ((h7 >> 21) | (h8 << 4));
+    s[25] = (unsigned char) ((h7 >> 21) | shl32(h8, 4));
     s[26] = (unsigned char) (h8 >> 4);
     s[27] = (unsigned char) (h8 >> 12);
-    s[28] = (unsigned char) ((h8 >> 20) | (h9 << 6));
+    s[28] = (unsigned char) ((h8 >> 20) | shl32(h9, 6));
     s[29] = (unsigned char) (h9 >> 2);
     s[30] = (unsigned char) (h9 >> 10);
     s[31] = (unsigned char) (h9 >> 18);
index d03e4bd..8abced0 100644 (file)
@@ -4,6 +4,9 @@
     Not a compatible replacement for <stdint.h>, do not blindly use it as such.
 */
 
+#ifndef __TINC_FIXEDINT_H__
+#define __TINC_FIXEDINT_H__
+
 #if ((defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L) || (defined(__WATCOMC__) && (defined(_STDINT_H_INCLUDED) || __WATCOMC__ >= 1250)) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_) || defined(__UINT_FAST64_TYPE__)) )) && !defined(FIXEDINT_H_INCLUDED)
     #include <stdint.h>
     #define FIXEDINT_H_INCLUDED
         #define INT64_C(v) v ##I64
     #endif
 #endif
+
+static inline unsigned char shlu8(unsigned char a, uint32_t b) {
+       return a << b;
+}
+
+static inline int32_t shl32(uint32_t a, uint32_t b) {
+       return a << b;
+}
+
+static inline int64_t shl64(uint64_t a, uint32_t b) {
+       return a << b;
+}
+
+static inline uint64_t shlu64(uint64_t a, uint32_t b) {
+       return a << b;
+}
+
+#endif
index 3c342b1..9488218 100644 (file)
@@ -356,7 +356,7 @@ static void cmov(ge_precomp *t, ge_precomp *u, unsigned char b) {
 static void select(ge_precomp *t, int pos, signed char b) {
     ge_precomp minust;
     unsigned char bnegative = negative(b);
-    unsigned char babs = b - (((-bnegative) & b) << 1);
+    unsigned char babs = b - shlu8(((-bnegative) & b), 1);
     fe_1(t->yplusx);
     fe_1(t->yminusx);
     fe_0(t->xy2d);
@@ -404,7 +404,7 @@ void ge_scalarmult_base(ge_p3 *h, const unsigned char *a) {
         e[i] += carry;
         carry = e[i] + 8;
         carry >>= 4;
-        e[i] -= carry << 4;
+        e[i] -= shl32(carry, 4);
     }
 
     e[63] += carry;
index ca5bad2..42cfc2d 100644 (file)
@@ -4,9 +4,9 @@
 static uint64_t load_3(const unsigned char *in) {
     uint64_t result;
 
-    result = (uint64_t) in[0];
-    result |= ((uint64_t) in[1]) << 8;
-    result |= ((uint64_t) in[2]) << 16;
+    result = in[0];
+    result |= shlu64(in[1], 8);
+    result |= shlu64(in[2], 16);
 
     return result;
 }
@@ -14,10 +14,10 @@ static uint64_t load_3(const unsigned char *in) {
 static uint64_t load_4(const unsigned char *in) {
     uint64_t result;
 
-    result = (uint64_t) in[0];
-    result |= ((uint64_t) in[1]) << 8;
-    result |= ((uint64_t) in[2]) << 16;
-    result |= ((uint64_t) in[3]) << 24;
+    result = in[0];
+    result |= shlu64(in[1], 8);
+    result |= shlu64(in[2], 16);
+    result |= shlu64(in[3], 24);
     
     return result;
 }
@@ -119,37 +119,37 @@ void sc_reduce(unsigned char *s) {
     s18 = 0;
     carry6 = (s6 + (1 << 20)) >> 21;
     s7 += carry6;
-    s6 -= carry6 << 21;
+    s6 -= shl64(carry6, 21);
     carry8 = (s8 + (1 << 20)) >> 21;
     s9 += carry8;
-    s8 -= carry8 << 21;
+    s8 -= shl64(carry8, 21);
     carry10 = (s10 + (1 << 20)) >> 21;
     s11 += carry10;
-    s10 -= carry10 << 21;
+    s10 -= shl64(carry10, 21);
     carry12 = (s12 + (1 << 20)) >> 21;
     s13 += carry12;
-    s12 -= carry12 << 21;
+    s12 -= shl64(carry12, 21);
     carry14 = (s14 + (1 << 20)) >> 21;
     s15 += carry14;
-    s14 -= carry14 << 21;
+    s14 -= shl64(carry14, 21);
     carry16 = (s16 + (1 << 20)) >> 21;
     s17 += carry16;
-    s16 -= carry16 << 21;
+    s16 -= shl64(carry16, 21);
     carry7 = (s7 + (1 << 20)) >> 21;
     s8 += carry7;
-    s7 -= carry7 << 21;
+    s7 -= shl64(carry7, 21);
     carry9 = (s9 + (1 << 20)) >> 21;
     s10 += carry9;
-    s9 -= carry9 << 21;
+    s9 -= shl64(carry9, 21);
     carry11 = (s11 + (1 << 20)) >> 21;
     s12 += carry11;
-    s11 -= carry11 << 21;
+    s11 -= shl64(carry11, 21);
     carry13 = (s13 + (1 << 20)) >> 21;
     s14 += carry13;
-    s13 -= carry13 << 21;
+    s13 -= shl64(carry13, 21);
     carry15 = (s15 + (1 << 20)) >> 21;
     s16 += carry15;
-    s15 -= carry15 << 21;
+    s15 -= shl64(carry15, 21);
     s5 += s17 * 666643;
     s6 += s17 * 470296;
     s7 += s17 * 654183;
@@ -194,40 +194,40 @@ void sc_reduce(unsigned char *s) {
     s12 = 0;
     carry0 = (s0 + (1 << 20)) >> 21;
     s1 += carry0;
-    s0 -= carry0 << 21;
+    s0 -= shl64(carry0, 21);
     carry2 = (s2 + (1 << 20)) >> 21;
     s3 += carry2;
-    s2 -= carry2 << 21;
+    s2 -= shl64(carry2, 21);
     carry4 = (s4 + (1 << 20)) >> 21;
     s5 += carry4;
-    s4 -= carry4 << 21;
+    s4 -= shl64(carry4, 21);
     carry6 = (s6 + (1 << 20)) >> 21;
     s7 += carry6;
-    s6 -= carry6 << 21;
+    s6 -= shl64(carry6, 21);
     carry8 = (s8 + (1 << 20)) >> 21;
     s9 += carry8;
-    s8 -= carry8 << 21;
+    s8 -= shl64(carry8, 21);
     carry10 = (s10 + (1 << 20)) >> 21;
     s11 += carry10;
-    s10 -= carry10 << 21;
+    s10 -= shl64(carry10, 21);
     carry1 = (s1 + (1 << 20)) >> 21;
     s2 += carry1;
-    s1 -= carry1 << 21;
+    s1 -= shl64(carry1, 21);
     carry3 = (s3 + (1 << 20)) >> 21;
     s4 += carry3;
-    s3 -= carry3 << 21;
+    s3 -= shl64(carry3, 21);
     carry5 = (s5 + (1 << 20)) >> 21;
     s6 += carry5;
-    s5 -= carry5 << 21;
+    s5 -= shl64(carry5, 21);
     carry7 = (s7 + (1 << 20)) >> 21;
     s8 += carry7;
-    s7 -= carry7 << 21;
+    s7 -= shl64(carry7, 21);
     carry9 = (s9 + (1 << 20)) >> 21;
     s10 += carry9;
-    s9 -= carry9 << 21;
+    s9 -= shl64(carry9, 21);
     carry11 = (s11 + (1 << 20)) >> 21;
     s12 += carry11;
-    s11 -= carry11 << 21;
+    s11 -= shl64(carry11, 21);
     s0 += s12 * 666643;
     s1 += s12 * 470296;
     s2 += s12 * 654183;
@@ -237,40 +237,40 @@ void sc_reduce(unsigned char *s) {
     s12 = 0;
     carry0 = s0 >> 21;
     s1 += carry0;
-    s0 -= carry0 << 21;
+    s0 -= shl64(carry0, 21);
     carry1 = s1 >> 21;
     s2 += carry1;
-    s1 -= carry1 << 21;
+    s1 -= shl64(carry1, 21);
     carry2 = s2 >> 21;
     s3 += carry2;
-    s2 -= carry2 << 21;
+    s2 -= shl64(carry2, 21);
     carry3 = s3 >> 21;
     s4 += carry3;
-    s3 -= carry3 << 21;
+    s3 -= shl64(carry3, 21);
     carry4 = s4 >> 21;
     s5 += carry4;
-    s4 -= carry4 << 21;
+    s4 -= shl64(carry4, 21);
     carry5 = s5 >> 21;
     s6 += carry5;
-    s5 -= carry5 << 21;
+    s5 -= shl64(carry5, 21);
     carry6 = s6 >> 21;
     s7 += carry6;
-    s6 -= carry6 << 21;
+    s6 -= shl64(carry6, 21);
     carry7 = s7 >> 21;
     s8 += carry7;
-    s7 -= carry7 << 21;
+    s7 -= shl64(carry7, 21);
     carry8 = s8 >> 21;
     s9 += carry8;
-    s8 -= carry8 << 21;
+    s8 -= shl64(carry8, 21);
     carry9 = s9 >> 21;
     s10 += carry9;
-    s9 -= carry9 << 21;
+    s9 -= shl64(carry9, 21);
     carry10 = s10 >> 21;
     s11 += carry10;
-    s10 -= carry10 << 21;
+    s10 -= shl64(carry10, 21);
     carry11 = s11 >> 21;
     s12 += carry11;
-    s11 -= carry11 << 21;
+    s11 -= shl64(carry11, 21);
     s0 += s12 * 666643;
     s1 += s12 * 470296;
     s2 += s12 * 654183;
@@ -280,67 +280,67 @@ void sc_reduce(unsigned char *s) {
     s12 = 0;
     carry0 = s0 >> 21;
     s1 += carry0;
-    s0 -= carry0 << 21;
+    s0 -= shl64(carry0, 21);
     carry1 = s1 >> 21;
     s2 += carry1;
-    s1 -= carry1 << 21;
+    s1 -= shl64(carry1, 21);
     carry2 = s2 >> 21;
     s3 += carry2;
-    s2 -= carry2 << 21;
+    s2 -= shl64(carry2, 21);
     carry3 = s3 >> 21;
     s4 += carry3;
-    s3 -= carry3 << 21;
+    s3 -= shl64(carry3, 21);
     carry4 = s4 >> 21;
     s5 += carry4;
-    s4 -= carry4 << 21;
+    s4 -= shl64(carry4, 21);
     carry5 = s5 >> 21;
     s6 += carry5;
-    s5 -= carry5 << 21;
+    s5 -= shl64(carry5, 21);
     carry6 = s6 >> 21;
     s7 += carry6;
-    s6 -= carry6 << 21;
+    s6 -= shl64(carry6, 21);
     carry7 = s7 >> 21;
     s8 += carry7;
-    s7 -= carry7 << 21;
+    s7 -= shl64(carry7, 21);
     carry8 = s8 >> 21;
     s9 += carry8;
-    s8 -= carry8 << 21;
+    s8 -= shl64(carry8, 21);
     carry9 = s9 >> 21;
     s10 += carry9;
-    s9 -= carry9 << 21;
+    s9 -= shl64(carry9, 21);
     carry10 = s10 >> 21;
     s11 += carry10;
-    s10 -= carry10 << 21;
+    s10 -= shl64(carry10, 21);
 
     s[0] = (unsigned char) (s0 >> 0);
     s[1] = (unsigned char) (s0 >> 8);
-    s[2] = (unsigned char) ((s0 >> 16) | (s1 << 5));
+    s[2] = (unsigned char) ((s0 >> 16) | shl64(s1, 5));
     s[3] = (unsigned char) (s1 >> 3);
     s[4] = (unsigned char) (s1 >> 11);
-    s[5] = (unsigned char) ((s1 >> 19) | (s2 << 2));
+    s[5] = (unsigned char) ((s1 >> 19) | shl64(s2, 2));
     s[6] = (unsigned char) (s2 >> 6);
-    s[7] = (unsigned char) ((s2 >> 14) | (s3 << 7));
+    s[7] = (unsigned char) ((s2 >> 14) | shl64(s3, 7));
     s[8] = (unsigned char) (s3 >> 1);
     s[9] = (unsigned char) (s3 >> 9);
-    s[10] = (unsigned char) ((s3 >> 17) | (s4 << 4));
+    s[10] = (unsigned char) ((s3 >> 17) | shl64(s4, 4));
     s[11] = (unsigned char) (s4 >> 4);
     s[12] = (unsigned char) (s4 >> 12);
-    s[13] = (unsigned char) ((s4 >> 20) | (s5 << 1));
+    s[13] = (unsigned char) ((s4 >> 20) | shl64(s5, 1));
     s[14] = (unsigned char) (s5 >> 7);
-    s[15] = (unsigned char) ((s5 >> 15) | (s6 << 6));
+    s[15] = (unsigned char) ((s5 >> 15) | shl64(s6, 6));
     s[16] = (unsigned char) (s6 >> 2);
     s[17] = (unsigned char) (s6 >> 10);
-    s[18] = (unsigned char) ((s6 >> 18) | (s7 << 3));
+    s[18] = (unsigned char) ((s6 >> 18) | shl64(s7, 3));
     s[19] = (unsigned char) (s7 >> 5);
     s[20] = (unsigned char) (s7 >> 13);
     s[21] = (unsigned char) (s8 >> 0);
     s[22] = (unsigned char) (s8 >> 8);
-    s[23] = (unsigned char) ((s8 >> 16) | (s9 << 5));
+    s[23] = (unsigned char) ((s8 >> 16) | shl64(s9, 5));
     s[24] = (unsigned char) (s9 >> 3);
     s[25] = (unsigned char) (s9 >> 11);
-    s[26] = (unsigned char) ((s9 >> 19) | (s10 << 2));
+    s[26] = (unsigned char) ((s9 >> 19) | shl64(s10, 2));
     s[27] = (unsigned char) (s10 >> 6);
-    s[28] = (unsigned char) ((s10 >> 14) | (s11 << 7));
+    s[28] = (unsigned char) ((s10 >> 14) | shl64(s11, 7));
     s[29] = (unsigned char) (s11 >> 1);
     s[30] = (unsigned char) (s11 >> 9);
     s[31] = (unsigned char) (s11 >> 17);
@@ -470,73 +470,73 @@ void sc_muladd(unsigned char *s, const unsigned char *a, const unsigned char *b,
     s23 = 0;
     carry0 = (s0 + (1 << 20)) >> 21;
     s1 += carry0;
-    s0 -= carry0 << 21;
+    s0 -= shl64(carry0, 21);
     carry2 = (s2 + (1 << 20)) >> 21;
     s3 += carry2;
-    s2 -= carry2 << 21;
+    s2 -= shl64(carry2, 21);
     carry4 = (s4 + (1 << 20)) >> 21;
     s5 += carry4;
-    s4 -= carry4 << 21;
+    s4 -= shl64(carry4, 21);
     carry6 = (s6 + (1 << 20)) >> 21;
     s7 += carry6;
-    s6 -= carry6 << 21;
+    s6 -= shl64(carry6, 21);
     carry8 = (s8 + (1 << 20)) >> 21;
     s9 += carry8;
-    s8 -= carry8 << 21;
+    s8 -= shl64(carry8, 21);
     carry10 = (s10 + (1 << 20)) >> 21;
     s11 += carry10;
-    s10 -= carry10 << 21;
+    s10 -= shl64(carry10, 21);
     carry12 = (s12 + (1 << 20)) >> 21;
     s13 += carry12;
-    s12 -= carry12 << 21;
+    s12 -= shl64(carry12, 21);
     carry14 = (s14 + (1 << 20)) >> 21;
     s15 += carry14;
-    s14 -= carry14 << 21;
+    s14 -= shl64(carry14, 21);
     carry16 = (s16 + (1 << 20)) >> 21;
     s17 += carry16;
-    s16 -= carry16 << 21;
+    s16 -= shl64(carry16, 21);
     carry18 = (s18 + (1 << 20)) >> 21;
     s19 += carry18;
-    s18 -= carry18 << 21;
+    s18 -= shl64(carry18, 21);
     carry20 = (s20 + (1 << 20)) >> 21;
     s21 += carry20;
-    s20 -= carry20 << 21;
+    s20 -= shl64(carry20, 21);
     carry22 = (s22 + (1 << 20)) >> 21;
     s23 += carry22;
-    s22 -= carry22 << 21;
+    s22 -= shl64(carry22, 21);
     carry1 = (s1 + (1 << 20)) >> 21;
     s2 += carry1;
-    s1 -= carry1 << 21;
+    s1 -= shl64(carry1, 21);
     carry3 = (s3 + (1 << 20)) >> 21;
     s4 += carry3;
-    s3 -= carry3 << 21;
+    s3 -= shl64(carry3, 21);
     carry5 = (s5 + (1 << 20)) >> 21;
     s6 += carry5;
-    s5 -= carry5 << 21;
+    s5 -= shl64(carry5, 21);
     carry7 = (s7 + (1 << 20)) >> 21;
     s8 += carry7;
-    s7 -= carry7 << 21;
+    s7 -= shl64(carry7, 21);
     carry9 = (s9 + (1 << 20)) >> 21;
     s10 += carry9;
-    s9 -= carry9 << 21;
+    s9 -= shl64(carry9, 21);
     carry11 = (s11 + (1 << 20)) >> 21;
     s12 += carry11;
-    s11 -= carry11 << 21;
+    s11 -= shl64(carry11, 21);
     carry13 = (s13 + (1 << 20)) >> 21;
     s14 += carry13;
-    s13 -= carry13 << 21;
+    s13 -= shl64(carry13, 21);
     carry15 = (s15 + (1 << 20)) >> 21;
     s16 += carry15;
-    s15 -= carry15 << 21;
+    s15 -= shl64(carry15, 21);
     carry17 = (s17 + (1 << 20)) >> 21;
     s18 += carry17;
-    s17 -= carry17 << 21;
+    s17 -= shl64(carry17, 21);
     carry19 = (s19 + (1 << 20)) >> 21;
     s20 += carry19;
-    s19 -= carry19 << 21;
+    s19 -= shl64(carry19, 21);
     carry21 = (s21 + (1 << 20)) >> 21;
     s22 += carry21;
-    s21 -= carry21 << 21;
+    s21 -= shl64(carry21, 21);
     s11 += s23 * 666643;
     s12 += s23 * 470296;
     s13 += s23 * 654183;
@@ -581,37 +581,37 @@ void sc_muladd(unsigned char *s, const unsigned char *a, const unsigned char *b,
     s18 = 0;
     carry6 = (s6 + (1 << 20)) >> 21;
     s7 += carry6;
-    s6 -= carry6 << 21;
+    s6 -= shl64(carry6, 21);
     carry8 = (s8 + (1 << 20)) >> 21;
     s9 += carry8;
-    s8 -= carry8 << 21;
+    s8 -= shl64(carry8, 21);
     carry10 = (s10 + (1 << 20)) >> 21;
     s11 += carry10;
-    s10 -= carry10 << 21;
+    s10 -= shl64(carry10, 21);
     carry12 = (s12 + (1 << 20)) >> 21;
     s13 += carry12;
-    s12 -= carry12 << 21;
+    s12 -= shl64(carry12, 21);
     carry14 = (s14 + (1 << 20)) >> 21;
     s15 += carry14;
-    s14 -= carry14 << 21;
+    s14 -= shl64(carry14, 21);
     carry16 = (s16 + (1 << 20)) >> 21;
     s17 += carry16;
-    s16 -= carry16 << 21;
+    s16 -= shl64(carry16, 21);
     carry7 = (s7 + (1 << 20)) >> 21;
     s8 += carry7;
-    s7 -= carry7 << 21;
+    s7 -= shl64(carry7, 21);
     carry9 = (s9 + (1 << 20)) >> 21;
     s10 += carry9;
-    s9 -= carry9 << 21;
+    s9 -= shl64(carry9, 21);
     carry11 = (s11 + (1 << 20)) >> 21;
     s12 += carry11;
-    s11 -= carry11 << 21;
+    s11 -= shl64(carry11, 21);
     carry13 = (s13 + (1 << 20)) >> 21;
     s14 += carry13;
-    s13 -= carry13 << 21;
+    s13 -= shl64(carry13, 21);
     carry15 = (s15 + (1 << 20)) >> 21;
     s16 += carry15;
-    s15 -= carry15 << 21;
+    s15 -= shl64(carry15, 21);
     s5 += s17 * 666643;
     s6 += s17 * 470296;
     s7 += s17 * 654183;
@@ -656,40 +656,40 @@ void sc_muladd(unsigned char *s, const unsigned char *a, const unsigned char *b,
     s12 = 0;
     carry0 = (s0 + (1 << 20)) >> 21;
     s1 += carry0;
-    s0 -= carry0 << 21;
+    s0 -= shl64(carry0, 21);
     carry2 = (s2 + (1 << 20)) >> 21;
     s3 += carry2;
-    s2 -= carry2 << 21;
+    s2 -= shl64(carry2, 21);
     carry4 = (s4 + (1 << 20)) >> 21;
     s5 += carry4;
-    s4 -= carry4 << 21;
+    s4 -= shl64(carry4, 21);
     carry6 = (s6 + (1 << 20)) >> 21;
     s7 += carry6;
-    s6 -= carry6 << 21;
+    s6 -= shl64(carry6, 21);
     carry8 = (s8 + (1 << 20)) >> 21;
     s9 += carry8;
-    s8 -= carry8 << 21;
+    s8 -= shl64(carry8, 21);
     carry10 = (s10 + (1 << 20)) >> 21;
     s11 += carry10;
-    s10 -= carry10 << 21;
+    s10 -= shl64(carry10, 21);
     carry1 = (s1 + (1 << 20)) >> 21;
     s2 += carry1;
-    s1 -= carry1 << 21;
+    s1 -= shl64(carry1, 21);
     carry3 = (s3 + (1 << 20)) >> 21;
     s4 += carry3;
-    s3 -= carry3 << 21;
+    s3 -= shl64(carry3, 21);
     carry5 = (s5 + (1 << 20)) >> 21;
     s6 += carry5;
-    s5 -= carry5 << 21;
+    s5 -= shl64(carry5, 21);
     carry7 = (s7 + (1 << 20)) >> 21;
     s8 += carry7;
-    s7 -= carry7 << 21;
+    s7 -= shl64(carry7, 21);
     carry9 = (s9 + (1 << 20)) >> 21;
     s10 += carry9;
-    s9 -= carry9 << 21;
+    s9 -= shl64(carry9, 21);
     carry11 = (s11 + (1 << 20)) >> 21;
     s12 += carry11;
-    s11 -= carry11 << 21;
+    s11 -= shl64(carry11, 21);
     s0 += s12 * 666643;
     s1 += s12 * 470296;
     s2 += s12 * 654183;
@@ -699,40 +699,40 @@ void sc_muladd(unsigned char *s, const unsigned char *a, const unsigned char *b,
     s12 = 0;
     carry0 = s0 >> 21;
     s1 += carry0;
-    s0 -= carry0 << 21;
+    s0 -= shl64(carry0, 21);
     carry1 = s1 >> 21;
     s2 += carry1;
-    s1 -= carry1 << 21;
+    s1 -= shl64(carry1, 21);
     carry2 = s2 >> 21;
     s3 += carry2;
-    s2 -= carry2 << 21;
+    s2 -= shl64(carry2, 21);
     carry3 = s3 >> 21;
     s4 += carry3;
-    s3 -= carry3 << 21;
+    s3 -= shl64(carry3, 21);
     carry4 = s4 >> 21;
     s5 += carry4;
-    s4 -= carry4 << 21;
+    s4 -= shl64(carry4, 21);
     carry5 = s5 >> 21;
     s6 += carry5;
-    s5 -= carry5 << 21;
+    s5 -= shl64(carry5, 21);
     carry6 = s6 >> 21;
     s7 += carry6;
-    s6 -= carry6 << 21;
+    s6 -= shl64(carry6, 21);
     carry7 = s7 >> 21;
     s8 += carry7;
-    s7 -= carry7 << 21;
+    s7 -= shl64(carry7, 21);
     carry8 = s8 >> 21;
     s9 += carry8;
-    s8 -= carry8 << 21;
+    s8 -= shl64(carry8, 21);
     carry9 = s9 >> 21;
     s10 += carry9;
-    s9 -= carry9 << 21;
+    s9 -= shl64(carry9, 21);
     carry10 = s10 >> 21;
     s11 += carry10;
-    s10 -= carry10 << 21;
+    s10 -= shl64(carry10, 21);
     carry11 = s11 >> 21;
     s12 += carry11;
-    s11 -= carry11 << 21;
+    s11 -= shl64(carry11, 21);
     s0 += s12 * 666643;
     s1 += s12 * 470296;
     s2 += s12 * 654183;
@@ -742,67 +742,67 @@ void sc_muladd(unsigned char *s, const unsigned char *a, const unsigned char *b,
     s12 = 0;
     carry0 = s0 >> 21;
     s1 += carry0;
-    s0 -= carry0 << 21;
+    s0 -= shl64(carry0, 21);
     carry1 = s1 >> 21;
     s2 += carry1;
-    s1 -= carry1 << 21;
+    s1 -= shl64(carry1, 21);
     carry2 = s2 >> 21;
     s3 += carry2;
-    s2 -= carry2 << 21;
+    s2 -= shl64(carry2, 21);
     carry3 = s3 >> 21;
     s4 += carry3;
-    s3 -= carry3 << 21;
+    s3 -= shl64(carry3, 21);
     carry4 = s4 >> 21;
     s5 += carry4;
-    s4 -= carry4 << 21;
+    s4 -= shl64(carry4, 21);
     carry5 = s5 >> 21;
     s6 += carry5;
-    s5 -= carry5 << 21;
+    s5 -= shl64(carry5, 21);
     carry6 = s6 >> 21;
     s7 += carry6;
-    s6 -= carry6 << 21;
+    s6 -= shl64(carry6, 21);
     carry7 = s7 >> 21;
     s8 += carry7;
-    s7 -= carry7 << 21;
+    s7 -= shl64(carry7, 21);
     carry8 = s8 >> 21;
     s9 += carry8;
-    s8 -= carry8 << 21;
+    s8 -= shl64(carry8, 21);
     carry9 = s9 >> 21;
     s10 += carry9;
-    s9 -= carry9 << 21;
+    s9 -= shl64(carry9, 21);
     carry10 = s10 >> 21;
     s11 += carry10;
-    s10 -= carry10 << 21;
+    s10 -= shl64(carry10, 21);
     
     s[0] = (unsigned char) (s0 >> 0);
     s[1] = (unsigned char) (s0 >> 8);
-    s[2] = (unsigned char) ((s0 >> 16) | (s1 << 5));
+    s[2] = (unsigned char) ((s0 >> 16) | shl64(s1, 5));
     s[3] = (unsigned char) (s1 >> 3);
     s[4] = (unsigned char) (s1 >> 11);
-    s[5] = (unsigned char) ((s1 >> 19) | (s2 << 2));
+    s[5] = (unsigned char) ((s1 >> 19) | shl64(s2, 2));
     s[6] = (unsigned char) (s2 >> 6);
-    s[7] = (unsigned char) ((s2 >> 14) | (s3 << 7));
+    s[7] = (unsigned char) ((s2 >> 14) | shl64(s3, 7));
     s[8] = (unsigned char) (s3 >> 1);
     s[9] = (unsigned char) (s3 >> 9);
-    s[10] = (unsigned char) ((s3 >> 17) | (s4 << 4));
+    s[10] = (unsigned char) ((s3 >> 17) | shl64(s4, 4));
     s[11] = (unsigned char) (s4 >> 4);
     s[12] = (unsigned char) (s4 >> 12);
-    s[13] = (unsigned char) ((s4 >> 20) | (s5 << 1));
+    s[13] = (unsigned char) ((s4 >> 20) | shl64(s5, 1));
     s[14] = (unsigned char) (s5 >> 7);
-    s[15] = (unsigned char) ((s5 >> 15) | (s6 << 6));
+    s[15] = (unsigned char) ((s5 >> 15) | shl64(s6, 6));
     s[16] = (unsigned char) (s6 >> 2);
     s[17] = (unsigned char) (s6 >> 10);
-    s[18] = (unsigned char) ((s6 >> 18) | (s7 << 3));
+    s[18] = (unsigned char) ((s6 >> 18) | shl64(s7, 3));
     s[19] = (unsigned char) (s7 >> 5);
     s[20] = (unsigned char) (s7 >> 13);
     s[21] = (unsigned char) (s8 >> 0);
     s[22] = (unsigned char) (s8 >> 8);
-    s[23] = (unsigned char) ((s8 >> 16) | (s9 << 5));
+    s[23] = (unsigned char) ((s8 >> 16) | shl64(s9, 5));
     s[24] = (unsigned char) (s9 >> 3);
     s[25] = (unsigned char) (s9 >> 11);
-    s[26] = (unsigned char) ((s9 >> 19) | (s10 << 2));
+    s[26] = (unsigned char) ((s9 >> 19) | shl64(s10, 2));
     s[27] = (unsigned char) (s10 >> 6);
-    s[28] = (unsigned char) ((s10 >> 14) | (s11 << 7));
+    s[28] = (unsigned char) ((s10 >> 14) | shl64(s11, 7));
     s[29] = (unsigned char) (s11 >> 1);
     s[30] = (unsigned char) (s11 >> 9);
     s[31] = (unsigned char) (s11 >> 17);
index fc5720a..f6c19b7 100644 (file)
@@ -1252,8 +1252,12 @@ void send_packet(node_t *n, vpn_packet_t *packet) {
        // If it's for myself, write it to the tun/tap device.
 
        if(n == myself) {
-               if(overwrite_mac)
+               if(overwrite_mac) {
                         memcpy(DATA(packet), mymac.x, ETH_ALEN);
+                        // Use an arbitrary fake source address.
+                        memcpy(DATA(packet) + ETH_ALEN, DATA(packet), ETH_ALEN);
+                        DATA(packet)[ETH_ALEN * 2 - 1] ^= 0xFF;
+               }
                n->out_packets++;
                n->out_bytes += packet->len;
                devops.write(packet);
@@ -1389,42 +1393,27 @@ static node_t *try_harder(const sockaddr_t *from, const vpn_packet_t *pkt) {
        return match;
 }
 
-void handle_incoming_vpn_data(void *data, int flags) {
-       listen_socket_t *ls = data;
-       vpn_packet_t pkt;
+static void handle_incoming_vpn_packet(listen_socket_t *ls, vpn_packet_t *pkt, sockaddr_t *addr) {
        char *hostname;
        node_id_t nullid = {};
-       sockaddr_t addr = {};
-       socklen_t addrlen = sizeof addr;
        node_t *from, *to;
        bool direct = false;
 
-       pkt.offset = 0;
-       int len = recvfrom(ls->udp.fd, DATA(&pkt), MAXSIZE, 0, &addr.sa, &addrlen);
-
-       if(len <= 0 || len > MAXSIZE) {
-               if(!sockwouldblock(sockerrno))
-                       logger(DEBUG_ALWAYS, LOG_ERR, "Receiving packet failed: %s", sockstrerror(sockerrno));
-               return;
-       }
-
-       pkt.len = len;
-
-       sockaddrunmap(&addr); /* Some braindead IPv6 implementations do stupid things. */
+       sockaddrunmap(addr); /* Some braindead IPv6 implementations do stupid things. */
 
        // Try to figure out who sent this packet.
 
-       node_t *n = lookup_node_udp(&addr);
+       node_t *n = lookup_node_udp(addr);
 
        if(n && !n->status.udp_confirmed)
                n = NULL; // Don't believe it if we don't have confirmation yet.
 
        if(!n) {
                // It might be from a 1.1 node, which might have a source ID in the packet.
-               pkt.offset = 2 * sizeof(node_id_t);
-               from = lookup_node_id(SRCID(&pkt));
-               if(from && !memcmp(DSTID(&pkt), &nullid, sizeof nullid) && from->status.sptps) {
-                       if(sptps_verify_datagram(&from->sptps, DATA(&pkt), pkt.len - 2 * sizeof(node_id_t)))
+               pkt->offset = 2 * sizeof(node_id_t);
+               from = lookup_node_id(SRCID(pkt));
+               if(from && !memcmp(DSTID(pkt), &nullid, sizeof nullid) && from->status.sptps) {
+                       if(sptps_verify_datagram(&from->sptps, DATA(pkt), pkt->len - 2 * sizeof(node_id_t)))
                                n = from;
                        else
                                goto skip_harder;
@@ -1432,36 +1421,36 @@ void handle_incoming_vpn_data(void *data, int flags) {
        }
 
        if(!n) {
-               pkt.offset = 0;
-               n = try_harder(&addr, &pkt);
+               pkt->offset = 0;
+               n = try_harder(addr, pkt);
        }
 
 skip_harder:
        if(!n) {
                if(debug_level >= DEBUG_PROTOCOL) {
-                       hostname = sockaddr2hostname(&addr);
+                       hostname = sockaddr2hostname(addr);
                        logger(DEBUG_PROTOCOL, LOG_WARNING, "Received UDP packet from unknown source %s", hostname);
                        free(hostname);
                }
                return;
        }
 
-       pkt.offset = 0;
+       pkt->offset = 0;
 
        if(n->status.sptps) {
                bool relay_enabled = (n->options >> 24) >= 4;
                if (relay_enabled) {
-                       pkt.offset = 2 * sizeof(node_id_t);
-                       pkt.len -= pkt.offset;
+                       pkt->offset = 2 * sizeof(node_id_t);
+                       pkt->len -= pkt->offset;
                }
 
-               if(!memcmp(DSTID(&pkt), &nullid, sizeof nullid) || !relay_enabled) {
+               if(!memcmp(DSTID(pkt), &nullid, sizeof nullid) || !relay_enabled) {
                        direct = true;
                        from = n;
                        to = myself;
                } else {
-                       from = lookup_node_id(SRCID(&pkt));
-                       to = lookup_node_id(DSTID(&pkt));
+                       from = lookup_node_id(SRCID(pkt));
+                       to = lookup_node_id(DSTID(pkt));
                }
                if(!from || !to) {
                        logger(DEBUG_PROTOCOL, LOG_WARNING, "Received UDP packet from %s (%s) with unknown source and/or destination ID", n->name, n->hostname);
@@ -1487,7 +1476,7 @@ skip_harder:
                /* If we're not the final recipient, relay the packet. */
 
                if(to != myself) {
-                       send_sptps_data(to, from, 0, DATA(&pkt), pkt.len);
+                       send_sptps_data(to, from, 0, DATA(pkt), pkt->len);
                        try_tx(to, true);
                        return;
                }
@@ -1496,12 +1485,12 @@ skip_harder:
                from = n;
        }
 
-       if(!receive_udppacket(from, &pkt))
+       if(!receive_udppacket(from, pkt))
                return;
 
        n->sock = ls - listen_socket;
-       if(direct && sockaddrcmp(&addr, &n->address))
-               update_node_udp(n, &addr);
+       if(direct && sockaddrcmp(addr, &n->address))
+               update_node_udp(n, addr);
 
        /* If the packet went through a relay, help the sender find the appropriate MTU
           through the relay path. */
@@ -1510,6 +1499,67 @@ skip_harder:
                send_mtu_info(myself, n, MTU);
 }
 
+void handle_incoming_vpn_data(void *data, int flags) {
+       listen_socket_t *ls = data;
+
+#ifdef HAVE_RECVMMSG
+#define MAX_MSG 64
+       static int num = MAX_MSG;
+       static vpn_packet_t pkt[MAX_MSG];
+       static sockaddr_t addr[MAX_MSG];
+       static struct mmsghdr msg[MAX_MSG];
+       static struct iovec iov[MAX_MSG];
+
+       for(int i = 0; i < num; i++) {
+               pkt[i].offset = 0;
+
+               iov[i] = (struct iovec){
+                       .iov_base = DATA(&pkt[i]),
+                       .iov_len = MAXSIZE,
+               };
+
+               msg[i].msg_hdr = (struct msghdr){
+                       .msg_name = &addr[i].sa,
+                       .msg_namelen = sizeof addr[i],
+                       .msg_iov = &iov[i],
+                       .msg_iovlen = 1,
+               };
+       }
+
+       num = recvmmsg(ls->udp.fd, msg, MAX_MSG, MSG_DONTWAIT, NULL);
+
+       if(num < 0) {
+               if(!sockwouldblock(sockerrno))
+                       logger(DEBUG_ALWAYS, LOG_ERR, "Receiving packet failed: %s", sockstrerror(sockerrno));
+               return;
+       }
+
+       for(int i = 0; i < num; i++) {
+               pkt[i].len = msg[i].msg_len;
+               if(pkt[i].len <= 0 || pkt[i].len > MAXSIZE)
+                       continue;
+               handle_incoming_vpn_packet(ls, &pkt[i], &addr[i]);
+       }
+#else
+       vpn_packet_t pkt;
+       sockaddr_t addr = {};
+       socklen_t addrlen = sizeof addr;
+
+       pkt.offset = 0;
+       int len = recvfrom(ls->udp.fd, DATA(&pkt), MAXSIZE, 0, &addr.sa, &addrlen);
+
+       if(len <= 0 || len > MAXSIZE) {
+               if(!sockwouldblock(sockerrno))
+                       logger(DEBUG_ALWAYS, LOG_ERR, "Receiving packet failed: %s", sockstrerror(sockerrno));
+               return;
+       }
+
+       pkt.len = len;
+
+       handle_incoming_vpn_packet(ls, &pkt, &addr);
+#endif
+}
+
 void handle_device_data(void *data, int flags) {
        vpn_packet_t packet;
        packet.offset = DEFAULT_PACKET_OFFSET;
index 23dd252..38fed52 100644 (file)
 #include "utils.h"
 #include "xalloc.h"
 
+#ifdef HAVE_MINIUPNPC
+#include "upnp.h"
+#endif
+
 char *myport;
 static char *myname;
 static io_t device_io;
@@ -1059,6 +1063,25 @@ static bool setup_myself(void) {
        xasprintf(&myself->hostname, "MYSELF port %s", myport);
        myself->connection->hostname = xstrdup(myself->hostname);
 
+       char *upnp = NULL;
+       get_config_string(lookup_config(config_tree, "UPnP"), &upnp);
+       bool upnp_tcp = false;
+       bool upnp_udp = false;
+       if (upnp) {
+               if (!strcasecmp(upnp, "yes"))
+                       upnp_tcp = upnp_udp = true;
+               else if (!strcasecmp(upnp, "udponly"))
+                       upnp_udp = true;
+               free(upnp);
+       }
+       if (upnp_tcp || upnp_udp) {
+#ifdef HAVE_MINIUPNPC
+               upnp_init(upnp_tcp, upnp_udp);
+#else
+               logger(DEBUG_ALWAYS, LOG_WARNING, "UPnP was requested, but tinc isn't built with miniupnpc support!");
+#endif
+       }
+
        /* Done. */
 
        last_config_check = now.tv_sec;
index 97d6c44..767e91e 100644 (file)
@@ -604,9 +604,12 @@ void setup_outgoing_connection(outgoing_t *outgoing) {
 
        if(n && n->connection) {
                logger(DEBUG_CONNECTIONS, LOG_INFO, "Already connected to %s", outgoing->name);
-
-               n->connection->outgoing = outgoing;
-               return;
+               if(!n->connection->outgoing) {
+                       n->connection->outgoing = outgoing;
+                       return;
+               } else {
+                       goto remove;
+               }
        }
 
        init_configuration(&outgoing->config_tree);
@@ -618,11 +621,15 @@ void setup_outgoing_connection(outgoing_t *outgoing) {
                        outgoing->aip = outgoing->ai = get_known_addresses(n);
                if(!outgoing->ai) {
                        logger(DEBUG_ALWAYS, LOG_DEBUG, "No address known for %s", outgoing->name);
-                       return;
+                       goto remove;
                }
        }
 
        do_outgoing_connection(outgoing);
+       return;
+
+remove:
+       list_delete(outgoing_list, outgoing);
 }
 
 /*
index fb4b7eb..bd94ed0 100644 (file)
@@ -34,8 +34,7 @@
 
 splay_tree_t *node_tree;
 static splay_tree_t *node_id_tree;
-static hash_t *node_udp_cache;
-static hash_t *node_id_cache;
+static splay_tree_t *node_udp_tree;
 
 node_t *myself;
 
@@ -47,16 +46,21 @@ static int node_id_compare(const node_t *a, const node_t *b) {
        return memcmp(&a->id, &b->id, sizeof(node_id_t));
 }
 
+static int node_udp_compare(const node_t *a, const node_t *b) {
+       int result = sockaddrcmp(&a->address, &b->address);
+       if (result)
+               return result;
+       return (a->name && b->name) ? strcmp(a->name, b->name) : 0;
+}
+
 void init_nodes(void) {
        node_tree = splay_alloc_tree((splay_compare_t) node_compare, (splay_action_t) free_node);
        node_id_tree = splay_alloc_tree((splay_compare_t) node_id_compare, NULL);
-       node_udp_cache = hash_alloc(0x100, sizeof(sockaddr_t));
-       node_id_cache = hash_alloc(0x100, sizeof(node_id_t));
+       node_udp_tree = splay_alloc_tree((splay_compare_t) node_udp_compare, NULL);
 }
 
 void exit_nodes(void) {
-       hash_free(node_id_cache);
-       hash_free(node_udp_cache);
+       splay_delete_tree(node_udp_tree);
        splay_delete_tree(node_id_tree);
        splay_delete_tree(node_tree);
 }
@@ -116,8 +120,7 @@ void node_add(node_t *n) {
 }
 
 void node_del(node_t *n) {
-       hash_delete(node_udp_cache, &n->address);
-       hash_delete(node_id_cache, &n->id);
+       splay_delete(node_udp_tree, n);
 
        for splay_each(subnet_t, s, n->subnet_tree)
                subnet_del(n, s);
@@ -138,19 +141,13 @@ node_t *lookup_node(char *name) {
 }
 
 node_t *lookup_node_id(const node_id_t *id) {
-       node_t *n = hash_search(node_id_cache, id);
-       if(!n) {
-               node_t tmp = {.id = *id};
-               n = splay_search(node_id_tree, &tmp);
-               if(n)
-                       hash_insert(node_id_cache, id, n);
-       }
-
-       return n;
+       node_t n = {.id = *id};
+       return splay_search(node_id_tree, &n);
 }
 
 node_t *lookup_node_udp(const sockaddr_t *sa) {
-       return hash_search(node_udp_cache, sa);
+       node_t tmp = {.address = *sa};
+       return splay_search(node_udp_tree, &tmp);
 }
 
 void update_node_udp(node_t *n, const sockaddr_t *sa) {
@@ -159,7 +156,7 @@ void update_node_udp(node_t *n, const sockaddr_t *sa) {
                return;
        }
 
-       hash_delete(node_udp_cache, &n->address);
+       splay_delete(node_udp_tree, n);
 
        if(sa) {
                n->address = *sa;
@@ -170,7 +167,7 @@ void update_node_udp(node_t *n, const sockaddr_t *sa) {
                                break;
                        }
                }
-               hash_insert(node_udp_cache, sa, n);
+               splay_insert(node_udp_tree, n);
                free(n->hostname);
                n->hostname = sockaddr2hostname(&n->address);
                logger(DEBUG_PROTOCOL, LOG_DEBUG, "UDP address of %s set to %s", n->name, n->hostname);
index b409a35..d24d4ac 100644 (file)
@@ -400,7 +400,7 @@ bool ans_key_h(connection_t *c, const char *request) {
                        return true;
                }
 
-               if(!*address && from->address.sa.sa_family != AF_UNSPEC) {
+               if(!*address && from->address.sa.sa_family != AF_UNSPEC && to->minmtu) {
                        char *address, *port;
                        logger(DEBUG_PROTOCOL, LOG_DEBUG, "Appending reflexive UDP address to ANS_KEY from %s to %s", from->name, to->name);
                        sockaddr2str(&from->address, &address, &port);
@@ -418,7 +418,7 @@ bool ans_key_h(connection_t *c, const char *request) {
        cipher_close(from->outcipher);
        digest_close(from->outdigest);
 #endif
-       from->status.validkey = false;
+       if (!from->status.sptps) from->status.validkey = false;
 
        if(compression < 0 || compression > 11) {
                logger(DEBUG_ALWAYS, LOG_ERR, "Node %s (%s) uses bogus compression level!", from->name, from->hostname);
index 70c5806..68a6649 100644 (file)
@@ -784,15 +784,13 @@ static void route_arp(node_t *source, vpn_packet_t *packet) {
        if(subnet->owner == myself)
                return;                                          /* silently ignore */
 
-       memcpy(DATA(packet), DATA(packet) + ETH_ALEN, ETH_ALEN); /* copy destination address */
-       DATA(packet)[ETH_ALEN * 2 - 1] ^= 0xFF;                  /* mangle source address so it looks like it's not from us */
-
        memcpy(&addr, arp.arp_tpa, sizeof addr);                 /* save protocol addr */
        memcpy(arp.arp_tpa, arp.arp_spa, sizeof addr);           /* swap destination and source protocol address */
        memcpy(arp.arp_spa, &addr, sizeof addr);                 /* ... */
 
        memcpy(arp.arp_tha, arp.arp_sha, ETH_ALEN);              /* set target hard/proto addr */
-       memcpy(arp.arp_sha, DATA(packet) + ETH_ALEN, ETH_ALEN);  /* add fake source hard addr */
+       memcpy(arp.arp_sha, DATA(packet) + ETH_ALEN, ETH_ALEN);  /* set source hard/proto addr */
+       arp.arp_sha[ETH_ALEN - 1] ^= 0xFF;                       /* for consistency with route_packet() */
        arp.arp_op = htons(ARPOP_REPLY);
 
        /* Copy structs on stack back to packet */
index abc5c09..6c54eff 100644 (file)
@@ -1481,6 +1481,9 @@ const var_t variables[] = {
        {"UDPInfoInterval", VAR_SERVER},
        {"UDPRcvBuf", VAR_SERVER},
        {"UDPSndBuf", VAR_SERVER},
+       {"UPnP", VAR_SERVER},
+       {"UPnPDiscoverWait", VAR_SERVER},
+       {"UPnPRefreshPeriod", VAR_SERVER},
        {"VDEGroup", VAR_SERVER},
        {"VDEPort", VAR_SERVER},
        /* Host configuration */
diff --git a/src/upnp.c b/src/upnp.c
new file mode 100644 (file)
index 0000000..abd2f92
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+    upnp.c -- UPnP-IGD client
+    Copyright (C) 2015 Guus Sliepen <guus@tinc-vpn.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 2 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, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "upnp.h"
+
+#include <pthread.h>
+
+#include "miniupnpc/miniupnpc.h"
+#include "miniupnpc/upnpcommands.h"
+#include "miniupnpc/upnperrors.h"
+
+#include "system.h"
+#include "logger.h"
+#include "names.h"
+#include "net.h"
+#include "netutl.h"
+#include "utils.h"
+
+static bool upnp_tcp;
+static bool upnp_udp;
+static int upnp_discover_wait = 5;
+static int upnp_refresh_period = 60;
+
+// Unfortunately, libminiupnpc devs don't seem to care about API compatibility,
+// and there are slight changes to function signatures between library versions.
+// Well, at least they publish a "MINIUPNPC_API_VERSION" constant, so we got that going for us, which is nice.
+// Differences between API versions are documented in "apiversions.txt" in the libminiupnpc distribution.
+
+#ifndef MINIUPNPC_API_VERSION
+#define MINIUPNPC_API_VERSION 0
+#endif
+
+static struct UPNPDev *upnp_discover(int delay, int *error) {
+#if MINIUPNPC_API_VERSION <= 13
+
+#if MINIUPNPC_API_VERSION < 8
+#warning "The version of libminiupnpc you're building against seems to be too old. Expect trouble."
+#endif
+
+       return upnpDiscover(delay, NULL, NULL, false, false, error);
+
+#elif MINIUPNPC_API_VERSION <= 14
+
+       return upnpDiscover(delay, NULL NULL, false, false, 2, error);
+
+#else
+
+#if MINIUPNPC_API_VERSION > 15
+#warning "The version of libminiupnpc you're building against seems to be too recent. Expect trouble."
+#endif
+
+       return upnpDiscover(delay, NULL, NULL, UPNP_LOCAL_PORT_ANY, false, 2, error);
+
+#endif
+}
+
+static void upnp_add_mapping(struct UPNPUrls *urls, struct IGDdatas *data, const char *myaddr, int socket, const char *proto) {
+       // Extract the port from the listening socket.
+       // Note that we can't simply use listen_socket[].sa because this won't have the port
+       // if we're running with Port=0 (dynamically assigned port).
+       sockaddr_t sa;
+       socklen_t salen = sizeof sa;
+       if (getsockname(socket, &sa.sa, &salen)) {
+               logger(DEBUG_PROTOCOL, LOG_ERR, "[upnp] Unable to get socket address: [%d] %s", sockerrno, sockstrerror(sockerrno));
+               return;
+       }
+       char *port;
+       sockaddr2str(&sa, NULL, &port);
+       if (!port) {
+               logger(DEBUG_PROTOCOL, LOG_ERR, "[upnp] Unable to get socket port");
+               return;
+       }
+
+       // Use a lease twice as long as the refresh period so that the mapping won't expire before we refresh.
+       char lease_duration[16];
+       snprintf(lease_duration, sizeof lease_duration, "%d", upnp_refresh_period * 2);
+
+       int error = UPNP_AddPortMapping(urls->controlURL, data->first.servicetype, port, port, myaddr, identname, proto, NULL, lease_duration);
+       if (error == 0) {
+               logger(DEBUG_PROTOCOL, LOG_INFO, "[upnp] Successfully set port mapping (%s:%s %s for %s seconds)", myaddr, port, proto, lease_duration);
+       } else {
+               logger(DEBUG_PROTOCOL, LOG_ERR, "[upnp] Failed to set port mapping (%s:%s %s for %s seconds): [%d] %s", myaddr, port, proto, lease_duration, error, strupnperror(error));
+       }
+
+       free(port);
+}
+
+static void upnp_refresh() {
+       logger(DEBUG_PROTOCOL, LOG_INFO, "[upnp] Discovering IGD devices");
+
+       int error;
+       struct UPNPDev *devices = upnp_discover(upnp_discover_wait * 1000, &error);
+       if (!devices) {
+               logger(DEBUG_PROTOCOL, LOG_WARNING, "[upnp] Unable to find IGD devices: [%d] %s", error, strupnperror(error));
+               freeUPNPDevlist(devices);
+               return;
+       }
+
+       struct UPNPUrls urls;
+       struct IGDdatas data;
+       char myaddr[64];
+       int result = UPNP_GetValidIGD(devices, &urls, &data, myaddr, sizeof myaddr);
+       if (result <= 0) {
+               logger(DEBUG_PROTOCOL, LOG_WARNING, "[upnp] No IGD found");
+               freeUPNPDevlist(devices);
+               return;
+       }
+       logger(DEBUG_PROTOCOL, LOG_INFO, "[upnp] IGD found: [%d] %s (local address: %s, service type: %s)", result, urls.controlURL, myaddr, data.first.servicetype);
+
+       for (int i = 0; i < listen_sockets; i++) {
+               if (upnp_tcp) upnp_add_mapping(&urls, &data, myaddr, listen_socket[i].tcp.fd, "TCP");
+               if (upnp_udp) upnp_add_mapping(&urls, &data, myaddr, listen_socket[i].udp.fd, "UDP");
+       }
+
+       FreeUPNPUrls(&urls);
+       freeUPNPDevlist(devices);
+}
+
+static void *upnp_thread(void *data) {
+       while (true) {
+               time_t start = time(NULL);
+               upnp_refresh();
+
+               // Make sure we'll stick to the refresh period no matter how long upnp_refresh() takes.
+               time_t refresh_time = start + upnp_refresh_period;
+               time_t now = time(NULL);
+               if (now < refresh_time) sleep(refresh_time - now);
+       }
+
+       // TODO: we don't have a clean thread shutdown procedure, so we can't remove the mapping.
+       //       this is probably not a concern as long as the UPnP device honors the lease duration,
+       //       but considering how bug-riddled these devices often are, that's a big "if".
+       return NULL;
+}
+
+void upnp_init(bool tcp, bool udp) {
+       upnp_tcp = tcp;
+       upnp_udp = udp;
+
+       get_config_int(lookup_config(config_tree, "UPnPDiscoverWait"), &upnp_discover_wait);
+       get_config_int(lookup_config(config_tree, "UPnPRefreshPeriod"), &upnp_refresh_period);
+
+       pthread_t thread;
+       int error = pthread_create(&thread, NULL, upnp_thread, NULL);
+       if (error) {
+               logger(DEBUG_ALWAYS, LOG_ERR, "Unable to start UPnP-IGD client thread: [%d] %s", error, strerror(error));
+       }
+}
diff --git a/src/upnp.h b/src/upnp.h
new file mode 100644 (file)
index 0000000..dd0531b
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+    upnp.h -- UPnP-IGD client
+    Copyright (C) 2015 Guus Sliepen <guus@tinc-vpn.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 2 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, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef __UPNP_H__
+#define __UPNP_H__
+
+#include "system.h"
+
+extern void upnp_init(bool, bool);
+
+#endif