Icmp:internet Control Message Protocol Implementation Learning notes

Source: Internet
Author: User

ICMP is a protocol of the network layer, which can be regarded as the satellite protocol of IP protocol, because it is mainly used by IP to exchange error messages and other information needing attention with other hosts or routers. Of course, higher-level protocols (TCP/UDP) may even be used by some user processes to use ICMP packets

The processing of the registered ICMP protocol and ICMP protocol involves the following files:

NET/IPV4/ICMP.C ICMP protocol processing entry

NET/IPV4/AF_INET.C Network layer and Transport Layer interface

ICMP message structure

See TCP/IP Protocol learning Note (5) Internet Control Message Protocol (ICMP)

registering ICMP message types

The ICMP net_protocol structure is icmp_protocol, which defines the receiving ICMP message routine as ICMP_RCV.

static const struct Net_protocol Icmp_protocol = {. handler =icmp_rcv,.no_policy =1,.NETNS_OK = 1,};
Initialization of ICMP

static int __net_init icmp_sk_init (struct net *net) {int I, Err;net->ipv4.icmp_sk =kzalloc (nr_cpu_ids * sizeof (struct s Ock *), Gfp_kernel); if (Net->ipv4.icmp_sk = = NULL) return-enomem;for_each_possible_cpu (i) {struct sock *sk;err = inet_ Ctl_sock_create (&sk, Pf_inet, Sock_raw, ipproto_icmp, net); if (Err < 0) goto Fail;net->ipv4.icmp_sk[i] = sk;/* Enough space for 2 64K ICMP packets, including * sk_buff struct overhead. */sk->sk_sndbuf = (2 * ((+ *) + sizeof (struct sk_buff))), Inet_sk (SK)->pmtudisc = Ip_pmtudisc_dont;} /* Control parameters for ECHO replies. */net->ipv4.sysctl_icmp_echo_ignore_all = 0;net->ipv4.sysctl_icmp_echo_ignore_broadcasts = 1;/* Control Parameter-ignore Bogus broadcast responses? */net->ipv4.sysctl_icmp_ignore_bogus_error_responses = 1;/* * Configurable global rate limit. * *ratelimit defines tokens/packet consumed for Dst->rate_token *bucket ratemask defines which ICMP types is Ratelimit Ed by *settingit ' s bit position. * *dEfault: *dest Unreachable (3), Source Quench (4), *time exceeded (one), parameter problem (*/NET-&GT;IPV4.SYSCTL_ICMP_R) Atelimit = 1 * hz;net->ipv4.sysctl_icmp_ratemask = 0X1818;NET-&GT;IPV4.SYSCTL_ICMP_ERRORS_USE_INBOUND_IFADDR = 0; return 0;fail:for_each_possible_cpu (i) Inet_ctl_sock_destroy (Net->ipv4.icmp_sk[i]); Kfree (Net->ipv4.icmp_sk ); return err;} static struct Pernet_operations __net_initdata icmp_sk_ops = {. init = Icmp_sk_init,. Exit = Icmp_sk_exit,};in T __init icmp_init (void) {return Register_pernet_subsys (&icmp_sk_ops);}
Input processing

The ICMP input handler function is ICMP_RCV (). When the ICMP packet arrives, the IP layer finds the function through INET_PROTOS[IPPROTO_ICMP] to input processing. After entering ICMP_RCV (), the parameters in the ICMP message are properly verified and then processed differently according to the ICMP message type.

An ICMP packet of one type corresponds to a icmp_control structure, and an array of that struct type is defined in the kernel Icmp_pointers[nr_icmp_types + 1] to manage ICMP packets, the Icmp_control structure is as follows:

struct Icmp_control {void (*handler) (struct Sk_buff *skb); short   error;/* This ICMP was classed as an error message */};
handler the processing function that corresponds to the input of this type of ICMP message

An error value of 1 indicates a error message, and 0 is a query ICMP packet.

