diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java
index f522193f68a2c3de455a82f1861a59be3d5d1f88..f261efa7edfac7dd273bbf1fd2304a7211390bb1 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java
@@ -1513,15 +1513,7 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
             addtask(task);
             notifyEvent("pingTaskId", Integer.valueOf(task.getId()));
         } else {
-            l.log("ping <opts> <b64dest|host>");
-            l.log("ping <opts> -h (pings all hosts in hosts.txt)");
-            l.log("ping <opts> -l <destlistfile> (pings a list of hosts in a file)");
-            l.log("   Options:\n" +
-                  "     -c (require 5 consecutive pings to report success)\n" +
-                  "     -m maxSimultaneousPings (default 10)\n" +
-                  "     -n numberOfPings (default 3)\n" +
-                  "     -t timeout (ms, default 30000)\n");
-            l.log("   Tests communication with peers.\n");
+            l.log(I2Ping.usage());
             notifyEvent("pingTaskId", Integer.valueOf(-1));
         }
     }
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2Ping.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2Ping.java
index a41ae15ed9f2307517f71b8b78d5249efa66f7f6..3e8a0a2482ce742a3d7b7744ab3db1d8ec816d59 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2Ping.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2Ping.java
@@ -11,6 +11,8 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
 
+import gnu.getopt.Getopt;
+
 import net.i2p.I2PAppContext;
 import net.i2p.I2PException;
 import net.i2p.client.I2PSession;
