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