Main Page | Class Hierarchy | Alphabetical List | Class List | File List | Class Members

pana_paa_factory.cxx

00001 /* BEGIN_COPYRIGHT                                                        */
00002 /*                                                                        */
00003 /* Open Diameter: Open-source software for the Diameter and               */
00004 /*                Diameter related protocols                              */
00005 /*                                                                        */
00006 /* Copyright (C) 2002-2004 Open Diameter Project                          */
00007 /*                                                                        */
00008 /* This library is free software; you can redistribute it and/or modify   */
00009 /* it under the terms of the GNU Lesser General Public License as         */
00010 /* published by the Free Software Foundation; either version 2.1 of the   */
00011 /* License, or (at your option) any later version.                        */
00012 /*                                                                        */
00013 /* This library is distributed in the hope that it will be useful,        */
00014 /* but WITHOUT ANY WARRANTY; without even the implied warranty of         */
00015 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU      */
00016 /* Lesser General Public License for more details.                        */
00017 /*                                                                        */
00018 /* You should have received a copy of the GNU Lesser General Public       */
00019 /* License along with this library; if not, write to the Free Software    */
00020 /* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307    */
00021 /* USA.                                                                   */
00022 /*                                                                        */
00023 /* In addition, when you copy and redistribute some or the entire part of */
00024 /* the source code of this software with or without modification, you     */
00025 /* MUST include this copyright notice in each copy.                       */
00026 /*                                                                        */
00027 /* If you make any changes that are appeared to be useful, please send    */
00028 /* sources that include the changed part to                               */
00029 /* diameter-developers@lists.sourceforge.net so that we can reflect your  */
00030 /* changes to one unified version of this software.                       */
00031 /*                                                                        */
00032 /* END_COPYRIGHT                                                          */
00033 
00034 #include "pana_session.h"
00035 #include "pana_paa_factory.h"
00036 #include "pana_database.h"
00037 #include "pana_cookie.h"
00038 #include "pana_serial_num.h"
00039 #include "pana_config_manager.h"
00040 #include "pana_sid_generator.h"
00041 
00042 void PANA_PaaSessionFactory::Receive(PANA_Message &msg)
00043 {
00044    // first level validation
00045    AAAAvpContainer* c_sessionId = msg.avpList().search("Session-Id");
00046    if (! c_sessionId) {
00047       if (msg.flags().request) {
00048          throw (PANA_Exception(PANA_Exception::INVALID_MESSAGE, 
00049                             "server received invalid request message"));
00050       }
00051       switch (msg.type()) {
00052          case PANA_MTYPE_DISCOVER: ReceiveDiscover(msg);    break;
00053          case PANA_MTYPE_START:    ReceiveStartAnswer(msg); break;
00054          default:
00055             throw (PANA_Exception(PANA_Exception::ENTRY_NOT_FOUND, 
00056                                  "Session Id AVP not found in packet, discarding message"));
00057       }
00058       return;
00059    }
00060    diameter_utf8string_t &sessionId = (*c_sessionId)
00061              [0]->dataRef(Type2Type<diameter_utf8string_t>());
00062 
00063    // session lookup and message reception
00064    PANA_PaaSession *session = PANA_SESSIONDB_SEARCH(sessionId);
00065    if (session) {
00066       session->Receive(msg);
00067       return;
00068    }
00069    throw (PANA_Exception(PANA_Exception::ENTRY_NOT_FOUND, 
00070                         "Session not found in the database, discarding message"));
00071 }
00072 
00073 void PANA_PaaSessionFactory::Error(int err)
00074 {
00075     ACE_DEBUG((LM_INFO, "(%P|%t) Server receive error handler, error=%s\n", 
00076                ACE_OS_String::strerror(err)));
00077 
00078     // TBD:: recurse through entire tree and submitt error
00079 }
00080 
00081 void PANA_PaaSessionFactory::ReceiveDiscover(PANA_Message &msg)
00082 {
00083    /* Draft 2 notes:
00084 
00085        PaC      PAA         Message 
00086        ------------------------------------------------------ 
00087        ----->            PANA-PAA-Discover(0,0) 
00088        <-----            PANA-Start-Request(x,0)[Cookie] 
00089        ----->            PANA-Start-Answer(x,y)[ Cookie] 
00090                          (continued to authentication phase) 
00091    */
00092 
00093    // validate sequence number
00094    if (msg.tseq() != 0 || msg.rseq() != 0) {
00095       throw (PANA_Exception(PANA_Exception::INVALID_MESSAGE, 
00096                            "Rseq or Tseq field of discover message is non-zero"));
00097    }
00098 
00099    PANA_DeviceId *ipId = msg.srcDevices().search(PANA_DeviceId::IPV4_ADDRESS);
00100    if (ipId == NULL) {
00101        throw (PANA_Exception(PANA_Exception::INVALID_MESSAGE, 
00102               "Cannot determine the device ID of peer"));
00103    }
00104    
00105    // extract device id if any and verify
00106    AAAAvpContainer *c_deviceId = msg.avpList().search("Device-Id");
00107    if (c_deviceId) {
00108        PANA_TVData_t &deviceId = (*c_deviceId)[0]->dataRef
00109            (Type2Type<PANA_TVData_t>());
00110        if (deviceId.type == ipId->type()) {
00111            if (ACE_OS::memcmp(deviceId.value.data(), ipId->id().data(),
00112                               deviceId.value.size())) {
00113               throw (PANA_Exception(PANA_Exception::INVALID_MESSAGE, 
00114                      "Device ID AVP value does not match device id of packet"));
00115            }
00116        }
00117    }
00118 
00119    if (PANA_CONFIG_AUTHAGENT().use_cookie_) {
00120        
00121        ACE_DEBUG((LM_INFO, "(%P|%t) RECV: Discover [stateless], S-flag %d, tseq=%d, rseq=%d\n",
00122                  msg.flags().separate, msg.tseq(), msg.rseq()));
00123 
00124        // generate cookie
00125        diameter_octetstring_t cookie;
00126        PANA_COOKIE_GENERATE(const_cast<std::string&>(ipId->id()),
00127                             cookie);
00128 
00129        SendStartRequest(msg, cookie);
00130    }
00131    else {
00132        
00133        // create and add a new session and add
00134        // to pending database use the device ID
00135        // as initial index
00136        PANA_PaaSession *session = Create();
00137        if (session == NULL) {
00138           throw (PANA_Exception(PANA_Exception::NO_MEMORY, 
00139                                "Failed to auth agent session"));
00140        }
00141 
00142        ACE_DEBUG((LM_INFO, "(%P|%t) New session created [stateful discovery]\n"));
00143    
00144        m_PendingDb.Add(const_cast<std::string&>(ipId->id()),
00145                        *session);
00146        session->Receive(msg);
00147    }
00148 }
00149 
00150 void PANA_PaaSessionFactory::SendStartRequest(PANA_Message &discover, 
00151                                        diameter_octetstring_t &cookie)
00152 {
00153    /*    
00154       A PANA-Start-Request message MAY carry a Cookie AVP that contains a
00155       cookie.  The rseq field of the header is set to zero (0).  The tseq
00156       field of the header contains the initial sequence number.  The cookie
00157       is used for preventing the PAA from resource consumption DoS attacks
00158       by blind attackers. The cookie is computed in such a way that it does
00159       not require any per-session state maintenance on the PAA in order to
00160       verify the cookie returned in a PANA-Start-Answer message. The exact
00161       algorithms and syntax used for generating cookies does not affect
00162       interoperability and hence is not specified here.  An example
00163       algorithm is described below.
00164 
00165       Cookie =
00166         <secret-version> | HMAC_SHA1( <Device-Id of PaC> | <secret> )
00167 
00168       where <secret> is a randomly generated secret known only to the PAA,
00169       <secret-version> is an index used for choosing the secret for
00170       generating the cookie and '|' indicates concatenation.  The secret-
00171       version should be changed frequently enough to prevent replay
00172       attacks. The secret key is locally known to the PAA only and valid
00173       for a certain time frame.
00174 
00175       PAA MAY enable NAP-ISP authentication separation by setting the
00176       S-flag of the message header of the PANA-Start-Request. Also, the
00177       PANA-Start-Request MAY contain zero or one NAP-Information AVP and
00178       zero or more ISP-Information AVPs to advertise the information on the
00179       NAP and/or ISPs.
00180 
00181        9.3.3 PANA-Start-Request (PSR)
00182 
00183          PANA-Start-Request (PSR) is sent by the PAA to the PaC. The PAA sets
00184          the transmission sequence number to an initial random value.  The
00185          received sequence number is set to zero (0).
00186 
00187               PANA-Start-Request ::= < PANA-Header: 2, REQ [SEP] >
00188                             [ Cookie ]
00189                             [ EAP-Payload ]
00190                             [ NAP-Information ]
00191                          *  [ ISP-Information ]
00192                          *  [ AVP ]
00193     */
00194 
00195    AAAAvpContainerManager cm;
00196    AAAAvpContainerEntryManager em;
00197    PANA_Message *msg;
00198 
00199    ACE_NEW_NORETURN(msg, PANA_Message);
00200    if (msg == NULL) {
00201       throw (PANA_Exception(PANA_Exception::NO_MEMORY, 
00202                             "Failed to allocate msg message"));
00203    }
00204 
00205    // Populate header
00206    PANA_MsgHeader::Flags flg = { 1, 0, 0, 0 };
00207    msg->flags(flg);
00208    msg->type(PANA_MTYPE_START);
00209    msg->tseq(PANA_SerialNumber::generateIsn());
00210    msg->rseq(0);
00211 
00212    // Calculate S-flag
00213    msg->flags().separate = PANA_CONFIG_AUTHAGENT().s_flag_;
00214 
00215    // Populate Cookie AVP if necessary
00216    AAAAvpContainerEntry *e;
00217    if (cookie.size() > 0) {
00218 
00219       AAAAvpContainer *c_cookie = cm.acquire("Cookie");
00220 
00221       // Add the AVP's to containers
00222       e = em.acquire(AAA_AVPDataType(AAA_AVP_STRING_TYPE));
00223       diameter_octetstring_t &ck = e->dataRef(Type2Type<diameter_octetstring_t>());
00224       c_cookie->add(e);
00225 
00226       // Add containers to list
00227       msg->avpList().add(c_cookie);
00228 
00229       // Populate cookie
00230       ck.assign(cookie.data(), cookie.size());
00231    }
00232    else {
00233       throw (PANA_Exception(PANA_Exception::NO_MEMORY, 
00234                             "Invalid cookie generated"));
00235    }
00236 
00237    // Populate NAP-Information 
00238    PANA_ProviderInfoTool infoTool;
00239    PANA_CfgProviderInfo *pInfo = &PANA_CONFIG_AUTHAGENT().nap_info_;
00240    if (pInfo->name_.length() > 0) {
00241 
00242       // Add the AVP's to containers
00243       AAAAvpContainer *c_napInfo = cm.acquire("NAP-Information");        
00244       e = em.acquire(AAA_AVP_GROUPED_TYPE);
00245       diameter_grouped_t &napInfo = e->dataRef(Type2Type<diameter_grouped_t>());
00246       c_napInfo->add(e);
00247 
00248       // Add containers to list and populate
00249       msg->avpList().add(c_napInfo);
00250       infoTool.Add(napInfo, *pInfo);
00251    }
00252    else {
00253       throw (PANA_Exception(PANA_Exception::NO_MEMORY, 
00254                             "NAP Information missing"));
00255    }
00256 
00257    // See if there is also ISP-Info
00258    PANA_CfgProviderList &ispList = PANA_CONFIG_AUTHAGENT().isp_info_;
00259    if (ispList.size() > 0) {
00260 
00261       // Add containers to message
00262       AAAAvpContainer *c_ispInfo = cm.acquire("ISP-Information");        
00263       msg->avpList().add(c_ispInfo);
00264 
00265       PANA_CfgProviderList::iterator i;
00266       for (i = ispList.begin(); i != ispList.end(); i ++) {
00267 
00268          pInfo = (*i);
00269 
00270          // Add the AVP's to containers
00271          e = em.acquire(AAA_AVP_GROUPED_TYPE);
00272          diameter_grouped_t &ispInfo = e->dataRef(Type2Type<diameter_grouped_t>());
00273          c_ispInfo->add(e);
00274 
00275          // Add containers to list and populate
00276          PANA_ProviderInfoTool info;
00277          info.Add(ispInfo, *pInfo);
00278       }
00279    }
00280 
00281    // Retrieve source devices and send back to Pac
00282    PANA_DeviceId *ipId = discover.srcDevices().search(PANA_DeviceId::IPV4_ADDRESS);
00283    msg->srcDevices().move(discover.srcDevices(), *ipId);
00284 
00285    // Carry over the destination port from source message
00286    msg->srcPort(discover.srcPort());
00287 
00288    m_UdpChannel.Send(*msg);
00289 
00290    ACE_DEBUG((LM_INFO, "(%P|%t) SEND: Start-Request, tseq=%d, rseq=%d\n",
00291               msg->tseq(), msg->rseq()));
00292 }
00293 
00294 void PANA_PaaSessionFactory::ReceiveStartAnswer(PANA_Message &msg)
00295 {
00296    /* 
00297       When the PAA receives the PANA-Start-Answer message from the PaC, it
00298       verifies the cookie.  The cookie is considered as valid if the
00299       received cookie has the expected value.  If the computed cookie is
00300       valid, the protocol enters the authentication phase.  Otherwise, it
00301       MUST silently discard the received message.
00302 
00303       When a Cookie-AVP is carried in a PANA-Start-Request message, the
00304       initial EAP Request MUST NOT be carried in the PANA-Start-Request
00305       message in order for the PAA to be stateless.
00306 
00307       When a Cookie-AVP is not carried in a PANA-Start-Request message, the
00308       PAA does not need to be stateless.  In this case, the initial EAP
00309       Request message MAY be carried in the PANA-Start-Request message.
00310 
00311       If the initial EAP Request message is carried in the
00312       PANA-Start-Request message, an EAP Response message MUST be carried
00313       in the PANA-Start-Answer message returned to the PAA.
00314 
00315       In any case, PANA MUST NOT generate an EAP message on behalf of EAP
00316       peer or EAP (pass-through) authenticator.
00317 
00318       The PANA-Start-Request/Answer exchange is needed before entering
00319       authentication phase even when the PaC is pre-configured with PAAs IP
00320       address and the PANA-PAA-Discover message is unicast.
00321 
00322       A PANA-Start-Request message is never retransmitted. A
00323       PANA-Start-Answer message is retransmitted based on timer in the same
00324       manner as other messages retransmitted at PANA-layer.
00325 
00326       It is possible that both PAA and PaC initiate the discovery and
00327       initial handshake procedure at the same time, i.e., the PAA sends a
00328       PANA-Start-Request message while the PaC sends a PANA-PAA-Discover
00329       message.  To resolve the race condition, the PAA SHOULD silently
00330       discard the PANA-PAA-Discover message received from the PaC after it
00331       has sent a PANA-Start-Request message with creating a state for the
00332       PaC.
00333    */
00334 
00335    // validate sequence number
00336    if (msg.tseq() == 0 || msg.rseq() == 0) {
00337       throw (PANA_Exception(PANA_Exception::INVALID_MESSAGE, 
00338                            "Rseq or Tseq field of start answer message is zero"));
00339    }
00340 
00341    ACE_DEBUG((LM_INFO, "(%P|%t) RECV: Start answer [factory], S-flag %d, tseq=%d, rseq=%d\n",
00342                        msg.flags().separate, msg.tseq(), msg.rseq()));
00343 
00344    PANA_PaaSession *session = NULL;
00345    if (PANA_CONFIG_AUTHAGENT().use_cookie_) {
00346        
00347        PANA_Paa::ValidateCookie(msg);
00348        
00349        ACE_DEBUG((LM_INFO, "(%P|%t) Pac validated, creating new session\n"));
00350        session = Create();
00351    }
00352    else {
00353        PANA_DeviceId *ipId = msg.srcDevices().search(PANA_DeviceId::IPV4_ADDRESS);
00354        if (ipId == NULL) {
00355            throw (PANA_Exception(PANA_Exception::INVALID_MESSAGE, 
00356                   "Cannot determine the device ID of peer"));
00357        }
00358        
00359        ACE_DEBUG((LM_INFO, "(%P|%t) Stateful discovery, updating session\n"));
00360        m_PendingDb.Remove(const_cast<std::string&>(ipId->id()),
00361                           &session);
00362    }   
00363        
00364    if (session == NULL) {
00365       throw (PANA_Exception(PANA_Exception::NO_MEMORY, 
00366                             "Failed to auth agent session"));
00367    }
00368    
00369    // generate a new session id 
00370    diameter_octetstring_t sessionId;
00371    PANA_SessionIdGenerator_S::instance()->Generate(sessionId);
00372 
00373    PANA_SESSIONDB_ADD(sessionId, *session);
00374 
00375    // tag the session id temporarily
00376    AAAAvpContainerManager cm;
00377    AAAAvpContainerEntryManager em;
00378    AAAAvpContainer *c_sessionId = cm.acquire("Session-Id");
00379 
00380    // Add the AVP's to containers
00381    AAAAvpContainerEntry *e = em.acquire(AAA_AVP_UTF8_STRING_TYPE);
00382    diameter_utf8string_t &sid = e->dataRef(Type2Type<diameter_utf8string_t>());
00383    c_sessionId->add(e);
00384 
00385    msg.avpList().add(c_sessionId);
00386    sid = sessionId;
00387 
00388    session->Receive(msg);
00389 }
00390 
00391 
00392 
00393 
00394 

Generated on Fri Jun 25 19:18:29 2004 for PANA by doxygen 1.3.5