|
|
1.1 ! root 1: /* Internet Control Message Protocol (ICMP) icmp.c */ ! 2: ! 3: /* ! 4: Copyright (C) 1992 Bob Harris ! 5: ! 6: This program is free software; you can redistribute it and/or modify ! 7: it under the terms of the GNU General Public License as published by ! 8: the Free Software Foundation; either version 2, or (at your option) ! 9: any later version. ! 10: ! 11: This program is distributed in the hope that it will be useful, ! 12: but WITHOUT ANY WARRANTY; without even the implied warranty of ! 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 14: GNU General Public License for more details. ! 15: ! 16: You should have received a copy of the GNU General Public License ! 17: along with this program; if not, write to the Free Software ! 18: Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ! 19: ! 20: The Author of tcpip package may be reached as [email protected] or ! 21: C/O Department of Mathematics; Stanford University; Stanford, CA 94305 ! 22: ! 23: The author of this file may be reached at [email protected] or Sparta, Inc. ! 24: 7926 Jones Branch Dr. Suite 900, McLean Va 22102. ! 25: */ ! 26: ! 27: /* modified by Ross Biro [email protected] to do more than just ! 28: echo responses. */ ! 29: ! 30: #include <linux/types.h> ! 31: #include <linux/sched.h> ! 32: #include <linux/kernel.h> /* free_s */ ! 33: #include <linux/fcntl.h> ! 34: #include <linux/socket.h> ! 35: #include <netinet/in.h> ! 36: #include "timer.h" ! 37: #include "ip.h" ! 38: #include "tcp.h" ! 39: #include "sock.h" ! 40: #include <linux/errno.h> ! 41: #include <linux/timer.h> ! 42: #include <asm/system.h> ! 43: #include <asm/segment.h> ! 44: #include "../kern_sock.h" /* for PRINTK */ ! 45: #include "icmp.h" ! 46: ! 47: #define min(a,b) ((a)<(b)?(a):(b)) ! 48: ! 49: /* an array of errno for error messages from dest unreach. */ ! 50: struct icmp_err icmp_err_convert[]= ! 51: { ! 52: {ENETUNREACH, 1}, ! 53: {EHOSTUNREACH, 1}, ! 54: {ENOPROTOOPT, 1}, ! 55: {ECONNREFUSED, 1}, ! 56: {EOPNOTSUPP, 0}, ! 57: {EOPNOTSUPP, 0}, ! 58: {ENETUNREACH, 1}, ! 59: {EHOSTDOWN, 1}, ! 60: {ENONET, 1}, ! 61: {ENETUNREACH, 1}, ! 62: {EHOSTUNREACH, 1}, ! 63: {EOPNOTSUPP, 0}, ! 64: {EOPNOTSUPP, 0} ! 65: }; ! 66: ! 67: void ! 68: print_icmph (struct icmp_header *icmph) ! 69: { ! 70: PRINTK (" type = %d, code = %d, checksum = %X\n", icmph->type, ! 71: icmph->code, icmph->checksum); ! 72: PRINTK (" gateway = %X\n", icmph->un.gateway); ! 73: } ! 74: ! 75: /* sends an icmp message in response to a packet. */ ! 76: void ! 77: icmp_reply (struct sk_buff *skb_in, int type, int code, struct device *dev) ! 78: { ! 79: struct sk_buff *skb; ! 80: struct ip_header *iph; ! 81: int offset; ! 82: struct icmp_header *icmph; ! 83: ! 84: int len; ! 85: /* get some memory for the replay. */ ! 86: len = sizeof (*skb) + 8 /* amount of header to return. */ + ! 87: sizeof (struct icmp_header) + ! 88: 64 /* enough for an ip header. */ + ! 89: dev->hard_header_len; ! 90: ! 91: skb = malloc (len); ! 92: if (skb == NULL) return; ! 93: ! 94: skb->mem_addr = skb; ! 95: skb->mem_len = len; ! 96: ! 97: len -= sizeof (*skb); ! 98: ! 99: /* find the ip header. */ ! 100: iph = (struct ip_header *)(skb_in+1); ! 101: iph = (struct ip_header *)((unsigned char *)iph + dev->hard_header_len); ! 102: ! 103: /* Build Layer 2-3 headers for message back to source */ ! 104: offset = ip_build_header( skb, iph->daddr, iph->saddr, ! 105: &dev, IP_ICMP, NULL, len ); ! 106: ! 107: if (offset < 0) ! 108: { ! 109: skb->sk = NULL; ! 110: free_skb (skb, FREE_READ); ! 111: return; ! 112: } ! 113: ! 114: /* Readjust length according to actual IP header size */ ! 115: skb->len = offset + sizeof (struct icmp_header) + 8; ! 116: ! 117: icmph = (struct icmp_header *)((unsigned char *)(skb+1) + offset); ! 118: icmph->type = type; ! 119: icmph->code = code; ! 120: icmph->checksum = 0; /* we don't need to compute this. */ ! 121: icmph->un.gateway = 0; /* might as well 0 it. */ ! 122: memcpy (icmph+1, iph+1, 8); ! 123: /* send it and free it. */ ! 124: ip_queue_xmit (NULL, dev, skb, 1); ! 125: ! 126: } ! 127: ! 128: /* deals with incoming icmp packets. */ ! 129: ! 130: int ! 131: icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt, ! 132: unsigned long daddr, unsigned short len, ! 133: unsigned long saddr, int redo, struct ip_protocol *protocol ) ! 134: { ! 135: int size, offset; ! 136: struct icmp_header *icmph, *icmphr; ! 137: struct sk_buff *skb; ! 138: unsigned char *buff; ! 139: ! 140: ! 141: /* drop broadcast packets. */ ! 142: if ((daddr & 0xff000000) == 0 || (daddr & 0xff000000) == 0xff000000) ! 143: { ! 144: skb1->sk = NULL; ! 145: free_skb (skb1, FREE_READ); ! 146: return (0); ! 147: } ! 148: ! 149: buff = skb1->h.raw; ! 150: ! 151: icmph = (struct icmp_header *)buff; ! 152: ! 153: /* Validate the packet first */ ! 154: if( icmph->checksum ) ! 155: { /* Checksums Enabled? */ ! 156: if( ip_compute_csum( (unsigned char *)icmph, len ) ) ! 157: { ! 158: /* Failed checksum! */ ! 159: PRINTK("\nICMP ECHO failed checksum!"); ! 160: skb1->sk = NULL; ! 161: free_skb (skb1, FREE_READ); ! 162: return (0); ! 163: } ! 164: } ! 165: ! 166: print_icmph(icmph); ! 167: ! 168: /* Parse the ICMP message */ ! 169: switch( icmph->type ) ! 170: { ! 171: case ICMP_DEST_UNREACH: ! 172: case ICMP_SOURCE_QUENCH: ! 173: { ! 174: struct ip_header *iph; ! 175: struct ip_protocol *ipprot; ! 176: unsigned char hash; ! 177: int err; ! 178: ! 179: err = icmph->type << 8 | icmph->code; ! 180: ! 181: /* we need to cause the socket to be closed and the error message ! 182: to be set appropriately. */ ! 183: iph = (struct ip_header *)(icmph+1); ! 184: ! 185: /* get the protocol(s) */ ! 186: hash = iph->protocol & (MAX_IP_PROTOS -1 ); ! 187: for (ipprot = ip_protos[hash]; ipprot != NULL; ipprot=ipprot->next) ! 188: { ! 189: /* pass it off to everyone who wants it. */ ! 190: ipprot->err_handler (err, (unsigned char *)iph+4*iph->ihl, ! 191: iph->daddr, iph->saddr, ipprot); ! 192: } ! 193: skb1->sk = NULL; ! 194: free_skb (skb1, FREE_READ); ! 195: return (0); ! 196: } ! 197: ! 198: case ICMP_REDIRECT: ! 199: { ! 200: /* we need to put a new route in the routing table. */ ! 201: struct rtable *rt; /* we will add a new route. */ ! 202: struct ip_header *iph; ! 203: ! 204: iph = (struct ip_header *)(icmph+1); ! 205: rt = malloc (sizeof (*rt)); ! 206: if (rt != NULL) ! 207: { ! 208: rt->net = iph->daddr; ! 209: /* assume class C network. Technically this is incorrect, ! 210: but will give it a try. */ ! 211: if ((icmph->code & 1) == 0) rt->net &= 0x00ffffff; ! 212: rt->dev = dev; ! 213: rt->router = icmph->un.gateway; ! 214: add_route (rt); ! 215: } ! 216: skb1->sk = NULL; ! 217: free_skb (skb1, FREE_READ); ! 218: return (0); ! 219: } ! 220: ! 221: case ICMP_ECHO: ! 222: ! 223: /* Allocate an sk_buff response buffer (assume 64 byte IP header) */ ! 224: ! 225: size = sizeof( struct sk_buff ) + dev->hard_header_len + 64 + len; ! 226: skb = malloc( size ); ! 227: if (skb == NULL) ! 228: { ! 229: skb1->sk = NULL; ! 230: free_skb (skb1, FREE_READ); ! 231: return (0); ! 232: } ! 233: skb->sk = NULL; ! 234: skb->mem_addr = skb; ! 235: skb->mem_len = size; ! 236: ! 237: /* Build Layer 2-3 headers for message back to source */ ! 238: offset = ip_build_header( skb, daddr, saddr, &dev, IP_ICMP, opt, len ); ! 239: if (offset < 0) ! 240: { ! 241: /* Problems building header */ ! 242: PRINTK("\nCould not build IP Header for ICMP ECHO Response"); ! 243: free_s (skb->mem_addr, skb->mem_len); ! 244: skb1->sk = NULL; ! 245: free_skb (skb1, FREE_READ); ! 246: return( 0 ); /* just toss the received packet */ ! 247: } ! 248: ! 249: /* Readjust length according to actual IP header size */ ! 250: skb->len = offset + len; ! 251: ! 252: /* Build ICMP_ECHO Response message */ ! 253: icmphr = (struct icmp_header *)( (char *)( skb + 1 ) + offset ); ! 254: memcpy( (char *)icmphr, (char *)icmph, len ); ! 255: icmphr->type = ICMP_ECHOREPLY; ! 256: icmphr->code = 0; ! 257: icmphr->checksum = 0; ! 258: ! 259: if( icmph->checksum ) ! 260: { /* Calculate Checksum */ ! 261: icmphr->checksum = ip_compute_csum( (void *)icmphr, len ); ! 262: } ! 263: ! 264: /* Ship it out - free it when done */ ! 265: ip_queue_xmit( (volatile struct sock *)NULL, dev, skb, 1 ); ! 266: ! 267: skb1->sk = NULL; ! 268: free_skb (skb1, FREE_READ); ! 269: return( 0 ); ! 270: ! 271: default: ! 272: PRINTK("\nUnsupported ICMP type = x%x", icmph->type ); ! 273: skb1->sk = NULL; ! 274: free_skb (skb1, FREE_READ); ! 275: return( 0 ); /* just toss the packet */ ! 276: } ! 277: ! 278: /* should be unecessary, but just in case. */ ! 279: skb1->sk = NULL; ! 280: free_skb (skb1, FREE_READ); ! 281: return( 0 ); /* just toss the packet */ ! 282: } ! 283:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.