diff --git a/.dir-locals.el b/.dir-locals.el
new file mode 100644
index 0000000..bb7424e
--- /dev/null
+++ b/.dir-locals.el
@@ -0,0 +1,3 @@
+((c-mode . ((indent-tabs-mode  . nil)
+            (c-file-style      . "gnu")
+            (c-basic-offset    . 4))))
diff --git a/Makefile.am b/Makefile.am
index c0709ca..29435e1 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -98,15 +98,22 @@ mtr_packet_SOURCES = \
 	packet/probe.c packet/probe.h \
 	packet/protocols.h \
 	packet/timeval.c packet/timeval.h \
-	packet/wait.h
+	packet/wait.h \
+	packet/sockaddr.c packet/sockaddr.h
 
 mtr_packet_LDADD = $(CAP_LIBS)
 
 
+if WITH_ERROR
+mtr_packet_SOURCES += \
+	portability/error.h \
+	portability/error.c
+endif
+
+
 if CYGWIN
 
 mtr_packet_SOURCES += \
-	packet/command_cygwin.c packet/command_cygwin.h \
 	packet/probe_cygwin.c packet/probe_cygwin.h \
 	packet/wait_cygwin.c
 mtr_packet_LDADD += -lcygwin -liphlpapi -lws2_32
@@ -141,7 +148,6 @@ else  # if CYGWIN
 check_PROGRAMS = mtr-packet-listen
 
 mtr_packet_SOURCES += \
-	packet/command_unix.c packet/command_unix.h \
 	packet/construct_unix.c packet/construct_unix.h \
 	packet/deconstruct_unix.c packet/deconstruct_unix.h \
 	packet/probe_unix.c packet/probe_unix.h \
@@ -156,3 +162,7 @@ endif  # if CYGWIN
 if BUILD_BASH_COMPLETION
 dist_bashcompletion_DATA = bash-completion/mtr
 endif
+
+dist-hook:
+	$(AM_V_GEN)echo $(VERSION) > $(distdir)/.tarball-version
+
diff --git a/NEWS b/NEWS
index 4cc42b1..bb2bf87 100644
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,106 @@ The new release script will do a "git shortlog" to add
 the commit messages here. 
 
 #NEW_STUFF_HERE this is a tag my script looks for. 
+V0.93
+    Adam (1):
+          Update README
+    
+    Adrien Gallouët (1):
+          Add a help line for the t command in curses
+    
+    Alexander Blesius (1):
+          convert README to markdown
+    
+    Arkadiusz Miśkiewicz (2):
+          Also try SOCK_RAW/IPPROTO_ICMP when other fail.
+          mtr to a unreachable host is possible again.
+    
+    Ben Williams (2):
+          added UI hotkeys description (from internal help) to NOTES section in mtr man page
+          renamed NOTES to INTERACTIVE CONTROL as per discussion in pull request
+    
+    Chonggang Li (4):
+          mtr-packet: use ICMP and UDP without privilege on linux
+          mtr-packet: fix Windows compilation
+          mtr-packet: fix compilation on OS X
+          mtr-packet: fix a bug causing IPv6 raw socket not working
+    
+    Markus Kötter (7):
+          set udp checksum
+          automake - configure show build options
+          sockaddr - unify access to sockaddr_in/6 port & address
+          probe - use INET6_ADDRSTRLEN
+          probe - extend matching to src/dst host&port
+          sockaddr - save a cast accessing the port
+          construct - fix set port
+    
+    Matt Kimball (7):
+          mtr-packet: report ICMP destination unreachable probes as "no route to host"
+          ui: display "no route to host" error as host entry rather than abort
+          json: Fix malformed json when the "hubs" list is empty
+          commandline: Added --interface for using a named network interface
+          Link portability/error.c with mtr-packet when missing on MacOS
+          Mention Python mtrpacket package in mtr-packet man page
+          Rework Cygwin mtr-packet to respond to signals (such as SIGTERM)
+    
+    R.E. Wolff (15):
+          fixed some outdated text in README.
+          minor changes top help Windows compilation on 32 bit machines
+          fix #204 : added exec of mtr-packet in the place where mtr was started 
+                from. Quick and dirty, There is probably a better place to declare variables.
+          Alternative 'skip uid 0 checks on cygwin' to adpoliak's implmentation
+          fix stupid typo. Thanks adpoliak!
+          possible fix for mac terminal 100% problem
+          Sami Kerola: prevent MTR reporting unknown revision
+          Merge branch 'master' of github.com:traviscross/mtr
+          fixed split like for macos
+          better fix. to dave's problem.
+          -f equals -m fix from yvs2014
+          rewritten weiyixuan's patch
+          fixed typo
+          Netbsd build fixes thanks to yvs2014
+          Merge branch 'master' of github.com:traviscross/mtr
+    
+    Robert Scheck (1):
+          Update incorrect FSF address
+    
+    Rogier Wolff (3):
+          Fixed issue #286
+          Manpage fix for Darwin by Matt. Rewritten by REW
+          Added parentheses
+    
+    SaintBol (9):
+          Update protocols.h
+          Update deconstruct_unix.c
+          Update probe.c
+          Update probe.h
+          Update cmdpipe.c
+          Update curses.c
+          Update mtr.h
+          Update report.c
+          Update mtr-packet.8.in
+    
+    Sami Kerola (1):
+          mtr-packet: make address-not-available errors less likely
+    
+    Samuel Henrique (1):
+          [typo]mtr.8.in: s/allows to/allows one to/
+    
+    Tobias Rittweiler (2):
+          Add a .dir-locals.el file for Emacs.
+          Replace perror(...); exit(...); by error(...);
+    
+    divinity76 (1):
+          use setup.exe's package manager mode, replacing apt-cyg
+    
+    tk (1):
+          Fix typo (resove -> resolve)
+    
+    weiyixuan (3):
+          Option -y can not work properly
+          Option --ipinfo 1 can not work properly
+          for tcp, fix : bind port failed, try next sequence
+    
 V0.92
    added a few arguments to calls added by fmazu. Allows it to compile.
 
diff --git a/README b/README
deleted file mode 100644
index 1ff5c0f..0000000
--- a/README
+++ /dev/null
@@ -1,101 +0,0 @@
-WHAT IS MTR?
-
-  mtr combines the functionality of the 'traceroute' and 'ping' programs 
-  in a single network diagnostic tool.
-
-  As mtr starts, it investigates the network connection between the host
-  mtr runs on and a user-specified destination host.  After it
-  determines the address of each network hop between the machines, 
-  it sends a sequence of ICMP ECHO requests to each one to determine the 
-  quality of the link to each machine.  As it does this, it prints
-  running statistics about each machine.
-
-  mtr is distributed under the GNU General Public License version 2.
-  See the COPYING file for details.  
-
-INSTALLING
-
-  If you're building this from a tarball, compiling mtr should be as
-  simple as:
-
-	make
-
-  It should first call the "configure" script and then run "make" again
-  with the makefile that "configure" just generated. 
-
-  If you're building from the git repository, you'll need to run:
-
-	./bootstrap.sh && ./configure && make
-
-  After compiling, install:
-
-	make install
-
-  Note that mtr-packet must be suid-root because it requires access to
-  raw IP sockets.  See SECURITY for security information.
-
-  Older versions used to require a non-existent path to GTK for a
-  correct build of a non-gtk version while GTK was installed. This is
-  no longer necessary. ./configure --without-gtk should now work. 
-  If it doesn't, try "make WITHOUT_X11=YES" as the make step. 
-
-  On Solaris, you'll need to use GNU make to build.
-  (Use 'gmake' rather than 'make'.)
-
-  On Solaris (and possibly other systems) the "gtk" library may be
-  installed in a directory where the dynamic linker refuses to look when
-  a binary is setuid. Roman Shterenzon reports that adding 
-        -Wl,-rpath=/usr/lib
-  to the commandline will work if you are using gnu LD. He tells me that
-  you're out of luck when you use the sun LD. That's not quite true, as
-  you can move the gtk libraries to /usr/lib instead of leaving them in
-  /usr/local/lib.  (when the ld tells you that /usr/local/lib is untrusted
-  and /usr/lib is trusted, and you trust the gtk libs enough to want them
-  in a setuid program, then there is something to say for moving them
-  to the "trusted" directory.)
-
-  Building on MacOS should not require any special steps.
-
-BUILDING FOR WINDOWS
-
-  Building for Windows requires Cygwin.  To obtain Cygwin, see
-  https://cygwin.com/install.html.  When installing Cygwin, select
-  the 'lynx' package for installation.  lynx is required by apt-cyg.
-
-  Next, install apt-cyg for easy installation of the remaining
-  components.  See https://github.com/transcode-open/apt-cyg.
-
-  Install the packages required for building:
-
-        apt-cyg install automake pkg-config make gcc-core libncurses-devel
-
-  Build as under Unix:
-
-        ./bootstrap.sh && ./configure && make
-
-  Finally, install the built binaries:
-
-        make install
-
-WHERE CAN I GET THE LATEST VERSION OR MORE INFORMATION?
-
-  mtr is now hosted on github. 
-      https://github.com/traviscross/mtr
-
-  See the mtr web page at 
-         http://www.BitWizard.nl/mtr/ 
-
-  Bug reports and feature requests should be submitted to the Github
-  bug tracking system.
-
-  Patches can be submitted by cloning the Github repository and issuing
-  a pull request, or by email to me. Please use unified diffs. Usually
-  the diff is sort of messy, so please check that the diff is clean and
-  doesn't contain too much of your local stuff (for example, I don't
-  want/need the "configure" script that /your/ automake made for you).
-
-  (There used to be a mailinglist, but all it got was spam. So
-  when the server was upgraded, the mailing list died.)
-
--- REW
-
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..77b6f79
--- /dev/null
+++ b/README.md
@@ -0,0 +1,109 @@
+WHAT IS MTR?
+===
+
+mtr combines the functionality of the 'traceroute' and 'ping' programs
+in a single network diagnostic tool.
+
+As mtr starts, it investigates the network connection between the host
+mtr runs on and a user-specified destination host.  After it
+determines the address of each network hop between the machines,
+it sends a sequence of ICMP ECHO requests to each one to determine the
+quality of the link to each machine.  As it does this, it prints
+running statistics about each machine.
+
+mtr is distributed under the GNU General Public License version 2.
+See the COPYING file for details.
+
+INSTALLING
+===
+
+If you're building this from a tarball, compiling mtr is as
+simple as:
+
+	./configure && make
+
+(in the past, there was a Makefile in the distribution that did
+the `./configure` for you and then ran make again with the generated
+Makefile, but this has suffered some bitrot. It didn't work well
+with git.)
+
+If you're building from the git repository, you'll need to run:
+
+	./bootstrap.sh && ./configure && make
+
+When it looks as if the compilation was succesful, you can
+test mtr with
+
+	sudo ./mtr <host>
+
+(fill in a hostname or IP address where it says <host>) or
+immediately continue on to installing:
+
+	make install
+
+Note that mtr-packet must be suid-root because it requires access to
+raw IP sockets.  See SECURITY for security information.
+
+Older versions used to require a non-existent path to GTK for a
+correct build of a non-gtk version while GTK was installed. This is
+no longer necessary. `./configure --without-gtk` should now work.
+If it doesn't, try `make WITHOUT_X11=YES` as the make step.
+
+On Solaris, you'll need to use GNU make to build.
+(Use `gmake` rather than `make`.)
+
+On Solaris (and possibly other systems) the "gtk" library may be
+installed in a directory where the dynamic linker refuses to look when
+a binary is setuid. Roman Shterenzon reports that adding
+        -Wl,-rpath=/usr/lib
+to the commandline will work if you are using gnu LD. He tells me that
+you're out of luck when you use the sun LD. That's not quite true, as
+you can move the gtk libraries to `/usr/lib` instead of leaving them in
+`/usr/local/lib`.  (when the ld tells you that `/usr/local/lib` is untrusted
+and `/usr/lib` is trusted, and you trust the gtk libs enough to want them
+in a setuid program, then there is something to say for moving them
+to the "trusted" directory.)
+
+Building on MacOS should not require any special steps.
+
+BUILDING FOR WINDOWS
+===
+
+Building for Windows requires Cygwin.  To obtain Cygwin, see
+https://cygwin.com/install.html.
+Next, re-run cygwin's `setup-x86.exe` (or `setup-x86_64.exe` if you're using 64bit cygwin) with the following arguments,  
+which will install the packages required for building:
+
+        setup-x86.exe --package-manager --wait --packages automake,pkg-config,make,gcc-core,libncurses-devel
+
+Build as under Unix:
+
+        ./bootstrap.sh && ./configure && make
+
+Finally, install the built binaries:
+
+        make install
+
+
+WHERE CAN I GET THE LATEST VERSION OR MORE INFORMATION?
+===
+
+mtr is now hosted on github.
+https://github.com/traviscross/mtr
+
+See the mtr web page at http://www.BitWizard.nl/mtr/
+
+Bug reports and feature requests should be submitted to the Github bug tracking system.
+
+Patches can be submitted by cloning the Github repository and issuing
+a pull request, or by email to me. Please use unified diffs. Usually
+the diff is sort of messy, so please check that the diff is clean and
+doesn't contain too much of your local stuff (for example, I don't
+want/need the "configure" script that /your/ automake made for you).
+
+(There used to be a mailinglist, but all it got was spam. So
+when the server was upgraded, the mailing list died.)
+
+
+REW
+
diff --git a/build-aux/mangen.sh b/build-aux/mangen.sh
index 2c12d87..6ce777e 100755
--- a/build-aux/mangen.sh
+++ b/build-aux/mangen.sh
@@ -11,4 +11,19 @@ if [ $# -lt 3 ]; then
     exit 1
 fi
 
-sed -e "s|@VERSION[@]|$1|g" $2 >$3
+VERSION=$1
+IN=$2
+OUT=$3
+
+#
+#  MacOS's groff is missing .UR and .UE support, which makes
+#  URL completely disappear from man pages.  We need to strip
+#  those codes out when building for MacOS
+#
+if [ $(uname -s) = "Darwin" ]; then
+   RMURUE='-e s/\.UR.//g -e s/\.UE//g'
+else
+   RMURUE=""
+fi
+
+sed -e "s|@VERSION[@]|$VERSION|g" $RMURUE $IN >$OUT
diff --git a/build-aux/mtr.bat b/build-aux/mtr.bat
index 044e4a7..031a105 100755
--- a/build-aux/mtr.bat
+++ b/build-aux/mtr.bat
@@ -12,9 +12,9 @@ rem  but WITHOUT ANY WARRANTY; without even the implied warranty of
 rem  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 rem  GNU General Public License for more details.
 rem
-rem  You should have received a copy of the GNU General Public License
-rem  along with this program; if not, write to the Free Software
-rem  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+rem  You should have received a copy of the GNU General Public License along
+rem  with this program; if not, write to the Free Software Foundation, Inc.,
+rem  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 rem
 
 rem Assume the path of this batch file is the mtr installation location
diff --git a/configure.ac b/configure.ac
index a08ce67..ad81332 100644
--- a/configure.ac
+++ b/configure.ac
@@ -31,6 +31,9 @@ before running ./bootstrap.sh again.])
 PKG_PROG_PKG_CONFIG
 
 AM_CONDITIONAL([CYGWIN], [test "$host_os" = cygwin])
+AM_COND_IF([CYGWIN],
+           [AC_DEFINE([USING_CYGWIN], [1], [Building Under Cygwin.])],
+           [])
 
 # Check bytes in types.
 AC_CHECK_SIZEOF([unsigned char], [1])
