📄 ipsec_icmp_pmtu.c
字号:
if (p_sa_bundle->mode == TRANSPORT) { /* In case of transport, we need full original packet to get * access to next header field in esp header. */ pmtu_message->transport = TRUE; if (data_len != complete_packet_len) { return (ERROR); } } if (ipsec_decrypt_esp_message ((SA_BUNDLE *)p_sa_bundle->reflected_sa, bptr_esp_hdr, data_len, &bptr_decrypted_data, &decrypted_data_len, &pad_len, &next_header) == FALSE) { return (ERROR); } data_len = decrypted_data_len; if (p_sa_bundle->mode == TRANSPORT) { pmtu_message->ip_nxt_protocol = next_header; data_len = data_len - pad_len - 2 * sizeof (UCHAR); status = ipsecPmtuDataCopy (pmtu_message, bptr_decrypted_data, data_len); } else { status = ipsecPmtuTunnelMessageProcess ((struct ip *)bptr_decrypted_data, data_len, pmtu_message, sa_info); } return (status); }/****************************************************************************** * ipsecPmtuTunnelMessageProcess - removes the tunnel headers * * This function populates the pmtu message with PMTU payload data and the * destination address of the host to which the PMTU message has to be sent * * NOMANUAL * * RETURNS : OK or ERROR if the destination address could not be found. */LOCAL STATUS ipsecPmtuTunnelMessageProcess ( struct ip *ip, /* ip header */ UINT data_len, /* remaining pmtu payload */ IPSEC_PMTU_MESSAGE *pmtu_message, /* structure to store pmtu info*/ SA_BUNDLE_INFO *sa_info /* info to retrieve sa from sadb */ ) { if (ip->ip_v == IP_V4) { if (data_len < MINIMUM_IP_V4_HEADER_LENGTH) { if (sa_info->p_sa_bundle == NULL) { sa_info->p_sa_bundle = ipsecPmtuSaBundleFind (sa_info); } if (sa_info->p_sa_bundle == NULL) { return (ERROR); } else { return (ipsecPmtuDestinationFind (pmtu_message, sa_info->p_sa_bundle)); } } WRSEC_INET4_SET_STRUCT_A_WITH_IN_ADDR_B ((*(WRSEC_INET4_ADDR *)pmtu_message->destination_address), ip->ip_src); } #if STACK_NAME == STACK_NAME_V4_V6 && defined (INET6) else if (ip->ip_v == IP_V6) { struct ip6_hdr *ip6 = (struct ip6_hdr *)ip; if (data_len < MINIMUM_IP_V6_HEADER_LENGTH) { if (sa_info->p_sa_bundle == NULL) { sa_info->p_sa_bundle = ipsecPmtuSaBundleFind (sa_info); } if (sa_info->p_sa_bundle == NULL) { return (ERROR); } else { return (ipsecPmtuDestinationFind (pmtu_message, sa_info->p_sa_bundle)); } } WRSEC_INET6_SET_STRUCT_A_WITH_IN6_ADDR_B ((*(WRSEC_INET6_ADDR *)pmtu_message->destination_address), ip6->ip6_src); } #endif /* STACK_NAME == STACK_NAME_V4_V6 && defined (INET6) */ else { ipsec_printf (IPSEC_ERROR_PRINTF, "IPSEC:PMTU:Tunnel:only IPv4 and IPv6 address are supported\n"); return (ERROR); } return ipsecPmtuDataCopy (pmtu_message, (UCHAR *)ip, data_len); }/****************************************************************************** * ipsecPmtuTransportMessageProcess - bypasses the packet to the upper layers. * * This function recalculates the icmp(6) checksum and bypasses the packet * to the upper layers. * * NOMANUAL * * RETURNS: OK always * */LOCAL STATUS ipsecPmtuTransportMessageProcess ( struct mbuf *m, /* pointer to mbuf */ IPSEC_PMTU_MESSAGE *pmtu_message /* contains pmtu info */ ) { STATUS status; UCHAR *p_transport; int hlen, ip2len; status = OK; hlen = ip2len = 0; p_transport = NULL; if (pmtu_message->family == WRSEC_AF_INET4) { struct icmp *icmp4; struct ip *ip1, *ip2; ip1 = NULL; icmp4 = NULL; ip1 = mtod (m, struct ip *); hlen = ip1->ip_hl << 2; icmp4 = (struct icmp *) ((UCHAR *)ip1 + hlen); ip2 = (struct ip *) ((UCHAR *)icmp4 + ICMP_MINLEN); ip2len = ip2->ip_hl << 2; p_transport = (UCHAR *)ip2 + ip2len; /* * For the error advice packets we must first insure that the * packet is large enough to contain the returned ip header. */ if (pmtu_message->datalength < (sizeof (struct ip) + MIN_TRANSPORT_HDR_LEN)) { /* Store the PMTU Message */ return (OK); } bcopy ((const char *)pmtu_message->data, (char *)p_transport, (int)pmtu_message->datalength); ip2->ip_p = pmtu_message->ip_nxt_protocol; ip2->ip_len = ip2len + pmtu_message->datalength; ip2->ip_len = htons (ip2->ip_len); ip1->ip_len = ICMP_MINLEN + ip2->ip_len; m->m_len = ip1->ip_len; m->m_data = (char *)icmp4; m->m_pkthdr.len = m->m_len; icmp4->icmp_nextmtu = htons (pmtu_message->pmtu); icmp4->icmp_cksum = 0; icmp4->icmp_cksum = in_cksum (m, (ICMP_MINLEN + ip2->ip_len)); m->m_data = (char *)ip1; m->m_len = ip1->ip_len + hlen; m->m_pkthdr.len = m->m_len; m->m_pkthdr.rcvif = (struct ifnet *)0; } #if STACK_NAME == STACK_NAME_V4_V6 && defined (INET6) else if (pmtu_message->family == WRSEC_AF_INET6) { struct ip6_hdr *ip6_hdr1, *ip6_hdr2; struct icmp6_hdr *icmp6; ip6_hdr1 = mtod (m, struct ip6_hdr *); hlen = ipsecIpv6HdrLenGet (NULL, ip6_hdr1); ip6_hdr2 = (struct ip6_hdr *) ((char *)ip6_hdr1 + hlen + ICMP6_MINLEN); ip2len = ipsecIpv6HdrLenGet (NULL, ip6_hdr2); p_transport = (UCHAR *)ip6_hdr2 + ip2len; if (pmtu_message->datalength < (sizeof (struct ip6_hdr) + MIN_TRANSPORT_HDR_LEN)) { /* Store the PMTU Message */ return (OK); } bcopy ((const char *)pmtu_message->data, (char *)p_transport, (int)pmtu_message->datalength); ip6_hdr2->ip6_nxt = pmtu_message->ip_nxt_protocol; ip6_hdr2->ip6_plen = pmtu_message->datalength; ip6_hdr1->ip6_plen = ICMP6_MINLEN + ip2len + ip6_hdr2->ip6_plen; ip6_hdr2->ip6_plen = htons (ip6_hdr2->ip6_plen); icmp6 = (struct icmp6_hdr *) ((char *)ip6_hdr1 + hlen); m->m_len = ip6_hdr1->ip6_plen + hlen; m->m_pkthdr.len = m->m_len; icmp6->icmp6_mtu = htonl (pmtu_message->pmtu); icmp6->icmp6_cksum = 0; icmp6->icmp6_cksum = in6_cksum (m, IPPROTO_ICMPV6, hlen, ip6_hdr1->ip6_plen); ip6_hdr1->ip6_plen = htons (ip6_hdr1->ip6_plen); m->m_pkthdr.rcvif = (struct ifnet *)0; return (status); } #endif /* STACK_NAME == STACK_NAME_V4_V6 && defined (INET6) */ return (status); }/****************************************************************************** * ipsecPmtuDataCopy - stores the PMTU payload in the PMTU message. * * NOMANUAL * RETUNRNS : OK or ERROR if the data pointer is not set. */LOCAL STATUS ipsecPmtuDataCopy ( IPSEC_PMTU_MESSAGE *pmtu_message, /* structure to store pmtu payload */ UCHAR *data, /* pmtu data to store */ UINT data_len /* length of pmtu data */ ) { pmtu_message->data = (UCHAR *)wrSecCalloc (1, data_len); if (pmtu_message->data == NULL) { return (ERROR); } pmtu_message->datalength = data_len; memcpy (pmtu_message->data, data, data_len); return (OK); }/****************************************************************************** * ipsecPmtuDestinationFind - finds the destination to which the PMTU * message has to be sent. * * This function finds the destination to which the PMTU message has to be * sent. This is called in case where the PMTU message received by the * gateway does not contain information regarding the originator of the * packet(i.e which caused the PMTU to be generated). * * NOMANUAL * * RETURNS : OK if the destination has been found else ERROR. */LOCAL STATUS ipsecPmtuDestinationFind ( IPSEC_PMTU_MESSAGE *pmtu_message, /* structure to store dest address */ SA_BUNDLE *p_sa_bundle /* outbound sa bundle */ ) { WRSEC_INET_ADDR *p_source; p_source = sadb_get_source_address ((SA_BUNDLE *)p_sa_bundle->reflected_sa); if (p_source == NULL) { return (ERROR); } if (p_source->type == WRSEC_AF_INET4) { WRSEC_INET4_ASSIGN_B_TO_A (((WRSEC_INET4_ADDR *)pmtu_message->destination_address), ((WRSEC_INET4_ADDR *)p_source)); } #if STACK_NAME == STACK_NAME_V4_V6 && defined (INET6) else if (p_source->type == WRSEC_AF_INET6) { WRSEC_INET6_ASSIGN_B_TO_A (((WRSEC_INET6_ADDR *)pmtu_message->destination_address), ((WRSEC_INET6_ADDR *)p_source)); } #endif /* STACK_NAME == STACK_NAME_V4_V6 && defined (INET6) */ else { return (ERROR); } return (OK); }/****************************************************************************** * ipsecPmtuForwardPmtuMessage - forward the pmtu message. * * This function is called after tunnel processing to forward the PMTU message * that the gateway has received on behalf of other hosts whose policies * have been configured in its SADB. * * NOMANUAL * * RETURNS : ERROR if the packet has been forwarded. */LOCAL STATUS ipsecPmtuForwardPmtuMessage ( struct mbuf *m_source, /* packet to forward */ IPSEC_PMTU_MESSAGE *pmtu_message /* info to make pmtu packet */ ) { STATUS status; USHORT icmp_len; int hlen, s; struct ifnet *sptr_ifnet = NULL; UINT mblk_size; struct mbuf *m; IPSEC_NETWORK_INTERFACE *p_network_interface; status = OK; if (pmtu_message->family == WRSEC_AF_INET4) { struct ip *orig_ip; struct ip *ip4; struct icmp *icmp4; struct route ro; icmp4 = NULL; orig_ip = NULL; orig_ip = mtod (m_source, struct ip *); hlen = orig_ip->ip_hl << 2; /* The pmtu payload should contain the full original ip header plus * 8 bytes of upper layer protocol ( UDP/TCP) */ if (pmtu_message->datalength < (sizeof (struct ip) + MIN_TRANSPORT_HDR_LEN)) { /* Store the PMTU Message */ WRN_M_FREEM (m_source); wrSecTrace( TRACE_ALL, L1, "PACKET DROPPED!! 'function::%s'\n", __FUNCTION__); return (ERROR); } mblk_size = ICMP_MINLEN + pmtu_message->datalength + (MINIMUM_IP_V4_HEADER_LENGTH); #if STACK_NAME == STACK_NAME_V4_V6 MGET1 (m, mblk_size, M_WAIT, m_source->m_type); #else m = m_getclr (M_WAIT, m_source->m_type, mblk_size, TRUE); #endif /* STACK_NAME == STACK_NAME_V4_V6 */ if (m == NULL) { /* Store the PMTU Message */ WRN_M_FREEM (m_source); wrSecTrace( TRACE_ALL, L1, "PACKET DROPPED!! 'function::%s'\n", __FUNCTION__); return (ERROR); } ip4 = mtod (m, struct ip *); ip4->ip_v = IPVERSION; ip4->ip_hl = MINIMUM_IP_V4_HEADER_LENGTH >> 2; ip4->ip_p = TRANSPORT_PROTO_ICMP; ip4->ip_off = 0; ip4->ip_ttl = IPDEFTTL; p_network_interface = ipsecFindNetworkInterfaceBasedOnIfnet (m_source->m_pkthdr.rcvif, WRSEC_AF_INET4); if (p_network_interface == NULL) { return (ERROR); } WRSEC_INET4_SET_IN_ADDR_A_WITH_STRUCT_B(ip4->ip_src, (*(WRSEC_INET4_ADDR *) (p_network_interface->p_address))) WRSEC_INET4_SET_IN_ADDR_A_WITH_STRUCT_B(ip4->ip_dst, (*(WRSEC_INET4_ADDR *)pmtu_message->destination_address)) icmp4 = (struct icmp *) ((UCHAR *)ip4 + MINIMUM_IP_V4_HEADER_LENGTH); icmp_len = ICMP_MINLEN; if (pmtu_message->data != NULL) { UCHAR *p_transport = (UCHAR *)icmp4 + ICMP_MINLEN;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -