コード例 #1
0
        void Save(bool onlyupdated)
        {
            var created = 0;
            var updated = 0;
            var deleted = 0;

            var sw = new Stopwatch();

            sw.Start();

            var inactive = Statistics.GetInactive();

            RemoveRouterInfo(inactive);

            using (var s = GetStore())
            {
                lock ( RouterInfos )
                {
                    foreach (var one in RouterInfos.ToArray())
                    {
                        try
                        {
                            if (one.Value.Value.Deleted)
                            {
                                if (one.Value.Value.StoreIx > 0)
                                {
                                    s.Delete(one.Value.Value.StoreIx);
                                }
                                RouterInfos.Remove(one.Key);
                                ++deleted;
                                continue;
                            }

                            if (!onlyupdated || (onlyupdated && one.Value.Value.Updated))
                            {
                                var rec = new BufLen[] { (BufLen)(int)StoreRecordId.StoreIdRouterInfo, new BufLen(one.Value.Key.ToByteArray()) };
                                if (one.Value.Value.StoreIx > 0)
                                {
                                    s.Write(rec, one.Value.Value.StoreIx);
                                    ++updated;
                                }
                                else
                                {
                                    one.Value.Value.StoreIx = s.Write(rec);
                                    ++created;
                                }
                                one.Value.Value.Updated = false;
                            }
                        }
                        catch (Exception ex)
                        {
                            Logging.LogDebug("NetDb: Save: Store exception: " + ex.ToString());
                            one.Value.Value.StoreIx = -1;
                        }
                    }
                }

                var lookup = s.GetMatching(e => (StoreRecordId)e[0] == StoreRecordId.StoreIdConfig, 1);
                Dictionary <I2PString, int> str2ix = new Dictionary <I2PString, int>();
                foreach (var one in lookup)
                {
                    var reader = new BufRefLen(one.Value);
                    reader.Read32();
                    var key = new I2PString(reader);
                    str2ix[key] = one.Key;
                }

                AccessConfig(delegate(Dictionary <I2PString, I2PString> settings)
                {
                    foreach (var one in settings)
                    {
                        var rec = new BufLen[] { (BufLen)(int)StoreRecordId.StoreIdConfig,
                                                 new BufLen(one.Key.ToByteArray()), new BufLen(one.Value.ToByteArray()) };

                        if (str2ix.ContainsKey(one.Key))
                        {
                            s.Write(rec, str2ix[one.Key]);
                        }
                        else
                        {
                            s.Write(rec);
                        }
                    }
                });
            }

            Logging.Log($"NetDb.Save( {( onlyupdated ? "updated" : "all" )} ): " +
                        $"{created} created, {updated} updated, {deleted} deleted.");

            Statistics.RemoveOldStatistics();
            UpdateSelectionProbabilities();

            sw.Stop();
            Logging.Log($"NetDB: Save: {sw.Elapsed}");
        }
コード例 #2
0
 public I2PKeyType(BufRef buf, I2PCertificate cert)
 {
     Certificate = cert;
     Key         = buf.ReadBufLen(KeySizeBytes);
 }
コード例 #3
0
 public I2PCertificate(BufRef buf)
 {
     Data = new BufLen(buf, 0, 3);
     Data = buf.ReadBufLen(CertLength);
 }
コード例 #4
0
 public I2PSignature()
 {
     Certificate = I2PSigningKey.DefaultSigningKeyCert;
     Sig         = new BufLen(new byte[Certificate.SignatureLength]);
 }
