Пример #1
0
void handle_mm(struct session_info *s, struct gsm48_hdr *dtap, unsigned dtap_len, uint32_t fn)
{
	if (dtap_len < sizeof(struct gsm48_hdr)) {
		SET_MSG_INFO(s, "FAILED SANITY CHECKS (MM_LEN)");
		return;
	}

	switch (dtap->msg_type & 0x3f) {
	case 0x01:
		session_reset(s, 1);
		s->started = 1;
		SET_MSG_INFO(s, "IMSI DETACH");
		s->detach = 1;
		s->mo = 1;
		handle_detach(s, dtap->data);
		break;
	case 0x02:
		SET_MSG_INFO(s, "LOC UPD ACCEPT");
		handle_loc_upd_acc(s, dtap->data, dtap_len - 2);
		break;
	case 0x04:
		SET_MSG_INFO(s, "LOC UPD REJECT cause=%d", dtap->data[0]);
		s->locupd = 1;
		s->lu_reject = 1;
		s->lu_rej_cause = dtap->data[0];
		s->mo = 1;
		break;
	case 0x08:
		session_reset(s, 1);
		if (dtap_len < sizeof(struct gsm48_loc_upd_req)) {
			SET_MSG_INFO(s, "FAILED SANITY CHECKS (LUR_DTAP_SIZE)");
			break;
		}
		SET_MSG_INFO(s, "LOC UPD REQUEST");
		handle_loc_upd_req(s, dtap->data);
		break;
	case 0x12:
		if ((dtap_len > 19) && (dtap->data[17] == 0x20) && (dtap->data[18] == 0x10)) {
			SET_MSG_INFO(s, "AUTH REQUEST (UMTS)");
			s->auth = 2;
		} else {
			SET_MSG_INFO(s, "AUTH REQUEST (GSM)");
			s->auth = 1;
		}
		if (!s->auth_req_fn) {
			if (fn) {
				s->auth_req_fn = fn;
			} else {
				s->auth_req_fn = GSM_MAX_FN;
			}
		}
		break;
	case 0x14:
		if ((dtap_len > 6) && (dtap->data[4] == 0x21) && (dtap->data[5] == 0x04)) {
			SET_MSG_INFO(s, "AUTH RESPONSE (UMTS)");
			if (!s->auth) {
				s->auth = 2;
			}
		} else {
			SET_MSG_INFO(s, "AUTH RESPONSE (GSM)");
			if (!s->auth) {
				s->auth = 1;
			}
		}
		if (!s->auth_resp_fn) {
			if (fn) {
				s->auth_resp_fn = fn;
			} else {
				s->auth_resp_fn = GSM_MAX_FN;
			}
		}
		break;
	case 0x18:
		switch (dtap->data[0] & GSM_MI_TYPE_MASK) {
		case GSM_MI_TYPE_IMSI:
			SET_MSG_INFO(s, "IDENTITY REQUEST, IMSI");
			if (s->cipher) {
				s->iden_imsi_ac = 1;
			} else {
				s->iden_imsi_bc = 1;
			}
			break;
		case GSM_MI_TYPE_IMEI:
		case GSM_MI_TYPE_IMEISV:
			SET_MSG_INFO(s, "IDENTITY REQUEST, IMEI");
			if (s->cipher) {
				s->iden_imei_ac = 1;
			} else {
				s->iden_imei_bc = 1;
			}
			break;
		}
		break;
	case 0x19:
		handle_mi(s, &dtap->data[1], dtap->data[0], 0);
		switch (dtap->data[1] & GSM_MI_TYPE_MASK) {
		case GSM_MI_TYPE_IMSI:
			SET_MSG_INFO(s, "IDENTITY RESPONSE, IMSI %s", s->imsi);
			if (s->cipher) {
				s->iden_imsi_ac = 1;
			} else {
				s->iden_imsi_bc = 1;
			}
			break;
		case GSM_MI_TYPE_IMEI:
		case GSM_MI_TYPE_IMEISV:
			SET_MSG_INFO(s, "IDENTITY RESPONSE, IMEI %s", s->imei);
			if (s->cipher) {
				s->iden_imei_ac = 1;
			} else {
				s->iden_imei_bc = 1;
			}
			break;
		}
		break;
	case 0x1a:
		SET_MSG_INFO(s, "TMSI REALLOC COMMAND");
		s->tmsi_realloc = 1;
		handle_lai(s, dtap->data, -1);
		handle_mi(s, &dtap->data[6], dtap->data[5], 1);
		break;
	case 0x1b:
		SET_MSG_INFO(s, "TMSI REALLOC COMPLETE");
		s->tmsi_realloc = 1;
		break;
	case 0x21:
		SET_MSG_INFO(s, "CM SERVICE ACCEPT");
		s->mo = 1;
		break;
	case 0x23:
		SET_MSG_INFO(s, "CM SERVICE ABORT");
		s->mo = 1;
		break;
	case 0x24:
		SET_MSG_INFO(s, "CM SERVICE REQUEST");
		session_reset(s, 1);
		s->started = 1;
		s->closed = 0;
		s->serv_req = 1;
		s->mo = 1;
		handle_cmreq(s, dtap->data);
		break;
	case 0x29:
		SET_MSG_INFO(s, "ABORT");
		s->abort = 1;
		break;
	case 0x32:
		SET_MSG_INFO(s, "MM INFORMATION");
		break;
	default:
		SET_MSG_INFO(s, "UNKNOWN MM (%02x)", dtap->msg_type & 0x3f);
		s->unknown = 1;
	}
}
Пример #2
0
void handle_rr(struct session_info *s, struct gsm48_hdr *dtap, unsigned len, uint32_t fn)
{
	struct gsm48_system_information_type_6 *si6;
	struct tlv_parsed tp;

	s->rat = RAT_GSM;
	assert(s->new_msg);

	if (!len) {
		return;
	}

	switch (dtap->msg_type) {
	case GSM48_MT_RR_SYSINFO_1:
		SET_MSG_INFO(s, "SYSTEM INFO 1");
		handle_sysinfo(s, dtap, len);
		break;
	case GSM48_MT_RR_SYSINFO_2:
		SET_MSG_INFO(s, "SYSTEM INFO 2");
		handle_sysinfo(s, dtap, len);
		break;
	case GSM48_MT_RR_SYSINFO_2bis:
		SET_MSG_INFO(s, "SYSTEM INFO 2bis");
		handle_sysinfo(s, dtap, len);
		break;
	case GSM48_MT_RR_SYSINFO_2ter:
		SET_MSG_INFO(s, "SYSTEM INFO 2ter");
		handle_sysinfo(s, dtap, len);
		break;
	case GSM48_MT_RR_SYSINFO_2quater:
		SET_MSG_INFO(s, "SYSTEM INFO 2quater");
		handle_sysinfo(s, dtap, len);
		break;
	case GSM48_MT_RR_SYSINFO_3:
		SET_MSG_INFO(s, "SYSTEM INFO 3");
		handle_sysinfo(s, dtap, len);
		break;
	case GSM48_MT_RR_SYSINFO_4:
		SET_MSG_INFO(s, "SYSTEM INFO 4");
		handle_sysinfo(s, dtap, len);
		break;
	case GSM48_MT_RR_SYSINFO_5:
		SET_MSG_INFO(s, "SYSTEM INFO 5");
		rand_check((uint8_t *)dtap, 18, &s->si5, s->cipher);
		handle_sysinfo(s, dtap, len);
		break;
	case GSM48_MT_RR_SYSINFO_5bis:
		SET_MSG_INFO(s, "SYSTEM INFO 5bis");
		rand_check((uint8_t *)dtap, 18, &s->si5bis, s->cipher);
		handle_sysinfo(s, dtap, len);
		break;
	case GSM48_MT_RR_SYSINFO_5ter:
		SET_MSG_INFO(s, "SYSTEM INFO 5ter");
		rand_check((uint8_t *)dtap, 18, &s->si5ter, s->cipher);
		handle_sysinfo(s, dtap, len);
		break;
	case GSM48_MT_RR_SYSINFO_6:
		SET_MSG_INFO(s, "SYSTEM INFO 6");
		rand_check((uint8_t *)dtap, 18, &s->si6, s->cipher);
		si6 = (struct gsm48_system_information_type_6 *) dtap;
		handle_lai(s, (uint8_t*)&si6->lai, htons(si6->cell_identity));
		handle_sysinfo(s, dtap, len);
		break;
	case GSM48_MT_RR_SYSINFO_13:
		SET_MSG_INFO(s, "SYSTEM INFO 13");
		handle_sysinfo(s, dtap, len);
		break;
	case GSM48_MT_RR_CHAN_REL:
		SET_MSG_INFO(s, "CHANNEL RELEASE");
		if (s->cipher && !s->fc.enc_rand)
			s->fc.predict++;

		s->release = 1;
		s->rr_cause = dtap->data[0];
		if ((len > 3) && ((dtap->data[1] & 0xf0) == 0xc0))
			s->have_gprs = 1;

		session_reset(&s[0], 0);
		if (auto_reset) {
			s[1].new_msg = NULL;
		}
		break;
	case GSM48_MT_RR_CLSM_ENQ:
		SET_MSG_INFO(s, "CLASSMARK ENQUIRY");
		break;
	case GSM48_MT_RR_MEAS_REP:
		SET_MSG_INFO(s, "MEASUREMENT REPORT");
		break;
	case GSM48_MT_RR_CLSM_CHG:
		SET_MSG_INFO(s, "CLASSMARK CHANGE");
		handle_classmark(s, &dtap->data[1], 2);
		break;
	case GSM48_MT_RR_PAG_REQ_1:
		SET_MSG_INFO(s, "PAGING REQ 1");
		handle_paging1(dtap, len);
		break;
	case GSM48_MT_RR_PAG_REQ_2:
		SET_MSG_INFO(s, "PAGING REQ 2");
		handle_paging2(dtap, len);
		break;
	case GSM48_MT_RR_PAG_REQ_3:
		SET_MSG_INFO(s, "PAGING REQ 3");
		handle_paging3();
		break;
	case GSM48_MT_RR_IMM_ASS:
		SET_MSG_INFO(s, "IMM ASSIGNMENT");
		break;
	case GSM48_MT_RR_IMM_ASS_EXT:
		SET_MSG_INFO(s, "IMM ASSIGNMENT EXT");
		break;
	case GSM48_MT_RR_IMM_ASS_REJ:
		SET_MSG_INFO(s, "IMM ASSIGNMENT REJECT");
		break;
	case GSM48_MT_RR_PAG_RESP:
		session_reset(s, 1);
		SET_MSG_INFO(s, "PAGING RESPONSE");
		handle_pag_resp(s, dtap->data);
		break;
	case GSM48_MT_RR_HANDO_CMD:
		SET_MSG_INFO(s, "HANDOVER COMMAND");
		parse_assignment(dtap, len, s->cell_arfcns, &s->ga);
		s->handover = 1;
		s->use_jump = 2;
		break;
	case GSM48_MT_RR_HANDO_COMPL:
		SET_MSG_INFO(s, "HANDOVER COMPLETE");
		break;
	case GSM48_MT_RR_ASS_CMD:
		SET_MSG_INFO(s, "ASSIGNMENT COMMAND");
		if ((s->fc.enc-s->fc.enc_null-s->fc.enc_si) == 1)
			s->forced_ho = 1;
		parse_assignment(dtap, len, s->cell_arfcns, &s->ga);
		s->assignment = 1;
		s->use_jump = 1;
		break;
	case GSM48_MT_RR_ASS_COMPL:
		SET_MSG_INFO(s, "ASSIGNMENT COMPLETE");
		s->assign_complete = 1;
		break;
	case GSM48_MT_RR_CIPH_M_COMPL:
		SET_MSG_INFO(s, "CIPHER MODE COMPLETE");
		if (s->cipher_missing < 0) {
			s->cipher_missing = 0;
		} else {
			s->cipher_missing = 1;
		}

		if (!s->cm_comp_first_fn) {
			if (fn) {
				s->cm_comp_first_fn = fn;
			} else {
				s->cm_comp_first_fn = GSM_MAX_FN;
			}
		}

		if (fn) {
			s->cm_comp_last_fn = fn;
		} else {
			s->cm_comp_last_fn = GSM_MAX_FN;
		}

		s->cm_comp_count++;

		if (dtap->data[0] == 0x2b)
			return;

		/* get IMEISV */
		tlv_parse(&tp, &gsm48_rr_att_tlvdef, dtap->data, len-2, 0, 0);
		if (TLVP_PRESENT(&tp, GSM48_IE_MOBILE_ID)) {
			uint8_t *v = (uint8_t *) TLVP_VAL(&tp, GSM48_IE_MOBILE_ID);
			handle_mi(s, &v[1], v[0], 0);
			s->cmc_imeisv = 1;
		}
		break;
	case GSM48_MT_RR_GPRS_SUSP_REQ:
		SET_MSG_INFO(s, "GPRS SUSPEND");
		s->have_gprs = 1;
		//tlli
		//rai (lai+rac)
		break;
	case GSM48_MT_RR_CIPH_M_CMD:
		if (!s->cm_cmd_fn) {
			if (fn) {
				s->cm_cmd_fn = fn;
			} else {
				s->cm_cmd_fn = GSM_MAX_FN;
			}
		}

		if (dtap->data[0] & 1) {
			s->cipher = 1 + ((dtap->data[0]>>1) & 7);
			if (!not_zero(s->key, 8))
				s->decoded = 0;
		}
		SET_MSG_INFO(s, "CIPHER MODE COMMAND, A5/%u", s->cipher);
		if (dtap->data[0] & 0x10) {
			s->cmc_imeisv = 1;

			if (s->cipher && !s->fc.enc_rand)
				s->fc.predict++;
		}
		s->cipher_missing = -1;
		break;
	case 0x60:
		SET_MSG_INFO(s, "UTRAN CLASSMARK");
		break;
	default:
		SET_MSG_INFO(s, "UNKNOWN RR (%02x)", dtap->msg_type);
		s->unknown = 1;
	}
Пример #3
0
void* session_worker(void* data) {
	int capacity = 1;
	int timeout = 30000; // 30 seconds

	// setup session data container
	struct session_data * session = (struct session_data*) data;
	int sockfd = session->sockfd;
	session_reset(session);

	printf("session %d: starting work, state %d\n", sockfd, session->state);

	REPLY_TO_CLIENT(sockfd, REPLY_GREET);

	// buffer for receiving messages
	int buffer_size = 1024;
	char* buffer = calloc(buffer_size, sizeof(char));

	// epoll setup
	int epoll_set = epoll_create(capacity);
	struct epoll_event listen_event;
	listen_event.data.fd = sockfd;
	listen_event.events = EPOLLIN;
	epoll_ctl(epoll_set, EPOLL_CTL_ADD, sockfd, &listen_event);
	struct epoll_event* caught_events = calloc(capacity, sizeof(struct epoll_event));

	while (session->state != SESSION_QUIT) {
		// we wait for some messages
		int nfds = epoll_wait(epoll_set, caught_events, 1, timeout);
		if (nfds == 0) {
			// timeout
			close(sockfd);
			printf("session %d: timeout, work is over\n", sockfd);
			break;
		}

		// we parse our messages, we assume only one event happens
		if (nfds == 1) {
			memset(buffer, 0, BUFFER_SIZE);
			int received_bytes = recv(sockfd, buffer, buffer_size - 1, 0);

			// connection closed
			if (received_bytes == 0) {
				printf("session %d: client closed connection\n", sockfd);
				break;
			}

			// errors
			if (received_bytes < 0) {
				printf("session %d: recv error\n", sockfd);
				break;
			}

			// form a request structure using the received message
			struct request* req = parse_request(buffer);

			// dont interpret text if we're in DATA state
			if (session->state == SESSION_DATA && req->command != CMD_CRLF) {
				// add line to body
				if (!session->message->body) {
					session->message->body = strdup(buffer);
				} else {
					// gotta love C
					int size = strlen(buffer) + strlen(session->message->body) + 1;
					char * extended_message = (char*) malloc(sizeof(char) * size);
					strncpy(extended_message, session->message->body, strlen(session->message->body)+1);
					strncat(extended_message, buffer, strlen(buffer));
					extended_message[size] = '\0';
					free(session->message->body);
					session->message->body = extended_message;
				}
				if (req->arguments) {
					free(req->arguments);	
				}
				free(req);
				continue;
			}

			if (session->state == SESSION_DATA && req->command == CMD_CRLF && (strlen(buffer) > 3)) {
				// add line to body
				if (!session->message->body) {
					session->message->body = strdup(buffer);
				} else {
					// gotta love C
					int size = strlen(buffer) + strlen(session->message->body) + 1;
					char * extended_message = (char*) malloc(sizeof(char) * size);
					strncpy(extended_message, session->message->body, strlen(session->message->body)+1);
					strncat(extended_message, buffer, strlen(buffer)-5);
					extended_message[size] = '\0';
					free(session->message->body);
					session->message->body = extended_message;
				}
				if (req->arguments) {
					free(req->arguments);	
				}
			}

			// fill session data according to request
			switch(req->command) {
				case CMD_HELO:
					// expect a helo at start; a helo resets session; helo expects 1 argument: domain
					session_reset(session);
					if (session->state == SESSION_NEW) {
						REPLY_TO_CLIENT(sockfd, REPLY_OK);
					}
					session->state = SESSION_GREET;
					session->domain = strdup((char*) (req->arguments));
					printf("session %d: state changed to greeted\n", sockfd);
					break;
				case CMD_MAIL:
					// mail from expects an argument: sender address;
					// can be after a helo or transaction completion
					if (session->state == SESSION_GREET) {
						session->state = SESSION_MAIL;
						session->message->mail_from = strdup((char*) (req->arguments));
						REPLY_TO_CLIENT(sockfd, REPLY_OK);
						printf("session %d: got mail from\n", sockfd);
					} else {
						REPLY_TO_CLIENT(sockfd, REPLY_OOO);
					}
					break;
				case CMD_RCPT:
					// rcpt to expects an argument: receipient address;
					// can be after a mail from or another rcpt to command
					if (session->state == SESSION_MAIL || session->state == SESSION_RCPT) {
						session->state = SESSION_RCPT;
						session->message->rcpt_to = strdup((char*) (req->arguments));
						REPLY_TO_CLIENT(sockfd, REPLY_OK);
						printf("session %d: state changed to got receipients\n", sockfd);
					} else {
						REPLY_TO_CLIENT(sockfd, REPLY_OOO);
					}
					break;
				case CMD_DATA:
					// no arguments; must be after a rcpt to command
					if (session->state == SESSION_RCPT) {
						session->state = SESSION_DATA;
						REPLY_TO_CLIENT(sockfd, REPLY_DATA_INFO);
						printf("session %d: state changed to data receival\n", sockfd);
					} else {
						REPLY_TO_CLIENT(sockfd, REPLY_OOO);
					}
					break;
				case CMD_CRLF:
					// signifies an end of a message's body;
					// only after data command was invoked
					if (session->state == SESSION_DATA) {
						session_submit(session);
						session_reset(session);
						session->state = SESSION_GREET;
						REPLY_TO_CLIENT(sockfd, REPLY_OK);
						printf("session %d: data transaction over, state changed to greeted\n", sockfd);
					} else {
						REPLY_TO_CLIENT(sockfd, REPLY_OOO);
					}
					break;
				case CMD_QUIT:
					// closes session
					session->state = SESSION_QUIT;
					REPLY_TO_CLIENT(sockfd, REPLY_BYE);
					printf("session %d: state changed to quit\n", sockfd);
					break;
				default:
					// send syntax error
					REPLY_TO_CLIENT(sockfd, REPLY_SYNTAX_ERROR);
					printf("session %d: syntax error\n", sockfd);
					break;
			}
			free(req);
		}
	}
	free(buffer);
	free(data);
	printf("session %d: finished\n", sockfd);
	close(sockfd);

	return NULL;
}