Exemplo n.º 1
0
uint_t
icmp_input (T_NET_BUF **inputp, uint_t *offp, uint_t *nextp)
{
	T_NET_BUF	*input = *inputp;
	T_ICMP4_HDR	*icmp4h;
	T_IN4_ADDR	addr;
	uint_t		len, align;

	NET_COUNT_ICMP4(net_count_icmp4.in_octets,
	               input->len - GET_IF_IP4_HDR_SIZE(input));
	NET_COUNT_ICMP4(net_count_icmp4.in_packets, 1);

	/* ICMP ヘッダの長さをチェックする。*/
	if (input->len < IF_IP4_ICMP4_HDR_SIZE) {
		NET_COUNT_ICMP4(net_count_icmp4.in_err_packets, 1);
		NET_COUNT_MIB(icmp_stats.icmpInErrors, 1);
		goto buf_rel;
		}

	icmp4h = (T_ICMP4_HDR *)(input->buf + *offp);

	/* 4 オクテット境界のデータ長 */
	len   = input->len - *offp;
	align = (len + 3) >> 2 << 2;

	/* 4 オクテット境界までパディングで埋める。*/
	if (align > len)
		memset((uint8_t*)input->buf + input->len, 0, (size_t)(align - len));

	/* チェックサムを計算する。*/
	if (in_cksum(icmp4h, align) != 0) {
		NET_COUNT_ICMP4(net_count_icmp4.in_err_packets, 1);
		goto buf_rel;
		}

	/* メッセージの型により分岐する。*/
	switch (icmp4h->type) {
	case ICMP4_ECHO_REQUEST:
		icmp_echo(input, *offp);
		return IPPROTO_DONE;
		break;
	case ICMP4_ECHO_REPLY:

#ifdef ICMP_CFG_CALLBACK_ECHO_REPLY

		icmp_echo_reply(input, *offp);

#endif	/* of #ifdef ICMP_CFG_CALLBACK_ECHO_REPLY */

		break;
	case ICMP4_UNREACH:
		icmp_unreach(input, *offp);
		break;
	case ICMP4_REDIRECT:

#if NUM_REDIRECT_ROUTE_ENTRY > 0

		addr = ntohl(icmp4h->data.addr);
		syslog(LOG_INFO, "[ICMP] redirect, addr: %s.", ip2str(NULL, &addr));
		icmp_redirect(input, *offp);

#else	/* of #if NUM_REDIRECT_ROUTE_ENTRY > 0 */

		addr = ntohl(icmp4h->data.addr);
		syslog(LOG_INFO, "[ICMP] redirect ignored, addr: %s.", ip2str(NULL, &addr));

#endif	/* of #if NUM_REDIRECT_ROUTE_ENTRY > 0 */

		break;
	default:
		syslog(LOG_INFO, "[ICMP] unknown type: %d.", icmp4h->type);
		NET_COUNT_ICMP4(net_count_icmp4.in_err_packets, 1);
		break;
		}

buf_rel:
	syscall(rel_net_buf(input));
	return IPPROTO_DONE;
	}
Exemplo n.º 2
0
/**
 * Handler for incoming ICMP packets.
 */