コード例 #5
0
ファイル: SSUState.cs プロジェクト: glasgowdev/i2p-cs
        /**
         * From PacketBuilder.java
         * -----8<-----
         * @param packet prepared packet with the first 32 bytes empty and a length
         *               whose size is mod 16.
         *               As of 0.9.7, length non-mod-16 is allowed; the
         *               last 1-15 bytes are included in the MAC calculation but are not encrypted.
         * -----8<-----
         */

        protected void SendMessage(
            IPEndPoint dest,
            SSUHeader.MessageTypes message,
            BufLen mackey,
            BufLen cryptokey,
            SendMessageGenerator gen,
            SendMessageGenerator genextrapadding)
        {
            var start = Session.Host.SendBuffers.Pop();

            var writer = new BufRefLen(start);
            var header = new SSUHeader(writer, message);

            if (!gen(start, writer))
            {
                return;
            }

            // Do not cut to datalen & ~0xf as that might make data at the end unencrypted
            var datapadding = BufUtils.Get16BytePadding(writer - start);

            writer.Write(BufUtils.Random(datapadding));
            var datalen = writer - start;

            var encryptedbuf = new BufLen(start, 32, datalen - 32);

            // TODO: Adding extra padding does not seem to work
            if (genextrapadding != null)
            {
                if (!genextrapadding(start, writer))
                {
                    return;
                }
            }

            var packetlen = writer - start;
            var data      = new BufLen(start, 0, packetlen);
            var hmac      = new BufLen(data, 32);

            SendMessageCipher.Init(true, cryptokey.ToParametersWithIV(header.IV));
            SendMessageCipher.ProcessBytes(encryptedbuf);

            I2PHMACMD5Digest.Generate(new BufLen[] {
                hmac,
                header.IV,
                BufUtils.Flip16BL((ushort)((ushort)hmac.Length ^ I2PConstants.SSU_PROTOCOL_VERSION))
            }, mackey, header.MAC);

#if LOG_ALL_TRANSPORT
            DebugUtils.Log(string.Format("SSUState SendMessage {0}: encrlen {1} bytes [0x{1:X}] (padding {2} bytes [0x{2:X}]), " +
                                         "hmac {3} bytes [0x{3:X}], sendlen {4} bytes [0x{4:X}]",
                                         Session.DebugId,
                                         encryptedbuf.Length,
                                         datapadding,
                                         hmac.Length,
                                         data.Length));
#endif

            DataSent();
            Session.Host.Send(dest, data);
        }
コード例 #6
0
 public AesEGBuildRequestRecord(EGBuildRequestRecord src, BufferedBlockCipher cipher)
 {
     Data = new BufLen(cipher.ProcessBytes(src.Data.BaseArray, src.Data.BaseArrayOffset, src.Data.Length));
 }
コード例 #7
0
 public BuildResponseRecord(EGBuildRequestRecord request)
 {
     // Replace it
     Data = request.Data;
     Data.Randomize();
 }
コード例 #8
0
 public I2PSessionKey(BufRef buf)
 {
     Key = buf.ReadBufLen(32);
 }
コード例 #9
0
 public I2PSessionKey(BufLen buf)
 {
     Key = buf;
 }
コード例 #10
0
 public I2PSessionKey(byte[] buf)
 {
     Key = new BufLen(buf, 0, 32);
 }
コード例 #11
0
 public I2PSessionKey(I2PSessionKey src)
 {
     Key = new BufLen(src.Key);
 }
コード例 #12
0
 public I2PSessionKey()
 {
     Key = new BufLen(BufUtils.Random(32));
 }
コード例 #13
0
ファイル: BuildRequestRecord.cs プロジェクト: itfenom/i2p-cs
 public BuildRequestRecord(BufRef buf)
 {
     Data        = buf.ReadBufLen(Length);
     ReducedHash = CreateReducedHash();
 }
コード例 #14
0
ファイル: BuildRequestRecord.cs プロジェクト: itfenom/i2p-cs
 public BuildRequestRecord()
 {
     Data        = new BufLen(new byte[Length]);
     ReducedHash = CreateReducedHash();
 }
コード例 #15
0
 public AesEGBuildRequestRecord(BufRef buf)
 {
     Data = buf.ReadBufLen(Length);
 }
コード例 #16
0
 public I2PPrivateKey(I2PCertificate cert) : base(cert)
 {
     Key     = new BufLen(BufUtils.RandomBytes(KeySizeBytes));
     Key[0] |= 0x80;
     Key[Key.Length - 1] |= 0x01;
 }