#define ICMP_ECHOREPLY0/* Echo reply*/#define icmp_dest_unreach3/* Destination unreachable*/#define Icmp_source_ quench4/* Source quench*/#define icmp_redirect5/* Redirect (change route) */#define icmp_echo8/* Echo request*/#define icmp_time_exceeded11/* time exceeded*/#define icmp_parameterprob12/* Parameter problem*/#define Icmp_timestamp13/* Timestamp request*/#define icmp_timestampreply14/* Timestamp reply*/#define ICMP_INFO_REQUEST15/* Information Request */#define ICMP_INFO_REPLY16/* Information reply*/#define icmp_address17/* Address Mask request*/#define Icmp_ addressreply18/* Address Mask reply*/#define nr_icmp_types18/* *this table is the definition of how we handle ICMP.  */static const struct Icmp_control icmp_pointers[nr_icmp_types + 1] = {[Icmp_echoreply] = {. Handler = icmp_discard,},[1] = {. Handler = Icmp_discard,.error = 1,},[2] = {. Handler = Icmp_discard,.error = 1,},[icmp_dest_unreach] = {. Handler = Icmp_ Unreach,.error = 1,},[icmp_source_quench] = {. Handler = Icmp_unreach,. Error = 1,},[icmp_redirect] = {. Handler = Icmp_redirect,.error = 1,},[6] = {. Handler = Icmp_discard,.error = 1,},[7] = {.  Handler = Icmp_discard,.error = 1,},[icmp_echo] = {. Handler = Icmp_echo,},[9] = {. Handler = Icmp_discard,.error = 1,},[10]  = {. Handler = Icmp_discard,.error = 1,},[icmp_time_exceeded] = {. Handler = Icmp_unreach,.error = 1,},[icmp_parameterprob]  = {. Handler = Icmp_unreach,.error = 1,},[icmp_timestamp] = {. Handler = icmp_timestamp,},[icmp_timestampreply] = {. handler = Icmp_discard,},[icmp_info_request] = {. Handler = icmp_discard,},[icmp_info_reply] = {. Handler = Icmp_discard,},[icmp_ ADDRESS] = {. Handler = icmp_address,},[icmp_addressreply] = {. Handler = Icmp_address_reply,},};
The function call procedure for receiving processing of ICMP packets:


/* *deal with incoming ICMP packets. */int ICMP_RCV (struct sk_buff *skb) {struct ICMPHDR *icmph;struct rtable *rt = skb_rtable (SKB); struct Net *net = dev_net (rt ->u.dst.dev), if (!xfrm4_policy_check (NULL, xfrm_policy_in, SKB)) {struct Sec_path *sp = Skb_sec_path (SKB); int nh;if ( ! (Sp && sp->xvec[sp->len-1]->props.flags & xfrm_state_icmp)) Goto Drop;if (!pskb_may_pull (SKB, sizeof (*icmph) + sizeof (struct IPHDR))) goto DROP;NH = Skb_network_offset (SKB); skb_set _network_header (SKB, sizeof (*icmph)), if (!xfrm4_policy_check_reverse (NULL, xfrm_policy_in, SKB)) Goto drop;skb_set_ Network_header (SKB, NH);} ICMP_INC_STATS_BH (NET, icmp_mib_inmsgs); switch (skb->ip_summed) {case checksum_complete:if (!csum_fold (skb-> csum)) break;/* fall through */case checksum_none:skb->csum = 0;if (__skb_checksum_complete (SKB)) goto error;} if (!pskb_pull (SKB, sizeof (*icmph))) goto error;icmph = ICMP_HDR (SKB); ICMPMSGIN_INC_STATS_BH (NET, icmph->type);/* * The is the highest ' known ' ICMP type. ANything else is a mystery * *rfc 1122:3.2.2 Unknown ICMP messages types must be silently * discarded. */if (Icmph->type > Nr_icmp_types) goto error;/* *parse The ICMP message */if (Rt->rt_flags & (Rtcf_broadcast | Rtcf_multicast) {/* *RFC 1122:3.2.2.6 an Icmp_echo to broadcast could be * silently ignored (we let user decide with a sy SCTL). *RFC 1122:3.2.2.8 an icmp_timestamp is silently * discarded if to broadcast/multicast.     */if ((Icmph->type = = Icmp_echo | | Icmph->type = = icmp_timestamp) && net->ipv4.sysctl_icmp_echo_ignore_broadcasts) {goto error;} if (icmph->type! = Icmp_echo && Icmph->type! = Icmp_timestamp && Icmph->type! = Icmp_addres S && Icmph->type! = icmp_addressreply) {goto error;}} Icmp_pointers[icmph->type].handler (SKB);d rop:kfree_skb (SKB); return 0;error:icmp_inc_stats_bh (NET, ICMP_MIB_ inerrors); goto drop;}
Output processing

Sending ICMP messages

Icmp_send () is used to output a variety of specified types and encoded ICMP packets, but this function cannot answer packets of hardware addresses or IP addresses of the destination address as multicast or broadcast type

/* *send an ICMP message in response to a situation * *RFC 1122:3.2.2must Send At least the IP header and 8 bytes of head Er. * May send more (we do). *must not the change this header information. *must not reply to a multicast/broadcast IP address. *must not reply to a multicast/broadcast MAC address. *must reply to only the first fragment. */void icmp_send (struct sk_buff *skb_in, int type, int code, __BE32 info) {struct IPHDR *iph;int room;struct icmp_bxm icmp_ Param;struct rtable *rt = skb_rtable (skb_in); struct Ipcm_cookie ipc;__be32 saddr;u8 tos;struct net *net;struct sock *sk;i F (!rt) goto out;net = Dev_net (Rt->u.dst.dev);/* *find the original header. It is expected to be valid, of course. *check This, icmp_send are called from the most obscure devices *sometimes.    */iph = IP_HDR (skb_in); if (U8 *) Iph < Skb_in->head | | (Skb_in->network_header + sizeof (*IPH)) > Skb_in->tail) goto out;/* *no Replies to Physical Multicast/broadcast * /if (Skb_in->pkt_type! = Packet_hosT) goto out;/* *now Check at the protocol level */if (Rt->rt_flags & (Rtcf_broadcast | rtcf_multicast)) Goto out;/* *only reply to fragment 0. We byte re-order The constant *mask for efficiency.  */if (Iph->frag_off & Htons (ip_offset)) goto out;/* *if We send a ICMP error to an ICMP error a mess would result: */if (Icmp_pointers[type].error) {/* *we is an error, check if We is replying to an *icmp error */if (iph->protocol = = ipproto_icmp) {U8 _inner_type, *ITP;ITP = Skb_header_pointer (skb_in, Skb_network_header (skb_in) + (IPH-&GT;IHL <& Lt  2) + offsetof (struct ICMPHDR, type)-Skb_in->data, sizeof (_inner_type), &_inner_type); if (ITP = = NULL) goto out;/* *assume any unknown ICMP type was an error. This *ISN ' t specified is the RFC, but think about it.    */if (*ITP > Nr_icmp_types | | Icmp_pointers[*itp].error) goto out;}} SK = Icmp_xmit_lock (NET), if (SK = = NULL) return;/* *construct Source address and options. */SADDR = Iph->daddr;if (!) ( Rt->rt_flags & rtcf_local) {struct Net_device *dev = null;if (Rt->fl.iif &&net->ipv4.sysctl_icmp_errors_use_inbound_ ifaddr) dev = dev_get_by_index (NET, rt->fl.iif), if (dev) {saddr = inet_select_addr (Dev, 0, rt_scope_link);d ev_put (Dev );} elsesaddr = 0;} TOS = Icmp_pointers[type].error?   ((Iph->tos & Iptos_tos_mask) | Iptos_prec_internetcontrol): Iph->tos;if (Ip_options_echo (&icmp_param.replyopts, skb_in)) Goto out_unlock;/* *prepare data for ICMP header. */icmp_param.data.icmph.type = Type;icmp_param.data.icmph.code = Code;icmp_param.data.icmph.un.gateway = Info;icmp_ Param.data.icmph.checksum = 0;ICMP_PARAM.SKB = Skb_in;icmp_param.offset = Skb_network_offset (skb_in); Inet_sk (SK)- >tos = tos;ipc.addr = iph->saddr;ipc.opt = &icmp_param.replyopts;ipc.shtx.flags = 0;  {struct Flowi fl = {. Nl_u = {. Ip4_u = {. daddr = ICMP_PARAM.REPLYOPTS.SRR? icmp_param.replyopts.faddr:iph->saddr,.saddr = Saddr,.tos = Rt_tos (TOS)}},.proto = Ipproto_icmp,.uli_u = {. Icmpt = {. type = Type,.code = Code}}};int err;struct rtable *rt2;security_skb_classify_flow (skb_in, &AMP;FL); if (__ip_route_output_ Key (NET, &rt, &AMP;FL)) goto out_unlock;/* No need to clone since we ' re just using its address. */rt2 = Rt;err = xfrm_lookup (NET, struct dst_entry * *) &rt, &AMP;FL, NULL, 0); switch (err) {case 0:if (rt! = Rt2) goto Route_done;break;case-eperm:rt = Null;break;default:goto Out_unlock;} if (Xfrm_decode_session_reverse (skb_in, &AMP;FL, af_inet)) Goto relookup_failed;if (Inet_addr_type (NET, fl.fl4_src) = = rtn_local) Err = __ip_route_output_key (NET, &rt2, &AMP;FL); else {struct Flowi fl2 = {};struct Dst_entry *odst;fl2.fl4_ DST = fl.fl4_src;if (Ip_route_output_key (NET, &rt2, &AMP;FL2)) Goto relookup_failed;/* ugh! */ODST = SKB_DST (skb_in); err = Ip_route_input (skb_in, FL.FL4_DST, Fl.fl4_src, Rt_tos (TOS), Rt2->u.dst.dev);d St_rele ASE (&AMP;RT2-&GT;U.DST); rt2 = Skb_rtable (skb_in); Skb_dst_set (skb_in, ODST);} if (err) goto Relookup_failed;err = xfrm_lookup (NET, structDst_entry *) &rt2, &AMP;FL, NULL, xfrm_lookup_icmp), switch (err) {case 0:dst_release (&AMP;RT-&GT;U.DST); rt = Rt2; Break;case-eperm:goto ende;default:relookup_failed:if (!rt) goto Out_unlock;break;}} Route_done:if (!icmpv4_xrlim_allow (NET, RT, type, code)) Goto ende;/* RFC says return as much as we can without exceeding 5 Bytes. */room = DST_MTU (&AMP;RT-&GT;U.DST), if (Guest > 576), and 576;room-= sizeof (struct IPHDR) + icmp_param.replyopts.optle N;room-= sizeof (struct ICMPHDR); Icmp_param.data_len = Skb_in->len-icmp_param.offset;if (Icmp_param.data_len > Icmp_param.data_len = Room;icmp_param.head_len = sizeof (struct ICMPHDR); Icmp_push_reply (&icmp_param, & IPC, &AMP;RT); Ende:ip_rt_put (RT); Out_unlock:icmp_xmit_unlock (SK); out:;}
The General error and request ICMP messages are sent through Icmp_send (), while echo response and timestamp response messages are output by Icmp_replay ().

