Exemplo n.º 1
0
/**
 * Processes an incoming message.
 * This actually just puts the message into a message queue. One worker will pick-it-up
 * and do the actual processing.
 * \note Must be called with a lock on the peer.
 * @param p - peer received from
 * @param msg - the message received
 */
void Rcv_Process(peer *p, AAAMessage *msg)
{
	AAASession *session=0;
	int nput=0;
	if (msg->sessionId) session = cdp_get_session(msg->sessionId->data);

	if (session){
		switch (session->type){
			case ACCT_CC_CLIENT:
				if (is_req(msg)){
					LM_WARN("unhandled receive request on Credit Control Acct session\n");
					AAASessionsUnlock(session->hash);	//must be called because we dont call state machine here
					session = 0; //we dont call SM here so we mustnt set to 0
				} else {
					cc_acc_client_stateful_sm_process(session, ACC_CC_EV_RECV_ANS, msg);
					session = 0;
				}
				break;
			case AUTH_CLIENT_STATEFULL:
				if (is_req(msg)){
					if (msg->commandCode==IMS_ASR)
						auth_client_statefull_sm_process(session,AUTH_EV_RECV_ASR,msg);
					else
						auth_client_statefull_sm_process(session,AUTH_EV_RECV_REQ,msg);
					session = 0;
				}else {
					if (msg->commandCode==IMS_STA)
						nput=auth_client_statefull_sm_process(session,AUTH_EV_RECV_STA,msg);
					else
						auth_client_statefull_sm_process(session,AUTH_EV_RECV_ANS,msg);
					session = 0;
				}
				break;
			case AUTH_SERVER_STATEFULL:
				if (is_req(msg))
				{
					if (msg->commandCode==IMS_STR)
					{
						auth_server_statefull_sm_process(session,AUTH_EV_RECV_STR,msg);
					} else {
						auth_server_statefull_sm_process(session,AUTH_EV_RECV_REQ,msg);
					}
					session = 0;
				}else{
					if (msg->commandCode==IMS_ASA)
						auth_server_statefull_sm_process(session,AUTH_EV_RECV_ASA,msg);
					else
						auth_server_statefull_sm_process(session,AUTH_EV_RECV_ANS,msg);
					session = 0;
				}
				break;
			default:
				AAASessionsUnlock(session->hash);
				session =0;
				break;
		}
	}else{
		if (msg->sessionId){
			if (msg->commandCode == IMS_ASR)
				auth_client_statefull_sm_process(0,AUTH_EV_RECV_ASR,msg);
		}

	}
	if (!nput && !put_task(p,msg)){
		LM_ERR("Rcv_Process(): Queue refused task\n");
		if (msg) AAAFreeMessage(&msg);
	}
	//if (msg) LM_ERR("Rcv_Process(): task added to queue command %d, flags %#1x endtoend %u hopbyhop %u\n",msg->commandCode,msg->flags,msg->endtoendId,msg->hopbyhopId);

	//	AAAPrintMessage(msg);

}
Exemplo n.º 2
0
/**
 * Diameter base protocol state-machine processing.
 * This function get's called for every event. It updates the states and can trigger
 * other events.
 * @param p - the peer for which the event happened
 * @param event - the event that happened
 * @param msg - if a Diameter message was received this is it, or NULL if not
 * @param peer_locked - if the peer lock is already aquired
 * @param sock - socket that this event happened on, or NULL if unrelated
 * @returns 1 on success, 0 on error. Also the peer states are updated
 */