コード例 #17
0
 public AesEGBuildRequestRecord(BufLen dest, EGBuildRequestRecord src, BufferedBlockCipher cipher)
 {
     Data = dest;
     cipher.ProcessBytes(src.Data.BaseArray, src.Data.BaseArrayOffset, src.Data.Length, Data.BaseArray, Data.BaseArrayOffset);
 }
コード例 #18
0
        public override SSUState HandleMessage(SSUHeader header, BufRefLen reader)
        {
            var tstime = SSUHost.SSUDateTime(header.TimeStamp);

            if (header.MessageType != SSUHeader.MessageTypes.SessionCreated)
            {
#if LOG_ALL_TRANSPORT
                DebugUtils.Log("SSU SessionRequestState: Received unexpected message " + tstime.ToString() + " : " + header.Flag.ToString());
#endif
                return(this);
            }

            SCMessage = new SessionCreated(reader, Session.RemoteRouter.Certificate);

            Session.RelayTag = SCMessage.RelayTag;

            Y = new I2PPublicKey((BufRefLen)SCMessage.Y, Session.RemoteRouter.Certificate);
            BufUtils.DHI2PToSessionAndMAC(out Session.SharedKey, out Session.MACKey,
                                          Y.ToBigInteger().ModPow(PrivateKey.ToBigInteger(), I2PConstants.ElGamalP));

            var    ipaddr = new IPAddress(SCMessage.Address.ToByteArray());
            ushort port   = SCMessage.Port.PeekFlip16(0);
            Session.SignOnTimeB = SCMessage.SignOnTime.Peek32(0);
            var btime = SSUHost.SSUDateTime(BufUtils.Flip32(Session.SignOnTimeB));

#if LOG_ALL_TRANSPORT
            DebugUtils.Log("SSU SessionRequestState " + Session.DebugId + " : Received SessionCreated. " + tstime.ToString() + " : " + btime.ToString());
#endif
            Session.Host.ReportedAddress(ipaddr);

            if (!I2PSignature.SupportedSignatureType(Session.RemoteRouter.Certificate.SignatureType))
            {
                throw new SignatureCheckFailureException("SSU SessionRequestState " + Session.DebugId + " : " +
                                                         "Received non supported signature type: " +
                                                         Session.RemoteRouter.Certificate.SignatureType.ToString());
            }

            var cipher = new CbcBlockCipher(new AesEngine());
            cipher.Init(false, Session.SharedKey.ToParametersWithIV(header.IV));
            cipher.ProcessBytes(SCMessage.SignatureEncrBuf);

            var baddr = new BufLen(Session.RemoteEP.Address.GetAddressBytes());
            var sign  = new I2PSignature((BufRefLen)SCMessage.Signature, Session.RemoteRouter.Certificate);

            var sok = I2PSignature.DoVerify(
                Session.RemoteRouter.SigningPublicKey, sign,
                X.Key, Y.Key,
                SCMessage.Address, SCMessage.Port,
                baddr, BufUtils.Flip16BL((ushort)Session.RemoteEP.Port),
                SCMessage.RelayTag, SCMessage.SignOnTime);

#if LOG_ALL_TRANSPORT
            DebugUtils.Log("SSU SessionRequestState: Signature check: " + sok.ToString() + ". " + Session.RemoteRouter.Certificate.SignatureType.ToString());
#endif
            if (!sok)
            {
                throw new SignatureCheckFailureException("SSU SessionRequestState " + Session.DebugId + ": Received SessionCreated signature check failed." +
                                                         Session.RemoteRouter.Certificate.ToString());
            }

            var relaytag = SCMessage.RelayTag.PeekFlip32(0);
            if (relaytag != 0)
            {
                Session.Host.IntroductionRelayOffered(
                    new IntroducerInfo(
                        Session.RemoteEP.Address,
                        (ushort)Session.RemoteEP.Port,
                        Session.IntroKey, relaytag));
            }

            DebugUtils.Log("SSU SessionRequestState: Session " + Session.DebugId + " created. Moving to SessionConfirmedState.");
            Session.ReportConnectionEstablished();
            return(new SessionConfirmedState(Session, this));
        }
