1/*
2 * natd - Network Address Translation Daemon for FreeBSD.
3 *
4 * This software is provided free of charge, with no
5 * warranty of any kind, either expressed or implied.
6 * Use at your own risk.
7 *
8 * You may copy, modify and distribute this software (icmp.c) freely.
9 *
10 * Ari Suutari <suutari@iki.fi>
11 *
12 * $FreeBSD$
13 */
14
15#include <stdlib.h>
16#include <stdio.h>
17#include <unistd.h>
18#include <string.h>
19#include <ctype.h>
20
21#include <sys/types.h>
22#include <sys/socket.h>
23#include <sys/time.h>
24#include <errno.h>
25#include <signal.h>
26
27#include <netdb.h>
28
29#include <netinet/in.h>
30#include <netinet/in_systm.h>
31#include <netinet/ip.h>
32#include <netinet/ip_icmp.h>
33#include <machine/in_cksum.h>
34
35#include <alias.h>
36
37#include "natd.h"
38
39int SendNeedFragIcmp (int sock, struct ip* failedDgram, int mtu)
40{
41	char			icmpBuf[IP_MAXPACKET];
42	struct ip*		ip;
43	struct icmp*		icmp;
44	int			icmpLen;
45	int			failBytes;
46	int			failHdrLen;
47	struct sockaddr_in	addr;
48	int			wrote;
49	struct in_addr		swap;
50/*
51 * Don't send error if packet is
52 * not the first fragment.
53 */
54	if (ntohs (failedDgram->ip_off) & ~(IP_MF | IP_DF))
55		return 0;
56/*
57 * Dont respond if failed datagram is ICMP.
58 */
59	if (failedDgram->ip_p == IPPROTO_ICMP)
60		return 0;
61/*
62 * Start building the message.
63 */
64	ip   = (struct ip*) icmpBuf;
65	icmp = (struct icmp*) (icmpBuf + sizeof (struct ip));
66/*
67 * Complete ICMP part.
68 */
69	icmp->icmp_type  	= ICMP_UNREACH;
70	icmp->icmp_code		= ICMP_UNREACH_NEEDFRAG;
71	icmp->icmp_cksum	= 0;
72	icmp->icmp_void		= 0;
73	icmp->icmp_nextmtu	= htons (mtu);
74/*
75 * Copy header + 64 bits of original datagram.
76 */
77	failHdrLen = (failedDgram->ip_hl << 2);
78	failBytes  = failedDgram->ip_len - failHdrLen;
79	if (failBytes > 8)
80		failBytes = 8;
81
82	failBytes += failHdrLen;
83	icmpLen    = ICMP_MINLEN + failBytes;
84
85	memcpy (&icmp->icmp_ip, failedDgram, failBytes);
86/*
87 * Calculate checksum.
88 */
89	icmp->icmp_cksum = LibAliasInternetChecksum (mla, (u_short*) icmp,
90							icmpLen);
91/*
92 * Add IP header using old IP header as template.
93 */
94	memcpy (ip, failedDgram, sizeof (struct ip));
95
96	ip->ip_v	= 4;
97	ip->ip_hl	= 5;
98	ip->ip_len	= htons (sizeof (struct ip) + icmpLen);
99	ip->ip_p	= IPPROTO_ICMP;
100	ip->ip_tos	= 0;
101
102	swap = ip->ip_dst;
103	ip->ip_dst = ip->ip_src;
104	ip->ip_src = swap;
105
106	LibAliasIn (mla, (char*) ip, IP_MAXPACKET);
107
108	addr.sin_family		= AF_INET;
109	addr.sin_addr		= ip->ip_dst;
110	addr.sin_port		= 0;
111/*
112 * Put packet into processing queue.
113 */
114	wrote = sendto (sock,
115		        icmp,
116	    		icmpLen,
117	    		0,
118	    		(struct sockaddr*) &addr,
119	    		sizeof addr);
120
121	if (wrote != icmpLen)
122		Warn ("Cannot send ICMP message.");
123
124	return 1;
125}
126
127
128