1: /*
   2:  * Copyright (c) 1982, 1986 Regents of the University of California.
   3:  * All rights reserved.
   4:  *
   5:  * Redistribution and use in source and binary forms are permitted
   6:  * provided that this notice is preserved and that due credit is given
   7:  * to the University of California at Berkeley. The name of the University
   8:  * may not be used to endorse or promote products derived from this
   9:  * software without specific prior written permission. This software
  10:  * is provided ``as is'' without express or implied warranty.
  11:  *
  12:  *	@(#)ip_icmp.c	7.7.2 (2.11BSD GTE) 1995/10/10
  13:  */
  14: 
  15: #include "param.h"
  16: #include "systm.h"
  17: #include "mbuf.h"
  18: #include "protosw.h"
  19: #include "socket.h"
  20: #include "time.h"
  21: #include "kernel.h"
  22: #include "errno.h"
  23: 
  24: #include "../net/route.h"
  25: #include "../net/if.h"
  26: 
  27: #include "domain.h"
  28: #include "in.h"
  29: #include "in_systm.h"
  30: #include "in_var.h"
  31: #include "ip.h"
  32: #include "ip_icmp.h"
  33: #include "icmp_var.h"
  34: 
  35: extern  int icmpmaskrepl;
  36: #ifdef ICMPPRINTFS
  37: /*
  38:  * ICMP routines: error generation, receive packet processing, and
  39:  * routines to turnaround packets back to the originator, and
  40:  * host table maintenance routines.
  41:  */
  42: int icmpprintfs = 0;
  43: #endif
  44: 
  45: /*
  46:  * Generate an error packet of type error
  47:  * in response to bad packet ip.
  48:  */
  49: /*VARARGS4*/
  50: icmp_error(oip, type, code, ifp, dest)
  51:     struct ip *oip;
  52:     int type, code;
  53:     struct ifnet *ifp;
  54:     struct in_addr dest;
  55: {
  56:     register unsigned oiplen = oip->ip_hl << 2;
  57:     register struct icmp *icp;
  58:     struct mbuf *m;
  59:     struct ip *nip;
  60:     unsigned icmplen;
  61: 
  62: #ifdef ICMPPRINTFS
  63:     if (icmpprintfs)
  64:         printf("icmp_error(%x, %d, %d)\n", oip, type, code);
  65: #endif
  66:     if (type != ICMP_REDIRECT)
  67:         icmpstat.icps_error++;
  68:     /*
  69: 	 * Don't send error if not the first fragment of message.
  70: 	 * Don't error if the old packet protocol was ICMP
  71: 	 * error message, only known informational types.
  72: 	 */
  73:     if (oip->ip_off &~ (IP_MF|IP_DF))
  74:         goto free;
  75:     if (oip->ip_p == IPPROTO_ICMP && type != ICMP_REDIRECT &&
  76:       !ICMP_INFOTYPE(((struct icmp *)((caddr_t)oip + oiplen))->icmp_type)) {
  77:         icmpstat.icps_oldicmp++;
  78:         goto free;
  79:     }
  80: 
  81:     /*
  82: 	 * First, formulate icmp message
  83: 	 */
  84:     m = m_get(M_DONTWAIT, MT_HEADER);
  85:     if (m == NULL)
  86:         goto free;
  87:     icmplen = oiplen + MIN(8, oip->ip_len);
  88:     m->m_len = icmplen + ICMP_MINLEN;
  89:     m->m_off = MMAXOFF - m->m_len;
  90:     icp = mtod(m, struct icmp *);
  91:     if ((u_int)type > ICMP_MAXTYPE)
  92:         panic("icmp_error");
  93:     icmpstat.icps_outhist[type]++;
  94:     icp->icmp_type = type;
  95:     if (type == ICMP_REDIRECT)
  96:         icp->icmp_gwaddr = dest;
  97:     else
  98:         icp->icmp_void = 0;
  99:     if (type == ICMP_PARAMPROB) {
 100:         icp->icmp_pptr = code;
 101:         code = 0;
 102:     }
 103:     icp->icmp_code = code;
 104:     bcopy((caddr_t)oip, (caddr_t)&icp->icmp_ip, icmplen);
 105:     nip = &icp->icmp_ip;
 106:     nip->ip_len += oiplen;
 107:     nip->ip_len = htons((u_short)nip->ip_len);
 108: 
 109:     /*
 110: 	 * Now, copy old ip header in front of icmp message.
 111: 	 */
 112:     if (m->m_len + oiplen > MLEN)
 113:         oiplen = sizeof(struct ip);
 114:     if (m->m_len + oiplen > MLEN)
 115:         panic("icmp len");
 116:     m->m_off -= oiplen;
 117:     m->m_len += oiplen;
 118:     nip = mtod(m, struct ip *);
 119:     bcopy((caddr_t)oip, (caddr_t)nip, oiplen);
 120:     nip->ip_len = m->m_len;
 121:     nip->ip_p = IPPROTO_ICMP;
 122:     icmp_reflect(nip, ifp);
 123: 
 124: free:
 125:     m_freem(dtom(oip));
 126: }
 127: 
 128: static struct sockproto icmproto = { AF_INET, IPPROTO_ICMP };
 129: static struct sockaddr_in icmpsrc = { AF_INET };
 130: static struct sockaddr_in icmpdst = { AF_INET };
 131: static struct sockaddr_in icmpgw = { AF_INET };
 132: struct in_ifaddr *ifptoia();
 133: 
 134: /*
 135:  * Process a received ICMP message.
 136:  */
 137: icmp_input(m, ifp)
 138:     register struct mbuf *m;
 139:     struct ifnet *ifp;
 140: {
 141:     register struct icmp *icp;
 142:     register struct ip *ip = mtod(m, struct ip *);
 143:     int icmplen = ip->ip_len, hlen = ip->ip_hl << 2;
 144:     register int i;
 145:     struct in_ifaddr *ia;
 146:     int (*ctlfunc)(), code;
 147:     extern u_char ip_protox[];
 148:     extern struct in_addr in_makeaddr();
 149: 
 150:     /*
 151: 	 * Locate icmp structure in mbuf, and check
 152: 	 * that not corrupted and of at least minimum length.
 153: 	 */
 154: #ifdef ICMPPRINTFS
 155:     if (icmpprintfs)
 156:         printf("icmp_input src %X len %d", ntohl(ip->ip_src), icmplen);
 157: #endif
 158:     if (icmplen < ICMP_MINLEN) {
 159:         icmpstat.icps_tooshort++;
 160:         goto free;
 161:     }
 162:     i = hlen + MIN(icmplen, ICMP_ADVLENMIN);
 163:     if ((m->m_off > MMAXOFF || m->m_len < i) &&
 164:         (m = m_pullup(m, i)) == 0)  {
 165:         icmpstat.icps_tooshort++;
 166:         return;
 167:     }
 168:     ip = mtod(m, struct ip *);
 169:     m->m_len -= hlen;
 170:     m->m_off += hlen;
 171:     icp = mtod(m, struct icmp *);
 172:     if (in_cksum(m, icmplen)) {
 173:         icmpstat.icps_checksum++;
 174:         goto free;
 175:     }
 176:     m->m_len += hlen;
 177:     m->m_off -= hlen;
 178: 
 179: #ifdef ICMPPRINTFS
 180:     /*
 181: 	 * Message type specific processing.
 182: 	 */
 183:     if (icmpprintfs)
 184:         printf("icmp_input, type %d code %d\n", icp->icmp_type,
 185:             icp->icmp_code);
 186: #endif
 187:     if (icp->icmp_type > ICMP_MAXTYPE)
 188:         goto raw;
 189:     icmpstat.icps_inhist[icp->icmp_type]++;
 190:     code = icp->icmp_code;
 191:     switch (icp->icmp_type) {
 192: 
 193:     case ICMP_UNREACH:
 194:         if (code > 5)
 195:             goto badcode;
 196:         code += PRC_UNREACH_NET;
 197:         goto deliver;
 198: 
 199:     case ICMP_TIMXCEED:
 200:         if (code > 1)
 201:             goto badcode;
 202:         code += PRC_TIMXCEED_INTRANS;
 203:         goto deliver;
 204: 
 205:     case ICMP_PARAMPROB:
 206:         if (code)
 207:             goto badcode;
 208:         code = PRC_PARAMPROB;
 209:         goto deliver;
 210: 
 211:     case ICMP_SOURCEQUENCH:
 212:         if (code)
 213:             goto badcode;
 214:         code = PRC_QUENCH;
 215:     deliver:
 216:         /*
 217: 		 * Problem with datagram; advise higher level routines.
 218: 		 */
 219:         icp->icmp_ip.ip_len = ntohs((u_short)icp->icmp_ip.ip_len);
 220:         if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) {
 221:             icmpstat.icps_badlen++;
 222:             goto free;
 223:         }
 224: #ifdef ICMPPRINTFS
 225:         if (icmpprintfs)
 226:             printf("deliver to protocol %d\n", icp->icmp_ip.ip_p);
 227: #endif
 228:         icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
 229:         if (ctlfunc = inetsw[ip_protox[icp->icmp_ip.ip_p]].pr_ctlinput)
 230:             (*ctlfunc)(code, (struct sockaddr *)&icmpsrc,
 231:                 (caddr_t)&icp->icmp_ip);
 232:         break;
 233: 
 234:     badcode:
 235:         icmpstat.icps_badcode++;
 236:         break;
 237: 
 238:     case ICMP_ECHO:
 239:         icp->icmp_type = ICMP_ECHOREPLY;
 240:         goto reflect;
 241: 
 242:     case ICMP_TSTAMP:
 243:         if (icmplen < ICMP_TSLEN) {
 244:             icmpstat.icps_badlen++;
 245:             break;
 246:         }
 247:         icp->icmp_type = ICMP_TSTAMPREPLY;
 248:         icp->icmp_rtime = iptime();
 249:         icp->icmp_ttime = icp->icmp_rtime;  /* bogus, do later! */
 250:         goto reflect;
 251: 
 252:     case ICMP_IREQ:
 253: #define satosin(sa) ((struct sockaddr_in *)(sa))
 254:         if (in_netof(ip->ip_src) == 0 && (ia = ifptoia(ifp)))
 255:             ip->ip_src = in_makeaddr(in_netof(IA_SIN(ia)->sin_addr),
 256:                 in_lnaof(ip->ip_src));
 257:         icp->icmp_type = ICMP_IREQREPLY;
 258:         goto reflect;
 259: 
 260:     case ICMP_MASKREQ:
 261:         if (icmpmaskrepl == 0)
 262:             break;
 263:         /*
 264: 		 * We are not able to respond with all ones broadcast
 265: 		 * unless we receive it over a point-to-point interface.
 266: 		 * This check is a 'switch' in 4.4BSD but 2.11's C compiler
 267: 		 * does not allow "long"s in a switch statement.
 268: 		*/
 269:         if (icmplen < ICMP_MASKLEN || (ia = ifptoia(ifp)) == 0)
 270:             break;
 271:         if ((ip->ip_dst.s_addr == INADDR_BROADCAST ||
 272:              ip->ip_dst.s_addr == INADDR_ANY))
 273:             icmpdst.sin_addr = ip->ip_src;
 274:         else
 275:             icmpdst.sin_addr = ip->ip_dst;
 276:         icp->icmp_type = ICMP_MASKREPLY;
 277:         icp->icmp_mask = htonl(ia->ia_subnetmask);
 278:         if (ip->ip_src.s_addr == 0) {
 279:             if (ia->ia_ifp->if_flags & IFF_BROADCAST)
 280:                 ip->ip_src = satosin(&ia->ia_broadaddr)->sin_addr;
 281:             else if (ia->ia_ifp->if_flags & IFF_POINTOPOINT)
 282:                 ip->ip_src = satosin(&ia->ia_dstaddr)->sin_addr;
 283:         }
 284: reflect:
 285:         ip->ip_len += hlen; /* since ip_input deducts this */
 286:         icmpstat.icps_reflect++;
 287:         icmpstat.icps_outhist[icp->icmp_type]++;
 288:         icmp_reflect(ip, ifp);
 289:         return;
 290: 
 291:     case ICMP_REDIRECT:
 292:         if (icmplen < ICMP_ADVLENMIN || icmplen < ICMP_ADVLEN(icp)) {
 293:             icmpstat.icps_badlen++;
 294:             break;
 295:         }
 296:         /*
 297: 		 * Short circuit routing redirects to force
 298: 		 * immediate change in the kernel's routing
 299: 		 * tables.  The message is also handed to anyone
 300: 		 * listening on a raw socket (e.g. the routing
 301: 		 * daemon for use in updating its tables).
 302: 		 */
 303:         icmpgw.sin_addr = ip->ip_src;
 304:         icmpdst.sin_addr = icp->icmp_gwaddr;
 305: #ifdef  ICMPPRINTFS
 306:         if (icmpprintfs)
 307:             printf("redirect dst %X to %X\n", ntohl(icp->icmp_ip.ip_dst),
 308:                 ntohl(icp->icmp_gwaddr));
 309: #endif
 310:         if (code == ICMP_REDIRECT_NET || code == ICMP_REDIRECT_TOSNET) {
 311:             icmpsrc.sin_addr =
 312:              in_makeaddr(in_netof(icp->icmp_ip.ip_dst), INADDR_ANY);
 313:             rtredirect((struct sockaddr *)&icmpsrc,
 314:               (struct sockaddr *)&icmpdst, RTF_GATEWAY,
 315:               (struct sockaddr *)&icmpgw);
 316:             icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
 317:             pfctlinput(PRC_REDIRECT_NET,
 318:               (struct sockaddr *)&icmpsrc);
 319:         } else {
 320:             icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
 321:             rtredirect((struct sockaddr *)&icmpsrc,
 322:               (struct sockaddr *)&icmpdst, RTF_GATEWAY | RTF_HOST,
 323:               (struct sockaddr *)&icmpgw);
 324:             pfctlinput(PRC_REDIRECT_HOST,
 325:               (struct sockaddr *)&icmpsrc);
 326:         }
 327:         break;
 328: 
 329:     /*
 330: 	 * No kernel processing for the following;
 331: 	 * just fall through to send to raw listener.
 332: 	 */
 333:     case ICMP_ECHOREPLY:
 334:     case ICMP_TSTAMPREPLY:
 335:     case ICMP_IREQREPLY:
 336:     case ICMP_MASKREPLY:
 337:     default:
 338:         break;
 339:     }
 340: 
 341: raw:
 342:     icmpsrc.sin_addr = ip->ip_src;
 343:     icmpdst.sin_addr = ip->ip_dst;
 344:     raw_input(m, &icmproto, (struct sockaddr *)&icmpsrc,
 345:         (struct sockaddr *)&icmpdst);
 346:     return;
 347: 
 348: free:
 349:     m_freem(m);
 350: }
 351: 
 352: /*
 353:  * Reflect the ip packet back to the source
 354:  */
 355: icmp_reflect(ip, ifp)
 356:     register struct ip *ip;
 357:     struct ifnet *ifp;
 358: {
 359:     register struct in_ifaddr *ia;
 360:     struct in_addr t;
 361:     struct mbuf *opts = 0, *ip_srcroute();
 362:     int optlen = (ip->ip_hl << 2) - sizeof(struct ip);
 363: 
 364:     t = ip->ip_dst;
 365:     ip->ip_dst = ip->ip_src;
 366:     /*
 367: 	 * If the incoming packet was addressed directly to us,
 368: 	 * use dst as the src for the reply.  Otherwise (broadcast
 369: 	 * or anonymous), use the address which corresponds
 370: 	 * to the incoming interface.
 371: 	 */
 372:     for (ia = in_ifaddr; ia; ia = ia->ia_next) {
 373:         if (t.s_addr == IA_SIN(ia)->sin_addr.s_addr)
 374:             break;
 375:         if ((ia->ia_ifp->if_flags & IFF_BROADCAST) &&
 376:             t.s_addr == satosin(&ia->ia_broadaddr)->sin_addr.s_addr)
 377:             break;
 378:     }
 379:     if (ia == (struct in_ifaddr *)0)
 380:         ia = ifptoia(ifp);
 381:     if (ia == (struct in_ifaddr *)0)
 382:         ia = in_ifaddr;
 383:     t = IA_SIN(ia)->sin_addr;
 384:     ip->ip_src = t;
 385:     ip->ip_ttl = MAXTTL;
 386: 
 387:     if (optlen > 0) {
 388:         /*
 389: 		 * Retrieve any source routing from the incoming packet
 390: 		 * and strip out other options.  Adjust the IP length.
 391: 		 */
 392:         opts = ip_srcroute();
 393:         ip->ip_len -= optlen;
 394:         ip_stripoptions(ip, (struct mbuf *)0);
 395:     }
 396:     icmp_send(ip, opts);
 397:     if (opts)
 398:         (void)m_free(opts);
 399: }
 400: 
 401: struct in_ifaddr *
 402: ifptoia(ifp)
 403:     struct ifnet *ifp;
 404: {
 405:     register struct in_ifaddr *ia;
 406: 
 407:     for (ia = in_ifaddr; ia; ia = ia->ia_next)
 408:         if (ia->ia_ifp == ifp)
 409:             return (ia);
 410:     return ((struct in_ifaddr *)0);
 411: }
 412: 
 413: /*
 414:  * Send an icmp packet back to the ip level,
 415:  * after supplying a checksum.
 416:  */
 417: icmp_send(ip, opts)
 418:     register struct ip *ip;
 419:     struct mbuf *opts;
 420: {
 421:     register int hlen;
 422:     register struct icmp *icp;
 423:     register struct mbuf *m;
 424: 
 425:     m = dtom(ip);
 426:     hlen = ip->ip_hl << 2;
 427:     m->m_off += hlen;
 428:     m->m_len -= hlen;
 429:     icp = mtod(m, struct icmp *);
 430:     icp->icmp_cksum = 0;
 431:     icp->icmp_cksum = in_cksum(m, ip->ip_len - hlen);
 432:     m->m_off -= hlen;
 433:     m->m_len += hlen;
 434: #ifdef ICMPPRINTFS
 435:     if (icmpprintfs)
 436:         printf("icmp_send dst %X src %X\n", ntohl(ip->ip_dst.s_addr), ntohl(ip->ip_src.s_addr));
 437: #endif
 438:     (void) ip_output(m, opts, (struct route *)0, 0);
 439: }
 440: 
 441: n_time
 442: iptime()
 443: {
 444:     struct timeval atv;
 445:     int s = splhigh();
 446:     u_long t;
 447:     extern struct timeval time;
 448:     extern int lbolt, hz;
 449: 
 450:     cpfromkern(&time, &atv, sizeof(struct timeval));
 451:     t = (atv.tv_sec % (24L*60L*60L)) * 1000L
 452:       + (long)mfkd(&lbolt) * 1000L / (long)hz;
 453:     splx(s);
 454:     return (htonl(t));
 455: }
 456: 
 457: int
 458: icmp_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
 459:     int *name;
 460:     u_int namelen;
 461:     void *oldp;
 462:     size_t *oldlenp;
 463:     void *newp;
 464:     size_t newlen;
 465: {
 466: 
 467:     /* All sysctl names at this level are terminal. */
 468:     if (namelen != 1)
 469:         return (ENOTDIR);
 470: 
 471:     switch (name[0]) {
 472:     case ICMPCTL_MASKREPL:
 473:         return (sysctl_int(oldp, oldlenp, newp, newlen, &icmpmaskrepl));
 474:     default:
 475:         return (ENOPROTOOPT);
 476:     }
 477:     /* NOTREACHED */
 478: }

Defined functions

icmp_error defined in line 50; never used
icmp_input defined in line 137; never used
icmp_reflect defined in line 355; used 2 times
icmp_send defined in line 417; used 1 times
icmp_sysctl defined in line 457; never used
ifptoia defined in line 401; used 4 times
iptime defined in line 441; used 1 times

Defined variables

icmpdst defined in line 130; used 7 times
icmpgw defined in line 131; used 3 times
icmpprintfs defined in line 42; used 6 times
icmproto defined in line 128; used 1 times
icmpsrc defined in line 129; used 11 times

Defined macros

satosin defined in line 253; used 3 times
Last modified: 1995-10-11
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 5342
Valid CSS Valid XHTML 1.0 Strict