int sm_process(peer *p,peer_event_t event,AAAMessage *msg,int peer_locked,int sock)
{
	int result_code;
	peer_event_t next_event;
	int msg_received=0;

	if (!peer_locked) lock_get(p->lock);
	LM_DBG("sm_process(): Peer %.*s State %s Event %s\n",
			p->fqdn.len,p->fqdn.s,dp_states[p->state],dp_events[event-101]);

	switch (p->state){
		case Closed:
			switch (event){
				case Start:
					p->state = Wait_Conn_Ack;
					next_event = I_Snd_Conn_Req(p);
					if (next_event==I_Rcv_Conn_NAck)
						sm_process(p,next_event,0,1,p->I_sock);
					else{
						/* wait for fd to be transmitted to the respective receiver,
						 * in order to get a send pipe opened */
					}
					break;
				case R_Conn_CER:
					R_Accept(p,sock);
					result_code = Process_CER(p,msg);
					Snd_CEA(p,msg,result_code,p->R_sock);
					msg=0;
					if (result_code>=2000 && result_code<3000)
						p->state = R_Open;
					else {
						R_Disc(p);
						p->state = Closed;
					}
					log_peer_list(L_INFO);
					break;
				case Stop:
					/* just ignore this state */
					p->state = Closed;
					break;
				default:
					LM_ERR("sm_process(): In state %s invalid event %s\n",
							dp_states[p->state],dp_events[event-101]);
					goto error;
			}
			break;
		case Wait_Conn_Ack:
			switch(event){
				case I_Rcv_Conn_Ack:
					I_Snd_CER(p);
					p->state = Wait_I_CEA;
					break;
				case I_Rcv_Conn_NAck:
					Cleanup(p,p->I_sock);
					p->state = Closed;
					break;
				case R_Conn_CER:
					if (p->r_cer) AAAFreeMessage(&(p->r_cer));
					R_Accept(p,sock);
					result_code = Process_CER(p,msg);
					if (result_code>=2000 && result_code<3000){
						p->state = Wait_Conn_Ack_Elect;
						p->r_cer = msg;
					}
					else {
						p->state = Closed;
						AAAFreeMessage(&msg);
						R_Disc(p);
						I_Disc(p);
					}
					break;
				case Timeout:
					Error(p,p->I_sock);
					p->state = Closed;
				default:
					LM_ERR("sm_process(): In state %s invalid event %s\n",
							dp_states[p->state],dp_events[event-101]);
					goto error;
			}
			break;

		case Wait_I_CEA:
			switch(event){
				case I_Rcv_CEA:
					result_code = Process_CEA(p,msg);
					if (result_code>=2000 && result_code<3000)
						p->state = I_Open;
					else {
						Cleanup(p,p->I_sock);
						p->state = Closed;
					}
					log_peer_list(L_INFO);
					break;
				case R_Conn_CER:
					if (p->r_cer) AAAFreeMessage(&(p->r_cer));
					R_Accept(p,sock);
					result_code = Process_CER(p,msg);
					if (result_code>=2000 && result_code<3000){
						p->state = Wait_Returns;
						if (Elect(p,msg)){
							// won the election = > I_Disc(), R_Send_CEA()
							LM_INFO("sm_process():Wait_I_CEA Win Elect \n");
							sm_process(p,Win_Election,msg,1,sock);
						} else {
							// lost the election => wait for I_Recv_CEA, then R_Disc()
							LM_INFO("sm_process():Wait_I_CEA Lose Elect \n");
							p->r_cer = msg;
							sm_process(p,I_Peer_Disc,0,1,p->I_sock);
						}
					}
					else{
						Snd_CEA(p,msg,result_code,p->R_sock);
						R_Disc(p);
						I_Disc(p);
						p->state=Closed;
						break;
					}
					break;
				case I_Peer_Disc:
					I_Disc(p);
					p->state = Closed;
					break;
				case I_Rcv_Non_CEA:
					Error(p,p->I_sock);
					p->state = Closed;
					break;
				case Timeout:
					Error(p,p->I_sock);
					p->state = Closed;
					break;
				default:
					LM_ERR("sm_process(): In state %s invalid event %s\n",
							dp_states[p->state],dp_events[event-101]);
					goto error;
			}
			break;

		case Wait_Conn_Ack_Elect:
			switch(event){
				case I_Rcv_Conn_Ack:
					I_Snd_CER(p);
					if (p->r_cer){
						p->state = Wait_Returns;
						if (Elect(p,p->r_cer)){
							// won the election = > I_Disc(), R_Send_CEA()
							LM_INFO("sm_process():Wait_Conn_Ack_Elect Win Elect \n");
							sm_process(p,Win_Election,p->r_cer,1,sock);
							p->r_cer = 0;
						} else {
							// lost the election => wait for I_Recv_CEA, then R_Disc()
							LM_INFO("sm_process():Wait_Conn_Ack_Elect Lose Elect \n");
							AAAFreeMessage(&p->r_cer);
						}
					} else {
						LM_ERR("sm_process():Wait_Conn_Ack_Elect, I_Rcv_Conn_Ack, No R-CER ! \n");
						p->state = Wait_I_CEA;
					}
					break;
				case I_Rcv_Conn_NAck:
					Cleanup(p,p->I_sock);
					if (p->r_cer){
						result_code = Process_CER(p,p->r_cer);
						Snd_CEA(p,p->r_cer,result_code,p->R_sock);
						p->r_cer=0;
						if (result_code>=2000 && result_code<3000)
							p->state = R_Open;
						else {
							R_Disc(p);
							p->state = Closed;
							//	p->state = R_Open; /* Or maybe I should disconnect it?*/
						}
					}else{
						LM_ERR("sm_process():Wait_Conn_Ack_Elect, I_Rcv_Conn_NAck No R-CER ! \n");
					}
					break;
				case R_Peer_Disc:
					R_Disc(p);
					p->state = Wait_Conn_Ack;
					break;
				case R_Conn_CER:
					R_Reject(p,sock);
					AAAFreeMessage(&msg);
					p->state = Wait_Conn_Ack_Elect;
					break;
				case Timeout:
					if (p->I_sock>=0) Error(p,p->I_sock);
					if (p->R_sock>=0) Error(p,p->R_sock);
					p->state = Closed;
					break;
				default:
					LM_ERR("sm_process(): In state %s invalid event %s\n",
							dp_states[p->state],dp_events[event-101]);
					goto error;
			}
			break;

		case Wait_Returns:
			switch(event){
				case Win_Election:
					/* this is the Win Election -> I is dropped, R is kept */
					LM_INFO("sm_process():Wait_Returns Win Elect \n");
					I_Disc(p);
					result_code = Process_CER(p,msg);
					Snd_CEA(p,msg,result_code,p->R_sock);
					if (result_code>=2000 && result_code<3000){
						p->state = R_Open;
					}else{
						R_Disc(p);
						p->state = Closed;
					}
					break;
				case I_Peer_Disc:
					I_Disc(p);
					if (p->r_cer){
						result_code = Process_CER(p,p->r_cer);
						Snd_CEA(p,p->r_cer,result_code,p->R_sock);
						p->r_cer=0;
						if (result_code>=2000 && result_code<3000){
							p->state = R_Open;
						}else{
							R_Disc(p);
							p->state = Closed;
						}
					}else {
						LM_ERR("sm_process():Wait_Returns, I_Peer_Disc No R-CER ! \n");
					}
					break;
				case I_Rcv_CEA:
					/* this is the Lost Election -> I is kept, R dropped */
					LM_INFO("sm_process():Wait_Returns Lost Elect \n");
					R_Disc(p);
					result_code = Process_CEA(p,msg);
					if (result_code>=2000 && result_code<3000)
						p->state = I_Open;
					else {
						Cleanup(p,p->I_sock);
						p->state = Closed;
					}
					break;
				case R_Peer_Disc:
					R_Disc(p);
					p->state = Wait_I_CEA;
					break;
				case R_Conn_CER:
					R_Reject(p,p->R_sock);
					AAAFreeMessage(&msg);
					p->state = Wait_Returns;
					break;
				case Timeout:
					if (p->I_sock>=0) Error(p,p->I_sock);
					if (p->R_sock>=0) Error(p,p->R_sock);
					p->state = Closed;
				default:
					LM_ERR("sm_process(): In state %s invalid event %s\n",
							dp_states[p->state],dp_events[event-101]);
					goto error;
			}
			break;
		case R_Open:
			switch (event){
				case Send_Message:
					Snd_Message(p,msg);
					p->state = R_Open;
					break;
				case R_Rcv_Message:
					// delayed processing until out of the critical zone
					//Rcv_Process(p,msg);
					msg_received = 1;
					p->state = R_Open;
					break;
				case R_Rcv_DWR:
					result_code = Process_DWR(p,msg);
					Snd_DWA(p,msg,result_code,p->R_sock);
					p->state = R_Open;
					break;
				case R_Rcv_DWA:
					Process_DWA(p,msg);
					p->state = R_Open;
					break;
				case R_Conn_CER:
					R_Reject(p,sock);
					AAAFreeMessage(&msg);
					p->state = R_Open;
					break;
				case Stop:
					Snd_DPR(p);
					p->state = Closing;
					break;
				case R_Rcv_DPR:
					Snd_DPA(p,msg,AAA_SUCCESS,p->R_sock);
					R_Disc(p);
					p->state = Closed;
					log_peer_list(L_INFO);
					break;
				case R_Peer_Disc:
					R_Disc(p);
					p->state = Closed;
					log_peer_list(L_INFO);
					break;
				case R_Rcv_CER:
					result_code = Process_CER(p,msg);
					Snd_CEA(p,msg,result_code,p->R_sock);
					if (result_code>=2000 && result_code<3000)
						p->state = R_Open;
					else {
						/*R_Disc(p);p.state = Closed;*/
						p->state = R_Open; /* Or maybe I should disconnect it?*/
					}
					break;
				case R_Rcv_CEA:
					result_code = Process_CEA(p,msg);
					if (result_code>=2000 && result_code<3000)
						p->state = R_Open;
					else {
						/*R_Disc(p);p.state = Closed;*/
						p->state = R_Open; /* Or maybe I should disconnect it?*/
					}
					log_peer_list(L_INFO);
					break;
				default:
					LM_ERR("sm_process(): In state %s invalid event %s\n",
							dp_states[p->state],dp_events[event-101]);
					goto error;
			}
			break;
		case I_Open:
			switch (event){
				case Send_Message:
					Snd_Message(p,msg);
					p->state = I_Open;
					break;
				case I_Rcv_Message:
					// delayed processing until out of the critical zone
					//Rcv_Process(p,msg);
					msg_received = 1;
					p->state = I_Open;
					break;
				case I_Rcv_DWR:
					result_code = Process_DWR(p,msg);
					Snd_DWA(p,msg,result_code,p->I_sock);
					p->state =I_Open;
					break;
				case I_Rcv_DWA:
					Process_DWA(p,msg);
					p->state =I_Open;
					break;
				case R_Conn_CER:
					R_Reject(p,sock);
					AAAFreeMessage(&msg);
					p->state = I_Open;
					break;
				case Stop:
					Snd_DPR(p);
					p->state = Closing;
					break;
				case I_Rcv_DPR:
					Snd_DPA(p,msg,2001,p->I_sock);
					I_Disc(p);
					p->state = Closed;
					log_peer_list(L_INFO);
					break;
				case I_Peer_Disc:
					I_Disc(p);
					p->state = Closed;
					log_peer_list(L_INFO);
					break;
				case I_Rcv_CER:
					result_code = Process_CER(p,msg);
					Snd_CEA(p,msg,result_code,p->I_sock);
					if (result_code>=2000 && result_code<3000)
						p->state = I_Open;
					else {
						/*I_Disc(p);p.state = Closed;*/
						p->state = I_Open; /* Or maybe I should disconnect it?*/
					}
					break;
				case I_Rcv_CEA:
					result_code = Process_CEA(p,msg);
					if (result_code>=2000 && result_code<3000)
						p->state = I_Open;
					else {
						/*I_Disc(p);p.state = Closed;*/
						p->state = I_Open; /* Or maybe I should disconnect it?*/
					}
					break;
				default:
					LM_ERR("sm_process(): In state %s invalid event %s\n",
							dp_states[p->state],dp_events[event-101]);
					goto error;
			}
			break;
		case Closing:
			switch(event){
				case I_Rcv_DPA:
					I_Disc(p);
					p->state = Closed;
					break;
				case R_Rcv_DPA:
					R_Disc(p);
					p->state = Closed;
					break;
				case Timeout:
					if (p->I_sock>=0) Error(p,p->I_sock);
					if (p->R_sock>=0) Error(p,p->R_sock);
					p->state = Closed;
					break;
				case I_Peer_Disc:
					I_Disc(p);
					p->state = Closed;
					break;
				case R_Peer_Disc:
					R_Disc(p);
					p->state = Closed;
					break;
				default:
					LM_ERR("sm_process(): In state %s invalid event %s\n",
							dp_states[p->state],dp_events[event-101]);
					goto error;
			}
			break;
	}
	if (!peer_locked) lock_release(p->lock);

	if (msg_received)
		Rcv_Process(p,msg);

	return 1;
error:
	if (!peer_locked) lock_release(p->lock);
	return 0;
}
Exemplo n.º 3
0
/**
 * Select on sockets for receiving.
 * Selects on both the socket and on the send pipe.
 * @param s - the receive socket
 * @param buf - buffer to read into
 * @param len - max length of the read buffer
 * @param opt - recv() flags
 * @returns number of bytes read or -1 on error 
 */ 
