World stuff...

This commit is contained in:
Adam Ierymenko 2015-10-13 12:10:44 -07:00
parent 05677f57e2
commit 5d2f523e81
15 changed files with 101 additions and 175 deletions

3
.gitignore vendored
View File

@ -31,7 +31,8 @@ Thumbs.db
/ZeroTierOneInstaller-*
/examples/docker/zerotier-one
/examples/docker/test-*.env
/mkworld
/world/mkworld
/world/*.c25519
# Miscellaneous file types that we don't want to check in
*.log

View File

@ -582,11 +582,6 @@ typedef struct
*/
uint64_t lastReceive;
/**
* Is path fixed? (i.e. not learned, static)
*/
int fixed;
/**
* Is path active?
*/

View File

@ -79,10 +79,6 @@ selftest: $(OBJS) selftest.o
$(CXX) $(CXXFLAGS) -o zerotier-selftest selftest.o $(OBJS) $(LIBS)
$(STRIP) zerotier-selftest
mkworld: $(OBJS)
rm -f mkworld
$(CXX) $(CXXFLAGS) -o mkworld mkworld.cpp $(OBJS) $(LIBS)
# Requires Packages: http://s.sudre.free.fr/Software/Packages/about.html
mac-dist-pkg: FORCE
packagesbuild "ext/installfiles/mac/ZeroTier One.pkgproj"

View File

