1/*
2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License").  You may not use this file except in compliance with the
9 * License.  Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/*
23 * natd - Network Address Translation Daemon for FreeBSD.
24 *
25 * This software is provided free of charge, with no
26 * warranty of any kind, either expressed or implied.
27 * Use at your own risk.
28 *
29 * You may copy, modify and distribute this software (icmp.c) freely.
30 *
31 * Ari Suutari <suutari@iki.fi>
32 *
33 * Based upon:
34 * $FreeBSD: src/sbin/natd/icmp.c,v 1.6 1999/08/28 00:13:45 peter Exp $
35 */
36
37#include <stdlib.h>
38#include <stdio.h>
39#include <unistd.h>
40#include <string.h>
41#include <ctype.h>
42
43#include <sys/types.h>
44#include <sys/socket.h>
45#include <sys/time.h>
46#include <errno.h>
47#include <signal.h>
48
49#include <netdb.h>
50
51#include <netinet/in.h>
52#include <netinet/in_systm.h>
53#include <netinet/ip.h>
54#include <netinet/ip_icmp.h>
55
56#include <alias.h>
57
58#include "natd.h"
59
60int SendNeedFragIcmp (int sock, struct ip* failedDgram, int mtu)
61{
62	char			icmpBuf[IP_MAXPACKET];
63	struct ip*		ip;
64	struct icmp*		icmp;
65	int			icmpLen;
66	int			failBytes;
67	int			failHdrLen;
68	struct sockaddr_in	addr;
69	int			wrote;
70	struct in_addr		swap;
71/*
72 * Don't send error if packet is
73 * not the first fragment.
74 */
75	if (ntohs (failedDgram->ip_off) & ~(IP_MF | IP_DF))
76		return 0;
77/*
78 * Dont respond if failed datagram is ICMP.
79 */
80	if (failedDgram->ip_p == IPPROTO_ICMP)
81		return 0;
82/*
83 * Start building the message.
84 */
85	ip   = (struct ip*) icmpBuf;
86	icmp = (struct icmp*) (icmpBuf + sizeof (struct ip));
87/*
88 * Complete ICMP part.
89 */
90	icmp->icmp_type  	= ICMP_UNREACH;
91	icmp->icmp_code		= ICMP_UNREACH_NEEDFRAG;
92	icmp->icmp_cksum	= 0;
93	icmp->icmp_void		= 0;
94	icmp->icmp_nextmtu	= htons (mtu);
95/*
96 * Copy header + 64 bits of original datagram.
97 */
98	failHdrLen = (failedDgram->ip_hl << 2);
99	failBytes  = failedDgram->ip_len - failHdrLen;
100	if (failBytes > 8)
101		failBytes = 8;
102
103	failBytes += failHdrLen;
104	icmpLen    = ICMP_MINLEN + failBytes;
105
106	memcpy (&icmp->icmp_ip, failedDgram, failBytes);
107/*
108 * Calculate checksum.
109 */
110	icmp->icmp_cksum = PacketAliasInternetChecksum ((u_short*) icmp,
111							icmpLen);
112/*
113 * Add IP header using old IP header as template.
114 */
115	memcpy (ip, failedDgram, sizeof (struct ip));
116
117	ip->ip_v	= 4;
118	ip->ip_hl	= 5;
119	ip->ip_len	= htons (sizeof (struct ip) + icmpLen);
120	ip->ip_p	= IPPROTO_ICMP;
121	ip->ip_tos	= 0;
122
123	swap = ip->ip_dst;
124	ip->ip_dst = ip->ip_src;
125	ip->ip_src = swap;
126
127	PacketAliasIn ((char*) ip, IP_MAXPACKET);
128
129	addr.sin_family		= AF_INET;
130	addr.sin_addr		= ip->ip_dst;
131	addr.sin_port		= 0;
132/*
133 * Put packet into processing queue.
134 */
135	wrote = sendto (sock,
136		        icmp,
137	    		icmpLen,
138	    		0,
139	    		(struct sockaddr*) &addr,
140	    		sizeof addr);
141
142	if (wrote != icmpLen)
143		Warn ("Cannot send ICMP message.");
144
145	return 1;
146}
147
148
149