I2P Address: [http://git.idk.i2p]

Skip to content
Snippets Groups Projects
Commit 1e89fac1 authored by zzz's avatar zzz
Browse files

SSU: Add support for requesting a relay tag via

Session Request extended options (ticket #1465)
parent 4c72c08d
No related branches found
No related tags found
No related merge requests found
......@@ -131,8 +131,11 @@ class EstablishmentManager {
* Java I2P has always parsed the length of the extended options field,
* but i2pd hasn't recognized it until this release.
* No matter, the options weren't defined until this release anyway.
*
* FIXME 0.9.22 for testing, change to 0.9.24 for release
*
*/
private static final String VERSION_ALLOW_EXTENDED_OPTIONS = "0.9.24";
private static final String VERSION_ALLOW_EXTENDED_OPTIONS = "0.9.22";
public EstablishmentManager(RouterContext ctx, UDPTransport transport) {
......@@ -367,8 +370,11 @@ class EstablishmentManager {
}
boolean allowExtendedOptions = VersionComparator.comp(toRouterInfo.getVersion(),
VERSION_ALLOW_EXTENDED_OPTIONS) >= 0;
// w/o ext options, it's always 'requested', no need to set
boolean requestIntroduction = allowExtendedOptions && _transport.introducersRequired();
state = new OutboundEstablishState(_context, maybeTo, to,
toIdentity, allowExtendedOptions,
requestIntroduction,
sessionKey, addr, _transport.getDHFactory());
OutboundEstablishState oldState = _outboundStates.putIfAbsent(to, state);
boolean isNew = oldState == null;
......@@ -488,8 +494,9 @@ class EstablishmentManager {
// Don't offer to relay to privileged ports.
// Only offer for an IPv4 session.
// TODO if already we have their RI, only offer if they need it (no 'C' cap)
// TODO if extended options, only if they asked for it
if (_transport.canIntroduce() && state.getSentPort() >= 1024 &&
// if extended options, only if they asked for it
if (state.isIntroductionRequested() &&
_transport.canIntroduce() && state.getSentPort() >= 1024 &&
state.getSentIP().length == 4) {
// ensure > 0
long tag = 1 + _context.random().nextLong(MAX_TAG_VALUE);
......
......@@ -62,6 +62,8 @@ class InboundEstablishState {
private final Queue<OutNetMessage> _queuedMessages;
// count for backoff
private int _createdSentCount;
// default true
private boolean _introductionRequested = true;
public enum InboundState {
/** nothin known yet */
......@@ -150,6 +152,10 @@ class InboundEstablishState {
if (_bobIP == null)
_bobIP = new byte[req.readIPSize()];
req.readIP(_bobIP, 0);
byte[] ext = req.readExtendedOptions();
if (ext != null && ext.length >= UDPPacket.SESS_REQ_MIN_EXT_OPTIONS_LENGTH) {
_introductionRequested = (ext[1] & (byte) UDPPacket.SESS_REQ_EXT_FLAG_REQUEST_RELAY_TAG) != 0;
}
if (_log.shouldLog(Log.DEBUG))
_log.debug("Receive sessionRequest, BobIP = " + Addresses.toString(_bobIP));
if (_currentState == InboundState.IB_STATE_UNKNOWN)
......@@ -160,6 +166,12 @@ class InboundEstablishState {
public synchronized boolean sessionRequestReceived() { return _receivedX != null; }
public synchronized byte[] getReceivedX() { return _receivedX; }
public synchronized byte[] getReceivedOurIP() { return _bobIP; }
/**
* True (default) if no extended options in session request,
* or value of flag bit in the extended options.
* @since 0.9.24
*/
public synchronized boolean isIntroductionRequested() { return _introductionRequested; }
/**
* Generates session key and mac key.
......
......@@ -57,6 +57,7 @@ class OutboundEstablishState {
private final RemoteHostId _claimedAddress;
private final RouterIdentity _remotePeer;
private final boolean _allowExtendedOptions;
private final boolean _needIntroduction;
private final SessionKey _introKey;
private final Queue<OutNetMessage> _queuedMessages;
private OutboundState _currentState;
......@@ -108,12 +109,16 @@ class OutboundEstablishState {
* @param claimedAddress an IP/port based RemoteHostId, or null if unknown
* @param remoteHostId non-null, == claimedAddress if direct, or a hash-based one if indirect
* @param remotePeer must have supported sig type
* @param allowExtenededOptions are we allowed to send extended options to Bob?
* @param needIntroduction should we ask Bob to be an introducer for us?
ignored unless allowExtendedOptions is true
* @param introKey Bob's introduction key, as published in the netdb
* @param addr non-null
*/
public OutboundEstablishState(RouterContext ctx, RemoteHostId claimedAddress,
RemoteHostId remoteHostId,
RouterIdentity remotePeer, boolean allowExtendedOptions,
boolean needIntroduction,
SessionKey introKey, UDPAddress addr,
DHSessionKeyBuilder.Factory dh) {
_context = ctx;
......@@ -128,6 +133,7 @@ class OutboundEstablishState {
_claimedAddress = claimedAddress;
_remoteHostId = remoteHostId;
_allowExtendedOptions = allowExtendedOptions;
_needIntroduction = needIntroduction;
_remotePeer = remotePeer;
_introKey = introKey;
_queuedMessages = new LinkedBlockingQueue<OutNetMessage>();
......@@ -161,8 +167,18 @@ class OutboundEstablishState {
/** @return -1 if unset */
public long getIntroNonce() { return _introductionNonce; }
/** @since 0.9.24 */
/**
* Are we allowed to send extended options to this peer?
* @since 0.9.24
*/
public boolean isExtendedOptionsAllowed() { return _allowExtendedOptions; }
/**
* Should we ask this peer to be an introducer for us?
* Ignored unless allowExtendedOptions is true
* @since 0.9.24
*/
public boolean needIntroduction() { return _needIntroduction; }
/**
* Queue a message to be sent after the session is established.
......
......@@ -783,15 +783,20 @@ class PacketBuilder {
* @return ready to send packet, or null if there was a problem
*/
public UDPPacket buildSessionRequestPacket(OutboundEstablishState state) {
// TODO
// boolean ext = state.isExtendedOptionsAllowed();
// if (ext)
//byte[] options = new byte[3];
//UDPPacket packet = buildPacketHeader(SESSION_REQUEST_FLAG_BYTE, options);
UDPPacket packet = buildPacketHeader(SESSION_REQUEST_FLAG_BYTE);
int off = HEADER_SIZE;
byte[] options;
boolean ext = state.isExtendedOptionsAllowed();
if (ext) {
options = new byte[UDPPacket.SESS_REQ_MIN_EXT_OPTIONS_LENGTH];
if (state.needIntroduction())
options[1] = (byte) UDPPacket.SESS_REQ_EXT_FLAG_REQUEST_RELAY_TAG;
off += UDPPacket.SESS_REQ_MIN_EXT_OPTIONS_LENGTH + 1;
} else {
options = null;
}
UDPPacket packet = buildPacketHeader(SESSION_REQUEST_FLAG_BYTE, options);
DatagramPacket pkt = packet.getPacket();
byte data[] = pkt.getData();
int off = HEADER_SIZE; // + 1 + options.length;
byte toIP[] = state.getSentIP();
if (!_transport.isValid(toIP)) {
......
......@@ -101,6 +101,14 @@ class UDPPacket implements CDQEntry {
*/
public static final byte HEADER_FLAG_EXTENDED_OPTIONS = (1 << 2);
// Extended options for session request
public static final int SESS_REQ_MIN_EXT_OPTIONS_LENGTH = 2;
// bytes 0-1 are flags
/**
* set to 1 to request a session tag, i.e. we want him to be an introducer for us
*/
public static final int SESS_REQ_EXT_FLAG_REQUEST_RELAY_TAG = 0x01;
// 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);
......
......@@ -104,6 +104,7 @@ class UDPPacketReader {
/**
* Returns extended option data, 0-255 bytes, or null if none.
* Returned array does NOT include the length byte.
*
* @return extended options or null if none is included
* @since 0.9.24
......@@ -175,8 +176,26 @@ class UDPPacketReader {
/* ------- Begin Reader Classes ------- */
/**
* Base
*
* @since 0.9.24
*/
public abstract class Reader {
/**
* Returns extended option data from the header, 0-255 bytes, or null if none.
* Returned array does NOT include the length byte.
*
* @return extended options or null if none is included
* @since 0.9.24
*/
public byte[] readExtendedOptions() {
return UDPPacketReader.this.readExtendedOptions();
}
}
/** Help read the SessionRequest payload */
public class SessionRequestReader {
public class SessionRequestReader extends Reader {
public static final int X_LENGTH = 256;
public void readX(byte target[], int targetOffset) {
int readOffset = readBodyOffset();
......@@ -198,7 +217,7 @@ class UDPPacketReader {
}
/** Help read the SessionCreated payload */
public class SessionCreatedReader {
public class SessionCreatedReader extends Reader {
public static final int Y_LENGTH = 256;
public void readY(byte target[], int targetOffset) {
int readOffset = readBodyOffset();
......@@ -253,7 +272,7 @@ class UDPPacketReader {
}
/** parse out the confirmed message */
public class SessionConfirmedReader {
public class SessionConfirmedReader extends Reader {
/** which fragment is this? */
public int readCurrentFragmentNum() {
int readOffset = readBodyOffset();
......@@ -306,7 +325,7 @@ class UDPPacketReader {
}
/** parse out the data message */
public class DataReader {
public class DataReader extends Reader {
/**
* @return the data size, NOT including IP header, UDP header, IV, or MAC
......@@ -642,7 +661,7 @@ class UDPPacketReader {
}
/** Help read the PeerTest payload */
public class PeerTestReader {
public class PeerTestReader extends Reader {
private static final int NONCE_LENGTH = 4;
public long readNonce() {
......@@ -683,7 +702,7 @@ class UDPPacketReader {
}
/** Help read the RelayRequest payload */
public class RelayRequestReader {
public class RelayRequestReader extends Reader {
public long readTag() {
long rv = DataHelper.fromLong(_message, readBodyOffset(), 4);
if (_log.shouldLog(Log.DEBUG))
......@@ -767,7 +786,7 @@ class UDPPacketReader {
}
/** Help read the RelayIntro payload */
public class RelayIntroReader {
public class RelayIntroReader extends Reader {
public int readIPSize() {
int offset = readBodyOffset();
return _message[offset] & 0xff;
......@@ -808,7 +827,7 @@ class UDPPacketReader {
/** Help read the RelayResponse payload */
public class RelayResponseReader {
public class RelayResponseReader extends Reader {
public int readCharlieIPSize() {
int offset = readBodyOffset();
return _message[offset] & 0xff;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment