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