132026Salex/* 244558Sbrian * natd - Network Address Translation Daemon for FreeBSD. 344558Sbrian * 432107Salex * This software is provided free of charge, with no 532107Salex * warranty of any kind, either expressed or implied. 632107Salex * Use at your own risk. 732107Salex * 844558Sbrian * You may copy, modify and distribute this software (icmp.c) freely. 932107Salex * 1032107Salex * Ari Suutari <suutari@iki.fi> 1132107Salex * 1250476Speter * $FreeBSD$ 1332026Salex */ 1432026Salex 1526781Sbrian#include <stdlib.h> 1626781Sbrian#include <stdio.h> 1726781Sbrian#include <unistd.h> 1826781Sbrian#include <string.h> 1926781Sbrian#include <ctype.h> 2026781Sbrian 2126781Sbrian#include <sys/types.h> 2226781Sbrian#include <sys/socket.h> 2326781Sbrian#include <sys/time.h> 2426781Sbrian#include <errno.h> 2526781Sbrian#include <signal.h> 2626781Sbrian 2726781Sbrian#include <netdb.h> 2826781Sbrian 2926781Sbrian#include <netinet/in.h> 3026781Sbrian#include <netinet/in_systm.h> 3126781Sbrian#include <netinet/ip.h> 3226781Sbrian#include <netinet/ip_icmp.h> 3326781Sbrian#include <machine/in_cksum.h> 3426781Sbrian 3526781Sbrian#include <alias.h> 3626781Sbrian 3726781Sbrian#include "natd.h" 3826781Sbrian 3926781Sbrianint SendNeedFragIcmp (int sock, struct ip* failedDgram, int mtu) 4026781Sbrian{ 4126781Sbrian char icmpBuf[IP_MAXPACKET]; 4226781Sbrian struct ip* ip; 4326781Sbrian struct icmp* icmp; 4426781Sbrian int icmpLen; 4526781Sbrian int failBytes; 4626781Sbrian int failHdrLen; 4726781Sbrian struct sockaddr_in addr; 4826781Sbrian int wrote; 4926781Sbrian struct in_addr swap; 5026781Sbrian/* 5126781Sbrian * Don't send error if packet is 5226781Sbrian * not the first fragment. 5326781Sbrian */ 5426781Sbrian if (ntohs (failedDgram->ip_off) & ~(IP_MF | IP_DF)) 5526781Sbrian return 0; 5626781Sbrian/* 5726781Sbrian * Dont respond if failed datagram is ICMP. 5826781Sbrian */ 5926781Sbrian if (failedDgram->ip_p == IPPROTO_ICMP) 6026781Sbrian return 0; 6126781Sbrian/* 6226781Sbrian * Start building the message. 6326781Sbrian */ 6426781Sbrian ip = (struct ip*) icmpBuf; 6526781Sbrian icmp = (struct icmp*) (icmpBuf + sizeof (struct ip)); 6626781Sbrian/* 6726781Sbrian * Complete ICMP part. 6826781Sbrian */ 6926781Sbrian icmp->icmp_type = ICMP_UNREACH; 7026781Sbrian icmp->icmp_code = ICMP_UNREACH_NEEDFRAG; 7126781Sbrian icmp->icmp_cksum = 0; 7226781Sbrian icmp->icmp_void = 0; 7326781Sbrian icmp->icmp_nextmtu = htons (mtu); 7426781Sbrian/* 7526781Sbrian * Copy header + 64 bits of original datagram. 7626781Sbrian */ 7726781Sbrian failHdrLen = (failedDgram->ip_hl << 2); 7826781Sbrian failBytes = failedDgram->ip_len - failHdrLen; 7926781Sbrian if (failBytes > 8) 8026781Sbrian failBytes = 8; 8126781Sbrian 8226781Sbrian failBytes += failHdrLen; 8326781Sbrian icmpLen = ICMP_MINLEN + failBytes; 8426781Sbrian 8526781Sbrian memcpy (&icmp->icmp_ip, failedDgram, failBytes); 8626781Sbrian/* 8726781Sbrian * Calculate checksum. 8826781Sbrian */ 89131567Sphk icmp->icmp_cksum = LibAliasInternetChecksum (mla, (u_short*) icmp, 9028045Sbrian icmpLen); 9126781Sbrian/* 9226781Sbrian * Add IP header using old IP header as template. 9326781Sbrian */ 9426781Sbrian memcpy (ip, failedDgram, sizeof (struct ip)); 9526781Sbrian 9626781Sbrian ip->ip_v = 4; 9726781Sbrian ip->ip_hl = 5; 9826781Sbrian ip->ip_len = htons (sizeof (struct ip) + icmpLen); 9926781Sbrian ip->ip_p = IPPROTO_ICMP; 10026781Sbrian ip->ip_tos = 0; 10126781Sbrian 10226781Sbrian swap = ip->ip_dst; 10326781Sbrian ip->ip_dst = ip->ip_src; 10426781Sbrian ip->ip_src = swap; 10526781Sbrian 106131567Sphk LibAliasIn (mla, (char*) ip, IP_MAXPACKET); 10726781Sbrian 10826781Sbrian addr.sin_family = AF_INET; 10926781Sbrian addr.sin_addr = ip->ip_dst; 11026781Sbrian addr.sin_port = 0; 11126781Sbrian/* 11226781Sbrian * Put packet into processing queue. 11326781Sbrian */ 11426781Sbrian wrote = sendto (sock, 11526781Sbrian icmp, 11626781Sbrian icmpLen, 11726781Sbrian 0, 11826781Sbrian (struct sockaddr*) &addr, 11926781Sbrian sizeof addr); 12026781Sbrian 12126781Sbrian if (wrote != icmpLen) 12226781Sbrian Warn ("Cannot send ICMP message."); 12326781Sbrian 12426781Sbrian return 1; 12526781Sbrian} 12626781Sbrian 12726781Sbrian 128