1f13f9fadSAlexander Langer /* 2f13f9fadSAlexander Langer * $Id$ 3f13f9fadSAlexander Langer */ 4f13f9fadSAlexander Langer 524084f9bSBrian Somers #include <stdlib.h> 624084f9bSBrian Somers #include <stdio.h> 724084f9bSBrian Somers #include <unistd.h> 824084f9bSBrian Somers #include <string.h> 924084f9bSBrian Somers #include <ctype.h> 1024084f9bSBrian Somers 1124084f9bSBrian Somers #include <sys/types.h> 1224084f9bSBrian Somers #include <sys/socket.h> 1324084f9bSBrian Somers #include <sys/time.h> 1424084f9bSBrian Somers #include <errno.h> 1524084f9bSBrian Somers #include <signal.h> 1624084f9bSBrian Somers 1724084f9bSBrian Somers #include <netdb.h> 1824084f9bSBrian Somers 1924084f9bSBrian Somers #include <netinet/in.h> 2024084f9bSBrian Somers #include <netinet/in_systm.h> 2124084f9bSBrian Somers #include <netinet/ip.h> 2224084f9bSBrian Somers #include <netinet/ip_icmp.h> 2324084f9bSBrian Somers #include <machine/in_cksum.h> 2424084f9bSBrian Somers 2524084f9bSBrian Somers #include <alias.h> 2624084f9bSBrian Somers 2724084f9bSBrian Somers #include "natd.h" 2824084f9bSBrian Somers 2924084f9bSBrian Somers int SendNeedFragIcmp (int sock, struct ip* failedDgram, int mtu) 3024084f9bSBrian Somers { 3124084f9bSBrian Somers char icmpBuf[IP_MAXPACKET]; 3224084f9bSBrian Somers struct ip* ip; 3324084f9bSBrian Somers struct icmp* icmp; 3424084f9bSBrian Somers int icmpLen; 3524084f9bSBrian Somers int failBytes; 3624084f9bSBrian Somers int failHdrLen; 3724084f9bSBrian Somers struct sockaddr_in addr; 3824084f9bSBrian Somers int wrote; 3924084f9bSBrian Somers struct in_addr swap; 4024084f9bSBrian Somers /* 4124084f9bSBrian Somers * Don't send error if packet is 4224084f9bSBrian Somers * not the first fragment. 4324084f9bSBrian Somers */ 4424084f9bSBrian Somers if (ntohs (failedDgram->ip_off) & ~(IP_MF | IP_DF)) 4524084f9bSBrian Somers return 0; 4624084f9bSBrian Somers /* 4724084f9bSBrian Somers * Dont respond if failed datagram is ICMP. 4824084f9bSBrian Somers */ 4924084f9bSBrian Somers if (failedDgram->ip_p == IPPROTO_ICMP) 5024084f9bSBrian Somers return 0; 5124084f9bSBrian Somers /* 5224084f9bSBrian Somers * Start building the message. 5324084f9bSBrian Somers */ 5424084f9bSBrian Somers ip = (struct ip*) icmpBuf; 5524084f9bSBrian Somers icmp = (struct icmp*) (icmpBuf + sizeof (struct ip)); 5624084f9bSBrian Somers /* 5724084f9bSBrian Somers * Complete ICMP part. 5824084f9bSBrian Somers */ 5924084f9bSBrian Somers icmp->icmp_type = ICMP_UNREACH; 6024084f9bSBrian Somers icmp->icmp_code = ICMP_UNREACH_NEEDFRAG; 6124084f9bSBrian Somers icmp->icmp_cksum = 0; 6224084f9bSBrian Somers icmp->icmp_void = 0; 6324084f9bSBrian Somers icmp->icmp_nextmtu = htons (mtu); 6424084f9bSBrian Somers /* 6524084f9bSBrian Somers * Copy header + 64 bits of original datagram. 6624084f9bSBrian Somers */ 6724084f9bSBrian Somers failHdrLen = (failedDgram->ip_hl << 2); 6824084f9bSBrian Somers failBytes = failedDgram->ip_len - failHdrLen; 6924084f9bSBrian Somers if (failBytes > 8) 7024084f9bSBrian Somers failBytes = 8; 7124084f9bSBrian Somers 7224084f9bSBrian Somers failBytes += failHdrLen; 7324084f9bSBrian Somers icmpLen = ICMP_MINLEN + failBytes; 7424084f9bSBrian Somers 7524084f9bSBrian Somers memcpy (&icmp->icmp_ip, failedDgram, failBytes); 7624084f9bSBrian Somers /* 7724084f9bSBrian Somers * Calculate checksum. 7824084f9bSBrian Somers */ 79fb994b07SBrian Somers icmp->icmp_cksum = PacketAliasInternetChecksum ((u_short*) icmp, 80fb994b07SBrian Somers icmpLen); 8124084f9bSBrian Somers /* 8224084f9bSBrian Somers * Add IP header using old IP header as template. 8324084f9bSBrian Somers */ 8424084f9bSBrian Somers memcpy (ip, failedDgram, sizeof (struct ip)); 8524084f9bSBrian Somers 8624084f9bSBrian Somers ip->ip_v = 4; 8724084f9bSBrian Somers ip->ip_hl = 5; 8824084f9bSBrian Somers ip->ip_len = htons (sizeof (struct ip) + icmpLen); 8924084f9bSBrian Somers ip->ip_p = IPPROTO_ICMP; 9024084f9bSBrian Somers ip->ip_tos = 0; 9124084f9bSBrian Somers 9224084f9bSBrian Somers swap = ip->ip_dst; 9324084f9bSBrian Somers ip->ip_dst = ip->ip_src; 9424084f9bSBrian Somers ip->ip_src = swap; 9524084f9bSBrian Somers 9624084f9bSBrian Somers PacketAliasIn ((char*) ip, IP_MAXPACKET); 9724084f9bSBrian Somers 9824084f9bSBrian Somers addr.sin_family = AF_INET; 9924084f9bSBrian Somers addr.sin_addr = ip->ip_dst; 10024084f9bSBrian Somers addr.sin_port = 0; 10124084f9bSBrian Somers /* 10224084f9bSBrian Somers * Put packet into processing queue. 10324084f9bSBrian Somers */ 10424084f9bSBrian Somers wrote = sendto (sock, 10524084f9bSBrian Somers icmp, 10624084f9bSBrian Somers icmpLen, 10724084f9bSBrian Somers 0, 10824084f9bSBrian Somers (struct sockaddr*) &addr, 10924084f9bSBrian Somers sizeof addr); 11024084f9bSBrian Somers 11124084f9bSBrian Somers if (wrote != icmpLen) 11224084f9bSBrian Somers Warn ("Cannot send ICMP message."); 11324084f9bSBrian Somers 11424084f9bSBrian Somers return 1; 11524084f9bSBrian Somers } 11624084f9bSBrian Somers 11724084f9bSBrian Somers 118