コード例 #19
0
 public BuildResponseRecord(BufRef buf)
 {
     Data = buf.ReadBufLen(Length);
 }
コード例 #20
0
ファイル: Program.cs プロジェクト: itfenom/i2p-cs
 static void MyOrigin_DataReceived(ClientDestination dest, BufLen data)
 {
     Logging.LogInformation($"Program {MyOrigin}: data received. {data:15}");
 }
コード例 #21
0
 public BuildResponseRecord(AesEGBuildRequestRecord request)
 {
     // Reuse it
     Data = request.Data;
 }
コード例 #22
0
ファイル: Program.cs プロジェクト: itfenom/i2p-cs
        static void Main(string[] args)
        {
            PeriodicAction SendInterval = new PeriodicAction(TickSpan.Seconds(20));

            Logging.ReadAppConfig();
            Logging.LogToDebug   = false;
            Logging.LogToConsole = true;

            RouterContext.RouterSettingsFile = "I2PDemo.bin";

            MyDestinationInfo = new I2PDestinationInfo(I2PSigningKey.SigningKeyTypes.EdDSA_SHA512_Ed25519);

            for (int i = 0; i < args.Length; ++i)
            {
                switch (args[i])
                {
                case "--addr":
                case "--address":
                    if (args.Length > i + 1)
                    {
                        RouterContext.Inst.DefaultExtAddress = IPAddress.Parse(args[++i]);
                        Console.WriteLine($"addr {RouterContext.Inst.DefaultExtAddress}");
                    }
                    else
                    {
                        Console.WriteLine("--addr require ip number");
                        return;
                    }
                    break;

                case "--port":
                    if (args.Length > i + 1)
                    {
                        var port = int.Parse(args[++i]);
                        RouterContext.Inst.DefaultTCPPort = port;
                        RouterContext.Inst.DefaultUDPPort = port;
                        Console.WriteLine($"port {port}");
                    }
                    else
                    {
                        Console.WriteLine("--port require port number");
                        return;
                    }
                    break;

                case "--nofw":
                    RouterContext.Inst.IsFirewalled = false;
                    Console.WriteLine($"Firewalled {RouterContext.Inst.IsFirewalled}");
                    break;

                case "--mkdest":
                case "--create-destination":
                    var certtype = 0;
                    if (args.Length > i + 1)
                    {
                        certtype = int.Parse(args[++i]);
                    }

                    I2PSigningKey.SigningKeyTypes ct;
                    I2PDestinationInfo            d;

                    switch (certtype)
                    {
                    default:
                    case 0:
                        ct = I2PSigningKey.SigningKeyTypes.EdDSA_SHA512_Ed25519;
                        d  = new I2PDestinationInfo(ct);
                        break;

                    case 1:
                        ct = I2PSigningKey.SigningKeyTypes.DSA_SHA1;
                        d  = new I2PDestinationInfo(ct);
                        break;

                    case 2:
                        ct = I2PSigningKey.SigningKeyTypes.ECDSA_SHA256_P256;
                        d  = new I2PDestinationInfo(ct);
                        break;

                    case 3:
                        ct = I2PSigningKey.SigningKeyTypes.ECDSA_SHA384_P384;
                        d  = new I2PDestinationInfo(ct);
                        break;
                    }

                    Console.WriteLine($"New destination {ct}: {d.ToBase64()}");
                    return;

                case "--destination":
                    if (args.Length > i + 1)
                    {
                        MyDestinationInfo = new I2PDestinationInfo(args[++i]);
                        Console.WriteLine($"Destination {MyDestinationInfo}");
                    }
                    else
                    {
                        Console.WriteLine("Base64 encoded Destination required");
                        return;
                    }
                    break;

                default:
                    Console.WriteLine(args[i]);
                    Console.WriteLine("Usage: I2P.exe --addr 12.34.56.78 --port 8081 --nofw --create-destination [0-3] --destination b64...");
                    break;
                }
            }

            RouterContext.Inst.ApplyNewSettings();

            var pnp = new UPnp();

            Thread.Sleep(5000);   // Give UPnp a chance

            Router.Start();

            // Create new identities for this run

            MyDestination = MyDestinationInfo.Destination;

#if MANUAL_SIGN
            PublishedDestination = Router.CreateDestination(
                MyDestination,
                MyDestinationInfo.PrivateKey,
                true,
                out _);      // Publish our destinaiton
            PublishedDestination.SignLeasesRequest += MyDestination_SignLeasesRequest;
#else
            PublishedDestination = Router.CreateDestination(MyDestinationInfo, true, out _);   // Publish our destinaiton
#endif
            PublishedDestination.DataReceived += MyDestination_DataReceived;
            PublishedDestination.Name          = "PublishedDestination";

            MyOriginInfo = new I2PDestinationInfo(I2PSigningKey.SigningKeyTypes.DSA_SHA1);
            MyOrigin     = Router.CreateDestination(MyOriginInfo, false, out _);
            MyOrigin.ClientStateChanged += MyOrigin_ClientStateChanged;
            MyOrigin.DataReceived       += MyOrigin_DataReceived;
            MyOrigin.Name = "MyOrigin";

            Logging.LogInformation($"MyDestination: {PublishedDestination.Destination.IdentHash} {MyDestinationInfo.Destination.Certificate}");

            while (true)
            {
                try
                {
                    Connected = true;

                    MyOrigin.LookupDestination(PublishedDestination.Destination.IdentHash, LookupResult);

                    var sendevents = 0;

                    while (Connected)
                    {
                        Thread.Sleep(2000);

                        if (LookedUpDestination != null &&
                            MyOrigin.ClientState == ClientDestination.ClientStates.Established)
                        {
                            SendInterval.Do(() =>
                            {
                                if (sendevents++ < 10)
                                {
                                    // Send some data to the MyDestination
                                    DataSent = new BufLen(
                                        BufUtils.RandomBytes(
                                            (int)(1 + BufUtils.RandomDouble(25) * 1024)));

                                    var ok = MyOrigin.Send(LookedUpDestination, DataSent);
                                    Logging.LogInformation($"Program {MyOrigin}: Send[{sendevents}] {ok}, {DataSent:15}");
                                }

                                if (sendevents > 100)
                                {
                                    sendevents = 0;
                                }
                            });
                        }
                    }
                }
                catch (SocketException ex)
                {
                    Logging.Log(ex);
                }
                catch (IOException ex)
                {
                    Logging.Log(ex);
                }
                catch (Exception ex)
                {
                    Logging.Log(ex);
                }
            }
        }
