diff --git a/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java b/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java index ac64e7d42..07f9ec341 100644 --- a/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java +++ b/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java @@ -783,10 +783,13 @@ class PacketBuilder { * @return ready to send packet, or null if there was a problem */ public UDPPacket buildSessionRequestPacket(OutboundEstablishState state) { + // TODO + //byte[] options = new byte[3]; + //UDPPacket packet = buildPacketHeader(SESSION_REQUEST_FLAG_BYTE, options); UDPPacket packet = buildPacketHeader(SESSION_REQUEST_FLAG_BYTE); DatagramPacket pkt = packet.getPacket(); byte data[] = pkt.getData(); - int off = HEADER_SIZE; + int off = HEADER_SIZE; // + 1 + options.length; byte toIP[] = state.getSentIP(); if (!_transport.isValid(toIP)) { @@ -1433,24 +1436,49 @@ class PacketBuilder { /** * Create a new packet and add the flag byte and the time stamp. * Caller should add data starting at HEADER_SIZE. - * At this point, adding support for extended options and rekeying is unlikely, - * but if we do, we'll have to change this. + * Does not include extended options or rekeying. * * @param flagByte contains type and flags * @since 0.8.1 */ private UDPPacket buildPacketHeader(byte flagByte) { + return buildPacketHeader(flagByte, null); + } + + /** + * Create a new packet and add the flag byte and the time stamp. + * Caller should add data starting at HEADER_SIZE. + * (if extendedOptions != null, at HEADER_SIZE + 1 + extendedOptions.length) + * Does not include rekeying. + * + * @param flagByte contains type and flags + * @param extendedOptions May be null. If non-null, we will add the associated flag here. + * 255 bytes max. + * @since 0.9.24 + */ + private UDPPacket buildPacketHeader(byte flagByte, byte[] extendedOptions) { UDPPacket packet = UDPPacket.acquire(_context, false); byte data[] = packet.getPacket().getData(); Arrays.fill(data, 0, data.length, (byte)0x0); int off = UDPPacket.MAC_SIZE + UDPPacket.IV_SIZE; // header + if (extendedOptions != null) + flagByte |= UDPPacket.HEADER_FLAG_EXTENDED_OPTIONS; data[off] = flagByte; off++; long now = (_context.clock().now() + 500) / 1000; DataHelper.toLong(data, off, 4, now); - // todo: add support for rekeying and extended options + // todo: add support for rekeying + // extended options + if (extendedOptions != null) { + off+= 4; + int len = extendedOptions.length; + if (len > 255) + throw new IllegalArgumentException(); + data[off++] = (byte) len; + System.arraycopy(extendedOptions, 0, data, off, len); + } return packet; } diff --git a/router/java/src/net/i2p/router/transport/udp/UDPPacket.java b/router/java/src/net/i2p/router/transport/udp/UDPPacket.java index e2e1b3f59..fae13ab1f 100644 --- a/router/java/src/net/i2p/router/transport/udp/UDPPacket.java +++ b/router/java/src/net/i2p/router/transport/udp/UDPPacket.java @@ -89,14 +89,26 @@ class UDPPacket implements CDQEntry { /** @since 0.8.1 */ public static final int PAYLOAD_TYPE_SESSION_DESTROY = 8; + // various flag fields for use in the header + /** + * Defined in the spec from the beginning, Unused + * @since 0.9.24 + */ + public static final byte HEADER_FLAG_REKEY = (1 << 3); + /** + * Defined in the spec from the beginning, Used starting in 0.9.24 + * @since 0.9.24 + */ + public static final byte HEADER_FLAG_EXTENDED_OPTIONS = (1 << 2); + // various flag fields for use in the data packets public static final byte DATA_FLAG_EXPLICIT_ACK = (byte)(1 << 7); public static final byte DATA_FLAG_ACK_BITFIELDS = (1 << 6); - // unused + /** unused */ public static final byte DATA_FLAG_ECN = (1 << 4); public static final byte DATA_FLAG_WANT_ACKS = (1 << 3); public static final byte DATA_FLAG_WANT_REPLY = (1 << 2); - // unused + /** unused */ public static final byte DATA_FLAG_EXTENDED = (1 << 1); public static final byte BITFIELD_CONTINUATION = (byte)(1 << 7); diff --git a/router/java/src/net/i2p/router/transport/udp/UDPPacketReader.java b/router/java/src/net/i2p/router/transport/udp/UDPPacketReader.java index adacea03f..18c27806a 100644 --- a/router/java/src/net/i2p/router/transport/udp/UDPPacketReader.java +++ b/router/java/src/net/i2p/router/transport/udp/UDPPacketReader.java @@ -67,13 +67,19 @@ class UDPPacketReader { return (_message[_payloadBeginOffset] & 0xFF) >>> 4; } - /** does this packet include rekeying data? */ - public boolean readRekeying() { - return (_message[_payloadBeginOffset] & (1 << 3)) != 0; + /** + * Does this packet include rekeying data in the header? + * Unused, should always be false. + */ + public boolean isRekeyingIncluded() { + return (_message[_payloadBeginOffset] & UDPPacket.HEADER_FLAG_REKEY) != 0; } - public boolean readExtendedOptionsIncluded() { - return (_message[_payloadBeginOffset] & (1 << 2)) != 0; + /** + * Does this packet include extended options in the header? + */ + public boolean isExtendedOptionsIncluded() { + return (_message[_payloadBeginOffset] & UDPPacket.HEADER_FLAG_EXTENDED_OPTIONS) != 0; } /** @return seconds */ @@ -81,19 +87,46 @@ class UDPPacketReader { return DataHelper.fromLong(_message, _payloadBeginOffset + 1, 4); } - public void readKeyingMaterial(byte target[], int targetOffset) { - if (!readRekeying()) - throw new IllegalStateException("This packet is not rekeying!"); - System.arraycopy(_message, _payloadBeginOffset + 1 + 4, target, targetOffset, KEYING_MATERIAL_LENGTH); + /** + * Returns rekeying data (64 bytes), or null if none. + * Unused, should always return null. + * + * @deprecated unused + */ + @Deprecated + public byte[] readKeyingMaterial() { + if (!isRekeyingIncluded()) + return null; + byte[] rv = new byte[KEYING_MATERIAL_LENGTH]; + System.arraycopy(_message, _payloadBeginOffset + 1 + 4, rv, 0, KEYING_MATERIAL_LENGTH); + return rv; + } + + /** + * Returns extended option data, 0-255 bytes, or null if none. + * + * @return extended options or null if none is included + * @since 0.9.24 + */ + public byte[] readExtendedOptions() { + if (!isExtendedOptionsIncluded()) + return null; + int offset = _payloadBeginOffset + 1 + 4; + if (isRekeyingIncluded()) + offset += KEYING_MATERIAL_LENGTH; + int optionsSize = _message[offset++] & 0xff; + byte[] rv = new byte[optionsSize]; + System.arraycopy(_message, offset, rv, 0, optionsSize); + return rv; } /** index into the message where the body begins */ private int readBodyOffset() { int offset = _payloadBeginOffset + 1 + 4; - if (readRekeying()) + if (isRekeyingIncluded()) offset += KEYING_MATERIAL_LENGTH; - if (readExtendedOptionsIncluded()) { - int optionsSize = (int)DataHelper.fromLong(_message, offset, 1); + if (isExtendedOptionsIncluded()) { + int optionsSize = _message[offset] & 0xff; offset += optionsSize + 1; } return offset;