📄 ipsec_icmp_pmtu.c
字号:
/* save this destination, if we later find that original packet was * not tunnelled then we need this destination (us). */ WRSEC_INET4_SET_STRUCT_A_WITH_IN_ADDR_B((*(WRSEC_INET4_ADDR *)pmtu_message->destination_address), ip1->ip_dst) /* Check if we are the destination address */ if (ipsec_find_network_interface_based_on_ip_address (pmtu_message->destination_address) == NULL) { /* We are not the destination for this packet, * so we will not do any pmtu processing */ ipsecPmtuMessageDelete (pmtu_message); ipsecSAInfoDestroy (sa_info); return (OK); } offset = ip1->ip_hl << 2; total_packet_length = m->m_pkthdr.len; if (m->m_len < total_packet_length) { if ((*pp_m = m_pullup (m, total_packet_length)) == NULL) { ipsecPmtuMessageDelete (pmtu_message); ipsecSAInfoDestroy (sa_info); WRN_M_FREEM (m); /* drop the packet*/ wrSecTrace( TRACE_ALL, L1, "PACKET DROPPED!! 'function::%s'\n", __FUNCTION__); return (ERROR); } } icmp4 = (struct icmp *) ((UCHAR *)ip1 + (ip1->ip_hl << 2)); offset += ICMP_MINLEN; ip2 = (struct ip *) ((UCHAR *)icmp4 + ICMP_MINLEN); complete_packet_len = ntohs (ip2->ip_len); pmtu_message->pmtu = ntohs (icmp4->icmp_nextmtu) - packetBufReservedHeaderSizeGet(); WRSEC_INET4_SET_STRUCT_A_WITH_IN_ADDR_B((*(WRSEC_INET4_ADDR *)sa_info->tunnel_endpoint), ip2->ip_dst) offset += ip2->ip_hl << 2; complete_packet_len -= ip2->ip_hl << 2; next_protocol = ip2->ip_p; } #if STACK_NAME == STACK_NAME_V4_V6 && defined (INET6) else if (((struct ip *)ip)->ip_v == IP_V6) { struct icmp6_hdr *icmp6; struct ip6_hdr *ip6_hdr2; struct ip6_hdr *ip6_hdr1; BOOL loop_continue = TRUE; UCHAR *p_extn_header; int ip6hdr2_len; USHORT fragment_offset; /* initialize pmtu_mesage */ ipsecPmtuMessageCreate (pmtu_message, WRSEC_AF_INET6); ipsecPmtuSaInfoCreate (sa_info, WRSEC_AF_INET6); ip6_hdr1 = (struct ip6_hdr *)ip; WRSEC_INET6_SET_STRUCT_A_WITH_IN6_ADDR_B((*(WRSEC_INET6_ADDR *)pmtu_message->destination_address), ip6_hdr1->ip6_dst) offset = ipsecIpv6HdrLenGet (m, NULL); /* Check if we are the destination address */ if (ipsec_find_network_interface_based_on_ip_address (pmtu_message->destination_address) == NULL) { /* We are not the destination for this packet, * so we will not do any pmtu processing */ ipsecPmtuMessageDelete (pmtu_message); ipsecSAInfoDestroy (sa_info); return (OK); } total_packet_length = m->m_pkthdr.len; if (m->m_len < total_packet_length) { if ((*pp_m = m_pullup (m, total_packet_length)) == 0) { ipsecPmtuMessageDelete (pmtu_message); ipsecSAInfoDestroy (sa_info); WRN_M_FREEM (m); /* drop the packet*/ wrSecTrace( TRACE_ALL, L1, "PACKET DROPPED!! 'function::%s'\n", __FUNCTION__); return (ERROR); } } icmp6 = (struct icmp6_hdr *) ((UCHAR *)ip6_hdr1 + offset); offset += ICMP6_MINLEN; ip6_hdr2 = (struct ip6_hdr *) ((UCHAR *)icmp6 + ICMP6_MINLEN); ip6hdr2_len = sizeof (struct ip6_hdr); complete_packet_len = ntohs (ip6_hdr2->ip6_plen); next_protocol = ip6_hdr2->ip6_nxt; pmtu_message->pmtu = ntohl (icmp6->icmp6_mtu) - packetBufReservedHeaderSizeGet(); WRSEC_INET6_SET_STRUCT_A_WITH_IN6_ADDR_B((*(WRSEC_INET6_ADDR *)sa_info->tunnel_endpoint), ip6_hdr2->ip6_dst) offset += ip6hdr2_len; while (loop_continue) { p_extn_header = (UCHAR *)ip + offset; switch (next_protocol) { case IPPROTO_HOPOPTS: case IPPROTO_DSTOPTS: case IPPROTO_ROUTING: /* The length feild in the case of routing ,hop by * hop ,destination extension headers is the header * length in 8-octet units,not counting the first 8 * octets. */ offset += 8 + 8 * (* (p_extn_header + 1)); break; case IPPROTO_FRAGMENT: /* The Length of the fragment header is 8 bytes */ offset += 8; /* check if fragment offset is zero. */ fragment_offset = *(p_extn_header + 2) << 5; fragment_offset |= *(p_extn_header + 3) >> 3; if (fragment_offset) { loop_continue = FALSE; } break; default: loop_continue = FALSE; } if (loop_continue) { next_protocol = * (p_extn_header); } } } #endif /* STACK_NAME == STACK_NAME_V4_V6 && defined (INET6) */ if (next_protocol == TRANSPORT_PROTO_AH) { UCHAR *ah_header; /* * IP1 ICMP IP2 AH/AH+ESP [IP3*] TCP* /UDP* /OTHERS* * (*:may be encrypted) */ ah_header = (UCHAR *)ip + offset; status = ipsecPmtuAhMessageProcess (ah_header, (total_packet_length - offset), complete_packet_len, pmtu_message, sa_info); } else if (next_protocol == TRANSPORT_PROTO_ESP) { UCHAR *esp_header; /* * IP1 ICMP IP2 ESP [IP3*] TCP* /UDP* /OTHERS* * (*:may be encrypted) */ esp_header = (UCHAR *)ip + offset; status = ipsecPmtuEspMessageProcess (esp_header, (total_packet_length - offset), complete_packet_len, pmtu_message, sa_info); } else { ipsecPmtuMessageDelete (pmtu_message); ipsecSAInfoDestroy (sa_info); return (OK); } if (status == OK) { /* We have found the destinataion. */ if (pmtu_message->transport == TRUE) { status = (ipsecPmtuTransportMessageProcess (m, pmtu_message)); } else { status = ipsecPmtuForwardPmtuMessage (m, pmtu_message); } } else { WRN_M_FREEM (m); wrSecTrace( TRACE_ALL, L1, "PACKET DROPPED!! 'function::%s'\n", __FUNCTION__); status = ERROR; } /* store PMTU information in the database */ if (ipsecPmtuStorePmtuInfo (pmtu_message, sa_info) == ERROR) { status = ERROR; } ipsecPmtuMessageDelete (pmtu_message); ipsecSAInfoDestroy (sa_info); return (status); }/****************************************************************************** * ipsecPmtuStorePmtuInfo - stores the PMTU information in the database. * * NOMANUAL * RETURNS : OK if the info has been stored or else ERROR. */LOCAL STATUS ipsecPmtuStorePmtuInfo ( IPSEC_PMTU_MESSAGE *pmtu_message, SA_BUNDLE_INFO *sa_info ) { UINT age; if (sa_info->p_sa_bundle == NULL) { sa_info->p_sa_bundle = ipsecPmtuSaBundleFind (sa_info); if (sa_info->p_sa_bundle == NULL) { return (ERROR); } } age = ipsecPmtuAgeGet (sa_info->p_sa_bundle->p_reflected_address); sa_info->p_sa_bundle->pmtu_age = age; sa_info->p_sa_bundle->pmtu = pmtu_message->pmtu; return (OK); }/****************************************************************************** * ipsecPmtuAhMessageProcess - removes the ah header from the packet. * * This function removes the ah header from the packet and bypasses it to the * the upper layers if ah was applied to the packet in transport mode.In case * of tunnel it removes the ah header and tunnel header.If the next header is * a esp header then the packet is sent for furthur esp processing. * * NOMANUAL * * RETURNS : * OK : if the packet is to be bypassed to the upper layers or if all * the information necessary to send the PMTU message has been * stored in IPSEC_PMTU_MESSAGE. * ERROR : if all the pmtu information could not be found . */LOCAL STATUS ipsecPmtuAhMessageProcess ( UCHAR *bptr_ah_hdr, /* pointer to ah header */ int data_len, /* pmtu payload length */ UINT complete_packet_len, /* packet length of original packet */ IPSEC_PMTU_MESSAGE *pmtu_message, /* structure to store pmtu info */ SA_BUNDLE_INFO *sa_info /* information to retrive SA from database */ ) { UCHAR next_protocol; UCHAR *p_spi; STATUS status; USHORT ipsec_headers_length; USHORT ah_header_len; status = OK; ipsec_headers_length = 0; next_protocol = *bptr_ah_hdr; /* The payoad length field provides the length of the * authentication header in 32 bit words,not counting * the first 8 octets. */ ah_header_len = *(bptr_ah_hdr + 1) * 4 + 8; p_spi = bptr_ah_hdr + 4; sa_info->protocol = TRANSPORT_PROTO_AH; sa_info->spi = wrSecDeserializeULong (&p_spi); data_len -= ah_header_len; complete_packet_len -= ah_header_len; if (data_len <= 0) { sa_info->p_sa_bundle = ipsecPmtuSaBundleFind (sa_info); if (sa_info->p_sa_bundle == NULL) { return (ERROR); } if (sa_info->p_sa_bundle->mode == TRANSPORT) { pmtu_message->transport = TRUE; } /* We dont have enough data to find the source of the original * packet. Lets try to find from SA Bundle); */ return ipsecPmtuDestinationFind (pmtu_message, sa_info->p_sa_bundle); } if (next_protocol == TRANSPORT_PROTO_ESP) { status = ipsecPmtuEspMessageProcess (bptr_ah_hdr + ah_header_len, data_len, complete_packet_len, pmtu_message, sa_info); } else if ((next_protocol == TRANSPORT_PORTO_IP_IN_IP_IPV4) || (next_protocol == TRANSPORT_PROTO_IP_IN_IP_IPV6)) { status = ipsecPmtuTunnelMessageProcess ((struct ip *) (bptr_ah_hdr + ah_header_len), data_len, pmtu_message, sa_info); } else { UCHAR *data = bptr_ah_hdr + ah_header_len; pmtu_message->ip_nxt_protocol = next_protocol; pmtu_message->transport = TRUE; status = ipsecPmtuDataCopy (pmtu_message, data, data_len); } return (status); }/****************************************************************************** * ipsecPmtuEspMessageProcess - removes the esp header and decrypts packet. * * This function removes the esp header from the packet.If esp has been * applied in transport mode to the packet,then the packet is decrypted only * if we get the complete packet as the icmp pmtu payload.This is because, we * will not be having access to the next header field if we do not have the * esp trailer. In case of tunnel mode is packet is always decrypted and sent * for furthur processing. * * RETURNS : * OK : if a pmtu message has been filled with all the information necessary * to send the PMTU message. * * ERROR : if the sa bundle could not be found or if packet could not be * decrypted or if all the pmtu information could not be found. */LOCAL STATUS ipsecPmtuEspMessageProcess ( UCHAR *bptr_esp_hdr, /* pointer to esp header */ int data_len, /* pmtu payload length */ UINT complete_packet_len, /* packet length of the orginal packet */ IPSEC_PMTU_MESSAGE *pmtu_message, /* structure to store pmtu info */ SA_BUNDLE_INFO *sa_info /* info to retrieve sa from sadb */ ) { UCHAR *bptr_decrypted_data; SA_BUNDLE *p_sa_bundle; USHORT decrypted_data_len; UINT pad_len; UCHAR next_header; STATUS status; status = OK; if (sa_info->protocol != TRANSPORT_PROTO_AH) { UCHAR *p_spi = bptr_esp_hdr; sa_info->spi = wrSecDeserializeULong ((UCHAR ** )&p_spi); sa_info->protocol = TRANSPORT_PROTO_ESP; } p_sa_bundle = ipsecPmtuSaBundleFind (sa_info); if (p_sa_bundle == NULL) { status = ERROR; return (status); } sa_info->p_sa_bundle = p_sa_bundle;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -