icmp.c revision 50476
1184610Salfred/* 2184610Salfred * natd - Network Address Translation Daemon for FreeBSD. 3184610Salfred * 4184610Salfred * This software is provided free of charge, with no 5184610Salfred * warranty of any kind, either expressed or implied. 6184610Salfred * Use at your own risk. 7184610Salfred * 8184610Salfred * You may copy, modify and distribute this software (icmp.c) freely. 9184610Salfred * 10184610Salfred * Ari Suutari <suutari@iki.fi> 11184610Salfred * 12184610Salfred * $FreeBSD: head/sbin/natd/icmp.c 50476 1999-08-28 00:22:10Z peter $ 13184610Salfred */ 14184610Salfred 15184610Salfred#include <stdlib.h> 16184610Salfred#include <stdio.h> 17184610Salfred#include <unistd.h> 18184610Salfred#include <string.h> 19184610Salfred#include <ctype.h> 20184610Salfred 21184610Salfred#include <sys/types.h> 22184610Salfred#include <sys/socket.h> 23184610Salfred#include <sys/time.h> 24184610Salfred#include <errno.h> 25184610Salfred#include <signal.h> 26184610Salfred 27194677Sthompsa#include <netdb.h> 28194677Sthompsa 29194677Sthompsa#include <netinet/in.h> 30194677Sthompsa#include <netinet/in_systm.h> 31194677Sthompsa#include <netinet/ip.h> 32194677Sthompsa#include <netinet/ip_icmp.h> 33194677Sthompsa#include <machine/in_cksum.h> 34194677Sthompsa 35194677Sthompsa#include <alias.h> 36194677Sthompsa 37194677Sthompsa#include "natd.h" 38194677Sthompsa 39194677Sthompsaint SendNeedFragIcmp (int sock, struct ip* failedDgram, int mtu) 40194677Sthompsa{ 41194677Sthompsa char icmpBuf[IP_MAXPACKET]; 42194677Sthompsa struct ip* ip; 43194677Sthompsa struct icmp* icmp; 44194677Sthompsa int icmpLen; 45194677Sthompsa int failBytes; 46194677Sthompsa int failHdrLen; 47194677Sthompsa struct sockaddr_in addr; 48188942Sthompsa int wrote; 49188942Sthompsa struct in_addr swap; 50194677Sthompsa/* 51194677Sthompsa * Don't send error if packet is 52184610Salfred * not the first fragment. 53184610Salfred */ 54184610Salfred if (ntohs (failedDgram->ip_off) & ~(IP_MF | IP_DF)) 55188942Sthompsa return 0; 56194677Sthompsa/* 57188942Sthompsa * Dont respond if failed datagram is ICMP. 58188942Sthompsa */ 59188942Sthompsa if (failedDgram->ip_p == IPPROTO_ICMP) 60188942Sthompsa return 0; 61188942Sthompsa/* 62188942Sthompsa * Start building the message. 63188942Sthompsa */ 64188942Sthompsa ip = (struct ip*) icmpBuf; 65188942Sthompsa icmp = (struct icmp*) (icmpBuf + sizeof (struct ip)); 66188942Sthompsa/* 67184610Salfred * Complete ICMP part. 68188942Sthompsa */ 69188942Sthompsa icmp->icmp_type = ICMP_UNREACH; 70184610Salfred icmp->icmp_code = ICMP_UNREACH_NEEDFRAG; 71190191Sthompsa icmp->icmp_cksum = 0; 72190191Sthompsa icmp->icmp_void = 0; 73184610Salfred icmp->icmp_nextmtu = htons (mtu); 74184610Salfred/* 75184610Salfred * Copy header + 64 bits of original datagram. 76184610Salfred */ 77184610Salfred failHdrLen = (failedDgram->ip_hl << 2); 78184610Salfred failBytes = failedDgram->ip_len - failHdrLen; 79184610Salfred if (failBytes > 8) 80184610Salfred failBytes = 8; 81193045Sthompsa 82193045Sthompsa failBytes += failHdrLen; 83207080Sthompsa icmpLen = ICMP_MINLEN + failBytes; 84207080Sthompsa 85193045Sthompsa memcpy (&icmp->icmp_ip, failedDgram, failBytes); 86193045Sthompsa/* 87207080Sthompsa * Calculate checksum. 88184610Salfred */ 89193045Sthompsa icmp->icmp_cksum = PacketAliasInternetChecksum ((u_short*) icmp, 90193045Sthompsa icmpLen); 91193045Sthompsa/* 92193045Sthompsa * Add IP header using old IP header as template. 93193045Sthompsa */ 94193045Sthompsa memcpy (ip, failedDgram, sizeof (struct ip)); 95193045Sthompsa 96184610Salfred ip->ip_v = 4; 97192984Sthompsa ip->ip_hl = 5; 98192984Sthompsa ip->ip_len = htons (sizeof (struct ip) + icmpLen); 99192984Sthompsa ip->ip_p = IPPROTO_ICMP; 100192984Sthompsa ip->ip_tos = 0; 101192984Sthompsa 102192984Sthompsa swap = ip->ip_dst; 103192984Sthompsa ip->ip_dst = ip->ip_src; 104192984Sthompsa ip->ip_src = swap; 105192984Sthompsa 106194228Sthompsa PacketAliasIn ((char*) ip, IP_MAXPACKET); 107192984Sthompsa 108192984Sthompsa addr.sin_family = AF_INET; 109192984Sthompsa addr.sin_addr = ip->ip_dst; 110192984Sthompsa addr.sin_port = 0; 111213432Shselasky/* 112184610Salfred * Put packet into processing queue. 113184610Salfred */ 114184610Salfred wrote = sendto (sock, 115194228Sthompsa icmp, 116184610Salfred icmpLen, 117184610Salfred 0, 118184610Salfred (struct sockaddr*) &addr, 119185087Salfred sizeof addr); 120184610Salfred 121184610Salfred if (wrote != icmpLen) 122184610Salfred Warn ("Cannot send ICMP message."); 123184610Salfred 124184610Salfred return 1; 125184610Salfred} 126194677Sthompsa 127184610Salfred 128184610Salfred