xref: /dflybsd-src/sbin/natd/icmp.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
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