コード例 #23
0
        public I2PSignature(BufRef buf, I2PCertificate cert)
        {
            Certificate = cert;

            Sig = buf.ReadBufLen(cert.SignatureLength);
        }
コード例 #24
0
 public EGGarlic(BufRef reader)
 {
     Data = reader.ReadBufLen((int)reader.PeekFlip32(0) + 4);
 }
コード例 #25
0
ファイル: SSUState.cs プロジェクト: glasgowdev/i2p-cs
 bool RandomExtraPadding(BufLen start, BufRefLen writer)
 {
     writer.Write(BufUtils.Random(BufUtils.RandomInt(16)));
     return(true);
 }
コード例 #26
0
 public DataMessage(BufLen data)
 {
     AllocateBuffer(4 + data.Length);
     Payload.PokeFlip32((uint)data.Length, 0);
     Payload.Poke(data, 4);
 }
コード例 #27
0
        public override SSUState HandleMessage(SSUHeader header, BufRefLen reader)
        {
            switch (header.MessageType)
            {
            case SSUHeader.MessageTypes.Data:
                try
                {
                    var datamsg = new SSUDataMessage(reader, Session.Defragmenter);
                    if (datamsg.ExplicitAcks != null)
                    {
                        Session.Fragmenter.GotAck(datamsg.ExplicitAcks);
                    }
                    if (datamsg.AckBitfields != null)
                    {
                        Session.Fragmenter.GotAck(datamsg.AckBitfields);
                    }
                    if (datamsg.NewMessages != null)
                    {
                        foreach (var msg in datamsg.NewMessages)
                        {
                            var i2npmsg = I2NPMessage.ReadHeader16((BufRefLen)msg.GetPayload());

#if LOG_MUCH_TRANSPORT
                            Logging.LogDebugData($"SSU {this} complete message " +
                                                 $"{msg.MessageId}: {i2npmsg.Expiration}");
#endif

                            if (i2npmsg.MessageType == I2NPMessage.MessageTypes.DeliveryStatus)
                            {
                                if (((DeliveryStatusMessage)i2npmsg.Message).IsNetworkId((ulong)I2PConstants.I2P_NETWORK_ID))
                                {
                                    continue;
                                }
                            }

                            Session.MessageReceived(i2npmsg);
                        }
                    }
                }
                catch (Exception ex)
                {
                    Logging.Log("EstablishedState: SSUHost.SSUMessageTypes.Data", ex);
                }
                break;

            case SSUHeader.MessageTypes.PeerTest:
                HandleIncomingPeerTestPackage(reader);
                break;

            case SSUHeader.MessageTypes.RelayResponse:
                Logging.LogTransport($"SSU EstablishedState {Session.DebugId}: RelayResponse received from {Session.RemoteEP}.");
                var response = new RelayResponse(reader);
                Session.Host.ReportRelayResponse(header, response, Session.RemoteEP);
                break;

            case SSUHeader.MessageTypes.RelayIntro:
                var intro = new RelayIntro(reader);
                Logging.LogTransport($"SSU EstablishedState {Session.DebugId}: RelayIntro received from {Session.RemoteEP} for {intro.AliceEndpoint}.");

                var data = new BufLen(new byte[12]);
                data.Randomize();
                Send(intro.AliceEndpoint, data);

                ++Session.Host.EPStatisitcs[Session.RemoteEP].RelayIntrosReceived;
                ++Session.RelayIntroductionsReceived;
                break;

            case SSUHeader.MessageTypes.RelayRequest:
                // TODO: Implement
                // if ( !SSUHost.IntroductionSupported ) throw new Exception( "SSU relay introduction not supported" );
                Logging.LogTransport(string.Format("SSU EstablishedState {0}: Relay introduction not supported.", Session.DebugId));
                break;

            case SSUHeader.MessageTypes.SessionRequest:
                Logging.LogTransport(string.Format("SSU EstablishedState {0}: SessionRequest received. Ending session.", Session.DebugId));
                SendSessionDestroyed();
                return(null);

            default:
                Logging.LogTransport(string.Format("SSU EstablishedState {0}: Unexpected message received: {1}.",
                                                   Session.DebugId, header.MessageType));
                break;
            }

            return(this);
        }