static inline int select_recv(int s,void * buf,int len,int opt)
{
	fd_set rfds,efds;
	struct timeval tv;
	int n,max;
	AAAMessage *msg=0;
	int r=0,cnt=0;
	
//	if (shutdownx) return -1;
	max = s;
	if (pipe_fd>max) max = pipe_fd;
	n = 0;
	
	while(!n){
   		if (shutdownx&&*shutdownx) break;	

		FD_ZERO(&rfds);
		FD_SET(s,&rfds);
		FD_SET(pipe_fd,&rfds);
		FD_ZERO(&efds);
		FD_SET(s,&efds);
		tv.tv_sec=1;
		tv.tv_usec=0;

//		LOG(L_CRIT,"ERROR:select_recv(): HERE\n");
		
		n = select(max+1,&rfds,0,&efds,&tv);
		if (n==-1){
			if (shutdownx&&*shutdownx) return -1;
			LOG(L_ERR,"ERROR:select_recv(): %s\n",strerror(errno));
			return -1;
		}else
			if (n){
				if (FD_ISSET(s,&efds)) return -1;				
				if (FD_ISSET(pipe_fd,&rfds)) {					
					LOG(L_DBG,"DBG:select_recv(): There is something on the pipe\n");
					cnt = read(pipe_fd,&msg,sizeof(AAAMessage *));
					LOG(L_DBG,"DBG:select_recv(): Pipe says [%p] %d\n",msg,cnt);
					if (cnt==0){
						//This is very stupid and might not work well - droped messages... to be fixed
						LOG(L_INFO,"INFO:select_recv(): ReOpening pipe for read. This should not happen...\n");
						close(pipe_fd);
						pipe_fd = open(pipe_name.s, O_RDONLY | O_NDELAY);
						goto receive;
					}
					if (cnt<sizeof(AAAMessage *)){
						if (cnt<0) LOG(L_ERR,"ERROR:select_recv(): Error reading from pipe\n");
						r = -1;
						goto receive;
					}	
					
					while( (cnt=write(s,msg->buf.s,msg->buf.len))==-1 ) {
						if (errno==EINTR)
							continue;
						LOG(L_ERR,"ERROR:select_recv(): write returned error> %s\n",
							strerror(errno));
						close(s);
						AAAFreeMessage(&msg);		
						r = -1;
						return r;
					}
											
					if (cnt!=msg->buf.len){
						LOG(L_ERR,"ERROR:select_recv(): only wrote %d/%d bytes\n",cnt,msg->buf.len);
						close(s);
						AAAFreeMessage(&msg);		
						r = -1;
						return r;
					}
					AAAFreeMessage(&msg);
					//don't return, maybe there is something to read
				}
receive:
				if (FD_ISSET(s,&rfds)) {
					cnt = recv(s,buf,len,opt);
					if (cnt==0) return -1;
					else return cnt;
				}
			}
		//LOG(L_ERR,".");
	}
	return r;
}
Exemplo n.º 4
0
/**
 * 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);								
		}
	}
}
Exemplo n.º 5
0
/**
 *  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)
				LOG(L_DBG,"ERROR: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) {
		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;
	} 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) {
				LOG(L_ERR,"ERR:AAANewMessage: Failed creating Destination Host avp\n");
				goto error;
			}
			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);
				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) {
				LOG(L_ERR,"ERR:AAANewMessage: Failed creating Destination Realm avp\n");
				goto error;
			}
			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);
				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:
	LOG(L_ERR,"ERROR:AAANewMessage: failed to create a new AAA message!\n");
	AAAFreeMessage(&msg);
	return 0;
}
Exemplo n.º 6
0
/**
 *  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;
}
Exemplo n.º 7
0
/**
 * Process a Diameter Watch-dog Answer.
 * The flag for waiting a DWA is reseted.
 * \note Must be called with a lock on the peer.
 * @param p - the peer that the DWR was received from
 * @param dwa - the DWA message
 */