/* *driving logic for building and sending ICMP messages. */static void icmp_reply (struct icmp_bxm *icmp_param, struct sk_buff *skb) {struct Ipcm_cookie ipc;struct rtable *rt = skb_ Rtable (SKB); struct Net *net = dev_net (rt->u.dst.dev); struct sock *sk;struct inet_sock *inet;__be32 daddr;if (ip_ Options_echo (&icmp_param->replyopts, SKB)) Return;sk = Icmp_xmit_lock (NET); if (SK = = NULL) return;inet = Inet_sk ( SK); icmp_param->data.icmph.checksum = 0;inet->tos = Ip_hdr (SKB)->tos;daddr = IPC.ADDR = rt->rt_src;ipc.opt = Null;ipc.shtx.flags = 0;if (icmp_param->replyopts.optlen) {ipc.opt = &icmp_param->replyopts;if (ipc.opt- &GT;SRR) daddr = icmp_param->replyopts.faddr;} {struct Flowi fl = {. Nl_u = {. Ip4_u = {. daddr = Daddr,.saddr = Rt->rt_spec_dst,.tos = Rt_tos (Ip_hdr (SKB)->to s)}},. proto = ipproto_icmp};security_skb_classify_flow (SKB, &AMP;FL); if (Ip_route_output_key (NET, &rt, &AMP;FL) ) goto Out_unlock;} if (Icmpv4_xrlim_allow (NET, RT, Icmp_param->data.icmph.type, Icmp_param->data.icmph.code)) icmp_push_reply (Icmp_param, &AMP;IPC, &rt); Ip_rt_put (RT ); Out_unlock:icmp_xmit_unlock (SK);}

Icmp:internet Control Message Protocol Implementation Learning notes

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.