/* * natd - Network Address Translation Daemon for FreeBSD. * * This software is provided free of charge, with no * warranty of any kind, either expressed or implied. * Use at your own risk. * * You may copy, modify and distribute this software (icmp.c) freely. * * Ari Suutari * * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "natd.h" int SendNeedFragIcmp (int sock, struct ip* failedDgram, int mtu) { char icmpBuf[IP_MAXPACKET]; struct ip* ip; struct icmp* icmp; int icmpLen; int failBytes; int failHdrLen; struct sockaddr_in addr; int wrote; struct in_addr swap; /* * Don't send error if packet is * not the first fragment. */ if (ntohs (failedDgram->ip_off) & ~(IP_MF | IP_DF)) return 0; /* * Dont respond if failed datagram is ICMP. */ if (failedDgram->ip_p == IPPROTO_ICMP) return 0; /* * Start building the message. */ ip = (struct ip*) icmpBuf; icmp = (struct icmp*) (icmpBuf + sizeof (struct ip)); /* * Complete ICMP part. */ icmp->icmp_type = ICMP_UNREACH; icmp->icmp_code = ICMP_UNREACH_NEEDFRAG; icmp->icmp_cksum = 0; icmp->icmp_void = 0; icmp->icmp_nextmtu = htons (mtu); /* * Copy header + 64 bits of original datagram. */ failHdrLen = (failedDgram->ip_hl << 2); failBytes = failedDgram->ip_len - failHdrLen; if (failBytes > 8) failBytes = 8; failBytes += failHdrLen; icmpLen = ICMP_MINLEN + failBytes; memcpy (&icmp->icmp_ip, failedDgram, failBytes); /* * Calculate checksum. */ icmp->icmp_cksum = LibAliasInternetChecksum (mla, (u_short*) icmp, icmpLen); /* * Add IP header using old IP header as template. */ memcpy (ip, failedDgram, sizeof (struct ip)); ip->ip_v = 4; ip->ip_hl = 5; ip->ip_len = htons (sizeof (struct ip) + icmpLen); ip->ip_p = IPPROTO_ICMP; ip->ip_tos = 0; swap = ip->ip_dst; ip->ip_dst = ip->ip_src; ip->ip_src = swap; LibAliasIn (mla, (char*) ip, IP_MAXPACKET); addr.sin_family = AF_INET; addr.sin_addr = ip->ip_dst; addr.sin_port = 0; /* * Put packet into processing queue. */ wrote = sendto (sock, icmp, icmpLen, 0, (struct sockaddr*) &addr, sizeof addr); if (wrote != icmpLen) Warn ("Cannot send ICMP message."); return 1; }