Refactored packing and unpacking code to support name compression

Previously, all packing and unpacking functions took a slice of the raw
packet starting the relevant offset, and returned the change in offset.
This turned out not to work for name compression because the
unpackName() function needs to access lower offsets of the message.
All packing and unpacking functions have been modified to take a pointer
to an int for the offset, and modify that as it traverses the message.

Also, recursive resolving of queries has been started, and the replies
from the root DNS servers are successfully understood. Next step is to
do something with those replies.