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 36 int 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