void icmp_handler (const in_Header *ip, BOOL broadcast)
{
  union ICMP_PKT  *icmp;
  const in_Header *orig_ip;
  int              type, code;
  unsigned         len;
  DWORD            delta_time;
  BOOL             for_me, i_orig;  /* is it for me, did I originate it */
  const char      *msg;

  DEBUG_RX (NULL, ip);

  if (block_icmp)   /* application is handling ICMP; not needed */
     return;

  len    = in_GetHdrLen (ip);
  icmp   = (union ICMP_PKT*) ((BYTE*)ip + len);
  len    = intel16 (ip->length) - len;
  for_me = _ip4_is_multihome_addr (intel(ip->destination));

  if (!for_me || broadcast)  /* drop broadcast pings.. */
     return;

  if (len < sizeof(icmp->info))
  {
    STAT (icmpstats.icps_tooshort++);
    return;
  }

  if (CHECKSUM(icmp,len) != 0xFFFF)
  {
    STAT (icmpstats.icps_checksum++);
    icmp_print (1, _LANG("bad checksum"), ip->source);
    return;
  }

  type    = icmp->unused.type;
  code    = icmp->unused.code;
  orig_ip = &icmp->ip.ip;
  i_orig  = _ip4_is_local_addr (intel(orig_ip->source));

  if (type == ICMP_MASKREPLY)
  {
    if (!_do_mask_req)
       return;
    i_orig = TRUE;
  }

  /* !! this needs work
   */
  if (!i_orig &&
      (type != ICMP_ECHOREPLY && type != ICMP_ECHO &&
       type != ICMP_IREQREPLY && type != ICMP_TSTAMP))
  {
    icmp_bogus (ip, type, NULL);
    return;
  }

  switch (type)
  {
    case ICMP_ECHOREPLY:  /* check if we were waiting for it */
         delta_time = set_timeout(0) - icmp->echo.identifier;
         add_ping (intel(ip->source), delta_time, icmp->echo.index);
         return;

    case ICMP_UNREACH:
         if (code < DIM(icmp_unreach_str))
         {
           UINT len_needed = 8 + in_GetHdrLen (orig_ip);
           WORD next_mtu   = 0;

           msg = _LANG (icmp_unreach_str[code]);
           icmp_print (1, msg, ip->source);

           if (orig_ip->proto == TCP_PROTO ||
               orig_ip->proto == UDP_PROTO)
              len_needed += 4;  /* Need the src/dest port numbers */

           if (len >= len_needed)
           {
             if (code == ICMP_UNREACH_NEEDFRAG)
                next_mtu = intel16 (icmp->needfrag.next_mtu);

#if !defined(USE_UDP_ONLY)
             if (orig_ip->proto == TCP_PROTO)
                _tcp_cancel (orig_ip, ICMP_UNREACH, code, msg, &next_mtu);
             else
#endif
             if (orig_ip->proto == UDP_PROTO)
                _udp_cancel (orig_ip, ICMP_UNREACH, code, msg, &next_mtu);

             /** \todo Handle cancelling raw sockets */
#if defined(USE_BSD_API) && 0  
             else
              _raw_cancel (orig_ip, ICMP_UNREACH, code, msg);
#endif
           }
           else
             STAT (icmpstats.icps_tooshort++);
         }
         else
           STAT (icmpstats.icps_badcode++);
         return;

    case ICMP_SOURCEQUENCH:
#if !defined(USE_UDP_ONLY)
         if (orig_ip->proto == TCP_PROTO)
         {
           msg = _LANG (icmp_type_str[type]);
           icmp_print (1, msg, ip->source);
           _tcp_cancel (orig_ip, ICMP_SOURCEQUENCH, code, msg, NULL);
         }
#endif
         return;

    case ICMP_REDIRECT:
         if (code < DIM(icmp_redirect_str))
              icmp_redirect (icmp, ip, orig_ip, code);
         else STAT (icmpstats.icps_badcode++);
         return;

    case ICMP_ECHO:
         icmp_print (2, _LANG("PING requested of us"), ip->source);
         icmp_echo_reply (ip, icmp, len);
         return;

    case ICMP_TIMXCEED:
         if (code >= DIM(icmp_exceed_str))
         {
           STAT (icmpstats.icps_badcode++);
           return;
         }
         if (code == 0)  /* "TTL exceeded in transit" */
            switch (orig_ip->proto)
            {
#if !defined(USE_UDP_ONLY)
              case TCP_PROTO:
                   msg = _LANG (icmp_exceed_str[0]);
                   icmp_print (1, msg, ip->source);
                   _tcp_cancel (orig_ip, ICMP_TIMXCEED, code, msg, NULL);
                   break;
#endif
              case UDP_PROTO:
                   msg = _LANG (icmp_exceed_str[0]);
                   icmp_print (1, msg, ip->source);
                   _udp_cancel (orig_ip, ICMP_TIMXCEED, code, msg, NULL);
                   break;
            }
         return;

    case ICMP_PARAMPROB:
         msg = _LANG (icmp_type_str[ICMP_PARAMPROB]);
         switch (orig_ip->proto)
         {
#if !defined(USE_UDP_ONLY)
           case TCP_PROTO:
                icmp_print (0, msg, ip->source);
                _tcp_cancel (orig_ip, ICMP_PARAMPROB, code, msg, NULL);
                break;
#endif
           case UDP_PROTO:
                icmp_print (0, msg, ip->source);
                _udp_cancel (orig_ip, ICMP_PARAMPROB, code, msg, NULL);
                break;
         }
         return;

    case ICMP_ROUTERADVERT:  /* todo !! */
         msg = _LANG (icmp_type_str[ICMP_ROUTERADVERT]);
         icmp_print (1, msg, ip->source);
         return;

    case ICMP_ROUTERSOLICIT: /* todo !! */
         msg = _LANG (icmp_type_str[ICMP_ROUTERSOLICIT]);
         icmp_print (1, msg, ip->source);
         return;

    case ICMP_TSTAMP:
         msg = _LANG (icmp_type_str[ICMP_TSTAMP]);
         icmp_print (1, msg, ip->source);
         /**< \todo send reply? */
         return;

    case ICMP_TSTAMPREPLY:
         msg = _LANG (icmp_type_str[ICMP_TSTAMPREPLY]);
         icmp_print (1, msg, ip->source);
         /**< \todo should store */
         return;

    case ICMP_IREQ:
         msg = _LANG (icmp_type_str[ICMP_IREQ]);
         icmp_print (1, msg, ip->source);
         /**< \todo send reply */
         return;

    case ICMP_IREQREPLY:
         msg = _LANG (icmp_type_str[ICMP_IREQREPLY]);
         icmp_print (1, msg, ip->source);
         /**< \todo send reply upwards */
         return;

    case ICMP_MASKREQ:
         /* might be sent by us, never answer */
         break;

    case ICMP_MASKREPLY:
         msg = _LANG (icmp_type_str[ICMP_MASKREPLY]);
         icmp_print (0, msg, ip->source);
         if ((icmp->mask.identifier == addr_mask_id)    &&
             (icmp->mask.sequence   == addr_mask_seq-1) &&
             sin_mask != intel(icmp->mask.mask))
            outsnl ("Conflicting net-mask from \"ICMP Addr Mask Reply\"\7");
         addr_mask_id = 0;
         return;
  }
}