@@ -86,48 +88,76 @@ public class I2Ping extends I2PTunnelClientBase {
       int count = PING_COUNT;
       boolean countPing = false;
       boolean reportTimes = true;
-      while (true) {
-        if (cmd.startsWith("-t ")) { // timeout
-            cmd = cmd.substring(3);
-            int pos = cmd.indexOf(" ");
-            if (pos == -1) {
-                l.log("Syntax error");
-                return;
-            } else {
-                timeout = Long.parseLong(cmd.substring(0, pos));
+      String hostListFile = null;
+      int localPort = 0;
+      int remotePort = 0;
+      boolean error = false;
+      String[] argv = cmd.split(" ");
+      Getopt g = new Getopt("ping", argv, "t:m:n:chl:f:p:");
+      int c;
+      while ((c = g.getopt()) != -1) {
+        switch (c) {
+          case 't':  // timeout
+            timeout = Long.parseLong(g.getOptarg());
                 // convenience, convert msec to sec
                 if (timeout < 100)
                     timeout *= 1000;
-                cmd = cmd.substring(pos + 1);
-            }
-        } else if (cmd.startsWith("-m ")) { // max simultaneous pings
-            cmd = cmd.substring(3);
-            int pos = cmd.indexOf(" ");
-            if (pos == -1) {
-                l.log("Syntax error");
-                return;
-            } else {
-                MAX_SIMUL_PINGS = Integer.parseInt(cmd.substring(0, pos));
-                cmd = cmd.substring(pos + 1);
-            }
-        } else if (cmd.startsWith("-n ")) { // number of pings
-            cmd = cmd.substring(3);
-            int pos = cmd.indexOf(" ");
-            if (pos == -1) {
-                l.log("Syntax error");
-                return;
-            } else {
-                count = Integer.parseInt(cmd.substring(0, pos));
-                cmd = cmd.substring(pos + 1);
-            }
-        } else if (cmd.startsWith("-c ")) { // "count" ping
+            break;
+
+          case 'm': // max simultaneous pings
+            MAX_SIMUL_PINGS = Integer.parseInt(g.getOptarg());
+            break;
+
+          case 'n': // number of pings
+            count = Integer.parseInt(g.getOptarg());
+            break;
+
+          case 'c': // "count" ping
             countPing = true;
             count = CPING_COUNT;
-            cmd = cmd.substring(3);
-        } else if (cmd.equals("-h")) { // ping all hosts
-            cmd = "-l hosts.txt";
-        } else if (cmd.startsWith("-l ")) { // ping a list of hosts
-            BufferedReader br = new BufferedReader(new FileReader(cmd.substring(3)));
+            break;
+
+          case 'h': // ping all hosts
+            if (hostListFile != null)
+                error = true;
+            else
+                hostListFile = "hosts.txt";
+            break;
+
+          case 'l':  // ping a list of hosts
+            if (hostListFile != null)
+                error = true;
+            else
+                hostListFile = g.getOptarg();
+            break;
+
+          case 'f': // local port
+            localPort = Integer.parseInt(g.getOptarg());
+            break;
+
+          case 'p': // remote port
+            remotePort = Integer.parseInt(g.getOptarg());
+            break;
+
+          case '?':
+          case ':':
+          default:
+            error = true;
+        }
+      }
+
+      int remaining = argv.length - g.getOptind();
+
+      if (error ||
+          remaining > 1 ||
+          (remaining <= 0 && hostListFile == null) ||
+          (remaining > 0 && hostListFile != null)) {
+          System.out.println(usage());
+          return;
+      }
+
+      if (hostListFile != null) {
+            BufferedReader br = new BufferedReader(new FileReader(hostListFile));
             String line;
             List<PingHandler> pingHandlers = new ArrayList<PingHandler>();
             int i = 0;
@@ -138,7 +168,8 @@ public class I2Ping extends I2PTunnelClientBase {
                 if (line.indexOf("=") != -1) { // maybe file is hosts.txt?
                     line = line.substring(0, line.indexOf("="));
                 }
-                PingHandler ph = new PingHandler(line, count, timeout, countPing, reportTimes);
+                PingHandler ph = new PingHandler(line, count, localPort, remotePort,
+                                                 timeout, countPing, reportTimes);
                 ph.start();
                 pingHandlers.add(ph);
                 if (++i > 1)
@@ -148,13 +179,31 @@ public class I2Ping extends I2PTunnelClientBase {
             for (Thread t : pingHandlers)
                 t.join();
             return;
-        } else {
-            Thread t = new PingHandler(cmd, count, timeout, countPing, reportTimes);
-            t.start();
-            t.join();
-            return;
-        }
       }
+
+      String host = argv[g.getOptind()];
+      Thread t = new PingHandler(host, count, localPort, remotePort,
+                                 timeout, countPing, reportTimes);
+      t.start();
+      t.join();
+    }
+
+    /**
+     *  With newlines except for last line
+     *  @since 0.9.12
+     */
+    public static String usage() {
+        return
+            "ping <opts> <b64dest|host>\n" +
+            "ping <opts> -h (pings all hosts in hosts.txt)\n" +
+            "ping <opts> -l <destlistfile> (pings a list of hosts in a file)\n" +
+            "Options:\n" +
+            "     -c (require 5 consecutive pings to report success)\n" +
+            "     -m maxSimultaneousPings (default 10)\n" +
+            "     -n numberOfPings (default 3)\n" +
+            "     -t timeout (ms, default 30000)\n" +
+            "     -f fromPort\n" +
+            "     -p toPort";
     }
 
     @Override
@@ -170,7 +219,7 @@ public class I2Ping extends I2PTunnelClientBase {
         return true;
     }
 
-    private boolean ping(Destination dest, long timeout) throws I2PException {
+    private boolean ping(Destination dest, int fromPort, int toPort, long timeout) throws I2PException {
         try {
             synchronized (simulLock) {
                 while (simulPings >= MAX_SIMUL_PINGS) {
@@ -183,7 +232,7 @@ public class I2Ping extends I2PTunnelClientBase {
                 }
                 lastPingTime = System.currentTimeMillis();
             }
-            boolean sent = sockMgr.ping(dest, timeout);
+            boolean sent = sockMgr.ping(dest, fromPort, toPort, timeout);
             synchronized (simulLock) {
                 simulPings--;
                 simulLock.notifyAll();
@@ -207,15 +256,20 @@ public class I2Ping extends I2PTunnelClientBase {
         private final long timeout;
         private final boolean countPing;
         private final boolean reportTimes;
+        private final int localPort;
+        private final int remotePort;
 
         /**
          *  As of 0.9.10, does NOT start itself.
          *  Caller must call start()
          *  @param dest b64 or b32 or host name
          */
-        public PingHandler(String dest, int count, long timeout, boolean countPings, boolean report) {
+        public PingHandler(String dest, int count, int fromPort, int toPort,
+                           long timeout, boolean countPings, boolean report) {
             this.destination = dest;
             cnt = count;
+            localPort = fromPort;
+            remotePort = toPort;
             this.timeout = timeout;
             countPing = countPings;
             reportTimes = report;
@@ -235,8 +289,7 @@ public class I2Ping extends I2PTunnelClientBase {
                 long totalTime = 0;
                 StringBuilder pingResults = new StringBuilder(2 * cnt + destination.length() + 3);
                 for (int i = 0; i < cnt; i++) {
-                    boolean sent;
-                    sent = ping(dest, timeout);
+                    boolean sent = ping(dest, localPort, remotePort, timeout);
                     if (countPing) {
                         if (!sent) {
                             pingResults.append(i).append(" ");