forked from I2P_Developers/i2p.i2p
SSU: Add support for requesting a relay tag via
Session Request extended options (ticket #1465)
This commit is contained in:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user