@ -42,6 +42,7 @@
#include "SelfAwareness.hpp"
#include "Salsa20.hpp"
#include "SHA512.hpp"
#include "World.hpp"
namespace ZeroTier {
@ -199,10 +200,18 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR)
const uint64_t timestamp = at<uint64_t>(ZT_PROTO_VERB_HELLO_IDX_TIMESTAMP);
Identity id;
const unsigned int destAddrPtr = ZT_PROTO_VERB_HELLO_IDX_IDENTITY + id.deserialize(*this,ZT_PROTO_VERB_HELLO_IDX_IDENTITY);
InetAddress destAddr;
if (destAddrPtr < size()) // ZeroTier One < 1.0.3 did not include this field
destAddr.deserialize(*this,destAddrPtr);
uint64_t worldId = ZT_WORLD_ID_NULL;
uint64_t worldTimestamp = 0;
{
unsigned int ptr = ZT_PROTO_VERB_HELLO_IDX_IDENTITY + id.deserialize(*this,ZT_PROTO_VERB_HELLO_IDX_IDENTITY);
if (ptr < size()) // ZeroTier One < 1.0.3 did not include physical destination address info
ptr += destAddr.deserialize(*this,ptr);
if ((ptr + 16) <= size()) { // older versions also did not include World IDs or timestamps
worldId = at<uint64_t>(ptr); ptr += 8;
worldTimestamp = at<uint64_t>(ptr);
}
}
if (protoVersion < ZT_PROTO_VERSION_MIN) {
TRACE("dropped HELLO from %s(%s): protocol version too old",id.address().toString().c_str(),_remoteAddress.toString().c_str());
@ -286,8 +295,23 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR)
outp.append((unsigned char)ZEROTIER_ONE_VERSION_MINOR);
outp.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION);
_remoteAddress.serialize(outp);
outp.armor(peer->key(),true);
RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
if ((worldId != ZT_WORLD_ID_NULL)&&(worldId == RR->topology->worldId())) {
if (RR->topology->worldTimestamp() > worldTimestamp) {
World w(RR->topology->world());
const unsigned int sizeAt = outp.size();
outp.addSize(2); // make room for 16-bit size field
w.serialize(outp,false);
outp.setAt<uint16_t>(sizeAt,(uint16_t)(outp.size() - sizeAt));
} else {
outp.append((uint16_t)0); // no world update needed
}
outp.armor(peer->key(),true);
RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
} else {
TRACE("dropped HELLO from %s(%s): world ID mismatch: peer is %llu and we are %llu",source().toString().c_str(),_remoteAddress.toString().c_str(),worldId,RR->topology->worldId());
}
} catch ( ... ) {
TRACE("dropped HELLO from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str());
}

View File

@ -177,37 +177,47 @@ public:
RR(renv),
_now(now),
_relays(relays),
_rootAddresses(RR->topology->rootAddresses())
_world(RR->topology->world())
{
}
uint64_t lastReceiveFromUpstream;
uint64_t lastReceiveFromUpstream; // tracks last time we got a packet from an 'upstream' peer like a root or a relay
inline void operator()(Topology &t,const SharedPtr<Peer> &p)
{
bool isRelay = false;
for(std::vector< std::pair<Address,InetAddress> >::const_iterator r(_relays.begin());r!=_relays.end();++r) {
if (r->first == p->address()) {
isRelay = true;
bool upstream = false;
InetAddress stableEndpoint;
for(std::vector<World::Root>::const_iterator r(_world.roots().begin());r!=_world.roots().end();++r) {
if (r->identity.address() == p->address()) {
if (r->stableEndpoints.size() > 0)
stableEndpoint = r->stableEndpoints[(unsigned long)RR->node->prng() % r->stableEndpoints.size()];
upstream = true;
break;
}
}
if ((isRelay)||(std::find(_rootAddresses.begin(),_rootAddresses.end(),p->address()) != _rootAddresses.end())) {
p->doPingAndKeepalive(RR,_now);
if (p->lastReceive() > lastReceiveFromUpstream)
lastReceiveFromUpstream = p->lastReceive();
} else {
if (p->alive(_now))
p->doPingAndKeepalive(RR,_now);
if (!upstream) {
for(std::vector< std::pair<Address,InetAddress> >::const_iterator r(_relays.begin());r!=_relays.end();++r) {
if (r->first == p->address()) {
stableEndpoint = r->second;
upstream = true;
break;
}
}
}
if ((!p->doPingAndKeepalive(RR,_now))&&(stableEndpoint))
p->attemptToContactAt(RR,InetAddress(),stableEndpoint,_now);
if (upstream)
lastReceiveFromUpstream = std::max(p->lastReceive(),lastReceiveFromUpstream);
}
private:
const RuntimeEnvironment *RR;
uint64_t _now;
const std::vector< std::pair<Address,InetAddress> > &_relays;
std::vector<Address> _rootAddresses;
World _world;
};
ZT_ResultCode Node::processBackgroundTasks(uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline)
@ -376,7 +386,6 @@ ZT_PeerList *Node::peers() const
memcpy(&(p->paths[p->pathCount].address),&(path->address()),sizeof(struct sockaddr_storage));
p->paths[p->pathCount].lastSend = path->lastSend();
p->paths[p->pathCount].lastReceive = path->lastReceived();
p->paths[p->pathCount].fixed = path->fixed() ? 1 : 0;
p->paths[p->pathCount].active = path->active(_now) ? 1 : 0;
p->paths[p->pathCount].preferred = ((bestPath)&&(*path == *bestPath)) ? 1 : 0;
++p->pathCount;

View File

@ -566,8 +566,8 @@ public:
* <[2] software revision (of responder)>
* <[1] destination address type (for this OK, not copied from HELLO)>
* [<[...] destination address>]
* <[8] 64-bit world ID of current world (of responder)>
* <[8] 64-bit timestamp of current world (of responder)>
* <[2] 16-bit length of world update or 0 if none>
* [[...] world update]
*
* ERROR has no payload.
*/
@ -1098,36 +1098,7 @@ public:
*
* ERROR has no payload.
*/
VERB_REQUEST_PROOF_OF_WORK = 19,
/**
* Generic binary object access:
* <[8] 64-bit request ID>
* <[4] 32-bit index in blob to retrieve>
* <[2] 16-bit max length of block to retrieve>
* <[2] 16-bit length of blob identifier>
* <[...] blob identifier>
*
* This is used as a generic remote object retrieval mechanism. It returns
* OK if the object is accessible, INVALID_REQUEST if the index is beyond
* the size of the blob or another element is invalid, and OBJ_NOT_FOUND
* if no blob with the given identifier is available.
*
* Blob identifiers follow a de facto path-like schema, with the following
* names reserved:
* world - Current world definition (see World.hpp)
* updates.d/<any> - Software updates (not used yet, but reserved)
*
* OK payload:
* <[8] 64-bit request ID>
* <[4] 32-bit total length of blob>
* <[4] 32-bit index of this data in blob>
* <[...] data>
*
* ERROR payload:
* <[8] 64-bit request ID>
*/
VERB_GET_OBJECT = 20
VERB_REQUEST_PROOF_OF_WORK = 19
};
/**

View File

@ -108,17 +108,16 @@ void Peer::received(
// Add new path
slot = &(_paths[np++]);
} else {
// Replace oldest non-fixed path
uint64_t slotLRmin = 0xffffffffffffffffULL;
for(unsigned int p=0;p<ZT_MAX_PEER_NETWORK_PATHS;++p) {
if ((!_paths[p].fixed())&&(_paths[p].lastReceived() <= slotLRmin)) {
if (_paths[p].lastReceived() <= slotLRmin) {
slotLRmin = _paths[p].lastReceived();
slot = &(_paths[p]);
}
}
}
if (slot) {
*slot = RemotePath(localAddr,remoteAddr,false);
*slot = RemotePath(localAddr,remoteAddr);
slot->received(now);
_numPaths = np;
pathIsConfirmed = true;
@ -172,12 +171,15 @@ void Peer::attemptToContactAt(const RuntimeEnvironment *RR,const InetAddress &lo
outp.append(now);
RR->identity.serialize(outp,false);
atAddress.serialize(outp);
outp.append((uint64_t)RR->topology->worldId());
outp.append((uint64_t)RR->topology->worldTimestamp());
outp.armor(_key,false); // HELLO is sent in the clear
RR->antiRec->logOutgoingZT(outp.data(),outp.size());
RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size());
}
void Peer::doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now)
RemotePath *Peer::doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now)
{
Mutex::Lock _l(_lock);
RemotePath *const bestPath = _getBestPath(now);
@ -193,6 +195,7 @@ void Peer::doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now)
bestPath->sent(now);
}
}
return bestPath;
}
void Peer::pushDirectPaths(const RuntimeEnvironment *RR,RemotePath *path,uint64_t now,bool force)
@ -269,59 +272,6 @@ void Peer::pushDirectPaths(const RuntimeEnvironment *RR,RemotePath *path,uint64_
}
}
void Peer::addPath(const RemotePath &newp,uint64_t now)
{
Mutex::Lock _l(_lock);
unsigned int np = _numPaths;
for(unsigned int p=0;p<np;++p) {
if (_paths[p].address() == newp.address()) {
_paths[p].setFixed(newp.fixed());
_sortPaths(now);
return;
}
}
RemotePath *slot = (RemotePath *)0;
if (np < ZT_MAX_PEER_NETWORK_PATHS) {
// Add new path
slot = &(_paths[np++]);
} else {
// Replace oldest non-fixed path
uint64_t slotLRmin = 0xffffffffffffffffULL;
for(unsigned int p=0;p<ZT_MAX_PEER_NETWORK_PATHS;++p) {
if ((!_paths[p].fixed())&&(_paths[p].lastReceived() <= slotLRmin)) {
slotLRmin = _paths[p].lastReceived();
slot = &(_paths[p]);
}
}
}
if (slot) {
*slot = newp;
_numPaths = np;
}
_sortPaths(now);
}
void Peer::clearPaths(bool fixedToo)
{
if (fixedToo) {
_numPaths = 0;
} else {
unsigned int np = _numPaths;
unsigned int x = 0;
unsigned int y = 0;
while (x < np) {
if (_paths[x].fixed())
_paths[y++] = _paths[x];
++x;
}
_numPaths = y;
}
}
bool Peer::resetWithinScope(const RuntimeEnvironment *RR,InetAddress::IpScope scope,uint64_t now)
{
Mutex::Lock _l(_lock);
@ -330,12 +280,9 @@ bool Peer::resetWithinScope(const RuntimeEnvironment *RR,InetAddress::IpScope sc
unsigned int y = 0;
while (x < np) {
if (_paths[x].address().ipScope() == scope) {
if (_paths[x].fixed()) {
attemptToContactAt(RR,_paths[x].localAddress(),_paths[x].address(),now);
_paths[y++] = _paths[x]; // keep fixed paths
}
attemptToContactAt(RR,_paths[x].localAddress(),_paths[x].address(),now);
} else {
_paths[y++] = _paths[x]; // keep paths not in this scope
_paths[y++] = _paths[x];
}
++x;
}

View File

@ -133,7 +133,7 @@ public:
* Get the best direct path to this peer
*
* @param now Current time
* @return Best path or NULL if there are no active (or fixed) direct paths
* @return Best path or NULL if there are no active direct paths
*/
inline RemotePath *getBestPath(uint64_t now)
{
@ -178,8 +178,9 @@ public:
*
* @param RR Runtime environment
* @param now Current time
* @return Current best path or NULL if no active paths
*/
void doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now);
RemotePath *doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now);
/**
* Push direct paths if we haven't done so in [rate limit] milliseconds
@ -290,7 +291,7 @@ public:
/**
* @param now Current time
* @return True if this peer has at least one active or fixed direct path
* @return True if this peer has at least one active direct path
*/
inline bool hasActiveDirectPath(uint64_t now) const
throw()
@ -303,27 +304,9 @@ public:
return false;
}
/**
* Add a path (if we don't already have it)
*
* @param p New path to add
* @param now Current time
*/
void addPath(const RemotePath &newp,uint64_t now);
/**
* Clear paths
*
* @param fixedToo If true, clear fixed paths as well as learned ones
*/
void clearPaths(bool fixedToo);
/**
* Reset paths within a given scope
*
* For fixed paths in this scope, a packet is sent. Non-fixed paths in this
* scope are forgotten.
*
* @param RR Runtime environment
* @param scope IP scope of paths to reset
* @param now Current time

View File

@ -39,8 +39,6 @@
#include "AntiRecursion.hpp"
#include "RuntimeEnvironment.hpp"
#define ZT_REMOTEPATH_FLAG_FIXED 0x0001
namespace ZeroTier {
/**
@ -58,34 +56,18 @@ public:
_localAddress(),
_flags(0) {}
RemotePath(const InetAddress &localAddress,const InetAddress &addr,bool fixed) :
RemotePath(const InetAddress &localAddress,const InetAddress &addr) :
Path(addr,0,TRUST_NORMAL),
_lastSend(0),
_lastReceived(0),
_localAddress(localAddress),
_flags(fixed ? ZT_REMOTEPATH_FLAG_FIXED : 0) {}
_flags(0) {}
inline const InetAddress &localAddress() const throw() { return _localAddress; }
inline uint64_t lastSend() const throw() { return _lastSend; }
inline uint64_t lastReceived() const throw() { return _lastReceived; }
/**
* @return Is this a fixed path?
*/
inline bool fixed() const throw() { return ((_flags & ZT_REMOTEPATH_FLAG_FIXED) != 0); }
/**
* @param f New value of fixed flag
*/
inline void setFixed(const bool f)
throw()
{
if (f)
_flags |= ZT_REMOTEPATH_FLAG_FIXED;
else _flags &= ~ZT_REMOTEPATH_FLAG_FIXED;
}
/**
* Called when a packet is sent to this remote path
*
@ -112,12 +94,12 @@ public:
/**
* @param now Current time
* @return True if this path is fixed or has received data in last ACTIVITY_TIMEOUT ms
* @return True if this path appears active
*/
inline bool active(uint64_t now) const
throw()
{
return ( ((_flags & ZT_REMOTEPATH_FLAG_FIXED) != 0) || ((now - _lastReceived) < ZT_PEER_ACTIVITY_TIMEOUT) );
return ((now - _lastReceived) < ZT_PEER_ACTIVITY_TIMEOUT);
}
/**

View File

@ -35,8 +35,8 @@
namespace ZeroTier {
// Default World
#define ZT_DEFAULT_WORLD_LENGTH 1
static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = { 0 };
#define ZT_DEFAULT_WORLD_LENGTH 494
static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = {0x01,0x00,0x00,0x00,0x00,0x08,0xea,0xc9,0x0a,0x00,0x00,0x01,0x4f,0xdf,0xbf,0xfc,0xbb,0x6c,0x7e,0x15,0x67,0x85,0x1b,0xb4,0x65,0x04,0x01,0xaf,0x56,0xbf,0xe7,0x63,0x9d,0x77,0xef,0xa4,0x1e,0x61,0x53,0x88,0xcb,0x8d,0x78,0xe5,0x47,0x38,0x98,0x5a,0x6c,0x8a,0xdd,0xe6,0x9c,0x65,0xdf,0x1a,0x80,0x63,0xce,0x2e,0x4d,0x48,0x24,0x3d,0x68,0x87,0x96,0x13,0x89,0xba,0x25,0x6f,0xc9,0xb0,0x9f,0x20,0xc5,0x4c,0x51,0x7b,0x30,0xb7,0x5f,0xba,0xca,0xa4,0xc5,0x48,0xa3,0x15,0xab,0x2f,0x1d,0x64,0xe8,0x04,0x42,0xb3,0x1c,0x51,0x8b,0x2a,0x04,0x01,0xf8,0xe1,0x81,0xaf,0x60,0x2f,0x70,0x3e,0xcd,0x0b,0x21,0x38,0x19,0x62,0x02,0xbd,0x0e,0x33,0x1d,0x0a,0x7b,0xf1,0xec,0xad,0xef,0x54,0xb3,0x7b,0x17,0x84,0xaa,0xda,0x0a,0x85,0x5d,0x0b,0x1c,0x05,0x83,0xb9,0x0e,0x3e,0xe3,0xb4,0xd1,0x8b,0x5b,0x64,0xf7,0xcf,0xe1,0xff,0x5d,0xc2,0x2a,0xcf,0x60,0x7b,0x09,0xb4,0xa3,0x86,0x3c,0x5a,0x7e,0x31,0xa0,0xc7,0xb4,0x86,0xe3,0x41,0x33,0x04,0x7e,0x19,0x87,0x6a,0xba,0x00,0x2a,0x6e,0x2b,0x23,0x18,0x93,0x0f,0x60,0xeb,0x09,0x7f,0x70,0xd0,0xf4,0xb0,0x28,0xb2,0xcd,0x6d,0x3d,0x0c,0x63,0xc0,0x14,0xb9,0x03,0x9f,0xf3,0x53,0x90,0xe4,0x11,0x81,0xf2,0x16,0xfb,0x2e,0x6f,0xa8,0xd9,0x5c,0x1e,0xe9,0x66,0x71,0x56,0x41,0x19,0x05,0xc3,0xdc,0xcf,0xea,0x78,0xd8,0xc6,0xdf,0xaf,0xba,0x68,0x81,0x70,0xb3,0xfa,0x00,0x01,0x04,0xc6,0xc7,0x61,0xdc,0x27,0x09,0x88,0x41,0x40,0x8a,0x2e,0x00,0xbb,0x1d,0x31,0xf2,0xc3,0x23,0xe2,0x64,0xe9,0xe6,0x41,0x72,0xc1,0xa7,0x4f,0x77,0x89,0x95,0x55,0xed,0x10,0x75,0x1c,0xd5,0x6e,0x86,0x40,0x5c,0xde,0x11,0x8d,0x02,0xdf,0xfe,0x55,0x5d,0x46,0x2c,0xcf,0x6a,0x85,0xb5,0x63,0x1c,0x12,0x35,0x0c,0x8d,0x5d,0xc4,0x09,0xba,0x10,0xb9,0x02,0x5d,0x0f,0x44,0x5c,0xf4,0x49,0xd9,0x2b,0x1c,0x00,0x01,0x04,0x6b,0xbf,0x2e,0xd2,0x27,0x09,0x8a,0xcf,0x05,0x9f,0xe3,0x00,0x48,0x2f,0x6e,0xe5,0xdf,0xe9,0x02,0x31,0x9b,0x41,0x9d,0xe5,0xbd,0xc7,0x65,0x20,0x9c,0x0e,0xcd,0xa3,0x8c,0x4d,0x6e,0x4f,0xcf,0x0d,0x33,0x65,0x83,0x98,0xb4,0x52,0x7d,0xcd,0x22,0xf9,0x31,0x12,0xfb,0x9b,0xef,0xd0,0x2f,0xd7,0x8b,0xf7,0x26,0x1b,0x33,0x3f,0xc1,0x05,0xd1,0x92,0xa6,0x23,0xca,0x9e,0x50,0xfc,0x60,0xb3,0x74,0xa5,0x00,0x01,0x04,0xa2,0xf3,0x4d,0x6f,0x27,0x09,0x9d,0x21,0x90,0x39,0xf3,0x00,0x01,0xf0,0x92,0x2a,0x98,0xe3,0xb3,0x4e,0xbc,0xbf,0xf3,0x33,0x26,0x9d,0xc2,0x65,0xd7,0xa0,0x20,0xaa,0xb6,0x9d,0x72,0xbe,0x4d,0x4a,0xcc,0x9c,0x8c,0x92,0x94,0x78,0x57,0x71,0x25,0x6c,0xd1,0xd9,0x42,0xa9,0x0d,0x1b,0xd1,0xd2,0xdc,0xa3,0xea,0x84,0xef,0x7d,0x85,0xaf,0xe6,0x61,0x1f,0xb4,0x3f,0xf0,0xb7,0x41,0x26,0xd9,0x0a,0x6e,0x00,0x01,0x04,0x80,0xc7,0xc5,0xd9,0x27,0x09};
Topology::Topology(const RuntimeEnvironment *renv) :
RR(renv),
@ -276,6 +276,13 @@ bool Topology::worldUpdateIfValid(const World &newWorld)
Mutex::Lock _l(_lock);
if (_world.shouldBeReplacedBy(newWorld,true)) {
_setWorld(newWorld);
try {
Buffer<ZT_WORLD_MAX_SERIALIZED_LENGTH> dswtmp;
newWorld.serialize(dswtmp,false);
RR->node->dataStorePut("world",dswtmp.data(),dswtmp.size(),false);
} catch ( ... ) {
RR->node->dataStoreDelete("world");
}
return true;
}
return false;

View File

@ -147,12 +147,19 @@ public:
}
/**
* @return Pair containing world ID and world timestamp (faster than world().id() etc.)
* @return Current world ID
*/
inline std::pair<uint64_t,uint64_t> worldIdentification() const
inline uint64_t worldId() const
{
Mutex::Lock _l(_lock);
return std::pair<uint64_t,uint64_t>(_world.id(),_world.timestamp());
return _world.id(); // safe to read without lock, and used from within eachPeer() so don't lock
}
/**
* @return Current world timestamp
*/
inline uint64_t worldTimestamp() const
{
return _world.timestamp(); // safe to read without lock, and used from within eachPeer() so don't lock
}
/**

View File

@ -182,14 +182,12 @@ static std::string _jsonEnumerate(unsigned int depth,const ZT_PeerPhysicalPath *
"%s\t\"address\": \"%s\",\n"
"%s\t\"lastSend\": %llu,\n"
"%s\t\"lastReceive\": %llu,\n"
"%s\t\"fixed\": %s,\n"
"%s\t\"active\": %s,\n"
"%s\t\"preferred\": %s\n"
"%s}",
prefix,_jsonEscape(reinterpret_cast<const InetAddress *>(&(pp[i].address))->toString()).c_str(),
prefix,pp[i].lastSend,
prefix,pp[i].lastReceive,
prefix,(pp[i].fixed == 0) ? "false" : "true",
prefix,(pp[i].active == 0) ? "false" : "true",
prefix,(pp[i].preferred == 0) ? "false" : "true",
prefix);

BIN
world/2015-10-13.bin Normal file

Binary file not shown.

6
world/2015-10-13.out Normal file
View File

@ -0,0 +1,6 @@
INFO: created initial world keys: previous.c25519, current.c25519
INFO: generating and signing id==149604618 ts==1442567945403
INFO: wrote 494 bytes to stdout
#define ZT_DEFAULT_WORLD_LENGTH 494
static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = {0x01,0x00,0x00,0x00,0x00,0x08,0xea,0xc9,0x0a,0x00,0x00,0x01,0x4f,0xdf,0xbf,0xfc,0xbb,0x6c,0x7e,0x15,0x67,0x85,0x1b,0xb4,0x65,0x04,0x01,0xaf,0x56,0xbf,0xe7,0x63,0x9d,0x77,0xef,0xa4,0x1e,0x61,0x53,0x88,0xcb,0x8d,0x78,0xe5,0x47,0x38,0x98,0x5a,0x6c,0x8a,0xdd,0xe6,0x9c,0x65,0xdf,0x1a,0x80,0x63,0xce,0x2e,0x4d,0x48,0x24,0x3d,0x68,0x87,0x96,0x13,0x89,0xba,0x25,0x6f,0xc9,0xb0,0x9f,0x20,0xc5,0x4c,0x51,0x7b,0x30,0xb7,0x5f,0xba,0xca,0xa4,0xc5,0x48,0xa3,0x15,0xab,0x2f,0x1d,0x64,0xe8,0x04,0x42,0xb3,0x1c,0x51,0x8b,0x2a,0x04,0x01,0xf8,0xe1,0x81,0xaf,0x60,0x2f,0x70,0x3e,0xcd,0x0b,0x21,0x38,0x19,0x62,0x02,0xbd,0x0e,0x33,0x1d,0x0a,0x7b,0xf1,0xec,0xad,0xef,0x54,0xb3,0x7b,0x17,0x84,0xaa,0xda,0x0a,0x85,0x5d,0x0b,0x1c,0x05,0x83,0xb9,0x0e,0x3e,0xe3,0xb4,0xd1,0x8b,0x5b,0x64,0xf7,0xcf,0xe1,0xff,0x5d,0xc2,0x2a,0xcf,0x60,0x7b,0x09,0xb4,0xa3,0x86,0x3c,0x5a,0x7e,0x31,0xa0,0xc7,0xb4,0x86,0xe3,0x41,0x33,0x04,0x7e,0x19,0x87,0x6a,0xba,0x00,0x2a,0x6e,0x2b,0x23,0x18,0x93,0x0f,0x60,0xeb,0x09,0x7f,0x70,0xd0,0xf4,0xb0,0x28,0xb2,0xcd,0x6d,0x3d,0x0c,0x63,0xc0,0x14,0xb9,0x03,0x9f,0xf3,0x53,0x90,0xe4,0x11,0x81,0xf2,0x16,0xfb,0x2e,0x6f,0xa8,0xd9,0x5c,0x1e,0xe9,0x66,0x71,0x56,0x41,0x19,0x05,0xc3,0xdc,0xcf,0xea,0x78,0xd8,0xc6,0xdf,0xaf,0xba,0x68,0x81,0x70,0xb3,0xfa,0x00,0x01,0x04,0xc6,0xc7,0x61,0xdc,0x27,0x09,0x88,0x41,0x40,0x8a,0x2e,0x00,0xbb,0x1d,0x31,0xf2,0xc3,0x23,0xe2,0x64,0xe9,0xe6,0x41,0x72,0xc1,0xa7,0x4f,0x77,0x89,0x95,0x55,0xed,0x10,0x75,0x1c,0xd5,0x6e,0x86,0x40,0x5c,0xde,0x11,0x8d,0x02,0xdf,0xfe,0x55,0x5d,0x46,0x2c,0xcf,0x6a,0x85,0xb5,0x63,0x1c,0x12,0x35,0x0c,0x8d,0x5d,0xc4,0x09,0xba,0x10,0xb9,0x02,0x5d,0x0f,0x44,0x5c,0xf4,0x49,0xd9,0x2b,0x1c,0x00,0x01,0x04,0x6b,0xbf,0x2e,0xd2,0x27,0x09,0x8a,0xcf,0x05,0x9f,0xe3,0x00,0x48,0x2f,0x6e,0xe5,0xdf,0xe9,0x02,0x31,0x9b,0x41,0x9d,0xe5,0xbd,0xc7,0x65,0x20,0x9c,0x0e,0xcd,0xa3,0x8c,0x4d,0x6e,0x4f,0xcf,0x0d,0x33,0x65,0x83,0x98,0xb4,0x52,0x7d,0xcd,0x22,0xf9,0x31,0x12,0xfb,0x9b,0xef,0xd0,0x2f,0xd7,0x8b,0xf7,0x26,0x1b,0x33,0x3f,0xc1,0x05,0xd1,0x92,0xa6,0x23,0xca,0x9e,0x50,0xfc,0x60,0xb3,0x74,0xa5,0x00,0x01,0x04,0xa2,0xf3,0x4d,0x6f,0x27,0x09,0x9d,0x21,0x90,0x39,0xf3,0x00,0x01,0xf0,0x92,0x2a,0x98,0xe3,0xb3,0x4e,0xbc,0xbf,0xf3,0x33,0x26,0x9d,0xc2,0x65,0xd7,0xa0,0x20,0xaa,0xb6,0x9d,0x72,0xbe,0x4d,0x4a,0xcc,0x9c,0x8c,0x92,0x94,0x78,0x57,0x71,0x25,0x6c,0xd1,0xd9,0x42,0xa9,0x0d,0x1b,0xd1,0xd2,0xdc,0xa3,0xea,0x84,0xef,0x7d,0x85,0xaf,0xe6,0x61,0x1f,0xb4,0x3f,0xf0,0xb7,0x41,0x26,0xd9,0x0a,0x6e,0x00,0x01,0x04,0x80,0xc7,0xc5,0xd9,0x27,0x09};