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