icmp.c revision 50476
1184610Salfred/*
2184610Salfred * natd - Network Address Translation Daemon for FreeBSD.
3184610Salfred *
4184610Salfred * This software is provided free of charge, with no
5184610Salfred * warranty of any kind, either expressed or implied.
6184610Salfred * Use at your own risk.
7184610Salfred *
8184610Salfred * You may copy, modify and distribute this software (icmp.c) freely.
9184610Salfred *
10184610Salfred * Ari Suutari <suutari@iki.fi>
11184610Salfred *
12184610Salfred * $FreeBSD: head/sbin/natd/icmp.c 50476 1999-08-28 00:22:10Z peter $
13184610Salfred */
14184610Salfred
15184610Salfred#include <stdlib.h>
16184610Salfred#include <stdio.h>
17184610Salfred#include <unistd.h>
18184610Salfred#include <string.h>
19184610Salfred#include <ctype.h>
20184610Salfred
21184610Salfred#include <sys/types.h>
22184610Salfred#include <sys/socket.h>
23184610Salfred#include <sys/time.h>
24184610Salfred#include <errno.h>
25184610Salfred#include <signal.h>
26184610Salfred
27194677Sthompsa#include <netdb.h>
28194677Sthompsa
29194677Sthompsa#include <netinet/in.h>
30194677Sthompsa#include <netinet/in_systm.h>
31194677Sthompsa#include <netinet/ip.h>
32194677Sthompsa#include <netinet/ip_icmp.h>
33194677Sthompsa#include <machine/in_cksum.h>
34194677Sthompsa
35194677Sthompsa#include <alias.h>
36194677Sthompsa
37194677Sthompsa#include "natd.h"
38194677Sthompsa
39194677Sthompsaint SendNeedFragIcmp (int sock, struct ip* failedDgram, int mtu)
40194677Sthompsa{
41194677Sthompsa	char			icmpBuf[IP_MAXPACKET];
42194677Sthompsa	struct ip*		ip;
43194677Sthompsa	struct icmp*		icmp;
44194677Sthompsa	int			icmpLen;
45194677Sthompsa	int			failBytes;
46194677Sthompsa	int			failHdrLen;
47194677Sthompsa	struct sockaddr_in	addr;
48188942Sthompsa	int			wrote;
49188942Sthompsa	struct in_addr		swap;
50194677Sthompsa/*
51194677Sthompsa * Don't send error if packet is
52184610Salfred * not the first fragment.
53184610Salfred */
54184610Salfred	if (ntohs (failedDgram->ip_off) & ~(IP_MF | IP_DF))
55188942Sthompsa		return 0;
56194677Sthompsa/*
57188942Sthompsa * Dont respond if failed datagram is ICMP.
58188942Sthompsa */
59188942Sthompsa	if (failedDgram->ip_p == IPPROTO_ICMP)
60188942Sthompsa		return 0;
61188942Sthompsa/*
62188942Sthompsa * Start building the message.
63188942Sthompsa */
64188942Sthompsa	ip   = (struct ip*) icmpBuf;
65188942Sthompsa	icmp = (struct icmp*) (icmpBuf + sizeof (struct ip));
66188942Sthompsa/*
67184610Salfred * Complete ICMP part.
68188942Sthompsa */
69188942Sthompsa	icmp->icmp_type  	= ICMP_UNREACH;
70184610Salfred	icmp->icmp_code		= ICMP_UNREACH_NEEDFRAG;
71190191Sthompsa	icmp->icmp_cksum	= 0;
72190191Sthompsa	icmp->icmp_void		= 0;
73184610Salfred	icmp->icmp_nextmtu	= htons (mtu);
74184610Salfred/*
75184610Salfred * Copy header + 64 bits of original datagram.
76184610Salfred */
77184610Salfred	failHdrLen = (failedDgram->ip_hl << 2);
78184610Salfred	failBytes  = failedDgram->ip_len - failHdrLen;
79184610Salfred	if (failBytes > 8)
80184610Salfred		failBytes = 8;
81193045Sthompsa
82193045Sthompsa	failBytes += failHdrLen;
83207080Sthompsa	icmpLen    = ICMP_MINLEN + failBytes;
84207080Sthompsa
85193045Sthompsa	memcpy (&icmp->icmp_ip, failedDgram, failBytes);
86193045Sthompsa/*
87207080Sthompsa * Calculate checksum.
88184610Salfred */
89193045Sthompsa	icmp->icmp_cksum = PacketAliasInternetChecksum ((u_short*) icmp,
90193045Sthompsa							icmpLen);
91193045Sthompsa/*
92193045Sthompsa * Add IP header using old IP header as template.
93193045Sthompsa */
94193045Sthompsa	memcpy (ip, failedDgram, sizeof (struct ip));
95193045Sthompsa
96184610Salfred	ip->ip_v	= 4;
97192984Sthompsa	ip->ip_hl	= 5;
98192984Sthompsa	ip->ip_len	= htons (sizeof (struct ip) + icmpLen);
99192984Sthompsa	ip->ip_p	= IPPROTO_ICMP;
100192984Sthompsa	ip->ip_tos	= 0;
101192984Sthompsa
102192984Sthompsa	swap = ip->ip_dst;
103192984Sthompsa	ip->ip_dst = ip->ip_src;
104192984Sthompsa	ip->ip_src = swap;
105192984Sthompsa
106194228Sthompsa	PacketAliasIn ((char*) ip, IP_MAXPACKET);
107192984Sthompsa
108192984Sthompsa	addr.sin_family		= AF_INET;
109192984Sthompsa	addr.sin_addr		= ip->ip_dst;
110192984Sthompsa	addr.sin_port		= 0;
111213432Shselasky/*
112184610Salfred * Put packet into processing queue.
113184610Salfred */
114184610Salfred	wrote = sendto (sock,
115194228Sthompsa		        icmp,
116184610Salfred	    		icmpLen,
117184610Salfred	    		0,
118184610Salfred	    		(struct sockaddr*) &addr,
119185087Salfred	    		sizeof addr);
120184610Salfred
121184610Salfred	if (wrote != icmpLen)
122184610Salfred		Warn ("Cannot send ICMP message.");
123184610Salfred
124184610Salfred	return 1;
125184610Salfred}
126194677Sthompsa
127184610Salfred
128184610Salfred