/* copies the Origin-Host AVP from the src message in a Destination-Host AVP in the dest message * copies the Origin-Realm AVP from the src message in a Destination-Realm AVP in the dest message * */ int dup_routing_avps(AAAMessage* src, AAAMessage *dest){ AAA_AVP * avp; str dest_host, dest_realm; if(!src) return 1; avp = AAAFindMatchingAVP(src,src->avpList.head,AVP_Origin_Host,0,AAA_FORWARD_SEARCH); if(avp && avp->data.s && avp->data.len) { LOG(L_DBG,"DBG:dup_routing_avps: Origin Host AVP present, duplicating %.*s\n", avp->data.len, avp->data.s); dest_host = avp->data; avp = AAACreateAVP(AVP_Destination_Host,AAA_AVP_FLAG_MANDATORY,0, dest_host.s,dest_host.len,AVP_DUPLICATE_DATA); if (!avp) { LOG(L_ERR,"ERR:dup_routing_avps: Failed creating Destination Host avp\n"); goto error; } if (AAAAddAVPToMessage(dest,avp,dest->avpList.tail)!=AAA_ERR_SUCCESS) { LOG(L_ERR,"ERR:dup_routing_avps: Failed adding Destination Host avp to message\n"); AAAFreeAVP(&avp); goto error; } } avp = AAAFindMatchingAVP(src,src->avpList.head,AVP_Origin_Realm,0,AAA_FORWARD_SEARCH); if(avp && avp->data.s && avp->data.len) { LOG(L_DBG,"DBG:dup_routing_avps: Origin Realm AVP present, duplicating %.*s\n", avp->data.len, avp->data.s); dest_realm = avp->data; avp = AAACreateAVP(AVP_Destination_Realm,AAA_AVP_FLAG_MANDATORY,0, dest_realm.s,dest_realm.len,AVP_DUPLICATE_DATA); if (!avp) { LOG(L_ERR,"ERR:dup_routing_avps: Failed creating Destination Host avp\n"); goto error; } if (AAAAddAVPToMessage(dest,avp,dest->avpList.tail)!=AAA_ERR_SUCCESS) { LOG(L_ERR,"ERR:dup_routing_avps: Failed adding Destination Host avp to message\n"); AAAFreeAVP(&avp); goto error; } } return 1; error: return 0; }
int count_Supported_Vendor_Id_AVPS(AAAMessage *msg) { AAA_AVP* avp_vendor; int avp_vendor_cnt; avp_vendor = AAAFindMatchingAVP(msg,0,AVP_Supported_Vendor_Id,0,0); avp_vendor_cnt = 0; while (avp_vendor) { avp_vendor_cnt++; if (!avp_vendor->next) break; avp_vendor = AAAFindMatchingAVP(msg,avp_vendor->next,AVP_Supported_Vendor_Id,0,0); } LM_DBG("Found %i Supported_Vendor AVPS", avp_vendor_cnt); return avp_vendor_cnt; }
/** * Perform the Election mechanism. * When 2 peers connect to each-other at the same moment, an election is triggered. * That means that based on the alphabetical relation between the FQDNs, one peer is * kept as winner on Initiator and that connection is kept, while the other keeps the same * connection as Receiver and drops its Initiator connection. * \note Must be called with a lock on the peer. * @param p - peer identification * @param cer - the CER message * @returns 1 if winning, 0 if loosing */ int Elect(peer *p,AAAMessage *cer) { /* returns if we win the election */ AAA_AVP *avp; str remote,local; int i,d; if(!cer){ LM_ERR("Elect cer is NULL \n"); // return lose return 0; } local = config->fqdn; avp = AAAFindMatchingAVP(cer,cer->avpList.head,AVP_Origin_Host,0,0); if (!avp) { return 1; }else{ remote = avp->data; for(i=0;i<remote.len&&i<local.len;i++){ d = ((unsigned char) local.s[i])-((unsigned char) remote.s[i]); if (d>0) return 1; if (d<0) return 0; } if (local.len>remote.len) return 1; return 0; } }
/** * update Granted Service Unit timers based on CCR */ inline void update_gsu_request_timers(cdp_cc_acc_session_t* session, AAAMessage* msg) { AAA_AVP *avp; avp = AAAFindMatchingAVP(msg, 0, AVP_Event_Timestamp, 0, 0); if (avp && avp->data.len == 4) { session->last_reservation_request_time = ntohl(*((uint32_t*)avp->data.s))-EPOCH_UNIX_TO_EPOCH_NTP; } }
/** * Sends a message to the peer. * \note Must be called with a lock on the peer. * @param p - peer to send to * @param msg - message to send */ void Snd_Message(peer *p, AAAMessage *msg) { AAASession *session=0; int rcode; int send_message_before_session_sm=0; touch_peer(p); if (msg->sessionId) session = get_session(msg->sessionId->data); if (session){ switch (session->type){ case AUTH_CLIENT_STATEFULL: if (is_req(msg)) auth_client_statefull_sm_process(session,AUTH_EV_SEND_REQ,msg); else { if (msg->commandCode == IMS_ASA){ if (!msg->res_code){ msg->res_code = AAAFindMatchingAVP(msg,0,AVP_Result_Code,0,0); } if (!msg->res_code) auth_client_statefull_sm_process(session,AUTH_EV_SEND_ASA_UNSUCCESS,msg); else { rcode = get_4bytes(msg->res_code->data.s); if (rcode>=2000 && rcode<3000) { peer_send_msg(p,msg); send_message_before_session_sm=1; auth_client_statefull_sm_process(session,AUTH_EV_SEND_ASA_SUCCESS,msg); } else auth_client_statefull_sm_process(session,AUTH_EV_SEND_ASA_UNSUCCESS,msg); } }else auth_client_statefull_sm_process(session,AUTH_EV_SEND_ANS,msg); } break; case AUTH_SERVER_STATEFULL: if (is_req(msg)) { if (msg->commandCode== IMS_ASR) { auth_server_statefull_sm_process(session,AUTH_EV_SEND_ASR,msg); } else { //would be a RAR but ok! auth_server_statefull_sm_process(session,AUTH_EV_SEND_REQ,msg); } } else { if (msg->commandCode == IMS_STR) auth_server_statefull_sm_process(session,AUTH_EV_SEND_STA,msg); else auth_server_statefull_sm_process(session,AUTH_EV_SEND_ANS,msg); } break; default: break; } sessions_unlock(session->hash); } if (!send_message_before_session_sm) peer_send_msg(p,msg); }
/** * Process a Capability Exchange Answer. * \note Must be called with a lock on the peer. * @param p - the peer that the CEA was received from * @param cea - the CEA message * @returns the result-code from CEA or AAA_UNABLE_TO_COMPLY if no result-code found */ int Process_CEA(peer *p,AAAMessage *cea) { AAA_AVP *avp; avp = AAAFindMatchingAVP(cea,cea->avpList.head,AVP_Result_Code,0,0); save_peer_applications(p,cea); AAAFreeMessage(&cea); if (!avp) return AAA_UNABLE_TO_COMPLY; else return get_4bytes(avp->data.s); }
int get_auth_session_state(AAAMessage* msg) { if (!msg) goto error; AAA_AVP* rc = AAAFindMatchingAVP(msg, 0, AVP_Auth_Session_State, 0, 0); if (!rc) goto error; return get_4bytes(rc->data.s); error: LM_DBG("get_auth_session_state(): no AAAMessage or Auth Session State not found\n"); return STATE_MAINTAINED; }
/** * update Granted Service Unit timers based on CCA, for onw we assume on one MSCC per session and only TIME based supported */ inline void update_gsu_response_timers(cdp_cc_acc_session_t* session, AAAMessage* msg) { AAA_AVP *avp; AAA_AVP_LIST mscc_avp_list; AAA_AVP_LIST y; AAA_AVP *z; avp = AAAFindMatchingAVP(msg, 0, AVP_Multiple_Services_Credit_Control, 0, 0); if (!avp) { LM_WARN("Trying to update GSU timers but there is no MSCC AVP in the CCA response\n"); return; } mscc_avp_list = AAAUngroupAVPS(avp->data); AAA_AVP *mscc_avp = mscc_avp_list.head; while (mscc_avp != NULL ) { LM_DBG("MSCC AVP code is [%i] and data length is [%i]", mscc_avp->code, mscc_avp->data.len); switch (mscc_avp->code) { case AVP_Granted_Service_Unit: y = AAAUngroupAVPS(mscc_avp->data); z = y.head; while (z) { switch (z->code) { case AVP_CC_Time: session->reserved_units = get_4bytes(z->data.s); break; default: LM_DBG("ignoring AVP in GSU group with code:[%d]\n", z->code); } z = z->next; } break; case AVP_Validity_Time: session->reserved_units_validity_time = get_4bytes(mscc_avp->data.s); break; case AVP_Final_Unit_Indication: y = AAAUngroupAVPS(mscc_avp->data); z = y.head; while (z) { switch (z->code) { case AVP_Final_Unit_Action: session->fua = get_4bytes(z->data.s); break; default: LM_DBG("ignoring AVP in FUI group with code:[%d]\n", z->code); } z = z->next; } break; } mscc_avp = mscc_avp->next; } AAAFreeAVPList(&mscc_avp_list); AAAFreeAVPList(&y); }
int get_result_code(AAAMessage* msg) { if (!msg) goto error; AAA_AVP* rc = AAAFindMatchingAVP(msg, 0, AVP_Result_Code, 0, 0); if (!rc) goto error; return get_4bytes(rc->data.s); error: LOG(L_INFO, "INF: no AAAMessage or Result Code not found\n"); return 0; }
/** * Retrieve the Session-Timeout, Auth-Lifetime and Auth-Grace-Period AVPs and update the session timers accordingly * @param x * @param msg */ void update_auth_session_timers(cdp_auth_session_t *x,AAAMessage *msg) { AAA_AVP *avp; uint32_t session_timeout=0,grace_period=0,auth_lifetime=0; avp = AAAFindMatchingAVP(msg,0,AVP_Auth_Grace_Period,0,0); if (avp &&avp->data.len==4){ grace_period = get_4bytes(avp->data.s); x->grace_period = grace_period; } avp = AAAFindMatchingAVP(msg,0,AVP_Authorization_Lifetime,0,0); if (avp &&avp->data.len==4) { auth_lifetime = get_4bytes(avp->data.s); switch(auth_lifetime){ case 0: x->lifetime = time(0); break; case 0xFFFFFFFF: x->lifetime = -1; break; default: x->lifetime = time(0)+auth_lifetime; } if (x->timeout!=-1 && x->timeout<x->lifetime) x->timeout = x->lifetime+x->grace_period; } avp = AAAFindMatchingAVP(msg,0,AVP_Session_Timeout,0,0); if (avp &&avp->data.len==4) { session_timeout = get_4bytes(avp->data.s); switch(session_timeout){ case 0: x->timeout = time(0)+config->default_auth_session_timeout; break; case 0xFFFFFFFF: x->timeout = -1; break; default: x->timeout = time(0)+session_timeout; } if (!x->lifetime) x->lifetime = x->timeout; } }
/** * Add Session-Timeout, Auth-Lifetime and Auth-Grace-Period AVPs to outgoing messages in case they are missing * @param x * @param msg */ void add_auth_session_timers(cdp_auth_session_t *x,AAAMessage *msg) { AAA_AVP *avp; char data[4]; uint32_t v; avp = AAAFindMatchingAVP(msg,0,AVP_Authorization_Lifetime,0,0); if (!avp){ if (x->lifetime==-1) v=0xFFFFFFFF; else { v = x->lifetime-time(0); if (v<0) v = 0; } set_4bytes(data,v); avp = AAACreateAVP(AVP_Authorization_Lifetime,AAA_AVP_FLAG_MANDATORY,0,data,4,AVP_DUPLICATE_DATA); if (avp) AAAAddAVPToMessage(msg,avp,0); } if (x->lifetime!=-1){ avp = AAAFindMatchingAVP(msg,0,AVP_Auth_Grace_Period,0,0); if (!avp){ v = x->grace_period; set_4bytes(data,v); avp = AAACreateAVP(AVP_Auth_Grace_Period,AAA_AVP_FLAG_MANDATORY,0,data,4,AVP_DUPLICATE_DATA); if (avp) AAAAddAVPToMessage(msg,avp,0); } } avp = AAAFindMatchingAVP(msg,0,AVP_Session_Timeout,0,0); if (!avp){ if (x->timeout==-1) v=0xFFFFFFFF; else { v = x->timeout-time(0); if (v<0) v = 0; } set_4bytes(data,v); avp = AAACreateAVP(AVP_Session_Timeout,AAA_AVP_FLAG_MANDATORY,0,data,4,AVP_DUPLICATE_DATA); if (avp) AAAAddAVPToMessage(msg,avp,0); } }
/* copies the Origin-Host AVP from the src message in a Destination-Host AVP in the dest message * copies the Origin-Realm AVP from the src message in a Destination-Realm AVP in the dest message * */ int dup_routing_avps(AAAMessage* src, AAAMessage *dest) { AAA_AVP * avp; str dest_realm; if (!src) return 1; /* Removed By Jason to facilitate use of Diameter clustering (MUX) in SLEE architecture (Realm-routing only) - TODO - check spec */ /*avp = AAAFindMatchingAVP(src,src->avpList.head,AVP_Origin_Host,0,AAA_FORWARD_SEARCH); if(avp && avp->data.s && avp->data.len) { LM_DBG("dup_routing_avps: Origin Host AVP present, duplicating %.*s\n", avp->data.len, avp->data.s); dest_host = avp->data; avp = AAACreateAVP(AVP_Destination_Host,AAA_AVP_FLAG_MANDATORY,0, dest_host.s,dest_host.len,AVP_DUPLICATE_DATA); if (!avp) { LM_ERR("dup_routing_avps: Failed creating Destination Host avp\n"); goto error; } if (AAAAddAVPToMessage(dest,avp,dest->avpList.tail)!=AAA_ERR_SUCCESS) { LM_ERR("dup_routing_avps: Failed adding Destination Host avp to message\n"); AAAFreeAVP(&avp); goto error; } }*/ avp = AAAFindMatchingAVP(src, src->avpList.head, AVP_Origin_Realm, 0, AAA_FORWARD_SEARCH); if (avp && avp->data.s && avp->data.len) { LM_DBG("dup_routing_avps: Origin Realm AVP present, duplicating %.*s\n", avp->data.len, avp->data.s); dest_realm = avp->data; avp = AAACreateAVP(AVP_Destination_Realm, AAA_AVP_FLAG_MANDATORY, 0, dest_realm.s, dest_realm.len, AVP_DUPLICATE_DATA); if (!avp) { LM_ERR("dup_routing_avps: Failed creating Destination Host avp\n"); goto error; } if (AAAAddAVPToMessage(dest, avp, dest->avpList.tail) != AAA_ERR_SUCCESS) { LM_ERR("dup_routing_avps: Failed adding Destination Host avp to message\n"); AAAFreeAVP(&avp); goto error; } } return 1; error: return 0; }
/** * Returns the value of a certain AVP from a Diameter message. * @param m - Diameter message to look into * @param avp_code - the code to search for * @param vendorid - the value of the vendor id to look for or 0 if none * @param func - the name of the calling function, for debugging purposes * @returns the str with the payload on success or an empty string on failure */ static inline str get_avp(AAAMessage *msg,int avp_code,int vendor_id, const char *func) { AAA_AVP *avp; str r={0,0}; avp = AAAFindMatchingAVP(msg,0,avp_code,vendor_id,0); if (avp==0){ LOG(L_INFO,"INFO: Failed finding avp\n"); return r; } else return avp->data; }
/** * Returns the value of a certain AVP from a Diameter message. * westart searching from the beginning 0 * @param msg - Diameter message to look into * @param avp_code - the code to search for * @param vendorid - the value of the vendor id to look for or 0 if none * * @returns the AAA_AVP* if found, NULL if not */ AAA_AVP *Rf_get_avp(AAAMessage *msg,int avp_code,int vendor_id) { AAA_AVP *avp; /* param checking */ if (!msg) { LOG(L_ERR,"ERR:Rf_get_avp: param msg passed null !!\n"); return 0; } avp = AAAFindMatchingAVP(msg,0,avp_code,vendor_id,0); if (avp==0){ LOG(L_ERR,"ERR: Rf_get_avp: Failed finding avp\n"); return 0; } else return avp; }
void Send_ASA(cdp_session_t* s, AAAMessage* msg) { AAAMessage *asa; char x[4]; AAA_AVP *avp; LOG(L_INFO,"Send_ASA(): sending ASA\n"); if (!s) { //send an ASA for UNKNOWN_SESSION_ID - use AAASendMessage() // msg is the ASR received asa = AAANewMessage(IMS_ASA,0,0,msg); if (!asa) return; set_4bytes(x,AAA_SUCCESS); AAACreateAndAddAVPToMessage(asa,AVP_Result_Code,AAA_AVP_FLAG_MANDATORY,0,x,4); AAASendMessage(asa,0,0); }else{ // send... many cases... maybe not needed. // for now we do the same asa = AAANewMessage(IMS_ASA,0,0,msg); if (!asa) return; set_4bytes(x,AAA_SUCCESS); AAACreateAndAddAVPToMessage(asa,AVP_Result_Code,AAA_AVP_FLAG_MANDATORY,0,x,4); avp = AAAFindMatchingAVP(msg,0,AVP_Origin_Host,0,0); if (avp) { // This is because AAASendMessage is not going to find a route to the // the PCRF because TS 29.214 says no Destination-Host and no Auth-Application-Id // in the ASA LOG(L_INFO,"sending ASA to peer %.*s\n",avp->data.len,avp->data.s); peer *p; p = get_peer_by_fqdn(&avp->data); if (!peer_send_msg(p,asa)) { if (asa) AAAFreeMessage(&asa); //needed in frequency } else LOG(L_INFO,"success sending ASA\n"); }else if (!AAASendMessage(asa,0,0)) { LOG(L_ERR,"Send_ASA() : error sending ASA\n"); } } }
/** * Allocates a new AAAMessage. * @param commandCode - the command code for this message * @param applicationId - application id to be set * @param sessionId - session id to be set * @param request - if you want to create a response, put the request here. If you want a * request, call with NULL * @returns the AAAMessage* or NULL on error * \note This function is taken from DISC http://developer.berlios.de/projects/disc/ */ AAAMessage *AAANewMessage( AAACommandCode commandCode, AAAApplicationId applicationId, AAASessionId *sessionId, AAAMessage *request) { AAAMessage *msg; AAA_AVP *avp; AAA_AVP *avp_t; #if 0 unsigned int code; #endif str dest_host={"?",1}; str dest_realm={"?",1}; msg = 0; if (!sessionId||!sessionId->s) { if (request && request->sessionId){ /* copy old session id */ avp = request->sessionId; if (avp) { sessionId = &(avp->data); } }else{ //because of diameter base messages etc // LOG(L_ERR,"ERROR:AAANewMessage: param session-ID received null and it's a request!!\n"); // goto error; } } /* allocated a new AAAMessage structure and set it to 0 */ msg = (AAAMessage*)shm_malloc(sizeof(AAAMessage)); if (!msg) { LOG(L_ERR,"ERROR:AAANewMessage: no more free memory!!\n"); goto error; } memset(msg,0,sizeof(AAAMessage)); /* command code */ msg->commandCode = commandCode; /* application ID */ msg->applicationId = applicationId; /* add session ID */ if (sessionId){ avp = AAACreateAVP( 263, 0, 0, sessionId->s, sessionId->len, AVP_DUPLICATE_DATA); if ( !avp || AAAAddAVPToMessage(msg,avp,0)!=AAA_ERR_SUCCESS) { LOG(L_ERR,"ERROR:AAANewMessage: cannot create/add Session-Id avp\n"); if (avp) AAAFreeAVP( &avp ); goto error; } msg->sessionId = avp; } /* add origin host AVP */ /* changed by cristian to comply with rfc3588: * 6.3. Origin-Host AVP * * The Origin-Host AVP (AVP Code 264) is of type * DiameterIdentity... */ avp = AAACreateAVP( 264, 0, 0, config->fqdn.s, config->fqdn.len, AVP_DUPLICATE_DATA); if (!avp||AAAAddAVPToMessage(msg,avp,msg->avpList.tail)!=AAA_ERR_SUCCESS) { LOG(L_ERR,"ERROR:AAANewMessage: cannot create/add Origin-Host avp\n"); if (avp) AAAFreeAVP( &avp ); goto error; } msg->orig_host = avp; /* add origin realm AVP */ avp = AAACreateAVP( 296, 0, 0, config->realm.s, config->realm.len, AVP_DUPLICATE_DATA); if (!avp||AAAAddAVPToMessage(msg,avp,msg->avpList.tail)!=AAA_ERR_SUCCESS) { LOG(L_ERR,"ERROR:AAANewMessage: cannot create/add Origin-Realm avp\n"); if (avp) AAAFreeAVP( &avp ); goto error; } msg->orig_realm = avp; if (!request) { /* it's a new request -> set the flag */ msg->flags = 0x80; /* keep track of the session -> SendMessage will need it! */ msg->sId = sessionId; } else { /* it'a an answer -> it will have the same session Id */ msg->sId = request->sId; /* link the incoming peer to the answer */ msg->in_peer = request->in_peer; /* set the P flag as in request */ msg->flags |= request->flags&0x40; /**/ msg->endtoendId = request->endtoendId; msg->hopbyhopId = request->hopbyhopId; /* Mirror the old originhost/realm to destinationhost/realm*/ avp = AAAFindMatchingAVP(request,0,AVP_Origin_Host,0,0); if (avp) dest_host = avp->data; /* add destination host and destination realm */ avp = AAACreateAVP(AVP_Destination_Host,AAA_AVP_FLAG_MANDATORY,0, dest_host.s,dest_host.len,AVP_DUPLICATE_DATA); if (!avp) { LOG(L_ERR,"ERR:AAANewMessage: Failed creating Destination Host avp\n"); return 0; } if (AAAAddAVPToMessage(msg,avp,msg->avpList.tail)!=AAA_ERR_SUCCESS) { LOG(L_ERR,"ERR:AAANewMessage: Failed adding Destination Host avp to message\n"); AAAFreeAVP(&avp); return 0; } avp = AAAFindMatchingAVP(request,0,AVP_Origin_Realm,0,0); if (avp) dest_realm = avp->data; avp = AAACreateAVP(AVP_Destination_Realm,AAA_AVP_FLAG_MANDATORY,0, dest_realm.s,dest_realm.len,AVP_DUPLICATE_DATA); if (!avp) { LOG(L_ERR,"ERR:AAANewMessage: Failed creating Destination Realm avp\n"); return 0; } if (AAAAddAVPToMessage(msg,avp,msg->avpList.tail)!=AAA_ERR_SUCCESS) { LOG(L_ERR,"ERR:AAANewMessage: Failed adding Destination Realm avp to message\n"); AAAFreeAVP(&avp); return 0; } msg->res_code=0; /* mirror all the proxy-info avp in the same order */ avp_t = request->avpList.head; while ( (avp_t=AAAFindMatchingAVP (request,avp_t,284,0,AAA_FORWARD_SEARCH))!=0 ) { if ( (avp=AAACloneAVP(avp_t,1))==0 || AAAAddAVPToMessage( msg, avp, msg->avpList.tail)!=AAA_ERR_SUCCESS ) goto error; } } return msg; error: LOG(L_ERR,"ERROR:AAANewMessage: failed to create a new AAA message!\n"); AAAFreeMessage(&msg); return 0; }
/** * Add Session-Timeout, Auth-Lifetime and Auth-Grace-Period AVPs to outgoing messages in case they are missing * @param x * @param msg */ void add_auth_session_timers(cdp_auth_session_t *x, AAAMessage *msg) { AAA_AVP *avp; char data[4]; uint32_t v; uint32_t lifetime, timeout, grace; avp = AAAFindMatchingAVP(msg, 0, AVP_Authorization_Lifetime, 0, 0); if (!avp) { if (x->lifetime == -1) v = 0xFFFFFFFF; else { v = x->lifetime - time(0); if (v < 0) v = 0; } x->last_requested_lifetime = v; set_4bytes(data, v); avp = AAACreateAVP(AVP_Authorization_Lifetime, AAA_AVP_FLAG_MANDATORY, 0, data, 4, AVP_DUPLICATE_DATA); if (avp) AAAAddAVPToMessage(msg, avp, msg->avpList.tail); } else { if (avp->data.len == 4) { lifetime = get_4bytes(avp->data.s); switch (lifetime) { case 0: x->last_requested_lifetime = 0; break; case 0xFFFFFFFF: x->last_requested_lifetime = -1; break; default: x->last_requested_lifetime = lifetime; } } } if (x->lifetime != -1) { avp = AAAFindMatchingAVP(msg, 0, AVP_Auth_Grace_Period, 0, 0); if (!avp) { v = x->grace_period; set_4bytes(data, v); avp = AAACreateAVP(AVP_Auth_Grace_Period, AAA_AVP_FLAG_MANDATORY, 0, data, 4, AVP_DUPLICATE_DATA); if (avp) AAAAddAVPToMessage(msg, avp, msg->avpList.tail); x->last_requested_grace = v; } else { if (avp->data.len == 4) { grace = get_4bytes(avp->data.s); switch (grace) { case 0: x->last_requested_grace = 0; break; case 0xFFFFFFFF: x->last_requested_grace = -1; break; default: x->last_requested_grace = grace; } } } } avp = AAAFindMatchingAVP(msg, 0, AVP_Session_Timeout, 0, 0); if (!avp) { if (x->timeout == -1) v = 0xFFFFFFFF; else { v = x->timeout - time(0); if (v < 0) v = 0; } set_4bytes(data, v); avp = AAACreateAVP(AVP_Session_Timeout, AAA_AVP_FLAG_MANDATORY, 0, data, 4, AVP_DUPLICATE_DATA); if (avp) AAAAddAVPToMessage(msg, avp, msg->avpList.tail); x->last_requested_timeout = v; } else { if (avp->data.len == 4) { timeout = get_4bytes(avp->data.s); switch (timeout) { case 0: x->last_requested_timeout = 0; break; case 0xFFFFFFFF: x->last_requested_timeout = -1; break; default: x->last_requested_timeout = lifetime; } } } }
/** * Receives a mesasge and does basic processing or call the sm_process(). * This gets called from the receive_loop for every message that is received. * @param msg - the message received * @param sock - socket received on */ void receive_message(AAAMessage *msg,int sock) { AAA_AVP *avp1,*avp2; LOG(L_DBG,"DBG:receive_message(): [%d] Recv msg %d\n",sock,msg->commandCode); if (!this_peer) { this_peer = get_peer_from_sock(sock); set_peer_pipe(); } if (!this_peer){ switch (msg->commandCode){ case Code_CE: if (is_req(msg)){ avp1 = AAAFindMatchingAVP(msg,msg->avpList.head,AVP_Origin_Host,0,0); avp2 = AAAFindMatchingAVP(msg,msg->avpList.head,AVP_Origin_Realm,0,0); if (avp1&&avp2){ this_peer = get_peer_from_fqdn(avp1->data,avp2->data); } if (!this_peer) { LOG(L_ERR,"ERROR:receive_msg(): Received CER from unknown peer (accept unknown=%d) -ignored\n", config->accept_unknown_peers); AAAFreeMessage(&msg); }else{ set_peer_pipe(); sm_process(this_peer,R_Conn_CER,msg,0,sock); } } else{ LOG(L_ERR,"ERROR:receive_msg(): Received CEA from an unknown peer -ignored\n"); AAAFreeMessage(&msg); } break; default: LOG(L_ERR,"ERROR:receive_msg(): Received non-CE from an unknown peer -ignored\n"); AAAFreeMessage(&msg); } }else{ touch_peer(this_peer); switch (this_peer->state){ case Wait_I_CEA: if (msg->commandCode!=Code_CE||is_req(msg)){ sm_process(this_peer,I_Rcv_Non_CEA,msg,0,sock); }else sm_process(this_peer,I_Rcv_CEA,msg,0,sock); break; case I_Open: switch (msg->commandCode){ case Code_CE: if (is_req(msg)) sm_process(this_peer,I_Rcv_CER,msg,0,sock); else sm_process(this_peer,I_Rcv_CEA,msg,0,sock); break; case Code_DW: if (is_req(msg)) sm_process(this_peer,I_Rcv_DWR,msg,0,sock); else sm_process(this_peer,I_Rcv_DWA,msg,0,sock); break; case Code_DP: if (is_req(msg)) sm_process(this_peer,I_Rcv_DPR,msg,0,sock); else sm_process(this_peer,I_Rcv_DPA,msg,0,sock); break; default: sm_process(this_peer,I_Rcv_Message,msg,0,sock); } break; case R_Open: switch (msg->commandCode){ case Code_CE: if (is_req(msg)) sm_process(this_peer,R_Rcv_CER,msg,0,sock); else sm_process(this_peer,R_Rcv_CEA,msg,0,sock); break; case Code_DW: if (is_req(msg)) sm_process(this_peer,R_Rcv_DWR,msg,0,sock); else sm_process(this_peer,R_Rcv_DWA,msg,0,sock); break; case Code_DP: if (is_req(msg)) sm_process(this_peer,R_Rcv_DPR,msg,0,sock); else sm_process(this_peer,R_Rcv_DPA,msg,0,sock); break; default: sm_process(this_peer,R_Rcv_Message,msg,0,sock); } break; default: LOG(L_ERR,"ERROR:receive_msg(): Received msg while peer in state %d -ignored\n",this_peer->state); AAAFreeMessage(&msg); } } }
/*! \brief send a message over an already opened TCP connection */ int tcp_send_recv(int sockfd, char* buf, int len, rd_buf_t* rb, unsigned int waited_id) { int n, number_of_tries; fd_set active_fd_set, read_fd_set; struct timeval tv; unsigned long int result_code; AAAMessage *msg; AAA_AVP *avp; char serviceType; unsigned int m_id; /* try to write the message to the Diameter client */ while( (n=write(sockfd, buf, len))==-1 ) { if (errno==EINTR) continue; LM_ERR("write returned error: %s\n", strerror(errno)); return AAA_ERROR; } if (n!=len) { LM_ERR("write gave no error but wrote less than asked\n"); return AAA_ERROR; } /* wait for the answer a limited amount of time */ tv.tv_sec = MAX_WAIT_SEC; tv.tv_usec = MAX_WAIT_USEC; /* Initialize the set of active sockets. */ FD_ZERO (&active_fd_set); FD_SET (sockfd, &active_fd_set); number_of_tries = 0; while(number_of_tries<MAX_TRIES) { read_fd_set = active_fd_set; if (select (sockfd+1, &read_fd_set, NULL, NULL, &tv) < 0) { LM_ERR("select function failed\n"); return AAA_ERROR; } /* if (!FD_ISSET (sockfd, &read_fd_set)) { LM_ERR("no response received\n"); // return AAA_ERROR; } */ /* Data arriving on a already-connected socket. */ reset_read_buffer(rb); switch( do_read(sockfd, rb) ) { case CONN_ERROR: LM_ERR("failed to read from socket\n"); return AAA_CONN_CLOSED; case CONN_CLOSED: LM_ERR("failed to read from socket\n"); return AAA_CONN_CLOSED; } /* obtain the structure corresponding to the message */ msg = AAATranslateMessage(rb->buf, rb->buf_len, 0); if(!msg) { LM_ERR("message structure not obtained\n"); return AAA_ERROR; } avp = AAAFindMatchingAVP(msg, NULL, AVP_SIP_MSGID, vendorID, AAA_FORWARD_SEARCH); if(!avp) { LM_ERR("AVP_SIP_MSGID not found\n"); return AAA_ERROR; } m_id = *((unsigned int*)(avp->data.s)); LM_DBG("######## m_id=%d\n", m_id); if(m_id!=waited_id) { number_of_tries ++; LM_NOTICE("old message received\n"); continue; } goto next; } LM_ERR("too many old messages received\n"); return AAA_TIMEOUT; next: /* Finally die correct answer */ avp = AAAFindMatchingAVP(msg, NULL, AVP_Service_Type, vendorID, AAA_FORWARD_SEARCH); if(!avp) { LM_ERR("AVP_Service_Type not found\n"); return AAA_ERROR; } serviceType = avp->data.s[0]; result_code = ntohl(*((unsigned long int*)(msg->res_code->data.s))); switch(result_code) { case AAA_SUCCESS: /* 2001 */ return ACC_SUCCESS; default: /* error */ return ACC_FAILURE; } }
/** * Receives a message and does basic processing or call the sm_process(). * This gets called from the do_receive() for every message that is received. * Basic processing, before the state machine, is done here. * @param msg - the message received * @param sp - the serviced peer that it was receiver on */ void receive_message(AAAMessage *msg,serviced_peer_t *sp) { AAA_AVP *avp1,*avp2; LM_DBG("receive_message(): [%.*s] Recv msg %d\n", sp->p?sp->p->fqdn.len:0, sp->p?sp->p->fqdn.s:0, msg->commandCode); if (!sp->p){ switch (msg->commandCode){ case Code_CE: if (is_req(msg)){ avp1 = AAAFindMatchingAVP(msg,msg->avpList.head,AVP_Origin_Host,0,0); avp2 = AAAFindMatchingAVP(msg,msg->avpList.head,AVP_Origin_Realm,0,0); if (avp1&&avp2){ sp->p = get_peer_from_fqdn(avp1->data,avp2->data); } if (!sp->p) { LM_ERR("receive_msg(): Received CER from unknown peer (accept unknown=%d) -ignored\n", config->accept_unknown_peers); AAAFreeMessage(&msg); }else{ LM_DBG("receive_message(): [%.*s] This receiver has no peer associated\n", sp->p?sp->p->fqdn.len:0, sp->p?sp->p->fqdn.s:0 ); //set_peer_pipe(); make_send_pipe(sp); sm_process(sp->p,R_Conn_CER,msg,0,sp->tcp_socket); } } else{ LM_ERR("receive_msg(): Received CEA from an unknown peer -ignored\n"); AAAFreeMessage(&msg); } break; default: LM_ERR("receive_msg(): Received non-CE from an unknown peer -ignored\n"); AAAFreeMessage(&msg); } }else{ touch_peer(sp->p); switch (sp->p->state){ case Wait_I_CEA: if (msg->commandCode!=Code_CE||is_req(msg)){ sm_process(sp->p,I_Rcv_Non_CEA,msg,0,sp->tcp_socket); }else sm_process(sp->p,I_Rcv_CEA,msg,0,sp->tcp_socket); break; case I_Open: switch (msg->commandCode){ case Code_CE: if (is_req(msg)) sm_process(sp->p,I_Rcv_CER,msg,0,sp->tcp_socket); else sm_process(sp->p,I_Rcv_CEA,msg,0,sp->tcp_socket); break; case Code_DW: if (is_req(msg)) sm_process(sp->p,I_Rcv_DWR,msg,0,sp->tcp_socket); else sm_process(sp->p,I_Rcv_DWA,msg,0,sp->tcp_socket); break; case Code_DP: if (is_req(msg)) sm_process(sp->p,I_Rcv_DPR,msg,0,sp->tcp_socket); else sm_process(sp->p,I_Rcv_DPA,msg,0,sp->tcp_socket); break; default: sm_process(sp->p,I_Rcv_Message,msg,0,sp->tcp_socket); } break; case R_Open: switch (msg->commandCode){ case Code_CE: if (is_req(msg)) sm_process(sp->p,R_Rcv_CER,msg,0,sp->tcp_socket); else sm_process(sp->p,R_Rcv_CEA,msg,0,sp->tcp_socket); break; case Code_DW: if (is_req(msg)) sm_process(sp->p,R_Rcv_DWR,msg,0,sp->tcp_socket); else sm_process(sp->p,R_Rcv_DWA,msg,0,sp->tcp_socket); break; case Code_DP: if (is_req(msg)) sm_process(sp->p,R_Rcv_DPR,msg,0,sp->tcp_socket); else sm_process(sp->p,R_Rcv_DPA,msg,0,sp->tcp_socket); break; default: sm_process(sp->p,R_Rcv_Message,msg,0,sp->tcp_socket); } break; default: LM_ERR("receive_msg(): [%.*s] Received msg while peer in state %d -ignored\n", sp->p->fqdn.len, sp->p->fqdn.s, sp->p->state); AAAFreeMessage(&msg); } } }
void save_peer_applications(peer *p,AAAMessage *msg) { int total_cnt=0; int supported_vendor_id_avp_cnt = 0; AAA_AVP *avp,*avp_vendor,*avp2; AAA_AVP_LIST group; int id,vendor; if (p->applications) { shm_free(p->applications); p->applications = 0; p->applications_cnt = 0; } supported_vendor_id_avp_cnt = count_Supported_Vendor_Id_AVPS(msg); for(avp=msg->avpList.head;avp;avp = avp->next) switch (avp->code){ case AVP_Auth_Application_Id: total_cnt += supported_vendor_id_avp_cnt; break; case AVP_Acct_Application_Id: total_cnt += supported_vendor_id_avp_cnt; break; case AVP_Vendor_Specific_Application_Id: total_cnt+=2;/* wasteful, but let's skip decoding */ break; } p->applications_cnt = 0; p->applications = shm_malloc(sizeof(app_config)*total_cnt); if (!p->applications){ LM_ERR("save_peer_applications(): Error allocating %ld bytes! No applications saved...\n", (long int)(sizeof(app_config)*total_cnt)); return; } for(avp=msg->avpList.head;avp;avp = avp->next) { switch (avp->code){ case AVP_Auth_Application_Id: id = get_4bytes(avp->data.s); add_peer_application(p,id,0,DP_AUTHORIZATION); avp_vendor = AAAFindMatchingAVP(msg,0,AVP_Supported_Vendor_Id,0,0); while (avp_vendor) { vendor = get_4bytes(avp_vendor->data.s); LM_DBG("Found Supported Vendor for Application %i: %i\n", DP_AUTHORIZATION, vendor); add_peer_application(p,id,vendor,DP_AUTHORIZATION); if (!avp_vendor->next) break; avp_vendor = AAAFindMatchingAVP(msg,avp_vendor->next,AVP_Supported_Vendor_Id,0,AAA_FORWARD_SEARCH); } break; case AVP_Acct_Application_Id: id = get_4bytes(avp->data.s); add_peer_application(p,id,0,DP_ACCOUNTING); avp_vendor = AAAFindMatchingAVP(msg,0,AVP_Supported_Vendor_Id,0,0); while (avp_vendor) { vendor = get_4bytes(avp_vendor->data.s); LM_DBG("Found Supported Vendor for Application %i: %i\n", DP_ACCOUNTING, vendor); add_peer_application(p,id,vendor,DP_ACCOUNTING); if (!avp_vendor->next) break; avp_vendor = AAAFindMatchingAVP(msg,avp_vendor->next,AVP_Supported_Vendor_Id,0,AAA_FORWARD_SEARCH); } break; case AVP_Vendor_Specific_Application_Id: group = AAAUngroupAVPS(avp->data); avp_vendor = AAAFindMatchingAVPList(group,group.head,AVP_Vendor_Id,0,0); avp2 = AAAFindMatchingAVPList(group,group.head,AVP_Auth_Application_Id,0,AAA_FORWARD_SEARCH); if (avp_vendor&&avp2){ vendor = get_4bytes(avp_vendor->data.s); id = get_4bytes(avp2->data.s); add_peer_application(p,id,vendor,DP_AUTHORIZATION); } avp2 = AAAFindMatchingAVPList(group,group.head,AVP_Acct_Application_Id,0,AAA_FORWARD_SEARCH); if (avp_vendor&&avp2){ vendor = get_4bytes(avp_vendor->data.s); id = get_4bytes(avp2->data.s); add_peer_application(p,id,vendor,DP_ACCOUNTING); } AAAFreeAVPList(&group); break; } } }
/** * This function convert message from the network format to the AAAMessage structure (decoder). * @param source - the source char buffer * @param sourceLen - the length of the input buffer * @param attach_buf - whether to attach the input buffer to the message * @returns the AAAMessage* or NULL on error * \note This function is taken from DISC http://developer.berlios.de/projects/disc/ */ AAAMessage* AAATranslateMessage( unsigned char* source, unsigned int sourceLen, int attach_buf) { unsigned char *ptr; AAAMessage *msg; unsigned char version; unsigned int msg_len; AAA_AVP *avp; unsigned int avp_code; unsigned char avp_flags; unsigned int avp_len; unsigned int avp_vendorID; unsigned int avp_data_len; /* check the params */ if( !source || !sourceLen || sourceLen<AAA_MSG_HDR_SIZE) { LOG(L_ERR,"ERROR:AAATranslateMessage: invalid buffered received!\n"); goto error; } /* inits */ msg = 0; avp = 0; ptr = source; /* alloc a new message structure */ msg = (AAAMessage*)shm_malloc(sizeof(AAAMessage)); if (!msg) { LOG(L_ERR,"ERROR:AAATranslateMessage: no more free memory!!\n"); goto error; } memset(msg,0,sizeof(AAAMessage)); /* get the version */ version = (unsigned char)*ptr; ptr += VER_SIZE; if (version!=1) { LOG(L_ERR,"ERROR:AAATranslateMessage: invalid version [%d]in " "AAA msg\n",version); goto error; } /* message length */ msg_len = get_3bytes( ptr ); ptr += MESSAGE_LENGTH_SIZE; if (msg_len>sourceLen) { LOG(L_ERR,"ERROR:AAATranslateMessage: AAA message len [%d] bigger then" " buffer len [%d]\n",msg_len,sourceLen); goto error; } /* command flags */ msg->flags = *ptr; ptr += FLAGS_SIZE; /* command code */ msg->commandCode = get_3bytes( ptr ); ptr += COMMAND_CODE_SIZE; /* application-Id */ msg->applicationId = get_4bytes( ptr ); ptr += APPLICATION_ID_SIZE; /* Hop-by-Hop-Id */ msg->hopbyhopId = ntohl(*((unsigned int*)ptr)); ptr += HOP_BY_HOP_IDENTIFIER_SIZE; /* End-to-End-Id */ msg->endtoendId = ntohl(*((unsigned int*)ptr)); ptr += END_TO_END_IDENTIFIER_SIZE; /* start decoding the AVPS */ while (ptr < source+msg_len) { if (ptr+AVP_HDR_SIZE(0x80)>source+msg_len){ LOG(L_ERR,"ERROR:AAATranslateMessage: source buffer to short!! " "Cannot read the whole AVP header!\n"); goto error; } /* avp code */ avp_code = get_4bytes( ptr ); ptr += AVP_CODE_SIZE; /* avp flags */ avp_flags = (unsigned char)*ptr; ptr += AVP_FLAGS_SIZE; /* avp length */ avp_len = get_3bytes( ptr ); ptr += AVP_LENGTH_SIZE; if (avp_len<1) { LOG(L_ERR,"ERROR:AAATranslateMessage: invalid AVP len [%d]\n", avp_len); goto error; } /* avp vendor-ID */ avp_vendorID = 0; if (avp_flags&AAA_AVP_FLAG_VENDOR_SPECIFIC) { avp_vendorID = get_4bytes( ptr ); ptr += AVP_VENDOR_ID_SIZE; } /* data length */ avp_data_len = avp_len-AVP_HDR_SIZE(avp_flags); /*check the data length */ if ( source+msg_len<ptr+avp_data_len) { LOG(L_ERR,"ERROR:AAATranslateMessage: source buffer to short!! " "Cannot read a whole data for AVP!\n"); goto error; } /* create the AVP */ avp = AAACreateAVP( avp_code, avp_flags, avp_vendorID, (char*) ptr, avp_data_len, AVP_DONT_FREE_DATA); if (!avp) goto error; /* link the avp into aaa message to the end */ AAAAddAVPToMessage( msg, avp, msg->avpList.tail); ptr += to_32x_len( avp_data_len ); } /* link the buffer to the message */ if (attach_buf) { msg->buf.s = (char*) source; msg->buf.len = msg_len; } msg->sessionId = AAAFindMatchingAVP(msg,0,AVP_Session_Id,0,0); //AAAPrintMessage( msg ); return msg; error: LOG(L_ERR,"ERROR:AAATranslateMessage: message conversion droped!!\n"); AAAFreeMessage(&msg); return 0; }
/** * Retrieve the Session-Timeout, Auth-Lifetime and Auth-Grace-Period AVPs and update the session timers accordingly * @param x * @param msg */ void update_auth_session_timers(cdp_auth_session_t *x, AAAMessage *msg) { AAA_AVP *avp; uint32_t session_timeout = 0, grace_period = 0, auth_lifetime = 0; int update_grace = 0, update_lifetime = 0; avp = AAAFindMatchingAVP(msg, 0, AVP_Auth_Grace_Period, 0, 0); if (avp && avp->data.len == 4) { grace_period = get_4bytes(avp->data.s); update_grace = 1; } else { if (!avp) { grace_period = x->last_requested_grace; } } if (update_grace) x->grace_period = grace_period; avp = AAAFindMatchingAVP(msg, 0, AVP_Authorization_Lifetime, 0, 0); if (avp && avp->data.len == 4) { auth_lifetime = get_4bytes(avp->data.s); update_lifetime = 1; } else { if (!avp) { LM_DBG("using timers from our request as there is nothing in the response (lifetime) - last requested lifetime was [%d]\n", x->last_requested_lifetime); if (x->last_requested_lifetime > 0) { update_lifetime = 1; auth_lifetime = x->last_requested_lifetime; } } } if (update_lifetime) { switch (auth_lifetime) { case 0: x->lifetime = time(0); break; case 0xFFFFFFFF: x->lifetime = -1; break; default: x->lifetime = time(0) + auth_lifetime; } if (x->timeout != -1 && x->timeout < x->lifetime) { x->timeout = x->lifetime + x->grace_period; } } avp = AAAFindMatchingAVP(msg, 0, AVP_Session_Timeout, 0, 0); if (avp && avp->data.len == 4) { session_timeout = get_4bytes(avp->data.s); switch (session_timeout) { case 0: x->timeout = time(0) + config->default_auth_session_timeout; break; case 0xFFFFFFFF: x->timeout = -1; break; default: x->timeout = time(0) + session_timeout; } if (!x->lifetime) x->lifetime = x->timeout; } }
void Send_STR(cdp_session_t* s, AAAMessage* msg) { AAAMessage *str = 0; AAA_AVP *avp = 0; peer *p = 0; char x[4]; LM_DBG("sending STR\n"); //if (msg) LM_DBG("Send_STR() : sending STR for %d, flags %#1x endtoend %u hopbyhop %u\n",msg->commandCode,msg->flags,msg->endtoendId,msg->hopbyhopId); //else LM_DBG("Send_STR() called from AAATerminateAuthSession or some other event\n"); str = AAACreateRequest(s->application_id, IMS_STR, Flag_Proxyable, s); if (!str) { LM_ERR("Send_STR(): error creating STR!\n"); return; } if (!dup_routing_avps(msg, str)) { LM_ERR("Send_STR(): error duplicating routing AVPs!\n"); AAAFreeMessage(&str); return; } if (s->vendor_id != 0 && !add_vendor_specific_application_id_group(str, s->vendor_id, s->application_id)) { LM_ERR("Send_STR(): error adding Vendor-Id-Specific-Application-Id Group!\n"); AAAFreeMessage(&str); return; } //Richard added this - if timers expire dest realm is not here! LM_DBG("Adding dest realm if not there already...\n"); LM_DBG("Destination realm: [%.*s] \n", s->dest_realm.len, s->dest_realm.s); /* Add Destination-Realm AVP, if not already there */ avp = AAAFindMatchingAVP(str, str->avpList.head, AVP_Destination_Realm, 0, AAA_FORWARD_SEARCH); if (!avp) { avp = AAACreateAVP(AVP_Destination_Realm, AAA_AVP_FLAG_MANDATORY, 0, s->dest_realm.s, s->dest_realm.len, AVP_DUPLICATE_DATA); AAAAddAVPToMessage(str, avp, str->avpList.tail); } set_4bytes(x, s->application_id); avp = AAACreateAVP(AVP_Auth_Application_Id, AAA_AVP_FLAG_MANDATORY, 0, x, 4, AVP_DUPLICATE_DATA); AAAAddAVPToMessage(str, avp, str->avpList.tail); set_4bytes(x, 4); // Diameter_administrative avp = AAACreateAVP(AVP_Termination_Cause, AAA_AVP_FLAG_MANDATORY, 0, x, 4, AVP_DUPLICATE_DATA); AAAAddAVPToMessage(str, avp, str->avpList.tail); //todo - add all the other avps /* we are already locked on the auth session*/ p = get_routing_peer(s, str); if (!p) { LM_ERR("unable to get routing peer in Send_STR \n"); if (str) AAAFreeMessage(&str); //needed in frequency return; } //if (str) LM_CRIT("Send_STR() : sending STR %d, flags %#1x endtoend %u hopbyhop %u\n",str->commandCode,str->flags,str->endtoendId,str->hopbyhopId); if (!peer_send_msg(p, str)) { LM_DBG("Send_STR peer_send_msg return error!\n"); if (str) AAAFreeMessage(&str); //needed in frequency } else { LM_DBG("success sending STR\n"); } }
/** * Sends a message to the peer. * \note Must be called with a lock on the peer. * @param p - peer to send to * @param msg - message to send */ void Snd_Message(peer *p, AAAMessage *msg) { AAASession *session=0; int rcode; int send_message_before_session_sm=0; LM_DBG("Snd_Message called to peer [%.*s] for %s with code %d \n", p->fqdn.len,p->fqdn.s,is_req(msg)?"request":"response",msg->commandCode); touch_peer(p); if (msg->sessionId) session = cdp_get_session(msg->sessionId->data); if (session){ LM_DBG("There is a session of type %d\n",session->type); switch (session->type){ case AUTH_CLIENT_STATEFULL: if (is_req(msg)) { auth_client_statefull_sm_process(session,AUTH_EV_SEND_REQ,msg); session = 0; } else { if (msg->commandCode == IMS_ASA){ if (!msg->res_code){ msg->res_code = AAAFindMatchingAVP(msg,0,AVP_Result_Code,0,0); } if (!msg->res_code) { auth_client_statefull_sm_process(session,AUTH_EV_SEND_ASA_UNSUCCESS,msg); session = 0; } else { rcode = get_4bytes(msg->res_code->data.s); if (rcode>=2000 && rcode<3000) { peer_send_msg(p,msg); send_message_before_session_sm=1; auth_client_statefull_sm_process(session,AUTH_EV_SEND_ASA_SUCCESS,msg); session = 0; } else { auth_client_statefull_sm_process(session,AUTH_EV_SEND_ASA_UNSUCCESS,msg); session = 0; } } }else { auth_client_statefull_sm_process(session,AUTH_EV_SEND_ANS,msg); session = 0; } } break; case AUTH_SERVER_STATEFULL: LM_DBG("this message is matched here to see what request or reply it is\n"); if (is_req(msg)) { if (msg->commandCode== IMS_ASR) { LM_DBG("ASR\n"); auth_server_statefull_sm_process(session,AUTH_EV_SEND_ASR,msg); session = 0; } else { //would be a RAR but ok! LM_DBG("other request\n"); auth_server_statefull_sm_process(session,AUTH_EV_SEND_REQ,msg); session = 0; } } else { if (msg->commandCode == IMS_STR) { LM_DBG("STA\n"); auth_server_statefull_sm_process(session,AUTH_EV_SEND_STA,msg); session = 0; } else { LM_DBG("other reply\n"); auth_server_statefull_sm_process(session,AUTH_EV_SEND_ANS,msg); session = 0; } } break; default: break; } if (session) AAASessionsUnlock(session->hash); } if (!send_message_before_session_sm) peer_send_msg(p,msg); }
/** * Get the first connect peer that matches the routing mechanisms. * - First the Destination-Host AVP value is tried if connected (the peer does not have to * be in the routing table at all). * - Then we look for a connected peer in the specific realm for the Destination-Realm AVP * - Then we look for the first connected peer in the default routes * @param m - the Diameter message to find the destination peer for * @returns - the connected peer or null if none connected found */ peer* get_routing_peer(cdp_session_t* cdp_session, AAAMessage *m) { str destination_realm = {0, 0}, destination_host = {0, 0}; AAA_AVP *avp, *avp_vendor, *avp2; AAA_AVP_LIST group; peer *p; routing_realm *rr; int app_id = 0, vendor_id = 0; LM_DBG("getting diameter routing peer for realm: [%.*s]\n", m->dest_realm->data.len, m->dest_realm->data.s); app_id = m->applicationId; avp = AAAFindMatchingAVP(m, 0, AVP_Vendor_Specific_Application_Id, 0, AAA_FORWARD_SEARCH); if (avp) { group = AAAUngroupAVPS(avp->data); avp_vendor = AAAFindMatchingAVPList(group, group.head, AVP_Vendor_Id, 0, 0); avp2 = AAAFindMatchingAVPList(group, group.head, AVP_Auth_Application_Id, 0, 0); if (avp_vendor && avp2) { vendor_id = get_4bytes(avp_vendor->data.s); app_id = get_4bytes(avp2->data.s); } avp2 = AAAFindMatchingAVPList(group, group.head, AVP_Acct_Application_Id, 0, 0); if (avp_vendor && avp2) { vendor_id = get_4bytes(avp_vendor->data.s); app_id = get_4bytes(avp2->data.s); } AAAFreeAVPList(&group); } avp_vendor = AAAFindMatchingAVP(m, 0, AVP_Vendor_Id, 0, AAA_FORWARD_SEARCH); avp = AAAFindMatchingAVP(m, 0, AVP_Auth_Application_Id, 0, AAA_FORWARD_SEARCH); if (avp && avp_vendor) { vendor_id = get_4bytes(avp_vendor->data.s); app_id = get_4bytes(avp->data.s); } avp = AAAFindMatchingAVP(m, 0, AVP_Acct_Application_Id, 0, AAA_FORWARD_SEARCH); if (avp && avp_vendor) { vendor_id = get_4bytes(avp_vendor->data.s); app_id = get_4bytes(avp->data.s); } avp = AAAFindMatchingAVP(m, 0, AVP_Destination_Host, 0, AAA_FORWARD_SEARCH); if (avp) destination_host = avp->data; if (destination_host.len) { /* There is a destination host present in the message try and route directly there */ p = get_peer_by_fqdn(&destination_host); if (p && (p->state == I_Open || p->state == R_Open) && peer_handles_application(p, app_id, vendor_id)) { p->last_selected = time(NULL); return p; } /* the destination host peer is not connected at the moment, try a normal route then */ } avp = AAAFindMatchingAVP(m, 0, AVP_Destination_Realm, 0, AAA_FORWARD_SEARCH); if (avp) destination_realm = avp->data; if (!config->r_table) { LM_ERR("get_routing_peer(): Empty routing table.\n"); return 0; } if (destination_realm.len) { /* first search for the destination realm */ for (rr = config->r_table->realms; rr; rr = rr->next) if (rr->realm.len == destination_realm.len && strncasecmp(rr->realm.s, destination_realm.s, destination_realm.len) == 0) break; if (rr) { p = get_first_connected_route(cdp_session, rr->routes, app_id, vendor_id); if (p) return p; else LM_ERR("get_routing_peer(): No connected Route peer found for Realm <%.*s>. Trying DefaultRoutes next...\n", destination_realm.len, destination_realm.s); } } /* if not found in the realms or no destination_realm, * get the first connected host in default routes */ LM_DBG("no routing peer found, trying default route\n"); p = get_first_connected_route(cdp_session, config->r_table->routes, app_id, vendor_id); if (!p) { LM_ERR("get_routing_peer(): No connected DefaultRoute peer found for app_id %d and vendor id %d.\n", app_id, vendor_id); } return p; }
/** * Allocates a new AAAMessage. * @param commandCode - the command code for this message * @param applicationId - application id to be set * @param sessionId - session id to be set * @param request - if you want to create a response, put the request here. If you want a * request, call with NULL * @returns the AAAMessage* or NULL on error * \note This function is taken from DISC http://developer.berlios.de/projects/disc/ */ AAAMessage *AAANewMessage( AAACommandCode commandCode, AAAApplicationId applicationId, AAASession *session, AAAMessage *request) { AAAMessage *msg; AAA_AVP *avp; AAA_AVP *avp_t; str *sessionId=0; #if 0 unsigned int code; #endif // str dest_host={"?",1}; str dest_realm={"?",1}; msg = 0; if (!session||!session->id.s) { if (request){ /* copy old session id from AVP */ if (request->sessionId) sessionId = &(request->sessionId->data); }else{ if (commandCode!=Code_DW) LM_DBG("AAANewMessage: param session received null and it's a request!!\n"); } }else{ sessionId = &(session->id); } /* allocated a new AAAMessage structure and set it to 0 */ msg = (AAAMessage*)shm_malloc(sizeof(AAAMessage)); if (!msg) { LM_ERR("AAANewMessage: no more free memory!!\n"); goto error; } memset(msg,0,sizeof(AAAMessage)); /* command code */ msg->commandCode = commandCode; /* application ID */ msg->applicationId = applicationId; /*add session ID */ if (sessionId){ avp = AAACreateAVP( 263, 0, 0, sessionId->s, sessionId->len, AVP_DUPLICATE_DATA); if ( !avp || AAAAddAVPToMessage(msg,avp,0)!=AAA_ERR_SUCCESS) { LM_ERR("AAANewMessage: cannot create/add Session-Id avp\n"); if (avp) AAAFreeAVP( &avp ); goto error; } msg->sessionId = avp; } /* add origin host AVP */ /* changed by cristian to comply with rfc3588: * 6.3. Origin-Host AVP * * The Origin-Host AVP (AVP Code 264) is of type * DiameterIdentity... */ avp = AAACreateAVP( 264, 0, 0, config->fqdn.s, config->fqdn.len, AVP_DUPLICATE_DATA); if (!avp||AAAAddAVPToMessage(msg,avp,msg->avpList.tail)!=AAA_ERR_SUCCESS) { LM_ERR("AAANewMessage: cannot create/add Origin-Host avp\n"); if (avp) AAAFreeAVP( &avp ); goto error; } msg->orig_host = avp; /* add origin realm AVP */ avp = AAACreateAVP( 296, 0, 0, config->realm.s, config->realm.len, AVP_DUPLICATE_DATA); if (!avp||AAAAddAVPToMessage(msg,avp,msg->avpList.tail)!=AAA_ERR_SUCCESS) { LM_ERR("AAANewMessage: cannot create/add Origin-Realm avp\n"); if (avp) AAAFreeAVP( &avp ); goto error; } msg->orig_realm = avp; if (!request) { /* it's a new request -> set the flag */ msg->flags = 0x80; } else { /* link the incoming peer to the answer */ msg->in_peer = request->in_peer; /* set the P flag as in request */ msg->flags |= request->flags&0x40; /**/ msg->endtoendId = request->endtoendId; msg->hopbyhopId = request->hopbyhopId; //TODO: aon:move this information in the AAASession structure, do not add these fields for if (msg->commandCode==Code_CE||msg->commandCode==Code_DP||msg->commandCode==Code_DW || msg->commandCode==Diameter_CCR || msg->commandCode==Diameter_RAR){ // Don't add Destination Host/Realm because some stacks are way to picky and will just refuse it }else{ /* Mirror the old originhost/realm to destinationhost/realm*/ //avp = AAAFindMatchingAVP(request,0,AVP_Origin_Host,0,0); //if (avp) dest_host = avp->data; /* add destination host and destination realm */ //avp = AAACreateAVP(AVP_Destination_Host,AAA_AVP_FLAG_MANDATORY,0, // dest_host.s,dest_host.len,AVP_DUPLICATE_DATA); //if (!avp) { // LM_ERR("ERR:AAANewMessage: Failed creating Destination Host avp\n"); // goto error; // } // if (AAAAddAVPToMessage(msg,avp,msg->avpList.tail)!=AAA_ERR_SUCCESS) { // LM_ERR("ERR:AAANewMessage: Failed adding Destination Host avp to message\n"); // AAAFreeAVP(&avp); // goto error; // } avp = AAAFindMatchingAVP(request,0,AVP_Origin_Realm,0,0); if (avp) dest_realm = avp->data; avp = AAACreateAVP(AVP_Destination_Realm,AAA_AVP_FLAG_MANDATORY,0, dest_realm.s,dest_realm.len,AVP_DUPLICATE_DATA); if (!avp) { LM_ERR("ERR:AAANewMessage: Failed creating Destination Realm avp\n"); goto error; } if (AAAAddAVPToMessage(msg,avp,msg->avpList.tail)!=AAA_ERR_SUCCESS) { LM_ERR("ERR:AAANewMessage: Failed adding Destination Realm avp to message\n"); AAAFreeAVP(&avp); goto error; } } msg->res_code=0; /* mirror all the proxy-info avp in the same order */ avp_t = request->avpList.head; while ( (avp_t=AAAFindMatchingAVP (request,avp_t,284,0,AAA_FORWARD_SEARCH))!=0 ) { if ( (avp=AAACloneAVP(avp_t,1))==0 || AAAAddAVPToMessage( msg, avp, msg->avpList.tail)!=AAA_ERR_SUCCESS ) goto error; } } return msg; error: LM_ERR("AAANewMessage: failed to create a new AAA message!\n"); AAAFreeMessage(&msg); return 0; }