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; }
/** * 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; } }