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