162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * NET3: Implementation of the ICMP protocol layer. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Alan Cox, <alan@lxorguk.ukuu.org.uk> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Some of the function names and the icmp unreach table for this 862306a36Sopenharmony_ci * module were derived from [icmp.c 1.0.11 06/02/93] by 962306a36Sopenharmony_ci * Ross Biro, Fred N. van Kempen, Mark Evans, Alan Cox, Gerhard Koerting. 1062306a36Sopenharmony_ci * Other than that this module is a complete rewrite. 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * Fixes: 1362306a36Sopenharmony_ci * Clemens Fruhwirth : introduce global icmp rate limiting 1462306a36Sopenharmony_ci * with icmp type masking ability instead 1562306a36Sopenharmony_ci * of broken per type icmp timeouts. 1662306a36Sopenharmony_ci * Mike Shaver : RFC1122 checks. 1762306a36Sopenharmony_ci * Alan Cox : Multicast ping reply as self. 1862306a36Sopenharmony_ci * Alan Cox : Fix atomicity lockup in ip_build_xmit 1962306a36Sopenharmony_ci * call. 2062306a36Sopenharmony_ci * Alan Cox : Added 216,128 byte paths to the MTU 2162306a36Sopenharmony_ci * code. 2262306a36Sopenharmony_ci * Martin Mares : RFC1812 checks. 2362306a36Sopenharmony_ci * Martin Mares : Can be configured to follow redirects 2462306a36Sopenharmony_ci * if acting as a router _without_ a 2562306a36Sopenharmony_ci * routing protocol (RFC 1812). 2662306a36Sopenharmony_ci * Martin Mares : Echo requests may be configured to 2762306a36Sopenharmony_ci * be ignored (RFC 1812). 2862306a36Sopenharmony_ci * Martin Mares : Limitation of ICMP error message 2962306a36Sopenharmony_ci * transmit rate (RFC 1812). 3062306a36Sopenharmony_ci * Martin Mares : TOS and Precedence set correctly 3162306a36Sopenharmony_ci * (RFC 1812). 3262306a36Sopenharmony_ci * Martin Mares : Now copying as much data from the 3362306a36Sopenharmony_ci * original packet as we can without 3462306a36Sopenharmony_ci * exceeding 576 bytes (RFC 1812). 3562306a36Sopenharmony_ci * Willy Konynenberg : Transparent proxying support. 3662306a36Sopenharmony_ci * Keith Owens : RFC1191 correction for 4.2BSD based 3762306a36Sopenharmony_ci * path MTU bug. 3862306a36Sopenharmony_ci * Thomas Quinot : ICMP Dest Unreach codes up to 15 are 3962306a36Sopenharmony_ci * valid (RFC 1812). 4062306a36Sopenharmony_ci * Andi Kleen : Check all packet lengths properly 4162306a36Sopenharmony_ci * and moved all kfree_skb() up to 4262306a36Sopenharmony_ci * icmp_rcv. 4362306a36Sopenharmony_ci * Andi Kleen : Move the rate limit bookkeeping 4462306a36Sopenharmony_ci * into the dest entry and use a token 4562306a36Sopenharmony_ci * bucket filter (thanks to ANK). Make 4662306a36Sopenharmony_ci * the rates sysctl configurable. 4762306a36Sopenharmony_ci * Yu Tianli : Fixed two ugly bugs in icmp_send 4862306a36Sopenharmony_ci * - IP option length was accounted wrongly 4962306a36Sopenharmony_ci * - ICMP header length was not accounted 5062306a36Sopenharmony_ci * at all. 5162306a36Sopenharmony_ci * Tristan Greaves : Added sysctl option to ignore bogus 5262306a36Sopenharmony_ci * broadcast responses from broken routers. 5362306a36Sopenharmony_ci * 5462306a36Sopenharmony_ci * To Fix: 5562306a36Sopenharmony_ci * 5662306a36Sopenharmony_ci * - Should use skb_pull() instead of all the manual checking. 5762306a36Sopenharmony_ci * This would also greatly simply some upper layer error handlers. --AK 5862306a36Sopenharmony_ci */ 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci#include <linux/module.h> 6362306a36Sopenharmony_ci#include <linux/types.h> 6462306a36Sopenharmony_ci#include <linux/jiffies.h> 6562306a36Sopenharmony_ci#include <linux/kernel.h> 6662306a36Sopenharmony_ci#include <linux/fcntl.h> 6762306a36Sopenharmony_ci#include <linux/socket.h> 6862306a36Sopenharmony_ci#include <linux/in.h> 6962306a36Sopenharmony_ci#include <linux/inet.h> 7062306a36Sopenharmony_ci#include <linux/inetdevice.h> 7162306a36Sopenharmony_ci#include <linux/netdevice.h> 7262306a36Sopenharmony_ci#include <linux/string.h> 7362306a36Sopenharmony_ci#include <linux/netfilter_ipv4.h> 7462306a36Sopenharmony_ci#include <linux/slab.h> 7562306a36Sopenharmony_ci#include <net/snmp.h> 7662306a36Sopenharmony_ci#include <net/ip.h> 7762306a36Sopenharmony_ci#include <net/route.h> 7862306a36Sopenharmony_ci#include <net/protocol.h> 7962306a36Sopenharmony_ci#include <net/icmp.h> 8062306a36Sopenharmony_ci#include <net/tcp.h> 8162306a36Sopenharmony_ci#include <net/udp.h> 8262306a36Sopenharmony_ci#include <net/raw.h> 8362306a36Sopenharmony_ci#include <net/ping.h> 8462306a36Sopenharmony_ci#include <linux/skbuff.h> 8562306a36Sopenharmony_ci#include <net/sock.h> 8662306a36Sopenharmony_ci#include <linux/errno.h> 8762306a36Sopenharmony_ci#include <linux/timer.h> 8862306a36Sopenharmony_ci#include <linux/init.h> 8962306a36Sopenharmony_ci#include <linux/uaccess.h> 9062306a36Sopenharmony_ci#include <net/checksum.h> 9162306a36Sopenharmony_ci#include <net/xfrm.h> 9262306a36Sopenharmony_ci#include <net/inet_common.h> 9362306a36Sopenharmony_ci#include <net/ip_fib.h> 9462306a36Sopenharmony_ci#include <net/l3mdev.h> 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci/* 9762306a36Sopenharmony_ci * Build xmit assembly blocks 9862306a36Sopenharmony_ci */ 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cistruct icmp_bxm { 10162306a36Sopenharmony_ci struct sk_buff *skb; 10262306a36Sopenharmony_ci int offset; 10362306a36Sopenharmony_ci int data_len; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci struct { 10662306a36Sopenharmony_ci struct icmphdr icmph; 10762306a36Sopenharmony_ci __be32 times[3]; 10862306a36Sopenharmony_ci } data; 10962306a36Sopenharmony_ci int head_len; 11062306a36Sopenharmony_ci struct ip_options_data replyopts; 11162306a36Sopenharmony_ci}; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci/* An array of errno for error messages from dest unreach. */ 11462306a36Sopenharmony_ci/* RFC 1122: 3.2.2.1 States that NET_UNREACH, HOST_UNREACH and SR_FAILED MUST be considered 'transient errs'. */ 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ciconst struct icmp_err icmp_err_convert[] = { 11762306a36Sopenharmony_ci { 11862306a36Sopenharmony_ci .errno = ENETUNREACH, /* ICMP_NET_UNREACH */ 11962306a36Sopenharmony_ci .fatal = 0, 12062306a36Sopenharmony_ci }, 12162306a36Sopenharmony_ci { 12262306a36Sopenharmony_ci .errno = EHOSTUNREACH, /* ICMP_HOST_UNREACH */ 12362306a36Sopenharmony_ci .fatal = 0, 12462306a36Sopenharmony_ci }, 12562306a36Sopenharmony_ci { 12662306a36Sopenharmony_ci .errno = ENOPROTOOPT /* ICMP_PROT_UNREACH */, 12762306a36Sopenharmony_ci .fatal = 1, 12862306a36Sopenharmony_ci }, 12962306a36Sopenharmony_ci { 13062306a36Sopenharmony_ci .errno = ECONNREFUSED, /* ICMP_PORT_UNREACH */ 13162306a36Sopenharmony_ci .fatal = 1, 13262306a36Sopenharmony_ci }, 13362306a36Sopenharmony_ci { 13462306a36Sopenharmony_ci .errno = EMSGSIZE, /* ICMP_FRAG_NEEDED */ 13562306a36Sopenharmony_ci .fatal = 0, 13662306a36Sopenharmony_ci }, 13762306a36Sopenharmony_ci { 13862306a36Sopenharmony_ci .errno = EOPNOTSUPP, /* ICMP_SR_FAILED */ 13962306a36Sopenharmony_ci .fatal = 0, 14062306a36Sopenharmony_ci }, 14162306a36Sopenharmony_ci { 14262306a36Sopenharmony_ci .errno = ENETUNREACH, /* ICMP_NET_UNKNOWN */ 14362306a36Sopenharmony_ci .fatal = 1, 14462306a36Sopenharmony_ci }, 14562306a36Sopenharmony_ci { 14662306a36Sopenharmony_ci .errno = EHOSTDOWN, /* ICMP_HOST_UNKNOWN */ 14762306a36Sopenharmony_ci .fatal = 1, 14862306a36Sopenharmony_ci }, 14962306a36Sopenharmony_ci { 15062306a36Sopenharmony_ci .errno = ENONET, /* ICMP_HOST_ISOLATED */ 15162306a36Sopenharmony_ci .fatal = 1, 15262306a36Sopenharmony_ci }, 15362306a36Sopenharmony_ci { 15462306a36Sopenharmony_ci .errno = ENETUNREACH, /* ICMP_NET_ANO */ 15562306a36Sopenharmony_ci .fatal = 1, 15662306a36Sopenharmony_ci }, 15762306a36Sopenharmony_ci { 15862306a36Sopenharmony_ci .errno = EHOSTUNREACH, /* ICMP_HOST_ANO */ 15962306a36Sopenharmony_ci .fatal = 1, 16062306a36Sopenharmony_ci }, 16162306a36Sopenharmony_ci { 16262306a36Sopenharmony_ci .errno = ENETUNREACH, /* ICMP_NET_UNR_TOS */ 16362306a36Sopenharmony_ci .fatal = 0, 16462306a36Sopenharmony_ci }, 16562306a36Sopenharmony_ci { 16662306a36Sopenharmony_ci .errno = EHOSTUNREACH, /* ICMP_HOST_UNR_TOS */ 16762306a36Sopenharmony_ci .fatal = 0, 16862306a36Sopenharmony_ci }, 16962306a36Sopenharmony_ci { 17062306a36Sopenharmony_ci .errno = EHOSTUNREACH, /* ICMP_PKT_FILTERED */ 17162306a36Sopenharmony_ci .fatal = 1, 17262306a36Sopenharmony_ci }, 17362306a36Sopenharmony_ci { 17462306a36Sopenharmony_ci .errno = EHOSTUNREACH, /* ICMP_PREC_VIOLATION */ 17562306a36Sopenharmony_ci .fatal = 1, 17662306a36Sopenharmony_ci }, 17762306a36Sopenharmony_ci { 17862306a36Sopenharmony_ci .errno = EHOSTUNREACH, /* ICMP_PREC_CUTOFF */ 17962306a36Sopenharmony_ci .fatal = 1, 18062306a36Sopenharmony_ci }, 18162306a36Sopenharmony_ci}; 18262306a36Sopenharmony_ciEXPORT_SYMBOL(icmp_err_convert); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci/* 18562306a36Sopenharmony_ci * ICMP control array. This specifies what to do with each ICMP. 18662306a36Sopenharmony_ci */ 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cistruct icmp_control { 18962306a36Sopenharmony_ci enum skb_drop_reason (*handler)(struct sk_buff *skb); 19062306a36Sopenharmony_ci short error; /* This ICMP is classed as an error message */ 19162306a36Sopenharmony_ci}; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_cistatic const struct icmp_control icmp_pointers[NR_ICMP_TYPES+1]; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_cistatic DEFINE_PER_CPU(struct sock *, ipv4_icmp_sk); 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci/* Called with BH disabled */ 19862306a36Sopenharmony_cistatic inline struct sock *icmp_xmit_lock(struct net *net) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci struct sock *sk; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci sk = this_cpu_read(ipv4_icmp_sk); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci if (unlikely(!spin_trylock(&sk->sk_lock.slock))) { 20562306a36Sopenharmony_ci /* This can happen if the output path signals a 20662306a36Sopenharmony_ci * dst_link_failure() for an outgoing ICMP packet. 20762306a36Sopenharmony_ci */ 20862306a36Sopenharmony_ci return NULL; 20962306a36Sopenharmony_ci } 21062306a36Sopenharmony_ci sock_net_set(sk, net); 21162306a36Sopenharmony_ci return sk; 21262306a36Sopenharmony_ci} 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_cistatic inline void icmp_xmit_unlock(struct sock *sk) 21562306a36Sopenharmony_ci{ 21662306a36Sopenharmony_ci sock_net_set(sk, &init_net); 21762306a36Sopenharmony_ci spin_unlock(&sk->sk_lock.slock); 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ciint sysctl_icmp_msgs_per_sec __read_mostly = 1000; 22162306a36Sopenharmony_ciint sysctl_icmp_msgs_burst __read_mostly = 50; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_cistatic struct { 22462306a36Sopenharmony_ci spinlock_t lock; 22562306a36Sopenharmony_ci u32 credit; 22662306a36Sopenharmony_ci u32 stamp; 22762306a36Sopenharmony_ci} icmp_global = { 22862306a36Sopenharmony_ci .lock = __SPIN_LOCK_UNLOCKED(icmp_global.lock), 22962306a36Sopenharmony_ci}; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci/** 23262306a36Sopenharmony_ci * icmp_global_allow - Are we allowed to send one more ICMP message ? 23362306a36Sopenharmony_ci * 23462306a36Sopenharmony_ci * Uses a token bucket to limit our ICMP messages to ~sysctl_icmp_msgs_per_sec. 23562306a36Sopenharmony_ci * Returns false if we reached the limit and can not send another packet. 23662306a36Sopenharmony_ci * Note: called with BH disabled 23762306a36Sopenharmony_ci */ 23862306a36Sopenharmony_cibool icmp_global_allow(void) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci u32 credit, delta, incr = 0, now = (u32)jiffies; 24162306a36Sopenharmony_ci bool rc = false; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci /* Check if token bucket is empty and cannot be refilled 24462306a36Sopenharmony_ci * without taking the spinlock. The READ_ONCE() are paired 24562306a36Sopenharmony_ci * with the following WRITE_ONCE() in this same function. 24662306a36Sopenharmony_ci */ 24762306a36Sopenharmony_ci if (!READ_ONCE(icmp_global.credit)) { 24862306a36Sopenharmony_ci delta = min_t(u32, now - READ_ONCE(icmp_global.stamp), HZ); 24962306a36Sopenharmony_ci if (delta < HZ / 50) 25062306a36Sopenharmony_ci return false; 25162306a36Sopenharmony_ci } 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci spin_lock(&icmp_global.lock); 25462306a36Sopenharmony_ci delta = min_t(u32, now - icmp_global.stamp, HZ); 25562306a36Sopenharmony_ci if (delta >= HZ / 50) { 25662306a36Sopenharmony_ci incr = READ_ONCE(sysctl_icmp_msgs_per_sec) * delta / HZ; 25762306a36Sopenharmony_ci if (incr) 25862306a36Sopenharmony_ci WRITE_ONCE(icmp_global.stamp, now); 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci credit = min_t(u32, icmp_global.credit + incr, 26162306a36Sopenharmony_ci READ_ONCE(sysctl_icmp_msgs_burst)); 26262306a36Sopenharmony_ci if (credit) { 26362306a36Sopenharmony_ci /* We want to use a credit of one in average, but need to randomize 26462306a36Sopenharmony_ci * it for security reasons. 26562306a36Sopenharmony_ci */ 26662306a36Sopenharmony_ci credit = max_t(int, credit - get_random_u32_below(3), 0); 26762306a36Sopenharmony_ci rc = true; 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci WRITE_ONCE(icmp_global.credit, credit); 27062306a36Sopenharmony_ci spin_unlock(&icmp_global.lock); 27162306a36Sopenharmony_ci return rc; 27262306a36Sopenharmony_ci} 27362306a36Sopenharmony_ciEXPORT_SYMBOL(icmp_global_allow); 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_cistatic bool icmpv4_mask_allow(struct net *net, int type, int code) 27662306a36Sopenharmony_ci{ 27762306a36Sopenharmony_ci if (type > NR_ICMP_TYPES) 27862306a36Sopenharmony_ci return true; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci /* Don't limit PMTU discovery. */ 28162306a36Sopenharmony_ci if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) 28262306a36Sopenharmony_ci return true; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci /* Limit if icmp type is enabled in ratemask. */ 28562306a36Sopenharmony_ci if (!((1 << type) & READ_ONCE(net->ipv4.sysctl_icmp_ratemask))) 28662306a36Sopenharmony_ci return true; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci return false; 28962306a36Sopenharmony_ci} 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_cistatic bool icmpv4_global_allow(struct net *net, int type, int code) 29262306a36Sopenharmony_ci{ 29362306a36Sopenharmony_ci if (icmpv4_mask_allow(net, type, code)) 29462306a36Sopenharmony_ci return true; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci if (icmp_global_allow()) 29762306a36Sopenharmony_ci return true; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci __ICMP_INC_STATS(net, ICMP_MIB_RATELIMITGLOBAL); 30062306a36Sopenharmony_ci return false; 30162306a36Sopenharmony_ci} 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci/* 30462306a36Sopenharmony_ci * Send an ICMP frame. 30562306a36Sopenharmony_ci */ 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_cistatic bool icmpv4_xrlim_allow(struct net *net, struct rtable *rt, 30862306a36Sopenharmony_ci struct flowi4 *fl4, int type, int code) 30962306a36Sopenharmony_ci{ 31062306a36Sopenharmony_ci struct dst_entry *dst = &rt->dst; 31162306a36Sopenharmony_ci struct inet_peer *peer; 31262306a36Sopenharmony_ci bool rc = true; 31362306a36Sopenharmony_ci int vif; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci if (icmpv4_mask_allow(net, type, code)) 31662306a36Sopenharmony_ci goto out; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci /* No rate limit on loopback */ 31962306a36Sopenharmony_ci if (dst->dev && (dst->dev->flags&IFF_LOOPBACK)) 32062306a36Sopenharmony_ci goto out; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci vif = l3mdev_master_ifindex(dst->dev); 32362306a36Sopenharmony_ci peer = inet_getpeer_v4(net->ipv4.peers, fl4->daddr, vif, 1); 32462306a36Sopenharmony_ci rc = inet_peer_xrlim_allow(peer, 32562306a36Sopenharmony_ci READ_ONCE(net->ipv4.sysctl_icmp_ratelimit)); 32662306a36Sopenharmony_ci if (peer) 32762306a36Sopenharmony_ci inet_putpeer(peer); 32862306a36Sopenharmony_ciout: 32962306a36Sopenharmony_ci if (!rc) 33062306a36Sopenharmony_ci __ICMP_INC_STATS(net, ICMP_MIB_RATELIMITHOST); 33162306a36Sopenharmony_ci return rc; 33262306a36Sopenharmony_ci} 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci/* 33562306a36Sopenharmony_ci * Maintain the counters used in the SNMP statistics for outgoing ICMP 33662306a36Sopenharmony_ci */ 33762306a36Sopenharmony_civoid icmp_out_count(struct net *net, unsigned char type) 33862306a36Sopenharmony_ci{ 33962306a36Sopenharmony_ci ICMPMSGOUT_INC_STATS(net, type); 34062306a36Sopenharmony_ci ICMP_INC_STATS(net, ICMP_MIB_OUTMSGS); 34162306a36Sopenharmony_ci} 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci/* 34462306a36Sopenharmony_ci * Checksum each fragment, and on the first include the headers and final 34562306a36Sopenharmony_ci * checksum. 34662306a36Sopenharmony_ci */ 34762306a36Sopenharmony_cistatic int icmp_glue_bits(void *from, char *to, int offset, int len, int odd, 34862306a36Sopenharmony_ci struct sk_buff *skb) 34962306a36Sopenharmony_ci{ 35062306a36Sopenharmony_ci struct icmp_bxm *icmp_param = from; 35162306a36Sopenharmony_ci __wsum csum; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci csum = skb_copy_and_csum_bits(icmp_param->skb, 35462306a36Sopenharmony_ci icmp_param->offset + offset, 35562306a36Sopenharmony_ci to, len); 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci skb->csum = csum_block_add(skb->csum, csum, odd); 35862306a36Sopenharmony_ci if (icmp_pointers[icmp_param->data.icmph.type].error) 35962306a36Sopenharmony_ci nf_ct_attach(skb, icmp_param->skb); 36062306a36Sopenharmony_ci return 0; 36162306a36Sopenharmony_ci} 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_cistatic void icmp_push_reply(struct sock *sk, 36462306a36Sopenharmony_ci struct icmp_bxm *icmp_param, 36562306a36Sopenharmony_ci struct flowi4 *fl4, 36662306a36Sopenharmony_ci struct ipcm_cookie *ipc, struct rtable **rt) 36762306a36Sopenharmony_ci{ 36862306a36Sopenharmony_ci struct sk_buff *skb; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci if (ip_append_data(sk, fl4, icmp_glue_bits, icmp_param, 37162306a36Sopenharmony_ci icmp_param->data_len+icmp_param->head_len, 37262306a36Sopenharmony_ci icmp_param->head_len, 37362306a36Sopenharmony_ci ipc, rt, MSG_DONTWAIT) < 0) { 37462306a36Sopenharmony_ci __ICMP_INC_STATS(sock_net(sk), ICMP_MIB_OUTERRORS); 37562306a36Sopenharmony_ci ip_flush_pending_frames(sk); 37662306a36Sopenharmony_ci } else if ((skb = skb_peek(&sk->sk_write_queue)) != NULL) { 37762306a36Sopenharmony_ci struct icmphdr *icmph = icmp_hdr(skb); 37862306a36Sopenharmony_ci __wsum csum; 37962306a36Sopenharmony_ci struct sk_buff *skb1; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci csum = csum_partial_copy_nocheck((void *)&icmp_param->data, 38262306a36Sopenharmony_ci (char *)icmph, 38362306a36Sopenharmony_ci icmp_param->head_len); 38462306a36Sopenharmony_ci skb_queue_walk(&sk->sk_write_queue, skb1) { 38562306a36Sopenharmony_ci csum = csum_add(csum, skb1->csum); 38662306a36Sopenharmony_ci } 38762306a36Sopenharmony_ci icmph->checksum = csum_fold(csum); 38862306a36Sopenharmony_ci skb->ip_summed = CHECKSUM_NONE; 38962306a36Sopenharmony_ci ip_push_pending_frames(sk, fl4); 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci} 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci/* 39462306a36Sopenharmony_ci * Driving logic for building and sending ICMP messages. 39562306a36Sopenharmony_ci */ 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_cistatic void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) 39862306a36Sopenharmony_ci{ 39962306a36Sopenharmony_ci struct ipcm_cookie ipc; 40062306a36Sopenharmony_ci struct rtable *rt = skb_rtable(skb); 40162306a36Sopenharmony_ci struct net *net = dev_net(rt->dst.dev); 40262306a36Sopenharmony_ci struct flowi4 fl4; 40362306a36Sopenharmony_ci struct sock *sk; 40462306a36Sopenharmony_ci struct inet_sock *inet; 40562306a36Sopenharmony_ci __be32 daddr, saddr; 40662306a36Sopenharmony_ci u32 mark = IP4_REPLY_MARK(net, skb->mark); 40762306a36Sopenharmony_ci int type = icmp_param->data.icmph.type; 40862306a36Sopenharmony_ci int code = icmp_param->data.icmph.code; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci if (ip_options_echo(net, &icmp_param->replyopts.opt.opt, skb)) 41162306a36Sopenharmony_ci return; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci /* Needed by both icmp_global_allow and icmp_xmit_lock */ 41462306a36Sopenharmony_ci local_bh_disable(); 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci /* global icmp_msgs_per_sec */ 41762306a36Sopenharmony_ci if (!icmpv4_global_allow(net, type, code)) 41862306a36Sopenharmony_ci goto out_bh_enable; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci sk = icmp_xmit_lock(net); 42162306a36Sopenharmony_ci if (!sk) 42262306a36Sopenharmony_ci goto out_bh_enable; 42362306a36Sopenharmony_ci inet = inet_sk(sk); 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci icmp_param->data.icmph.checksum = 0; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci ipcm_init(&ipc); 42862306a36Sopenharmony_ci inet->tos = ip_hdr(skb)->tos; 42962306a36Sopenharmony_ci ipc.sockc.mark = mark; 43062306a36Sopenharmony_ci daddr = ipc.addr = ip_hdr(skb)->saddr; 43162306a36Sopenharmony_ci saddr = fib_compute_spec_dst(skb); 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci if (icmp_param->replyopts.opt.opt.optlen) { 43462306a36Sopenharmony_ci ipc.opt = &icmp_param->replyopts.opt; 43562306a36Sopenharmony_ci if (ipc.opt->opt.srr) 43662306a36Sopenharmony_ci daddr = icmp_param->replyopts.opt.opt.faddr; 43762306a36Sopenharmony_ci } 43862306a36Sopenharmony_ci memset(&fl4, 0, sizeof(fl4)); 43962306a36Sopenharmony_ci fl4.daddr = daddr; 44062306a36Sopenharmony_ci fl4.saddr = saddr; 44162306a36Sopenharmony_ci fl4.flowi4_mark = mark; 44262306a36Sopenharmony_ci fl4.flowi4_uid = sock_net_uid(net, NULL); 44362306a36Sopenharmony_ci fl4.flowi4_tos = RT_TOS(ip_hdr(skb)->tos); 44462306a36Sopenharmony_ci fl4.flowi4_proto = IPPROTO_ICMP; 44562306a36Sopenharmony_ci fl4.flowi4_oif = l3mdev_master_ifindex(skb->dev); 44662306a36Sopenharmony_ci security_skb_classify_flow(skb, flowi4_to_flowi_common(&fl4)); 44762306a36Sopenharmony_ci rt = ip_route_output_key(net, &fl4); 44862306a36Sopenharmony_ci if (IS_ERR(rt)) 44962306a36Sopenharmony_ci goto out_unlock; 45062306a36Sopenharmony_ci if (icmpv4_xrlim_allow(net, rt, &fl4, type, code)) 45162306a36Sopenharmony_ci icmp_push_reply(sk, icmp_param, &fl4, &ipc, &rt); 45262306a36Sopenharmony_ci ip_rt_put(rt); 45362306a36Sopenharmony_ciout_unlock: 45462306a36Sopenharmony_ci icmp_xmit_unlock(sk); 45562306a36Sopenharmony_ciout_bh_enable: 45662306a36Sopenharmony_ci local_bh_enable(); 45762306a36Sopenharmony_ci} 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci/* 46062306a36Sopenharmony_ci * The device used for looking up which routing table to use for sending an ICMP 46162306a36Sopenharmony_ci * error is preferably the source whenever it is set, which should ensure the 46262306a36Sopenharmony_ci * icmp error can be sent to the source host, else lookup using the routing 46362306a36Sopenharmony_ci * table of the destination device, else use the main routing table (index 0). 46462306a36Sopenharmony_ci */ 46562306a36Sopenharmony_cistatic struct net_device *icmp_get_route_lookup_dev(struct sk_buff *skb) 46662306a36Sopenharmony_ci{ 46762306a36Sopenharmony_ci struct net_device *route_lookup_dev = NULL; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci if (skb->dev) 47062306a36Sopenharmony_ci route_lookup_dev = skb->dev; 47162306a36Sopenharmony_ci else if (skb_dst(skb)) 47262306a36Sopenharmony_ci route_lookup_dev = skb_dst(skb)->dev; 47362306a36Sopenharmony_ci return route_lookup_dev; 47462306a36Sopenharmony_ci} 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_cistatic struct rtable *icmp_route_lookup(struct net *net, 47762306a36Sopenharmony_ci struct flowi4 *fl4, 47862306a36Sopenharmony_ci struct sk_buff *skb_in, 47962306a36Sopenharmony_ci const struct iphdr *iph, 48062306a36Sopenharmony_ci __be32 saddr, u8 tos, u32 mark, 48162306a36Sopenharmony_ci int type, int code, 48262306a36Sopenharmony_ci struct icmp_bxm *param) 48362306a36Sopenharmony_ci{ 48462306a36Sopenharmony_ci struct net_device *route_lookup_dev; 48562306a36Sopenharmony_ci struct rtable *rt, *rt2; 48662306a36Sopenharmony_ci struct flowi4 fl4_dec; 48762306a36Sopenharmony_ci int err; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci memset(fl4, 0, sizeof(*fl4)); 49062306a36Sopenharmony_ci fl4->daddr = (param->replyopts.opt.opt.srr ? 49162306a36Sopenharmony_ci param->replyopts.opt.opt.faddr : iph->saddr); 49262306a36Sopenharmony_ci fl4->saddr = saddr; 49362306a36Sopenharmony_ci fl4->flowi4_mark = mark; 49462306a36Sopenharmony_ci fl4->flowi4_uid = sock_net_uid(net, NULL); 49562306a36Sopenharmony_ci fl4->flowi4_tos = RT_TOS(tos); 49662306a36Sopenharmony_ci fl4->flowi4_proto = IPPROTO_ICMP; 49762306a36Sopenharmony_ci fl4->fl4_icmp_type = type; 49862306a36Sopenharmony_ci fl4->fl4_icmp_code = code; 49962306a36Sopenharmony_ci route_lookup_dev = icmp_get_route_lookup_dev(skb_in); 50062306a36Sopenharmony_ci fl4->flowi4_oif = l3mdev_master_ifindex(route_lookup_dev); 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci security_skb_classify_flow(skb_in, flowi4_to_flowi_common(fl4)); 50362306a36Sopenharmony_ci rt = ip_route_output_key_hash(net, fl4, skb_in); 50462306a36Sopenharmony_ci if (IS_ERR(rt)) 50562306a36Sopenharmony_ci return rt; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci /* No need to clone since we're just using its address. */ 50862306a36Sopenharmony_ci rt2 = rt; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci rt = (struct rtable *) xfrm_lookup(net, &rt->dst, 51162306a36Sopenharmony_ci flowi4_to_flowi(fl4), NULL, 0); 51262306a36Sopenharmony_ci if (!IS_ERR(rt)) { 51362306a36Sopenharmony_ci if (rt != rt2) 51462306a36Sopenharmony_ci return rt; 51562306a36Sopenharmony_ci } else if (PTR_ERR(rt) == -EPERM) { 51662306a36Sopenharmony_ci rt = NULL; 51762306a36Sopenharmony_ci } else 51862306a36Sopenharmony_ci return rt; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci err = xfrm_decode_session_reverse(skb_in, flowi4_to_flowi(&fl4_dec), AF_INET); 52162306a36Sopenharmony_ci if (err) 52262306a36Sopenharmony_ci goto relookup_failed; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci if (inet_addr_type_dev_table(net, route_lookup_dev, 52562306a36Sopenharmony_ci fl4_dec.saddr) == RTN_LOCAL) { 52662306a36Sopenharmony_ci rt2 = __ip_route_output_key(net, &fl4_dec); 52762306a36Sopenharmony_ci if (IS_ERR(rt2)) 52862306a36Sopenharmony_ci err = PTR_ERR(rt2); 52962306a36Sopenharmony_ci } else { 53062306a36Sopenharmony_ci struct flowi4 fl4_2 = {}; 53162306a36Sopenharmony_ci unsigned long orefdst; 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci fl4_2.daddr = fl4_dec.saddr; 53462306a36Sopenharmony_ci rt2 = ip_route_output_key(net, &fl4_2); 53562306a36Sopenharmony_ci if (IS_ERR(rt2)) { 53662306a36Sopenharmony_ci err = PTR_ERR(rt2); 53762306a36Sopenharmony_ci goto relookup_failed; 53862306a36Sopenharmony_ci } 53962306a36Sopenharmony_ci /* Ugh! */ 54062306a36Sopenharmony_ci orefdst = skb_in->_skb_refdst; /* save old refdst */ 54162306a36Sopenharmony_ci skb_dst_set(skb_in, NULL); 54262306a36Sopenharmony_ci err = ip_route_input(skb_in, fl4_dec.daddr, fl4_dec.saddr, 54362306a36Sopenharmony_ci RT_TOS(tos), rt2->dst.dev); 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci dst_release(&rt2->dst); 54662306a36Sopenharmony_ci rt2 = skb_rtable(skb_in); 54762306a36Sopenharmony_ci skb_in->_skb_refdst = orefdst; /* restore old refdst */ 54862306a36Sopenharmony_ci } 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci if (err) 55162306a36Sopenharmony_ci goto relookup_failed; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci rt2 = (struct rtable *) xfrm_lookup(net, &rt2->dst, 55462306a36Sopenharmony_ci flowi4_to_flowi(&fl4_dec), NULL, 55562306a36Sopenharmony_ci XFRM_LOOKUP_ICMP); 55662306a36Sopenharmony_ci if (!IS_ERR(rt2)) { 55762306a36Sopenharmony_ci dst_release(&rt->dst); 55862306a36Sopenharmony_ci memcpy(fl4, &fl4_dec, sizeof(*fl4)); 55962306a36Sopenharmony_ci rt = rt2; 56062306a36Sopenharmony_ci } else if (PTR_ERR(rt2) == -EPERM) { 56162306a36Sopenharmony_ci if (rt) 56262306a36Sopenharmony_ci dst_release(&rt->dst); 56362306a36Sopenharmony_ci return rt2; 56462306a36Sopenharmony_ci } else { 56562306a36Sopenharmony_ci err = PTR_ERR(rt2); 56662306a36Sopenharmony_ci goto relookup_failed; 56762306a36Sopenharmony_ci } 56862306a36Sopenharmony_ci return rt; 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_cirelookup_failed: 57162306a36Sopenharmony_ci if (rt) 57262306a36Sopenharmony_ci return rt; 57362306a36Sopenharmony_ci return ERR_PTR(err); 57462306a36Sopenharmony_ci} 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci/* 57762306a36Sopenharmony_ci * Send an ICMP message in response to a situation 57862306a36Sopenharmony_ci * 57962306a36Sopenharmony_ci * RFC 1122: 3.2.2 MUST send at least the IP header and 8 bytes of header. 58062306a36Sopenharmony_ci * MAY send more (we do). 58162306a36Sopenharmony_ci * MUST NOT change this header information. 58262306a36Sopenharmony_ci * MUST NOT reply to a multicast/broadcast IP address. 58362306a36Sopenharmony_ci * MUST NOT reply to a multicast/broadcast MAC address. 58462306a36Sopenharmony_ci * MUST reply to only the first fragment. 58562306a36Sopenharmony_ci */ 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_civoid __icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info, 58862306a36Sopenharmony_ci const struct ip_options *opt) 58962306a36Sopenharmony_ci{ 59062306a36Sopenharmony_ci struct iphdr *iph; 59162306a36Sopenharmony_ci int room; 59262306a36Sopenharmony_ci struct icmp_bxm icmp_param; 59362306a36Sopenharmony_ci struct rtable *rt = skb_rtable(skb_in); 59462306a36Sopenharmony_ci struct ipcm_cookie ipc; 59562306a36Sopenharmony_ci struct flowi4 fl4; 59662306a36Sopenharmony_ci __be32 saddr; 59762306a36Sopenharmony_ci u8 tos; 59862306a36Sopenharmony_ci u32 mark; 59962306a36Sopenharmony_ci struct net *net; 60062306a36Sopenharmony_ci struct sock *sk; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci if (!rt) 60362306a36Sopenharmony_ci goto out; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci if (rt->dst.dev) 60662306a36Sopenharmony_ci net = dev_net(rt->dst.dev); 60762306a36Sopenharmony_ci else if (skb_in->dev) 60862306a36Sopenharmony_ci net = dev_net(skb_in->dev); 60962306a36Sopenharmony_ci else 61062306a36Sopenharmony_ci goto out; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci /* 61362306a36Sopenharmony_ci * Find the original header. It is expected to be valid, of course. 61462306a36Sopenharmony_ci * Check this, icmp_send is called from the most obscure devices 61562306a36Sopenharmony_ci * sometimes. 61662306a36Sopenharmony_ci */ 61762306a36Sopenharmony_ci iph = ip_hdr(skb_in); 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci if ((u8 *)iph < skb_in->head || 62062306a36Sopenharmony_ci (skb_network_header(skb_in) + sizeof(*iph)) > 62162306a36Sopenharmony_ci skb_tail_pointer(skb_in)) 62262306a36Sopenharmony_ci goto out; 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci /* 62562306a36Sopenharmony_ci * No replies to physical multicast/broadcast 62662306a36Sopenharmony_ci */ 62762306a36Sopenharmony_ci if (skb_in->pkt_type != PACKET_HOST) 62862306a36Sopenharmony_ci goto out; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci /* 63162306a36Sopenharmony_ci * Now check at the protocol level 63262306a36Sopenharmony_ci */ 63362306a36Sopenharmony_ci if (rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) 63462306a36Sopenharmony_ci goto out; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci /* 63762306a36Sopenharmony_ci * Only reply to fragment 0. We byte re-order the constant 63862306a36Sopenharmony_ci * mask for efficiency. 63962306a36Sopenharmony_ci */ 64062306a36Sopenharmony_ci if (iph->frag_off & htons(IP_OFFSET)) 64162306a36Sopenharmony_ci goto out; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci /* 64462306a36Sopenharmony_ci * If we send an ICMP error to an ICMP error a mess would result.. 64562306a36Sopenharmony_ci */ 64662306a36Sopenharmony_ci if (icmp_pointers[type].error) { 64762306a36Sopenharmony_ci /* 64862306a36Sopenharmony_ci * We are an error, check if we are replying to an 64962306a36Sopenharmony_ci * ICMP error 65062306a36Sopenharmony_ci */ 65162306a36Sopenharmony_ci if (iph->protocol == IPPROTO_ICMP) { 65262306a36Sopenharmony_ci u8 _inner_type, *itp; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci itp = skb_header_pointer(skb_in, 65562306a36Sopenharmony_ci skb_network_header(skb_in) + 65662306a36Sopenharmony_ci (iph->ihl << 2) + 65762306a36Sopenharmony_ci offsetof(struct icmphdr, 65862306a36Sopenharmony_ci type) - 65962306a36Sopenharmony_ci skb_in->data, 66062306a36Sopenharmony_ci sizeof(_inner_type), 66162306a36Sopenharmony_ci &_inner_type); 66262306a36Sopenharmony_ci if (!itp) 66362306a36Sopenharmony_ci goto out; 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci /* 66662306a36Sopenharmony_ci * Assume any unknown ICMP type is an error. This 66762306a36Sopenharmony_ci * isn't specified by the RFC, but think about it.. 66862306a36Sopenharmony_ci */ 66962306a36Sopenharmony_ci if (*itp > NR_ICMP_TYPES || 67062306a36Sopenharmony_ci icmp_pointers[*itp].error) 67162306a36Sopenharmony_ci goto out; 67262306a36Sopenharmony_ci } 67362306a36Sopenharmony_ci } 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci /* Needed by both icmp_global_allow and icmp_xmit_lock */ 67662306a36Sopenharmony_ci local_bh_disable(); 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci /* Check global sysctl_icmp_msgs_per_sec ratelimit, unless 67962306a36Sopenharmony_ci * incoming dev is loopback. If outgoing dev change to not be 68062306a36Sopenharmony_ci * loopback, then peer ratelimit still work (in icmpv4_xrlim_allow) 68162306a36Sopenharmony_ci */ 68262306a36Sopenharmony_ci if (!(skb_in->dev && (skb_in->dev->flags&IFF_LOOPBACK)) && 68362306a36Sopenharmony_ci !icmpv4_global_allow(net, type, code)) 68462306a36Sopenharmony_ci goto out_bh_enable; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci sk = icmp_xmit_lock(net); 68762306a36Sopenharmony_ci if (!sk) 68862306a36Sopenharmony_ci goto out_bh_enable; 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci /* 69162306a36Sopenharmony_ci * Construct source address and options. 69262306a36Sopenharmony_ci */ 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci saddr = iph->daddr; 69562306a36Sopenharmony_ci if (!(rt->rt_flags & RTCF_LOCAL)) { 69662306a36Sopenharmony_ci struct net_device *dev = NULL; 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci rcu_read_lock(); 69962306a36Sopenharmony_ci if (rt_is_input_route(rt) && 70062306a36Sopenharmony_ci READ_ONCE(net->ipv4.sysctl_icmp_errors_use_inbound_ifaddr)) 70162306a36Sopenharmony_ci dev = dev_get_by_index_rcu(net, inet_iif(skb_in)); 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci if (dev) 70462306a36Sopenharmony_ci saddr = inet_select_addr(dev, iph->saddr, 70562306a36Sopenharmony_ci RT_SCOPE_LINK); 70662306a36Sopenharmony_ci else 70762306a36Sopenharmony_ci saddr = 0; 70862306a36Sopenharmony_ci rcu_read_unlock(); 70962306a36Sopenharmony_ci } 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci tos = icmp_pointers[type].error ? (RT_TOS(iph->tos) | 71262306a36Sopenharmony_ci IPTOS_PREC_INTERNETCONTROL) : 71362306a36Sopenharmony_ci iph->tos; 71462306a36Sopenharmony_ci mark = IP4_REPLY_MARK(net, skb_in->mark); 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci if (__ip_options_echo(net, &icmp_param.replyopts.opt.opt, skb_in, opt)) 71762306a36Sopenharmony_ci goto out_unlock; 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci /* 72162306a36Sopenharmony_ci * Prepare data for ICMP header. 72262306a36Sopenharmony_ci */ 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci icmp_param.data.icmph.type = type; 72562306a36Sopenharmony_ci icmp_param.data.icmph.code = code; 72662306a36Sopenharmony_ci icmp_param.data.icmph.un.gateway = info; 72762306a36Sopenharmony_ci icmp_param.data.icmph.checksum = 0; 72862306a36Sopenharmony_ci icmp_param.skb = skb_in; 72962306a36Sopenharmony_ci icmp_param.offset = skb_network_offset(skb_in); 73062306a36Sopenharmony_ci inet_sk(sk)->tos = tos; 73162306a36Sopenharmony_ci ipcm_init(&ipc); 73262306a36Sopenharmony_ci ipc.addr = iph->saddr; 73362306a36Sopenharmony_ci ipc.opt = &icmp_param.replyopts.opt; 73462306a36Sopenharmony_ci ipc.sockc.mark = mark; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci rt = icmp_route_lookup(net, &fl4, skb_in, iph, saddr, tos, mark, 73762306a36Sopenharmony_ci type, code, &icmp_param); 73862306a36Sopenharmony_ci if (IS_ERR(rt)) 73962306a36Sopenharmony_ci goto out_unlock; 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci /* peer icmp_ratelimit */ 74262306a36Sopenharmony_ci if (!icmpv4_xrlim_allow(net, rt, &fl4, type, code)) 74362306a36Sopenharmony_ci goto ende; 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci /* RFC says return as much as we can without exceeding 576 bytes. */ 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci room = dst_mtu(&rt->dst); 74862306a36Sopenharmony_ci if (room > 576) 74962306a36Sopenharmony_ci room = 576; 75062306a36Sopenharmony_ci room -= sizeof(struct iphdr) + icmp_param.replyopts.opt.opt.optlen; 75162306a36Sopenharmony_ci room -= sizeof(struct icmphdr); 75262306a36Sopenharmony_ci /* Guard against tiny mtu. We need to include at least one 75362306a36Sopenharmony_ci * IP network header for this message to make any sense. 75462306a36Sopenharmony_ci */ 75562306a36Sopenharmony_ci if (room <= (int)sizeof(struct iphdr)) 75662306a36Sopenharmony_ci goto ende; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci icmp_param.data_len = skb_in->len - icmp_param.offset; 75962306a36Sopenharmony_ci if (icmp_param.data_len > room) 76062306a36Sopenharmony_ci icmp_param.data_len = room; 76162306a36Sopenharmony_ci icmp_param.head_len = sizeof(struct icmphdr); 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci /* if we don't have a source address at this point, fall back to the 76462306a36Sopenharmony_ci * dummy address instead of sending out a packet with a source address 76562306a36Sopenharmony_ci * of 0.0.0.0 76662306a36Sopenharmony_ci */ 76762306a36Sopenharmony_ci if (!fl4.saddr) 76862306a36Sopenharmony_ci fl4.saddr = htonl(INADDR_DUMMY); 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci icmp_push_reply(sk, &icmp_param, &fl4, &ipc, &rt); 77162306a36Sopenharmony_ciende: 77262306a36Sopenharmony_ci ip_rt_put(rt); 77362306a36Sopenharmony_ciout_unlock: 77462306a36Sopenharmony_ci icmp_xmit_unlock(sk); 77562306a36Sopenharmony_ciout_bh_enable: 77662306a36Sopenharmony_ci local_bh_enable(); 77762306a36Sopenharmony_ciout:; 77862306a36Sopenharmony_ci} 77962306a36Sopenharmony_ciEXPORT_SYMBOL(__icmp_send); 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_NF_NAT) 78262306a36Sopenharmony_ci#include <net/netfilter/nf_conntrack.h> 78362306a36Sopenharmony_civoid icmp_ndo_send(struct sk_buff *skb_in, int type, int code, __be32 info) 78462306a36Sopenharmony_ci{ 78562306a36Sopenharmony_ci struct sk_buff *cloned_skb = NULL; 78662306a36Sopenharmony_ci struct ip_options opts = { 0 }; 78762306a36Sopenharmony_ci enum ip_conntrack_info ctinfo; 78862306a36Sopenharmony_ci struct nf_conn *ct; 78962306a36Sopenharmony_ci __be32 orig_ip; 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci ct = nf_ct_get(skb_in, &ctinfo); 79262306a36Sopenharmony_ci if (!ct || !(ct->status & IPS_SRC_NAT)) { 79362306a36Sopenharmony_ci __icmp_send(skb_in, type, code, info, &opts); 79462306a36Sopenharmony_ci return; 79562306a36Sopenharmony_ci } 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci if (skb_shared(skb_in)) 79862306a36Sopenharmony_ci skb_in = cloned_skb = skb_clone(skb_in, GFP_ATOMIC); 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci if (unlikely(!skb_in || skb_network_header(skb_in) < skb_in->head || 80162306a36Sopenharmony_ci (skb_network_header(skb_in) + sizeof(struct iphdr)) > 80262306a36Sopenharmony_ci skb_tail_pointer(skb_in) || skb_ensure_writable(skb_in, 80362306a36Sopenharmony_ci skb_network_offset(skb_in) + sizeof(struct iphdr)))) 80462306a36Sopenharmony_ci goto out; 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci orig_ip = ip_hdr(skb_in)->saddr; 80762306a36Sopenharmony_ci ip_hdr(skb_in)->saddr = ct->tuplehash[0].tuple.src.u3.ip; 80862306a36Sopenharmony_ci __icmp_send(skb_in, type, code, info, &opts); 80962306a36Sopenharmony_ci ip_hdr(skb_in)->saddr = orig_ip; 81062306a36Sopenharmony_ciout: 81162306a36Sopenharmony_ci consume_skb(cloned_skb); 81262306a36Sopenharmony_ci} 81362306a36Sopenharmony_ciEXPORT_SYMBOL(icmp_ndo_send); 81462306a36Sopenharmony_ci#endif 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_cistatic void icmp_socket_deliver(struct sk_buff *skb, u32 info) 81762306a36Sopenharmony_ci{ 81862306a36Sopenharmony_ci const struct iphdr *iph = (const struct iphdr *)skb->data; 81962306a36Sopenharmony_ci const struct net_protocol *ipprot; 82062306a36Sopenharmony_ci int protocol = iph->protocol; 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci /* Checkin full IP header plus 8 bytes of protocol to 82362306a36Sopenharmony_ci * avoid additional coding at protocol handlers. 82462306a36Sopenharmony_ci */ 82562306a36Sopenharmony_ci if (!pskb_may_pull(skb, iph->ihl * 4 + 8)) { 82662306a36Sopenharmony_ci __ICMP_INC_STATS(dev_net(skb->dev), ICMP_MIB_INERRORS); 82762306a36Sopenharmony_ci return; 82862306a36Sopenharmony_ci } 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci raw_icmp_error(skb, protocol, info); 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci ipprot = rcu_dereference(inet_protos[protocol]); 83362306a36Sopenharmony_ci if (ipprot && ipprot->err_handler) 83462306a36Sopenharmony_ci ipprot->err_handler(skb, info); 83562306a36Sopenharmony_ci} 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_cistatic bool icmp_tag_validation(int proto) 83862306a36Sopenharmony_ci{ 83962306a36Sopenharmony_ci bool ok; 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci rcu_read_lock(); 84262306a36Sopenharmony_ci ok = rcu_dereference(inet_protos[proto])->icmp_strict_tag_validation; 84362306a36Sopenharmony_ci rcu_read_unlock(); 84462306a36Sopenharmony_ci return ok; 84562306a36Sopenharmony_ci} 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci/* 84862306a36Sopenharmony_ci * Handle ICMP_DEST_UNREACH, ICMP_TIME_EXCEEDED, ICMP_QUENCH, and 84962306a36Sopenharmony_ci * ICMP_PARAMETERPROB. 85062306a36Sopenharmony_ci */ 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_cistatic enum skb_drop_reason icmp_unreach(struct sk_buff *skb) 85362306a36Sopenharmony_ci{ 85462306a36Sopenharmony_ci enum skb_drop_reason reason = SKB_NOT_DROPPED_YET; 85562306a36Sopenharmony_ci const struct iphdr *iph; 85662306a36Sopenharmony_ci struct icmphdr *icmph; 85762306a36Sopenharmony_ci struct net *net; 85862306a36Sopenharmony_ci u32 info = 0; 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci net = dev_net(skb_dst(skb)->dev); 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci /* 86362306a36Sopenharmony_ci * Incomplete header ? 86462306a36Sopenharmony_ci * Only checks for the IP header, there should be an 86562306a36Sopenharmony_ci * additional check for longer headers in upper levels. 86662306a36Sopenharmony_ci */ 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci if (!pskb_may_pull(skb, sizeof(struct iphdr))) 86962306a36Sopenharmony_ci goto out_err; 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci icmph = icmp_hdr(skb); 87262306a36Sopenharmony_ci iph = (const struct iphdr *)skb->data; 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci if (iph->ihl < 5) { /* Mangled header, drop. */ 87562306a36Sopenharmony_ci reason = SKB_DROP_REASON_IP_INHDR; 87662306a36Sopenharmony_ci goto out_err; 87762306a36Sopenharmony_ci } 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci switch (icmph->type) { 88062306a36Sopenharmony_ci case ICMP_DEST_UNREACH: 88162306a36Sopenharmony_ci switch (icmph->code & 15) { 88262306a36Sopenharmony_ci case ICMP_NET_UNREACH: 88362306a36Sopenharmony_ci case ICMP_HOST_UNREACH: 88462306a36Sopenharmony_ci case ICMP_PROT_UNREACH: 88562306a36Sopenharmony_ci case ICMP_PORT_UNREACH: 88662306a36Sopenharmony_ci break; 88762306a36Sopenharmony_ci case ICMP_FRAG_NEEDED: 88862306a36Sopenharmony_ci /* for documentation of the ip_no_pmtu_disc 88962306a36Sopenharmony_ci * values please see 89062306a36Sopenharmony_ci * Documentation/networking/ip-sysctl.rst 89162306a36Sopenharmony_ci */ 89262306a36Sopenharmony_ci switch (READ_ONCE(net->ipv4.sysctl_ip_no_pmtu_disc)) { 89362306a36Sopenharmony_ci default: 89462306a36Sopenharmony_ci net_dbg_ratelimited("%pI4: fragmentation needed and DF set\n", 89562306a36Sopenharmony_ci &iph->daddr); 89662306a36Sopenharmony_ci break; 89762306a36Sopenharmony_ci case 2: 89862306a36Sopenharmony_ci goto out; 89962306a36Sopenharmony_ci case 3: 90062306a36Sopenharmony_ci if (!icmp_tag_validation(iph->protocol)) 90162306a36Sopenharmony_ci goto out; 90262306a36Sopenharmony_ci fallthrough; 90362306a36Sopenharmony_ci case 0: 90462306a36Sopenharmony_ci info = ntohs(icmph->un.frag.mtu); 90562306a36Sopenharmony_ci } 90662306a36Sopenharmony_ci break; 90762306a36Sopenharmony_ci case ICMP_SR_FAILED: 90862306a36Sopenharmony_ci net_dbg_ratelimited("%pI4: Source Route Failed\n", 90962306a36Sopenharmony_ci &iph->daddr); 91062306a36Sopenharmony_ci break; 91162306a36Sopenharmony_ci default: 91262306a36Sopenharmony_ci break; 91362306a36Sopenharmony_ci } 91462306a36Sopenharmony_ci if (icmph->code > NR_ICMP_UNREACH) 91562306a36Sopenharmony_ci goto out; 91662306a36Sopenharmony_ci break; 91762306a36Sopenharmony_ci case ICMP_PARAMETERPROB: 91862306a36Sopenharmony_ci info = ntohl(icmph->un.gateway) >> 24; 91962306a36Sopenharmony_ci break; 92062306a36Sopenharmony_ci case ICMP_TIME_EXCEEDED: 92162306a36Sopenharmony_ci __ICMP_INC_STATS(net, ICMP_MIB_INTIMEEXCDS); 92262306a36Sopenharmony_ci if (icmph->code == ICMP_EXC_FRAGTIME) 92362306a36Sopenharmony_ci goto out; 92462306a36Sopenharmony_ci break; 92562306a36Sopenharmony_ci } 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci /* 92862306a36Sopenharmony_ci * Throw it at our lower layers 92962306a36Sopenharmony_ci * 93062306a36Sopenharmony_ci * RFC 1122: 3.2.2 MUST extract the protocol ID from the passed 93162306a36Sopenharmony_ci * header. 93262306a36Sopenharmony_ci * RFC 1122: 3.2.2.1 MUST pass ICMP unreach messages to the 93362306a36Sopenharmony_ci * transport layer. 93462306a36Sopenharmony_ci * RFC 1122: 3.2.2.2 MUST pass ICMP time expired messages to 93562306a36Sopenharmony_ci * transport layer. 93662306a36Sopenharmony_ci */ 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci /* 93962306a36Sopenharmony_ci * Check the other end isn't violating RFC 1122. Some routers send 94062306a36Sopenharmony_ci * bogus responses to broadcast frames. If you see this message 94162306a36Sopenharmony_ci * first check your netmask matches at both ends, if it does then 94262306a36Sopenharmony_ci * get the other vendor to fix their kit. 94362306a36Sopenharmony_ci */ 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci if (!READ_ONCE(net->ipv4.sysctl_icmp_ignore_bogus_error_responses) && 94662306a36Sopenharmony_ci inet_addr_type_dev_table(net, skb->dev, iph->daddr) == RTN_BROADCAST) { 94762306a36Sopenharmony_ci net_warn_ratelimited("%pI4 sent an invalid ICMP type %u, code %u error to a broadcast: %pI4 on %s\n", 94862306a36Sopenharmony_ci &ip_hdr(skb)->saddr, 94962306a36Sopenharmony_ci icmph->type, icmph->code, 95062306a36Sopenharmony_ci &iph->daddr, skb->dev->name); 95162306a36Sopenharmony_ci goto out; 95262306a36Sopenharmony_ci } 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci icmp_socket_deliver(skb, info); 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ciout: 95762306a36Sopenharmony_ci return reason; 95862306a36Sopenharmony_ciout_err: 95962306a36Sopenharmony_ci __ICMP_INC_STATS(net, ICMP_MIB_INERRORS); 96062306a36Sopenharmony_ci return reason ?: SKB_DROP_REASON_NOT_SPECIFIED; 96162306a36Sopenharmony_ci} 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci/* 96562306a36Sopenharmony_ci * Handle ICMP_REDIRECT. 96662306a36Sopenharmony_ci */ 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_cistatic enum skb_drop_reason icmp_redirect(struct sk_buff *skb) 96962306a36Sopenharmony_ci{ 97062306a36Sopenharmony_ci if (skb->len < sizeof(struct iphdr)) { 97162306a36Sopenharmony_ci __ICMP_INC_STATS(dev_net(skb->dev), ICMP_MIB_INERRORS); 97262306a36Sopenharmony_ci return SKB_DROP_REASON_PKT_TOO_SMALL; 97362306a36Sopenharmony_ci } 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci if (!pskb_may_pull(skb, sizeof(struct iphdr))) { 97662306a36Sopenharmony_ci /* there aught to be a stat */ 97762306a36Sopenharmony_ci return SKB_DROP_REASON_NOMEM; 97862306a36Sopenharmony_ci } 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci icmp_socket_deliver(skb, ntohl(icmp_hdr(skb)->un.gateway)); 98162306a36Sopenharmony_ci return SKB_NOT_DROPPED_YET; 98262306a36Sopenharmony_ci} 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci/* 98562306a36Sopenharmony_ci * Handle ICMP_ECHO ("ping") and ICMP_EXT_ECHO ("PROBE") requests. 98662306a36Sopenharmony_ci * 98762306a36Sopenharmony_ci * RFC 1122: 3.2.2.6 MUST have an echo server that answers ICMP echo 98862306a36Sopenharmony_ci * requests. 98962306a36Sopenharmony_ci * RFC 1122: 3.2.2.6 Data received in the ICMP_ECHO request MUST be 99062306a36Sopenharmony_ci * included in the reply. 99162306a36Sopenharmony_ci * RFC 1812: 4.3.3.6 SHOULD have a config option for silently ignoring 99262306a36Sopenharmony_ci * echo requests, MUST have default=NOT. 99362306a36Sopenharmony_ci * RFC 8335: 8 MUST have a config option to enable/disable ICMP 99462306a36Sopenharmony_ci * Extended Echo Functionality, MUST be disabled by default 99562306a36Sopenharmony_ci * See also WRT handling of options once they are done and working. 99662306a36Sopenharmony_ci */ 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_cistatic enum skb_drop_reason icmp_echo(struct sk_buff *skb) 99962306a36Sopenharmony_ci{ 100062306a36Sopenharmony_ci struct icmp_bxm icmp_param; 100162306a36Sopenharmony_ci struct net *net; 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci net = dev_net(skb_dst(skb)->dev); 100462306a36Sopenharmony_ci /* should there be an ICMP stat for ignored echos? */ 100562306a36Sopenharmony_ci if (READ_ONCE(net->ipv4.sysctl_icmp_echo_ignore_all)) 100662306a36Sopenharmony_ci return SKB_NOT_DROPPED_YET; 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci icmp_param.data.icmph = *icmp_hdr(skb); 100962306a36Sopenharmony_ci icmp_param.skb = skb; 101062306a36Sopenharmony_ci icmp_param.offset = 0; 101162306a36Sopenharmony_ci icmp_param.data_len = skb->len; 101262306a36Sopenharmony_ci icmp_param.head_len = sizeof(struct icmphdr); 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci if (icmp_param.data.icmph.type == ICMP_ECHO) 101562306a36Sopenharmony_ci icmp_param.data.icmph.type = ICMP_ECHOREPLY; 101662306a36Sopenharmony_ci else if (!icmp_build_probe(skb, &icmp_param.data.icmph)) 101762306a36Sopenharmony_ci return SKB_NOT_DROPPED_YET; 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci icmp_reply(&icmp_param, skb); 102062306a36Sopenharmony_ci return SKB_NOT_DROPPED_YET; 102162306a36Sopenharmony_ci} 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci/* Helper for icmp_echo and icmpv6_echo_reply. 102462306a36Sopenharmony_ci * Searches for net_device that matches PROBE interface identifier 102562306a36Sopenharmony_ci * and builds PROBE reply message in icmphdr. 102662306a36Sopenharmony_ci * 102762306a36Sopenharmony_ci * Returns false if PROBE responses are disabled via sysctl 102862306a36Sopenharmony_ci */ 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_cibool icmp_build_probe(struct sk_buff *skb, struct icmphdr *icmphdr) 103162306a36Sopenharmony_ci{ 103262306a36Sopenharmony_ci struct icmp_ext_hdr *ext_hdr, _ext_hdr; 103362306a36Sopenharmony_ci struct icmp_ext_echo_iio *iio, _iio; 103462306a36Sopenharmony_ci struct net *net = dev_net(skb->dev); 103562306a36Sopenharmony_ci struct net_device *dev; 103662306a36Sopenharmony_ci char buff[IFNAMSIZ]; 103762306a36Sopenharmony_ci u16 ident_len; 103862306a36Sopenharmony_ci u8 status; 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci if (!READ_ONCE(net->ipv4.sysctl_icmp_echo_enable_probe)) 104162306a36Sopenharmony_ci return false; 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci /* We currently only support probing interfaces on the proxy node 104462306a36Sopenharmony_ci * Check to ensure L-bit is set 104562306a36Sopenharmony_ci */ 104662306a36Sopenharmony_ci if (!(ntohs(icmphdr->un.echo.sequence) & 1)) 104762306a36Sopenharmony_ci return false; 104862306a36Sopenharmony_ci /* Clear status bits in reply message */ 104962306a36Sopenharmony_ci icmphdr->un.echo.sequence &= htons(0xFF00); 105062306a36Sopenharmony_ci if (icmphdr->type == ICMP_EXT_ECHO) 105162306a36Sopenharmony_ci icmphdr->type = ICMP_EXT_ECHOREPLY; 105262306a36Sopenharmony_ci else 105362306a36Sopenharmony_ci icmphdr->type = ICMPV6_EXT_ECHO_REPLY; 105462306a36Sopenharmony_ci ext_hdr = skb_header_pointer(skb, 0, sizeof(_ext_hdr), &_ext_hdr); 105562306a36Sopenharmony_ci /* Size of iio is class_type dependent. 105662306a36Sopenharmony_ci * Only check header here and assign length based on ctype in the switch statement 105762306a36Sopenharmony_ci */ 105862306a36Sopenharmony_ci iio = skb_header_pointer(skb, sizeof(_ext_hdr), sizeof(iio->extobj_hdr), &_iio); 105962306a36Sopenharmony_ci if (!ext_hdr || !iio) 106062306a36Sopenharmony_ci goto send_mal_query; 106162306a36Sopenharmony_ci if (ntohs(iio->extobj_hdr.length) <= sizeof(iio->extobj_hdr) || 106262306a36Sopenharmony_ci ntohs(iio->extobj_hdr.length) > sizeof(_iio)) 106362306a36Sopenharmony_ci goto send_mal_query; 106462306a36Sopenharmony_ci ident_len = ntohs(iio->extobj_hdr.length) - sizeof(iio->extobj_hdr); 106562306a36Sopenharmony_ci iio = skb_header_pointer(skb, sizeof(_ext_hdr), 106662306a36Sopenharmony_ci sizeof(iio->extobj_hdr) + ident_len, &_iio); 106762306a36Sopenharmony_ci if (!iio) 106862306a36Sopenharmony_ci goto send_mal_query; 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci status = 0; 107162306a36Sopenharmony_ci dev = NULL; 107262306a36Sopenharmony_ci switch (iio->extobj_hdr.class_type) { 107362306a36Sopenharmony_ci case ICMP_EXT_ECHO_CTYPE_NAME: 107462306a36Sopenharmony_ci if (ident_len >= IFNAMSIZ) 107562306a36Sopenharmony_ci goto send_mal_query; 107662306a36Sopenharmony_ci memset(buff, 0, sizeof(buff)); 107762306a36Sopenharmony_ci memcpy(buff, &iio->ident.name, ident_len); 107862306a36Sopenharmony_ci dev = dev_get_by_name(net, buff); 107962306a36Sopenharmony_ci break; 108062306a36Sopenharmony_ci case ICMP_EXT_ECHO_CTYPE_INDEX: 108162306a36Sopenharmony_ci if (ident_len != sizeof(iio->ident.ifindex)) 108262306a36Sopenharmony_ci goto send_mal_query; 108362306a36Sopenharmony_ci dev = dev_get_by_index(net, ntohl(iio->ident.ifindex)); 108462306a36Sopenharmony_ci break; 108562306a36Sopenharmony_ci case ICMP_EXT_ECHO_CTYPE_ADDR: 108662306a36Sopenharmony_ci if (ident_len < sizeof(iio->ident.addr.ctype3_hdr) || 108762306a36Sopenharmony_ci ident_len != sizeof(iio->ident.addr.ctype3_hdr) + 108862306a36Sopenharmony_ci iio->ident.addr.ctype3_hdr.addrlen) 108962306a36Sopenharmony_ci goto send_mal_query; 109062306a36Sopenharmony_ci switch (ntohs(iio->ident.addr.ctype3_hdr.afi)) { 109162306a36Sopenharmony_ci case ICMP_AFI_IP: 109262306a36Sopenharmony_ci if (iio->ident.addr.ctype3_hdr.addrlen != sizeof(struct in_addr)) 109362306a36Sopenharmony_ci goto send_mal_query; 109462306a36Sopenharmony_ci dev = ip_dev_find(net, iio->ident.addr.ip_addr.ipv4_addr); 109562306a36Sopenharmony_ci break; 109662306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 109762306a36Sopenharmony_ci case ICMP_AFI_IP6: 109862306a36Sopenharmony_ci if (iio->ident.addr.ctype3_hdr.addrlen != sizeof(struct in6_addr)) 109962306a36Sopenharmony_ci goto send_mal_query; 110062306a36Sopenharmony_ci dev = ipv6_stub->ipv6_dev_find(net, &iio->ident.addr.ip_addr.ipv6_addr, dev); 110162306a36Sopenharmony_ci dev_hold(dev); 110262306a36Sopenharmony_ci break; 110362306a36Sopenharmony_ci#endif 110462306a36Sopenharmony_ci default: 110562306a36Sopenharmony_ci goto send_mal_query; 110662306a36Sopenharmony_ci } 110762306a36Sopenharmony_ci break; 110862306a36Sopenharmony_ci default: 110962306a36Sopenharmony_ci goto send_mal_query; 111062306a36Sopenharmony_ci } 111162306a36Sopenharmony_ci if (!dev) { 111262306a36Sopenharmony_ci icmphdr->code = ICMP_EXT_CODE_NO_IF; 111362306a36Sopenharmony_ci return true; 111462306a36Sopenharmony_ci } 111562306a36Sopenharmony_ci /* Fill bits in reply message */ 111662306a36Sopenharmony_ci if (dev->flags & IFF_UP) 111762306a36Sopenharmony_ci status |= ICMP_EXT_ECHOREPLY_ACTIVE; 111862306a36Sopenharmony_ci if (__in_dev_get_rcu(dev) && __in_dev_get_rcu(dev)->ifa_list) 111962306a36Sopenharmony_ci status |= ICMP_EXT_ECHOREPLY_IPV4; 112062306a36Sopenharmony_ci if (!list_empty(&rcu_dereference(dev->ip6_ptr)->addr_list)) 112162306a36Sopenharmony_ci status |= ICMP_EXT_ECHOREPLY_IPV6; 112262306a36Sopenharmony_ci dev_put(dev); 112362306a36Sopenharmony_ci icmphdr->un.echo.sequence |= htons(status); 112462306a36Sopenharmony_ci return true; 112562306a36Sopenharmony_cisend_mal_query: 112662306a36Sopenharmony_ci icmphdr->code = ICMP_EXT_CODE_MAL_QUERY; 112762306a36Sopenharmony_ci return true; 112862306a36Sopenharmony_ci} 112962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(icmp_build_probe); 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci/* 113262306a36Sopenharmony_ci * Handle ICMP Timestamp requests. 113362306a36Sopenharmony_ci * RFC 1122: 3.2.2.8 MAY implement ICMP timestamp requests. 113462306a36Sopenharmony_ci * SHOULD be in the kernel for minimum random latency. 113562306a36Sopenharmony_ci * MUST be accurate to a few minutes. 113662306a36Sopenharmony_ci * MUST be updated at least at 15Hz. 113762306a36Sopenharmony_ci */ 113862306a36Sopenharmony_cistatic enum skb_drop_reason icmp_timestamp(struct sk_buff *skb) 113962306a36Sopenharmony_ci{ 114062306a36Sopenharmony_ci struct icmp_bxm icmp_param; 114162306a36Sopenharmony_ci /* 114262306a36Sopenharmony_ci * Too short. 114362306a36Sopenharmony_ci */ 114462306a36Sopenharmony_ci if (skb->len < 4) 114562306a36Sopenharmony_ci goto out_err; 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci /* 114862306a36Sopenharmony_ci * Fill in the current time as ms since midnight UT: 114962306a36Sopenharmony_ci */ 115062306a36Sopenharmony_ci icmp_param.data.times[1] = inet_current_timestamp(); 115162306a36Sopenharmony_ci icmp_param.data.times[2] = icmp_param.data.times[1]; 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci BUG_ON(skb_copy_bits(skb, 0, &icmp_param.data.times[0], 4)); 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci icmp_param.data.icmph = *icmp_hdr(skb); 115662306a36Sopenharmony_ci icmp_param.data.icmph.type = ICMP_TIMESTAMPREPLY; 115762306a36Sopenharmony_ci icmp_param.data.icmph.code = 0; 115862306a36Sopenharmony_ci icmp_param.skb = skb; 115962306a36Sopenharmony_ci icmp_param.offset = 0; 116062306a36Sopenharmony_ci icmp_param.data_len = 0; 116162306a36Sopenharmony_ci icmp_param.head_len = sizeof(struct icmphdr) + 12; 116262306a36Sopenharmony_ci icmp_reply(&icmp_param, skb); 116362306a36Sopenharmony_ci return SKB_NOT_DROPPED_YET; 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ciout_err: 116662306a36Sopenharmony_ci __ICMP_INC_STATS(dev_net(skb_dst(skb)->dev), ICMP_MIB_INERRORS); 116762306a36Sopenharmony_ci return SKB_DROP_REASON_PKT_TOO_SMALL; 116862306a36Sopenharmony_ci} 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_cistatic enum skb_drop_reason icmp_discard(struct sk_buff *skb) 117162306a36Sopenharmony_ci{ 117262306a36Sopenharmony_ci /* pretend it was a success */ 117362306a36Sopenharmony_ci return SKB_NOT_DROPPED_YET; 117462306a36Sopenharmony_ci} 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci/* 117762306a36Sopenharmony_ci * Deal with incoming ICMP packets. 117862306a36Sopenharmony_ci */ 117962306a36Sopenharmony_ciint icmp_rcv(struct sk_buff *skb) 118062306a36Sopenharmony_ci{ 118162306a36Sopenharmony_ci enum skb_drop_reason reason = SKB_DROP_REASON_NOT_SPECIFIED; 118262306a36Sopenharmony_ci struct rtable *rt = skb_rtable(skb); 118362306a36Sopenharmony_ci struct net *net = dev_net(rt->dst.dev); 118462306a36Sopenharmony_ci struct icmphdr *icmph; 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) { 118762306a36Sopenharmony_ci struct sec_path *sp = skb_sec_path(skb); 118862306a36Sopenharmony_ci int nh; 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci if (!(sp && sp->xvec[sp->len - 1]->props.flags & 119162306a36Sopenharmony_ci XFRM_STATE_ICMP)) { 119262306a36Sopenharmony_ci reason = SKB_DROP_REASON_XFRM_POLICY; 119362306a36Sopenharmony_ci goto drop; 119462306a36Sopenharmony_ci } 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci if (!pskb_may_pull(skb, sizeof(*icmph) + sizeof(struct iphdr))) 119762306a36Sopenharmony_ci goto drop; 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci nh = skb_network_offset(skb); 120062306a36Sopenharmony_ci skb_set_network_header(skb, sizeof(*icmph)); 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci if (!xfrm4_policy_check_reverse(NULL, XFRM_POLICY_IN, 120362306a36Sopenharmony_ci skb)) { 120462306a36Sopenharmony_ci reason = SKB_DROP_REASON_XFRM_POLICY; 120562306a36Sopenharmony_ci goto drop; 120662306a36Sopenharmony_ci } 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci skb_set_network_header(skb, nh); 120962306a36Sopenharmony_ci } 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci __ICMP_INC_STATS(net, ICMP_MIB_INMSGS); 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci if (skb_checksum_simple_validate(skb)) 121462306a36Sopenharmony_ci goto csum_error; 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_ci if (!pskb_pull(skb, sizeof(*icmph))) 121762306a36Sopenharmony_ci goto error; 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci icmph = icmp_hdr(skb); 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci ICMPMSGIN_INC_STATS(net, icmph->type); 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci /* Check for ICMP Extended Echo (PROBE) messages */ 122462306a36Sopenharmony_ci if (icmph->type == ICMP_EXT_ECHO) { 122562306a36Sopenharmony_ci /* We can't use icmp_pointers[].handler() because it is an array of 122662306a36Sopenharmony_ci * size NR_ICMP_TYPES + 1 (19 elements) and PROBE has code 42. 122762306a36Sopenharmony_ci */ 122862306a36Sopenharmony_ci reason = icmp_echo(skb); 122962306a36Sopenharmony_ci goto reason_check; 123062306a36Sopenharmony_ci } 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci if (icmph->type == ICMP_EXT_ECHOREPLY) { 123362306a36Sopenharmony_ci reason = ping_rcv(skb); 123462306a36Sopenharmony_ci goto reason_check; 123562306a36Sopenharmony_ci } 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci /* 123862306a36Sopenharmony_ci * 18 is the highest 'known' ICMP type. Anything else is a mystery 123962306a36Sopenharmony_ci * 124062306a36Sopenharmony_ci * RFC 1122: 3.2.2 Unknown ICMP messages types MUST be silently 124162306a36Sopenharmony_ci * discarded. 124262306a36Sopenharmony_ci */ 124362306a36Sopenharmony_ci if (icmph->type > NR_ICMP_TYPES) { 124462306a36Sopenharmony_ci reason = SKB_DROP_REASON_UNHANDLED_PROTO; 124562306a36Sopenharmony_ci goto error; 124662306a36Sopenharmony_ci } 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci /* 124962306a36Sopenharmony_ci * Parse the ICMP message 125062306a36Sopenharmony_ci */ 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci if (rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) { 125362306a36Sopenharmony_ci /* 125462306a36Sopenharmony_ci * RFC 1122: 3.2.2.6 An ICMP_ECHO to broadcast MAY be 125562306a36Sopenharmony_ci * silently ignored (we let user decide with a sysctl). 125662306a36Sopenharmony_ci * RFC 1122: 3.2.2.8 An ICMP_TIMESTAMP MAY be silently 125762306a36Sopenharmony_ci * discarded if to broadcast/multicast. 125862306a36Sopenharmony_ci */ 125962306a36Sopenharmony_ci if ((icmph->type == ICMP_ECHO || 126062306a36Sopenharmony_ci icmph->type == ICMP_TIMESTAMP) && 126162306a36Sopenharmony_ci READ_ONCE(net->ipv4.sysctl_icmp_echo_ignore_broadcasts)) { 126262306a36Sopenharmony_ci reason = SKB_DROP_REASON_INVALID_PROTO; 126362306a36Sopenharmony_ci goto error; 126462306a36Sopenharmony_ci } 126562306a36Sopenharmony_ci if (icmph->type != ICMP_ECHO && 126662306a36Sopenharmony_ci icmph->type != ICMP_TIMESTAMP && 126762306a36Sopenharmony_ci icmph->type != ICMP_ADDRESS && 126862306a36Sopenharmony_ci icmph->type != ICMP_ADDRESSREPLY) { 126962306a36Sopenharmony_ci reason = SKB_DROP_REASON_INVALID_PROTO; 127062306a36Sopenharmony_ci goto error; 127162306a36Sopenharmony_ci } 127262306a36Sopenharmony_ci } 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci reason = icmp_pointers[icmph->type].handler(skb); 127562306a36Sopenharmony_cireason_check: 127662306a36Sopenharmony_ci if (!reason) { 127762306a36Sopenharmony_ci consume_skb(skb); 127862306a36Sopenharmony_ci return NET_RX_SUCCESS; 127962306a36Sopenharmony_ci } 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_cidrop: 128262306a36Sopenharmony_ci kfree_skb_reason(skb, reason); 128362306a36Sopenharmony_ci return NET_RX_DROP; 128462306a36Sopenharmony_cicsum_error: 128562306a36Sopenharmony_ci reason = SKB_DROP_REASON_ICMP_CSUM; 128662306a36Sopenharmony_ci __ICMP_INC_STATS(net, ICMP_MIB_CSUMERRORS); 128762306a36Sopenharmony_cierror: 128862306a36Sopenharmony_ci __ICMP_INC_STATS(net, ICMP_MIB_INERRORS); 128962306a36Sopenharmony_ci goto drop; 129062306a36Sopenharmony_ci} 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_cistatic bool ip_icmp_error_rfc4884_validate(const struct sk_buff *skb, int off) 129362306a36Sopenharmony_ci{ 129462306a36Sopenharmony_ci struct icmp_extobj_hdr *objh, _objh; 129562306a36Sopenharmony_ci struct icmp_ext_hdr *exth, _exth; 129662306a36Sopenharmony_ci u16 olen; 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ci exth = skb_header_pointer(skb, off, sizeof(_exth), &_exth); 129962306a36Sopenharmony_ci if (!exth) 130062306a36Sopenharmony_ci return false; 130162306a36Sopenharmony_ci if (exth->version != 2) 130262306a36Sopenharmony_ci return true; 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci if (exth->checksum && 130562306a36Sopenharmony_ci csum_fold(skb_checksum(skb, off, skb->len - off, 0))) 130662306a36Sopenharmony_ci return false; 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci off += sizeof(_exth); 130962306a36Sopenharmony_ci while (off < skb->len) { 131062306a36Sopenharmony_ci objh = skb_header_pointer(skb, off, sizeof(_objh), &_objh); 131162306a36Sopenharmony_ci if (!objh) 131262306a36Sopenharmony_ci return false; 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci olen = ntohs(objh->length); 131562306a36Sopenharmony_ci if (olen < sizeof(_objh)) 131662306a36Sopenharmony_ci return false; 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci off += olen; 131962306a36Sopenharmony_ci if (off > skb->len) 132062306a36Sopenharmony_ci return false; 132162306a36Sopenharmony_ci } 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_ci return true; 132462306a36Sopenharmony_ci} 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_civoid ip_icmp_error_rfc4884(const struct sk_buff *skb, 132762306a36Sopenharmony_ci struct sock_ee_data_rfc4884 *out, 132862306a36Sopenharmony_ci int thlen, int off) 132962306a36Sopenharmony_ci{ 133062306a36Sopenharmony_ci int hlen; 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_ci /* original datagram headers: end of icmph to payload (skb->data) */ 133362306a36Sopenharmony_ci hlen = -skb_transport_offset(skb) - thlen; 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci /* per rfc 4884: minimal datagram length of 128 bytes */ 133662306a36Sopenharmony_ci if (off < 128 || off < hlen) 133762306a36Sopenharmony_ci return; 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_ci /* kernel has stripped headers: return payload offset in bytes */ 134062306a36Sopenharmony_ci off -= hlen; 134162306a36Sopenharmony_ci if (off + sizeof(struct icmp_ext_hdr) > skb->len) 134262306a36Sopenharmony_ci return; 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_ci out->len = off; 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ci if (!ip_icmp_error_rfc4884_validate(skb, off)) 134762306a36Sopenharmony_ci out->flags |= SO_EE_RFC4884_FLAG_INVALID; 134862306a36Sopenharmony_ci} 134962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ip_icmp_error_rfc4884); 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ciint icmp_err(struct sk_buff *skb, u32 info) 135262306a36Sopenharmony_ci{ 135362306a36Sopenharmony_ci struct iphdr *iph = (struct iphdr *)skb->data; 135462306a36Sopenharmony_ci int offset = iph->ihl<<2; 135562306a36Sopenharmony_ci struct icmphdr *icmph = (struct icmphdr *)(skb->data + offset); 135662306a36Sopenharmony_ci int type = icmp_hdr(skb)->type; 135762306a36Sopenharmony_ci int code = icmp_hdr(skb)->code; 135862306a36Sopenharmony_ci struct net *net = dev_net(skb->dev); 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci /* 136162306a36Sopenharmony_ci * Use ping_err to handle all icmp errors except those 136262306a36Sopenharmony_ci * triggered by ICMP_ECHOREPLY which sent from kernel. 136362306a36Sopenharmony_ci */ 136462306a36Sopenharmony_ci if (icmph->type != ICMP_ECHOREPLY) { 136562306a36Sopenharmony_ci ping_err(skb, offset, info); 136662306a36Sopenharmony_ci return 0; 136762306a36Sopenharmony_ci } 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) 137062306a36Sopenharmony_ci ipv4_update_pmtu(skb, net, info, 0, IPPROTO_ICMP); 137162306a36Sopenharmony_ci else if (type == ICMP_REDIRECT) 137262306a36Sopenharmony_ci ipv4_redirect(skb, net, 0, IPPROTO_ICMP); 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_ci return 0; 137562306a36Sopenharmony_ci} 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_ci/* 137862306a36Sopenharmony_ci * This table is the definition of how we handle ICMP. 137962306a36Sopenharmony_ci */ 138062306a36Sopenharmony_cistatic const struct icmp_control icmp_pointers[NR_ICMP_TYPES + 1] = { 138162306a36Sopenharmony_ci [ICMP_ECHOREPLY] = { 138262306a36Sopenharmony_ci .handler = ping_rcv, 138362306a36Sopenharmony_ci }, 138462306a36Sopenharmony_ci [1] = { 138562306a36Sopenharmony_ci .handler = icmp_discard, 138662306a36Sopenharmony_ci .error = 1, 138762306a36Sopenharmony_ci }, 138862306a36Sopenharmony_ci [2] = { 138962306a36Sopenharmony_ci .handler = icmp_discard, 139062306a36Sopenharmony_ci .error = 1, 139162306a36Sopenharmony_ci }, 139262306a36Sopenharmony_ci [ICMP_DEST_UNREACH] = { 139362306a36Sopenharmony_ci .handler = icmp_unreach, 139462306a36Sopenharmony_ci .error = 1, 139562306a36Sopenharmony_ci }, 139662306a36Sopenharmony_ci [ICMP_SOURCE_QUENCH] = { 139762306a36Sopenharmony_ci .handler = icmp_unreach, 139862306a36Sopenharmony_ci .error = 1, 139962306a36Sopenharmony_ci }, 140062306a36Sopenharmony_ci [ICMP_REDIRECT] = { 140162306a36Sopenharmony_ci .handler = icmp_redirect, 140262306a36Sopenharmony_ci .error = 1, 140362306a36Sopenharmony_ci }, 140462306a36Sopenharmony_ci [6] = { 140562306a36Sopenharmony_ci .handler = icmp_discard, 140662306a36Sopenharmony_ci .error = 1, 140762306a36Sopenharmony_ci }, 140862306a36Sopenharmony_ci [7] = { 140962306a36Sopenharmony_ci .handler = icmp_discard, 141062306a36Sopenharmony_ci .error = 1, 141162306a36Sopenharmony_ci }, 141262306a36Sopenharmony_ci [ICMP_ECHO] = { 141362306a36Sopenharmony_ci .handler = icmp_echo, 141462306a36Sopenharmony_ci }, 141562306a36Sopenharmony_ci [9] = { 141662306a36Sopenharmony_ci .handler = icmp_discard, 141762306a36Sopenharmony_ci .error = 1, 141862306a36Sopenharmony_ci }, 141962306a36Sopenharmony_ci [10] = { 142062306a36Sopenharmony_ci .handler = icmp_discard, 142162306a36Sopenharmony_ci .error = 1, 142262306a36Sopenharmony_ci }, 142362306a36Sopenharmony_ci [ICMP_TIME_EXCEEDED] = { 142462306a36Sopenharmony_ci .handler = icmp_unreach, 142562306a36Sopenharmony_ci .error = 1, 142662306a36Sopenharmony_ci }, 142762306a36Sopenharmony_ci [ICMP_PARAMETERPROB] = { 142862306a36Sopenharmony_ci .handler = icmp_unreach, 142962306a36Sopenharmony_ci .error = 1, 143062306a36Sopenharmony_ci }, 143162306a36Sopenharmony_ci [ICMP_TIMESTAMP] = { 143262306a36Sopenharmony_ci .handler = icmp_timestamp, 143362306a36Sopenharmony_ci }, 143462306a36Sopenharmony_ci [ICMP_TIMESTAMPREPLY] = { 143562306a36Sopenharmony_ci .handler = icmp_discard, 143662306a36Sopenharmony_ci }, 143762306a36Sopenharmony_ci [ICMP_INFO_REQUEST] = { 143862306a36Sopenharmony_ci .handler = icmp_discard, 143962306a36Sopenharmony_ci }, 144062306a36Sopenharmony_ci [ICMP_INFO_REPLY] = { 144162306a36Sopenharmony_ci .handler = icmp_discard, 144262306a36Sopenharmony_ci }, 144362306a36Sopenharmony_ci [ICMP_ADDRESS] = { 144462306a36Sopenharmony_ci .handler = icmp_discard, 144562306a36Sopenharmony_ci }, 144662306a36Sopenharmony_ci [ICMP_ADDRESSREPLY] = { 144762306a36Sopenharmony_ci .handler = icmp_discard, 144862306a36Sopenharmony_ci }, 144962306a36Sopenharmony_ci}; 145062306a36Sopenharmony_ci 145162306a36Sopenharmony_cistatic int __net_init icmp_sk_init(struct net *net) 145262306a36Sopenharmony_ci{ 145362306a36Sopenharmony_ci /* Control parameters for ECHO replies. */ 145462306a36Sopenharmony_ci net->ipv4.sysctl_icmp_echo_ignore_all = 0; 145562306a36Sopenharmony_ci net->ipv4.sysctl_icmp_echo_enable_probe = 0; 145662306a36Sopenharmony_ci net->ipv4.sysctl_icmp_echo_ignore_broadcasts = 1; 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci /* Control parameter - ignore bogus broadcast responses? */ 145962306a36Sopenharmony_ci net->ipv4.sysctl_icmp_ignore_bogus_error_responses = 1; 146062306a36Sopenharmony_ci 146162306a36Sopenharmony_ci /* 146262306a36Sopenharmony_ci * Configurable global rate limit. 146362306a36Sopenharmony_ci * 146462306a36Sopenharmony_ci * ratelimit defines tokens/packet consumed for dst->rate_token 146562306a36Sopenharmony_ci * bucket ratemask defines which icmp types are ratelimited by 146662306a36Sopenharmony_ci * setting it's bit position. 146762306a36Sopenharmony_ci * 146862306a36Sopenharmony_ci * default: 146962306a36Sopenharmony_ci * dest unreachable (3), source quench (4), 147062306a36Sopenharmony_ci * time exceeded (11), parameter problem (12) 147162306a36Sopenharmony_ci */ 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_ci net->ipv4.sysctl_icmp_ratelimit = 1 * HZ; 147462306a36Sopenharmony_ci net->ipv4.sysctl_icmp_ratemask = 0x1818; 147562306a36Sopenharmony_ci net->ipv4.sysctl_icmp_errors_use_inbound_ifaddr = 0; 147662306a36Sopenharmony_ci 147762306a36Sopenharmony_ci return 0; 147862306a36Sopenharmony_ci} 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_cistatic struct pernet_operations __net_initdata icmp_sk_ops = { 148162306a36Sopenharmony_ci .init = icmp_sk_init, 148262306a36Sopenharmony_ci}; 148362306a36Sopenharmony_ci 148462306a36Sopenharmony_ciint __init icmp_init(void) 148562306a36Sopenharmony_ci{ 148662306a36Sopenharmony_ci int err, i; 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_ci for_each_possible_cpu(i) { 148962306a36Sopenharmony_ci struct sock *sk; 149062306a36Sopenharmony_ci 149162306a36Sopenharmony_ci err = inet_ctl_sock_create(&sk, PF_INET, 149262306a36Sopenharmony_ci SOCK_RAW, IPPROTO_ICMP, &init_net); 149362306a36Sopenharmony_ci if (err < 0) 149462306a36Sopenharmony_ci return err; 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_ci per_cpu(ipv4_icmp_sk, i) = sk; 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci /* Enough space for 2 64K ICMP packets, including 149962306a36Sopenharmony_ci * sk_buff/skb_shared_info struct overhead. 150062306a36Sopenharmony_ci */ 150162306a36Sopenharmony_ci sk->sk_sndbuf = 2 * SKB_TRUESIZE(64 * 1024); 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci /* 150462306a36Sopenharmony_ci * Speedup sock_wfree() 150562306a36Sopenharmony_ci */ 150662306a36Sopenharmony_ci sock_set_flag(sk, SOCK_USE_WRITE_QUEUE); 150762306a36Sopenharmony_ci inet_sk(sk)->pmtudisc = IP_PMTUDISC_DONT; 150862306a36Sopenharmony_ci } 150962306a36Sopenharmony_ci return register_pernet_subsys(&icmp_sk_ops); 151062306a36Sopenharmony_ci} 1511