/* receive CDN */ static int l2tp_recv_CDN(l2tp_call *_this, u_char *pkt, int pktlen) { int result, error, avpsz, len, sessid; struct l2tp_avp *avp; char buf[L2TP_AVP_MAXSIZ], emes[256], pmes[256]; /* initialize */ result = 0; error = 0; sessid = 0; strlcpy(pmes, "(none)", sizeof(pmes)); avp = (struct l2tp_avp *)buf; while (pktlen >= 6 && (avpsz = avp_enum(avp, pkt, pktlen, 1)) > 0) { pkt += avpsz; pktlen -= avpsz; if (avp->vendor_id != 0) { L2TP_CALL_DBG((_this, LOG_DEBUG, "Received a Vendor-specific AVP vendor-id=%d " "type=%d", avp->vendor_id, avp->attr_type)); continue; } if (avp->is_hidden != 0) { l2tp_call_log(_this, LOG_WARNING, "Received AVP (%s/%d) is hidden. But we don't " "share secret.", avp_attr_type_string(avp->attr_type), avp->attr_type); if (avp->is_mandatory != 0) { l2tp_call_disconnect(_this, L2TP_CDN_RCODE_ERROR_CODE, L2TP_ECODE_UNKNOWN_MANDATORY_AVP, NULL, NULL, 0); return 1; } continue; } switch (avp->attr_type) { case L2TP_AVP_TYPE_MESSAGE_TYPE: AVP_SIZE_CHECK(avp, ==, 8); continue; case L2TP_AVP_TYPE_RESULT_CODE: AVP_SIZE_CHECK(avp, >=, 8); result = avp->attr_value[0] << 8 | avp->attr_value[1]; if (avp->length >= 10) { error = avp->attr_value[2] << 8 | avp->attr_value[3]; len = avp->length - 12; if (len > 0) { len = MIN(len, sizeof(pmes) - 1); memcpy(pmes, &avp->attr_value[4], len); pmes[len] = '\0'; } } continue; case L2TP_AVP_TYPE_ASSIGNED_SESSION_ID: AVP_SIZE_CHECK(avp, >=, 8); sessid = avp_get_val16(avp); continue; default: if (avp->is_mandatory) { l2tp_call_log(_this, LOG_WARNING, "AVP (%s/%d) is not supported, but it's " "mandatory", avp_attr_type_string(avp->attr_type), avp->attr_type); if (avp->is_mandatory != 0) { l2tp_call_disconnect(_this, L2TP_CDN_RCODE_ERROR_CODE, L2TP_ECODE_UNKNOWN_MANDATORY_AVP, NULL, NULL, 0); return 1; } #ifdef L2TP_CALL_DEBUG } else { L2TP_CALL_DBG((_this, LOG_DEBUG, "AVP (%s/%d) is not handled", avp_attr_type_string(avp->attr_type), avp->attr_type)); #endif } } } if (error == 0) { l2tp_call_log(_this, LOG_INFO, "RecvCDN result=%s/%d", l2tp_cdn_rcode_string(result), result); } else { l2tp_call_log(_this, LOG_INFO, "RecvCDN result=%s/%d error=%s/%d message=%s", l2tp_cdn_rcode_string(result), result, l2tp_ecode_string(error), error, pmes); } return 0; size_check_failed: /* continue to process even if the CDN message was broken */ l2tp_call_log(_this, LOG_ERR, "Received bad CDN: %s", emes); return 0; }
/* * receive ICCN * @return return 0 if the ICCN is acceptable. * other value means fail to receive, and * CDN was sent and status was updated. */ static int l2tp_call_recv_ICCN(l2tp_call *_this, u_char *pkt, int pktlen, dialin_proxy_info *dpi) { int avpsz, tx_conn_speed; uint32_t framing_type = 0; struct l2tp_avp *avp; char buf[L2TP_AVP_MAXSIZ], emes[256]; tx_conn_speed = 0; avp = (struct l2tp_avp *)buf; while (pktlen >= 6 && (avpsz = avp_enum(avp, pkt, pktlen, 1)) > 0) { pkt += avpsz; pktlen -= avpsz; if (avp->vendor_id != 0) { L2TP_CALL_DBG((_this, LOG_DEBUG, "Received a Vendor-specific AVP vendor-id=%d " "type=%d", avp->vendor_id, avp->attr_type)); continue; } if (avp->is_hidden != 0) { l2tp_call_log(_this, LOG_WARNING, "Received AVP (%s/%d) is hidden. But we don't " "share secret.", avp_attr_type_string(avp->attr_type), avp->attr_type); if (avp->is_mandatory != 0) { l2tp_call_disconnect(_this, L2TP_CDN_RCODE_ERROR_CODE, L2TP_ECODE_UNKNOWN_MANDATORY_AVP, NULL, NULL, 0); return 1; } continue; } switch (avp->attr_type) { case L2TP_AVP_TYPE_MESSAGE_TYPE: AVP_SIZE_CHECK(avp, ==, 8); continue; case L2TP_AVP_TYPE_RX_CONNECT_SPEED: /* * As RFC 2661 this AVP is not mandatory. But `xl2tpd' * sends this as a mandatory AVP. Handle this to * ignore the xl2tpd' bug. */ AVP_SIZE_CHECK(avp, ==, 10); continue; case L2TP_AVP_TYPE_TX_CONNECT_SPEED: AVP_SIZE_CHECK(avp, ==, 10); tx_conn_speed = avp_get_val32(avp); continue; case L2TP_AVP_TYPE_FRAMING_TYPE: AVP_SIZE_CHECK(avp, ==, 10); framing_type = avp_get_val32(avp); continue; case L2TP_AVP_TYPE_SEQUENCING_REQUIRED: _this->seq_required = 1; _this->use_seq = 1; continue; #ifndef L2TPD_TEST /* * AVP's for Proxy-LCP and Proxy-Authen */ case L2TP_AVP_TYPE_LAST_SENT_LCP_CONFREQ: memcpy(dpi->last_sent_lcp.data, avp->attr_value, avp_attr_length(avp)); dpi->last_sent_lcp.ldata = avp_attr_length(avp); break; case L2TP_AVP_TYPE_LAST_RECV_LCP_CONFREQ: memcpy(dpi->last_recv_lcp.data, avp->attr_value, avp_attr_length(avp)); dpi->last_recv_lcp.ldata = avp_attr_length(avp); break; case L2TP_AVP_TYPE_PROXY_AUTHEN_CHALLENGE: memcpy(dpi->auth_chall, avp->attr_value, MIN(avp_attr_length(avp), sizeof(dpi->auth_chall))); dpi->lauth_chall = avp_attr_length(avp); break; case L2TP_AVP_TYPE_PROXY_AUTHEN_ID: dpi->auth_id = avp_get_val16(avp); break; case L2TP_AVP_TYPE_PROXY_AUTHEN_NAME: memcpy(dpi->username, avp->attr_value, MIN(sizeof(dpi->username) - 1, avp_attr_length(avp))); break; case L2TP_AVP_TYPE_PROXY_AUTHEN_RESPONSE: memcpy(dpi->auth_resp, avp->attr_value, MIN(avp_attr_length(avp), sizeof(dpi->auth_resp))); dpi->lauth_resp = avp_attr_length(avp); break; case L2TP_AVP_TYPE_PROXY_AUTHEN_TYPE: switch (avp_get_val16(avp)) { default: l2tp_call_log(_this, LOG_WARNING, "RecvICCN Unknown proxy-authen-type=%d", avp_get_val16(avp)); /* FALLTHROUGH */ case L2TP_AUTH_TYPE_NO_AUTH: dpi->auth_type = 0; break; case L2TP_AUTH_TYPE_PPP_CHAP: dpi->auth_type = PPP_AUTH_CHAP_MD5; break; case L2TP_AUTH_TYPE_PPP_PAP: dpi->auth_type = PPP_AUTH_PAP; break; case L2TP_AUTH_TYPE_MS_CHAP_V1: dpi->auth_type = PPP_AUTH_CHAP_MS; break; } break; #endif default: if (avp->is_mandatory != 0) { l2tp_call_log(_this, LOG_WARNING, "AVP (%s/%d) is not supported, but it's " "mandatory", avp_attr_type_string(avp->attr_type), avp->attr_type); l2tp_call_disconnect(_this, L2TP_CDN_RCODE_ERROR_CODE, L2TP_ECODE_UNKNOWN_MANDATORY_AVP, NULL, NULL, 0); return 1; #ifdef L2TP_CALL_DEBUG } else { L2TP_CALL_DBG((_this, LOG_DEBUG, "AVP (%s/%d) is not handled", avp_attr_type_string(avp->attr_type), avp->attr_type)); #endif } } } l2tp_call_log(_this, LOG_INFO, "RecvICCN " "session_id=%u calling_number=%s tx_conn_speed=%u framing=%s", _this->peer_session_id, _this->calling_number, tx_conn_speed, ((framing_type & L2TP_FRAMING_CAP_FLAGS_ASYNC) != 0)? "async" : ((framing_type & L2TP_FRAMING_CAP_FLAGS_SYNC) != 0)? "sync" : "unknown"); return 0; size_check_failed: l2tp_call_log(_this, LOG_ERR, "Received bad ICCN: %s", emes); l2tp_call_disconnect(_this, L2TP_CDN_RCODE_ERROR_CODE, L2TP_ECODE_WRONG_LENGTH, NULL, NULL, 0); return 1; }
/* * Receiver StopCCN */ static int l2tp_ctrl_recv_StopCCN(l2tp_ctrl *_this, u_char *pkt, int pktlen) { int result, error, avpsz, len; uint16_t tunid; struct l2tp_avp *avp; char buf[L2TP_AVP_MAXSIZ + 16], emes[256], pmes[256]; result = 0; error = 0; tunid = 0; pmes[0] = '\0'; avp = (struct l2tp_avp *)buf; while (pktlen >= 6 && (avpsz = avp_enum(avp, pkt, pktlen, 1)) > 0) { pkt += avpsz; pktlen -= avpsz; if (avp->vendor_id != 0) { L2TP_CTRL_DBG((_this, LOG_DEBUG, "Received a Vendor-specific AVP vendor-id=%d " "type=%d", avp->vendor_id, avp->attr_type)); continue; } if (avp->is_hidden != 0) { l2tp_ctrl_log(_this, LOG_WARNING, "Received AVP (%s/%d) is hidden. But we don't " "share secret.", avp_attr_type_string(avp->attr_type), avp->attr_type); if (avp->is_mandatory != 0) { l2tp_ctrl_stop(_this, L2TP_STOP_CCN_RCODE_GENERAL_ERROR | L2TP_ECODE_UNKNOWN_MANDATORY_AVP); return 1; } continue; } switch (avp->attr_type) { case L2TP_AVP_TYPE_MESSAGE_TYPE: AVP_SIZE_CHECK(avp, ==, 8); continue; case L2TP_AVP_TYPE_RESULT_CODE: AVP_SIZE_CHECK(avp, >=, 8); result = avp->attr_value[0] << 8 | avp->attr_value[1]; if (avp->length >= 10) { error = avp->attr_value[2] << 8 | avp->attr_value[3]; len = avp->length - 12; if (len > 0) { len = MINIMUM(len, sizeof(pmes) - 1); memcpy(pmes, &avp->attr_value[4], len); pmes[len] = '\0'; } } continue; case L2TP_AVP_TYPE_ASSINGED_TUNNEL_ID: AVP_SIZE_CHECK(avp, ==, 8); tunid = avp_get_val16(avp); continue; default: if (avp->is_mandatory != 0) { l2tp_ctrl_log(_this, LOG_WARNING, "Received AVP (%s/%d) is not supported, " "but it's mandatory", avp_attr_type_string(avp->attr_type), avp->attr_type); #ifdef L2TP_CTRL_DEBUG } else { L2TP_CTRL_DBG((_this, LOG_DEBUG, "AVP (%s/%d) is not handled", avp_attr_type_string(avp->attr_type), avp->attr_type)); #endif } } } if (result == L2TP_CDN_RCODE_ERROR_CODE && error == L2TP_ECODE_NO_RESOURCE) { /* * Memo: * This state may be happen in following state. * - lots of connect/disconect by long-running * windows2000, sometimes it fall to this state. * Once it fall to here, connection will fail till * the windows rebooted */ l2tp_ctrl_log(_this, LOG_WARNING, "Peer indicates \"No Resource\" error."); } l2tp_ctrl_log(_this, LOG_INFO, "RecvStopCCN result=%s/%u " "error=%s/%u tunnel_id=%u message=\"%s\"", l2tp_stopccn_rcode_string(result), result, l2tp_ecode_string(error), error, tunid, pmes); return 0; size_check_failed: l2tp_ctrl_log(_this, LOG_ERR, "Received bad StopCCN: %s", emes); return -1; }
/* * receieve ICRQ * @return return 0 if the ICRQ is acceptable. * other values means fail to receive, and * CDN was sent and status was updated. */ static int l2tp_call_recv_ICRQ(l2tp_call *_this, u_char *pkt, int pktlen) { int avpsz, slen; struct l2tp_avp *avp; char buf[L2TP_AVP_MAXSIZ], emes[256]; avp = (struct l2tp_avp *)buf; while (pktlen >= 6 && (avpsz = avp_enum(avp, pkt, pktlen, 1)) > 0) { pkt += avpsz; pktlen -= avpsz; if (avp->vendor_id != 0) { L2TP_CALL_DBG((_this, LOG_DEBUG, "Received a Vendor-specific AVP vendor-id=%d " "type=%d", avp->vendor_id, avp->attr_type)); continue; } if (avp->is_hidden != 0) { l2tp_call_log(_this, LOG_WARNING, "Received AVP (%s/%d) is hidden. But we don't " "share secret.", avp_attr_type_string(avp->attr_type), avp->attr_type); if (avp->is_mandatory != 0) { l2tp_call_disconnect(_this, L2TP_CDN_RCODE_ERROR_CODE, L2TP_ECODE_UNKNOWN_MANDATORY_AVP, NULL, NULL, 0); return 1; } continue; } switch (avp->attr_type) { case L2TP_AVP_TYPE_MESSAGE_TYPE: AVP_SIZE_CHECK(avp, ==, 8); continue; case L2TP_AVP_TYPE_ASSIGNED_SESSION_ID: AVP_SIZE_CHECK(avp, ==, 8); _this->peer_session_id = avp_get_val16(avp); continue; case L2TP_AVP_TYPE_CALL_SERIAL_NUMBER: case L2TP_AVP_TYPE_BEARER_TYPE: case L2TP_AVP_TYPE_PHYSICAL_CHANNEL_ID: /* * Memo: * Microsoft "L2TP/IPsec VPN Client" for * Windows 98/Me/NT asserts mandatory bit in * Physical Channel Id */ break; case L2TP_AVP_TYPE_CALLING_NUMBER: slen = MIN(sizeof(_this->calling_number) - 1, avp_attr_length(avp)); memcpy(_this->calling_number, avp->attr_value, slen); _this->calling_number[slen] = '\0'; break; case L2TP_AVP_TYPE_CALLED_NUMBER: case L2TP_AVP_TYPE_SUB_ADDRESS: continue; default: if (avp->is_mandatory) { l2tp_call_log(_this, LOG_WARNING, "AVP (%s/%d) is not supported, but it's " "mandatory", avp_attr_type_string(avp->attr_type), avp->attr_type); if (avp->is_mandatory != 0) { l2tp_call_disconnect(_this, L2TP_CDN_RCODE_ERROR_CODE, L2TP_ECODE_UNKNOWN_MANDATORY_AVP, NULL, NULL, 0); return 1; } #ifdef L2TP_CALL_DEBUG } else { L2TP_CALL_DBG((_this, LOG_DEBUG, "AVP (%s/%d) is not handled", avp_attr_type_string(avp->attr_type), avp->attr_type)); #endif } } } if (_this->peer_session_id == 0) { l2tp_call_log(_this, LOG_ERR, "Received a bad ICRP: SessionId = 0"); l2tp_call_disconnect(_this, L2TP_CDN_RCODE_ERROR_CODE, L2TP_ECODE_INVALID_MESSAGE, "Session Id must not be 0", NULL, 0); return 1; } l2tp_call_log(_this, LOG_INFO, "RecvICRQ session_id=%u", _this->peer_session_id); return 0; size_check_failed: l2tp_call_log(_this, LOG_ERR, "Received bad ICRQ: %s", emes); l2tp_call_disconnect(_this, L2TP_CDN_RCODE_ERROR_CODE, L2TP_ECODE_WRONG_LENGTH, NULL, NULL, 0); return 1; }
/* * receiver SCCRQ */ static int l2tp_ctrl_recv_SCCRQ(l2tp_ctrl *_this, u_char *pkt, int pktlen, l2tpd *_l2tpd, struct sockaddr *peer) { int avpsz, len, protover, protorev, firmrev, result; struct l2tp_avp *avp; char host[NI_MAXHOST], serv[NI_MAXSERV]; char buf[L2TP_AVP_MAXSIZ], emes[256], hostname[256], vendorname[256]; result = L2TP_STOP_CCN_RCODE_GENERAL_ERROR; strlcpy(hostname, "(no hostname)", sizeof(hostname)); strlcpy(vendorname, "(no vendorname)", sizeof(vendorname)); firmrev = 0; protover = 0; protorev = 0; avp = (struct l2tp_avp *)buf; while (pktlen >= 6 && (avpsz = avp_enum(avp, pkt, pktlen, 1)) > 0) { pkt += avpsz; pktlen -= avpsz; if (avp->vendor_id != 0) { L2TP_CTRL_DBG((_this, LOG_DEBUG, "Received a Vendor-specific AVP vendor-id=%d " "type=%d", avp->vendor_id, avp->attr_type)); continue; } switch (avp->attr_type) { case L2TP_AVP_TYPE_MESSAGE_TYPE: AVP_SIZE_CHECK(avp, ==, 8); continue; case L2TP_AVP_TYPE_PROTOCOL_VERSION: AVP_SIZE_CHECK(avp, ==, 8); protover = avp->attr_value[0]; protorev = avp->attr_value[1]; if (protover != L2TP_RFC2661_VERSION || protorev != L2TP_RFC2661_REVISION) { result = L2TP_STOP_CCN_RCODE_GENERAL_ERROR; snprintf(emes, sizeof(emes), "Peer's protocol version is not supported:" " %d.%d", protover, protorev); goto not_acceptable; } continue; case L2TP_AVP_TYPE_FRAMING_CAPABILITIES: AVP_SIZE_CHECK(avp, ==, 10); if ((avp_get_val32(avp) & L2TP_FRAMING_CAP_FLAGS_SYNC) == 0) { L2TP_CTRL_DBG((_this, LOG_DEBUG, "Peer doesn't " "support synchronous framing")); } continue; case L2TP_AVP_TYPE_BEARER_CAPABILITIES: AVP_SIZE_CHECK(avp, ==, 10); continue; case L2TP_AVP_TYPE_TIE_BREAKER: AVP_SIZE_CHECK(avp, ==, 14); /* * As the implementation never send SCCRQ, * the peer is always winner */ continue; case L2TP_AVP_TYPE_FIRMWARE_REVISION: AVP_SIZE_CHECK(avp, >=, 6); firmrev = avp_get_val16(avp); continue; case L2TP_AVP_TYPE_HOST_NAME: AVP_SIZE_CHECK(avp, >, 4); len = MINIMUM(sizeof(hostname) - 1, avp->length - 6); memcpy(hostname, avp->attr_value, len); hostname[len] = '\0'; continue; case L2TP_AVP_TYPE_VENDOR_NAME: AVP_SIZE_CHECK(avp, >, 4); len = MINIMUM(sizeof(vendorname) - 1, avp->length - 6); memcpy(vendorname, avp->attr_value, len); vendorname[len] = '\0'; continue; case L2TP_AVP_TYPE_ASSINGED_TUNNEL_ID: AVP_SIZE_CHECK(avp, ==, 8); _this->peer_tunnel_id = avp_get_val16(avp); continue; case L2TP_AVP_TYPE_RECV_WINDOW_SIZE: AVP_SIZE_CHECK(avp, ==, 8); _this->peer_winsz = avp_get_val16(avp); continue; } if (avp->is_mandatory) { l2tp_ctrl_log(_this, LOG_WARNING, "Received AVP (%s/%d) is not supported, but it's " "mandatory", avp_attr_type_string(avp->attr_type), avp->attr_type); #ifdef L2TP_CTRL_DEBUG } else { L2TP_CTRL_DBG((_this, LOG_DEBUG, "AVP (%s/%d) is not handled", avp_attr_type_string(avp->attr_type), avp->attr_type)); #endif } } if (getnameinfo((struct sockaddr *)&_this->peer, _this->peer.ss_len, host, sizeof(host), serv, sizeof(serv), NI_NUMERICHOST | NI_NUMERICSERV | NI_DGRAM) != 0) { l2tp_ctrl_log(_this, LOG_ERR, "getnameinfo() failed at %s(): %m", __func__); strlcpy(host, "error", sizeof(host)); strlcpy(serv, "error", sizeof(serv)); } l2tp_ctrl_log(_this, LOG_NOTICE, "logtype=Started RecvSCCRQ " "from=%s:%s/udp tunnel_id=%u/%u protocol=%d.%d winsize=%d " "hostname=%s vendor=%s firm=%04X", host, serv, _this->tunnel_id, _this->peer_tunnel_id, protover, protorev, _this->peer_winsz, hostname, vendorname, firmrev); return 0; not_acceptable: size_check_failed: l2tp_ctrl_log(_this, LOG_ERR, "Received bad SCCRQ: %s", emes); l2tp_ctrl_stop(_this, result); return 1; }