diff options
Diffstat (limited to 'usr.sbin/natd/icmp.c')
-rw-r--r-- | usr.sbin/natd/icmp.c | 112 |
1 files changed, 112 insertions, 0 deletions
diff --git a/usr.sbin/natd/icmp.c b/usr.sbin/natd/icmp.c new file mode 100644 index 0000000..40464ff --- /dev/null +++ b/usr.sbin/natd/icmp.c @@ -0,0 +1,112 @@ +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <ctype.h> + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <errno.h> +#include <signal.h> + +#include <netdb.h> + +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/ip_icmp.h> +#include <machine/in_cksum.h> + +#include <alias.h> + +#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 = InternetChecksum ((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; + + PacketAliasIn ((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; +} + + |