/*************************************************************************************** * * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. * * By downloading, copying, installing or using the software you agree to this license. * If you do not agree to this license, do not download, install, * copy or use the software. * * Copyright (C) 2014-2022, Happytimesoft Corporation, all rights reserved. * * Redistribution and use in binary forms, with or without modification, are permitted. * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific * language governing permissions and limitations under the License. * ****************************************************************************************/ #include "sys_inc.h" #include "hqueue.h" #include "linked_list.h" #include "rfc_md5.h" #include "word_analyse.h" #include "digcalc.h" #include "ppstack.h" #include "hsip.h" #include "sua.h" #include "sip_parse.h" #include "sip_tx.h" #include "sip_reg.h" #include "gb28181.h" /*******************************************************/ extern HSIP_CLASS hsip; /*******************************************************\ 建立注册消息实用函数 \*******************************************************/ void sip_reg_build_from(HSIP_MSG * tx_msg, HSIP_USER * p_user) { int offset = 0; char tmp_buf[512]; if (p_user->user_disp_name[0] != '\0') { offset += sprintf(tmp_buf+offset, "\"%s\" ", p_user->user_disp_name); } offset += sprintf(tmp_buf+offset, "<%s>", p_user->user_sip_addr); if (p_user->auth_f_tag[0] != '\0') { offset += sprintf(tmp_buf+offset, ";%s", p_user->auth_f_tag); } sip_add_tx_msg_line(tx_msg, "From", "%s", tmp_buf); } void sip_reg_build_to(HSIP_MSG * tx_msg, HSIP_USER * p_user) { int offset = 0; char tmp_buf[512]; if (p_user->user_disp_name[0] != '\0') { offset += sprintf(tmp_buf+offset, "\"%s\" ", p_user->user_disp_name); } offset += sprintf(tmp_buf+offset, "<%s>", p_user->user_sip_addr); sip_add_tx_msg_line(tx_msg, "To", "%s", tmp_buf); } void sip_reg_build_contact(HSIP_MSG * tx_msg, HSIP_USER * p_user) { if (p_user->user_disp_name[0] == '\0') { sip_add_tx_msg_line(tx_msg, "Contact", "", p_user->user_name, p_user->user_ip, p_user->user_port); } else { sip_add_tx_msg_line(tx_msg, "Contact", "\"%s\" ", p_user->user_disp_name, p_user->user_name, p_user->user_ip, p_user->user_port); } } /*******************************************************\ 建立普通注册消息 \*******************************************************/ HSIP_MSG * sip_build_register_normal_msg(HSIP_USER * p_user, uint32 srv_ip, uint16 srv_port) { HSIP_MSG * tx_msg = sip_get_msg_buf(); if (NULL == tx_msg) { log_print(HT_LOG_ERR, "%s, get message buffer failed\r\n", __FUNCTION__); return NULL; } tx_msg->msg_type = 0; tx_msg->msg_sub_type = SIP_MT_REG; tx_msg->msg_crpty_mode = p_user->user_crpty_mode; tx_msg->local_port = p_user->sip_port; // sip_add_tx_msg_fline(tx_msg, "REGISTER", "sip:%s@%s:%d SIP/2.0", p_user->server_id, p_user->server_ipstr, p_user->server_port); sip_add_tx_msg_fline(tx_msg, "REGISTER", "%s SIP/2.0", p_user->server_sip_addr); sprintf(p_user->auth_via.branch, "z9hG4bK%x", sys_os_get_uptime()); if (p_user->usrf_tcp_sip == 1) { sip_add_tx_msg_via(tx_msg, "SIP/2.0/TCP %s:%u;rport;branch=%s", p_user->user_ip, p_user->user_port, p_user->auth_via.branch); } else { sip_add_tx_msg_via(tx_msg, "SIP/2.0/UDP %s:%u;rport;branch=%s", p_user->user_ip, p_user->user_port, p_user->auth_via.branch); } if (p_user->auth_f_tag[0] == '\0') { sprintf(p_user->auth_f_tag, "tag=%08x", rand()); } sip_reg_build_from(tx_msg,p_user); sip_reg_build_to(tx_msg,p_user); sip_reg_build_contact(tx_msg,p_user); if (p_user->auth_call_id[0] == '\0') { sprintf(p_user->auth_call_id, "%08X%08X@%s", rand(), rand(), p_user->user_ip); } sip_add_tx_msg_line(tx_msg, "Call-ID", "%s", p_user->auth_call_id); p_user->auth_cseq++; if (p_user->auth_cseq == 0) { p_user->auth_cseq = 1; } sip_add_tx_msg_line(tx_msg, "CSeq", "%d REGISTER", p_user->auth_cseq); sip_add_tx_msg_line(tx_msg, "Max-Forwards", "70"); sip_add_tx_msg_line(tx_msg, "Expires", "%u", p_user->expires_time); sip_add_tx_msg_line(tx_msg, "User-Agent", "%s", p_user->user_agent_desc); sip_add_tx_msg_line(tx_msg, "Content-Length", "0"); tx_msg->remote_ip = srv_ip; tx_msg->remote_port = srv_port; p_user->last_reg_time = sys_os_get_uptime(); return tx_msg; } /*******************************************************\ 建立带HTTP摘要认证信息的注册消息 \*******************************************************/ HSIP_MSG * sip_build_register_digest_msg(HSIP_MSG * rx_msg, HSIP_USER * p_user) { HSIP_MSG * tx_msg = sip_get_msg_buf(); if (NULL == tx_msg) { log_print(HT_LOG_ERR, "%s, get message buffer failed\r\n", __FUNCTION__); return NULL; } tx_msg->msg_type = 0; tx_msg->msg_sub_type = SIP_MT_REG; tx_msg->msg_crpty_mode = rx_msg->msg_crpty_mode; tx_msg->local_port = p_user->sip_port; // sip_add_tx_msg_fline(tx_msg, "REGISTER", "sip:%s@%s:%d SIP/2.0", p_user->server_id, p_user->server_ipstr, p_user->server_port); sip_add_tx_msg_fline(tx_msg, "REGISTER", "%s SIP/2.0", p_user->server_sip_addr); sprintf(p_user->auth_via.branch, "z9hG4bK%x", sys_os_get_uptime()); if (p_user->usrf_tcp_sip == 1) { sip_add_tx_msg_via(tx_msg, "SIP/2.0/TCP %s:%u;rport;branch=%s", p_user->user_ip, p_user->user_port, p_user->auth_via.branch); } else { sip_add_tx_msg_via(tx_msg, "SIP/2.0/UDP %s:%u;rport;branch=%s", p_user->user_ip, p_user->user_port, p_user->auth_via.branch); } sip_reg_build_from(tx_msg, p_user); sip_reg_build_to(tx_msg, p_user); sip_reg_build_contact(tx_msg, p_user); sip_add_tx_msg_line(tx_msg, "Call-ID", "%s", p_user->auth_call_id); char cseq_buf[256]; sip_get_msg_cseq(rx_msg, cseq_buf, sizeof(cseq_buf)); p_user->auth_cseq = atoi(cseq_buf) + 1; sip_add_tx_msg_line(tx_msg, "CSeq", "%d REGISTER", p_user->auth_cseq); sip_add_tx_msg_line(tx_msg, "Max-Forwards", "70"); sip_add_tx_msg_line(tx_msg, "Expires", "%u", p_user->expires_time); sip_add_tx_msg_line(tx_msg, "User-Agent", "%s", p_user->user_agent_desc); char auth_field_name[MAX_USRL]; if (rx_msg->msg_sub_type == 401) { strcpy(auth_field_name, "Authorization"); } else if (rx_msg->msg_sub_type == 407) { strcpy(auth_field_name, "Proxy-Authorization"); } else { auth_field_name[0] = '\0'; } if (p_user->user_auth_info.auth_qop[0] != '\0') { sip_add_tx_msg_line(tx_msg, auth_field_name, "Digest username=\"%s\",realm=\"%s\",nonce=\"%s\",response=\"%s\"," " uri=\"%s\",qop=auth,algorithm=MD5,cnonce=\"%s\",nc=%s", p_user->user_auth_info.auth_name, p_user->user_auth_info.auth_realm, p_user->user_auth_info.auth_nonce, p_user->user_auth_info.auth_response, p_user->user_auth_info.auth_uri, p_user->user_auth_info.auth_cnonce, p_user->user_auth_info.auth_ncstr); } else { sip_add_tx_msg_line(tx_msg,auth_field_name, "Digest username=\"%s\",realm=\"%s\",uri=\"%s\",nonce=\"%s\",response=\"%s\",algorithm=MD5", p_user->user_auth_info.auth_name, p_user->user_auth_info.auth_realm, p_user->user_auth_info.auth_uri, p_user->user_auth_info.auth_nonce, p_user->user_auth_info.auth_response); } sip_add_tx_msg_line(tx_msg, "Content-Length", "0"); tx_msg->remote_ip = rx_msg->remote_ip; tx_msg->remote_port = rx_msg->remote_port; return tx_msg; } /*******************************************************\ 从消息中获取服务器发送的digest chap 信息 \*******************************************************/ BOOL sip_get_digest_info(HSIP_MSG * rx_msg, HD_AUTH_INFO * auth_info) { HDRV * chap_id = NULL; if (rx_msg->msg_sub_type == 401) { chap_id = sip_find_headline(rx_msg, "WWW-Authenticate"); } if (rx_msg->msg_sub_type == 407) { chap_id = sip_find_headline(rx_msg, "Proxy-Authenticate"); } if (chap_id == NULL) { return FALSE; } char word_buf[128]; int next_offset; auth_info->auth_response[0] = '\0'; auth_info->auth_uri[0] = '\0'; word_buf[0] = '\0'; GetLineWord(chap_id->value_string, 0, strlen(chap_id->value_string), word_buf, sizeof(word_buf), &next_offset, WORD_TYPE_STRING); if (strcasecmp(word_buf, "digest") != 0) { return FALSE; } word_buf[0] = '\0'; if (GetNameValuePair(chap_id->value_string+next_offset, strlen(chap_id->value_string)-next_offset, "realm", word_buf, sizeof(word_buf)) == FALSE) { return FALSE; } strcpy(auth_info->auth_realm, word_buf); word_buf[0] = '\0'; if (GetNameValuePair(chap_id->value_string+next_offset, strlen(chap_id->value_string)-next_offset, "nonce", word_buf, sizeof(word_buf)) == FALSE) { return FALSE; } strcpy(auth_info->auth_nonce, word_buf); word_buf[0] = '\0'; if (GetNameValuePair(chap_id->value_string+next_offset, strlen(chap_id->value_string)-next_offset,"qop",word_buf,sizeof(word_buf))) { // strcpy(auth_info->auth_qop, word_buf); strcpy(auth_info->auth_qop, "auth"); } else { auth_info->auth_qop[0] = '\0'; } sprintf(auth_info->auth_cnonce, "%08X%08X", rand(),rand()); auth_info->auth_nc++; sprintf(auth_info->auth_ncstr, "%08X", auth_info->auth_nc); return TRUE; } /*******************************************************\ 计算HTTP摘要认证响应 method_type值:"REGISTER","INVITE",... \*******************************************************/ BOOL sip_sua_digest_calc(const char * method_type, SUA * p_sua) { HASHHEX HA1; HASHHEX HA2 = ""; HSIP_USER * p_user = p_sua->p_user; if (p_user == NULL) { log_print(HT_LOG_ERR, "%s, p_user == NULL!!!\r\n", __FUNCTION__); return FALSE; } sprintf(p_sua->user_auth_info.auth_ncstr,"%08X", p_sua->user_auth_info.auth_nc); DigestCalcHA1("md5",p_sua->user_auth_info.auth_name, p_sua->user_auth_info.auth_realm, p_user->user_auth_passwd, p_sua->user_auth_info.auth_nonce, p_sua->user_auth_info.auth_cnonce, HA1); DigestCalcResponse(HA1, p_sua->user_auth_info.auth_nonce, p_sua->user_auth_info.auth_ncstr, p_sua->user_auth_info.auth_cnonce, p_sua->user_auth_info.auth_qop, method_type,p_sua->user_auth_info.auth_uri, HA2, p_sua->user_auth_info.auth_response); return TRUE; } /*******************************************************\ UA注册响应消息接收处理 \*******************************************************/ void sip_register_response_rx(HSIP_MSG * rx_msg, HSIP_USER * p_user) { char expires_buf[16]; switch (rx_msg->msg_sub_type) { case 401: case 407: { char tmp_auth_name[MAX_USRL]; strcpy(tmp_auth_name, p_user->user_auth_info.auth_name); // 暂存认证用户名 if (sip_get_digest_info(rx_msg, &(p_user->user_auth_info))) // 获取WWW-Authentication信息 { strcpy(p_user->user_auth_info.auth_name, tmp_auth_name); sprintf(p_user->user_auth_info.auth_uri, "sip:%s@%s", p_user->server_id, p_user->user_domain); http_digest_auth(p_user, &(p_user->user_auth_info), "REGISTER"); // 计算出Authorization部分信息 usleep(500*1000); // 休眠500ms HSIP_MSG * tx_msg = sip_build_register_digest_msg(rx_msg, p_user); if (tx_msg) { user_tx_free_msg(p_user,tx_msg); } p_user->user_state = HSIP_AUTH_CHAP_RX; sip_reg_notify(p_user, PUEVT_REGING); } else { p_user->usrf_auth = 0; p_user->user_state = HSIP_AUTH_FAIL; sip_reg_notify(p_user, PUEVT_REG_FAIL); } p_user->last_reg_time = sys_os_get_uptime(); } break; case 200: // 注册成功,改变相应状态 p_user->user_state = HSIP_AUTH_200; p_user->last_reg_time = sys_os_get_uptime(); // 获取注册超期时长,如果没有指定可能需要在每个呼叫中进行认证 if (sip_get_msg_expires(rx_msg, expires_buf, sizeof(expires_buf))) { p_user->expires_time = atol(expires_buf); } if (p_user->expires_time == 0) // 用户注销的情况 { p_user->user_state = HSIP_AUTH_IDLE; p_user->usrf_auth = 0; } else { // SIP注册校时 HDRV * data_line = sip_find_headline(rx_msg, "Date"); if (data_line && data_line->value_string) { gb28181_time_update(data_line->value_string); } HDRV * srvid_line = sip_find_headline(rx_msg, "SRV-ID"); if (srvid_line && srvid_line->value_string) { strncpy(p_user->server_id, srvid_line->value_string, sizeof(p_user->server_id)); } // 获取 To 字段的显示名称 char disp_name[128]; if (sip_get_disp_name(rx_msg, "To", disp_name, sizeof(disp_name))) { strcpy(p_user->user_disp_name, disp_name); } sip_get_server_info(rx_msg, p_user->server_agent, sizeof(p_user->server_agent) - 1); if (0 == p_user->usrf_auth) { p_user->usrf_auth = 1; p_user->last_hb_time = sys_os_get_uptime(); sip_reg_notify(p_user, PUEVT_REG_PASS); } } break; case 404: p_user->user_state = HSIP_AUTH_FAIL; p_user->usrf_auth = 0; sip_reg_notify(p_user, PUEVT_REG_FAIL); break; } } /***********************************************************************\ 从HSIP_USER结构中取信息进行计算: 如果response为空,则将计算出来的值以字符 串方式填入response中,返回TRUE 如果非空,则与之进行比较,返回比较结果 \***********************************************************************/ BOOL http_digest_auth(HSIP_USER * p_user, HD_AUTH_INFO * auth_info, const char * method) { HASHHEX HA1; HASHHEX HA2 = ""; DigestCalcHA1("md5",auth_info->auth_name, auth_info->auth_realm, p_user->user_auth_passwd, auth_info->auth_nonce, auth_info->auth_cnonce, HA1); if (auth_info->auth_response[0] == '\0') { sprintf(auth_info->auth_ncstr,"%08X", auth_info->auth_nc); DigestCalcResponse(HA1, auth_info->auth_nonce, auth_info->auth_ncstr, auth_info->auth_cnonce, auth_info->auth_qop, method/*"REGISTER"*/,auth_info->auth_uri, HA2, auth_info->auth_response); return TRUE; } else { char calc_response[36]; DigestCalcResponse(HA1, auth_info->auth_nonce, auth_info->auth_ncstr, auth_info->auth_cnonce, auth_info->auth_qop, method/*"REGISTER"*/,auth_info->auth_uri, HA2, calc_response); if (strcmp(calc_response, auth_info->auth_response) == 0) return TRUE; else return FALSE; } return FALSE; } /***********************************************************************\ 注册状态向上通知 \***********************************************************************/ BOOL sip_reg_notify(HSIP_USER * p_user, PUAEVT evt) { if (p_user == NULL) { return FALSE; } sys_os_mutex_enter(hsip.mutex_cb); if (hsip.ext_ntf_func) { (*hsip.ext_ntf_func)(0, evt, NULL, 0, hsip.user_data); } sys_os_mutex_leave(hsip.mutex_cb); return TRUE; }