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