diff --git a/router/java/src/net/i2p/router/time/NtpClient.java b/router/java/src/net/i2p/router/time/NtpClient.java
index d5fecdc2df4b41fb40cd64e6f95bd65304c0a05b..e7f9b2a635aed66bd95c384e1d82ea27b310d83b 100644
--- a/router/java/src/net/i2p/router/time/NtpClient.java
+++ b/router/java/src/net/i2p/router/time/NtpClient.java
@@ -36,6 +36,9 @@ import java.net.InetAddress;
 import java.util.ArrayList;
 import java.util.Collections;
 
+import net.i2p.data.DataHelper;
+import net.i2p.util.HexDump;
+import net.i2p.util.Log;
 
 /**
  * NtpClient - an NTP client for Java.  This program connects to an NTP server
@@ -53,9 +56,12 @@ import java.util.Collections;
  */
 class NtpClient {
     /** difference between the unix epoch and jan 1 1900 (NTP uses that) */
-    private final static double SECONDS_1900_TO_EPOCH = 2208988800.0;
+    public final static double SECONDS_1900_TO_EPOCH = 2208988800.0;
     private final static int NTP_PORT = 123;
     private static final int DEFAULT_TIMEOUT = 10*1000;
+    private static final int OFF_ORIGTIME = 24;
+    private static final int OFF_TXTIME = 40;
+    private static final int MIN_PKT_LEN = 48;
 
     /**
      * Query the ntp servers, returning the current time from first one we find
@@ -63,6 +69,7 @@ class NtpClient {
      * @return milliseconds since january 1, 1970 (UTC)
      * @throws IllegalArgumentException if none of the servers are reachable
      */
+/****
     public static long currentTime(String serverNames[]) {
         if (serverNames == null) 
             throw new IllegalArgumentException("No NTP servers specified");
@@ -77,15 +84,18 @@ class NtpClient {
         }
         throw new IllegalArgumentException("No reachable NTP servers specified");
     }
+****/
     
     /**
      * Query the ntp servers, returning the current time from first one we find
      * Hack to return time and stratum
+     *
+     * @param log may be null
      * @return time in rv[0] and stratum in rv[1]
      * @throws IllegalArgumentException if none of the servers are reachable
      * @since 0.7.12
      */
-    public static long[] currentTimeAndStratum(String serverNames[], int perServerTimeout) {
+    public static long[] currentTimeAndStratum(String serverNames[], int perServerTimeout, Log log) {
         if (serverNames == null) 
             throw new IllegalArgumentException("No NTP servers specified");
         ArrayList<String> names = new ArrayList<String>(serverNames.length);
@@ -93,7 +103,7 @@ class NtpClient {
             names.add(serverNames[i]);
         Collections.shuffle(names);
         for (int i = 0; i < names.size(); i++) {
-            long[] rv = currentTimeAndStratum(names.get(i), perServerTimeout);
+            long[] rv = currentTimeAndStratum(names.get(i), perServerTimeout, log);
             if (rv != null && rv[0] > 0)
                 return rv;
         }
@@ -105,19 +115,23 @@ class NtpClient {
      *
      * @return milliseconds since january 1, 1970 (UTC), or -1 on error
      */
+/****
     public static long currentTime(String serverName) {
          long[] la = currentTimeAndStratum(serverName, DEFAULT_TIMEOUT);
          if (la != null)
              return la[0];
          return -1;
     }
+****/
 
     /**
      * Hack to return time and stratum
+     *
+     * @param log may be null
      * @return time in rv[0] and stratum in rv[1], or null for error
      * @since 0.7.12
      */
-    private static long[] currentTimeAndStratum(String serverName, int timeout) {
+    private static long[] currentTimeAndStratum(String serverName, int timeout, Log log) {
         DatagramSocket socket = null;
         try {
             // Send request
@@ -125,14 +139,19 @@ class NtpClient {
             InetAddress address = InetAddress.getByName(serverName);
             byte[] buf = new NtpMessage().toByteArray();
             DatagramPacket packet = new DatagramPacket(buf, buf.length, address, NTP_PORT);
+            byte[] txtime = new byte[8];
 
             // Set the transmit timestamp *just* before sending the packet
             // ToDo: Does this actually improve performance or not?
-            NtpMessage.encodeTimestamp(packet.getData(), 40,
+            NtpMessage.encodeTimestamp(packet.getData(), OFF_TXTIME,
                                        (System.currentTimeMillis()/1000.0) 
                                        + SECONDS_1900_TO_EPOCH);
 
             socket.send(packet);
+            // save for check
+            System.arraycopy(packet.getData(), OFF_TXTIME, txtime, 0, 8);
+            if (log != null && log.shouldDebug())
+                log.debug("Sent:\n" + HexDump.dump(buf));
 
             // Get response
             packet = new DatagramPacket(buf, buf.length);
@@ -142,28 +161,51 @@ class NtpClient {
             // Immediately record the incoming timestamp
             double destinationTimestamp = (System.currentTimeMillis()/1000.0) + SECONDS_1900_TO_EPOCH;
 
+            if (packet.getLength() < MIN_PKT_LEN) {
+                if (log != null && log.shouldWarn())
+                    log.warn("Short packet length " + packet.getLength());
+                return null;
+            }
+
             // Process response
             NtpMessage msg = new NtpMessage(packet.getData());
 
-            //double roundTripDelay = (destinationTimestamp-msg.originateTimestamp) -
-            //                        (msg.receiveTimestamp-msg.transmitTimestamp);
-            double localClockOffset = ((msg.receiveTimestamp - msg.originateTimestamp) +
-                                       (msg.transmitTimestamp - destinationTimestamp)) / 2;
+            if (log != null && log.shouldDebug())
+                log.debug("Received from: " + packet.getAddress().getHostAddress() +
+                          '\n' + msg + '\n' + HexDump.dump(packet.getData()));
 
             // Stratum must be between 1 (atomic) and 15 (maximum defined value)
             // Anything else is right out, treat such responses like errors
             if ((msg.stratum < 1) || (msg.stratum > 15)) {
-                //System.out.println("Response from NTP server of unacceptable stratum " + msg.stratum + ", failing.");
+                if (log != null && log.shouldWarn())
+                    log.warn("Response from NTP server of unacceptable stratum " + msg.stratum + ", failing.");
                 return null;
             }
+
+            if (!DataHelper.eq(txtime, 0, packet.getData(), OFF_ORIGTIME, 8)) {
+                if (log != null && log.shouldWarn())
+                    log.warn("Origin time mismatch sent:\n" + HexDump.dump(txtime) +
+                             "rcvd:\n" + HexDump.dump(packet.getData(), OFF_ORIGTIME, 8));
+                return null;
+            }
+
+
+            double localClockOffset = ((msg.receiveTimestamp - msg.originateTimestamp) +
+                                       (msg.transmitTimestamp - destinationTimestamp)) / 2;
             
             long[] rv = new long[2];
             rv[0] = (long)(System.currentTimeMillis() + localClockOffset*1000);
             rv[1] = msg.stratum;
-            //System.out.println("host: " + address.getHostAddress() + " rtt: " + roundTripDelay + " offset: " + localClockOffset + " seconds");
+            if (log != null && log.shouldInfo()) {
+                double roundTripDelay = (destinationTimestamp-msg.originateTimestamp) -
+                                        (msg.receiveTimestamp-msg.transmitTimestamp);
+                log.info("host: " + packet.getAddress().getHostAddress() + " rtt: " +
+                         roundTripDelay + " offset: " + localClockOffset + " seconds");
+            }
             return rv;
         } catch (IOException ioe) {
-            //ioe.printStackTrace();
+            if (log != null && log.shouldWarn())
+                log.warn("NTP failure from " + serverName, ioe);
             return null;
         } finally {
             if (socket != null)
@@ -171,20 +213,19 @@ class NtpClient {
         }
     }
     
-/****
     public static void main(String[] args) throws IOException {
         // Process command-line args
         if(args.length <= 0) {
-            printUsage();
-            return;
-            // args = new String[] { "ntp1.sth.netnod.se", "ntp2.sth.netnod.se" };
+           args = new String[] { "pool.ntp.org" };
         } 
 
-        long now = currentTime(args);
-        System.out.println("Current time: " + new java.util.Date(now));
+        Log log = new Log(NtpClient.class);
+        long[] rv = currentTimeAndStratum(args, DEFAULT_TIMEOUT, log);
+        System.out.println("Current time: " + new java.util.Date(rv[0]) + " (stratum " + rv[1] + ')');
     }
     
-    static void printUsage() {
+/****
+    private static void printUsage() {
         System.out.println(
         "NtpClient - an NTP client for Java.\n" +
         "\n" +
diff --git a/router/java/src/net/i2p/router/time/NtpMessage.java b/router/java/src/net/i2p/router/time/NtpMessage.java
index ea02cce5f8884005e2ce3d90a4c7d68b0d648b43..4f471cce955f945bb0218f33861c179c2a3b40bf 100644
--- a/router/java/src/net/i2p/router/time/NtpMessage.java
+++ b/router/java/src/net/i2p/router/time/NtpMessage.java
@@ -31,6 +31,7 @@ package net.i2p.router.time;
 
 import java.text.DecimalFormat;
 import java.text.SimpleDateFormat;
+import java.util.Arrays;
 import java.util.Date;
 
 import net.i2p.util.RandomSource;
@@ -117,7 +118,7 @@ class NtpMessage {
      * in the request and the server sets it to 4 (server) in the reply. In
      * multicast mode, the server sets this field to 5 (broadcast).
      */
-    public byte mode = 0;
+    public final byte mode;
     
     
     /**
@@ -233,12 +234,14 @@ class NtpMessage {
      * This is the time at which the reply departed the server for the client,
      * in seconds since 00:00 1-Jan-1900.
      */
-    public double transmitTimestamp = 0;
+    public final double transmitTimestamp;
     
     
     
     /**
      * Constructs a new NtpMessage from an array of bytes.
+     *
+     * @param array 48 bytes minimum
      */
     public NtpMessage(byte[] array) {
         // See the packet format diagram in RFC 2030 for details
@@ -280,13 +283,15 @@ class NtpMessage {
         // Note that all the other member variables are already set with
         // appropriate default values.
         this.mode = 3;
-        this.transmitTimestamp = (System.currentTimeMillis()/1000.0) + 2208988800.0;
+        this.transmitTimestamp = (System.currentTimeMillis()/1000.0) + NtpClient.SECONDS_1900_TO_EPOCH;
     }
     
     
     
     /**
      * This method constructs the data bytes of a raw NTP packet.
+     *
+     * @return 48 bytes
      */
     public byte[] toByteArray() {
         // All bytes are automatically set to 0
@@ -368,6 +373,10 @@ class NtpMessage {
      * Will read 8 bytes of a message beginning at <code>pointer</code>
      * and return it as a double, according to the NTP 64-bit timestamp
      * format.
+     *
+     * @param array 8 bytes starting at pointer
+     * @param pointer the offset
+     * @return the time since 1900 (NOT Java time)
      */
     public static double decodeTimestamp(byte[] array, int pointer) {
         double r = 0.0;
@@ -383,10 +392,21 @@ class NtpMessage {
     
     /**
      * Encodes a timestamp in the specified position in the message
+     *
+     * @param array output 8 bytes starting at pointer
+     * @param pointer the offset
+     * @param timestamp the time to encode (since 1900, NOT Java time)
      */
     public static void encodeTimestamp(byte[] array, int pointer, double timestamp) {
+        if (timestamp == 0.0) {
+            // don't put in random data
+            Arrays.fill(array, pointer, pointer + 8, (byte) 0);
+            return;
+        }
+
         // Converts a double into a 64-bit fixed point
-        for(int i=0; i<8; i++) {
+        // 6 bytes of real data
+        for(int i=0; i<7; i++) {
             // 2^24, 2^16, 2^8, .. 2^-32
             double base = Math.pow(2, (3-i)*8);
             
@@ -401,7 +421,8 @@ class NtpMessage {
         // low order bits of the timestamp with a random, unbiased
         // bitstring, both to avoid systematic roundoff errors and as
         // a means of loop detection and replay detection.
-        array[7+pointer] = (byte) (RandomSource.getInstance().nextInt());
+        // 2 bytes of random data
+        RandomSource.getInstance().nextBytes(array, pointer + 6, 2);
     }
     
     
@@ -415,7 +436,7 @@ class NtpMessage {
         
         // timestamp is relative to 1900, utc is used by Java and is relative
         // to 1970
-        double utc = timestamp - (2208988800.0);
+        double utc = timestamp - NtpClient.SECONDS_1900_TO_EPOCH;
         
         // milliseconds
         long ms = (long) (utc * 1000.0);
@@ -425,7 +446,7 @@ class NtpMessage {
         
         // fraction
         double fraction = timestamp - ((long) timestamp);
-        String fractionSting = new DecimalFormat(".000000").format(fraction);
+        String fractionSting = new DecimalFormat(".000000000").format(fraction);
         
         return date + fractionSting;
     }
diff --git a/router/java/src/net/i2p/router/time/RouterTimestamper.java b/router/java/src/net/i2p/router/time/RouterTimestamper.java
index 88d837a02da7c3576edfd207f1c76f62a9c12d0a..83b22e56aec608d1c0c9622e259907f71e4f3241 100644
--- a/router/java/src/net/i2p/router/time/RouterTimestamper.java
+++ b/router/java/src/net/i2p/router/time/RouterTimestamper.java
@@ -273,7 +273,7 @@ public class RouterTimestamper extends Timestamper {
             //    // this delays startup when net is disconnected or the timeserver list is bad, don't make it too long
             //    try { Thread.sleep(2*1000); } catch (InterruptedException ie) {}
             //}
-            long[] timeAndStratum = NtpClient.currentTimeAndStratum(serverList, perServerTimeout);
+            long[] timeAndStratum = NtpClient.currentTimeAndStratum(serverList, perServerTimeout, _log);
             now = timeAndStratum[0];
             stratum = (int) timeAndStratum[1];
             long delta = now - _context.clock().now();