void Process_DWA(peer *p,AAAMessage *dwa)
{
	p->waitingDWA = 0;
	AAAFreeMessage(&dwa);
}
Exemplo n.º 8
0
/* it checks if a user is member of a group */
int diameter_is_user_in(struct sip_msg* _m, char* _hf, char* _group)
{
	str *grp, user_name, user, domain, uri;
	dig_cred_t* cred = 0;
	int hf_type;
	struct hdr_field* h;
	struct sip_uri puri;
	AAAMessage *req;
	AAA_AVP *avp; 
	int ret;
	unsigned int tmp;

	grp = (str*)_group; /* via fixup */

	hf_type = (int)(long)_hf;

	uri.s = 0;
	uri.len = 0;

	/* extract the uri according with the _hf parameter */
	switch(hf_type) 
	{
		case 1: /* Request-URI */
			uri = *(GET_RURI(_m));
		break;

		case 2: /* To */
			if (get_to_uri(_m, &uri) < 0) 
			{
				LM_ERR("failed to extract To\n");
				return -2;
			}
			break;

		case 3: /* From */
			if (get_from_uri(_m, &uri) < 0) 
			{
				LM_ERR("failed to extract From URI\n");
				return -3;
			}
			break;

		case 4: /* Credentials */
			get_authorized_cred(_m->authorization, &h);
			if (!h) 	
			{
				get_authorized_cred(_m->proxy_auth, &h);
				if (!h) 
				{
					LM_ERR("no authorized credentials found "
							"(error in scripts)\n");
					return -4;
				}
			}
			cred = &((auth_body_t*)(h->parsed))->digest;
			break;
	}

	if (hf_type != 4) 
	{
		if (parse_uri(uri.s, uri.len, &puri) < 0) 
		{
			LM_ERR("failed to parse URI\n");
			return -5;
		}
		user = puri.user;
		domain = puri.host;
	} 
	else
	{
		user = cred->username.user;
		domain = cred->realm;
	}
	
	/* user@domain mode */
	if (use_domain)
	{
		user_name.s = 0;
		user_name.len = user.len + domain.len;
		if(user_name.len>0)
		{
			user_name.len++;
			user_name.s = (char*)pkg_malloc(user_name.len);
			if (!user_name.s) 
			{
				LM_ERR("no pkg memory left\n");
				return -6;
			}
		
			memcpy(user_name.s, user.s, user.len);
			if(user.len>0)
			{
				user_name.s[user.len] = '@';
				memcpy(user_name.s + user.len + 1, domain.s, domain.len);
			}
			else
				memcpy(user_name.s, domain.s, domain.len);
		}
	} 
	else 
		user_name = user;
	
	
	if ( (req=AAAInMessage(AA_REQUEST, AAA_APP_NASREQ))==NULL)
	{
		LM_ERR("can't create new AAA message!\n");
		return -1;
	}
	
	/* Username AVP */
	if( (avp=AAACreateAVP(AVP_User_Name, 0, 0, user_name.s,
				user_name.len, AVP_DUPLICATE_DATA)) == 0)
	{
		LM_ERR("no more pkg memory!\n");
		goto error;
	}
	if( AAAAddAVPToMessage(req, avp, 0)!= AAA_ERR_SUCCESS)
	{
		LM_ERR("avp not added \n");
		goto error1;
	}

	/* Usergroup AVP */
	if( (avp=AAACreateAVP(AVP_User_Group, 0, 0, grp->s,
				grp->len, AVP_DUPLICATE_DATA)) == 0)
	{
		LM_ERR("no more pkg memory!\n");
		goto error;
	}
	if( AAAAddAVPToMessage(req, avp, 0)!= AAA_ERR_SUCCESS)
	{
		LM_ERR("avp not added \n");
		goto error1;
	}

	/* SIP_MSGID AVP */
	LM_DBG("******* m_id=%d\n", _m->id);
	tmp = _m->id;
	if( (avp=AAACreateAVP(AVP_SIP_MSGID, 0, 0, (char*)(&tmp), 
				sizeof(tmp), AVP_DUPLICATE_DATA)) == 0)
	{
		LM_ERR("no more pkg memory!\n");
		goto error;
	}
	if( AAAAddAVPToMessage(req, avp, 0)!= AAA_ERR_SUCCESS)
	{
		LM_ERR("avp not added \n");
		goto error1;
	}

	
	/* ServiceType AVP */
	if( (avp=AAACreateAVP(AVP_Service_Type, 0, 0, SIP_GROUP_CHECK, 
				SERVICE_LEN, AVP_DUPLICATE_DATA)) == 0)
	{
		LM_ERR("no more pkg memory!\n");
		goto error;
	}
	if( AAAAddAVPToMessage(req, avp, 0)!= AAA_ERR_SUCCESS)
	{
		LM_ERR("avp not added \n");
		goto error1;
	}
	

	/* Destination-Realm AVP */
	uri = *(GET_RURI(_m));
	parse_uri(uri.s, uri.len, &puri);
	if( (avp=AAACreateAVP(AVP_Destination_Realm, 0, 0, puri.host.s,
						puri.host.len, AVP_DUPLICATE_DATA)) == 0)
	{
		LM_ERR("no more pkg memory!\n");
		goto error;
	}
	
	if( AAAAddAVPToMessage(req, avp, 0)!= AAA_ERR_SUCCESS)
	{
		LM_ERR("avp not added \n");
		goto error1;
	}
	
#ifdef DEBUG
	AAAPrintMessage(req);
#endif

	/* build a AAA message buffer */
	if(AAABuildMsgBuffer(req) != AAA_ERR_SUCCESS)
	{
		LM_ERR("message buffer not created\n");
		goto error;
	}

	if(sockfd==AAA_NO_CONNECTION)
	{
		sockfd = init_mytcp(diameter_client_host, diameter_client_port);
		if(sockfd==AAA_NO_CONNECTION)
		{
			LM_ERR("failed to reconnect to Diameter client\n");
			goto error;
		}
	}

	ret =tcp_send_recv(sockfd, req->buf.s, req->buf.len, rb, _m->id);

	if(ret == AAA_CONN_CLOSED)
	{
		LM_NOTICE("connection to Diameter client closed."
				"It will be reopened by the next request\n");
		close(sockfd);
		sockfd = AAA_NO_CONNECTION;
		goto error;
	}
	if(ret != AAA_USER_IN_GROUP)
	{
		LM_ERR("message sending to the DIAMETER backend authorization server"
				"failed or user is not in group\n");
		goto error;
	}
	
	AAAFreeMessage(&req);
	return 1;

error1:
	AAAFreeAVP(&avp);
error:
	AAAFreeMessage(&req);
	return -1;

}
Exemplo n.º 9
0
/**
 * Processes an incoming message.
 * This actually just puts the message into a message queue. One worker will pick-it-up
 * and do the actual processing.
 * \note Must be called with a lock on the peer.
 * @param p - peer received from
 * @param msg - the message received
 */ 
