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