int CTCPConnection::PacketReceived (const void *pPacket, unsigned nLength, CIPAddress &rSenderIP, int nProtocol) { if (nProtocol != IPPROTO_TCP) { return 0; } if (nLength < sizeof (TTCPHeader)) { return -1; } assert (pPacket != 0); TTCPHeader *pHeader = (TTCPHeader *) pPacket; if (m_nOwnPort != be2le16 (pHeader->nDestPort)) { return 0; } if (m_State != TCPStateListen) { if ( m_ForeignIP != rSenderIP || m_nForeignPort != be2le16 (pHeader->nSourcePort)) { return 0; } } else { if (!(pHeader->nDataOffsetFlags & TCP_FLAG_SYN)) { return 0; } m_Checksum.SetDestinationAddress (rSenderIP); } if (m_Checksum.Calculate (pPacket, nLength) != CHECKSUM_OK) { return 0; } u16 nFlags = pHeader->nDataOffsetFlags; u32 nDataOffset = TCP_DATA_OFFSET (pHeader->nDataOffsetFlags)*4; u32 nDataLength = nLength-nDataOffset; // Current Segment Variables u32 nSEG_SEQ = be2le32 (pHeader->nSequenceNumber); u32 nSEG_ACK = be2le32 (pHeader->nAcknowledgmentNumber); u32 nSEG_LEN = nDataLength; if (nFlags & TCP_FLAG_SYN) { nSEG_LEN++; } if (nFlags & TCP_FLAG_FIN) { nSEG_LEN++; } u32 nSEG_WND = be2le16 (pHeader->nWindow); //u16 nSEG_UP = be2le16 (pHeader->nUrgentPointer); //u32 nSEG_PRC; // segment precedence value ScanOptions (pHeader); #ifdef TCP_DEBUG CLogger::Get ()->Write (FromTCP, LogDebug, "rx %c%c%c%c%c%c, seq %u, ack %u, win %u, len %u", nFlags & TCP_FLAG_URGENT ? 'U' : '-', nFlags & TCP_FLAG_ACK ? 'A' : '-', nFlags & TCP_FLAG_PUSH ? 'P' : '-', nFlags & TCP_FLAG_RESET ? 'R' : '-', nFlags & TCP_FLAG_SYN ? 'S' : '-', nFlags & TCP_FLAG_FIN ? 'F' : '-', nSEG_SEQ-m_nIRS, nFlags & TCP_FLAG_ACK ? nSEG_ACK-m_nISS : 0, nSEG_WND, nDataLength); DumpStatus (); #endif boolean bAcceptable = FALSE; // RFC 793 section 3.9 "SEGMENT ARRIVES" switch (m_State) { case TCPStateClosed: if (nFlags & TCP_FLAG_RESET) { // ignore } else if (!(nFlags & TCP_FLAG_ACK)) { m_ForeignIP.Set (rSenderIP); m_nForeignPort = be2le16 (pHeader->nSourcePort); m_Checksum.SetDestinationAddress (rSenderIP); SendSegment (TCP_FLAG_RESET | TCP_FLAG_ACK, 0, nSEG_SEQ+nSEG_LEN); } else { m_ForeignIP.Set (rSenderIP); m_nForeignPort = be2le16 (pHeader->nSourcePort); m_Checksum.SetDestinationAddress (rSenderIP); SendSegment (TCP_FLAG_RESET, nSEG_ACK); } break; case TCPStateListen: if (nFlags & TCP_FLAG_RESET) { // ignore } else if (nFlags & TCP_FLAG_ACK) { m_ForeignIP.Set (rSenderIP); m_nForeignPort = be2le16 (pHeader->nSourcePort); m_Checksum.SetDestinationAddress (rSenderIP); SendSegment (TCP_FLAG_RESET, nSEG_ACK); } else if (nFlags & TCP_FLAG_SYN) { m_nRCV_NXT = nSEG_SEQ+1; m_nIRS = nSEG_SEQ; m_nSND_WND = nSEG_WND; m_nSND_WL1 = nSEG_SEQ; m_nSND_WL2 = nSEG_ACK; assert (nSEG_LEN > 0); if (nDataLength > 0) { m_RxQueue.Enqueue ((u8 *) pPacket+nDataOffset, nDataLength); } m_nISS = CalculateISN (); m_RTOCalculator.Initialize (m_nISS); m_ForeignIP.Set (rSenderIP); m_nForeignPort = be2le16 (pHeader->nSourcePort); m_Checksum.SetDestinationAddress (rSenderIP); SendSegment (TCP_FLAG_SYN | TCP_FLAG_ACK, m_nISS, m_nRCV_NXT); m_RTOCalculator.SegmentSent (m_nISS); m_nSND_NXT = m_nISS+1; m_nSND_UNA = m_nISS; NEW_STATE (TCPStateSynReceived); m_Event.Set (); } break; case TCPStateSynSent: if (nFlags & TCP_FLAG_ACK) { if (!bwh (m_nISS, nSEG_ACK, m_nSND_NXT)) { if (!(nFlags & TCP_FLAG_RESET)) { SendSegment (TCP_FLAG_RESET, nSEG_ACK); } return 1; } else if (bwlh (m_nSND_UNA, nSEG_ACK, m_nSND_NXT)) { bAcceptable = TRUE; } } if (nFlags & TCP_FLAG_RESET) { if (bAcceptable) { NEW_STATE (TCPStateClosed); m_bSendSYN = FALSE; m_nErrno = -1; m_Event.Set (); } break; } if ( (nFlags & TCP_FLAG_ACK) && !bAcceptable) { break; } if (nFlags & TCP_FLAG_SYN) { m_nRCV_NXT = nSEG_SEQ+1; m_nIRS = nSEG_SEQ; if (nFlags & TCP_FLAG_ACK) { m_RTOCalculator.SegmentAcknowledged (nSEG_ACK); if (nSEG_ACK-m_nSND_UNA > 1) { m_RetransmissionQueue.Advance (nSEG_ACK-m_nSND_UNA-1); } m_nSND_UNA = nSEG_ACK; } if (gt (m_nSND_UNA, m_nISS)) { NEW_STATE (TCPStateEstablished); m_bSendSYN = FALSE; StopTimer (TCPTimerRetransmission); // next transmission starts with this count m_nRetransmissionCount = MAX_RETRANSMISSIONS; m_Event.Set (); // RFC 1122 section 4.2.2.20 (c) m_nSND_WND = nSEG_WND; m_nSND_WL1 = nSEG_SEQ; m_nSND_WL2 = nSEG_ACK; SendSegment (TCP_FLAG_ACK, m_nSND_NXT, m_nRCV_NXT); if ( (nFlags & TCP_FLAG_FIN) // other controls? || nDataLength > 0) { goto StepSix; } break; } else { NEW_STATE (TCPStateSynReceived); m_bSendSYN = FALSE; SendSegment (TCP_FLAG_SYN | TCP_FLAG_ACK, m_nISS, m_nRCV_NXT); m_RTOCalculator.SegmentSent (m_nISS); m_nRetransmissionCount = MAX_RETRANSMISSIONS; StartTimer (TCPTimerRetransmission, m_RTOCalculator.GetRTO ()); if ( (nFlags & TCP_FLAG_FIN) // other controls? || nDataLength > 0) { if (nFlags & TCP_FLAG_FIN) { SendSegment (TCP_FLAG_RESET, m_nSND_NXT); NEW_STATE (TCPStateClosed); } if (nDataLength > 0) { m_RxQueue.Enqueue ((u8 *) pPacket+nDataOffset, nDataLength); } break; } } } break; case TCPStateSynReceived: case TCPStateEstablished: case TCPStateFinWait1: case TCPStateFinWait2: case TCPStateCloseWait: case TCPStateClosing: case TCPStateLastAck: case TCPStateTimeWait: // step 1 ( check sequence number) if (m_nRCV_WND > 0) { if (nSEG_LEN == 0) { if (bwl (m_nRCV_NXT, nSEG_SEQ, m_nRCV_NXT+m_nRCV_WND)) { bAcceptable = TRUE; } } else { if ( bwl (m_nRCV_NXT, nSEG_SEQ, m_nRCV_NXT+m_nRCV_WND) || bwl (m_nRCV_NXT, nSEG_SEQ+nSEG_LEN-1, m_nRCV_NXT+m_nRCV_WND)) { bAcceptable = TRUE; } } } else { if (nSEG_LEN == 0) { if (nSEG_SEQ == m_nRCV_NXT) { bAcceptable = TRUE; } } } if ( !bAcceptable && m_State != TCPStateSynReceived) { SendSegment (TCP_FLAG_ACK, m_nSND_NXT, m_nRCV_NXT); break; } // step 2 (check RST bit) if (nFlags & TCP_FLAG_RESET) { switch (m_State) { case TCPStateSynReceived: m_RetransmissionQueue.Flush (); if (!m_bActiveOpen) { NEW_STATE (TCPStateListen); return 1; } else { m_nErrno = -1; NEW_STATE (TCPStateClosed); m_Event.Set (); return 1; } break; case TCPStateEstablished: case TCPStateFinWait1: case TCPStateFinWait2: case TCPStateCloseWait: m_nErrno = -1; m_RetransmissionQueue.Flush (); m_TxQueue.Flush (); m_RxQueue.Flush (); NEW_STATE (TCPStateClosed); m_Event.Set (); return 1; case TCPStateClosing: case TCPStateLastAck: case TCPStateTimeWait: NEW_STATE (TCPStateClosed); m_Event.Set (); return 1; default: UNEXPECTED_STATE (); return 1; } } // step 3 (check security and precedence, not supported) // step 4 (check SYN bit) if (nFlags & TCP_FLAG_SYN) { // RFC 1122 section 4.2.2.20 (e) if ( m_State == TCPStateSynReceived && !m_bActiveOpen) { NEW_STATE (TCPStateListen); return 1; } SendSegment (TCP_FLAG_RESET, m_nSND_NXT); m_nErrno = -1; m_RetransmissionQueue.Flush (); m_TxQueue.Flush (); m_RxQueue.Flush (); NEW_STATE (TCPStateClosed); m_Event.Set (); return 1; } // step 5 (check ACK field) if (!(nFlags & TCP_FLAG_ACK)) { return 1; } switch (m_State) { case TCPStateSynReceived: if (bwlh (m_nSND_UNA, nSEG_ACK, m_nSND_NXT)) { // RFC 1122 section 4.2.2.20 (f) m_nSND_WND = nSEG_WND; m_nSND_WL1 = nSEG_SEQ; m_nSND_WL2 = nSEG_ACK; m_nSND_UNA = nSEG_ACK; // got ACK for SYN m_RTOCalculator.SegmentAcknowledged (nSEG_ACK); NEW_STATE (TCPStateEstablished); // next transmission starts with this count m_nRetransmissionCount = MAX_RETRANSMISSIONS; } else { SendSegment (TCP_FLAG_RESET, nSEG_ACK); } break; case TCPStateEstablished: case TCPStateFinWait1: case TCPStateFinWait2: case TCPStateCloseWait: case TCPStateClosing: if (bwh (m_nSND_UNA, nSEG_ACK, m_nSND_NXT)) { m_RTOCalculator.SegmentAcknowledged (nSEG_ACK); unsigned nBytesAck = nSEG_ACK-m_nSND_UNA; m_nSND_UNA = nSEG_ACK; if (nSEG_ACK == m_nSND_NXT) // all segments are acknowledged { StopTimer (TCPTimerRetransmission); // next transmission starts with this count m_nRetransmissionCount = MAX_RETRANSMISSIONS; m_Event.Set (); } if ( m_State == TCPStateFinWait1 || m_State == TCPStateClosing) { nBytesAck--; // acknowledged FIN does not count m_bFINQueued = FALSE; } if ( m_State == TCPStateEstablished && nBytesAck == 1) { nBytesAck--; } if (nBytesAck > 0) { m_RetransmissionQueue.Advance (nBytesAck); } // update send window if ( lt (m_nSND_WL1, nSEG_SEQ) || ( m_nSND_WL1 == nSEG_SEQ && le (m_nSND_WL2, nSEG_ACK))) { m_nSND_WND = nSEG_WND; m_nSND_WL1 = nSEG_SEQ; m_nSND_WL2 = nSEG_ACK; } } else if (le (nSEG_ACK, m_nSND_UNA)) // RFC 1122 section 4.2.2.20 (g) { // ignore duplicate ACK ... // RFC 1122 section 4.2.2.20 (g) if (bwlh (m_nSND_UNA, nSEG_ACK, m_nSND_NXT)) { // ... but update send window if ( lt (m_nSND_WL1, nSEG_SEQ) || ( m_nSND_WL1 == nSEG_SEQ && le (m_nSND_WL2, nSEG_ACK))) { m_nSND_WND = nSEG_WND; m_nSND_WL1 = nSEG_SEQ; m_nSND_WL2 = nSEG_ACK; } } } else if (gt (nSEG_ACK, m_nSND_NXT)) { SendSegment (TCP_FLAG_ACK, m_nSND_NXT, m_nRCV_NXT); return 1; } switch (m_State) { case TCPStateEstablished: case TCPStateCloseWait: break; case TCPStateFinWait1: if (nSEG_ACK == m_nSND_NXT) // if our FIN is now acknowledged { m_RTOCalculator.SegmentAcknowledged (nSEG_ACK); m_bFINQueued = FALSE; StopTimer (TCPTimerRetransmission); NEW_STATE (TCPStateFinWait2); } else { break; } // fall through case TCPStateFinWait2: if (m_RetransmissionQueue.IsEmpty ()) { m_Event.Set (); } break; case TCPStateClosing: if (nSEG_ACK == m_nSND_NXT) // if our FIN is now acknowledged { m_RTOCalculator.SegmentAcknowledged (nSEG_ACK); m_bFINQueued = FALSE; StopTimer (TCPTimerRetransmission); NEW_STATE (TCPStateTimeWait); StartTimer (TCPTimerTimeWait, HZ_TIMEWAIT); } break; default: UNEXPECTED_STATE (); break; } break; case TCPStateLastAck: if (nSEG_ACK == m_nSND_NXT) // if our FIN is now acknowledged { m_bFINQueued = FALSE; NEW_STATE (TCPStateClosed); m_Event.Set (); return 1; } break; case TCPStateTimeWait: if (nSEG_ACK == m_nSND_NXT) // if our FIN is now acknowledged { m_bFINQueued = FALSE; SendSegment (TCP_FLAG_ACK, m_nSND_NXT, m_nRCV_NXT); StartTimer (TCPTimerTimeWait, HZ_TIMEWAIT); } break; default: UNEXPECTED_STATE (); break; } // step 6 (check URG bit, not supported) StepSix: // step 7 (process text segment) if (nSEG_LEN == 0) { return 1; } switch (m_State) { case TCPStateEstablished: case TCPStateFinWait1: case TCPStateFinWait2: if (nSEG_SEQ == m_nRCV_NXT) { if (nDataLength > 0) { m_RxQueue.Enqueue ((u8 *) pPacket+nDataOffset, nDataLength); m_nRCV_NXT += nDataLength; // m_nRCV_WND should be adjusted here (section 3.7) // following ACK could be piggybacked with data SendSegment (TCP_FLAG_ACK, m_nSND_NXT, m_nRCV_NXT); if (nFlags & TCP_FLAG_PUSH) { m_Event.Set (); } } } else { SendSegment (TCP_FLAG_ACK, m_nSND_NXT, m_nRCV_NXT); } break; case TCPStateCloseWait: case TCPStateClosing: case TCPStateLastAck: case TCPStateTimeWait: break; default: UNEXPECTED_STATE (); break; } // step 8 (check FIN bit) if ( m_State == TCPStateClosed || m_State == TCPStateListen || m_State == TCPStateSynSent) { return 1; } if (!(nFlags & TCP_FLAG_FIN)) { return 1; } // connection is closing m_nRCV_NXT++; SendSegment (TCP_FLAG_ACK, m_nSND_NXT, m_nRCV_NXT); switch (m_State) { case TCPStateSynReceived: case TCPStateEstablished: NEW_STATE (TCPStateCloseWait); m_Event.Set (); break; case TCPStateFinWait1: if (nSEG_ACK == m_nSND_NXT) // if our FIN is now acknowledged { m_bFINQueued = FALSE; StopTimer (TCPTimerRetransmission); StopTimer (TCPTimerUser); NEW_STATE (TCPStateTimeWait); StartTimer (TCPTimerTimeWait, HZ_TIMEWAIT); } else { NEW_STATE (TCPStateClosing); } break; case TCPStateFinWait2: StopTimer (TCPTimerRetransmission); StopTimer (TCPTimerUser); NEW_STATE (TCPStateTimeWait); StartTimer (TCPTimerTimeWait, HZ_TIMEWAIT); break; case TCPStateCloseWait: case TCPStateClosing: case TCPStateLastAck: break; case TCPStateTimeWait: StartTimer (TCPTimerTimeWait, HZ_TIMEWAIT); break; default: UNEXPECTED_STATE (); break; } break; } return 1; }
int CTCPRejector::PacketReceived (const void *pPacket, unsigned nLength, CIPAddress &rSenderIP, CIPAddress &rReceiverIP, int nProtocol) { if (nProtocol != IPPROTO_TCP) { return 0; } if (nLength < sizeof (TTCPHeader)) { return -1; } assert (pPacket != 0); TTCPHeader *pHeader = (TTCPHeader *) pPacket; m_nOwnPort = be2le16 (pHeader->nDestPort); if (m_nOwnPort == 0) { return -1; } assert (m_pNetConfig != 0); if (m_pNetConfig->GetIPAddress ()->IsNull ()) { return 0; } m_Checksum.SetSourceAddress (*m_pNetConfig->GetIPAddress ()); m_Checksum.SetDestinationAddress (rSenderIP); if (m_Checksum.Calculate (pPacket, nLength) != CHECKSUM_OK) { return 0; } u16 nFlags = pHeader->nDataOffsetFlags; u32 nDataOffset = TCP_DATA_OFFSET (pHeader->nDataOffsetFlags)*4; u32 nDataLength = nLength-nDataOffset; // Current Segment Variables u32 nSEG_SEQ = be2le32 (pHeader->nSequenceNumber); u32 nSEG_ACK = be2le32 (pHeader->nAcknowledgmentNumber); u32 nSEG_LEN = nDataLength; if (nFlags & TCP_FLAG_SYN) { nSEG_LEN++; } if (nFlags & TCP_FLAG_FIN) { nSEG_LEN++; } #ifdef TCP_DEBUG u32 nSEG_WND = be2le16 (pHeader->nWindow); CLogger::Get ()->Write (FromTCP, LogDebug, "rx %c%c%c%c%c%c, seq %u, ack %u, win %u, len %u", nFlags & TCP_FLAG_URGENT ? 'U' : '-', nFlags & TCP_FLAG_ACK ? 'A' : '-', nFlags & TCP_FLAG_PUSH ? 'P' : '-', nFlags & TCP_FLAG_RESET ? 'R' : '-', nFlags & TCP_FLAG_SYN ? 'S' : '-', nFlags & TCP_FLAG_FIN ? 'F' : '-', nSEG_SEQ, nFlags & TCP_FLAG_ACK ? nSEG_ACK : 0, nSEG_WND, nDataLength); #endif m_ForeignIP.Set (rSenderIP); m_nForeignPort = be2le16 (pHeader->nSourcePort); if (nFlags & TCP_FLAG_RESET) { // ignore } else if (!(nFlags & TCP_FLAG_ACK)) { SendSegment (TCP_FLAG_RESET | TCP_FLAG_ACK, 0, nSEG_SEQ+nSEG_LEN); } else { SendSegment (TCP_FLAG_RESET, nSEG_ACK); } return 1; }