void Rcv_Process(peer *p, AAAMessage *msg)
{
	AAASession *session=0;
	unsigned int hash; // we need this here because after the sm_processing , we might end up
					   // with no session any more
	if (msg->sessionId) session = get_session(msg->sessionId->data);
	
	if (session){
		hash=session->hash;
		switch (session->type){
			case AUTH_CLIENT_STATEFULL:
				if (is_req(msg)){
					if (msg->commandCode==IMS_ASR)
						auth_client_statefull_sm_process(session,AUTH_EV_RECV_ASR,msg);
					else 
						auth_client_statefull_sm_process(session,AUTH_EV_RECV_REQ,msg);
				}else {
					if (msg->commandCode==IMS_STA)
						auth_client_statefull_sm_process(session,AUTH_EV_RECV_STA,msg);
					else
						auth_client_statefull_sm_process(session,AUTH_EV_RECV_ANS,msg);
				}
				break;
			 case AUTH_SERVER_STATEFULL:
			 	if (is_req(msg))
			 	{
			 		auth_server_statefull_sm_process(session,AUTH_EV_RECV_REQ,msg);
			 	}else{
			 		if (msg->commandCode==IMS_ASA)
			 			auth_server_statefull_sm_process(session,AUTH_EV_RECV_ASA,msg);
			 		else
			 			auth_server_statefull_sm_process(session,AUTH_EV_RECV_ANS,msg);
			 	}
			 	break;
			default:
				break;			 
		}
		sessions_unlock(hash);
	}else{
		if (msg->sessionId){
			if (msg->commandCode == IMS_ASR) 
				auth_client_statefull_sm_process(0,AUTH_EV_RECV_ASR,msg);
			if (msg->commandCode == IMS_AAR)
			{
				session=AAACreateAuthSession(0,0,1,0,0);
				
				shm_str_dup(session->id,msg->sessionId->data); 
				auth_server_statefull_sm_process(0,AUTH_EV_RECV_REQ,msg);				
			}
			// Any other cases to think about?	 
		} 
				 
	}

	if (!put_task(p,msg)){
		LOG(L_ERR,"ERROR:Rcv_Process(): Queue refused task\n");
		AAAFreeMessage(&msg);
	}
	LOG(L_DBG,"DBG:Rcv_Process(): task added to queue\n");
	
//	AAAPrintMessage(msg);
	
}
Exemplo n.º 10
0
/**
 * Selects once on sockets for receiving and sending stuff.
 * Monitors:
 *  - the fd exchange pipe, for receiving descriptors to be handled here
 *  - the tcp sockets of all serviced peers, triggering the incoming messages do_receive()
 *  - the send pipes of all serviced peers, triggering the sending of outgoing messages
 * @returns 0 on normal exit or -1 on error
 */
