Пример #1
0
 /**
  * We found a non-SYN packet that was queued in the syn queue, check to see if it has a home now,
  * else drop it ...
  */
 private void reReceivePacket(Packet packet) {
   Connection con = _manager.getConnectionByOutboundId(packet.getReceiveStreamId());
   if (con != null) {
     // Send it through the packet handler again
     if (_log.shouldLog(Log.WARN)) _log.warn("Found con for queued non-syn packet: " + packet);
     // false -> don't requeue, fixes a race where a SYN gets dropped
     // between here and PacketHandler, causing the packet to loop forever....
     _manager.getPacketHandler().receivePacketDirect(packet, false);
   } else {
     // goodbye
     if (_log.shouldLog(Log.WARN))
       _log.warn("Did not find con for queued non-syn packet, dropping: " + packet);
     packet.releasePayload();
   }
 }
Пример #2
0
 /**
  * This sends a reset back to the place this packet came from. If the packet has no 'optional
  * from' or valid signature, this does nothing. This is not associated with a connection, so no
  * con stats are updated.
  */
 private void sendReset(Packet packet) {
   Destination from = packet.getOptionalFrom();
   if (from == null) return;
   boolean ok = packet.verifySignature(_context, from, null);
   if (!ok) {
     if (_log.shouldLog(Log.WARN))
       _log.warn("Can't send reset after recv spoofed packet: " + packet);
     return;
   }
   PacketLocal reply = new PacketLocal(_context, from);
   reply.setFlag(Packet.FLAG_RESET);
   reply.setFlag(Packet.FLAG_SIGNATURE_INCLUDED);
   reply.setSendStreamId(packet.getReceiveStreamId());
   reply.setReceiveStreamId(packet.getSendStreamId());
   reply.setOptionalFrom(_manager.getSession().getMyDestination());
   // this just sends the packet - no retries or whatnot
   _manager.getPacketQueue().enqueue(reply);
 }
Пример #3
0
 private void sendReset(Packet packet) {
   boolean ok = packet.verifySignature(_context, packet.getOptionalFrom(), null);
   if (!ok) {
     if (_log.shouldLog(Log.WARN))
       _log.warn("Received a spoofed SYN packet: they said they were " + packet.getOptionalFrom());
     return;
   }
   PacketLocal reply = new PacketLocal(_context, packet.getOptionalFrom());
   reply.setFlag(Packet.FLAG_RESET);
   reply.setFlag(Packet.FLAG_SIGNATURE_INCLUDED);
   reply.setAckThrough(packet.getSequenceNum());
   reply.setSendStreamId(packet.getReceiveStreamId());
   reply.setReceiveStreamId(0);
   reply.setOptionalFrom(_manager.getSession().getMyDestination());
   if (_log.shouldLog(Log.DEBUG)) _log.debug("Sending RST: " + reply + " because of " + packet);
   // this just sends the packet - no retries or whatnot
   _manager.getPacketQueue().enqueue(reply);
 }
Пример #4
0
  /**
   * We found a non-SYN packet that was queued in the syn queue, check to see if it has a home now,
   * else drop it ...
   */
  private void reReceivePacket(Packet packet) {
    Connection con = _manager.getConnectionByOutboundId(packet.getReceiveStreamId());
    if (con != null) {
      // Send it through the packet handler again
      if (_log.shouldLog(Log.WARN)) _log.warn("Found con for queued non-syn packet: " + packet);
      // false -> don't requeue, fixes a race where a SYN gets dropped
      // between here and PacketHandler, causing the packet to loop forever....
      _manager.getPacketHandler().receivePacketDirect(packet, false);
    } else {
      // log it here, just before we kill it - dest will be unknown
      if (I2PSocketManagerFull.pcapWriter != null
          && _context.getBooleanProperty(I2PSocketManagerFull.PROP_PCAP)) packet.logTCPDump(null);

      // goodbye
      if (_log.shouldLog(Log.WARN))
        _log.warn("Did not find con for queued non-syn packet, dropping: " + packet);
      packet.releasePayload();
    }
  }
Пример #5
0
 private void receivePong(Packet packet) {
   _manager.receivePong(packet.getReceiveStreamId());
 }
Пример #6
0
  private void receiveUnknownCon(Packet packet, long sendId, boolean queueIfNoConn) {
    if (packet.isFlagSet(Packet.FLAG_ECHO)) {
      if (packet.getSendStreamId() > 0) {
        if (_manager.answerPings()) receivePing(packet);
        else if (_log.shouldLog(Log.WARN))
          _log.warn("Dropping Echo packet on unknown con: " + packet);
      } else if (packet.getReceiveStreamId() > 0) {
        receivePong(packet);
      } else {
        if (_log.shouldLog(Log.WARN))
          _log.warn("Echo packet received with no stream IDs: " + packet);
      }
      packet.releasePayload();
    } else {
      if (_log.shouldLog(Log.WARN) && !packet.isFlagSet(Packet.FLAG_SYNCHRONIZE))
        _log.warn("Packet received on an unknown stream (and not an ECHO or SYN): " + packet);
      if (sendId <= 0) {
        Connection con = _manager.getConnectionByOutboundId(packet.getReceiveStreamId());
        if (con != null) {
          if ((con.getHighestAckedThrough() <= 5) && (packet.getSequenceNum() <= 5)) {
            if (_log.shouldLog(Log.WARN))
              _log.warn(
                  "Received additional packet w/o SendStreamID after the syn on "
                      + con
                      + ": "
                      + packet);
            receiveKnownCon(con, packet);
            return;
          } else {
            if (_log.shouldLog(Log.WARN))
              _log.warn(
                  "hrmph, received while ack of syn was in flight on "
                      + con
                      + ": "
                      + packet
                      + " acked: "
                      + con.getAckedPackets());
            // allow unlimited packets without a SendStreamID for now
            receiveKnownCon(con, packet);
            return;
          }
        }
      }

      if (packet.isFlagSet(Packet.FLAG_SYNCHRONIZE)) {
        // logTCPDump() will be called in ConnectionManager.receiveConnection(),
        // which is called by ConnectionHandler.receiveNewSyn(),
        // after we have a new conn, which makes the logging better.
        _manager.getConnectionHandler().receiveNewSyn(packet);
      } else if (queueIfNoConn) {
        // don't call logTCPDump() here, wait for it to find a conn

        // We can get here on the 2nd+ packet if the 1st (SYN) packet
        // is still on the _synQueue in the ConnectionHandler, and
        // ConnectionManager.receiveConnection() hasn't run yet to put
        // the StreamID on the getConnectionByOutboundId list.
        // Then the 2nd packet gets discarded and has to be retransmitted.
        //
        // We fix this by putting this packet on the syn queue too!
        // Then ConnectionHandler.accept() will check the connection list
        // and call receivePacket() above instead of receiveConnection().
        if (_log.shouldLog(Log.WARN)) {
          _log.warn("Packet belongs to no other cons, putting on the syn queue: " + packet);
        }
        if (_log.shouldLog(Log.DEBUG)) {
          StringBuilder buf = new StringBuilder(128);
          for (Connection con : _manager.listConnections()) {
            buf.append(con.toString()).append(" ");
          }
          _log.debug(
              "connections: "
                  + buf.toString()
                  + " sendId: "
                  + (sendId > 0 ? Packet.toId(sendId) : " unknown"));
        }
        // packet.releasePayload();
        _manager.getConnectionHandler().receiveNewSyn(packet);
      } else {
        // log it here, just before we kill it - dest will be unknown
        if (I2PSocketManagerFull.pcapWriter != null
            && _context.getBooleanProperty(I2PSocketManagerFull.PROP_PCAP)) packet.logTCPDump(null);
        // don't queue again (infinite loop!)
        sendReset(packet);
        packet.releasePayload();
      }
    }
  }
Пример #7
0
  private void receiveKnownCon(Connection con, Packet packet) {
    // is this ok here or does it need to be below each packetHandler().receivePacket() ?
    if (I2PSocketManagerFull.pcapWriter != null
        && _context.getBooleanProperty(I2PSocketManagerFull.PROP_PCAP)) packet.logTCPDump(con);
    if (packet.isFlagSet(Packet.FLAG_ECHO)) {
      if (packet.getSendStreamId() > 0) {
        if (con.getOptions().getAnswerPings()) receivePing(packet);
        else if (_log.shouldLog(Log.WARN))
          _log.warn("Dropping Echo packet on existing con: " + packet);
      } else if (packet.getReceiveStreamId() > 0) {
        receivePong(packet);
      } else {
        if (_log.shouldLog(Log.WARN))
          _log.warn("Echo packet received with no stream IDs: " + packet);
      }
      packet.releasePayload();
      return;
    }

    // the packet is pointed at a stream ID we're receiving on
    if (isValidMatch(con.getSendStreamId(), packet.getReceiveStreamId())) {
      // the packet's receive stream ID also matches what we expect
      // if (_log.shouldLog(Log.DEBUG))
      //    _log.debug("receive valid: " + packet);
      try {
        con.getPacketHandler().receivePacket(packet, con);
      } catch (I2PException ie) {
        if (_log.shouldLog(Log.WARN)) _log.warn("Received forged packet for " + con, ie);
      }
    } else {
      if (packet.isFlagSet(Packet.FLAG_RESET)) {
        // refused
        if (_log.shouldLog(Log.DEBUG)) _log.debug("receive reset: " + packet);
        try {
          con.getPacketHandler().receivePacket(packet, con);
        } catch (I2PException ie) {
          if (_log.shouldLog(Log.WARN)) _log.warn("Received forged reset for " + con, ie);
        }
      } else {
        if ((con.getSendStreamId() <= 0)
            || (con.getSendStreamId() == packet.getReceiveStreamId())
            || (packet.getSequenceNum()
                <= ConnectionOptions.MIN_WINDOW_SIZE)) { // its in flight from the first batch
          long oldId = con.getSendStreamId();
          if (packet.isFlagSet(Packet.FLAG_SYNCHRONIZE)) {
            if (oldId <= 0) {
              // con fully established, w00t
              con.setSendStreamId(packet.getReceiveStreamId());
            } else if (oldId == packet.getReceiveStreamId()) {
              // ok, as expected...
            } else {
              if (_log.shouldLog(Log.WARN))
                _log.warn("Received a syn with the wrong IDs, con=" + con + " packet=" + packet);
              sendReset(packet);
              packet.releasePayload();
              return;
            }
          }

          try {
            con.getPacketHandler().receivePacket(packet, con);
          } catch (I2PException ie) {
            if (_log.shouldLog(Log.ERROR))
              _log.error("Received forged packet for " + con + "/" + oldId + ": " + packet, ie);
            con.setSendStreamId(oldId);
          }
        } else if (packet.isFlagSet(Packet.FLAG_SYNCHRONIZE)) {
          if (_log.shouldLog(Log.WARN))
            _log.warn("Receive a syn packet with the wrong IDs, sending reset: " + packet);
          sendReset(packet);
          packet.releasePayload();
        } else {
          if (!con.getResetSent()) {
            // someone is sending us a packet on the wrong stream
            // It isn't a SYN so it isn't likely to have a FROM to send a reset back to
            if (_log.shouldLog(Log.ERROR)) {
              StringBuilder buf = new StringBuilder(512);
              buf.append("Received a packet on the wrong stream: ");
              buf.append(packet);
              buf.append("\nthis connection:\n");
              buf.append(con);
              buf.append("\nall connections:");
              for (Connection cur : _manager.listConnections()) {
                buf.append('\n').append(cur);
              }
              _log.error(buf.toString(), new Exception("Wrong stream"));
            }
          }
          packet.releasePayload();
        }
      }
    }
  }
