As for the TCP MSS option you can check CsnatDlg::CheckMTUCorrelation in snatDlg.cpp
I don’t have an open source sample using ICMP fragmentation needed option, but if packet size exceeds MTU and DF flag is set then you can use the function below to convert it to ICMP type 3 code 4 (“fragmentation needed but don’t fragment set”) and forward back to the host.
void convert_to_icmp_unreachable(INTERMEDIATE_BUFFER& buffer) const
{
auto* eth_header = reinterpret_cast<ether_header_ptr>(buffer.m_IBuffer);
auto* ip_header = reinterpret_cast<iphdr_ptr>(buffer.m_IBuffer + ETHER_HEADER_LENGTH);
// 1. Copy IP header and 8 bytes of payload after icmp header
auto* const next_header = reinterpret_cast<PCHAR>(ip_header) + sizeof(DWORD) * ip_header->ip_hl;
const auto payload_length = static_cast<unsigned short>(next_header - reinterpret_cast<char*>(ip_header) + 8);
memmove(
reinterpret_cast<char*>(eth_header) + ETHER_HEADER_LENGTH + sizeof(iphdr) + sizeof(icmphdr),
ip_header,
payload_length
);
// 2. Swap MAC addresses
std::swap(eth_header->h_dest, eth_header->h_source);
// 3. Swap IP addresses
std::swap(ip_header->ip_dst, ip_header->ip_src);
// 4. Initialize IP header
ip_header->ip_hl = 5;
ip_header->ip_v = 4;
ip_header->ip_tos = 0;
ip_header->ip_len = htons(sizeof(iphdr) + sizeof(icmphdr) + payload_length);
ip_header->ip_off = htons(IP_DF);
ip_header->ip_ttl = 30;
ip_header->ip_p = IPPROTO_ICMP;
// 5. Initialize ICMP header
auto* const icmp_header = reinterpret_cast<icmphdr_ptr>(ip_header + 1);
icmp_header->type = 3;
icmp_header->code = 4;
icmp_header->seq = htons(config_.default_adapter->get_mtu());
// Recalculate checksum
RecalculateICMPChecksum(&buffer);
RecalculateIPChecksum(&buffer);
buffer.m_Length = ETHER_HEADER_LENGTH + sizeof(iphdr) + sizeof(icmphdr) + payload_length;
}