int receive_loop(peer *original_peer)
{
	fd_set rfds,efds;
	struct timeval tv;
	int n,max=0,cnt=0;
	AAAMessage *msg=0;
	serviced_peer_t *sp,*sp2;
	peer *p;
	int fd=-1;
	int fd_exchange_pipe_local=0;

	if (original_peer) fd_exchange_pipe_local = original_peer->fd_exchange_pipe_local;
	else fd_exchange_pipe_local = fd_exchange_pipe_unknown_local;

//	if (shutdownx) return -1;

	while(shutdownx&&!*shutdownx){
		n = 0;

		while(!n){
			if (shutdownx&&*shutdownx) break;
			cfg_update();

			log_serviced_peers();

			max =-1;

			FD_ZERO(&rfds);
			FD_ZERO(&efds);

			FD_SET(fd_exchange_pipe_local,&rfds);
			if (fd_exchange_pipe_local>max) max = fd_exchange_pipe_local;

			for(sp=serviced_peers;sp;sp=sp->next){
				if (sp->tcp_socket>=0){
					FD_SET(sp->tcp_socket,&rfds);
					FD_SET(sp->tcp_socket,&efds);
					if (sp->tcp_socket>max) max = sp->tcp_socket;
				}
				if (sp->send_pipe_fd>=0) {
					FD_SET(sp->send_pipe_fd,&rfds);
					if (sp->send_pipe_fd>max) max = sp->send_pipe_fd;
				}
			}

			tv.tv_sec=1;
			tv.tv_usec=0;

			n = select(max+1,&rfds,0,&efds,&tv);
			if (n==-1){
				if (shutdownx&&*shutdownx) return 0;
				LM_ERR("select_recv(): %s\n",strerror(errno));
				for(sp=serviced_peers;sp;sp=sp2){
					sp2 = sp->next;
					disconnect_serviced_peer(sp,0);
					if (sp->p && sp->p->is_dynamic)
						drop_serviced_peer(sp,0);
				}
				sleep(1);
				break;
			}else
				if (n){

					if (FD_ISSET(fd_exchange_pipe_local,&rfds)){
						/* fd exchange */
						LM_DBG("select_recv(): There is something on the fd exchange pipe\n");
						p = 0;
						fd = -1;
						if (!receive_fd(fd_exchange_pipe_local,&fd,&p)){
							LM_ERR("select_recv(): Error reading from fd exchange pipe\n");
						}else{
							LM_DBG("select_recv(): fd exchange pipe says fd [%d] for peer %p:[%.*s]\n",fd,
									p,
									p?p->fqdn.len:0,
									p?p->fqdn.s:0);
							if (p){
								sp2=0;
								for(sp=serviced_peers;sp;sp=sp->next)
									if (sp->p==p){
										sp2 = sp;
										break;
									}
								if (!sp2)
									sp2 = add_serviced_peer(p);
								else
									make_send_pipe(sp2);
								if (!sp2) {
									LM_ERR("Error on add_serviced_peer()\n");
									continue;
								}

								sp2->tcp_socket = fd;
								if (p->state == Wait_Conn_Ack){
									p->I_sock = fd;
									sm_process(p,I_Rcv_Conn_Ack,0,0,fd);
								}else{
									p->R_sock = fd;
								}
							}else{
								sp2 = add_serviced_peer(NULL);
								if (!sp2) {
									LM_ERR("Error on add_serviced_peer()\n");
									continue;
								}
								sp2->tcp_socket = fd;
							}
						}
					}

					for(sp=serviced_peers;sp;){
						if (sp->tcp_socket>=0 && FD_ISSET(sp->tcp_socket,&efds)) {
							LM_INFO("select_recv(): [%.*s] Peer socket [%d] found on the exception list... dropping\n",
									sp->p?sp->p->fqdn.len:0,
									sp->p?sp->p->fqdn.s:0,
									sp->tcp_socket);
							goto drop_peer;
						}
						if (sp->send_pipe_fd>=0 && FD_ISSET(sp->send_pipe_fd,&rfds)) {
							/* send */
							LM_DBG("select_recv(): There is something on the send pipe\n");
							cnt = read(sp->send_pipe_fd,&msg,sizeof(AAAMessage *));
							if (cnt==0){
								//This is very stupid and might not work well - droped messages... to be fixed
								LM_INFO("select_recv(): ReOpening pipe for read. This should not happen...\n");
								close(sp->send_pipe_fd);
								sp->send_pipe_fd = open(sp->send_pipe_name.s, O_RDONLY | O_NDELAY);
								goto receive;
							}
							if (cnt<sizeof(AAAMessage *)){
								if (cnt<0) LM_ERR("select_recv(): Error reading from send pipe\n");
								goto receive;
							}
							LM_DBG("select_recv(): Send pipe says [%p] %d\n",msg,cnt);
							if (sp->tcp_socket<0){
								LM_ERR("select_recv(): got a signal to send something, but the connection was not opened");
							} else {
								while( (cnt=write(sp->tcp_socket,msg->buf.s,msg->buf.len))==-1 ) {
									if (errno==EINTR)
										continue;
									LM_ERR("select_recv(): [%.*s] write on socket [%d] returned error> %s... dropping\n",
											sp->p?sp->p->fqdn.len:0,
											sp->p?sp->p->fqdn.s:0,
											sp->tcp_socket,
											strerror(errno));
									AAAFreeMessage(&msg);
									close(sp->tcp_socket);
									goto drop_peer;
								}

								if (cnt!=msg->buf.len){
									LM_ERR("select_recv(): [%.*s] write on socket [%d] only wrote %d/%d bytes... dropping\n",
											sp->p?sp->p->fqdn.len:0,
											sp->p?sp->p->fqdn.s:0,
											sp->tcp_socket,
											cnt,
											msg->buf.len);
									AAAFreeMessage(&msg);
									close(sp->tcp_socket);
									goto drop_peer;
								}
							}
							AAAFreeMessage(&msg);
							//don't return, maybe there is something to read
						}
	receive:
						/* receive */
						if (sp->tcp_socket>=0 && FD_ISSET(sp->tcp_socket,&rfds)) {
							errno=0;
							cnt = do_receive(sp);
							if (cnt<=0) {
								LM_INFO("select_recv(): [%.*s] read on socket [%d] returned %d > %s... dropping\n",
										sp->p?sp->p->fqdn.len:0,
										sp->p?sp->p->fqdn.s:0,
										sp->tcp_socket,
										cnt,
										errno?strerror(errno):"");
								goto drop_peer;
							}
						}

	//next_sp:
						/* go to next serviced peer */
						sp=sp->next;
						continue;
	drop_peer:
						/* drop this serviced peer on error */
						sp2 = sp->next;
						disconnect_serviced_peer(sp,0);
						if (sp->p && sp->p->is_dynamic)
							drop_serviced_peer(sp,0);
						sp = sp2;
					}
				}
		}
	}
	return 0;
}
Exemplo n.º 11
0
/**
 * 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);
		}
	}
}
Exemplo n.º 12
0
int acc_diameter_send_request(sip_msg_t *req, acc_info_t *inf)
{
	int attr_cnt;
	int cnt;
	AAAMessage *send = NULL;
	AAA_AVP *avp;
	struct sip_uri puri;
	str *uri;
	int ret;
	int i;
	int status;
	char tmp[2];
	unsigned int mid;
	int m;
	int o;

	attr_cnt =  accb.get_core_attrs(req, inf->varr, inf->iarr, inf->tarr);
	/* last value is not used */
	attr_cnt--;

	if ( (send=AAAInMessage(ACCOUNTING_REQUEST, AAA_APP_NASREQ))==NULL) {
		LM_ERR("failed to create new AAA request\n");
		return -1;
	}

	m = 0;
	o = 0;
	/* AVP_ACCOUNTIG_RECORD_TYPE */
	if( (status = diam_status(req, inf->env->code))<0) {
		LM_ERR("status unknown\n");
		goto error;
	}
	tmp[0] = status+'0';
	tmp[1] = 0;
	if( (avp=AAACreateAVP(AVP_Accounting_Record_Type, 0, 0, tmp,
					1, AVP_DUPLICATE_DATA)) == 0) {
		LM_ERR("failed to create AVP:no more free memory!\n");
		goto error;
	}
	if( AAAAddAVPToMessage(send, avp, 0)!= AAA_ERR_SUCCESS) {
		LM_ERR("avp not added \n");
		AAAFreeAVP(&avp);
		goto error;
	}
	/* SIP_MSGID AVP */
	mid = req->id;
	if( (avp=AAACreateAVP(AVP_SIP_MSGID, 0, 0, (char*)(&mid),
					sizeof(mid), AVP_DUPLICATE_DATA)) == 0) {
		LM_ERR("failed to create AVP:no more free memory!\n");
		goto error;
	}
	if( AAAAddAVPToMessage(send, avp, 0)!= AAA_ERR_SUCCESS) {
		LM_ERR("avp not added \n");
		AAAFreeAVP(&avp);
		goto error;
	}

	/* SIP Service AVP */
	if( (avp=AAACreateAVP(AVP_Service_Type, 0, 0, SIP_ACCOUNTING,
					SERVICE_LEN, AVP_DUPLICATE_DATA)) == 0) {
		LM_ERR("failed to create AVP:no more free memory!\n");
		goto error;
	}
	if( AAAAddAVPToMessage(send, avp, 0)!= AAA_ERR_SUCCESS) {
		LM_ERR("avp not added \n");
		AAAFreeAVP(&avp);
		goto error;
	}

	/* also the extra attributes */
	o = accb.get_extra_attrs(diameter_extra, req, inf->varr+attr_cnt,
			inf->iarr+attr_cnt, inf->tarr+attr_cnt);
	attr_cnt += o;
	m = attr_cnt;

	/* add attributes */
	for(i=0; i<attr_cnt; i++) {
		if((avp=AAACreateAVP(diam_attrs[i], 0,0, inf->varr[i].s, inf->varr[i].len,
						AVP_DUPLICATE_DATA)) == 0) {
			LM_ERR("failed to create AVP: no more free memory!\n");
			goto error;
		}
		if( AAAAddAVPToMessage(send, avp, 0)!= AAA_ERR_SUCCESS) {
			LM_ERR("avp not added \n");
			AAAFreeAVP(&avp);
			goto error;
		}
	}

	/* and the leg attributes */
	if ( inf->leg_info ) {
		cnt = accb.get_leg_attrs(inf->leg_info,req,inf->varr,inf->iarr,inf->tarr,1);
		do {
			for (i=0; i<cnt; i++) {
				if((avp=AAACreateAVP(diam_attrs[attr_cnt+i], 0, 0,
								inf->varr[i].s, inf->varr[i].len, AVP_DUPLICATE_DATA)) == 0) {
					LM_ERR("failed to create AVP: no more free memory!\n");
					goto error;
				}
				if( AAAAddAVPToMessage(send, avp, 0)!= AAA_ERR_SUCCESS) {
					LM_ERR("avp not added \n");
					AAAFreeAVP(&avp);
					goto error;
				}
			}
		} while ( (attr_cnt=accb.get_leg_attrs(inf->leg_info,req,inf->varr,inf->iarr,
						inf->tarr, 0))!=0 );
	}

	if (get_uri(req, &uri) < 0) {
		LM_ERR("failed to get uri, From/To URI not found\n");
		goto error;
	}

	if (parse_uri(uri->s, uri->len, &puri) < 0) {
		LM_ERR("failed to parse From/To URI\n");
		goto error;
	}

	/* Destination-Realm AVP */
	if( (avp=AAACreateAVP(AVP_Destination_Realm, 0, 0, puri.host.s,
					puri.host.len, AVP_DUPLICATE_DATA)) == 0) {
		LM_ERR("failed to create AVP:no more free memory!\n");
		goto error;
	}

	if( AAAAddAVPToMessage(send, avp, 0)!= AAA_ERR_SUCCESS) {
		LM_ERR("avp not added \n");
		AAAFreeAVP(&avp);
		goto error;
	}

	/* prepare the message to be sent over the network */
	if(AAABuildMsgBuffer(send) != AAA_ERR_SUCCESS) {
		LM_ERR("message buffer not created\n");
		goto error;
	}

	if(sockfd==AAA_NO_CONNECTION) {
		sockfd = init_mytcp(diameter_client_host, diameter_client_port);
		if(sockfd==AAA_NO_CONNECTION) {
			LM_ERR("failed to reconnect to Diameter client\n");
			goto error;
		}
	}

	/* send the message to the DIAMETER client */
	ret = tcp_send_recv(sockfd, send->buf.s, send->buf.len, rb, req->id);
	if(ret == AAA_CONN_CLOSED) {
		LM_NOTICE("connection to Diameter client closed.It will be "
				"reopened by the next request\n");
		close(sockfd);
		sockfd = AAA_NO_CONNECTION;
		goto error;
	}

	if(ret != ACC_SUCCESS) {
		/* a transmission error occurred */
		LM_ERR("message sending to the DIAMETER backend authorization "
				"server failed\n");
		goto error;
	}

	AAAFreeMessage(&send);
	/* free memory allocated by extra2strar */
	free_strar_mem( &(inf->tarr[m-o]), &(inf->varr[m-o]), o, m);
	return 1;

