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.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import net.i2p.I2PAppContext;
@ -156,7 +155,9 @@ class PacketBuilder {
* included, it should be removed from the list.
*/
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;
boolean acksIncluded = false;
@ -168,19 +169,6 @@ class PacketBuilder {
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...
// 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;
* 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
*/
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;
if (_log.shouldLog(Log.DEBUG)) {
@ -334,18 +325,6 @@ class PacketBuilder {
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 partialACKCount = 0;
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
*/
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;
try {
@ -446,17 +427,6 @@ class PacketBuilder {
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();
if ( (sentIP == null) || (sentIP.length <= 0) || ( (_transport != null) && (!_transport.isValid(sentIP)) ) ) {
if (_log.shouldLog(Log.ERROR))
@ -535,7 +505,10 @@ class PacketBuilder {
* @return ready to send packet, or null if there was a problem
*/
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();
if ( (_transport !=null) && (!_transport.isValid(toIP)) ) {
packet.release();
@ -550,19 +523,8 @@ class PacketBuilder {
packet.release();
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))
_log.debug("Sending request with time = " + new Date(now*1000));
off += 4;
_log.debug("Sending request");
// now for the body
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
*/
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;
try {
to = InetAddress.getByAddress(state.getSentIP());
@ -633,17 +598,6 @@ class PacketBuilder {
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
data[off] |= fragmentNum << 4;
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,
* 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);
}
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();
Arrays.fill(data, 0, data.length, (byte)0x0);
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);
int off = HEADER_SIZE;
if (_log.shouldLog(Log.DEBUG))
_log.debug("Sending peer test " + nonce + " to Bob with time = " + new Date(now*1000));
off += 4;
_log.debug("Sending peer test " + nonce + " to Bob");
// now for the body
DataHelper.toLong(data, off, 4, nonce);
@ -757,19 +733,11 @@ class PacketBuilder {
* @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) {
UDPPacket packet = UDPPacket.acquire(_context, false);
UDPPacket packet = buildPacketHeader(PEER_TEST_FLAG_BYTE);
byte data[] = packet.getPacket().getData();
Arrays.fill(data, 0, data.length, (byte)0x0);
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);
int off = HEADER_SIZE;
if (_log.shouldLog(Log.DEBUG))
_log.debug("Sending peer test " + nonce + " to Alice with time = " + new Date(now*1000));
off += 4;
_log.debug("Sending peer test " + nonce + " to Alice");
// now for the body
DataHelper.toLong(data, off, 4, nonce);
@ -804,19 +772,11 @@ class PacketBuilder {
public UDPPacket buildPeerTestToCharlie(InetAddress aliceIP, int alicePort, SessionKey aliceIntroKey, long nonce,
InetAddress charlieIP, int charliePort,
SessionKey charlieCipherKey, SessionKey charlieMACKey) {
UDPPacket packet = UDPPacket.acquire(_context, false);
UDPPacket packet = buildPacketHeader(PEER_TEST_FLAG_BYTE);
byte data[] = packet.getPacket().getData();
Arrays.fill(data, 0, data.length, (byte)0x0);
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);
int off = HEADER_SIZE;
if (_log.shouldLog(Log.DEBUG))
_log.debug("Sending peer test " + nonce + " to Charlie with time = " + new Date(now*1000));
off += 4;
_log.debug("Sending peer test " + nonce + " to Charlie");
// now for the body
DataHelper.toLong(data, off, 4, nonce);
@ -849,19 +809,11 @@ class PacketBuilder {
* @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) {
UDPPacket packet = UDPPacket.acquire(_context, false);
UDPPacket packet = buildPacketHeader(PEER_TEST_FLAG_BYTE);
byte data[] = packet.getPacket().getData();
Arrays.fill(data, 0, data.length, (byte)0x0);
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);
int off = HEADER_SIZE;
if (_log.shouldLog(Log.DEBUG))
_log.debug("Sending peer test " + nonce + " to Bob with time = " + new Date(now*1000));
off += 4;
_log.debug("Sending peer test " + nonce + " to Bob");
// now for the body
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) {
UDPPacket packet = UDPPacket.acquire(_context, false);
UDPPacket packet = buildPacketHeader(PEER_RELAY_REQUEST_FLAG_BYTE);
byte data[] = packet.getPacket().getData();
Arrays.fill(data, 0, data.length, (byte)0x0);
int off = UDPPacket.MAC_SIZE + UDPPacket.IV_SIZE;
int off = HEADER_SIZE;
byte ourIP[] = getOurExplicitIP();
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))
_log.info("Sending intro relay request to " + introHost + ":" + introPort); // + " regarding " + state.getRemoteIdentity().calculateHash().toBase64());
off += 4;
// now for the body
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);
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();
Arrays.fill(data, 0, data.length, (byte)0x0);
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);
int off = HEADER_SIZE;
if (_log.shouldLog(Log.INFO))
_log.info("Sending intro to " + charlie + " for " + alice);
off += 4;
// now for the body
byte ip[] = alice.getIP();
@ -1051,17 +988,9 @@ class PacketBuilder {
return null;
}
UDPPacket packet = UDPPacket.acquire(_context, false);
UDPPacket packet = buildPacketHeader(PEER_RELAY_RESPONSE_FLAG_BYTE);
byte data[] = packet.getPacket().getData();
Arrays.fill(data, 0, data.length, (byte)0x0);
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;
int off = HEADER_SIZE;
if (_log.shouldLog(Log.INFO))
_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);
byte data[] = packet.getPacket().getData();
Arrays.fill(data, 0, data.length, (byte)0x0);
int off = UDPPacket.MAC_SIZE + UDPPacket.IV_SIZE;
int ipSize = reader.getRelayIntroReader().readIPSize();
byte ip[] = new byte[ipSize];
@ -1134,6 +1062,33 @@ class PacketBuilder {
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) {
packet.getPacket().setAddress(ip);
packet.getPacket().setPort(port);

View File

@ -55,6 +55,7 @@ class UDPPacket {
public static final int IV_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_CREATED = 1;
public static final int PAYLOAD_TYPE_SESSION_CONFIRMED = 2;