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