Jelajahi Sumber

Invalid Login requests during full feature phase is now properly rejected,

Login request during full feature phase is now properly rejected.
Any PDU other than Login request is now properly rejected during the
login phase once the login phase has started.
Tal Aloni 8 tahun lalu
induk
melakukan
b4049f00dc
1 mengubah file dengan 66 tambahan dan 35 penghapusan
  1. 66 35
      ISCSI/Server/ISCSIServer.cs

+ 66 - 35
ISCSI/Server/ISCSIServer.cs

@@ -328,56 +328,70 @@ namespace ISCSI.Server
                 }
             }
 
-            if (pdu is LoginRequestPDU)
+            if (!state.SessionParameters.IsFullFeaturePhase)
             {
-                LoginRequestPDU request = (LoginRequestPDU)pdu;
-                Log("[{0}][ReceiveCallback] Login Request, current stage: {1}, next stage: {2}, parameters: {3}", state.ConnectionIdentifier, request.CurrentStage, request.NextStage, KeyValuePairUtils.ToString(request.LoginParameters));
-                if (request.TSIH != 0)
+                if (pdu is LoginRequestPDU)
                 {
-                    // RFC 3720: A Login Request with a non-zero TSIH and a CID equal to that of an existing
-                    // connection implies a logout of the connection followed by a Login
-                    lock (m_activeConnections)
+                    LoginRequestPDU request = (LoginRequestPDU)pdu;
+                    Log("[{0}][ReceiveCallback] Login Request, current stage: {1}, next stage: {2}, parameters: {3}", state.ConnectionIdentifier, request.CurrentStage, request.NextStage, KeyValuePairUtils.ToString(request.LoginParameters));
+                    if (request.TSIH != 0)
                     {
-                        int existingConnectionIndex = GetStateObjectIndex(m_activeConnections, request.ISID, request.TSIH, request.CID);
-                        if (existingConnectionIndex >= 0)
+                        // RFC 3720: A Login Request with a non-zero TSIH and a CID equal to that of an existing
+                        // connection implies a logout of the connection followed by a Login
+                        lock (m_activeConnections)
                         {
-                            // Perform implicit logout
-                            Log("[{0}][ProcessPDU] Initiating implicit logout", state.ConnectionIdentifier);
-                            SocketUtils.ReleaseSocket(m_activeConnections[existingConnectionIndex].ClientSocket);
-                            if (m_activeConnections[existingConnectionIndex].Target != null)
+                            int existingConnectionIndex = GetStateObjectIndex(m_activeConnections, request.ISID, request.TSIH, request.CID);
+                            if (existingConnectionIndex >= 0)
                             {
-                                lock (m_activeConnections[existingConnectionIndex].Target.IOLock)
+                                // Perform implicit logout
+                                Log("[{0}][ProcessPDU] Initiating implicit logout", state.ConnectionIdentifier);
+                                SocketUtils.ReleaseSocket(m_activeConnections[existingConnectionIndex].ClientSocket);
+                                if (m_activeConnections[existingConnectionIndex].Target != null)
                                 {
-                                    // Wait for pending I/O to complete.
+                                    lock (m_activeConnections[existingConnectionIndex].Target.IOLock)
+                                    {
+                                        // Wait for pending I/O to complete.
+                                    }
                                 }
+                                m_activeConnections.RemoveAt(existingConnectionIndex);
+                                Log("[{0}][ProcessPDU] Implicit logout completed", state.ConnectionIdentifier);
                             }
-                            m_activeConnections.RemoveAt(existingConnectionIndex);
-                            Log("[{0}][ProcessPDU] Implicit logout completed", state.ConnectionIdentifier);
                         }
                     }
+                    LoginResponsePDU response = ServerResponseHelper.GetLoginResponsePDU(request, m_targets, state.SessionParameters, state.ConnectionParameters, ref state.Target, GetNextTSIH);
+                    if (state.SessionParameters.IsFullFeaturePhase)
+                    {
+                        state.SessionParameters.ISID = request.ISID;
+                        state.ConnectionParameters.CID = request.CID;
+                        lock (m_activeConnections)
+                        {
+                            m_activeConnections.Add(state);
+                        }
+                    }
+                    Log("[{0}][ReceiveCallback] Login Response parameters: {1}", state.ConnectionIdentifier, KeyValuePairUtils.ToString(response.LoginParameters));
+                    TrySendPDU(state, response);
                 }
-                LoginResponsePDU response = ServerResponseHelper.GetLoginResponsePDU(request, m_targets, state.SessionParameters, state.ConnectionParameters, ref state.Target, GetNextTSIH);
-                if (state.SessionParameters.IsFullFeaturePhase)
+                else
                 {
-                    state.SessionParameters.ISID = request.ISID;
-                    state.ConnectionParameters.CID = request.CID;
-                    lock (m_activeConnections)
+                    // Before the Full Feature Phase is established, only Login Request and Login Response PDUs are allowed.
+                    Log("[{0}][ProcessPDU] Improper command during login phase, OpCode: 0x{1}", state.ConnectionIdentifier, pdu.OpCode.ToString("x"));
+                    if (state.SessionParameters.TSIH == 0)
+                    {
+                        // A target receiving any PDU except a Login request before the Login phase is started MUST
+                        // immediately terminate the connection on which the PDU was received.
+                        clientSocket.Close();
+                    }
+                    else
                     {
-                        m_activeConnections.Add(state);
+                        // Once the Login phase has started, if the target receives any PDU except a Login request,
+                        // it MUST send a Login reject (with Status "invalid during login") and then disconnect.
+                        LoginResponsePDU loginResponse = new LoginResponsePDU();
+                        loginResponse.TSIH = state.SessionParameters.TSIH;
+                        loginResponse.Status = LoginResponseStatusName.InvalidDuringLogon;
+                        TrySendPDU(state, loginResponse);
+                        clientSocket.Close();
                     }
                 }
-                Log("[{0}][ReceiveCallback] Login Response parameters: {1}", state.ConnectionIdentifier, KeyValuePairUtils.ToString(response.LoginParameters));
-                TrySendPDU(state, response);
-            }
-            else if (!state.SessionParameters.IsFullFeaturePhase)
-            {
-                // Before the Full Feature Phase is established, only Login Request and Login Response PDUs are allowed.
-                Log("[{0}][ProcessPDU] Improper command during login phase, OpCode: 0x{1}", state.ConnectionIdentifier, pdu.OpCode.ToString("x"));
-                // A target receiving any PDU except a Login request before the Login phase is started MUST
-                // immediately terminate the connection on which the PDU was received.
-                // Once the Login phase has started, if the target receives any PDU except a Login request,
-                // it MUST send a Login reject (with Status "invalid during login") and then disconnect.
-                clientSocket.Close();
             }
             else // Logged in
             {
@@ -452,9 +466,26 @@ namespace ISCSI.Server
                         }
                     }
                 }
+                else if (pdu is LoginRequestPDU)
+                {
+                    Log("[{0}][ProcessPDU] Protocol Error (Login request during full feature phase)", state.ConnectionIdentifier);
+                    // RFC 3720: Login requests and responses MUST be used exclusively during Login.
+                    // On any connection, the login phase MUST immediately follow TCP connection establishment and
+                    // a subsequent Login Phase MUST NOT occur before tearing down a connection
+                    RejectPDU reject = new RejectPDU();
+                    reject.Reason = RejectReason.ProtocolError;
+                    reject.Data = ByteReader.ReadBytes(pdu.GetBytes(), 0, 48);
+
+                    TrySendPDU(state, reject);
+                }
                 else
                 {
                     Log("[{0}][ProcessPDU] Unsupported command, OpCode: 0x{1}", state.ConnectionIdentifier, pdu.OpCode.ToString("x"));
+                    RejectPDU reject = new RejectPDU();
+                    reject.Reason = RejectReason.CommandNotSupported;
+                    reject.Data = ByteReader.ReadBytes(pdu.GetBytes(), 0, 48);
+
+                    TrySendPDU(state, reject);
                 }
             }
         }