コード例 #28
0
        GarlicCreationInfo GenerateNewSessionTags(uint trackingid, GarlicCloveDelivery[] cloves)
        {
            var newtags = new List <I2PSessionTag>();

            for (int i = 0; i < 50; ++i)
            {
                newtags.Add(new I2PSessionTag());
            }

            lock ( SessionTags )
            {
                SessionTags.AddRange(newtags);
            }

            // Add a ACK message
            DeliveryStatusMessage ackmsg;
            var msg = AddExplAck(cloves, out ackmsg);

            var payload = msg.ToByteArray();
            var dest    = new BufLen(new byte[61000]);
            var writer  = new BufRefLen(dest, 4);  // Reserve 4 bytes for GarlicMessageLength

            // ElGamal block
            var egbuf         = new BufLen(writer, 0, 222);
            var sessionkeybuf = new BufLen(egbuf, 0, 32);
            var preivbuf      = new BufLen(egbuf, 32, 32);
            var egpadding     = new BufLen(egbuf, 64);

            sessionkeybuf.Poke(SessionKey.Key, 0);
            preivbuf.Randomize();
            egpadding.Randomize();

            var preiv = preivbuf.Clone();

            var eg = new ElGamalCrypto(Destination.PublicKey);

            eg.Encrypt(writer, egbuf, true);

            // AES block
            var aesstart = new BufLen(writer);
            var aesblock = new GarlicAESBlock(writer, newtags, null, new BufRefLen(payload));

            var pivh = I2PHashSHA256.GetHash(preiv);

            Cipher.Init(true, SessionKey.Key.ToParametersWithIV(new BufLen(pivh, 0, 16)));
            Cipher.ProcessBytes(aesblock.DataBuf);

            var length = writer - dest;

            dest.PokeFlip32((uint)(length - 4), 0);

            LatestEGAckMessageId = ackmsg.MessageId;

#if LOG_ALL_TUNNEL_TRANSFER
            Logging.LogDebug(() => string.Format(
                                 "DestinationSession: Garlic generated with ElGamal encryption, {0} cloves. {1} tags available. Ack MessageId: {2}.",
                                 msg.Cloves.Count, SessionTags.Count, LatestEGAckMessageId));
#endif

            return(new GarlicCreationInfo(
                       Destination.IdentHash,
                       cloves,
                       new EGGarlic(new BufRefLen(dest, 0, length)),
                       GarlicCreationInfo.KeyUsed.ElGamal,
                       SessionTags.Count(),
                       trackingid,
                       ackmsg.MessageId,
                       LatestEGAckMessageId));
        }