@@ -46,6 +49,7 @@ AC_CHECK_HEADERS([ \
   error.h \
   fcntl.h \
   linux/icmp.h \
+  linux/errqueue.h \
   ncurses.h \
   ncurses/curses.h \
   netinet/in.h \
@@ -106,7 +110,7 @@ AS_IF([test "x$with_ncurses" = "xyes"],
 ])
 AM_CONDITIONAL([WITH_CURSES], [test "x$with_ncurses" = xyes])
 
-AC_CHECK_LIB([cap], [cap_set_proc], [],
+AC_CHECK_LIB([cap], [cap_set_proc], [have_cap="yes"],
   AS_IF([test "$host_os" = linux-gnu],
     AC_MSG_WARN([Capabilities support is strongly recommended for increased security.  See SECURITY for more information.])))
 
@@ -239,7 +243,16 @@ AC_ARG_ENABLE([bash-completion],
   [], [enable_bash_completion=yes]
 )
 AM_CONDITIONAL([BUILD_BASH_COMPLETION], [test "x$enable_bash_completion" = xyes])
-
+echo "build options:"
+echo "--------------"
+echo "ipv6    :$USES_IPV6"
+echo "ipinfo  :$with_ipinfo"
+echo "ncurses :$with_ncurses"
+echo "gtk     :$with_gtk"
+echo "cap     :$have_cap"
+echo "libs    :$LIBS"
+echo "cflags  :$CFLAGS"
+echo "--------------"
 # Prepare config.h, Makefile, and output them.
 AC_CONFIG_HEADERS([config.h])
 AC_CONFIG_FILES([Makefile])
diff --git a/man/mtr-packet.8.in b/man/mtr-packet.8.in
index 9691f74..9c02470 100644
--- a/man/mtr-packet.8.in
+++ b/man/mtr-packet.8.in
@@ -312,7 +312,7 @@ of four.  The first four values in the list correspond to the
 first MPLS label, the next four values correspond to the second MPLS
 label, and so on.  The values are provided in this order:
 .IR label ,
-.IR experimental-use ,
+.IR traffic-class ,
 .IR bottom-of-stack ,
 .IR ttl .
 .HP 7
@@ -437,6 +437,12 @@ Note that the replies in this example are printed out of order.
 This is the reason that it is important to send commands with unique
 token values, and to use those token values to match replies with
 their originating commands.
+.SH LANGUAGE BINDINGS
+.PP
+A Python 3.x package for sending asynchronous network probes using
+mtr-packet is available.  See
+.UR https://\:pypi.\:org/\:project/\:mtrpacket/
+.UE
 .SH CONTACT INFORMATION
 .PP
 For the latest version, see the mtr web page at
diff --git a/man/mtr.8.in b/man/mtr.8.in
index 7b6709b..db55012 100644
--- a/man/mtr.8.in
+++ b/man/mtr.8.in
@@ -77,6 +77,9 @@ mtr \- a network diagnostic tool
 .B \-\-mpls\c
 ]
 [\c
+.BI \-I \ NAME\c
+]
+[\c
 .BI \-a \ ADDRESS\c
 ]
 [\c
@@ -377,6 +380,12 @@ Use this option to tell
 to display information from ICMP extensions for MPLS (RFC 4950)
 that are encoded in the response packets.
 .TP
+.B \-I \fINAME\fR, \fB\-\-interface \fINAME
+Use the network interface with a specific name for sending network probes.
+This can be useful when you have multiple network interfaces with routes
+to your destination, for example both wired Ethernet and WiFi, and wish
+to test a particular interface.
+.TP
 .B \-a \fIADDRESS\fR, \fB\-\-address \fIADDRESS
 Use this option to bind the outgoing socket to
 .IR ADDRESS ,
@@ -429,9 +438,9 @@ for full description of this socket option.
 recognizes a few environment variables.
 .TP
 .B MTR_OPTIONS
-This environment variable allows to specify options, as if they were
-passed on the command line.  It is parsed before reading the actual
-command line options, so that options specified in
+This environment variable allows one to specify options, as if they
+were passed on the command line.  It is parsed before reading the
+actual command line options, so that options specified in
 .B MTR_OPTIONS
 are overridden by command-line options.
 
@@ -466,6 +475,28 @@ executable.
 .TP
 .B DISPLAY
 Specifies an X11 server for the GTK+ frontend.
+.SH INTERACTIVE CONTROL
+.B mtr
+can be controlled while it is running with the following keys:
+  ?|h     help
+  p       pause (SPACE to resume)
+  d       switching display mode
+  e       toggle MPLS information on/off
+  n       toggle DNS on/off
+  r       reset all counters
+  o str   set the columns to display, default str='LRS N BAWV'
+  j       toggle latency(LS NABWV)/jitter(DR AGJMXI) stats
+  c <n>   report cycle n, default n=infinite
+  i <n>   set the ping interval to n seconds, default n=1
+  f <n>   set the initial time-to-live(ttl), default n=1
+  m <n>   set the max time-to-live, default n= # of hops
+  s <n>   set the packet size to n or random(n<0)
+  b <c>   set ping bit pattern to c(0..255) or random(c<0)
+  Q <t>   set ping packet's TOS to t
+  u       switch between ICMP ECHO and UDP datagrams
+  y       switching IP info
+  z       toggle ASN info on/off
+  q       exit
 .SH BUGS
 Some modern routers give a lower priority to ICMP ECHO packets than 
 to other network traffic.  Consequently, the reliability of these
diff --git a/packet/cmdparse.c b/packet/cmdparse.c
index 1084714..76e6c91 100644
--- a/packet/cmdparse.c
+++ b/packet/cmdparse.c
@@ -11,9 +11,9 @@
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    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 "cmdparse.h"
diff --git a/packet/cmdparse.h b/packet/cmdparse.h
index f52e48f..77c8281 100644
--- a/packet/cmdparse.h
+++ b/packet/cmdparse.h
@@ -11,9 +11,9 @@
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    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 CMDPARSE_H
diff --git a/packet/command.c b/packet/command.c
index 42b9a52..2026352 100644
--- a/packet/command.c
+++ b/packet/command.c
@@ -11,20 +11,27 @@
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    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 "command.h"
 
 #include <assert.h>
 #include <errno.h>
+#ifdef HAVE_ERROR_H
+#include <error.h>
+#else
+#include "portability/error.h"
+#endif
+#include <fcntl.h>
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <strings.h>
+#include <unistd.h>
 
 #include "cmdparse.h"
 #include "platform.h"
@@ -321,6 +328,7 @@ void send_probe_command(
     param.ttl = 255;
     param.packet_size = 64;
     param.timeout = 10;
+    param.is_probing_byte_order = false;
 
     for (i = 0; i < command->argument_count; i++) {
         name = command->argument_name[i];
@@ -423,3 +431,63 @@ void dispatch_buffer_commands(
         buffer->incoming_read_position = 0;
     }
 }
+
+/*
+    Initialize the command buffer and put the command stream in
+    non-blocking mode.
+*/
+void init_command_buffer(
+    struct command_buffer_t *command_buffer,
+    int command_stream)
+{
+    int flags;
+
+    memset(command_buffer, 0, sizeof(struct command_buffer_t));
+    command_buffer->command_stream = command_stream;
+
+    /*  Get the current command stream flags  */
+    flags = fcntl(command_stream, F_GETFL, 0);
+    if (flags == -1) {
+        error(EXIT_FAILURE, errno, "Unexpected command stream error");
+    }
+
+    /*  Set the O_NONBLOCK bit  */
+    if (fcntl(command_stream, F_SETFL, flags | O_NONBLOCK)) {
+        error(EXIT_FAILURE, errno, "Unexpected command stream error");
+    }
+}
+
+/*  Read currently available data from the command stream  */
+int read_commands(
+    struct command_buffer_t *buffer)
+{
+    int space_remaining =
+        COMMAND_BUFFER_SIZE - buffer->incoming_read_position - 1;
+    char *read_position =
+        &buffer->incoming_buffer[buffer->incoming_read_position];
+    int read_count;
+    int command_stream = buffer->command_stream;
+
+    read_count = read(command_stream, read_position, space_remaining);
+
+    /*  If the command stream has been closed, read will return zero.  */
+    if (read_count == 0) {
+        errno = EPIPE;
+        return -1;
+    }
+
+    if (read_count > 0) {
+        /*  Account for the newly read data  */
+        buffer->incoming_read_position += read_count;
+    }
+
+    if (read_count < 0) {
+        /*  EAGAIN simply means there is no available data to read  */
+        /*  EINTR indicates we received a signal during read  */
+        if (errno != EINTR && errno != EAGAIN) {
+            error(EXIT_FAILURE, errno, "Unexpected command buffer read error");
+        }
+    }
+
+    return 0;
+}
diff --git a/packet/command.h b/packet/command.h
index a1fe025..f9f0c0a 100644
--- a/packet/command.h
+++ b/packet/command.h
@@ -11,25 +11,18 @@
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    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 COMMAND_H
 #define COMMAND_H
 
-#include "platform.h"
 #include "probe.h"
 
 #define COMMAND_BUFFER_SIZE 4096
 
-#ifdef PLATFORM_CYGWIN
-#include "command_cygwin.h"
-#else
-#include "command_unix.h"
-#endif
-
 /*  Storage for incoming commands, prior to command parsing  */
 struct command_buffer_t {
     /*  The file descriptor of the incoming command stream  */
@@ -40,9 +33,6 @@ struct command_buffer_t {
 
     /*  The number of bytes read so far in incoming_buffer  */
     int incoming_read_position;
-
-    /*  Platform specific  */
-    struct command_buffer_platform_t platform;
 };
 
 void init_command_buffer(
diff --git a/packet/command_cygwin.c b/packet/command_cygwin.c
deleted file mode 100644
index 5e12fd6..0000000
--- a/packet/command_cygwin.c
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
-    mtr  --  a network diagnostic tool
-    Copyright (C) 2016  Matt Kimball
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License version 2 as
-    published by the Free Software Foundation.
-
-    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., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include "command.h"
-
-#include <errno.h>
-#include <io.h>
-#include <stdio.h>
-
-/*
-    A completion routine to be called by Windows when a read from
-    the command stream has completed.
-*/
-static
-void CALLBACK finish_read_command(
-    DWORD status,
-    DWORD size_read,
-    OVERLAPPED * overlapped)
-{
-    struct command_buffer_t *buffer;
-    char *read_position;
-
-    /*
-       hEvent is unusuaed by ReadFileEx, so we use it to pass
-       our command_buffer structure.
-     */
-    buffer = (struct command_buffer_t *) overlapped->hEvent;
-
-    if (status) {
-        /*  When the stream is closed ERROR_BROKEN_PIPE will be the result  */
-        if (status == ERROR_BROKEN_PIPE) {
-            buffer->platform.pipe_open = false;
-            return;
-        }
-
-        fprintf(stderr, "ReadFileEx completion failure %d\n", status);
-        exit(EXIT_FAILURE);
-    }
-
-    /*  Copy from the overlapped I/O buffer to the incoming command buffer  */
-    read_position =
-        &buffer->incoming_buffer[buffer->incoming_read_position];
-    memcpy(read_position, buffer->platform.overlapped_buffer, size_read);
-
-    /*  Account for the newly read data  */
-    buffer->incoming_read_position += size_read;
-    buffer->platform.read_active = false;
-}
-
-/*
-    An APC which does nothing, to be used only to wake from the current
-    alertable wait.
-*/
-static
-void CALLBACK empty_apc(
-    ULONG * param)
-{
-}
-
-/*  Wake from the next alertable wait without waiting for newly read data  */
-static
-void queue_empty_apc(
-    void)
-{
-    if (QueueUserAPC((PAPCFUNC) empty_apc, GetCurrentThread(), 0) == 0) {
-        fprintf(stderr, "Unexpected QueueUserAPC failure %d\n",
-                GetLastError());
-        exit(EXIT_FAILURE);
-    }
-}
-
-/*  Start a new overlapped I/O read from the command stream  */
-void start_read_command(
-    struct command_buffer_t *buffer)
-{
-    HANDLE command_stream = (HANDLE) get_osfhandle(buffer->command_stream);
-    int space_remaining =
-        COMMAND_BUFFER_SIZE - buffer->incoming_read_position - 1;
-    int err;
-
-    /*  If a read is already active, or the pipe is closed, do nothing  */
-    if (!buffer->platform.pipe_open || buffer->platform.read_active) {
-        return;
-    }
-
-    memset(&buffer->platform.overlapped, 0, sizeof(OVERLAPPED));
-    buffer->platform.overlapped.hEvent = (HANDLE) buffer;
-
-    if (!ReadFileEx
-        (command_stream, buffer->platform.overlapped_buffer,
-         space_remaining, &buffer->platform.overlapped,
-         finish_read_command)) {
-
-        err = GetLastError();
-
-        if (err == ERROR_BROKEN_PIPE) {
-            /*  If the command stream has been closed, we need to wake from
-               the next altertable wait to exit the main loop  */
-            buffer->platform.pipe_open = false;
-            queue_empty_apc();
-
-            return;
-        } else if (err != WAIT_IO_COMPLETION) {
-            fprintf(stderr, "Unexpected ReadFileEx failure %d\n",
-                    GetLastError());
-            exit(EXIT_FAILURE);
-        }
-    }
-
-    /*  Remember that we have started an overlapped read already  */
-    buffer->platform.read_active = true;
-}
-
-/*  Initialize the command buffer, and start the first overlapped read  */
-void init_command_buffer(
-    struct command_buffer_t *command_buffer,
-    int command_stream)
-{
-    memset(command_buffer, 0, sizeof(struct command_buffer_t));
-    command_buffer->command_stream = command_stream;
-    command_buffer->platform.pipe_open = true;
-}
-
-/*
-    Return with errno EPIPE if the command stream has been closed.
-    Otherwise, not much to do for Cygwin, since we are using Overlapped I/O
-    to read commands.
-*/
-int read_commands(
-    struct command_buffer_t *buffer)
-{
-    if (!buffer->platform.pipe_open) {
-        errno = EPIPE;
-        return -1;
-    }
-
-    return 0;
-}
diff --git a/packet/command_cygwin.h b/packet/command_cygwin.h
deleted file mode 100644
index 9224468..0000000
--- a/packet/command_cygwin.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
-    mtr  --  a network diagnostic tool
-    Copyright (C) 2016  Matt Kimball
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License version 2 as
-    published by the Free Software Foundation.
-
-    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., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef COMMAND_CYGWIN_H
-#define COMMAND_CYGWIN_H
-
-/*
-    Though Cygwin supports the usual Unix non-blocking reads on
-    the command stream, we've got to use Overlapped I/O instead because
-    ICMP.DLL's support for sending probes requires Overlapped I/O
-    and alertable waits for notification of replies.  Since we need
-    alertable waits, we can't use Cygwin's select to determine when
-    command stream data is available, but Overlapped I/O completion
-    will work.
-*/
-
-/*  Overlapped I/O manament for Windows command buffer reads  */
-struct command_buffer_platform_t {
-    /*  true if an overlapped I/O read is active  */
-    bool read_active;
-
-    /*  true if the command pipe is still open  */
-    bool pipe_open;
-
-    /*  Windows OVERLAPPED I/O data  */
-    OVERLAPPED overlapped;
-
-    /*  The buffer which active OVERLAPPED reads read into  */
-    char overlapped_buffer[COMMAND_BUFFER_SIZE];
-};
-
-struct command_buffer_t;
-
-void start_read_command(
-    struct command_buffer_t *buffer);
-
-#endif
diff --git a/packet/command_unix.c b/packet/command_unix.c
deleted file mode 100644
index f6d20aa..0000000
--- a/packet/command_unix.c
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
-    mtr  --  a network diagnostic tool
-    Copyright (C) 2016  Matt Kimball
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License version 2 as
-    published by the Free Software Foundation.
-
-    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., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include "command.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-/*
-    Initialize the command buffer and put the command stream in
-    non-blocking mode.
-*/
-void init_command_buffer(
-    struct command_buffer_t *command_buffer,
-    int command_stream)
-{
-    int flags;
-
-    memset(command_buffer, 0, sizeof(struct command_buffer_t));
-    command_buffer->command_stream = command_stream;
-
-    /*  Get the current command stream flags  */
-    flags = fcntl(command_stream, F_GETFL, 0);
-    if (flags == -1) {
-        perror("Unexpected command stream error");
-        exit(EXIT_FAILURE);
-    }
-
-    /*  Set the O_NONBLOCK bit  */
-    if (fcntl(command_stream, F_SETFL, flags | O_NONBLOCK)) {
-        perror("Unexpected command stream error");
-        exit(EXIT_FAILURE);
-    }
-}
-
-/*  Read currently available data from the command stream  */
-int read_commands(
-    struct command_buffer_t *buffer)
-{
-    int space_remaining =
-        COMMAND_BUFFER_SIZE - buffer->incoming_read_position - 1;
-    char *read_position =
-        &buffer->incoming_buffer[buffer->incoming_read_position];
-    int read_count;
-    int command_stream = buffer->command_stream;
-
-    read_count = read(command_stream, read_position, space_remaining);
-
-    /*  If the command stream has been closed, read will return zero.  */
-    if (read_count == 0) {
-        errno = EPIPE;
-        return -1;
-    }
-
-    if (read_count > 0) {
-        /*  Account for the newly read data  */
-        buffer->incoming_read_position += read_count;
-    }
-
-    if (read_count < 0) {
-        /*  EAGAIN simply means there is no available data to read  */
-        /*  EINTR indicates we received a signal during read  */
-        if (errno != EINTR && errno != EAGAIN) {
-            perror("Unexpected command buffer read error");
-            exit(EXIT_FAILURE);
-        }
-    }
-
-    return 0;
-}
diff --git a/packet/command_unix.h b/packet/command_unix.h
deleted file mode 100644
index ab89726..0000000
--- a/packet/command_unix.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
-    mtr  --  a network diagnostic tool
-    Copyright (C) 2016  Matt Kimball
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License version 2 as
-    published by the Free Software Foundation.
-
-    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., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef COMMAND_UNIX_H
-#define COMMAND_UNIX_H
-
-/*  No platform specific data is required for Unix command streams  */
-struct command_buffer_platform_t {
-};
-
-#endif
diff --git a/packet/construct_unix.c b/packet/construct_unix.c
index b0f4679..09250bc 100644
--- a/packet/construct_unix.c
+++ b/packet/construct_unix.c
@@ -11,9 +11,9 @@
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    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 "construct_unix.h"
@@ -25,6 +25,12 @@
 #include <unistd.h>
 
 #include "protocols.h"
+#include "sockaddr.h"
+
+/* For Mac OS X and FreeBSD */
+#ifndef SOL_IP
+#define SOL_IP IPPROTO_IP
+#endif
 
 /*  A source of data for computing a checksum  */
 struct checksum_source_t {
@@ -85,33 +91,20 @@ void construct_addr_port(
     const struct sockaddr_storage *addr,
     int port)
 {
-    struct sockaddr_in *addr4;
-    struct sockaddr_in6 *addr6;
-
     memcpy(addr_with_port, addr, sizeof(struct sockaddr_storage));
-
-    if (addr->ss_family == AF_INET6) {
-        addr6 = (struct sockaddr_in6 *) addr_with_port;
-        addr6->sin6_port = htons(port);
-    } else {
-        addr4 = (struct sockaddr_in *) addr_with_port;
-        addr4->sin_port = htons(port);
-    }
+    *sockaddr_port_offset(addr_with_port) = htons(port);
 }
 
 /*  Construct a header for IP version 4  */
 static
 void construct_ip4_header(
     const struct net_state_t *net_state,
+    const struct probe_t *probe,
     char *packet_buffer,
     int packet_size,
-    const struct sockaddr_storage *srcaddr,
-    const struct sockaddr_storage *destaddr,
     const struct probe_param_t *param)
 {
     struct IPHeader *ip;
-    struct sockaddr_in *srcaddr4 = (struct sockaddr_in *) srcaddr;
-    struct sockaddr_in *destaddr4 = (struct sockaddr_in *) destaddr;
 
     ip = (struct IPHeader *) &packet_buffer[0];
 
@@ -122,15 +115,20 @@ void construct_ip4_header(
     ip->len = length_byte_swap(net_state, packet_size);
     ip->ttl = param->ttl;
     ip->protocol = param->protocol;
-    memcpy(&ip->saddr, &srcaddr4->sin_addr, sizeof(uint32_t));
-    memcpy(&ip->daddr, &destaddr4->sin_addr, sizeof(uint32_t));
+//    ip->id = htons(getpid());
+    memcpy(&ip->saddr,
+           sockaddr_addr_offset(&probe->local_addr),
+           sockaddr_addr_size(&probe->local_addr));
+    memcpy(&ip->daddr,
+           sockaddr_addr_offset(&probe->remote_addr),
+           sockaddr_addr_size(&probe->remote_addr));
 }
 
 /*  Construct an ICMP header for IPv4  */
 static
 void construct_icmp4_header(
     const struct net_state_t *net_state,
-    int sequence,
+    struct probe_t *probe,
     char *packet_buffer,
     int packet_size,
     const struct probe_param_t *param)
@@ -138,14 +136,19 @@ void construct_icmp4_header(
     struct ICMPHeader *icmp;
     int icmp_size;
 
-    icmp = (struct ICMPHeader *) &packet_buffer[sizeof(struct IPHeader)];
-    icmp_size = packet_size - sizeof(struct IPHeader);
+    if (net_state->platform.ip4_socket_raw) {
+        icmp = (struct ICMPHeader *) &packet_buffer[sizeof(struct IPHeader)];
+        icmp_size = packet_size - sizeof(struct IPHeader);
+    } else {
+        icmp = (struct ICMPHeader *) &packet_buffer[0];
+        icmp_size = packet_size;
+    }
 
     memset(icmp, 0, sizeof(struct ICMPHeader));
 
     icmp->type = ICMP_ECHO;
     icmp->id = htons(getpid());
-    icmp->sequence = htons(sequence);
+    icmp->sequence = htons(probe->sequence);
     icmp->checksum = htons(compute_checksum(icmp, icmp_size));
 }
 
@@ -153,7 +156,7 @@ void construct_icmp4_header(
 static
 int construct_icmp6_packet(
     const struct net_state_t *net_state,
-    int sequence,
+    struct probe_t *probe,
     char *packet_buffer,
     int packet_size,
     const struct probe_param_t *param)
@@ -166,7 +169,7 @@ int construct_icmp6_packet(
 
     icmp->type = ICMP6_ECHO;
     icmp->id = htons(getpid());
-    icmp->sequence = htons(sequence);
+    icmp->sequence = htons(probe->sequence);
 
     return 0;
 }
@@ -183,7 +186,7 @@ int construct_icmp6_packet(
 static
 void set_udp_ports(
     struct UDPHeader *udp,
-    int sequence,
+    struct probe_t *probe,
     const struct probe_param_t *param)
 {
     if (param->dest_port) {
@@ -191,13 +194,13 @@ void set_udp_ports(
 
         if (param->local_port) {
             udp->srcport = htons(param->local_port);
-            udp->checksum = htons(sequence);
+            udp->checksum = htons(probe->sequence);
         } else {
-            udp->srcport = htons(sequence);
+            udp->srcport = htons(probe->sequence);
             udp->checksum = 0;
         }
     } else {
-        udp->dstport = htons(sequence);
+        udp->dstport = htons(probe->sequence);
 
         if (param->local_port) {
             udp->srcport = htons(param->local_port);
@@ -207,6 +210,27 @@ void set_udp_ports(
 
         udp->checksum = 0;
     }
+    *sockaddr_port_offset(&probe->local_addr) = udp->srcport;
+    *sockaddr_port_offset(&probe->remote_addr) = udp->dstport;
+}
+
+/* Prepend pseudoheader to the udp datagram and calculate checksum */
+static
+int udp4_checksum(void *pheader, void *udata, int psize, int dsize,
+                  int alt_checksum)
+{
+    unsigned int totalsize = psize + dsize;
+    unsigned char csumpacket[totalsize];
+
+    memcpy(csumpacket, pheader, psize); /* pseudo header */
+    memcpy(csumpacket+psize, udata, dsize);   /* udp header & payload */
+
+    if (alt_checksum && dsize >= sizeof(struct UDPHeader) + 2) {
+        csumpacket[psize + sizeof(struct UDPHeader)] = 0;
+        csumpacket[psize + sizeof(struct UDPHeader) + 1] = 0;
+    }
+
+    return compute_checksum(csumpacket, totalsize);
 }
 
 /*
@@ -216,7 +240,7 @@ void set_udp_ports(
 static
 void construct_udp4_header(
     const struct net_state_t *net_state,
-    int sequence,
+    struct probe_t *probe,
     char *packet_buffer,
     int packet_size,
     const struct probe_param_t *param)
@@ -224,20 +248,48 @@ void construct_udp4_header(
     struct UDPHeader *udp;
     int udp_size;
 
-    udp = (struct UDPHeader *) &packet_buffer[sizeof(struct IPHeader)];
-    udp_size = packet_size - sizeof(struct IPHeader);
+    if (net_state->platform.ip4_socket_raw) {
+        udp = (struct UDPHeader *) &packet_buffer[sizeof(struct IPHeader)];
+        udp_size = packet_size - sizeof(struct IPHeader);
+    } else {
+        udp = (struct UDPHeader *) &packet_buffer[0];
+        udp_size = packet_size;
+    }
 
     memset(udp, 0, sizeof(struct UDPHeader));
 
-    set_udp_ports(udp, sequence, param);
+    set_udp_ports(udp, probe, param);
     udp->length = htons(udp_size);
+
+    /* calculate udp checksum */
+    struct UDPPseudoHeader udph = {
+        .saddr = *(uint32_t *)sockaddr_addr_offset(&probe->local_addr),
+        .daddr = *(uint32_t *)sockaddr_addr_offset(&probe->remote_addr),
+        .zero = 0,
+        .protocol = 17,
+        .len = udp->length
+    };
+
+    /* get position to write checksum */
+    uint16_t *checksum_off = &udp->checksum;
+
+    if (udp->checksum != 0)
+    { /* checksum is sequence number - correct the payload to match the checksum
+         checksum_off is udp payload */
+        checksum_off = (uint16_t *)&packet_buffer[packet_size -
+                                                  udp_size +
+                                                  sizeof(struct UDPHeader)];
+    }
+    *checksum_off = htons(udp4_checksum(&udph, udp,
+                                        sizeof(struct UDPPseudoHeader),
+                                        udp_size, udp->checksum != 0));
 }
 
 /*  Construct a header for UDPv6 probes  */
 static
 int construct_udp6_packet(
     const struct net_state_t *net_state,
-    int sequence,
+    struct probe_t *probe,
     char *packet_buffer,
     int packet_size,
     const struct probe_param_t *param)
@@ -251,17 +303,19 @@ int construct_udp6_packet(
 
     memset(udp, 0, sizeof(struct UDPHeader));
 
-    set_udp_ports(udp, sequence, param);
+    set_udp_ports(udp, probe, param);
     udp->length = htons(udp_size);
 
-    /*
-       Instruct the kernel to put the pseudoheader checksum into the
-       UDP header.
-     */
-    int chksum_offset = (char *) &udp->checksum - (char *) udp;
-    if (setsockopt(udp_socket, IPPROTO_IPV6,
-                   IPV6_CHECKSUM, &chksum_offset, sizeof(int))) {
-        return -1;
+    if (net_state->platform.ip6_socket_raw) {
+        /*
+           Instruct the kernel to put the pseudoheader checksum into the
+           UDP header, this is only needed when using RAW socket.
+         */
+        int chksum_offset = (char *) &udp->checksum - (char *) udp;
+        if (setsockopt(udp_socket, IPPROTO_IPV6,
+                       IPV6_CHECKSUM, &chksum_offset, sizeof(int))) {
+            return -1;
+        }
     }
 
     return 0;
@@ -425,7 +479,7 @@ int compute_packet_size(
     const struct net_state_t *net_state,
     const struct probe_param_t *param)
 {
-    int packet_size;
+    int packet_size = 0;
 
     if (param->protocol == IPPROTO_TCP) {
         return 0;
@@ -438,9 +492,13 @@ int compute_packet_size(
 
     /*  Start by determining the full size, including omitted headers  */
     if (param->ip_version == 6) {
-        packet_size = sizeof(struct IP6Header);
+        if (net_state->platform.ip6_socket_raw) {
+            packet_size += sizeof(struct IP6Header);
+        }
     } else if (param->ip_version == 4) {
-        packet_size = sizeof(struct IPHeader);
+        if (net_state->platform.ip4_socket_raw) {
+            packet_size += sizeof(struct IPHeader);
+        }
     } else {
         errno = EINVAL;
         return -1;
@@ -470,7 +528,7 @@ int compute_packet_size(
        Since we don't explicitly construct the IPv6 header, we
        need to account for it in our transmitted size.
      */
-    if (param->ip_version == 6) {
+    if (param->ip_version == 6 && net_state->platform.ip6_socket_raw) {
         packet_size -= sizeof(struct IP6Header);
     }
 
@@ -482,15 +540,17 @@ static
 int construct_ip4_packet(
     const struct net_state_t *net_state,
     int *packet_socket,
-    int sequence,
+    struct probe_t *probe,
     char *packet_buffer,
     int packet_size,
-    const struct sockaddr_storage *src_sockaddr,
-    const struct sockaddr_storage *dest_sockaddr,
     const struct probe_param_t *param)
 {
     int send_socket = net_state->platform.ip4_send_socket;
     bool is_stream_protocol = false;
+    int tos, ttl, socket;
+    bool bind_send_socket = false;
+    struct sockaddr_storage current_sockaddr;
+    int current_sockaddr_len;
 
     if (param->protocol == IPPROTO_TCP) {
         is_stream_protocol = true;
@@ -499,14 +559,15 @@ int construct_ip4_packet(
         is_stream_protocol = true;
 #endif
     } else {
-        construct_ip4_header(net_state, packet_buffer, packet_size,
-                             src_sockaddr, dest_sockaddr, param);
-
+        if (net_state->platform.ip4_socket_raw) {
+            construct_ip4_header(net_state, probe, packet_buffer, packet_size,
+                                  param);
+        }
         if (param->protocol == IPPROTO_ICMP) {
-            construct_icmp4_header(net_state, sequence, packet_buffer,
+            construct_icmp4_header(net_state, probe, packet_buffer,
                                    packet_size, param);
         } else if (param->protocol == IPPROTO_UDP) {
-            construct_udp4_header(net_state, sequence, packet_buffer,
+            construct_udp4_header(net_state, probe, packet_buffer,
                                   packet_size, param);
         } else {
             errno = EINVAL;
@@ -516,8 +577,8 @@ int construct_ip4_packet(
 
     if (is_stream_protocol) {
         send_socket =
-            open_stream_socket(net_state, param->protocol, sequence,
-                               src_sockaddr, dest_sockaddr, param);
+            open_stream_socket(net_state, param->protocol, probe->sequence,
+                               &probe->local_addr, &probe->remote_addr, param);
 
         if (send_socket == -1) {
             return -1;
@@ -546,6 +607,55 @@ int construct_ip4_packet(
     }
 #endif
 
+    /*
+       Bind src port when not using raw socket to pass in ICMP id, kernel
+       get ICMP id from src_port when using DGRAM socket.
+     */
+    if (!net_state->platform.ip4_socket_raw &&
+            param->protocol == IPPROTO_ICMP &&
+            !param->is_probing_byte_order) {
+        current_sockaddr_len = sizeof(struct sockaddr_in);
+        bind_send_socket = true;
+        socket = net_state->platform.ip4_txrx_icmp_socket;
+        if (getsockname(socket, (struct sockaddr *) &current_sockaddr,
+                        &current_sockaddr_len)) {
+            return -1;
+        }
+        struct sockaddr_in *sin_cur =
+            (struct sockaddr_in *) &current_sockaddr;
+
+        /* avoid double bind */
+        if (sin_cur->sin_port) {
+            bind_send_socket = false;
+        }
+    }
+
+    /*  Bind to our local address  */
+    if (bind_send_socket && bind(socket, (struct sockaddr *)&probe->local_addr,
+                sizeof(struct sockaddr_in))) {
+        return -1;
+    }
+
+    /* set TOS and TTL for non-raw socket */
+    if (!net_state->platform.ip4_socket_raw && !param->is_probing_byte_order) {
+        if (param->protocol == IPPROTO_ICMP) {
+            socket = net_state->platform.ip4_txrx_icmp_socket;
+        } else if (param->protocol == IPPROTO_UDP) {
+            socket = net_state->platform.ip4_txrx_udp_socket;
+        } else {
+            return 0;
+        }
+        tos = param->type_of_service;
+        if (setsockopt(socket, SOL_IP, IP_TOS, &tos, sizeof(int))) {
+            return -1;
+        }
+        ttl = param->ttl;
+        if (setsockopt(socket, SOL_IP, IP_TTL,
+                       &ttl, sizeof(int)) == -1) {
+            return -1;
+        }
+    }
+
     return 0;
 }
 
@@ -554,11 +664,9 @@ static
 int construct_ip6_packet(
     const struct net_state_t *net_state,
     int *packet_socket,
-    int sequence,
+    struct probe_t *probe,
     char *packet_buffer,
     int packet_size,
-    const struct sockaddr_storage *src_sockaddr,
-    const struct sockaddr_storage *dest_sockaddr,
     const struct probe_param_t *param)
 {
     int send_socket;
@@ -574,17 +682,25 @@ int construct_ip6_packet(
         is_stream_protocol = true;
 #endif
     } else if (param->protocol == IPPROTO_ICMP) {
-        send_socket = net_state->platform.icmp6_send_socket;
+        if (net_state->platform.ip6_socket_raw) {
+            send_socket = net_state->platform.icmp6_send_socket;
+        } else {
+            send_socket = net_state->platform.ip6_txrx_icmp_socket;
+        }
 
         if (construct_icmp6_packet
-            (net_state, sequence, packet_buffer, packet_size, param)) {
+            (net_state, probe, packet_buffer, packet_size, param)) {
             return -1;
         }
     } else if (param->protocol == IPPROTO_UDP) {
-        send_socket = net_state->platform.udp6_send_socket;
+        if (net_state->platform.ip6_socket_raw) {
+            send_socket = net_state->platform.udp6_send_socket;
+        } else {
+            send_socket = net_state->platform.ip6_txrx_udp_socket;
+        }
 
         if (construct_udp6_packet
-            (net_state, sequence, packet_buffer, packet_size, param)) {
+            (net_state, probe, packet_buffer, packet_size, param)) {
             return -1;
         }
     } else {
@@ -594,8 +710,8 @@ int construct_ip6_packet(
 
     if (is_stream_protocol) {
         send_socket =
-            open_stream_socket(net_state, param->protocol, sequence,
-                               src_sockaddr, dest_sockaddr, param);
+            open_stream_socket(net_state, param->protocol, probe->sequence,
+                               &probe->local_addr, &probe->remote_addr, param);
 
         if (send_socket == -1) {
             return -1;
@@ -615,16 +731,24 @@ int construct_ip6_packet(
     current_sockaddr_len = sizeof(struct sockaddr_in6);
     if (getsockname(send_socket, (struct sockaddr *) &current_sockaddr,
                     &current_sockaddr_len) == 0) {
+        struct sockaddr_in6 *sin6_cur = (struct sockaddr_in6 *) &current_sockaddr;
 
-        if (memcmp(&current_sockaddr,
-                   src_sockaddr, sizeof(struct sockaddr_in6)) == 0) {
-            bind_send_socket = false;
+        if (net_state->platform.ip6_socket_raw) {
+            if (memcmp(&current_sockaddr,
+                       &probe->local_addr, sizeof(struct sockaddr_in6)) == 0) {
+                bind_send_socket = false;
+            }
+        } else {
+            /* avoid double bind for DGRAM socket */
+            if (sin6_cur->sin6_port) {
+                bind_send_socket = false;
+            }
         }
     }
 
     /*  Bind to our local address  */
     if (bind_send_socket) {
-        if (bind(send_socket, (struct sockaddr *) src_sockaddr,
+        if (bind(send_socket, (struct sockaddr *) &probe->local_addr,
                  sizeof(struct sockaddr_in6))) {
             return -1;
         }
@@ -658,11 +782,9 @@ int construct_ip6_packet(
 int construct_packet(
     const struct net_state_t *net_state,
     int *packet_socket,
-    int sequence,
+    struct probe_t *probe,
     char *packet_buffer,
     int packet_buffer_size,
-    const struct sockaddr_storage *dest_sockaddr,
-    const struct sockaddr_storage *src_sockaddr,
     const struct probe_param_t *param)
 {
     int packet_size;
@@ -680,15 +802,15 @@ int construct_packet(
     memset(packet_buffer, param->bit_pattern, packet_size);
 
     if (param->ip_version == 6) {
-        if (construct_ip6_packet(net_state, packet_socket, sequence,
+        if (construct_ip6_packet(net_state, packet_socket, probe,
                                  packet_buffer, packet_size,
-                                 src_sockaddr, dest_sockaddr, param)) {
+                                 param)) {
             return -1;
         }
     } else if (param->ip_version == 4) {
-        if (construct_ip4_packet(net_state, packet_socket, sequence,
+        if (construct_ip4_packet(net_state, packet_socket, probe,
                                  packet_buffer, packet_size,
-                                 src_sockaddr, dest_sockaddr, param)) {
+                                 param)) {
             return -1;
         }
     } else {
diff --git a/packet/construct_unix.h b/packet/construct_unix.h
index 7ac7110..99e1305 100644
--- a/packet/construct_unix.h
+++ b/packet/construct_unix.h
@@ -11,9 +11,9 @@
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    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 CONSTRUCT_H
@@ -24,11 +24,9 @@
 int construct_packet(
     const struct net_state_t *net_state,
     int *packet_socket,
-    int sequence,
+    struct probe_t *probe,
     char *packet_buffer,
     int packet_buffer_size,
-    const struct sockaddr_storage *dest_sockaddr,
-    const struct sockaddr_storage *src_sockaddr,
     const struct probe_param_t *param);
 
 #endif
diff --git a/packet/deconstruct_unix.c b/packet/deconstruct_unix.c
index ce889ca..1af7419 100644
--- a/packet/deconstruct_unix.c
+++ b/packet/deconstruct_unix.c
@@ -11,9 +11,9 @@
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    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 "deconstruct_unix.h"
@@ -23,6 +23,7 @@
 #include <string.h>
 
 #include "protocols.h"
+#include "sockaddr.h"
 
 #define MAX_MPLS_LABELS 8
 
@@ -64,6 +65,8 @@ void handle_inner_udp_packet(
     struct net_state_t *net_state,
     const struct sockaddr_storage *remote_addr,
     int icmp_result,
+    int af,
+    const void *ip,
     const struct UDPHeader *udp,
     int udp_length,
     struct timeval *timestamp,
@@ -79,11 +82,67 @@ void handle_inner_udp_packet(
     if (probe == NULL) {
         probe = find_probe(net_state, IPPROTO_UDP, 0, udp->checksum);
     }
+    if (probe == NULL)
+        return;
+
+    if (probe->remote_addr.ss_family != remote_addr->ss_family)
+        return;
+
+    if (udp->dstport != *sockaddr_port_offset(&probe->remote_addr) )
+        return;
+
+    if (udp->srcport != *sockaddr_port_offset(&probe->local_addr) )
+        return;
+
+    void *saddr, *daddr;
+    if (af == AF_INET)
+    {
+        saddr = &((struct IPHeader *)ip)->saddr;
+        daddr = &((struct IPHeader *)ip)->daddr;
+    }else
+    if (af == AF_INET6)
+    {
+        daddr = &((struct IP6Header *)ip)->daddr;
+        saddr = &((struct IP6Header *)ip)->saddr;
+    }else
+    {
+        return;
+    }
 
-    if (probe != NULL) {
-        receive_probe(net_state, probe, icmp_result,
+    if( memcmp(sockaddr_addr_offset(&probe->remote_addr),
+               daddr,
+               sockaddr_addr_size(&probe->remote_addr)) != 0 )
+            return;
+
+    if( memcmp(sockaddr_addr_offset(&probe->local_addr),
+           saddr,
+           sockaddr_addr_size(&probe->local_addr)) != 0)
+        return;
+
+    /* probe is not null */
+    receive_probe(net_state, probe, icmp_result,
                       remote_addr, timestamp, mpls_count, mpls);
+}
+
+void handle_error_queue_packet(
+    struct net_state_t *net_state,
+    const struct sockaddr_storage *remote_addr,
+    int icmp_result,
+    int proto,
+    char *packet,
+    int packet_length,
+    struct timeval *timestamp)
+{
+    if (proto == IPPROTO_UDP) {
+        handle_inner_udp_packet(net_state, remote_addr, ICMP_TIME_EXCEEDED, 0, NULL,
+                (struct UDPHeader *)packet, packet_length, timestamp, 0, NULL);
+    } else if (proto == IPPROTO_ICMP || proto == IPPROTO_ICMPV6) {
+        const struct ICMPHeader *icmp = (struct ICMPHeader *)packet;
+        find_and_receive_probe(net_state, remote_addr, timestamp,
+                               ICMP_TIME_EXCEEDED, IPPROTO_ICMP, icmp->id,
+                               icmp->sequence, 0, NULL);
     }
+
 }
 
 /*
@@ -136,7 +195,7 @@ void handle_inner_ip4_packet(
         udp = (struct UDPHeader *) (ip + 1);
         udp_length = packet_length - sizeof(struct IPHeader);
 
-        handle_inner_udp_packet(net_state, remote_addr, icmp_result, udp,
+        handle_inner_udp_packet(net_state, remote_addr, icmp_result, AF_INET, ip, udp,
                                 udp_length, timestamp, mpls_count, mpls);
     } else if (ip->protocol == IPPROTO_TCP) {
         if (packet_length < ip_tcp_size) {
@@ -212,7 +271,7 @@ void handle_inner_ip6_packet(
         udp = (struct UDPHeader *) (ip + 1);
         udp_length = packet_length - sizeof(struct IP6Header);
 
-        handle_inner_udp_packet(net_state, remote_addr, icmp_result, udp,
+        handle_inner_udp_packet(net_state, remote_addr, icmp_result, AF_INET6, ip, udp,
                                 udp_length, timestamp, mpls_count, mpls);
     } else if (ip->protocol == IPPROTO_TCP) {
         if (packet_length < ip_tcp_size) {
@@ -266,7 +325,7 @@ int decode_mpls_object(
         label->label =
             ext_label->label[0] << 12 |
             ext_label->label[1] << 4 | ext_label->label[2] >> 4;
-        label->experimental_use = (ext_label->label[2] & 0x0E) >> 1;
+        label->traffic_class = (ext_label->label[2] & 0x0E) >> 1;
         label->bottom_of_stack = ext_label->label[2] & 0x01;
         label->ttl = ext_label->ttl;
     }
@@ -347,13 +406,16 @@ void handle_received_icmp4_packet(
     int packet_length,
     struct timeval *timestamp)
 {
-    const int icmp_ip_size =
-        sizeof(struct ICMPHeader) + sizeof(struct IPHeader);
+    int icmp_ip_size = 0;
     const struct IPHeader *inner_ip;
     int inner_size = packet_length - sizeof(struct ICMPHeader);
     int mpls_count;
     struct mpls_label_t mpls[MAX_MPLS_LABELS];
 
+    if (net_state->platform.ip4_socket_raw) {
+        icmp_ip_size += sizeof(struct IPHeader);
+    }
+    icmp_ip_size += sizeof(struct ICMPHeader);
     mpls_count =
         decode_mpls_labels(icmp, packet_length, mpls, MAX_MPLS_LABELS);
 
@@ -394,6 +456,15 @@ void handle_received_icmp4_packet(
             handle_inner_ip4_packet(net_state, remote_addr,
                                     ICMP_ECHOREPLY, inner_ip, inner_size,
                                     timestamp, mpls_count, mpls);
+        } else {
+            /*
+                ICMP_DEST_UNREACH subtypes other than port unreachable
+                indicate an exceptional condition, and will be reported
+                as a "no route to host" probe response.
+            */
+            handle_inner_ip4_packet(net_state, remote_addr,
+                                    ICMP_DEST_UNREACH, inner_ip, inner_size,
+                                    timestamp, mpls_count, mpls);
         }
     }
 }
@@ -443,6 +514,10 @@ void handle_received_icmp6_packet(
             handle_inner_ip6_packet(net_state, remote_addr,
                                     ICMP_ECHOREPLY, inner_ip, inner_size,
                                     timestamp, mpls_count, mpls);
+        } else {
+            handle_inner_ip6_packet(net_state, remote_addr,
+                                    ICMP_DEST_UNREACH, inner_ip, inner_size,
+                                    timestamp, mpls_count, mpls);
         }
     }
 }
@@ -459,24 +534,33 @@ void handle_received_ip4_packet(
     int packet_length,
     struct timeval *timestamp)
 {
-    const int ip_icmp_size =
-        sizeof(struct IPHeader) + sizeof(struct ICMPHeader);
+    int ip_icmp_size = 0;
     const struct IPHeader *ip;
     const struct ICMPHeader *icmp;
     int icmp_length;
 
+    if (net_state->platform.ip4_socket_raw) {
+        ip_icmp_size += sizeof(struct IPHeader);
+    }
+    ip_icmp_size += sizeof(struct ICMPHeader);
+
     /*  Ensure that we don't access memory beyond the bounds of the packet  */
     if (packet_length < ip_icmp_size) {
         return;
     }
 
-    ip = (struct IPHeader *) packet;
-    if (ip->protocol != IPPROTO_ICMP) {
-        return;
-    }
+    if (net_state->platform.ip4_socket_raw) {
+        ip = (struct IPHeader *) packet;
+        if (ip->protocol != IPPROTO_ICMP) {
+            return;
+        }
 
-    icmp = (struct ICMPHeader *) (ip + 1);
-    icmp_length = packet_length - sizeof(struct IPHeader);
+        icmp = (struct ICMPHeader *) (ip + 1);
+        icmp_length = packet_length - sizeof(struct IPHeader);
+    } else {
+        icmp = (struct ICMPHeader *) packet;
+        icmp_length = packet_length;
+    }
 
     handle_received_icmp4_packet(net_state, remote_addr, icmp, icmp_length,
                                  timestamp);
diff --git a/packet/deconstruct_unix.h b/packet/deconstruct_unix.h
index 69186cd..08e6aee 100644
--- a/packet/deconstruct_unix.h
+++ b/packet/deconstruct_unix.h
@@ -11,9 +11,9 @@
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    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 DECONSTRUCT_H
@@ -43,4 +43,13 @@ void handle_received_ip6_packet(
     int packet_length,
     struct timeval *timestamp);
 
+void handle_error_queue_packet(
+    struct net_state_t *net_state,
+    const struct sockaddr_storage *remote_addr,
+    int icmp_result,
+    int proto,
+    char *packet,
+    int packet_length,
+    struct timeval *timestamp);
+
 #endif
diff --git a/packet/packet.c b/packet/packet.c
index f32f729..a8c2b6e 100644
--- a/packet/packet.c
+++ b/packet/packet.c
@@ -11,14 +11,19 @@
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    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 "config.h"
 
 #include <errno.h>
+#ifdef HAVE_ERROR_H
+#include <error.h>
+#else
+#include "portability/error.h"
+#endif
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -83,8 +88,7 @@ int main(
      */
     init_net_state_privileged(&net_state);
     if (drop_elevated_permissions()) {
-        perror("Unable to drop elevated permissions");
-        exit(EXIT_FAILURE);
+        error(EXIT_FAILURE, errno, "Unable to drop elevated permissions");
     }
     init_net_state(&net_state);
 
diff --git a/packet/platform.h b/packet/platform.h
index cca1274..3b0fbef 100644
--- a/packet/platform.h
+++ b/packet/platform.h
@@ -11,9 +11,9 @@
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    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 PLATFORM_H
diff --git a/packet/probe.c b/packet/probe.c
index 34ff368..0177e97 100644
--- a/packet/probe.c
+++ b/packet/probe.c
@@ -11,9 +11,9 @@
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    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 "probe.h"
@@ -21,6 +21,11 @@
 #include <arpa/inet.h>
 #include <assert.h>
 #include <errno.h>
+#ifdef HAVE_ERROR_H
+#include <error.h>
+#else
+#include "portability/error.h"
+#endif
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -31,8 +36,7 @@
 #include "platform.h"
 #include "protocols.h"
 #include "timeval.h"
-
-#define IP_TEXT_LENGTH 64
+#include "sockaddr.h"
 
 /*  Convert the destination address from text to sockaddr  */
 int decode_address_string(
@@ -87,6 +91,7 @@ int decode_address_string(
     for the probe.
 */
 int resolve_probe_addresses(
+    struct net_state_t *net_state,
     const struct probe_param_t *param,
     struct sockaddr_storage *dest_sockaddr,
     struct sockaddr_storage *src_sockaddr)
@@ -106,6 +111,12 @@ int resolve_probe_addresses(
             return -1;
         }
     }
+    /* DGRAM ICMP id is taken from src_port not from ICMP header */
+    if (param->protocol == IPPROTO_ICMP) {
+        if ( (src_sockaddr->ss_family == AF_INET && !net_state->platform.ip4_socket_raw) ||
+             (src_sockaddr->ss_family == AF_INET6 && !net_state->platform.ip6_socket_raw) )
+            *sockaddr_port_offset(src_sockaddr) = htons(getpid());
+    }
 
     return 0;
 }
@@ -215,7 +226,7 @@ void format_mpls_string(
         }
 
         snprintf(append_pos, buffer_size, "%d,%d,%d,%d",
-                 mpls->label, mpls->experimental_use,
+                 mpls->label, mpls->traffic_class,
                  mpls->bottom_of_stack, mpls->ttl);
 
         buffer_size -= strlen(append_pos);
@@ -236,18 +247,17 @@ void respond_to_probe(
     int mpls_count,
     const struct mpls_label_t *mpls)
 {
-    char ip_text[IP_TEXT_LENGTH];
+    char ip_text[INET6_ADDRSTRLEN];
     char response[COMMAND_BUFFER_SIZE];
     char mpls_str[COMMAND_BUFFER_SIZE];
     int remaining_size;
     const char *result;
     const char *ip_argument;
-    struct sockaddr_in *sockaddr4;
-    struct sockaddr_in6 *sockaddr6;
-    void *addr;
 
     if (icmp_type == ICMP_TIME_EXCEEDED) {
         result = "ttl-expired";
+    } else if (icmp_type == ICMP_DEST_UNREACH) {
+        result = "no-route";
     } else {
         assert(icmp_type == ICMP_ECHOREPLY);
         result = "reply";
@@ -255,19 +265,13 @@ void respond_to_probe(
 
     if (remote_addr->ss_family == AF_INET6) {
         ip_argument = "ip-6";
-        sockaddr6 = (struct sockaddr_in6 *) remote_addr;
-        addr = &sockaddr6->sin6_addr;
     } else {
         ip_argument = "ip-4";
-        sockaddr4 = (struct sockaddr_in *) remote_addr;
-        addr = &sockaddr4->sin_addr;
     }
 
-    if (inet_ntop(remote_addr->ss_family, addr, ip_text, IP_TEXT_LENGTH) ==
+    if (inet_ntop(remote_addr->ss_family, sockaddr_addr_offset(remote_addr), ip_text, INET6_ADDRSTRLEN) ==
         NULL) {
-
-        perror("inet_ntop failure");
-        exit(EXIT_FAILURE);
+        error(EXIT_FAILURE, errno, "inet_ntop failure");
     }
 
     snprintf(response, COMMAND_BUFFER_SIZE,
@@ -306,8 +310,6 @@ int find_source_addr(
 {
     int sock;
     int len;
-    struct sockaddr_in *destaddr4;
-    struct sockaddr_in6 *destaddr6;
     struct sockaddr_storage dest_with_port;
     struct sockaddr_in *srcaddr4;
     struct sockaddr_in6 *srcaddr6;
@@ -320,31 +322,40 @@ int find_source_addr(
        the connect will fail.  We aren't actually sending
        anything to the port.
      */
-    if (destaddr->ss_family == AF_INET6) {
-        destaddr6 = (struct sockaddr_in6 *) &dest_with_port;
-        destaddr6->sin6_port = htons(1);
-
-        len = sizeof(struct sockaddr_in6);
-    } else {
-        destaddr4 = (struct sockaddr_in *) &dest_with_port;
-        destaddr4->sin_port = htons(1);
-
-        len = sizeof(struct sockaddr_in);
-    }
+    *sockaddr_port_offset(&dest_with_port) = htons(1);
+    len = sockaddr_addr_size(&dest_with_port);
 
     sock = socket(destaddr->ss_family, SOCK_DGRAM, IPPROTO_UDP);
     if (sock == -1) {
         return -1;
     }
 
-    if (connect(sock, (struct sockaddr *) &dest_with_port, len)) {
-        close(sock);
-        return -1;
-    }
+    if (connect(sock, (struct sockaddr *) &dest_with_port, len) == 0) {
+        if (getsockname(sock, (struct sockaddr *) srcaddr, &len)) {
+            close(sock);
+            return -1;
+        }
+    } else {
+#ifdef __linux__
+        /* Linux doesn't require source address, so we can support
+         * a case when mtr is run against unreachable host (that can become
+         * reachable) */
+        if (errno != EHOSTUNREACH) {
+            close(sock);
+            return -1;
+        }
 
-    if (getsockname(sock, (struct sockaddr *) srcaddr, &len)) {
+        if (destaddr->ss_family == AF_INET6) {
+            srcaddr6 = (struct sockaddr_in6 *) srcaddr;
+            srcaddr6->sin6_addr = in6addr_any;
+        } else {
+            srcaddr4 = (struct sockaddr_in *) srcaddr;
+            srcaddr4->sin_addr.s_addr = INADDR_ANY;
+        }
+#else
         close(sock);
         return -1;
+#endif
     }
 
     close(sock);
@@ -353,15 +364,7 @@ int find_source_addr(
        Zero the port, as we may later use this address to finding, and
        we don't want to use the port from the socket we just created.
      */
-    if (destaddr->ss_family == AF_INET6) {
-        srcaddr6 = (struct sockaddr_in6 *) srcaddr;
-
-        srcaddr6->sin6_port = 0;
-    } else {
-        srcaddr4 = (struct sockaddr_in *) srcaddr;
-
-        srcaddr4->sin_port = 0;
-    }
+    *sockaddr_port_offset(&srcaddr) = 0;
 
     return 0;
 }
diff --git a/packet/probe.h b/packet/probe.h
index 9c8dfc6..53b8037 100644
--- a/packet/probe.h
+++ b/packet/probe.h
@@ -11,9 +11,9 @@
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    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 PROBE_H
@@ -79,6 +79,9 @@ struct probe_param_t {
 
     /*  The number of seconds to wait before assuming the probe was lost  */
     int timeout;
+
+    /*  true is the probe is to test byte order */
+    bool is_probing_byte_order;
 };
 
 /*  Tracking information for an outstanding probe  */
@@ -101,6 +104,10 @@ struct probe_t {
     /*  The address being probed  */
     struct sockaddr_storage remote_addr;
 
+    /* The local address which was used */
+    struct sockaddr_storage local_addr;
+
+
     /*  Platform specific probe tracking  */
     struct probe_platform_t platform;
 };
@@ -122,7 +129,7 @@ struct net_state_t {
 /*  Multiprotocol Label Switching information  */
 struct mpls_label_t {
     uint32_t label;
-    uint8_t experimental_use;
+    uint8_t traffic_class;
     uint8_t bottom_of_stack;
     uint8_t ttl;
 };
@@ -170,6 +177,7 @@ int decode_address_string(
     struct sockaddr_storage *address);
 
 int resolve_probe_addresses(
+    struct net_state_t *net_state,
     const struct probe_param_t *param,
     struct sockaddr_storage *dest_sockaddr,
     struct sockaddr_storage *src_sockaddr);
diff --git a/packet/probe_cygwin.c b/packet/probe_cygwin.c
index 56bd2b9..79e9fdb 100644
--- a/packet/probe_cygwin.c
+++ b/packet/probe_cygwin.c
@@ -11,29 +11,105 @@
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    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 "probe.h"
 
+#include <assert.h>
 #include <errno.h>
+#include <error.h>
+#include <fcntl.h>
+#include <io.h>
 #include <stdio.h>
+#include <unistd.h>
 #include <winternl.h>
 
 #include "protocols.h"
 
+
+/*
+    Implementation notes  (or "Why this uses a worker thread")
+
+    Having done my time debugging various race conditions over the
+    last twenty-plus years as a software developer, both of my own
+    creation and discovered in the code of others, I almost always
+    try to structure my code to be single-threaded.  However,
+    I think in this case, the ICMP service thread is unavoidable.
+
+    I would have liked to avoid multithreading entirely, but here are
+    the constraints:
+
+        a)  mtr was originally a Unix program which used "raw sockets".
+        b)  In order to port mtr to Windows, Cygwin is used to get a
+            Unix-like environment.
+        c)  You can't use a raw socket to receive an ICMP reply on Windows.
+            However, Windows provides a separate API in the form of
+            ICMP.DLL for sending and receiving ICMP messages.
+        d)  The ICMP API works asynchronously, and requires completion
+            through an asynchronous procedure call ("APC")
+        e)  APCs are only delivered during blocking Win32 operations
+            which are flagged as "alertable."  This prevents apps from
+            having APCs execute unexpectedly during an I/O operation.
+        f)  Cygwin's implementation of POSIX functions does all I/O
+            through non-alertable I/O operations.  This is reasonable
+            because APCs don't exist in the POSIX API.
+        g)  Cygwin implements Unix-style signals at the application level,
+            since the Windows kernel doesn't have them.  We want our
+            program to respond to SIGTERM and SIGKILL, at least.
+        h)  Cygwin's signal implementation will deliver signals during
+            blocking I/O functions in the Cygwin library, but won't
+            respond to signals if the signal is sent while the application
+            is in a blocking Windows API call which Cygwin is not aware of.
+        i)  Since we want to both send/receive ICMP probes and also respond
+            to Unix-style signals, we require two threads:  one which
+            uses Cygwin's POSIX style blocking I/O and can respond to
+            signals, and one which uses alertable waits using Win32
+            blocking APIs.
+
+    The solution is to have the main thread using select() as the
+    blocking operation in its loop, and also to have an ICMP service
+    thread using WaitForSingleObjectEx() as its blocking operation.
+    The main thread will respond to signals.  The ICMP service thread
+    will run the APCs completing ICMP.DLL requests.
+
+    These two threads communicate through a pair of pipes.  One pipe
+    sends requests from the main thread to the ICMP service thread,
+    and another pipe sends the requests back as they complete.
+
+    We use the Cygwin pipe() to create the pipes, but in the ICMP
+    service thread we use the Win32 HANDLE that corresponds to the
+    recieving end of the input pipe to wait for ICMP requests.
+*/
+
+
+static DWORD WINAPI icmp_service_thread(LPVOID param);
+
 /*  Windows doesn't require any initialization at a privileged level  */
 void init_net_state_privileged(
     struct net_state_t *net_state)
 {
 }
 
-/*  Open the ICMP.DLL interface  */
+/*
+    Convienience similar to error(), but for reporting Windows
+    error codes instead of errno codes.
+*/
+void error_win(int exit_code, int win_error, const char *str) {
+    fprintf(stderr, "%s (code %d)\n", str, win_error);
+    exit(exit_code);
+}
+
+/*  Open the ICMP.DLL interface and start the ICMP service thread  */
 void init_net_state(
     struct net_state_t *net_state)
 {
+    HANDLE thread;
+    int in_pipe[2], out_pipe[2];
+    int err;
+
     memset(net_state, 0, sizeof(struct net_state_t));
 
     net_state->platform.icmp4 = IcmpCreateFile();
@@ -41,8 +117,47 @@ void init_net_state(
 
     if (net_state->platform.icmp4 == INVALID_HANDLE_VALUE
         && net_state->platform.icmp6 == INVALID_HANDLE_VALUE) {
-        fprintf(stderr, "Failure opening ICMP %d\n", GetLastError());
-        exit(EXIT_FAILURE);
+
+        error_win(EXIT_FAILURE, GetLastError(), "Failure opening ICMP");
+    }
+    net_state->platform.ip4_socket_raw = false;
+    net_state->platform.ip6_socket_raw = false;
+
+    /*
+        We need a pipe for communication with the ICMP thread
+        in each direction.
+    */
+    if (pipe(in_pipe) == -1 || pipe(out_pipe) == -1) {
+        error(EXIT_FAILURE, errno, "Failure creating thread pipe");
+    }
+
+    net_state->platform.thread_in_pipe_read = in_pipe[0];
+    net_state->platform.thread_in_pipe_write = in_pipe[1];
+    net_state->platform.thread_out_pipe_read = out_pipe[0];
+    net_state->platform.thread_out_pipe_write = out_pipe[1];
+
+    net_state->platform.thread_in_pipe_read_handle =
+        (HANDLE)get_osfhandle(in_pipe[0]);
+
+    /*
+        The read on the out pipe needs to be nonblocking because
+        it will be occasionally checked in the main thread.
+    */
+    err = fcntl(out_pipe[0], F_SETFL, O_NONBLOCK);
+    if (err == -1) {
+        error(
+            EXIT_FAILURE, errno,
+            "Failure setting pipe to non-blocking");
+    }
+
+    /*  Spin up the ICMP service thread  */
+    thread = CreateThread(
+        NULL, 0, icmp_service_thread, net_state, 0, NULL);
+
+    if (thread == NULL) {
+        error_win(
+            EXIT_FAILURE, GetLastError(),
+            "Failure creating ICMP service thread");
     }
 }
 
@@ -87,10 +202,6 @@ void platform_alloc_probe(
 void platform_free_probe(
     struct probe_t *probe)
 {
-    if (probe->platform.reply4) {
-        free(probe->platform.reply4);
-        probe->platform.reply4 = NULL;
-    }
 }
 
 /*  Report a windows error code using a platform-independent error string  */
@@ -102,14 +213,6 @@ void report_win_error(
     /*  It could be that we got no reply because of timeout  */
     if (err == IP_REQ_TIMED_OUT || err == IP_SOURCE_QUENCH) {
         printf("%d no-reply\n", command_token);
-    } else if (err == IP_DEST_HOST_UNREACHABLE
-               || err == IP_DEST_PORT_UNREACHABLE
-               || err == IP_DEST_PROT_UNREACHABLE
-               || err == IP_DEST_NET_UNREACHABLE
-               || err == IP_DEST_UNREACHABLE
-               || err == IP_DEST_NO_ROUTE
-               || err == IP_BAD_ROUTE || err == IP_BAD_DESTINATION) {
-        printf("%d no-route\n", command_token);
     } else if (err == ERROR_INVALID_NETNAME) {
         printf("%d address-not-available\n", command_token);
     } else if (err == ERROR_INVALID_PARAMETER) {
@@ -120,6 +223,28 @@ void report_win_error(
 }
 
 /*
+    After we have the result of an ICMP probe on the ICMP service
+    thread, this is used to send the result back to the main thread
+    for probe result reporting.
+*/
+static
+void queue_thread_result(struct icmp_thread_request_t *request)
+{
+    int byte_count;
+
+    /*  Pass ownership of the request back through the result pipe  */
+    byte_count = write(
+        request->net_state->platform.thread_out_pipe_write,
+        &request,
+        sizeof(struct icmp_thread_request_t *));
+    if (byte_count == -1) {
+        error(
+            EXIT_FAILURE, errno,
+            "failure writing to probe result queue");
+    }
+}
+
+/*
     The overlapped I/O style completion routine to be called by
     Windows during an altertable wait when an ICMP probe has
     completed, either by reply, or by ICMP.DLL timeout.
@@ -130,8 +255,8 @@ void WINAPI on_icmp_reply(
     PIO_STATUS_BLOCK status,
     ULONG reserved)
 {
-    struct probe_t *probe = (struct probe_t *) context;
-    struct net_state_t *net_state = probe->platform.net_state;
+    struct icmp_thread_request_t *request =
+        (struct icmp_thread_request_t *) context;
     int icmp_type;
     int round_trip_us = 0;
     int reply_count;
@@ -139,11 +264,11 @@ void WINAPI on_icmp_reply(
     struct sockaddr_storage remote_addr;
     struct sockaddr_in *remote_addr4;
     struct sockaddr_in6 *remote_addr6;
-    ICMP_ECHO_REPLY32 *reply4;
+    ICMP_ECHO_REPLY *reply4;
     ICMPV6_ECHO_REPLY *reply6;
 
-    if (probe->platform.ip_version == 6) {
-        reply6 = probe->platform.reply6;
+    if (request->ip_version == 6) {
+        reply6 = request->reply6;
         reply_count = Icmp6ParseReplies(reply6, sizeof(ICMPV6_ECHO_REPLY));
 
         if (reply_count > 0) {
@@ -161,7 +286,7 @@ void WINAPI on_icmp_reply(
             remote_addr6->sin6_scope_id = 0;
         }
     } else {
-        reply4 = probe->platform.reply4;
+        reply4 = request->reply4;
         reply_count = IcmpParseReplies(reply4, sizeof(ICMP_ECHO_REPLY));
 
         if (reply_count > 0) {
@@ -186,27 +311,31 @@ void WINAPI on_icmp_reply(
         icmp_type = ICMP_ECHOREPLY;
     } else if (reply_status == IP_TTL_EXPIRED_TRANSIT
                || reply_status == IP_TTL_EXPIRED_REASSEM) {
+
         icmp_type = ICMP_TIME_EXCEEDED;
+    } else if (reply_status == IP_DEST_HOST_UNREACHABLE
+               || reply_status == IP_DEST_PORT_UNREACHABLE
+               || reply_status == IP_DEST_PROT_UNREACHABLE
+               || reply_status == IP_DEST_NET_UNREACHABLE
+               || reply_status == IP_DEST_UNREACHABLE
+               || reply_status == IP_DEST_NO_ROUTE
+               || reply_status == IP_BAD_ROUTE
+               || reply_status == IP_BAD_DESTINATION) {
+
+        icmp_type = ICMP_DEST_UNREACH;
     }
 
-    if (icmp_type != -1) {
-        /*  Record probe result  */
-        respond_to_probe(net_state, probe, icmp_type,
-                         &remote_addr, round_trip_us, 0, NULL);
-    } else {
-        report_win_error(probe->token, reply_status);
-        free_probe(net_state, probe);
-    }
+    request->icmp_type = icmp_type;
+    request->reply_status = reply_status;
+    request->remote_addr = remote_addr;
+    request->round_trip_us = round_trip_us;
+    queue_thread_result(request);
 }
 
 /*  Use ICMP.DLL's send echo support to send a probe  */
 static
 void icmp_send_probe(
-    struct net_state_t *net_state,
-    struct probe_t *probe,
-    const struct probe_param_t *param,
-    struct sockaddr_storage *src_sockaddr,
-    struct sockaddr_storage *dest_sockaddr,
+    struct icmp_thread_request_t *request,
     char *payload,
     int payload_size)
 {
@@ -219,8 +348,8 @@ void icmp_send_probe(
     struct sockaddr_in6 *src_sockaddr6;
     struct sockaddr_in6 *dest_sockaddr6;
 
-    if (param->timeout > 0) {
-        timeout = 1000 * param->timeout;
+    if (request->timeout > 0) {
+        timeout = 1000 * request->timeout;
     } else {
         /*
            IcmpSendEcho2 will return invalid argument on a timeout of 
@@ -230,52 +359,57 @@ void icmp_send_probe(
         timeout = 1;
     }
 
-    memset(&option, 0, sizeof(IP_OPTION_INFORMATION32));
-    option.Ttl = param->ttl;
+    memset(&option, 0, sizeof(IP_OPTION_INFORMATION));
+    option.Ttl = request->ttl;
 
-    if (param->ip_version == 6) {
+    if (request->ip_version == 6) {
         reply_size = sizeof(ICMPV6_ECHO_REPLY) + payload_size;
     } else {
-        reply_size = sizeof(ICMP_ECHO_REPLY32) + payload_size;
+        reply_size = sizeof(ICMP_ECHO_REPLY) + payload_size;
     }
 
-    probe->platform.reply4 = malloc(reply_size);
-    if (probe->platform.reply4 == NULL) {
-        perror("failure to allocate reply buffer");
-        exit(EXIT_FAILURE);
+    request->reply4 = malloc(reply_size);
+    if (request->reply4 == NULL) {
+        error(EXIT_FAILURE, errno, "failure to allocate reply buffer");
     }
 
-    if (param->ip_version == 6) {
-        src_sockaddr6 = (struct sockaddr_in6 *) src_sockaddr;
-        dest_sockaddr6 = (struct sockaddr_in6 *) dest_sockaddr;
+    if (request->ip_version == 6) {
+        src_sockaddr6 = (struct sockaddr_in6 *) &request->src_sockaddr;
+        dest_sockaddr6 = (struct sockaddr_in6 *) &request->dest_sockaddr;
 
-        send_result = Icmp6SendEcho2(net_state->platform.icmp6, NULL,
-                                     (FARPROC) on_icmp_reply, probe,
+        send_result = Icmp6SendEcho2(request->net_state->platform.icmp6,
+                                     NULL,
+                                     (FARPROC) on_icmp_reply,
+                                     request,
                                      src_sockaddr6, dest_sockaddr6,
                                      payload, payload_size, &option,
-                                     probe->platform.reply6, reply_size,
-                                     timeout);
+                                     request->reply6,
+                                     reply_size, timeout);
     } else {
-        dest_sockaddr4 = (struct sockaddr_in *) dest_sockaddr;
+        dest_sockaddr4 = (struct sockaddr_in *) &request->dest_sockaddr;
 
-        send_result = IcmpSendEcho2(net_state->platform.icmp4, NULL,
-                                    (FARPROC) on_icmp_reply, probe,
+        send_result = IcmpSendEcho2(request->net_state->platform.icmp4,
+                                    NULL,
+                                    (FARPROC) on_icmp_reply,
+                                    request,
                                     dest_sockaddr4->sin_addr.s_addr,
                                     payload, payload_size, &option,
-                                    probe->platform.reply4, reply_size,
-                                    timeout);
+                                    request->reply4,
+                                    reply_size, timeout);
     }
 
     if (send_result == 0) {
         err = GetLastError();
 
         /*
-           ERROR_IO_PENDING is expected for asynchronous probes,
-           but any other error is unexpected.
-         */
+            ERROR_IO_PENDING is expected when the probe is sent.
+            Other errors indicate the probe wasn't sent, and should
+            be reported in the main thread.
+        */
         if (err != ERROR_IO_PENDING) {
-            report_win_error(probe->token, err);
-            free_probe(net_state, probe);
+            request->icmp_type = -1;
+            request->reply_status = err;
+            queue_thread_result(request);
         }
     }
 }
@@ -283,24 +417,24 @@ void icmp_send_probe(
 /*  Fill the payload of the packet as specified by the probe parameters  */
 static
 int fill_payload(
-    const struct probe_param_t *param,
+    const struct icmp_thread_request_t *request,
     char *payload,
     int payload_buffer_size)
 {
     int ip_icmp_size;
     int payload_size;
 
-    if (param->ip_version == 6) {
+    if (request->ip_version == 6) {
         ip_icmp_size =
             sizeof(struct IP6Header) + sizeof(struct ICMPHeader);
-    } else if (param->ip_version == 4) {
+    } else if (request->ip_version == 4) {
         ip_icmp_size = sizeof(struct IPHeader) + sizeof(struct ICMPHeader);
     } else {
         errno = EINVAL;
         return -1;
     }
 
-    payload_size = param->packet_size - ip_icmp_size;
+    payload_size = request->packet_size - ip_icmp_size;
     if (payload_size < 0) {
         payload_size = 0;
     }
@@ -310,11 +444,184 @@ int fill_payload(
         return -1;
     }
 
-    memset(payload, param->bit_pattern, payload_size);
+    memset(payload, request->bit_pattern, payload_size);
 
     return payload_size;
 }
 
+/*
+    We've received a probe request from the main thread, so
+    fill out a payload buffer and then send the probe.
+*/
+static
+void icmp_handle_probe_request(struct icmp_thread_request_t *request)
+{
+    char payload[PACKET_BUFFER_SIZE];
+    int payload_size;
+
+    payload_size = fill_payload(request, payload, PACKET_BUFFER_SIZE);
+    if (payload_size < 0) {
+        error(EXIT_FAILURE, errno, "Error constructing packet");
+    }
+
+    icmp_send_probe(request, payload, payload_size);
+}
+
+/*
+    The main loop of the ICMP service thread.  The loop starts
+    an overlapped read on the incoming request pipe, then waits
+    in an alertable wait for that read to complete.  Because
+    the wait is alertable, ICMP probes can complete through
+    APCs in that wait.
+*/
+static
+DWORD WINAPI icmp_service_thread(LPVOID param) {
+    struct net_state_t *net_state;
+    struct icmp_thread_request_t *request;
+    DWORD wait_status;
+    OVERLAPPED overlapped;
+    HANDLE event;
+    BOOL success;
+    bool read_pending;
+    int read_count;
+    int err;
+
+    /*
+        We need an event to signal completion of reads from the request
+        pipe.
+    */
+    event = CreateEvent(NULL, TRUE, FALSE, NULL);
+    if (event == NULL) {
+        error_win(
+            EXIT_FAILURE, GetLastError(),
+            "failure creating ICMP thread event");
+    }
+
+    net_state = (struct net_state_t *)param;
+    read_pending = false;
+    while (true) {
+        /*
+            Start a new read on the request pipe if none is
+            currently pending.
+        */
+        if (!read_pending) {
+            request = NULL;
+
+            ResetEvent(event);
+
+            memset(&overlapped, 0, sizeof(OVERLAPPED));
+            overlapped.hEvent = event;
+
+            success = ReadFile(
+                net_state->platform.thread_in_pipe_read_handle,
+                &request,
+                sizeof(struct icmp_thread_request_t *),
+                NULL,
+                &overlapped);
+
+            if (!success) {
+                err = GetLastError();
+
+                if (err != ERROR_IO_PENDING) {
+                    error_win(
+                        EXIT_FAILURE, err,
+                        "failure starting overlapped thread pipe read");
+                }
+            }
+
+            read_pending = true;
+        }
+
+        /*
+            Wait for either the request read to complete, or
+            an APC which completes an ICMP probe.
+        */
+        wait_status = WaitForSingleObjectEx(
+            event,
+            INFINITE,
+            TRUE);
+
+        /*
+            If the event we waited on has been signalled, read
+            the request from the pipe.
+        */
+        if (wait_status == WAIT_OBJECT_0) {
+            read_pending = false;
+
+            success = GetOverlappedResult(
+                net_state->platform.thread_in_pipe_read_handle,
+                &overlapped,
+                &read_count,
+                FALSE);
+
+            if (!success) {
+                error_win(
+                    EXIT_FAILURE, GetLastError(),
+                    "failure completing overlapped thread pipe read");
+            }
+
+            if (read_count == 0) {
+                continue;
+            }
+
+            assert(
+                read_count == sizeof(struct icmp_thread_request_t *));
+
+            /*  Start the new probe from the request  */
+            icmp_handle_probe_request(request);
+        }
+    }
+}
+
+/*
+    When we are on the main thread and need the ICMP service thread
+    to start a new probe, this is used to pass the request for the
+    new probe to the service thread.
+*/
+static
+void queue_thread_request(
+    struct net_state_t *net_state,
+    struct probe_t *probe,
+    const struct probe_param_t *param,
+    struct sockaddr_storage *dest_sockaddr,
+    struct sockaddr_storage *src_sockaddr)
+{
+    struct icmp_thread_request_t *request;
+    int byte_count;
+
+    request = malloc(sizeof(struct icmp_thread_request_t));
+    if (request == NULL) {
+        error(EXIT_FAILURE, errno, "failure to allocate request");
+    }
+    memset(request, 0, sizeof(struct icmp_thread_request_t));
+
+    request->ip_version = param->ip_version;
+    request->ttl = param->ttl;
+    request->timeout = param->timeout;
+    request->packet_size = param->packet_size;
+    request->bit_pattern = param->bit_pattern;
+
+    request->net_state = net_state;
+    request->probe = probe;
+    request->dest_sockaddr = *dest_sockaddr;
+    request->src_sockaddr = *src_sockaddr;
+
+    /*
+        The ownership of the request is passed to the ICMP thread
+        through the pipe.
+    */
+    byte_count = write(
+        net_state->platform.thread_in_pipe_write,
+        &request,
+        sizeof(struct icmp_thread_request_t *));
+
+    if (byte_count == -1) {
+        error(
+            EXIT_FAILURE, errno,
+            "failure writing to probe request queue");
+    }
+}
+
 /*  Decode the probe parameters and send a probe  */
 void send_probe(
     struct net_state_t *net_state,
@@ -323,10 +630,9 @@ void send_probe(
     struct probe_t *probe;
     struct sockaddr_storage dest_sockaddr;
     struct sockaddr_storage src_sockaddr;
-    char payload[PACKET_BUFFER_SIZE];
-    int payload_size;
 
-    if (resolve_probe_addresses(param, &dest_sockaddr, &src_sockaddr)) {
+    if (resolve_probe_addresses(net_state, param, &dest_sockaddr,
+                &src_sockaddr)) {
         printf("%d invalid-argument\n", param->command_token);
         return;
     }
@@ -339,24 +645,75 @@ void send_probe(
 
     probe->platform.ip_version = param->ip_version;
 
-    payload_size = fill_payload(param, payload, PACKET_BUFFER_SIZE);
-    if (payload_size < 0) {
-        perror("Error construction packet");
-        exit(EXIT_FAILURE);
-    }
+    queue_thread_request(
+        net_state, probe, param, &dest_sockaddr, &src_sockaddr);
+}
+
+/*
+    After we've receive the result from the ICMP service thread,
+    report either the probe status, or any Windows error we
+    encountered while attempting to send the probe.
+*/
+static
+void complete_icmp_result(struct icmp_thread_request_t *request)
+{
+    struct net_state_t *net_state;
+    struct probe_t *probe;
+
+    /*
+        We can de-const the net_state and probe, since we are back
+        on the main thread.
+    */
+    net_state = (struct net_state_t *)request->net_state;
+    probe = (struct probe_t *)request->probe;
 
-    icmp_send_probe(net_state, probe, param,
-                    &src_sockaddr, &dest_sockaddr, payload, payload_size);
+    if (request->icmp_type != -1) {
+        /*  Record probe result  */
+        respond_to_probe(net_state, probe,
+                         request->icmp_type, &request->remote_addr,
+                         request->round_trip_us, 0, NULL);
+    } else {
+        report_win_error(probe->token, request->reply_status);
+        free_probe(net_state, probe);
+    }
 }
 
 /*
-    On Windows, an implementation of receive_replies is unnecessary, because,
-    unlike Unix, replies are completed using Overlapped I/O during an
-    alertable wait, and don't require explicit reads.
+    Read the status of completed probes from the ICMP service
+    if any has completed.
 */
 void receive_replies(
     struct net_state_t *net_state)
 {
+    int read_count;
+    struct icmp_thread_request_t *request;
+
+    read_count = read(
+        net_state->platform.thread_out_pipe_read,
+        &request,
+        sizeof(struct icmp_thread_request_t *));
+
+    if (read_count == -1) {
+        /*
+            EINTR and EAGAIN can occur under normal conditions, and
+            should be retried.  We will retry the next iteration
+            of the main loop.
+        */
+        if (errno == EINTR || errno == EAGAIN) {
+            return;
+        }
+
+        error(EXIT_FAILURE, errno, "thread result pipe read error");
+    }
+
+    assert(read_count == sizeof(struct icmp_thread_request_t *));
+    complete_icmp_result(request);
+
+    if (request->reply4) {
+        free(request->reply4);
+        request->reply4 = NULL;
+    }
+    free(request);
 }
 
 /*
diff --git a/packet/probe_cygwin.h b/packet/probe_cygwin.h
index 29ef982..eec001f 100644
--- a/packet/probe_cygwin.h
+++ b/packet/probe_cygwin.h
@@ -11,9 +11,9 @@
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    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 PROBE_CYGWIN_H
@@ -58,17 +58,57 @@ struct probe_platform_t {
 
     /*  IP version (4 or 6) used for the probe  */
     int ip_version;
-
-    union {
-        ICMP_ECHO_REPLY32 *reply4;
-        ICMPV6_ECHO_REPLY *reply6;
-    };
 };
 
 /*  A Windows HANDLE for the ICMP session  */
 struct net_state_platform_t {
     HANDLE icmp4;
     HANDLE icmp6;
+    bool ip4_socket_raw;
+    bool ip6_socket_raw;
+
+    HANDLE thread_in_pipe_read_handle;
+    int thread_in_pipe_read, thread_in_pipe_write;
+    int thread_out_pipe_read, thread_out_pipe_write;
+};
+
+/*
+    A request object passed between the main thread and the ICMP
+    service thread representing an outstanding probe.
+*/
+struct icmp_thread_request_t {
+    /*
+        net_state and probe are const to avoid race conditions between
+        the main thread and the ICMP service thread.  They are to be
+        considered read-only on the ICMP service thread.
+    */
+    const struct net_state_t *net_state;
+    const struct probe_t *probe;
+
+    /*  Parameters for the probe request  */
+    int ip_version;
+    int ttl;
+    int timeout;
+    int packet_size;
+    int bit_pattern;
+
+    /*  Source and destination for the probe  */
+    struct sockaddr_storage dest_sockaddr;
+    struct sockaddr_storage src_sockaddr;
+
+    /*  Scratch space used by the ICMP.DLL API  */
+    union {
+        ICMP_ECHO_REPLY *reply4;
+        ICMPV6_ECHO_REPLY *reply6;
+    };
+
+    /*  Probe results  */
+    int icmp_type;
+    int reply_status;
+    int round_trip_us;
+
+    /*  The remote address responding to the probe  */
+    struct sockaddr_storage remote_addr;
 };
 
 #endif
diff --git a/packet/probe_unix.c b/packet/probe_unix.c
index 53863eb..363930f 100644
--- a/packet/probe_unix.c
+++ b/packet/probe_unix.c
@@ -11,9 +11,9 @@
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    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 "probe.h"
@@ -21,6 +21,14 @@
 #include <assert.h>
 #include <errno.h>
 #include <fcntl.h>
+#ifdef HAVE_ERROR_H
+#include <error.h>
+#else
+#include "portability/error.h"
+#endif
+#ifdef HAVE_LINUX_ERRQUEUE_H
+#include <linux/errqueue.h>
+#endif
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -29,6 +37,7 @@
 
 #include "platform.h"
 #include "protocols.h"
+#include "sockaddr.h"
 #include "construct_unix.h"
 #include "deconstruct_unix.h"
 #include "timeval.h"
@@ -38,6 +47,7 @@ static
 int send_packet(
     const struct net_state_t *net_state,
     const struct probe_param_t *param,
+    int sequence,
     const char *packet,
     int packet_size,
     const struct sockaddr_storage *sockaddr)
@@ -49,14 +59,44 @@ int send_packet(
         sockaddr_length = sizeof(struct sockaddr_in6);
 
         if (param->protocol == IPPROTO_ICMP) {
-            send_socket = net_state->platform.icmp6_send_socket;
+            if (net_state->platform.ip6_socket_raw) {
+                send_socket = net_state->platform.icmp6_send_socket;
+            } else {
+                send_socket = net_state->platform.ip6_txrx_icmp_socket;
+            }
         } else if (param->protocol == IPPROTO_UDP) {
-            send_socket = net_state->platform.udp6_send_socket;
+            if (net_state->platform.ip6_socket_raw) {
+                send_socket = net_state->platform.udp6_send_socket;
+            } else {
+                send_socket = net_state->platform.ip6_txrx_udp_socket;
+                if (param->dest_port) {
+                    *sockaddr_port_offset(sockaddr) = htons(param->dest_port);
+                } else {
+                    *sockaddr_port_offset(sockaddr) = sequence;
+                }
+            }
         }
     } else if (sockaddr->ss_family == AF_INET) {
         sockaddr_length = sizeof(struct sockaddr_in);
 
-        send_socket = net_state->platform.ip4_send_socket;
+        if (net_state->platform.ip4_socket_raw) {
+            send_socket = net_state->platform.ip4_send_socket;
+        } else {
+            if (param->protocol == IPPROTO_ICMP) {
+                if (param->is_probing_byte_order) {
+                    send_socket = net_state->platform.ip4_tmp_icmp_socket;;
+                } else {
+                    send_socket = net_state->platform.ip4_txrx_icmp_socket;
+                }
+            } else if (param->protocol == IPPROTO_UDP) {
+                send_socket = net_state->platform.ip4_txrx_udp_socket;
+                if (param->dest_port) {
+                    *sockaddr_port_offset(sockaddr) = htons(param->dest_port);
+                } else {
+                    *sockaddr_port_offset(sockaddr) = sequence;
+                }
+            }
+        }
     }
 
     if (send_socket == 0) {
@@ -85,18 +125,26 @@ void check_length_order(
 {
     char packet[PACKET_BUFFER_SIZE];
     struct probe_param_t param;
-    struct sockaddr_storage dest_sockaddr;
-    struct sockaddr_storage src_sockaddr;
+    struct probe_t p0 = {.sequence = MIN_PORT };
     ssize_t bytes_sent;
     int packet_size;
 
+#ifdef __linux__
+    /*  Linux will accept either byte order and check below fails to work
+     *  in some cases due to sendto() returning EPERM. */
+    return;
+#endif
+
     memset(&param, 0, sizeof(struct probe_param_t));
     param.ip_version = 4;
     param.protocol = IPPROTO_ICMP;
     param.ttl = 255;
     param.remote_address = "127.0.0.1";
+    param.is_probing_byte_order = true;
 
-    if (resolve_probe_addresses(&param, &dest_sockaddr, &src_sockaddr)) {
+
+    if (resolve_probe_addresses(net_state, &param, &p0.remote_addr,
+                &p0.local_addr)) {
         fprintf(stderr, "Error decoding localhost address\n");
         exit(EXIT_FAILURE);
     }
@@ -104,17 +152,16 @@ void check_length_order(
     /*  First attempt to ping the localhost with network byte order  */
     net_state->platform.ip_length_host_order = false;
 
-    packet_size = construct_packet(net_state, NULL, MIN_PORT,
+    packet_size = construct_packet(net_state, NULL, &p0,
                                    packet, PACKET_BUFFER_SIZE,
-                                   &dest_sockaddr, &src_sockaddr, &param);
+                                   &param);
     if (packet_size < 0) {
-        perror("Unable to send to localhost");
-        exit(EXIT_FAILURE);
+      error(EXIT_FAILURE, errno, "Unable to send to localhost");
     }
 
     bytes_sent =
-        send_packet(net_state, &param, packet, packet_size,
-                    &dest_sockaddr);
+        send_packet(net_state, &param, MIN_PORT, packet, packet_size,
+                    &p0.remote_addr);
     if (bytes_sent > 0) {
         return;
     }
@@ -122,20 +169,18 @@ void check_length_order(
     /*  Since network byte order failed, try host byte order  */
     net_state->platform.ip_length_host_order = true;
 
-    packet_size = construct_packet(net_state, NULL, MIN_PORT,
+    packet_size = construct_packet(net_state, NULL, &p0,
                                    packet, PACKET_BUFFER_SIZE,
-                                   &dest_sockaddr, &src_sockaddr, &param);
+                                   &param);
     if (packet_size < 0) {
-        perror("Unable to send to localhost");
-        exit(EXIT_FAILURE);
+        error(EXIT_FAILURE, errno, "Unable to send to localhost");
     }
 
     bytes_sent =
-        send_packet(net_state, &param, packet, packet_size,
-                    &dest_sockaddr);
+        send_packet(net_state, &param, MIN_PORT, packet, packet_size,
+                    &p0.remote_addr);
     if (bytes_sent < 0) {
-        perror("Unable to send with swapped length");
-        exit(EXIT_FAILURE);
+        error(EXIT_FAILURE, errno, "Unable to send with swapped length");
     }
 }
 
@@ -169,19 +214,17 @@ void set_socket_nonblocking(
 
     flags = fcntl(socket, F_GETFL, 0);
     if (flags == -1) {
-        perror("Unexpected socket F_GETFL error");
-        exit(EXIT_FAILURE);
+        error(EXIT_FAILURE, errno, "Unexpected socket F_GETFL error");
     }
 
     if (fcntl(socket, F_SETFL, flags | O_NONBLOCK)) {
-        perror("Unexpected socket F_SETFL O_NONBLOCK error");
-        exit(EXIT_FAILURE);
+        error(EXIT_FAILURE, errno, "Unexpected socket F_SETFL O_NONBLOCK error");
     }
 }
 
 /*  Open the raw sockets for sending/receiving IPv4 packets  */
 static
-int open_ip4_sockets(
+int open_ip4_sockets_raw(
     struct net_state_t *net_state)
 {
     int send_socket;
@@ -190,7 +233,10 @@ int open_ip4_sockets(
 
     send_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
     if (send_socket == -1) {
-        return -1;
+        send_socket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
+        if (send_socket == -1) {
+            return -1;
+        }
     }
 
     /*
@@ -215,15 +261,68 @@ int open_ip4_sockets(
     }
 
     net_state->platform.ip4_present = true;
+    net_state->platform.ip4_socket_raw = true;
     net_state->platform.ip4_send_socket = send_socket;
     net_state->platform.ip4_recv_socket = recv_socket;
 
     return 0;
 }
 
+#ifdef HAVE_LINUX_ERRQUEUE_H
+/*  Open DGRAM sockets for sending/receiving IPv4 packets  */
+static
+int open_ip4_sockets_dgram(
+    struct net_state_t *net_state)
+{
+    int udp_socket;
+    int icmp_socket, icmp_tmp_socket;
+#ifdef HAVE_LINUX_ERRQUEUE_H
+    int val = 1;
+#endif
+
+    icmp_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
+    if (icmp_socket == -1) {
+        return -1;
+    }
+#ifdef HAVE_LINUX_ERRQUEUE_H
+    if (setsockopt(icmp_socket, SOL_IP, IP_RECVERR, &val, sizeof(val)) < 0) {
+        return -1;
+    }
+#endif
+
+    udp_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+    if (udp_socket == -1) {
+        close(icmp_socket);
+        return -1;
+    }
+#ifdef HAVE_LINUX_ERRQUEUE_H
+    if (setsockopt(udp_socket, SOL_IP, IP_RECVERR, &val, sizeof(val)) < 0) {
+        close(icmp_socket);
+        close(udp_socket);
+        return -1;
+    }
+#endif
+
+    icmp_tmp_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
+    if (icmp_tmp_socket == -1) {
+        close(icmp_socket);
+        close(udp_socket);
+        return -1;
+    }
+
+    net_state->platform.ip4_present = true;
+    net_state->platform.ip4_socket_raw = false;
+    net_state->platform.ip4_txrx_icmp_socket = icmp_socket;
+    net_state->platform.ip4_tmp_icmp_socket = icmp_tmp_socket;
+    net_state->platform.ip4_txrx_udp_socket = udp_socket;
+
+    return 0;
+}
+#endif
+
 /*  Open the raw sockets for sending/receiving IPv6 packets  */
 static
-int open_ip6_sockets(
+int open_ip6_sockets_raw(
     struct net_state_t *net_state)
 {
     int send_socket_icmp;
@@ -251,6 +350,7 @@ int open_ip6_sockets(
     }
 
     net_state->platform.ip6_present = true;
+    net_state->platform.ip6_socket_raw = true;
     net_state->platform.icmp6_send_socket = send_socket_icmp;
     net_state->platform.udp6_send_socket = send_socket_udp;
     net_state->platform.ip6_recv_socket = recv_socket;
@@ -258,6 +358,50 @@ int open_ip6_sockets(
     return 0;
 }
 
+#ifdef HAVE_LINUX_ERRQUEUE_H
+/*  Open DGRAM sockets for sending/receiving IPv6 packets  */
+static
+int open_ip6_sockets_dgram(
+    struct net_state_t *net_state)
+{
+    int icmp_socket;
+    int udp_socket;
+#ifdef HAVE_LINUX_ERRQUEUE_H
+    int val = 1;
+#endif
+
+    icmp_socket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6);
+    if (icmp_socket == -1) {
+        return -1;
+    }
+#ifdef HAVE_LINUX_ERRQUEUE_H
+    if (setsockopt(icmp_socket, SOL_IPV6, IPV6_RECVERR, &val, sizeof(val)) < 0) {
+        return -1;
+    }
+#endif
+
+    udp_socket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+    if (udp_socket == -1) {
+        close(icmp_socket);
+        return -1;
+    }
+#ifdef HAVE_LINUX_ERRQUEUE_H
+    if (setsockopt(udp_socket, SOL_IPV6, IPV6_RECVERR, &val, sizeof(val)) < 0) {
+        close(icmp_socket);
+        close(udp_socket);
+        return -1;
+    }
+#endif
+
+    net_state->platform.ip6_present = true;
+    net_state->platform.ip6_socket_raw = false;
+    net_state->platform.ip6_txrx_icmp_socket = icmp_socket;
+    net_state->platform.ip6_txrx_udp_socket = udp_socket;
+
+    return 0;
+}
+#endif
+
 /*
     The first half of the net state initialization.  Since this
     happens with elevated privileges, this is kept as minimal
@@ -273,11 +417,21 @@ void init_net_state_privileged(
 
     net_state->platform.next_sequence = MIN_PORT;
 
-    if (open_ip4_sockets(net_state)) {
-        ip4_err = errno;
+    if (open_ip4_sockets_raw(net_state)) {
+#ifdef HAVE_LINUX_ERRQUEUE_H
+        /* fall back to using unprivileged sockets */
+        if (open_ip4_sockets_dgram(net_state)) {
+            ip4_err = errno;
+        }
+#endif
     }
-    if (open_ip6_sockets(net_state)) {
-        ip6_err = errno;
+    if (open_ip6_sockets_raw(net_state)) {
+#ifdef HAVE_LINUX_ERRQUEUE_H
+        /* fall back to using unprivileged sockets */
+        if (open_ip6_sockets_dgram(net_state)) {
+            ip6_err = errno;
+        }
+#endif
     }
 
     /*
@@ -286,13 +440,8 @@ void init_net_state_privileged(
      */
     if (!net_state->platform.ip4_present
         && !net_state->platform.ip6_present) {
-
-        errno = ip4_err;
-        perror("Failure to open IPv4 sockets");
-
-        errno = ip6_err;
-        perror("Failure to open IPv6 sockets");
-
+        error(0, ip4_err, "Failure to open IPv4 sockets");
+        error(0, ip6_err, "Failure to open IPv6 sockets");
         exit(EXIT_FAILURE);
     }
 }
@@ -304,8 +453,18 @@ void init_net_state_privileged(
 void init_net_state(
     struct net_state_t *net_state)
 {
-    set_socket_nonblocking(net_state->platform.ip4_recv_socket);
-    set_socket_nonblocking(net_state->platform.ip6_recv_socket);
+    if (net_state->platform.ip4_socket_raw) {
+        set_socket_nonblocking(net_state->platform.ip4_recv_socket);
+    } else {
+        set_socket_nonblocking(net_state->platform.ip4_txrx_icmp_socket);
+        set_socket_nonblocking(net_state->platform.ip4_txrx_udp_socket);
+    }
+    if (net_state->platform.ip6_socket_raw) {
+        set_socket_nonblocking(net_state->platform.ip6_recv_socket);
+    } else {
+        set_socket_nonblocking(net_state->platform.ip6_txrx_icmp_socket);
+        set_socket_nonblocking(net_state->platform.ip6_txrx_udp_socket);
+    }
 
     if (net_state->platform.ip4_present) {
         check_length_order(net_state);
@@ -387,8 +546,8 @@ void send_probe(
 {
     char packet[PACKET_BUFFER_SIZE];
     struct probe_t *probe;
+    int trytimes;
     int packet_size;
-    struct sockaddr_storage src_sockaddr;
 
     probe = alloc_probe(net_state, param->command_token);
     if (probe == NULL) {
@@ -396,21 +555,41 @@ void send_probe(
         return;
     }
 
-    if (resolve_probe_addresses(param, &probe->remote_addr, &src_sockaddr)) {
+    if (resolve_probe_addresses(net_state, param, &probe->remote_addr,
+                &probe->local_addr)) {
         printf("%d invalid-argument\n", param->command_token);
         free_probe(net_state, probe);
         return;
     }
 
     if (gettimeofday(&probe->platform.departure_time, NULL)) {
-        perror("gettimeofday failure");
-        exit(EXIT_FAILURE);
+        error(EXIT_FAILURE, errno, "gettimeofday failure");
     }
 
-    packet_size =
-        construct_packet(net_state, &probe->platform.socket,
-                         probe->sequence, packet, PACKET_BUFFER_SIZE,
-                         &probe->remote_addr, &src_sockaddr, param);
+    // there might be an off-by-one in the number of tries here. 
+    // this is intentional.  It is no use exhausting the very last
+    // open port. Max 10 retries would've been acceptable too I think. 
+    for (trytimes=MIN_PORT; trytimes < MAX_PORT; trytimes++) {
+			
+        packet_size = construct_packet(net_state, &probe->platform.socket,
+                         probe, packet, PACKET_BUFFER_SIZE,
+                         param);
+
+        if (packet_size > 0) break; // no retry if we succeed.
+
+        if ((param->protocol != IPPROTO_TCP) && 
+            (param->protocol != IPPROTO_SCTP)) break; // no retry if not TCP/SCTP
+
+        if ((errno != EADDRINUSE) && (errno != EADDRNOTAVAIL)) {
+            break; // no retry
+        }
+
+     	probe->sequence = net_state->platform.next_sequence++;
+        	
+       	if (net_state->platform.next_sequence > MAX_PORT) {
+            net_state->platform.next_sequence = MIN_PORT;
+        }
+    }
 
     if (packet_size < 0) {
         /*
@@ -431,7 +610,7 @@ void send_probe(
     }
 
     if (packet_size > 0) {
-        if (send_packet(net_state, param,
+        if (send_packet(net_state, param, probe->sequence,
                         packet, packet_size, &probe->remote_addr) == -1) {
 
             report_packet_error(param->command_token);
@@ -488,8 +667,7 @@ void receive_probe(
 
     if (timestamp == NULL) {
         if (gettimeofday(&now, NULL)) {
-            perror("gettimeofday failure");
-            exit(EXIT_FAILURE);
+            error(EXIT_FAILURE, errno, "gettimeofday failure");
         }
 
         timestamp = &now;
@@ -508,7 +686,7 @@ void receive_probe(
     handle any responses to probes we have preivously sent.
 */
 static
-void receive_replies_from_icmp_socket(
+void receive_replies_from_recv_socket(
     struct net_state_t *net_state,
     int socket,
     received_packet_func_t handle_received_packet)
@@ -516,23 +694,39 @@ void receive_replies_from_icmp_socket(
     char packet[PACKET_BUFFER_SIZE];
     int packet_length;
     struct sockaddr_storage remote_addr;
-    socklen_t sockaddr_length;
     struct timeval timestamp;
+    int flag = 0;
+#ifdef HAVE_LINUX_ERRQUEUE_H
+    struct cmsghdr *cm;
+    struct sock_extended_err *ee = NULL;
+    bool icmp_connrefused_received = false;
+    bool icmp_hostunreach_received = false;
+#endif
 
     /*  Read until no more packets are available  */
     while (true) {
-        sockaddr_length = sizeof(struct sockaddr_storage);
-        packet_length = recvfrom(socket, packet, PACKET_BUFFER_SIZE, 0,
-                                 (struct sockaddr *) &remote_addr,
-                                 &sockaddr_length);
+        struct iovec iov;
+        struct msghdr msg;
+        char control[1024];
+
+        memset(&msg, 0, sizeof(msg));
+        memset(&iov, 0, sizeof(iov));
+        iov.iov_base = packet;
+        iov.iov_len = sizeof(packet);
+        msg.msg_iov = &iov;
+        msg.msg_iovlen = 1;
+        msg.msg_name = (struct sockaddr*) &remote_addr;
+        msg.msg_namelen = sizeof(remote_addr);
+        msg.msg_control = control;
+        msg.msg_controllen = sizeof(control);
+        packet_length = recvmsg(socket, &msg, flag);
 
         /*
            Get the time immediately after reading the packet to
            keep the timing as precise as we can.
          */
         if (gettimeofday(&timestamp, NULL)) {
-            perror("gettimeofday failure");
-            exit(EXIT_FAILURE);
+            error(EXIT_FAILURE, errno, "gettimeofday failure");
         }
 
         if (packet_length == -1) {
@@ -549,15 +743,84 @@ void receive_replies_from_icmp_socket(
                receive.
              */
             if (errno == EINTR) {
+                /* clear error */
+                int so_err;
+                socklen_t so_err_size = sizeof(so_err);
+                int err;
+
+                do {
+                  err = getsockopt(socket, SOL_SOCKET, SO_ERROR, &so_err, &so_err_size);
+                } while (err < 0 && errno == EINTR);
+                continue;
+            }
+
+            /* handle error received in error queue */
+            if (errno == EHOSTUNREACH) {
+                /* potential error caused by ttl, read inner icmp hdr from err queue */
+#ifdef HAVE_LINUX_ERRQUEUE_H
+                icmp_hostunreach_received = true;
+                flag |= MSG_ERRQUEUE;
+#endif
+                continue;
+            }
+
+            if (errno == ECONNREFUSED) {
+                /* udp packet reached dst, read inner udp hdr from err queue */
+#ifdef HAVE_LINUX_ERRQUEUE_H
+                icmp_connrefused_received = true;
+                flag |= MSG_ERRQUEUE;
+#endif
                 continue;
             }
 
-            perror("Failure receiving replies");
-            exit(EXIT_FAILURE);
+            error(EXIT_FAILURE, errno, "Failure receiving replies");
+        }
+
+#ifdef HAVE_LINUX_ERRQUEUE_H
+        /* get src ip for packets read from err queue */
+        if (flag & MSG_ERRQUEUE) {
+            for (cm = CMSG_FIRSTHDR(&msg); cm; cm = CMSG_NXTHDR(&msg, cm)) {
+                if (cm->cmsg_level == SOL_IP) {
+                    if (cm->cmsg_type == IP_RECVERR) {
+                        ee = (struct sock_extended_err *) CMSG_DATA(cm);
+                    }
+                }
+                else if (cm->cmsg_level == SOL_IPV6) {
+                    if (cm->cmsg_type == IPV6_RECVERR) {
+                        ee = (struct sock_extended_err *) CMSG_DATA(cm);
+                    }
+                }
+            }
+            if (ee) {
+                memcpy(&remote_addr, SO_EE_OFFENDER(ee), sizeof(remote_addr));
+            }
         }
+#endif
 
-        handle_received_packet(net_state, &remote_addr, packet,
-                               packet_length, &timestamp);
+#ifdef SO_PROTOCOL
+        if (icmp_connrefused_received) {
+            /* using ICMP type ICMP_ECHOREPLY is not a bug, it is an
+               indication of successfully reaching dst host.
+             */
+            handle_error_queue_packet(net_state, &remote_addr, ICMP_ECHOREPLY, IPPROTO_UDP,
+                    packet, packet_length, &timestamp);
+        } else if (icmp_hostunreach_received) {
+            /* handle packet based on send socket protocol */
+            int proto, length = sizeof(int);
+
+            if (getsockopt(socket, SOL_SOCKET, SO_PROTOCOL, &proto, &length) < 0) {
+                error(EXIT_FAILURE, errno, "getsockopt SO_PROTOCOL error");
+            }
+            handle_error_queue_packet(net_state, &remote_addr, ICMP_TIME_EXCEEDED, proto,
+                    packet, packet_length, &timestamp);
+        } else {
+#endif
+            /* ICMP packets received from raw socket */
+            handle_received_packet(net_state, &remote_addr, packet,
+                                   packet_length, &timestamp);
+#ifdef SO_PROTOCOL
+        }
+#endif
     }
 }
 
@@ -592,8 +855,7 @@ void receive_replies_from_probe_socket(
         if (errno == EAGAIN) {
             return;
         } else {
-            perror("probe socket select error");
-            exit(EXIT_FAILURE);
+            error(EXIT_FAILURE, errno, "probe socket select error");
         }
     }
 
@@ -605,8 +867,7 @@ void receive_replies_from_probe_socket(
     }
 
     if (getsockopt(probe_socket, SOL_SOCKET, SO_ERROR, &err, &err_length)) {
-        perror("probe socket SO_ERROR");
-        exit(EXIT_FAILURE);
+        error(EXIT_FAILURE, errno, "probe socket SO_ERROR");
     }
 
     /*
@@ -631,17 +892,39 @@ void receive_replies(
     struct probe_t *probe_safe_iter;
 
     if (net_state->platform.ip4_present) {
-        receive_replies_from_icmp_socket(net_state,
-                                         net_state->platform.
-                                         ip4_recv_socket,
-                                         handle_received_ip4_packet);
+        if (net_state->platform.ip4_socket_raw) {
+            receive_replies_from_recv_socket(net_state,
+                                             net_state->platform.
+                                             ip4_recv_socket,
+                                             handle_received_ip4_packet);
+        } else {
+            receive_replies_from_recv_socket(net_state,
+                                             net_state->platform.
+                                             ip4_txrx_icmp_socket,
+                                             handle_received_ip4_packet);
+            receive_replies_from_recv_socket(net_state,
+                                             net_state->platform.
+                                             ip4_txrx_udp_socket,
+                                             handle_received_ip4_packet);
+        }
     }
 
     if (net_state->platform.ip6_present) {
-        receive_replies_from_icmp_socket(net_state,
-                                         net_state->platform.
-                                         ip6_recv_socket,
-                                         handle_received_ip6_packet);
+        if (net_state->platform.ip6_socket_raw) {
+            receive_replies_from_recv_socket(net_state,
+                                             net_state->platform.
+                                             ip6_recv_socket,
+                                             handle_received_ip6_packet);
+        } else {
+            receive_replies_from_recv_socket(net_state,
+                                             net_state->platform.
+                                             ip6_txrx_icmp_socket,
+                                             handle_received_ip6_packet);
+            receive_replies_from_recv_socket(net_state,
+                                             net_state->platform.
+                                             ip6_txrx_udp_socket,
+                                             handle_received_ip6_packet);
+        }
     }
 
     LIST_FOREACH_SAFE(probe, &net_state->outstanding_probes,
@@ -692,8 +975,7 @@ void check_probe_timeouts(
     struct probe_t *probe_safe_iter;
 
     if (gettimeofday(&now, NULL)) {
-        perror("gettimeofday failure");
-        exit(EXIT_FAILURE);
+        error(EXIT_FAILURE, errno, "gettimeofday failure");
     }
 
     LIST_FOREACH_SAFE(probe, &net_state->outstanding_probes,
@@ -726,8 +1008,7 @@ bool get_next_probe_timeout(
     struct timeval probe_timeout;
 
     if (gettimeofday(&now, NULL)) {
-        perror("gettimeofday failure");
-        exit(EXIT_FAILURE);
+        error(EXIT_FAILURE, errno, "gettimeofday failure");
     }
 
     have_timeout = false;
diff --git a/packet/probe_unix.h b/packet/probe_unix.h
index 36b3159..cc01e1e 100644
--- a/packet/probe_unix.h
+++ b/packet/probe_unix.h
@@ -11,14 +11,19 @@
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    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 PROBE_UNIX_H
 #define PROBE_UNIX_H
 
+#ifndef IPPROTO_SCTP
+// Needed for Netbsd. 
+#define IPPROTO_SCTP           132             /* SCTP */
+#endif
+
 /*  The range of local port numbers to use for probes  */
 #define MIN_PORT 33000
 #define MAX_PORT 65535
@@ -43,12 +48,27 @@ struct net_state_platform_t {
     /*  true if we were successful at opening IPv6 sockets  */
     bool ip6_present;
 
+    /* true if ipv4 socket is raw socket */
+    bool ip4_socket_raw;
+
+    /* true if ipv6 socket is raw socket */
+    bool ip6_socket_raw;
+
     /*  Socket used to send raw IPv4 packets  */
     int ip4_send_socket;
 
     /*  Socket used to receive IPv4 ICMP replies  */
     int ip4_recv_socket;
 
+    /*  Socket used to probe byte order */
+    int ip4_tmp_icmp_socket;
+
+    /*  Socket used to tx & rx non-raw IPv4 icmp packets */
+    int ip4_txrx_icmp_socket;
+
+    /*  Socket used to send IPv4 udp packets and receive icmp err packets */
+    int ip4_txrx_udp_socket;
+
     /*  Send socket for ICMPv6 packets  */
     int icmp6_send_socket;
 
@@ -58,6 +78,12 @@ struct net_state_platform_t {
     /*  Receive socket for IPv6 packets  */
     int ip6_recv_socket;
 
+    /*  Socket used to tx & rx non-raw IPv6 icmp packets */
+    int ip6_txrx_icmp_socket;
+
+    /*  Socket used to send IPv6 udp packets and receive icmp err packets */
+    int ip6_txrx_udp_socket;
+
     /*
        true if we should encode the IP header length in host order.
        (as opposed to network order)
diff --git a/packet/protocols.h b/packet/protocols.h
index 75a8229..89d0a96 100644
--- a/packet/protocols.h
+++ b/packet/protocols.h
@@ -11,9 +11,9 @@
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    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 PROTOCOLS_H
@@ -78,7 +78,7 @@ struct ICMPExtensionObject {
 /*  An MPLS label included in an ICMP extension  */
 /*  See RFC 4950  */
 struct ICMPExtMPLSLabel {
-    uint8_t label[3];           // Low 4 bits are Experimental Use, Stack
+    uint8_t label[3];           // Low 4 bits are Traffic Class Use, Stack
     uint8_t ttl;
 };
 
diff --git a/packet/sockaddr.c b/packet/sockaddr.c
new file mode 100644
index 0000000..2a4b34a
--- /dev/null
+++ b/packet/sockaddr.c
@@ -0,0 +1,69 @@
+#include <stddef.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+void *sockaddr_addr_offset(const void *x)
+{
+	if( x == NULL )
+		return NULL;
+
+	if( ((struct sockaddr *)(x))->sa_family == AF_INET )
+	{
+		return ((void *)(x) + offsetof(struct sockaddr_in, sin_addr));
+	}else
+	if( ((struct sockaddr *)(x))->sa_family == AF_INET6 )
+	{
+		return ((void *)(x) + offsetof(struct sockaddr_in6, sin6_addr));
+	}
+
+	return NULL;
+}
+
+unsigned int sockaddr_addr_size(const void *x)
+{
+	if( x == NULL )
+		return 0;
+	if( ((struct sockaddr *)(x))->sa_family == AF_INET )
+	{
+		return sizeof(struct in_addr);
+	}else
+	if( ((struct sockaddr *)(x))->sa_family == AF_INET6 )
+	{
+		return sizeof(struct in6_addr);
+	}
+	return 0;
+}
+
+
+unsigned int sockaddr_size(const void *x)
+{
+	if( x == NULL )
+		return 0;
+	if( ((struct sockaddr *)(x))->sa_family == AF_INET )
+	{
+		return sizeof(struct sockaddr_in);
+	}else
+	if( ((struct sockaddr *)(x))->sa_family == AF_INET6 )
+	{
+		return sizeof(struct sockaddr_in6);
+	}
+	return 0;
+}
+
+in_port_t *sockaddr_port_offset(const void *x)
+{
+	if( x == NULL )
+		return NULL;
+
+	if( ((struct sockaddr *)(x))->sa_family == AF_INET )
+	{
+		return ((void *)(x) + offsetof(struct sockaddr_in, sin_port));
+	}else
+	if( ((struct sockaddr *)(x))->sa_family == AF_INET6 )
+	{
+		return ((void *)(x) + offsetof(struct sockaddr_in6, sin6_port));
+	}
+
+	return NULL;
+}
diff --git a/packet/sockaddr.h b/packet/sockaddr.h
new file mode 100644
index 0000000..9e44c44
--- /dev/null
+++ b/packet/sockaddr.h
@@ -0,0 +1,6 @@
+unsigned int sockaddr_size(const void *x);
+
+void *sockaddr_addr_offset(const void *x);
+unsigned int sockaddr_addr_size(const void *x);
+
+in_port_t *sockaddr_port_offset(const void *x);
diff --git a/packet/timeval.c b/packet/timeval.c
index 0f88a3a..11aa414 100644
--- a/packet/timeval.c
+++ b/packet/timeval.c
@@ -11,9 +11,9 @@
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    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 "timeval.h"
diff --git a/packet/timeval.h b/packet/timeval.h
index d00897a..7de980b 100644
--- a/packet/timeval.h
+++ b/packet/timeval.h
@@ -11,9 +11,9 @@
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    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 TIMEVAL_H
diff --git a/packet/wait.h b/packet/wait.h
index 0d24b4a..eadad2e 100644
--- a/packet/wait.h
+++ b/packet/wait.h
@@ -11,9 +11,9 @@
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    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 WAIT_H
diff --git a/packet/wait_cygwin.c b/packet/wait_cygwin.c
index 33cbbb9..6f93fb1 100644
--- a/packet/wait_cygwin.c
+++ b/packet/wait_cygwin.c
@@ -11,45 +11,55 @@
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    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 "wait.h"
 
-#include <io.h>
-#include <stdio.h>
-#include <windows.h>
+#include <error.h>
+#include <sys/select.h>
 
 #include "command.h"
 
 /*
-    Sleep until we receive a new probe response, a new command on the
-    command stream, or a probe timeout.  On Windows, this means that
-    we will sleep with an alertable wait, as all of these conditions
-    use I/O completion routines as notifications of these events.
+    Wait for either a request from the command stream or
+    for the probe results to be passed from the ICMP service
+    thread.
 */
 void wait_for_activity(
     struct command_buffer_t *command_buffer,
     struct net_state_t *net_state)
 {
-    DWORD wait_result;
-
-    /*
-       Start the command read overlapped I/O just prior to sleeping.
-       During development of the Cygwin port, there was a bug where the
-       overlapped I/O was started earlier in the mtr-packet loop, and
-       an intermediate alertable wait could leave us in this Sleep
-       without an active command read.  So now we do this here, instead.
-     */
-    start_read_command(command_buffer);
-
-    /*  Sleep until an I/O completion routine runs  */
-    wait_result = SleepEx(INFINITE, TRUE);
-
-    if (wait_result == WAIT_FAILED) {
-        fprintf(stderr, "SleepEx failure %d\n", GetLastError());
-        exit(EXIT_FAILURE);
+    int nfds;
+    fd_set read_set;
+    int ready_count;
+
+    FD_ZERO(&read_set);
+
+    FD_SET(command_buffer->command_stream, &read_set);
+    nfds = command_buffer->command_stream + 1;
+
+    FD_SET(net_state->platform.thread_out_pipe_read, &read_set);
+    if (net_state->platform.thread_out_pipe_read >= nfds) {
+        nfds = net_state->platform.thread_out_pipe_read + 1;
+    }
+
+    while (true) {
+        ready_count =
+            select(nfds, &read_set, NULL, NULL, NULL);
+
+        if (ready_count != -1) {
+            return;
+        }
+
+        /*
+            EINTR and EAGAIN simply mean that the select should
+            be retried.
+        */
+        if (errno != EINTR && errno != EAGAIN) {
+            error(EXIT_FAILURE, errno, "unexpected select error");
+        }
     }
 }
diff --git a/packet/wait_unix.c b/packet/wait_unix.c
index f347e23..06d2ea7 100644
--- a/packet/wait_unix.c
+++ b/packet/wait_unix.c
@@ -11,15 +11,20 @@
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    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 "wait.h"
 
 #include <assert.h>
 #include <errno.h>
+#ifdef HAVE_ERROR_H
+#include <error.h>
+#else
+#include "portability/error.h"
+#endif
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -39,8 +44,8 @@ int gather_read_fds(
 {
     int nfds;
     int probe_nfds;
-    int ip4_socket = net_state->platform.ip4_recv_socket;
-    int ip6_socket = net_state->platform.ip6_recv_socket;
+    int ip4_socket;
+    int ip6_socket;
     int command_stream = command_buffer->command_stream;
 
     FD_ZERO(read_set);
@@ -49,14 +54,42 @@ int gather_read_fds(
     FD_SET(command_stream, read_set);
     nfds = command_stream + 1;
 
-    FD_SET(ip4_socket, read_set);
-    if (ip4_socket >= nfds) {
-        nfds = ip4_socket + 1;
+    if (net_state->platform.ip4_socket_raw) {
+        ip4_socket = net_state->platform.ip4_recv_socket;
+        FD_SET(ip4_socket, read_set);
+        if (ip4_socket >= nfds) {
+            nfds = ip4_socket + 1;
+        }
+    } else {
+        ip4_socket = net_state->platform.ip4_txrx_icmp_socket;
+        FD_SET(ip4_socket, read_set);
+        if (ip4_socket >= nfds) {
+            nfds = ip4_socket + 1;
+        }
+        ip4_socket = net_state->platform.ip4_txrx_udp_socket;
+        FD_SET(ip4_socket, read_set);
+        if (ip4_socket >= nfds) {
+            nfds = ip4_socket + 1;
+        }
     }
 
-    FD_SET(ip6_socket, read_set);
-    if (ip6_socket >= nfds) {
-        nfds = ip6_socket + 1;
+    if (net_state->platform.ip6_socket_raw) {
+        ip6_socket = net_state->platform.ip6_recv_socket;
+        FD_SET(ip6_socket, read_set);
+        if (ip6_socket >= nfds) {
+            nfds = ip6_socket + 1;
+        }
+    } else {
+        ip6_socket = net_state->platform.ip6_txrx_icmp_socket;
+        FD_SET(ip6_socket, read_set);
+        if (ip6_socket >= nfds) {
+            nfds = ip6_socket + 1;
+        }
+        ip6_socket = net_state->platform.ip6_txrx_udp_socket;
+        FD_SET(ip6_socket, read_set);
+        if (ip6_socket >= nfds) {
+            nfds = ip6_socket + 1;
+        }
     }
 
     probe_nfds = gather_probe_sockets(net_state, write_set);
@@ -116,8 +149,7 @@ void wait_for_activity(
          */
         if (errno != EINTR && errno != EAGAIN) {
             /*  We don't expect other errors, so report them  */
-            perror("unexpected select error");
-            exit(EXIT_FAILURE);
+            error(EXIT_FAILURE, errno, "unexpected select error");
         }
     }
 }
diff --git a/portability/error.c b/portability/error.c
index 99b7c99..48101e0 100644
--- a/portability/error.c
+++ b/portability/error.c
@@ -12,9 +12,9 @@
    Lesser General Public License for more details.
 
    You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, write to the Free
-   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-   02111-1307 USA.
+   License along with this library; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301 USA.
 */
 
 #include <stdarg.h>
diff --git a/portability/error.h b/portability/error.h
index 5efbaed..bd8faad 100644
--- a/portability/error.h
+++ b/portability/error.h
@@ -12,9 +12,9 @@
    Lesser General Public License for more details.
 
    You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, write to the Free
-   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-   02111-1307 USA.
+   License along with this library; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301 USA.
 */
 
 void error(int status, int errnum, const char *format, ...);
diff --git a/portability/getopt.c b/portability/getopt.c
index b7d7d04..fcd0b7d 100644
--- a/portability/getopt.c
+++ b/portability/getopt.c
@@ -16,9 +16,9 @@
    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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+   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.  */
 
 /* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
    Ditto for AIX 3.2 and <stdlib.h>.  */
diff --git a/portability/getopt.h b/portability/getopt.h
index aaa627e..55877fd 100644
--- a/portability/getopt.h
+++ b/portability/getopt.h
@@ -13,9 +13,9 @@
    Lesser General Public License for more details.
 
    You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, write to the Free
-   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-   02111-1307 USA.  */
+   License along with this library; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301 USA.  */
 
 #ifndef _GETOPT_H
 
diff --git a/portability/getopt1.c b/portability/getopt1.c
index 6dd1183..b498253 100644
--- a/portability/getopt1.c
+++ b/portability/getopt1.c
@@ -11,9 +11,9 @@
    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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+   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.  */
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
diff --git a/test/cmdparse.py b/test/cmdparse.py
index 7a807c6..ad6d23c 100755
--- a/test/cmdparse.py
+++ b/test/cmdparse.py
@@ -12,9 +12,9 @@
 #   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., 675 Mass Ave, Cambridge, MA 02139, USA.
+#   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.
 #
 
 '''Test mtr-packet's command parsing.'''
diff --git a/test/mtrpacket.py b/test/mtrpacket.py
index be21dcd..68ecc20 100644
--- a/test/mtrpacket.py
+++ b/test/mtrpacket.py
@@ -11,9 +11,9 @@
 #   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., 675 Mass Ave, Cambridge, MA 02139, USA.
+#   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.
 #
 
 '''Infrastructure for running tests which invoke mtr-packet.'''
diff --git a/test/packet_listen.c b/test/packet_listen.c
index eedda4e..a822707 100644
--- a/test/packet_listen.c
+++ b/test/packet_listen.c
@@ -11,9 +11,9 @@
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    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 <netinet/in.h>
diff --git a/test/param.py b/test/param.py
index d511062..d220019 100755
--- a/test/param.py
+++ b/test/param.py
@@ -12,9 +12,9 @@
 #   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., 675 Mass Ave, Cambridge, MA 02139, USA.
+#   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.
 #
 
 '''Test probe customization parameters'''
diff --git a/test/probe.py b/test/probe.py
index 2b500c6..e69214c 100755
--- a/test/probe.py
+++ b/test/probe.py
@@ -12,9 +12,9 @@
 #   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., 675 Mass Ave, Cambridge, MA 02139, USA.
+#   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.
 #
 
 '''Test sending probes and receiving respones.'''
diff --git a/ui/asn.c b/ui/asn.c
index 04c8e3a..0ed0398 100644
--- a/ui/asn.c
+++ b/ui/asn.c
@@ -11,9 +11,9 @@
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    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 "config.h"
@@ -193,8 +193,6 @@ static char *split_txtrec(
     if (i > ctl->ipinfo_max)
         ctl->ipinfo_max = i;
     if (ctl->ipinfo_no >= i) {
-        if (ctl->ipinfo_no >= ctl->ipinfo_max)
-            ctl->ipinfo_no = 0;
         return (*items)[0];
     } else
         return (*items)[ctl->ipinfo_no];
@@ -309,7 +307,7 @@ char *fmt_ipinfo(
 int is_printii(
     struct mtr_ctl *ctl)
 {
-    return ((ctl->ipinfo_no >= 0) && (ctl->ipinfo_no != ctl->ipinfo_max));
+    return (ctl->ipinfo_no >= 0);
 }
 
 void asn_open(
diff --git a/ui/asn.h b/ui/asn.h
index 5301e9b..bd8c069 100644
--- a/ui/asn.h
+++ b/ui/asn.h
@@ -11,9 +11,9 @@
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    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 "mtr.h"
diff --git a/ui/cmdpipe.c b/ui/cmdpipe.c
index c7120e2..3581086 100644
--- a/ui/cmdpipe.c
+++ b/ui/cmdpipe.c
@@ -11,9 +11,9 @@
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    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 "cmdpipe.h"
@@ -204,6 +204,7 @@ int check_packet_features(
 }
 
 
+extern char *myname;
 /*
     Execute mtr-packet, allowing the MTR_PACKET evironment to override
     the PATH when locating the executable.
@@ -212,6 +213,7 @@ static
 void execute_packet_child(
     void)
 {
+    char buf[256];
     /*
        Allow the MTR_PACKET environment variable to override
        the path to the mtr-packet executable.  This is necessary
@@ -228,6 +230,14 @@ void execute_packet_child(
      */
     execlp(mtr_packet_path, "mtr-packet", (char *) NULL);
 
+    /* 
+       Then try to find it where WE were executed from.  
+     */
+    strncpy (buf, myname, 240);
+    strcat (buf, "-packet");
+    mtr_packet_path = buf;
+    execl(mtr_packet_path, "mtr-packet", (char *) NULL);
+
     /*
        If mtr-packet is not found, try to use mtr-packet from current directory
      */
@@ -507,7 +517,7 @@ void parse_mpls_values(
         if (label_field == 0) {
             mpls->label[label_count] = value;
         } else if (label_field == 1) {
-            mpls->exp[label_count] = value;
+            mpls->tc[label_count] = value;
         } else if (label_field == 2) {
             mpls->s[label_count] = value;
         } else if (label_field == 3) {
@@ -611,16 +621,6 @@ void handle_reply_errors(
 
     reply_name = reply->command_name;
 
-    if (!strcmp(reply_name, "no-route")) {
-        display_close(ctl);
-        error(EXIT_FAILURE, 0, "No route to host");
-    }
-
-    if (!strcmp(reply_name, "network-down")) {
-        display_close(ctl);
-        error(EXIT_FAILURE, 0, "Network down");
-    }
-
     if (!strcmp(reply_name, "probes-exhausted")) {
         display_close(ctl);
         error(EXIT_FAILURE, 0, "Probes exhausted");
@@ -667,6 +667,7 @@ void handle_command_reply(
     struct command_t reply;
     ip_t fromaddress;
     int seq_num;
+    int err;
     int round_trip_time;
     char *reply_name;
     struct mplslen mpls;
@@ -688,8 +689,16 @@ void handle_command_reply(
     seq_num = reply.token;
     reply_name = reply.command_name;
 
-    /*  If the reply type is unknown, ignore it for future compatibility  */
-    if (strcmp(reply_name, "reply") && strcmp(reply_name, "ttl-expired")) {
+    /*  Check for known reply types.  */
+    if (!strcmp(reply_name, "reply")
+            || !strcmp(reply_name, "ttl-expired")) {
+        err = 0;
+    } else if (!strcmp(reply_name, "no-route")) {
+        err = ENETUNREACH;
+    } else if (!strcmp(reply_name, "network-down")) {
+        err = ENETDOWN;
+    } else {
+        /*  If the reply type is unknown, ignore it  */
         return;
     }
 
@@ -700,7 +709,7 @@ void handle_command_reply(
     if (parse_reply_arguments
         (ctl, &reply, &fromaddress, &round_trip_time, &mpls)) {
 
-        reply_func(ctl, seq_num, &mpls, (void *) &fromaddress,
+        reply_func(ctl, seq_num, err, &mpls, (void *) &fromaddress,
                    round_trip_time);
     }
 }
diff --git a/ui/cmdpipe.h b/ui/cmdpipe.h
index 7a5b687..3d1c58f 100644
--- a/ui/cmdpipe.h
+++ b/ui/cmdpipe.h
@@ -11,9 +11,9 @@
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    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 CMDPIPE_H
@@ -47,6 +47,7 @@ void (
     *probe_reply_func_t) (
     struct mtr_ctl * ctl,
     int sequence,
+    int err,
     struct mplslen * mpls,
     ip_t * addr,
     int round_trip_time);
diff --git a/ui/curses.c b/ui/curses.c
index a7588ca..b0bc02e 100644
--- a/ui/curses.c
+++ b/ui/curses.c
@@ -11,9 +11,9 @@
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    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 "config.h"
@@ -157,6 +157,7 @@ int mtr_curses_keyaction(
 
     switch (c) {
     case 'q':
+    case -1:
     case 3:
         return ActionQuit;
     case 12:
@@ -235,7 +236,7 @@ int mtr_curses_keyaction(
 
         if (f <= 0.0)
             return ActionNone;
-        if (getuid() != 0 && f < 1.0)
+        if (!running_as_root() && (f < 1.0))
             return ActionNone;
         ctl->WaitTime = f;
 
@@ -363,6 +364,7 @@ int mtr_curses_keyaction(
             ("  b <c>   set ping bit pattern to c(0..255) or random(c<0)\n");
         printw("  Q <t>   set ping packet's TOS to t\n");
         printw("  u       switch between ICMP ECHO and UDP datagrams\n");
+        printw("  t       switch between ICMP ECHO and TCP\n");
 #ifdef HAVE_IPINFO
         printw("  y       switching IP info\n");
         printw("  z       toggle ASN info on/off\n");
@@ -404,6 +406,8 @@ static void mtr_curses_hosts(
     int at;
     struct mplslen *mpls, *mplss;
     ip_t *addr, *addrs;
+    int addrcmp_result;
+    int err;
     int y;
     char *name;
 
@@ -416,11 +420,14 @@ static void mtr_curses_hosts(
 
     for (at = net_min(ctl) + ctl->display_offset; at < max; at++) {
         printw("%2d. ", at + 1);
+        err = net_err(at);
         addr = net_addr(at);
         mpls = net_mpls(at);
 
-        if (addrcmp((void *) addr, (void *) &ctl->unspec_addr, ctl->af) !=
-            0) {
+        addrcmp_result = addrcmp(
+            (void *) addr, (void *) &ctl->unspec_addr, ctl->af);
+
+        if (err == 0 && addrcmp_result != 0) {
             name = dns_lookup(ctl, addr);
             if (!net_up(at))
                 attron(A_BOLD);
@@ -459,8 +466,8 @@ static void mtr_curses_hosts(
             printw("%s", buf);
 
             for (k = 0; k < mpls->labels && ctl->enablempls; k++) {
-                printw("\n    [MPLS: Lbl %lu Exp %u S %u TTL %u]",
-                       mpls->label[k], mpls->exp[k], mpls->s[k],
+                printw("\n    [MPLS: Lbl %lu TC %u S %u TTL %u]",
+                       mpls->label[k], mpls->tc[k], mpls->s[k],
                        mpls->ttl[k]);
             }
 
@@ -492,15 +499,16 @@ static void mtr_curses_hosts(
                     printw("%s", strlongip(ctl, addrs));
                 }
                 for (k = 0; k < mplss->labels && ctl->enablempls; k++) {
-                    printw("\n    [MPLS: Lbl %lu Exp %u S %u TTL %u]",
-                           mplss->label[k], mplss->exp[k], mplss->s[k],
+                    printw("\n    [MPLS: Lbl %lu TC %u S %u TTL %u]",
+                           mplss->label[k], mplss->tc[k], mplss->s[k],
                            mplss->ttl[k]);
                 }
                 attroff(A_BOLD);
             }
-
         } else {
-            printw("???");
+            attron(A_BOLD);
+            printw("(%s)", host_error_to_string(err));
+            attroff(A_BOLD);
         }
 
         printw("\n");
@@ -618,7 +626,7 @@ static void mtr_curses_graph(
     int startstat,
     int cols)
 {
-    int max, at, y;
+    int max, at, y, err;
     ip_t *addr;
     char *name;
     int __unused_int ATTRIBUTE_UNUSED;
@@ -629,22 +637,31 @@ static void mtr_curses_graph(
         printw("%2d. ", at + 1);
 
         addr = net_addr(at);
+        err = net_err(at);
+
         if (!addr) {
-            printw("???\n");
+            printw("(%s)", host_error_to_string(err));
             continue;
         }
 
-        if (!net_up(at))
-            attron(A_BOLD);
-        if (addrcmp((void *) addr, (void *) &ctl->unspec_addr, ctl->af)) {
+        if (err == 0
+            && addrcmp((void *) addr, (void *) &ctl->unspec_addr, ctl->af)) {
+
+            if (!net_up(at)) {
+                attron(A_BOLD);
+            }
+
 #ifdef HAVE_IPINFO
             if (is_printii(ctl))
                 printw(fmt_ipinfo(ctl, addr));
 #endif
             name = dns_lookup(ctl, addr);
             printw("%s", name ? name : strlongip(ctl, addr));
-        } else
-            printw("???");
+        } else {
+            attron(A_BOLD);
+            printw("(%s)", host_error_to_string(err));
+        }
+
         attroff(A_BOLD);
 
         getyx(stdscr, y, __unused_int);
diff --git a/ui/display.c b/ui/display.c
index 4c08889..9a8ac60 100644
--- a/ui/display.c
+++ b/ui/display.c
@@ -11,15 +11,17 @@
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    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 "config.h"
 
+#include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <sys/types.h>
 #include <time.h>
 
@@ -250,3 +252,26 @@ void display_clear(
         mtr_curses_clear(ctl);
 #endif
 }
+
+
+/*
+    Given an errno error code corresponding to a host entry, return a
+    user readable error string.
+*/
+char *host_error_to_string(
+    int err)
+{
+    if (err == ENETUNREACH) {
+        return "no route to host";
+    }
+
+    if (err == ENETDOWN) {
+        return "network down";
+    }
+
+    if (err == 0) {
+        return "waiting for reply";
+    }
+
+    return strerror(err);
+}
diff --git a/ui/display.h b/ui/display.h
index d827528..c577d3f 100644
--- a/ui/display.h
+++ b/ui/display.h
@@ -11,9 +11,9 @@
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    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 <netinet/in.h>
@@ -81,3 +81,5 @@ extern void display_loop(
     struct mtr_ctl *ctl);
 extern void display_clear(
     struct mtr_ctl *ctl);
+extern char *host_error_to_string(
+    int err);
diff --git a/ui/dns.c b/ui/dns.c
index 7d5ce1a..8b323ff 100644
--- a/ui/dns.c
+++ b/ui/dns.c
@@ -11,9 +11,9 @@
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    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.
 */
 
 /*
diff --git a/ui/dns.h b/ui/dns.h
index f38c846..c04d184 100644
--- a/ui/dns.h
+++ b/ui/dns.h
@@ -11,9 +11,9 @@
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    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 <config.h>
diff --git a/ui/gtk.c b/ui/gtk.c
index b05e869..a978d35 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -12,9 +12,9 @@
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    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 "config.h"
@@ -198,7 +198,7 @@ static gint About_clicked(
     gtk_show_about_dialog(GTK_WINDOW(main_window)
                           , "version", PACKAGE_VERSION, "copyright",
                           "Copyright \xc2\xa9 1997,1998  Matt Kimball",
-                          "website", "http://www.bitwizard.nl/mtr/",
+                          "website", "https://www.bitwizard.nl/mtr/",
                           "authors", authors, "comments",
                           "The 'traceroute' and 'ping' programs in a single network diagnostic tool.",
                           "license",
@@ -294,8 +294,7 @@ static void Toolbar_fill(
 
     /* allow root only to set zero delay */
     Adjustment = (GtkAdjustment *) gtk_adjustment_new(ctl->WaitTime,
-                                                      getuid() ==
-                                                      0 ? 0.01 : 1.00,
+                                                      running_as_root() ? 0.01 : 1.00,
                                                       999.99, 1.0, 10.0,
                                                       0.0);
     Button = gtk_spin_button_new(Adjustment, 0.5, 2);
diff --git a/ui/mtr-curses.h b/ui/mtr-curses.h
index 71298cf..7bb1975 100644
--- a/ui/mtr-curses.h
+++ b/ui/mtr-curses.h
@@ -11,9 +11,9 @@
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    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.
 */
 
 /*  Prototypes for curses.c  */
diff --git a/ui/mtr-gtk.h b/ui/mtr-gtk.h
index 88fa3a1..524de1c 100644
--- a/ui/mtr-gtk.h
+++ b/ui/mtr-gtk.h
@@ -11,9 +11,9 @@
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    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.
 */
 
 /*  Prototypes for gtk.c  */
diff --git a/ui/mtr.c b/ui/mtr.c
index 70ae5c4..a3fef48 100644
--- a/ui/mtr.c
+++ b/ui/mtr.c
@@ -11,9 +11,9 @@
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    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 "config.h"
@@ -70,6 +70,8 @@
 #endif
 
 
+char *myname;
+
 const struct fields data_fields[MAXFLD] = {
     /* key, Remark, Header, Format, Width, CallBackFunc */
     {' ', "<sp>: Space between fields", " ", " ", 1, &net_drop},
@@ -110,6 +112,8 @@ static void __attribute__ ((__noreturn__)) usage(FILE * out)
           out);
     fputs(" -T, --tcp                  use TCP instead of ICMP echo\n",
           out);
+    fputs(" -I, --interface NAME       use named network interface\n",
+         out);
     fputs
         (" -a, --address ADDRESS      bind the outgoing socket to ADDRESS\n",
          out);
@@ -161,7 +165,7 @@ static void __attribute__ ((__noreturn__)) usage(FILE * out)
 #ifdef HAVE_GTK
     fputs(" -g, --gtk                  use GTK+ xwindow interface\n", out);
 #endif
-    fputs(" -n, --no-dns               do not resove host names\n", out);
+    fputs(" -n, --no-dns               do not resolve host names\n", out);
     fputs(" -b, --show-ips             show IP numbers and host names\n",
           out);
     fputs(" -o, --order FIELDS         select output fields\n", out);
@@ -301,6 +305,7 @@ static void init_fld_options(
         ctl->available_options[i] = data_fields[i].key;
         ctl->fld_index[data_fields[i].key] = i;
     }
+    ctl->available_options[i++] = '_';
     ctl->available_options[i] = 0;
 }
 
@@ -363,6 +368,7 @@ static void parse_arg(
         {"bitpattern", 1, NULL, 'B'},   /* overload B>255, ->rand(0,255) */
         {"tos", 1, NULL, 'Q'},  /* typeof service (0,255) */
         {"mpls", 0, NULL, 'e'},
+        {"interface", 1, NULL, 'I'},
         {"address", 1, NULL, 'a'},
         {"first-ttl", 1, NULL, 'f'},    /* -f & -m are borrowed from traceroute */
         {"max-ttl", 1, NULL, 'm'},
@@ -462,6 +468,9 @@ static void parse_arg(
             ctl->cpacketsize =
                 strtonum_or_err(optarg, "invalid argument", STRTO_INT);
             break;
+        case 'I':
+            ctl->InterfaceName = optarg;
+            break;
         case 'a':
             ctl->InterfaceAddress = optarg;
             break;
@@ -476,7 +485,7 @@ static void parse_arg(
             if (ctl->WaitTime <= 0.0) {
                 error(EXIT_FAILURE, 0, "wait time must be positive");
             }
-            if (getuid() != 0 && ctl->WaitTime < 1.0) {
+            if (!running_as_root() && ctl->WaitTime < 1.0) {
                 error(EXIT_FAILURE, 0,
                       "non-root users cannot request an interval < 1.0 seconds");
             }
@@ -681,22 +690,83 @@ static void init_rand(
     srand((getpid() << 16) ^ getuid() ^ tv.tv_sec ^ tv.tv_usec);
 }
 
+
+/*
+    For historical reasons, we need a hostent structure to represent
+    our remote target for probing.  The obsolete way of doing this
+    would be to use gethostbyname().  We'll use getaddrinfo() instead
+    to generate the hostent.
+*/
+static int get_hostent_from_name(
+    struct mtr_ctl *ctl,
+    struct hostent *host,
+    const char *name,
+    char **alptr)
+{
+    int gai_error;
+    struct addrinfo hints, *res;
+    struct sockaddr_in *sa4;
+#ifdef ENABLE_IPV6
+    struct sockaddr_in6 *sa6;
+#endif
+
+    /* gethostbyname2() is deprecated so we'll use getaddrinfo() instead. */
+    memset(&hints, 0, sizeof hints);
+    hints.ai_family = ctl->af;
+    hints.ai_socktype = SOCK_DGRAM;
+    gai_error = getaddrinfo(name, NULL, &hints, &res);
+    if (gai_error) {
+        if (gai_error == EAI_SYSTEM)
+            error(0, 0, "Failed to resolve host: %s", name);
+        else
+            error(0, 0, "Failed to resolve host: %s: %s", name,
+                  gai_strerror(gai_error));
+
+        return -1;
+    }
+
+    /* Convert the first addrinfo into a hostent. */
+    memset(host, 0, sizeof(struct hostent));
+    host->h_name = res->ai_canonname;
+    host->h_aliases = NULL;
+    host->h_addrtype = res->ai_family;
+    ctl->af = res->ai_family;
+    host->h_length = res->ai_addrlen;
+    host->h_addr_list = alptr;
+    switch (ctl->af) {
+    case AF_INET:
+        sa4 = (struct sockaddr_in *) res->ai_addr;
+        alptr[0] = (void *) &(sa4->sin_addr);
+        break;
+#ifdef ENABLE_IPV6
+    case AF_INET6:
+        sa6 = (struct sockaddr_in6 *) res->ai_addr;
+        alptr[0] = (void *) &(sa6->sin6_addr);
+        break;
+#endif
+    default:
+        error(0, 0, "unknown address type");
+
+        errno = EINVAL;
+        return -1;
+    }
+    alptr[1] = NULL;
+
+    return 0;
+}
+
+
 int main(
     int argc,
     char **argv)
 {
     struct hostent *host = NULL;
-    struct addrinfo hints, *res;
-    int gai_error;
     struct hostent trhost;
     char *alptr[2];
-    struct sockaddr_in *sa4;
-#ifdef ENABLE_IPV6
-    struct sockaddr_in6 *sa6;
-#endif
     names_t *names_head = NULL;
     names_t *names_walk;
 
+    myname = argv[0];
     struct mtr_ctl ctl;
     memset(&ctl, 0, sizeof(ctl));
     /* initialize non-null values */
@@ -761,47 +831,8 @@ int main(
                      sizeof(ctl.LocalHostname));
         }
 
-        /* gethostbyname2() is deprecated so we'll use getaddrinfo() instead. */
-        memset(&hints, 0, sizeof hints);
-        hints.ai_family = ctl.af;
-        hints.ai_socktype = SOCK_DGRAM;
-        gai_error = getaddrinfo(ctl.Hostname, NULL, &hints, &res);
-        if (gai_error) {
-            if (gai_error == EAI_SYSTEM)
-                error(0, 0, "Failed to resolve host: %s", ctl.Hostname);
-            else
-                error(0, 0, "Failed to resolve host: %s: %s", ctl.Hostname,
-                      gai_strerror(gai_error));
-
-            if (ctl.Interactive)
-                exit(EXIT_FAILURE);
-            else {
-                names_walk = names_walk->next;
-                continue;
-            }
-        }
-        /* Convert the first addrinfo into a hostent. */
         host = &trhost;
-        memset(host, 0, sizeof trhost);
-        host->h_name = res->ai_canonname;
-        host->h_aliases = NULL;
-        host->h_addrtype = res->ai_family;
-        ctl.af = res->ai_family;
-        host->h_length = res->ai_addrlen;
-        host->h_addr_list = alptr;
-        switch (ctl.af) {
-        case AF_INET:
-            sa4 = (struct sockaddr_in *) res->ai_addr;
-            alptr[0] = (void *) &(sa4->sin_addr);
-            break;
-#ifdef ENABLE_IPV6
-        case AF_INET6:
-            sa6 = (struct sockaddr_in6 *) res->ai_addr;
-            alptr[0] = (void *) &(sa6->sin6_addr);
-            break;
-#endif
-        default:
-            error(0, 0, "unknown address type");
+        if (get_hostent_from_name(&ctl, host, ctl.Hostname, alptr) != 0) {
             if (ctl.Interactive)
                 exit(EXIT_FAILURE);
             else {
@@ -809,7 +840,6 @@ int main(
                 continue;
             }
         }
-        alptr[1] = NULL;
 
         if (net_open(&ctl, host) != 0) {
             error(0, 0, "Unable to start net module");
diff --git a/ui/mtr.h b/ui/mtr.h
index 7ede21d..ac38016 100644
--- a/ui/mtr.h
+++ b/ui/mtr.h
@@ -12,9 +12,9 @@
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    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 MTR_MTR_H
@@ -83,6 +83,7 @@ struct mtr_ctl {
     float WaitTime;
     float GraceTime;
     char *Hostname;
+    char *InterfaceName;
     char *InterfaceAddress;
     char LocalHostname[128];
     int ipinfo_no;
@@ -132,10 +133,17 @@ extern const struct fields data_fields[MAXFLD];
 /* MPLS label object */
 struct mplslen {
     unsigned long label[MAXLABELS];     /* label value */
-    uint8_t exp[MAXLABELS];     /* experimental bits */
+    uint8_t tc[MAXLABELS];     /* Traffic Class bits */
     uint8_t ttl[MAXLABELS];     /* MPLS TTL */
     char s[MAXLABELS];          /* bottom of stack */
     char labels;                /* how many labels did we get? */
 };
 
+
+#ifdef USING_CYGWIN
+#define running_as_root() 1
+#else
+#define running_as_root() (getuid() == 0)
+#endif
+
 #endif                          /* MTR_MTR_H */
diff --git a/ui/net.c b/ui/net.c
index 3a7abc8..1c78466 100644
--- a/ui/net.c
+++ b/ui/net.c
@@ -11,14 +11,16 @@
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    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 "config.h"
 
 #include <errno.h>
+#include <sys/types.h>
+#include <ifaddrs.h>
 #include <math.h>
 #include <stdlib.h>
 #include <string.h>
@@ -51,6 +53,7 @@ static void sockaddrtop(
 struct nethost {
     ip_t addr;
     ip_t addrs[MAXPATH];        /* for multi paths byMin */
+    int err;
     int xmit;
     int returned;
     int sent;
@@ -185,11 +188,37 @@ static void net_send_query(
 }
 
 
-/* We got a return on something we sent out.  Record the address and
-   time.  */
+/*
+    Mark a sequence entry as completed and return the host index
+    being probed.
+
+    Returns -1 in the case of an invalid sequence number.
+*/
+static int mark_sequence_complete(
+    int seq)
+{
+    if ((seq < 0) || (seq >= MaxSequence)) {
+        return -1;
+    }
+
+    if (!sequence[seq].transit) {
+        return -1;
+    }
+    sequence[seq].transit = 0;
+
+    return sequence[seq].index;
+}
+
+
+/*
+    A probe has successfully completed.
+
+    Record the round trip time and address of the responding host.
+*/
 static void net_process_ping(
     struct mtr_ctl *ctl,
     int seq,
+    int err,
     struct mplslen *mpls,
     ip_t * addr,
     int totusec)
@@ -206,16 +235,12 @@ static void net_process_ping(
 
     addrcpy((void *) &addrcopy, (char *) addr, ctl->af);
 
-    if ((seq < 0) || (seq >= MaxSequence)) {
-        return;
-    }
-
-    if (!sequence[seq].transit) {
+    index = mark_sequence_complete(seq);
+    if (index < 0) {
         return;
     }
-    sequence[seq].transit = 0;
 
-    index = sequence[seq].index;
+    host[index].err = err;
 
     if (addrcmp((void *) &(host[index].addr),
                 (void *) &ctl->unspec_addr, ctl->af) == 0) {
@@ -325,6 +350,15 @@ ip_t *net_addrs(
     return (ip_t *) & (host[at].addrs[i]);
 }
 
+/*
+    Get the error code corresponding to a host entry.
+*/
+int net_err(
+    int at)
+{
+    return host[at].err;
+}
+
 void *net_mpls(
     int at)
 {
@@ -440,16 +474,25 @@ int net_max(
     int max;
 
     max = 0;
-    for (at = 0; at < ctl->maxTTL - 1; at++) {
+    for (at = 0; at < ctl->maxTTL; at++) {
         if (addrcmp((void *) &(host[at].addr),
                     (void *) remoteaddress, ctl->af) == 0) {
             return at + 1;
+        } else if (host[at].err != 0) {
+            /*
+                If a hop has returned an ICMP error
+                (such as "no route to host") then we'll consider that the
+                final hop.
+            */
+            return at + 1;
         } else if (addrcmp((void *) &(host[at].addr),
                            (void *) &ctl->unspec_addr, ctl->af) != 0) {
             max = at + 2;
         }
     }
 
+    if (max > ctl->maxTTL)
+        max = ctl->maxTTL;
     return max;
 }
 
@@ -582,6 +625,61 @@ static void net_validate_interface_address(
 
 
 /*
+    Given the name of a network interface and a preferred address
+    family (IPv4 or IPv6), find the source IP address for sending
+    probes from that interface.
+*/
+static void net_find_interface_address_from_name(
+    struct sockaddr_storage *addr,
+    int address_family,
+    const char *interface_name)
+{
+    struct ifaddrs *ifaddrs;
+    struct ifaddrs *interface;
+    int found_interface_name = 0;
+
+    if (getifaddrs(&ifaddrs) != 0) {
+        error(EXIT_FAILURE, errno, "getifaddrs failure");
+    }
+
+    interface = ifaddrs;
+    while (interface != NULL) {
+        if (!strcmp(interface->ifa_name, interface_name)) {
+            found_interface_name = 1;
+
+            if (interface->ifa_addr->sa_family == address_family) {
+                if (address_family == AF_INET) {
+                    memcpy(addr,
+                        interface->ifa_addr, sizeof(struct sockaddr_in));
+                    freeifaddrs(ifaddrs);
+
+                    return;
+                } else if (address_family == AF_INET6) {
+                    memcpy(addr,
+                        interface->ifa_addr, sizeof(struct sockaddr_in6));
+                    freeifaddrs(ifaddrs);
+
+                    return;
+                }
+            }
+        }
+
+        interface = interface->ifa_next;
+    }
+
+    if (!found_interface_name) {
+        error(EXIT_FAILURE, 0, "no such interface");
+    } else if (address_family == AF_INET) {
+        error(EXIT_FAILURE, 0, "interface missing IPv4 address");
+    } else if (address_family == AF_INET6) {
+        error(EXIT_FAILURE, 0, "interface missing IPv6 address");
+    } else {
+        error(EXIT_FAILURE, 0, "interface missing address");
+    }
+}
+
+
+/*
   Find the local address we will use to sent to the remote
   host by connecting a UDP socket and checking the address
   the socket is bound to.
@@ -623,6 +721,16 @@ static void net_find_local_address(
 
     if (connect
         (udp_socket, (struct sockaddr *) &remote_sockaddr, addr_length)) {
+#ifdef __linux__
+        /* Linux doesn't require source address, so we can support
+         * a case when mtr is run against unreachable host (that can become
+         * reachable) */
+        if (errno == EHOSTUNREACH) {
+            close(udp_socket);
+            localaddr[0] = '\0';
+            return;
+        }
+#endif
         error(EXIT_FAILURE, errno, "udp socket connect failed");
     }
 
@@ -672,6 +780,11 @@ int net_open(
 
     if (ctl->InterfaceAddress) {
         net_validate_interface_address(ctl->af, ctl->InterfaceAddress);
+    } else if (ctl->InterfaceName) {
+        net_find_interface_address_from_name(
+            &sourcesockaddr_struct, ctl->af, ctl->InterfaceName);
+
+        sockaddrtop(sourcesockaddr, localaddr, sizeof(localaddr));
     } else {
         net_find_local_address();
     }
diff --git a/ui/net.h b/ui/net.h
index 6b95a00..0fb4700 100644
--- a/ui/net.h
+++ b/ui/net.h
@@ -11,9 +11,9 @@
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    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.
 */
 
 /*  Prototypes for functions in net.c  */
@@ -56,6 +56,8 @@ extern int net_last(
     int at);
 extern ip_t *net_addr(
     int at);
+extern int net_err(
+    int at);
 extern void *net_mpls(
     int at);
 extern void *net_mplss(
diff --git a/ui/raw.c b/ui/raw.c
index c13f00c..429a831 100644
--- a/ui/raw.c
+++ b/ui/raw.c
@@ -13,9 +13,9 @@
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    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 "config.h"
diff --git a/ui/raw.h b/ui/raw.h
index c79d8bb..bd1920c 100644
--- a/ui/raw.h
+++ b/ui/raw.h
@@ -13,9 +13,9 @@
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    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.
 */
 
 /*  Prototypes for raw.c  */
diff --git a/ui/report.c b/ui/report.c
index 7700391..97a3fa4 100644
--- a/ui/report.c
+++ b/ui/report.c
@@ -11,9 +11,9 @@
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    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 "config.h"
@@ -74,8 +74,8 @@ static void print_mpls(
 {
     int k;
     for (k = 0; k < mpls->labels; k++)
-        printf("       [MPLS: Lbl %lu Exp %u S %cu TTL %u]\n",
-               mpls->label[k], mpls->exp[k], mpls->s[k], mpls->ttl[k]);
+        printf("       [MPLS: Lbl %lu TC %u S %cu TTL %u]\n",
+               mpls->label[k], mpls->tc[k], mpls->s[k], mpls->ttl[k]);
 }
 #endif
 
@@ -210,8 +210,8 @@ void report_close(
                 if (mpls->labels && z == 1 && ctl->enablempls) {
                     for (k = 0; k < mpls->labels; k++) {
                         printf
-                            ("    |  |+-- [MPLS: Lbl %lu Exp %u S %u TTL %u]\n",
-                             mpls->label[k], mpls->exp[k], mpls->s[k],
+                            ("    |  |+-- [MPLS: Lbl %lu TC %u S %u TTL %u]\n",
+                             mpls->label[k], mpls->tc[k], mpls->s[k],
                              mpls->ttl[k]);
                     }
                 }
@@ -220,16 +220,16 @@ void report_close(
                     printf("    |  `|-- %s\n", strlongip(ctl, addr2));
                     for (k = 0; k < mplss->labels && ctl->enablempls; k++) {
                         printf
-                            ("    |   +-- [MPLS: Lbl %lu Exp %u S %u TTL %u]\n",
-                             mplss->label[k], mplss->exp[k], mplss->s[k],
+                            ("    |   +-- [MPLS: Lbl %lu TC %u S %u TTL %u]\n",
+                             mplss->label[k], mplss->tc[k], mplss->s[k],
                              mplss->ttl[k]);
                     }
                 } else {
                     printf("    |   |-- %s\n", strlongip(ctl, addr2));
                     for (k = 0; k < mplss->labels && ctl->enablempls; k++) {
                         printf
-                            ("    |   +-- [MPLS: Lbl %lu Exp %u S %u TTL %u]\n",
-                             mplss->label[k], mplss->exp[k], mplss->s[k],
+                            ("    |   +-- [MPLS: Lbl %lu TC %u S %u TTL %u]\n",
+                             mplss->label[k], mplss->tc[k], mplss->s[k],
                              mplss->ttl[k]);
                     }
                 }
@@ -247,8 +247,8 @@ void report_close(
         if (mpls->labels && z == 1 && ctl->enablempls) {
             int k;
             for (k = 0; k < mpls->labels; k++) {
-                printf("    |   +-- [MPLS: Lbl %lu Exp %u S %u TTL %u]\n",
-                       mpls->label[k], mpls->exp[k], mpls->s[k],
+                printf("    |   +-- [MPLS: Lbl %lu TC %u S %u TTL %u]\n",
+                       mpls->label[k], mpls->tc[k], mpls->s[k],
                        mpls->ttl[k]);
             }
         }
@@ -364,11 +364,12 @@ void json_close(
             }
         }
         if (at + 1 == max) {
-            printf("    }]\n");
+            printf("    }");
         } else {
             printf("    },\n");
         }
     }
+    printf("]\n");
     printf("  }\n");
     printf("}\n");
 }
diff --git a/ui/report.h b/ui/report.h
index 32b31c5..96eb46f 100644
--- a/ui/report.h
+++ b/ui/report.h
@@ -11,9 +11,9 @@
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    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.
 */
 
 /*  Prototypes for report.h  */
diff --git a/ui/select.c b/ui/select.c
index 15047a1..26748ac 100644
--- a/ui/select.c
+++ b/ui/select.c
@@ -11,9 +11,9 @@
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    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 "config.h"
diff --git a/ui/select.h b/ui/select.h
index 08ad44e..a6b2764 100644
--- a/ui/select.h
+++ b/ui/select.h
@@ -11,9 +11,9 @@
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    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.
 */
 
 extern void select_loop(
diff --git a/ui/split.c b/ui/split.c
index 0895103..c0f46be 100644
--- a/ui/split.c
+++ b/ui/split.c
@@ -15,9 +15,9 @@
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    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 "config.h"
@@ -166,7 +166,8 @@ int split_keyaction(
     tv.tv_usec = 0;
 
     if (select(1, &readfds, NULL, NULL, &tv) > 0) {
-        read(0, &c, 1);
+        if (read(0, &c, 1) <= 0) 
+          return ActionQuit;
     } else
         return 0;
 #endif
diff --git a/ui/split.h b/ui/split.h
index 84b6794..d6938c7 100644
--- a/ui/split.h
+++ b/ui/split.h
@@ -13,9 +13,9 @@
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    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.
 */
 
 /*  Prototypes for split.c  */
diff --git a/ui/utils.c b/ui/utils.c
index 94bf21a..bbdf69d 100644
--- a/ui/utils.c
+++ b/ui/utils.c
@@ -11,9 +11,9 @@
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    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 "config.h"
diff --git a/ui/utils.h b/ui/utils.h
index 7fc2055..1a44a8c 100644
--- a/ui/utils.h
+++ b/ui/utils.h
@@ -12,9 +12,9 @@
     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., 675 Mass Ave, Cambridge, MA 02139, USA.
+    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.
 */
 
 enum {