error:
	AAAFreeMessage(&send);
	/* free memory allocated by extra2strar */
	free_strar_mem( &(inf->tarr[m-o]), &(inf->varr[m-o]), o, m);
	return -1;
}
Exemplo n.º 13
0
/*
 * This function creates and submits diameter authentication request as per
 * draft-srinivas-aaa-basic-digest-00.txt. 
 * Service type of the request is Authenticate-Only.
 * Returns:
 * 		 1 - success
 * 		-1 - error
 * 			
 */
int diameter_authorize(struct hdr_field* hdr, str* p_method, struct sip_uri uri,
						struct sip_uri ruri, unsigned int m_id, rd_buf_t* rb)
{
	str user_name;
	AAAMessage *req;
	AAA_AVP *avp, *position; 
	int name_flag, port_flag;
	dig_cred_t* cred;
	unsigned int tmp;

	if ( !p_method )
	{
		LM_ERR("invalid parameter value\n");
		return -1;
	}

	if ( (req=AAAInMessage(AA_REQUEST, AAA_APP_NASREQ))==NULL)
		return -1;

	if(hdr && hdr->parsed)
		cred = &(((auth_body_t*)hdr->parsed)->digest);
	else
		cred = NULL;
			
	if(!cred)
	{
		/* Username AVP */
		user_name.s = 0;
		user_name.len = uri.user.len + uri.host.len;
		if(user_name.len>0)
		{
			user_name.len += 2;
			user_name.s = (char*)ad_malloc(user_name.len*sizeof(char));
			memset(user_name.s, 0, user_name.len);

			memcpy(user_name.s, uri.user.s, uri.user.len);
			if(uri.user.len>0)
			{
				memcpy(user_name.s+uri.user.len, "@", 1);
				memcpy(user_name.s+uri.user.len+1, uri.host.s, uri.host.len);
			}
			else
				memcpy(user_name.s, uri.host.s, uri.host.len);
		}

		if( (avp=AAACreateAVP(AVP_User_Name, 0, 0, user_name.s, 
							user_name.len, AVP_FREE_DATA)) == 0)
		{
			LM_ERR("no more pkg memory left!\n");
			if(user_name.len>0)
				pkg_free(user_name.s);
			goto error;
		}
		if( AAAAddAVPToMessage(req, avp, 0)!= AAA_ERR_SUCCESS)
		{
			LM_ERR("avp not added \n");
			goto error1;
		}
	}
	else /* it is a SIP message with credentials */
	{
		/* Add Username AVP */
		if (cred->username.domain.len>0) 
		{
			if( (avp=AAACreateAVP(AVP_User_Name, 0, 0, cred->username.whole.s,
							cred->username.whole.len, AVP_DUPLICATE_DATA)) == 0)
			{
				LM_ERR("no more pkg memory left!\n");
				goto error;
			}

			if( AAAAddAVPToMessage(req, avp, 0)!= AAA_ERR_SUCCESS)
			{
				LM_ERR("avp not added \n");
				goto error1;
			}
		}
		else 
		{
			user_name.s = 0;
			user_name.len = cred->username.user.len + cred->realm.len;
			if(user_name.len>0)
			{
				user_name.s = ad_malloc(user_name.len);
				if (!user_name.s) 
				{
					LM_ERR(" no more pkg memory left\n");
					goto error;
				}
				memcpy(user_name.s, cred->username.whole.s, 
									cred->username.whole.len);
				if(cred->username.whole.len>0)
				{
					user_name.s[cred->username.whole.len] = '@';
					memcpy(user_name.s + cred->username.whole.len + 1, 
							cred->realm.s, cred->realm.len);
				}
				else
					memcpy(user_name.s,	cred->realm.s, cred->realm.len);
			}

			if( (avp=AAACreateAVP(AVP_User_Name, 0, 0, user_name.s,	
							user_name.len, AVP_FREE_DATA)) == 0)
			{
				LM_ERR(" no more pkg memory left!\n");
				if(user_name.len>0)
					pkg_free(user_name.s);
				goto error;
			}

			if( AAAAddAVPToMessage(req, avp, 0)!= AAA_ERR_SUCCESS)
			{
				LM_ERR(" avp not added \n");
				goto error1;
			}
		}
	}

	/* SIP_MSGID AVP */
	LM_DBG("******* m_id=%d\n", m_id);
	tmp = m_id;
	if( (avp=AAACreateAVP(AVP_SIP_MSGID, 0, 0, (char*)(&tmp), 
				sizeof(m_id), AVP_DUPLICATE_DATA)) == 0)
	{
		LM_ERR(" no more pkg memory left!\n");
		goto error;
	}
	if( AAAAddAVPToMessage(req, avp, 0)!= AAA_ERR_SUCCESS)
	{
		LM_ERR(" avp not added \n");
		goto error1;
	}

	
	
	/* SIP Service AVP */
	if( (avp=AAACreateAVP(AVP_Service_Type, 0, 0, SIP_AUTHENTICATION, 
				SERVICE_LEN, AVP_DUPLICATE_DATA)) == 0)
	{
		LM_ERR(" no more pkg memory left!\n");
		goto error;
	}
	if( AAAAddAVPToMessage(req, avp, 0)!= AAA_ERR_SUCCESS)
	{
		LM_ERR(" avp not added \n");
		goto error1;
	}
		
	/* Destination-Realm AVP */
	if( (avp=AAACreateAVP(AVP_Destination_Realm, 0, 0, uri.host.s,
						uri.host.len, AVP_DUPLICATE_DATA)) == 0)
	{
		LM_ERR(" no more pkg memory left!\n");
		goto error;
	}

#ifdef DEBUG	
	LM_DBG("Destination Realm: %.*s\n", uri.host.len, uri.host.s);	
#endif

	if( AAAAddAVPToMessage(req, avp, 0)!= AAA_ERR_SUCCESS)
	{
		LM_ERR(" avp not added \n");
		goto error1;
	}
	
	/* Resource AVP */
	user_name.len = ruri.user.len + ruri.host.len + ruri.port.len + 2;
	user_name.s = (char*)ad_malloc(user_name.len*sizeof(char));
	memset(user_name.s, 0, user_name.len);
	memcpy(user_name.s, ruri.user.s, ruri.user.len);

	name_flag= 0;
	if(ruri.user.s)
	{		
		name_flag = 1;
		memcpy(user_name.s+ruri.user.len, "@", 1);
	}	

	memcpy(user_name.s+ruri.user.len+name_flag, ruri.host.s, ruri.host.len);

	port_flag=0;
	if(ruri.port.s)
	{
		port_flag = 1;	
		memcpy(user_name.s+ruri.user.len+ruri.host.len+1, ":", 1);
	}	
	memcpy(user_name.s+ruri.user.len+ruri.host.len+name_flag+port_flag, 
					ruri.port.s, ruri.port.len);
#ifdef DEBUG
	LM_DBG(": AVP_Resource=%.*s\n", user_name.len, user_name.s);
#endif

	if( (avp=AAACreateAVP(AVP_Resource, 0, 0, user_name.s,
						user_name.len, AVP_FREE_DATA)) == 0)
	{
		LM_ERR(" no more pkg memory left!\n");
		if(user_name.s)
			pkg_free(user_name.s);
		goto error;
	}
	if( AAAAddAVPToMessage(req, avp, 0)!= AAA_ERR_SUCCESS)
	{
		LM_ERR(" avp not added \n");
		goto error1;
	}

	if(cred) /* it is a SIP message with credentials */
	{
		/* Response AVP */
		if( (avp=AAACreateAVP(AVP_Response, 0, 0, hdr->body.s,
						hdr->body.len, AVP_DUPLICATE_DATA)) == 0)
		{
			LM_ERR(" no more pkg memory left!\n");
			goto error;
		}
		
		position = AAAGetLastAVP(&(req->avpList));
		if( AAAAddAVPToMessage(req, avp, position)!= AAA_ERR_SUCCESS)
				
		{
			LM_ERR(" avp not added \n");
			goto error1;
		}

		/* Method AVP */
		if( (avp=AAACreateAVP(AVP_Method, 0, 0, p_method->s,
						p_method->len, AVP_DUPLICATE_DATA)) == 0)
		{
			LM_ERR(" no more pkg memory left!\n");
			goto error;
		}
		
		position = AAAGetLastAVP(&(req->avpList));
		if( AAAAddAVPToMessage(req, avp, position)!= AAA_ERR_SUCCESS)
				
		{
			LM_ERR(" avp not added \n");
			goto error1;
		}

	
	}			
#ifdef DEBUG
	AAAPrintMessage(req);
#endif

	/* build a AAA message buffer */
	if(AAABuildMsgBuffer(req) != AAA_ERR_SUCCESS)
	{
		LM_ERR(" message buffer not created\n");
		goto error;
	}
	
	if(sockfd==AAA_NO_CONNECTION)
	{
		sockfd = init_mytcp(diameter_client_host, diameter_client_port);
		if(sockfd==AAA_NO_CONNECTION)
		{
			LM_ERR(" failed to reconnect to Diameter client\n");
			goto error;
		}
	}

	/* send the message to the DIAMETER CLIENT */
	switch( tcp_send_recv(sockfd, req->buf.s, req->buf.len, rb, m_id) )
	{
		case AAA_ERROR: /* a transmission error occurred */
			LM_ERR(" message sending to the" 
					" DIAMETER backend authorization server failed\n");
			goto error;
	
		case AAA_CONN_CLOSED:
			LM_NOTICE("connection to Diameter"
					" client closed.It will be reopened by the next request\n");
			close(sockfd);
			sockfd = AAA_NO_CONNECTION;
			goto error;

		case AAA_TIMEOUT:
			LM_NOTICE("no response received\n");
			close(sockfd);
			sockfd = AAA_NO_CONNECTION;
			goto error;
	}

	AAAFreeMessage(&req);
	return 1;

error1:
	AAAFreeAVP(&avp);
error:
	AAAFreeMessage(&req);
	return -1;
}