xref: /freebsd/sbin/natd/icmp.c (revision f13f9fada747ab4c953b849aadf4d155e671279f)
1f13f9fadSAlexander Langer /*
2f13f9fadSAlexander Langer  * $Id$
3f13f9fadSAlexander Langer  */
4f13f9fadSAlexander Langer 
524084f9bSBrian Somers #include <stdlib.h>
624084f9bSBrian Somers #include <stdio.h>
724084f9bSBrian Somers #include <unistd.h>
824084f9bSBrian Somers #include <string.h>
924084f9bSBrian Somers #include <ctype.h>
1024084f9bSBrian Somers 
1124084f9bSBrian Somers #include <sys/types.h>
1224084f9bSBrian Somers #include <sys/socket.h>
1324084f9bSBrian Somers #include <sys/time.h>
1424084f9bSBrian Somers #include <errno.h>
1524084f9bSBrian Somers #include <signal.h>
1624084f9bSBrian Somers 
1724084f9bSBrian Somers #include <netdb.h>
1824084f9bSBrian Somers 
1924084f9bSBrian Somers #include <netinet/in.h>
2024084f9bSBrian Somers #include <netinet/in_systm.h>
2124084f9bSBrian Somers #include <netinet/ip.h>
2224084f9bSBrian Somers #include <netinet/ip_icmp.h>
2324084f9bSBrian Somers #include <machine/in_cksum.h>
2424084f9bSBrian Somers 
2524084f9bSBrian Somers #include <alias.h>
2624084f9bSBrian Somers 
2724084f9bSBrian Somers #include "natd.h"
2824084f9bSBrian Somers 
2924084f9bSBrian Somers int SendNeedFragIcmp (int sock, struct ip* failedDgram, int mtu)
3024084f9bSBrian Somers {
3124084f9bSBrian Somers 	char			icmpBuf[IP_MAXPACKET];
3224084f9bSBrian Somers 	struct ip*		ip;
3324084f9bSBrian Somers 	struct icmp*		icmp;
3424084f9bSBrian Somers 	int			icmpLen;
3524084f9bSBrian Somers 	int			failBytes;
3624084f9bSBrian Somers 	int			failHdrLen;
3724084f9bSBrian Somers 	struct sockaddr_in	addr;
3824084f9bSBrian Somers 	int			wrote;
3924084f9bSBrian Somers 	struct in_addr		swap;
4024084f9bSBrian Somers /*
4124084f9bSBrian Somers  * Don't send error if packet is
4224084f9bSBrian Somers  * not the first fragment.
4324084f9bSBrian Somers  */
4424084f9bSBrian Somers 	if (ntohs (failedDgram->ip_off) & ~(IP_MF | IP_DF))
4524084f9bSBrian Somers 		return 0;
4624084f9bSBrian Somers /*
4724084f9bSBrian Somers  * Dont respond if failed datagram is ICMP.
4824084f9bSBrian Somers  */
4924084f9bSBrian Somers 	if (failedDgram->ip_p == IPPROTO_ICMP)
5024084f9bSBrian Somers 		return 0;
5124084f9bSBrian Somers /*
5224084f9bSBrian Somers  * Start building the message.
5324084f9bSBrian Somers  */
5424084f9bSBrian Somers 	ip   = (struct ip*) icmpBuf;
5524084f9bSBrian Somers 	icmp = (struct icmp*) (icmpBuf + sizeof (struct ip));
5624084f9bSBrian Somers /*
5724084f9bSBrian Somers  * Complete ICMP part.
5824084f9bSBrian Somers  */
5924084f9bSBrian Somers 	icmp->icmp_type  	= ICMP_UNREACH;
6024084f9bSBrian Somers 	icmp->icmp_code		= ICMP_UNREACH_NEEDFRAG;
6124084f9bSBrian Somers 	icmp->icmp_cksum	= 0;
6224084f9bSBrian Somers 	icmp->icmp_void		= 0;
6324084f9bSBrian Somers 	icmp->icmp_nextmtu	= htons (mtu);
6424084f9bSBrian Somers /*
6524084f9bSBrian Somers  * Copy header + 64 bits of original datagram.
6624084f9bSBrian Somers  */
6724084f9bSBrian Somers 	failHdrLen = (failedDgram->ip_hl << 2);
6824084f9bSBrian Somers 	failBytes  = failedDgram->ip_len - failHdrLen;
6924084f9bSBrian Somers 	if (failBytes > 8)
7024084f9bSBrian Somers 		failBytes = 8;
7124084f9bSBrian Somers 
7224084f9bSBrian Somers 	failBytes += failHdrLen;
7324084f9bSBrian Somers 	icmpLen    = ICMP_MINLEN + failBytes;
7424084f9bSBrian Somers 
7524084f9bSBrian Somers 	memcpy (&icmp->icmp_ip, failedDgram, failBytes);
7624084f9bSBrian Somers /*
7724084f9bSBrian Somers  * Calculate checksum.
7824084f9bSBrian Somers  */
79fb994b07SBrian Somers 	icmp->icmp_cksum = PacketAliasInternetChecksum ((u_short*) icmp,
80fb994b07SBrian Somers 							icmpLen);
8124084f9bSBrian Somers /*
8224084f9bSBrian Somers  * Add IP header using old IP header as template.
8324084f9bSBrian Somers  */
8424084f9bSBrian Somers 	memcpy (ip, failedDgram, sizeof (struct ip));
8524084f9bSBrian Somers 
8624084f9bSBrian Somers 	ip->ip_v	= 4;
8724084f9bSBrian Somers 	ip->ip_hl	= 5;
8824084f9bSBrian Somers 	ip->ip_len	= htons (sizeof (struct ip) + icmpLen);
8924084f9bSBrian Somers 	ip->ip_p	= IPPROTO_ICMP;
9024084f9bSBrian Somers 	ip->ip_tos	= 0;
9124084f9bSBrian Somers 
9224084f9bSBrian Somers 	swap = ip->ip_dst;
9324084f9bSBrian Somers 	ip->ip_dst = ip->ip_src;
9424084f9bSBrian Somers 	ip->ip_src = swap;
9524084f9bSBrian Somers 
9624084f9bSBrian Somers 	PacketAliasIn ((char*) ip, IP_MAXPACKET);
9724084f9bSBrian Somers 
9824084f9bSBrian Somers 	addr.sin_family		= AF_INET;
9924084f9bSBrian Somers 	addr.sin_addr		= ip->ip_dst;
10024084f9bSBrian Somers 	addr.sin_port		= 0;
10124084f9bSBrian Somers /*
10224084f9bSBrian Somers  * Put packet into processing queue.
10324084f9bSBrian Somers  */
10424084f9bSBrian Somers 	wrote = sendto (sock,
10524084f9bSBrian Somers 		        icmp,
10624084f9bSBrian Somers 	    		icmpLen,
10724084f9bSBrian Somers 	    		0,
10824084f9bSBrian Somers 	    		(struct sockaddr*) &addr,
10924084f9bSBrian Somers 	    		sizeof addr);
11024084f9bSBrian Somers 
11124084f9bSBrian Somers 	if (wrote != icmpLen)
11224084f9bSBrian Somers 		Warn ("Cannot send ICMP message.");
11324084f9bSBrian Somers 
11424084f9bSBrian Somers 	return 1;
11524084f9bSBrian Somers }
11624084f9bSBrian Somers 
11724084f9bSBrian Somers 
118