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