コード例 #29
0
 public I2PCertificate()
 {
     Data  = new BufLen(new byte[3]);
     CType = CertTypes.NULL;
 }
コード例 #30
0
        public SSUDataMessage(BufRef reader, DataDefragmenter fragments)
        {
            var dataflags = (DataMessageFlags)reader.Read8();

#if LOG_MUCH_TRANSPORT
            Logging.LogTransport("SSU DataMessage rececived flag: " + dataflags.ToString());
#endif
            var explicitacks  = (dataflags & DataMessageFlags.ExplicitAcks) != 0;
            var acksbitfields = (dataflags & DataMessageFlags.BitfieldAcks) != 0;
            ECN = (dataflags & DataMessageFlags.ECN) != 0;
            var extdata = (dataflags & DataMessageFlags.ExtendedDataIncluded) != 0;
            if (explicitacks)
            {
                ExplicitAcks = new List <uint>();
                var acks = reader.Read8();
                for (int i = 0; i < acks; ++i)
                {
                    ExplicitAcks.Add(reader.Read32());
                }
            }
            if (acksbitfields)
            {
                var bitfields = reader.Read8();
                AckBitfields = new List <KeyValuePair <uint, List <byte> > >(bitfields);
                for (int i = 0; i < bitfields; ++i)
                {
                    var  msgid = reader.Read32();
                    var  bfs   = new List <byte>(10);
                    byte bf;
                    while (true)
                    {
                        bf = reader.Read8();
                        bfs.Add((byte)(bf & 0x7f));
                        if ((bf & 0x80) == 0)
                        {
                            break;
                        }
                    }
                    AckBitfields.Add(new KeyValuePair <uint, List <byte> >(msgid, bfs));
                }
            }
            if (extdata)
            {
                var datasize = reader.Read8();
                ExtData = reader.ReadBufLen(datasize);
            }

            var fragcount = reader.Read8();
            for (int i = 0; i < fragcount; ++i)
            {
                var frag       = new DataFragment(reader);
                var newmessage = fragments.Add(frag);

                if (newmessage != null)
                {
                    if (NewMessages == null)
                    {
                        NewMessages = new List <RebuildI2NPMessage>();
                    }
                    NewMessages.Add(newmessage);
                }
            }
        }