Пример #8
0
  /**
   * Receive an incoming connection (built from a received SYN) Non-SYN packets with a zero
   * SendStreamID may also be queued here so that they don't get thrown away while the SYN packet
   * before it is queued.
   *
   * @param timeoutMs max amount of time to wait for a connection (if less than 1ms, wait
   *     indefinitely)
   * @return connection received, or null if there was a timeout or the handler was shut down
   */
  public Connection accept(long timeoutMs) {
    if (_log.shouldLog(Log.DEBUG)) _log.debug("Accept(" + timeoutMs + ") called");

    long expiration = timeoutMs + _context.clock().now();
    while (true) {
      if ((timeoutMs > 0) && (expiration < _context.clock().now())) return null;
      if (!_active) {
        // fail all the ones we had queued up
        while (true) {
          Packet packet = _synQueue.poll(); // fails immediately if empty
          if (packet == null || packet.getOptionalDelay() == PoisonPacket.POISON_MAX_DELAY_REQUEST)
            break;
          sendReset(packet);
        }
        return null;
      }

      Packet syn = null;
      while (_active && syn == null) {
        if (_log.shouldLog(Log.DEBUG))
          _log.debug(
              "Accept(" + timeoutMs + "): active=" + _active + " queue: " + _synQueue.size());
        if (timeoutMs <= 0) {
          try {
            syn = _synQueue.take(); // waits forever
          } catch (InterruptedException ie) {
          } // { break;}
        } else {
          long remaining = expiration - _context.clock().now();
          // (dont think this applies anymore for LinkedBlockingQueue)
          // BUGFIX
          // The specified amount of real time has elapsed, more or less.
          // If timeout is zero, however, then real time is not taken into consideration
          // and the thread simply waits until notified.
          if (remaining < 1) break;
          try {
            syn = _synQueue.poll(remaining, TimeUnit.MILLISECONDS); // waits the specified time max
          } catch (InterruptedException ie) {
          }
          break;
        }
      }

      if (syn != null) {
        if (syn.getOptionalDelay() == PoisonPacket.POISON_MAX_DELAY_REQUEST) return null;

        // deal with forged / invalid syn packets in _manager.receiveConnection()

        // Handle both SYN and non-SYN packets in the queue
        if (syn.isFlagSet(Packet.FLAG_SYNCHRONIZE)) {
          // We are single-threaded here, so this is
          // a good place to check for dup SYNs and drop them
          Destination from = syn.getOptionalFrom();
          if (from == null) {
            if (_log.shouldLog(Log.WARN)) _log.warn("Dropping SYN packet with no FROM: " + syn);
            // drop it
            continue;
          }
          Connection oldcon = _manager.getConnectionByOutboundId(syn.getReceiveStreamId());
          if (oldcon != null) {
            // His ID not guaranteed to be unique to us, but probably is...
            // only drop it on a destination match too
            if (from.equals(oldcon.getRemotePeer())) {
              if (_log.shouldLog(Log.WARN)) _log.warn("Dropping dup SYN: " + syn);
              continue;
            }
          }
          Connection con = _manager.receiveConnection(syn);
          if (con != null) return con;
        } else {
          reReceivePacket(syn);
          // ... and keep looping
        }
      }
      // keep looping...
    }
  }