SSU PacketBuilder: Refactor header generation, add destroy msg support

This commit is contained in:
zzz
2010-07-09 16:34:54 +00:00
parent c19af4dbcf
commit 8353b623da
2 changed files with 95 additions and 139 deletions

View File

@ -4,7 +4,6 @@ import java.net.InetAddress;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.Date;
import java.util.List; import java.util.List;
import net.i2p.I2PAppContext; import net.i2p.I2PAppContext;
@ -156,7 +155,9 @@ class PacketBuilder {
* included, it should be removed from the list. * included, it should be removed from the list.
*/ */
public UDPPacket buildPacket(OutboundMessageState state, int fragment, PeerState peer, List<Long> ackIdsRemaining, List<ACKBitfield> partialACKsRemaining) { public UDPPacket buildPacket(OutboundMessageState state, int fragment, PeerState peer, List<Long> ackIdsRemaining, List<ACKBitfield> partialACKsRemaining) {
UDPPacket packet = UDPPacket.acquire(_context, false); UDPPacket packet = buildPacketHeader((byte)(UDPPacket.PAYLOAD_TYPE_DATA << 4));
byte data[] = packet.getPacket().getData();
int off = HEADER_SIZE;
StringBuilder msg = null; StringBuilder msg = null;
boolean acksIncluded = false; boolean acksIncluded = false;
@ -168,19 +169,6 @@ class PacketBuilder {
msg.append("*"); msg.append("*");
} }
byte data[] = packet.getPacket().getData();
Arrays.fill(data, 0, data.length, (byte)0x0);
int start = UDPPacket.MAC_SIZE + UDPPacket.IV_SIZE;
int off = start;
// header
data[off] |= (UDPPacket.PAYLOAD_TYPE_DATA << 4);
// todo: add support for rekeying and extended options
off++;
long now = _context.clock().now() / 1000;
DataHelper.toLong(data, off, 4, now);
off += 4;
// ok, now for the body... // ok, now for the body...
// just always ask for an ACK for now... // just always ask for an ACK for now...
@ -322,11 +310,14 @@ class PacketBuilder {
/** /**
* Build the ack packet. The list need not be sorted into full and partial; * Build the ack packet. The list need not be sorted into full and partial;
* this method will put all fulls before the partials in the outgoing packet. * this method will put all fulls before the partials in the outgoing packet.
* An ack packet is just a data packet with no data.
* *
* @param ackBitfields list of ACKBitfield instances to either fully or partially ACK * @param ackBitfields list of ACKBitfield instances to either fully or partially ACK
*/ */
public UDPPacket buildACK(PeerState peer, List<ACKBitfield> ackBitfields) { public UDPPacket buildACK(PeerState peer, List<ACKBitfield> ackBitfields) {
UDPPacket packet = UDPPacket.acquire(_context, false); UDPPacket packet = buildPacketHeader((byte)(UDPPacket.PAYLOAD_TYPE_DATA << 4));
byte data[] = packet.getPacket().getData();
int off = HEADER_SIZE;
StringBuilder msg = null; StringBuilder msg = null;
if (_log.shouldLog(Log.DEBUG)) { if (_log.shouldLog(Log.DEBUG)) {
@ -334,18 +325,6 @@ class PacketBuilder {
msg.append("building ACK packet to ").append(peer.getRemotePeer().toBase64().substring(0,6)); msg.append("building ACK packet to ").append(peer.getRemotePeer().toBase64().substring(0,6));
} }
byte data[] = packet.getPacket().getData();
Arrays.fill(data, 0, data.length, (byte)0x0);
int off = UDPPacket.MAC_SIZE + UDPPacket.IV_SIZE;
// header
data[off] |= (UDPPacket.PAYLOAD_TYPE_DATA << 4);
// todo: add support for rekeying and extended options
off++;
long now = _context.clock().now() / 1000;
DataHelper.toLong(data, off, 4, now);
off += 4;
int fullACKCount = 0; int fullACKCount = 0;
int partialACKCount = 0; int partialACKCount = 0;
for (int i = 0; i < ackBitfields.size(); i++) { for (int i = 0; i < ackBitfields.size(); i++) {
@ -432,7 +411,9 @@ class PacketBuilder {
* @return ready to send packet, or null if there was a problem * @return ready to send packet, or null if there was a problem
*/ */
public UDPPacket buildSessionCreatedPacket(InboundEstablishState state, int externalPort, SessionKey ourIntroKey) { public UDPPacket buildSessionCreatedPacket(InboundEstablishState state, int externalPort, SessionKey ourIntroKey) {
UDPPacket packet = UDPPacket.acquire(_context, false); UDPPacket packet = buildPacketHeader(SESSION_CREATED_FLAG_BYTE);
byte data[] = packet.getPacket().getData();
int off = HEADER_SIZE;
InetAddress to = null; InetAddress to = null;
try { try {
@ -446,17 +427,6 @@ class PacketBuilder {
state.prepareSessionCreated(); state.prepareSessionCreated();
byte data[] = packet.getPacket().getData();
Arrays.fill(data, 0, data.length, (byte)0x0);
int off = UDPPacket.MAC_SIZE + UDPPacket.IV_SIZE;
// header
data[off] = SESSION_CREATED_FLAG_BYTE;
off++;
long now = _context.clock().now() / 1000;
DataHelper.toLong(data, off, 4, now);
off += 4;
byte sentIP[] = state.getSentIP(); byte sentIP[] = state.getSentIP();
if ( (sentIP == null) || (sentIP.length <= 0) || ( (_transport != null) && (!_transport.isValid(sentIP)) ) ) { if ( (sentIP == null) || (sentIP.length <= 0) || ( (_transport != null) && (!_transport.isValid(sentIP)) ) ) {
if (_log.shouldLog(Log.ERROR)) if (_log.shouldLog(Log.ERROR))
@ -535,7 +505,10 @@ class PacketBuilder {
* @return ready to send packet, or null if there was a problem * @return ready to send packet, or null if there was a problem
*/ */
public UDPPacket buildSessionRequestPacket(OutboundEstablishState state) { public UDPPacket buildSessionRequestPacket(OutboundEstablishState state) {
UDPPacket packet = UDPPacket.acquire(_context, false); UDPPacket packet = buildPacketHeader(SESSION_REQUEST_FLAG_BYTE);
byte data[] = packet.getPacket().getData();
int off = HEADER_SIZE;
byte toIP[] = state.getSentIP(); byte toIP[] = state.getSentIP();
if ( (_transport !=null) && (!_transport.isValid(toIP)) ) { if ( (_transport !=null) && (!_transport.isValid(toIP)) ) {
packet.release(); packet.release();
@ -550,19 +523,8 @@ class PacketBuilder {
packet.release(); packet.release();
return null; return null;
} }
byte data[] = packet.getPacket().getData();
Arrays.fill(data, 0, data.length, (byte)0x0);
int off = UDPPacket.MAC_SIZE + UDPPacket.IV_SIZE;
// header
data[off] = SESSION_REQUEST_FLAG_BYTE;
off++;
long now = _context.clock().now() / 1000;
DataHelper.toLong(data, off, 4, now);
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("Sending request with time = " + new Date(now*1000)); _log.debug("Sending request");
off += 4;
// now for the body // now for the body
System.arraycopy(state.getSentX(), 0, data, off, state.getSentX().length); System.arraycopy(state.getSentX(), 0, data, off, state.getSentX().length);
@ -622,7 +584,10 @@ class PacketBuilder {
* @return ready to send packets, or null if there was a problem * @return ready to send packets, or null if there was a problem
*/ */
public UDPPacket buildSessionConfirmedPacket(OutboundEstablishState state, int fragmentNum, int numFragments, byte identity[]) { public UDPPacket buildSessionConfirmedPacket(OutboundEstablishState state, int fragmentNum, int numFragments, byte identity[]) {
UDPPacket packet = UDPPacket.acquire(_context, false); UDPPacket packet = buildPacketHeader(SESSION_CONFIRMED_FLAG_BYTE);
byte data[] = packet.getPacket().getData();
int off = HEADER_SIZE;
InetAddress to = null; InetAddress to = null;
try { try {
to = InetAddress.getByAddress(state.getSentIP()); to = InetAddress.getByAddress(state.getSentIP());
@ -633,17 +598,6 @@ class PacketBuilder {
return null; return null;
} }
byte data[] = packet.getPacket().getData();
Arrays.fill(data, 0, data.length, (byte)0x0);
int off = UDPPacket.MAC_SIZE + UDPPacket.IV_SIZE;
// header
data[off] = SESSION_CONFIRMED_FLAG_BYTE;
off++;
long now = _context.clock().now() / 1000;
DataHelper.toLong(data, off, 4, now);
off += 4;
// now for the body // now for the body
data[off] |= fragmentNum << 4; data[off] |= fragmentNum << 4;
data[off] |= (numFragments & 0xF); data[off] |= (numFragments & 0xF);
@ -699,6 +653,36 @@ class PacketBuilder {
} }
/**
* Build a destroy packet, which contains a header but no body.
*
* @since 0.8.1
*/
public UDPPacket buildSessionDestroyPacket(PeerState peer) {
UDPPacket packet = buildPacketHeader((byte)(UDPPacket.PAYLOAD_TYPE_SESSION_DESTROY << 4));
byte data[] = packet.getPacket().getData();
int off = HEADER_SIZE;
StringBuilder msg = null;
if (_log.shouldLog(Log.DEBUG)) {
msg = new StringBuilder(128);
msg.append("building session destroy packet to ").append(peer.getRemotePeer().toBase64().substring(0,6));
}
// no body in this message
if (msg != null)
_log.debug(msg.toString());
// pad up so we're on the encryption boundary
if ( (off % 16) != 0)
off += 16 - (off % 16);
packet.getPacket().setLength(off);
authenticate(packet, peer.getCurrentCipherKey(), peer.getCurrentMACKey());
setTo(packet, peer.getRemoteIPAddress(), peer.getRemotePort());
return packet;
}
/** /**
* full flag info for a peerTest message. this can be fixed, * full flag info for a peerTest message. this can be fixed,
* since we never rekey on test, and don't need any extended options * since we never rekey on test, and don't need any extended options
@ -715,19 +699,11 @@ class PacketBuilder {
return buildPeerTestFromAlice(toIP, toPort, toIntroKey, toIntroKey, nonce, aliceIntroKey); return buildPeerTestFromAlice(toIP, toPort, toIntroKey, toIntroKey, nonce, aliceIntroKey);
} }
public UDPPacket buildPeerTestFromAlice(InetAddress toIP, int toPort, SessionKey toCipherKey, SessionKey toMACKey, long nonce, SessionKey aliceIntroKey) { public UDPPacket buildPeerTestFromAlice(InetAddress toIP, int toPort, SessionKey toCipherKey, SessionKey toMACKey, long nonce, SessionKey aliceIntroKey) {
UDPPacket packet = UDPPacket.acquire(_context, false); UDPPacket packet = buildPacketHeader(PEER_TEST_FLAG_BYTE);
byte data[] = packet.getPacket().getData(); byte data[] = packet.getPacket().getData();
Arrays.fill(data, 0, data.length, (byte)0x0); int off = HEADER_SIZE;
int off = UDPPacket.MAC_SIZE + UDPPacket.IV_SIZE;
// header
data[off] = PEER_TEST_FLAG_BYTE;
off++;
long now = _context.clock().now() / 1000;
DataHelper.toLong(data, off, 4, now);
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("Sending peer test " + nonce + " to Bob with time = " + new Date(now*1000)); _log.debug("Sending peer test " + nonce + " to Bob");
off += 4;
// now for the body // now for the body
DataHelper.toLong(data, off, 4, nonce); DataHelper.toLong(data, off, 4, nonce);
@ -757,19 +733,11 @@ class PacketBuilder {
* @return ready to send packet, or null if there was a problem * @return ready to send packet, or null if there was a problem
*/ */
public UDPPacket buildPeerTestToAlice(InetAddress aliceIP, int alicePort, SessionKey aliceIntroKey, SessionKey charlieIntroKey, long nonce) { public UDPPacket buildPeerTestToAlice(InetAddress aliceIP, int alicePort, SessionKey aliceIntroKey, SessionKey charlieIntroKey, long nonce) {
UDPPacket packet = UDPPacket.acquire(_context, false); UDPPacket packet = buildPacketHeader(PEER_TEST_FLAG_BYTE);
byte data[] = packet.getPacket().getData(); byte data[] = packet.getPacket().getData();
Arrays.fill(data, 0, data.length, (byte)0x0); int off = HEADER_SIZE;
int off = UDPPacket.MAC_SIZE + UDPPacket.IV_SIZE;
// header
data[off] = PEER_TEST_FLAG_BYTE;
off++;
long now = _context.clock().now() / 1000;
DataHelper.toLong(data, off, 4, now);
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("Sending peer test " + nonce + " to Alice with time = " + new Date(now*1000)); _log.debug("Sending peer test " + nonce + " to Alice");
off += 4;
// now for the body // now for the body
DataHelper.toLong(data, off, 4, nonce); DataHelper.toLong(data, off, 4, nonce);
@ -804,19 +772,11 @@ class PacketBuilder {
public UDPPacket buildPeerTestToCharlie(InetAddress aliceIP, int alicePort, SessionKey aliceIntroKey, long nonce, public UDPPacket buildPeerTestToCharlie(InetAddress aliceIP, int alicePort, SessionKey aliceIntroKey, long nonce,
InetAddress charlieIP, int charliePort, InetAddress charlieIP, int charliePort,
SessionKey charlieCipherKey, SessionKey charlieMACKey) { SessionKey charlieCipherKey, SessionKey charlieMACKey) {
UDPPacket packet = UDPPacket.acquire(_context, false); UDPPacket packet = buildPacketHeader(PEER_TEST_FLAG_BYTE);
byte data[] = packet.getPacket().getData(); byte data[] = packet.getPacket().getData();
Arrays.fill(data, 0, data.length, (byte)0x0); int off = HEADER_SIZE;
int off = UDPPacket.MAC_SIZE + UDPPacket.IV_SIZE;
// header
data[off] = PEER_TEST_FLAG_BYTE;
off++;
long now = _context.clock().now() / 1000;
DataHelper.toLong(data, off, 4, now);
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("Sending peer test " + nonce + " to Charlie with time = " + new Date(now*1000)); _log.debug("Sending peer test " + nonce + " to Charlie");
off += 4;
// now for the body // now for the body
DataHelper.toLong(data, off, 4, nonce); DataHelper.toLong(data, off, 4, nonce);
@ -849,19 +809,11 @@ class PacketBuilder {
* @return ready to send packet, or null if there was a problem * @return ready to send packet, or null if there was a problem
*/ */
public UDPPacket buildPeerTestToBob(InetAddress bobIP, int bobPort, InetAddress aliceIP, int alicePort, SessionKey aliceIntroKey, long nonce, SessionKey bobCipherKey, SessionKey bobMACKey) { public UDPPacket buildPeerTestToBob(InetAddress bobIP, int bobPort, InetAddress aliceIP, int alicePort, SessionKey aliceIntroKey, long nonce, SessionKey bobCipherKey, SessionKey bobMACKey) {
UDPPacket packet = UDPPacket.acquire(_context, false); UDPPacket packet = buildPacketHeader(PEER_TEST_FLAG_BYTE);
byte data[] = packet.getPacket().getData(); byte data[] = packet.getPacket().getData();
Arrays.fill(data, 0, data.length, (byte)0x0); int off = HEADER_SIZE;
int off = UDPPacket.MAC_SIZE + UDPPacket.IV_SIZE;
// header
data[off] = PEER_TEST_FLAG_BYTE;
off++;
long now = _context.clock().now() / 1000;
DataHelper.toLong(data, off, 4, now);
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("Sending peer test " + nonce + " to Bob with time = " + new Date(now*1000)); _log.debug("Sending peer test " + nonce + " to Bob");
off += 4;
// now for the body // now for the body
DataHelper.toLong(data, off, 4, nonce); DataHelper.toLong(data, off, 4, nonce);
@ -925,22 +877,15 @@ class PacketBuilder {
} }
public UDPPacket buildRelayRequest(InetAddress introHost, int introPort, byte introKey[], long introTag, SessionKey ourIntroKey, long introNonce, boolean encrypt) { public UDPPacket buildRelayRequest(InetAddress introHost, int introPort, byte introKey[], long introTag, SessionKey ourIntroKey, long introNonce, boolean encrypt) {
UDPPacket packet = UDPPacket.acquire(_context, false); UDPPacket packet = buildPacketHeader(PEER_RELAY_REQUEST_FLAG_BYTE);
byte data[] = packet.getPacket().getData(); byte data[] = packet.getPacket().getData();
Arrays.fill(data, 0, data.length, (byte)0x0); int off = HEADER_SIZE;
int off = UDPPacket.MAC_SIZE + UDPPacket.IV_SIZE;
byte ourIP[] = getOurExplicitIP(); byte ourIP[] = getOurExplicitIP();
int ourPort = getOurExplicitPort(); int ourPort = getOurExplicitPort();
// header
data[off] = PEER_RELAY_REQUEST_FLAG_BYTE;
off++;
long now = _context.clock().now() / 1000;
DataHelper.toLong(data, off, 4, now);
if (_log.shouldLog(Log.INFO)) if (_log.shouldLog(Log.INFO))
_log.info("Sending intro relay request to " + introHost + ":" + introPort); // + " regarding " + state.getRemoteIdentity().calculateHash().toBase64()); _log.info("Sending intro relay request to " + introHost + ":" + introPort); // + " regarding " + state.getRemoteIdentity().calculateHash().toBase64());
off += 4;
// now for the body // now for the body
DataHelper.toLong(data, off, 4, introTag); DataHelper.toLong(data, off, 4, introTag);
@ -994,19 +939,11 @@ class PacketBuilder {
private static final byte PEER_RELAY_INTRO_FLAG_BYTE = (UDPPacket.PAYLOAD_TYPE_RELAY_INTRO << 4); private static final byte PEER_RELAY_INTRO_FLAG_BYTE = (UDPPacket.PAYLOAD_TYPE_RELAY_INTRO << 4);
UDPPacket buildRelayIntro(RemoteHostId alice, PeerState charlie, UDPPacketReader.RelayRequestReader request) { UDPPacket buildRelayIntro(RemoteHostId alice, PeerState charlie, UDPPacketReader.RelayRequestReader request) {
UDPPacket packet = UDPPacket.acquire(_context, false); UDPPacket packet = buildPacketHeader(PEER_RELAY_INTRO_FLAG_BYTE);
byte data[] = packet.getPacket().getData(); byte data[] = packet.getPacket().getData();
Arrays.fill(data, 0, data.length, (byte)0x0); int off = HEADER_SIZE;
int off = UDPPacket.MAC_SIZE + UDPPacket.IV_SIZE;
// header
data[off] = PEER_RELAY_INTRO_FLAG_BYTE;
off++;
long now = _context.clock().now() / 1000;
DataHelper.toLong(data, off, 4, now);
if (_log.shouldLog(Log.INFO)) if (_log.shouldLog(Log.INFO))
_log.info("Sending intro to " + charlie + " for " + alice); _log.info("Sending intro to " + charlie + " for " + alice);
off += 4;
// now for the body // now for the body
byte ip[] = alice.getIP(); byte ip[] = alice.getIP();
@ -1051,17 +988,9 @@ class PacketBuilder {
return null; return null;
} }
UDPPacket packet = UDPPacket.acquire(_context, false); UDPPacket packet = buildPacketHeader(PEER_RELAY_RESPONSE_FLAG_BYTE);
byte data[] = packet.getPacket().getData(); byte data[] = packet.getPacket().getData();
Arrays.fill(data, 0, data.length, (byte)0x0); int off = HEADER_SIZE;
int off = UDPPacket.MAC_SIZE + UDPPacket.IV_SIZE;
// header
data[off] = PEER_RELAY_RESPONSE_FLAG_BYTE;
off++;
long now = _context.clock().now() / 1000;
DataHelper.toLong(data, off, 4, now);
off += 4;
if (_log.shouldLog(Log.INFO)) if (_log.shouldLog(Log.INFO))
_log.info("Sending relay response to " + alice + " for " + charlie + " with alice's intro key " + aliceIntroKey.toBase64()); _log.info("Sending relay response to " + alice + " for " + charlie + " with alice's intro key " + aliceIntroKey.toBase64());
@ -1105,7 +1034,6 @@ class PacketBuilder {
UDPPacket packet = UDPPacket.acquire(_context, false); UDPPacket packet = UDPPacket.acquire(_context, false);
byte data[] = packet.getPacket().getData(); byte data[] = packet.getPacket().getData();
Arrays.fill(data, 0, data.length, (byte)0x0); Arrays.fill(data, 0, data.length, (byte)0x0);
int off = UDPPacket.MAC_SIZE + UDPPacket.IV_SIZE;
int ipSize = reader.getRelayIntroReader().readIPSize(); int ipSize = reader.getRelayIntroReader().readIPSize();
byte ip[] = new byte[ipSize]; byte ip[] = new byte[ipSize];
@ -1134,6 +1062,33 @@ class PacketBuilder {
return packet; return packet;
} }
/** if no extended options or rekey data, which we don't support */
private static final int HEADER_SIZE = UDPPacket.MAC_SIZE + UDPPacket.IV_SIZE + 1 + 4;
/**
* 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.
*
* @param flagByte contains type and flags
* @since 0.8.1
*/
private UDPPacket buildPacketHeader(byte flagByte) {
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
data[off] = flagByte;
off++;
long now = _context.clock().now() / 1000;
DataHelper.toLong(data, off, 4, now);
// todo: add support for rekeying and extended options
return packet;
}
private static void setTo(UDPPacket packet, InetAddress ip, int port) { private static void setTo(UDPPacket packet, InetAddress ip, int port) {
packet.getPacket().setAddress(ip); packet.getPacket().setAddress(ip);
packet.getPacket().setPort(port); packet.getPacket().setPort(port);

View File

@ -55,6 +55,7 @@ class UDPPacket {
public static final int IV_SIZE = 16; public static final int IV_SIZE = 16;
public static final int MAC_SIZE = 16; public static final int MAC_SIZE = 16;
/** Message types, 4 bits max */
public static final int PAYLOAD_TYPE_SESSION_REQUEST = 0; public static final int PAYLOAD_TYPE_SESSION_REQUEST = 0;
public static final int PAYLOAD_TYPE_SESSION_CREATED = 1; public static final int PAYLOAD_TYPE_SESSION_CREATED = 1;
public static final int PAYLOAD_TYPE_SESSION_CONFIRMED = 2; public static final int PAYLOAD_TYPE_SESSION_CONFIRMED = 2;