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