18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * NET3: Implementation of the ICMP protocol layer. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Alan Cox, <alan@lxorguk.ukuu.org.uk> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Some of the function names and the icmp unreach table for this 88c2ecf20Sopenharmony_ci * module were derived from [icmp.c 1.0.11 06/02/93] by 98c2ecf20Sopenharmony_ci * Ross Biro, Fred N. van Kempen, Mark Evans, Alan Cox, Gerhard Koerting. 108c2ecf20Sopenharmony_ci * Other than that this module is a complete rewrite. 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Fixes: 138c2ecf20Sopenharmony_ci * Clemens Fruhwirth : introduce global icmp rate limiting 148c2ecf20Sopenharmony_ci * with icmp type masking ability instead 158c2ecf20Sopenharmony_ci * of broken per type icmp timeouts. 168c2ecf20Sopenharmony_ci * Mike Shaver : RFC1122 checks. 178c2ecf20Sopenharmony_ci * Alan Cox : Multicast ping reply as self. 188c2ecf20Sopenharmony_ci * Alan Cox : Fix atomicity lockup in ip_build_xmit 198c2ecf20Sopenharmony_ci * call. 208c2ecf20Sopenharmony_ci * Alan Cox : Added 216,128 byte paths to the MTU 218c2ecf20Sopenharmony_ci * code. 228c2ecf20Sopenharmony_ci * Martin Mares : RFC1812 checks. 238c2ecf20Sopenharmony_ci * Martin Mares : Can be configured to follow redirects 248c2ecf20Sopenharmony_ci * if acting as a router _without_ a 258c2ecf20Sopenharmony_ci * routing protocol (RFC 1812). 268c2ecf20Sopenharmony_ci * Martin Mares : Echo requests may be configured to 278c2ecf20Sopenharmony_ci * be ignored (RFC 1812). 288c2ecf20Sopenharmony_ci * Martin Mares : Limitation of ICMP error message 298c2ecf20Sopenharmony_ci * transmit rate (RFC 1812). 308c2ecf20Sopenharmony_ci * Martin Mares : TOS and Precedence set correctly 318c2ecf20Sopenharmony_ci * (RFC 1812). 328c2ecf20Sopenharmony_ci * Martin Mares : Now copying as much data from the 338c2ecf20Sopenharmony_ci * original packet as we can without 348c2ecf20Sopenharmony_ci * exceeding 576 bytes (RFC 1812). 358c2ecf20Sopenharmony_ci * Willy Konynenberg : Transparent proxying support. 368c2ecf20Sopenharmony_ci * Keith Owens : RFC1191 correction for 4.2BSD based 378c2ecf20Sopenharmony_ci * path MTU bug. 388c2ecf20Sopenharmony_ci * Thomas Quinot : ICMP Dest Unreach codes up to 15 are 398c2ecf20Sopenharmony_ci * valid (RFC 1812). 408c2ecf20Sopenharmony_ci * Andi Kleen : Check all packet lengths properly 418c2ecf20Sopenharmony_ci * and moved all kfree_skb() up to 428c2ecf20Sopenharmony_ci * icmp_rcv. 438c2ecf20Sopenharmony_ci * Andi Kleen : Move the rate limit bookkeeping 448c2ecf20Sopenharmony_ci * into the dest entry and use a token 458c2ecf20Sopenharmony_ci * bucket filter (thanks to ANK). Make 468c2ecf20Sopenharmony_ci * the rates sysctl configurable. 478c2ecf20Sopenharmony_ci * Yu Tianli : Fixed two ugly bugs in icmp_send 488c2ecf20Sopenharmony_ci * - IP option length was accounted wrongly 498c2ecf20Sopenharmony_ci * - ICMP header length was not accounted 508c2ecf20Sopenharmony_ci * at all. 518c2ecf20Sopenharmony_ci * Tristan Greaves : Added sysctl option to ignore bogus 528c2ecf20Sopenharmony_ci * broadcast responses from broken routers. 538c2ecf20Sopenharmony_ci * 548c2ecf20Sopenharmony_ci * To Fix: 558c2ecf20Sopenharmony_ci * 568c2ecf20Sopenharmony_ci * - Should use skb_pull() instead of all the manual checking. 578c2ecf20Sopenharmony_ci * This would also greatly simply some upper layer error handlers. --AK 588c2ecf20Sopenharmony_ci */ 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci#include <linux/module.h> 638c2ecf20Sopenharmony_ci#include <linux/types.h> 648c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 658c2ecf20Sopenharmony_ci#include <linux/kernel.h> 668c2ecf20Sopenharmony_ci#include <linux/fcntl.h> 678c2ecf20Sopenharmony_ci#include <linux/socket.h> 688c2ecf20Sopenharmony_ci#include <linux/in.h> 698c2ecf20Sopenharmony_ci#include <linux/inet.h> 708c2ecf20Sopenharmony_ci#include <linux/inetdevice.h> 718c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 728c2ecf20Sopenharmony_ci#include <linux/string.h> 738c2ecf20Sopenharmony_ci#include <linux/netfilter_ipv4.h> 748c2ecf20Sopenharmony_ci#include <linux/slab.h> 758c2ecf20Sopenharmony_ci#include <net/snmp.h> 768c2ecf20Sopenharmony_ci#include <net/ip.h> 778c2ecf20Sopenharmony_ci#include <net/route.h> 788c2ecf20Sopenharmony_ci#include <net/protocol.h> 798c2ecf20Sopenharmony_ci#include <net/icmp.h> 808c2ecf20Sopenharmony_ci#include <net/tcp.h> 818c2ecf20Sopenharmony_ci#include <net/udp.h> 828c2ecf20Sopenharmony_ci#include <net/raw.h> 838c2ecf20Sopenharmony_ci#include <net/ping.h> 848c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 858c2ecf20Sopenharmony_ci#include <net/sock.h> 868c2ecf20Sopenharmony_ci#include <linux/errno.h> 878c2ecf20Sopenharmony_ci#include <linux/timer.h> 888c2ecf20Sopenharmony_ci#include <linux/init.h> 898c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 908c2ecf20Sopenharmony_ci#include <net/checksum.h> 918c2ecf20Sopenharmony_ci#include <net/xfrm.h> 928c2ecf20Sopenharmony_ci#include <net/inet_common.h> 938c2ecf20Sopenharmony_ci#include <net/ip_fib.h> 948c2ecf20Sopenharmony_ci#include <net/l3mdev.h> 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci/* 978c2ecf20Sopenharmony_ci * Build xmit assembly blocks 988c2ecf20Sopenharmony_ci */ 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistruct icmp_bxm { 1018c2ecf20Sopenharmony_ci struct sk_buff *skb; 1028c2ecf20Sopenharmony_ci int offset; 1038c2ecf20Sopenharmony_ci int data_len; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci struct { 1068c2ecf20Sopenharmony_ci struct icmphdr icmph; 1078c2ecf20Sopenharmony_ci __be32 times[3]; 1088c2ecf20Sopenharmony_ci } data; 1098c2ecf20Sopenharmony_ci int head_len; 1108c2ecf20Sopenharmony_ci struct ip_options_data replyopts; 1118c2ecf20Sopenharmony_ci}; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci/* An array of errno for error messages from dest unreach. */ 1148c2ecf20Sopenharmony_ci/* RFC 1122: 3.2.2.1 States that NET_UNREACH, HOST_UNREACH and SR_FAILED MUST be considered 'transient errs'. */ 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ciconst struct icmp_err icmp_err_convert[] = { 1178c2ecf20Sopenharmony_ci { 1188c2ecf20Sopenharmony_ci .errno = ENETUNREACH, /* ICMP_NET_UNREACH */ 1198c2ecf20Sopenharmony_ci .fatal = 0, 1208c2ecf20Sopenharmony_ci }, 1218c2ecf20Sopenharmony_ci { 1228c2ecf20Sopenharmony_ci .errno = EHOSTUNREACH, /* ICMP_HOST_UNREACH */ 1238c2ecf20Sopenharmony_ci .fatal = 0, 1248c2ecf20Sopenharmony_ci }, 1258c2ecf20Sopenharmony_ci { 1268c2ecf20Sopenharmony_ci .errno = ENOPROTOOPT /* ICMP_PROT_UNREACH */, 1278c2ecf20Sopenharmony_ci .fatal = 1, 1288c2ecf20Sopenharmony_ci }, 1298c2ecf20Sopenharmony_ci { 1308c2ecf20Sopenharmony_ci .errno = ECONNREFUSED, /* ICMP_PORT_UNREACH */ 1318c2ecf20Sopenharmony_ci .fatal = 1, 1328c2ecf20Sopenharmony_ci }, 1338c2ecf20Sopenharmony_ci { 1348c2ecf20Sopenharmony_ci .errno = EMSGSIZE, /* ICMP_FRAG_NEEDED */ 1358c2ecf20Sopenharmony_ci .fatal = 0, 1368c2ecf20Sopenharmony_ci }, 1378c2ecf20Sopenharmony_ci { 1388c2ecf20Sopenharmony_ci .errno = EOPNOTSUPP, /* ICMP_SR_FAILED */ 1398c2ecf20Sopenharmony_ci .fatal = 0, 1408c2ecf20Sopenharmony_ci }, 1418c2ecf20Sopenharmony_ci { 1428c2ecf20Sopenharmony_ci .errno = ENETUNREACH, /* ICMP_NET_UNKNOWN */ 1438c2ecf20Sopenharmony_ci .fatal = 1, 1448c2ecf20Sopenharmony_ci }, 1458c2ecf20Sopenharmony_ci { 1468c2ecf20Sopenharmony_ci .errno = EHOSTDOWN, /* ICMP_HOST_UNKNOWN */ 1478c2ecf20Sopenharmony_ci .fatal = 1, 1488c2ecf20Sopenharmony_ci }, 1498c2ecf20Sopenharmony_ci { 1508c2ecf20Sopenharmony_ci .errno = ENONET, /* ICMP_HOST_ISOLATED */ 1518c2ecf20Sopenharmony_ci .fatal = 1, 1528c2ecf20Sopenharmony_ci }, 1538c2ecf20Sopenharmony_ci { 1548c2ecf20Sopenharmony_ci .errno = ENETUNREACH, /* ICMP_NET_ANO */ 1558c2ecf20Sopenharmony_ci .fatal = 1, 1568c2ecf20Sopenharmony_ci }, 1578c2ecf20Sopenharmony_ci { 1588c2ecf20Sopenharmony_ci .errno = EHOSTUNREACH, /* ICMP_HOST_ANO */ 1598c2ecf20Sopenharmony_ci .fatal = 1, 1608c2ecf20Sopenharmony_ci }, 1618c2ecf20Sopenharmony_ci { 1628c2ecf20Sopenharmony_ci .errno = ENETUNREACH, /* ICMP_NET_UNR_TOS */ 1638c2ecf20Sopenharmony_ci .fatal = 0, 1648c2ecf20Sopenharmony_ci }, 1658c2ecf20Sopenharmony_ci { 1668c2ecf20Sopenharmony_ci .errno = EHOSTUNREACH, /* ICMP_HOST_UNR_TOS */ 1678c2ecf20Sopenharmony_ci .fatal = 0, 1688c2ecf20Sopenharmony_ci }, 1698c2ecf20Sopenharmony_ci { 1708c2ecf20Sopenharmony_ci .errno = EHOSTUNREACH, /* ICMP_PKT_FILTERED */ 1718c2ecf20Sopenharmony_ci .fatal = 1, 1728c2ecf20Sopenharmony_ci }, 1738c2ecf20Sopenharmony_ci { 1748c2ecf20Sopenharmony_ci .errno = EHOSTUNREACH, /* ICMP_PREC_VIOLATION */ 1758c2ecf20Sopenharmony_ci .fatal = 1, 1768c2ecf20Sopenharmony_ci }, 1778c2ecf20Sopenharmony_ci { 1788c2ecf20Sopenharmony_ci .errno = EHOSTUNREACH, /* ICMP_PREC_CUTOFF */ 1798c2ecf20Sopenharmony_ci .fatal = 1, 1808c2ecf20Sopenharmony_ci }, 1818c2ecf20Sopenharmony_ci}; 1828c2ecf20Sopenharmony_ciEXPORT_SYMBOL(icmp_err_convert); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci/* 1858c2ecf20Sopenharmony_ci * ICMP control array. This specifies what to do with each ICMP. 1868c2ecf20Sopenharmony_ci */ 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistruct icmp_control { 1898c2ecf20Sopenharmony_ci bool (*handler)(struct sk_buff *skb); 1908c2ecf20Sopenharmony_ci short error; /* This ICMP is classed as an error message */ 1918c2ecf20Sopenharmony_ci}; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_cistatic const struct icmp_control icmp_pointers[NR_ICMP_TYPES+1]; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci/* 1968c2ecf20Sopenharmony_ci * The ICMP socket(s). This is the most convenient way to flow control 1978c2ecf20Sopenharmony_ci * our ICMP output as well as maintain a clean interface throughout 1988c2ecf20Sopenharmony_ci * all layers. All Socketless IP sends will soon be gone. 1998c2ecf20Sopenharmony_ci * 2008c2ecf20Sopenharmony_ci * On SMP we have one ICMP socket per-cpu. 2018c2ecf20Sopenharmony_ci */ 2028c2ecf20Sopenharmony_cistatic struct sock *icmp_sk(struct net *net) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci return this_cpu_read(*net->ipv4.icmp_sk); 2058c2ecf20Sopenharmony_ci} 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci/* Called with BH disabled */ 2088c2ecf20Sopenharmony_cistatic inline struct sock *icmp_xmit_lock(struct net *net) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci struct sock *sk; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci sk = icmp_sk(net); 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci if (unlikely(!spin_trylock(&sk->sk_lock.slock))) { 2158c2ecf20Sopenharmony_ci /* This can happen if the output path signals a 2168c2ecf20Sopenharmony_ci * dst_link_failure() for an outgoing ICMP packet. 2178c2ecf20Sopenharmony_ci */ 2188c2ecf20Sopenharmony_ci return NULL; 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci return sk; 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_cistatic inline void icmp_xmit_unlock(struct sock *sk) 2248c2ecf20Sopenharmony_ci{ 2258c2ecf20Sopenharmony_ci spin_unlock(&sk->sk_lock.slock); 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ciint sysctl_icmp_msgs_per_sec __read_mostly = 1000; 2298c2ecf20Sopenharmony_ciint sysctl_icmp_msgs_burst __read_mostly = 50; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_cistatic struct { 2328c2ecf20Sopenharmony_ci spinlock_t lock; 2338c2ecf20Sopenharmony_ci u32 credit; 2348c2ecf20Sopenharmony_ci u32 stamp; 2358c2ecf20Sopenharmony_ci} icmp_global = { 2368c2ecf20Sopenharmony_ci .lock = __SPIN_LOCK_UNLOCKED(icmp_global.lock), 2378c2ecf20Sopenharmony_ci}; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci/** 2408c2ecf20Sopenharmony_ci * icmp_global_allow - Are we allowed to send one more ICMP message ? 2418c2ecf20Sopenharmony_ci * 2428c2ecf20Sopenharmony_ci * Uses a token bucket to limit our ICMP messages to ~sysctl_icmp_msgs_per_sec. 2438c2ecf20Sopenharmony_ci * Returns false if we reached the limit and can not send another packet. 2448c2ecf20Sopenharmony_ci * Note: called with BH disabled 2458c2ecf20Sopenharmony_ci */ 2468c2ecf20Sopenharmony_cibool icmp_global_allow(void) 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci u32 credit, delta, incr = 0, now = (u32)jiffies; 2498c2ecf20Sopenharmony_ci bool rc = false; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci /* Check if token bucket is empty and cannot be refilled 2528c2ecf20Sopenharmony_ci * without taking the spinlock. The READ_ONCE() are paired 2538c2ecf20Sopenharmony_ci * with the following WRITE_ONCE() in this same function. 2548c2ecf20Sopenharmony_ci */ 2558c2ecf20Sopenharmony_ci if (!READ_ONCE(icmp_global.credit)) { 2568c2ecf20Sopenharmony_ci delta = min_t(u32, now - READ_ONCE(icmp_global.stamp), HZ); 2578c2ecf20Sopenharmony_ci if (delta < HZ / 50) 2588c2ecf20Sopenharmony_ci return false; 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci spin_lock(&icmp_global.lock); 2628c2ecf20Sopenharmony_ci delta = min_t(u32, now - icmp_global.stamp, HZ); 2638c2ecf20Sopenharmony_ci if (delta >= HZ / 50) { 2648c2ecf20Sopenharmony_ci incr = READ_ONCE(sysctl_icmp_msgs_per_sec) * delta / HZ; 2658c2ecf20Sopenharmony_ci if (incr) 2668c2ecf20Sopenharmony_ci WRITE_ONCE(icmp_global.stamp, now); 2678c2ecf20Sopenharmony_ci } 2688c2ecf20Sopenharmony_ci credit = min_t(u32, icmp_global.credit + incr, 2698c2ecf20Sopenharmony_ci READ_ONCE(sysctl_icmp_msgs_burst)); 2708c2ecf20Sopenharmony_ci if (credit) { 2718c2ecf20Sopenharmony_ci /* We want to use a credit of one in average, but need to randomize 2728c2ecf20Sopenharmony_ci * it for security reasons. 2738c2ecf20Sopenharmony_ci */ 2748c2ecf20Sopenharmony_ci credit = max_t(int, credit - prandom_u32_max(3), 0); 2758c2ecf20Sopenharmony_ci rc = true; 2768c2ecf20Sopenharmony_ci } 2778c2ecf20Sopenharmony_ci WRITE_ONCE(icmp_global.credit, credit); 2788c2ecf20Sopenharmony_ci spin_unlock(&icmp_global.lock); 2798c2ecf20Sopenharmony_ci return rc; 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ciEXPORT_SYMBOL(icmp_global_allow); 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_cistatic bool icmpv4_mask_allow(struct net *net, int type, int code) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci if (type > NR_ICMP_TYPES) 2868c2ecf20Sopenharmony_ci return true; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci /* Don't limit PMTU discovery. */ 2898c2ecf20Sopenharmony_ci if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) 2908c2ecf20Sopenharmony_ci return true; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci /* Limit if icmp type is enabled in ratemask. */ 2938c2ecf20Sopenharmony_ci if (!((1 << type) & READ_ONCE(net->ipv4.sysctl_icmp_ratemask))) 2948c2ecf20Sopenharmony_ci return true; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci return false; 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_cistatic bool icmpv4_global_allow(struct net *net, int type, int code) 3008c2ecf20Sopenharmony_ci{ 3018c2ecf20Sopenharmony_ci if (icmpv4_mask_allow(net, type, code)) 3028c2ecf20Sopenharmony_ci return true; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci if (icmp_global_allow()) 3058c2ecf20Sopenharmony_ci return true; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci return false; 3088c2ecf20Sopenharmony_ci} 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci/* 3118c2ecf20Sopenharmony_ci * Send an ICMP frame. 3128c2ecf20Sopenharmony_ci */ 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_cistatic bool icmpv4_xrlim_allow(struct net *net, struct rtable *rt, 3158c2ecf20Sopenharmony_ci struct flowi4 *fl4, int type, int code) 3168c2ecf20Sopenharmony_ci{ 3178c2ecf20Sopenharmony_ci struct dst_entry *dst = &rt->dst; 3188c2ecf20Sopenharmony_ci struct inet_peer *peer; 3198c2ecf20Sopenharmony_ci bool rc = true; 3208c2ecf20Sopenharmony_ci int vif; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci if (icmpv4_mask_allow(net, type, code)) 3238c2ecf20Sopenharmony_ci goto out; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci /* No rate limit on loopback */ 3268c2ecf20Sopenharmony_ci if (dst->dev && (dst->dev->flags&IFF_LOOPBACK)) 3278c2ecf20Sopenharmony_ci goto out; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci vif = l3mdev_master_ifindex(dst->dev); 3308c2ecf20Sopenharmony_ci peer = inet_getpeer_v4(net->ipv4.peers, fl4->daddr, vif, 1); 3318c2ecf20Sopenharmony_ci rc = inet_peer_xrlim_allow(peer, 3328c2ecf20Sopenharmony_ci READ_ONCE(net->ipv4.sysctl_icmp_ratelimit)); 3338c2ecf20Sopenharmony_ci if (peer) 3348c2ecf20Sopenharmony_ci inet_putpeer(peer); 3358c2ecf20Sopenharmony_ciout: 3368c2ecf20Sopenharmony_ci return rc; 3378c2ecf20Sopenharmony_ci} 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci/* 3408c2ecf20Sopenharmony_ci * Maintain the counters used in the SNMP statistics for outgoing ICMP 3418c2ecf20Sopenharmony_ci */ 3428c2ecf20Sopenharmony_civoid icmp_out_count(struct net *net, unsigned char type) 3438c2ecf20Sopenharmony_ci{ 3448c2ecf20Sopenharmony_ci ICMPMSGOUT_INC_STATS(net, type); 3458c2ecf20Sopenharmony_ci ICMP_INC_STATS(net, ICMP_MIB_OUTMSGS); 3468c2ecf20Sopenharmony_ci} 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci/* 3498c2ecf20Sopenharmony_ci * Checksum each fragment, and on the first include the headers and final 3508c2ecf20Sopenharmony_ci * checksum. 3518c2ecf20Sopenharmony_ci */ 3528c2ecf20Sopenharmony_cistatic int icmp_glue_bits(void *from, char *to, int offset, int len, int odd, 3538c2ecf20Sopenharmony_ci struct sk_buff *skb) 3548c2ecf20Sopenharmony_ci{ 3558c2ecf20Sopenharmony_ci struct icmp_bxm *icmp_param = (struct icmp_bxm *)from; 3568c2ecf20Sopenharmony_ci __wsum csum; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci csum = skb_copy_and_csum_bits(icmp_param->skb, 3598c2ecf20Sopenharmony_ci icmp_param->offset + offset, 3608c2ecf20Sopenharmony_ci to, len); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci skb->csum = csum_block_add(skb->csum, csum, odd); 3638c2ecf20Sopenharmony_ci if (icmp_pointers[icmp_param->data.icmph.type].error) 3648c2ecf20Sopenharmony_ci nf_ct_attach(skb, icmp_param->skb); 3658c2ecf20Sopenharmony_ci return 0; 3668c2ecf20Sopenharmony_ci} 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_cistatic void icmp_push_reply(struct icmp_bxm *icmp_param, 3698c2ecf20Sopenharmony_ci struct flowi4 *fl4, 3708c2ecf20Sopenharmony_ci struct ipcm_cookie *ipc, struct rtable **rt) 3718c2ecf20Sopenharmony_ci{ 3728c2ecf20Sopenharmony_ci struct sock *sk; 3738c2ecf20Sopenharmony_ci struct sk_buff *skb; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci sk = icmp_sk(dev_net((*rt)->dst.dev)); 3768c2ecf20Sopenharmony_ci if (ip_append_data(sk, fl4, icmp_glue_bits, icmp_param, 3778c2ecf20Sopenharmony_ci icmp_param->data_len+icmp_param->head_len, 3788c2ecf20Sopenharmony_ci icmp_param->head_len, 3798c2ecf20Sopenharmony_ci ipc, rt, MSG_DONTWAIT) < 0) { 3808c2ecf20Sopenharmony_ci __ICMP_INC_STATS(sock_net(sk), ICMP_MIB_OUTERRORS); 3818c2ecf20Sopenharmony_ci ip_flush_pending_frames(sk); 3828c2ecf20Sopenharmony_ci } else if ((skb = skb_peek(&sk->sk_write_queue)) != NULL) { 3838c2ecf20Sopenharmony_ci struct icmphdr *icmph = icmp_hdr(skb); 3848c2ecf20Sopenharmony_ci __wsum csum; 3858c2ecf20Sopenharmony_ci struct sk_buff *skb1; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci csum = csum_partial_copy_nocheck((void *)&icmp_param->data, 3888c2ecf20Sopenharmony_ci (char *)icmph, 3898c2ecf20Sopenharmony_ci icmp_param->head_len); 3908c2ecf20Sopenharmony_ci skb_queue_walk(&sk->sk_write_queue, skb1) { 3918c2ecf20Sopenharmony_ci csum = csum_add(csum, skb1->csum); 3928c2ecf20Sopenharmony_ci } 3938c2ecf20Sopenharmony_ci icmph->checksum = csum_fold(csum); 3948c2ecf20Sopenharmony_ci skb->ip_summed = CHECKSUM_NONE; 3958c2ecf20Sopenharmony_ci ip_push_pending_frames(sk, fl4); 3968c2ecf20Sopenharmony_ci } 3978c2ecf20Sopenharmony_ci} 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci/* 4008c2ecf20Sopenharmony_ci * Driving logic for building and sending ICMP messages. 4018c2ecf20Sopenharmony_ci */ 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_cistatic void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) 4048c2ecf20Sopenharmony_ci{ 4058c2ecf20Sopenharmony_ci struct ipcm_cookie ipc; 4068c2ecf20Sopenharmony_ci struct rtable *rt = skb_rtable(skb); 4078c2ecf20Sopenharmony_ci struct net *net = dev_net(rt->dst.dev); 4088c2ecf20Sopenharmony_ci struct flowi4 fl4; 4098c2ecf20Sopenharmony_ci struct sock *sk; 4108c2ecf20Sopenharmony_ci struct inet_sock *inet; 4118c2ecf20Sopenharmony_ci __be32 daddr, saddr; 4128c2ecf20Sopenharmony_ci u32 mark = IP4_REPLY_MARK(net, skb->mark); 4138c2ecf20Sopenharmony_ci int type = icmp_param->data.icmph.type; 4148c2ecf20Sopenharmony_ci int code = icmp_param->data.icmph.code; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci if (ip_options_echo(net, &icmp_param->replyopts.opt.opt, skb)) 4178c2ecf20Sopenharmony_ci return; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci /* Needed by both icmp_global_allow and icmp_xmit_lock */ 4208c2ecf20Sopenharmony_ci local_bh_disable(); 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci /* global icmp_msgs_per_sec */ 4238c2ecf20Sopenharmony_ci if (!icmpv4_global_allow(net, type, code)) 4248c2ecf20Sopenharmony_ci goto out_bh_enable; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci sk = icmp_xmit_lock(net); 4278c2ecf20Sopenharmony_ci if (!sk) 4288c2ecf20Sopenharmony_ci goto out_bh_enable; 4298c2ecf20Sopenharmony_ci inet = inet_sk(sk); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci icmp_param->data.icmph.checksum = 0; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci ipcm_init(&ipc); 4348c2ecf20Sopenharmony_ci inet->tos = ip_hdr(skb)->tos; 4358c2ecf20Sopenharmony_ci ipc.sockc.mark = mark; 4368c2ecf20Sopenharmony_ci daddr = ipc.addr = ip_hdr(skb)->saddr; 4378c2ecf20Sopenharmony_ci saddr = fib_compute_spec_dst(skb); 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci if (icmp_param->replyopts.opt.opt.optlen) { 4408c2ecf20Sopenharmony_ci ipc.opt = &icmp_param->replyopts.opt; 4418c2ecf20Sopenharmony_ci if (ipc.opt->opt.srr) 4428c2ecf20Sopenharmony_ci daddr = icmp_param->replyopts.opt.opt.faddr; 4438c2ecf20Sopenharmony_ci } 4448c2ecf20Sopenharmony_ci memset(&fl4, 0, sizeof(fl4)); 4458c2ecf20Sopenharmony_ci fl4.daddr = daddr; 4468c2ecf20Sopenharmony_ci fl4.saddr = saddr; 4478c2ecf20Sopenharmony_ci fl4.flowi4_mark = mark; 4488c2ecf20Sopenharmony_ci fl4.flowi4_uid = sock_net_uid(net, NULL); 4498c2ecf20Sopenharmony_ci fl4.flowi4_tos = RT_TOS(ip_hdr(skb)->tos); 4508c2ecf20Sopenharmony_ci fl4.flowi4_proto = IPPROTO_ICMP; 4518c2ecf20Sopenharmony_ci fl4.flowi4_oif = l3mdev_master_ifindex(skb->dev); 4528c2ecf20Sopenharmony_ci security_skb_classify_flow(skb, flowi4_to_flowi_common(&fl4)); 4538c2ecf20Sopenharmony_ci rt = ip_route_output_key(net, &fl4); 4548c2ecf20Sopenharmony_ci if (IS_ERR(rt)) 4558c2ecf20Sopenharmony_ci goto out_unlock; 4568c2ecf20Sopenharmony_ci if (icmpv4_xrlim_allow(net, rt, &fl4, type, code)) 4578c2ecf20Sopenharmony_ci icmp_push_reply(icmp_param, &fl4, &ipc, &rt); 4588c2ecf20Sopenharmony_ci ip_rt_put(rt); 4598c2ecf20Sopenharmony_ciout_unlock: 4608c2ecf20Sopenharmony_ci icmp_xmit_unlock(sk); 4618c2ecf20Sopenharmony_ciout_bh_enable: 4628c2ecf20Sopenharmony_ci local_bh_enable(); 4638c2ecf20Sopenharmony_ci} 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci/* 4668c2ecf20Sopenharmony_ci * The device used for looking up which routing table to use for sending an ICMP 4678c2ecf20Sopenharmony_ci * error is preferably the source whenever it is set, which should ensure the 4688c2ecf20Sopenharmony_ci * icmp error can be sent to the source host, else lookup using the routing 4698c2ecf20Sopenharmony_ci * table of the destination device, else use the main routing table (index 0). 4708c2ecf20Sopenharmony_ci */ 4718c2ecf20Sopenharmony_cistatic struct net_device *icmp_get_route_lookup_dev(struct sk_buff *skb) 4728c2ecf20Sopenharmony_ci{ 4738c2ecf20Sopenharmony_ci struct net_device *route_lookup_dev = NULL; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci if (skb->dev) 4768c2ecf20Sopenharmony_ci route_lookup_dev = skb->dev; 4778c2ecf20Sopenharmony_ci else if (skb_dst(skb)) 4788c2ecf20Sopenharmony_ci route_lookup_dev = skb_dst(skb)->dev; 4798c2ecf20Sopenharmony_ci return route_lookup_dev; 4808c2ecf20Sopenharmony_ci} 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_cistatic struct rtable *icmp_route_lookup(struct net *net, 4838c2ecf20Sopenharmony_ci struct flowi4 *fl4, 4848c2ecf20Sopenharmony_ci struct sk_buff *skb_in, 4858c2ecf20Sopenharmony_ci const struct iphdr *iph, 4868c2ecf20Sopenharmony_ci __be32 saddr, u8 tos, u32 mark, 4878c2ecf20Sopenharmony_ci int type, int code, 4888c2ecf20Sopenharmony_ci struct icmp_bxm *param) 4898c2ecf20Sopenharmony_ci{ 4908c2ecf20Sopenharmony_ci struct net_device *route_lookup_dev; 4918c2ecf20Sopenharmony_ci struct rtable *rt, *rt2; 4928c2ecf20Sopenharmony_ci struct flowi4 fl4_dec; 4938c2ecf20Sopenharmony_ci int err; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci memset(fl4, 0, sizeof(*fl4)); 4968c2ecf20Sopenharmony_ci fl4->daddr = (param->replyopts.opt.opt.srr ? 4978c2ecf20Sopenharmony_ci param->replyopts.opt.opt.faddr : iph->saddr); 4988c2ecf20Sopenharmony_ci fl4->saddr = saddr; 4998c2ecf20Sopenharmony_ci fl4->flowi4_mark = mark; 5008c2ecf20Sopenharmony_ci fl4->flowi4_uid = sock_net_uid(net, NULL); 5018c2ecf20Sopenharmony_ci fl4->flowi4_tos = RT_TOS(tos); 5028c2ecf20Sopenharmony_ci fl4->flowi4_proto = IPPROTO_ICMP; 5038c2ecf20Sopenharmony_ci fl4->fl4_icmp_type = type; 5048c2ecf20Sopenharmony_ci fl4->fl4_icmp_code = code; 5058c2ecf20Sopenharmony_ci route_lookup_dev = icmp_get_route_lookup_dev(skb_in); 5068c2ecf20Sopenharmony_ci fl4->flowi4_oif = l3mdev_master_ifindex(route_lookup_dev); 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci security_skb_classify_flow(skb_in, flowi4_to_flowi_common(fl4)); 5098c2ecf20Sopenharmony_ci rt = ip_route_output_key_hash(net, fl4, skb_in); 5108c2ecf20Sopenharmony_ci if (IS_ERR(rt)) 5118c2ecf20Sopenharmony_ci return rt; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci /* No need to clone since we're just using its address. */ 5148c2ecf20Sopenharmony_ci rt2 = rt; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci rt = (struct rtable *) xfrm_lookup(net, &rt->dst, 5178c2ecf20Sopenharmony_ci flowi4_to_flowi(fl4), NULL, 0); 5188c2ecf20Sopenharmony_ci if (!IS_ERR(rt)) { 5198c2ecf20Sopenharmony_ci if (rt != rt2) 5208c2ecf20Sopenharmony_ci return rt; 5218c2ecf20Sopenharmony_ci } else if (PTR_ERR(rt) == -EPERM) { 5228c2ecf20Sopenharmony_ci rt = NULL; 5238c2ecf20Sopenharmony_ci } else 5248c2ecf20Sopenharmony_ci return rt; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci err = xfrm_decode_session_reverse(skb_in, flowi4_to_flowi(&fl4_dec), AF_INET); 5278c2ecf20Sopenharmony_ci if (err) 5288c2ecf20Sopenharmony_ci goto relookup_failed; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci if (inet_addr_type_dev_table(net, route_lookup_dev, 5318c2ecf20Sopenharmony_ci fl4_dec.saddr) == RTN_LOCAL) { 5328c2ecf20Sopenharmony_ci rt2 = __ip_route_output_key(net, &fl4_dec); 5338c2ecf20Sopenharmony_ci if (IS_ERR(rt2)) 5348c2ecf20Sopenharmony_ci err = PTR_ERR(rt2); 5358c2ecf20Sopenharmony_ci } else { 5368c2ecf20Sopenharmony_ci struct flowi4 fl4_2 = {}; 5378c2ecf20Sopenharmony_ci unsigned long orefdst; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci fl4_2.daddr = fl4_dec.saddr; 5408c2ecf20Sopenharmony_ci rt2 = ip_route_output_key(net, &fl4_2); 5418c2ecf20Sopenharmony_ci if (IS_ERR(rt2)) { 5428c2ecf20Sopenharmony_ci err = PTR_ERR(rt2); 5438c2ecf20Sopenharmony_ci goto relookup_failed; 5448c2ecf20Sopenharmony_ci } 5458c2ecf20Sopenharmony_ci /* Ugh! */ 5468c2ecf20Sopenharmony_ci orefdst = skb_in->_skb_refdst; /* save old refdst */ 5478c2ecf20Sopenharmony_ci skb_dst_set(skb_in, NULL); 5488c2ecf20Sopenharmony_ci err = ip_route_input(skb_in, fl4_dec.daddr, fl4_dec.saddr, 5498c2ecf20Sopenharmony_ci RT_TOS(tos), rt2->dst.dev); 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci dst_release(&rt2->dst); 5528c2ecf20Sopenharmony_ci rt2 = skb_rtable(skb_in); 5538c2ecf20Sopenharmony_ci skb_in->_skb_refdst = orefdst; /* restore old refdst */ 5548c2ecf20Sopenharmony_ci } 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci if (err) 5578c2ecf20Sopenharmony_ci goto relookup_failed; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci rt2 = (struct rtable *) xfrm_lookup(net, &rt2->dst, 5608c2ecf20Sopenharmony_ci flowi4_to_flowi(&fl4_dec), NULL, 5618c2ecf20Sopenharmony_ci XFRM_LOOKUP_ICMP); 5628c2ecf20Sopenharmony_ci if (!IS_ERR(rt2)) { 5638c2ecf20Sopenharmony_ci dst_release(&rt->dst); 5648c2ecf20Sopenharmony_ci memcpy(fl4, &fl4_dec, sizeof(*fl4)); 5658c2ecf20Sopenharmony_ci rt = rt2; 5668c2ecf20Sopenharmony_ci } else if (PTR_ERR(rt2) == -EPERM) { 5678c2ecf20Sopenharmony_ci if (rt) 5688c2ecf20Sopenharmony_ci dst_release(&rt->dst); 5698c2ecf20Sopenharmony_ci return rt2; 5708c2ecf20Sopenharmony_ci } else { 5718c2ecf20Sopenharmony_ci err = PTR_ERR(rt2); 5728c2ecf20Sopenharmony_ci goto relookup_failed; 5738c2ecf20Sopenharmony_ci } 5748c2ecf20Sopenharmony_ci return rt; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_cirelookup_failed: 5778c2ecf20Sopenharmony_ci if (rt) 5788c2ecf20Sopenharmony_ci return rt; 5798c2ecf20Sopenharmony_ci return ERR_PTR(err); 5808c2ecf20Sopenharmony_ci} 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci/* 5838c2ecf20Sopenharmony_ci * Send an ICMP message in response to a situation 5848c2ecf20Sopenharmony_ci * 5858c2ecf20Sopenharmony_ci * RFC 1122: 3.2.2 MUST send at least the IP header and 8 bytes of header. 5868c2ecf20Sopenharmony_ci * MAY send more (we do). 5878c2ecf20Sopenharmony_ci * MUST NOT change this header information. 5888c2ecf20Sopenharmony_ci * MUST NOT reply to a multicast/broadcast IP address. 5898c2ecf20Sopenharmony_ci * MUST NOT reply to a multicast/broadcast MAC address. 5908c2ecf20Sopenharmony_ci * MUST reply to only the first fragment. 5918c2ecf20Sopenharmony_ci */ 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_civoid __icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info, 5948c2ecf20Sopenharmony_ci const struct ip_options *opt) 5958c2ecf20Sopenharmony_ci{ 5968c2ecf20Sopenharmony_ci struct iphdr *iph; 5978c2ecf20Sopenharmony_ci int room; 5988c2ecf20Sopenharmony_ci struct icmp_bxm icmp_param; 5998c2ecf20Sopenharmony_ci struct rtable *rt = skb_rtable(skb_in); 6008c2ecf20Sopenharmony_ci struct ipcm_cookie ipc; 6018c2ecf20Sopenharmony_ci struct flowi4 fl4; 6028c2ecf20Sopenharmony_ci __be32 saddr; 6038c2ecf20Sopenharmony_ci u8 tos; 6048c2ecf20Sopenharmony_ci u32 mark; 6058c2ecf20Sopenharmony_ci struct net *net; 6068c2ecf20Sopenharmony_ci struct sock *sk; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci if (!rt) 6098c2ecf20Sopenharmony_ci goto out; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci if (rt->dst.dev) 6128c2ecf20Sopenharmony_ci net = dev_net(rt->dst.dev); 6138c2ecf20Sopenharmony_ci else if (skb_in->dev) 6148c2ecf20Sopenharmony_ci net = dev_net(skb_in->dev); 6158c2ecf20Sopenharmony_ci else 6168c2ecf20Sopenharmony_ci goto out; 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci /* 6198c2ecf20Sopenharmony_ci * Find the original header. It is expected to be valid, of course. 6208c2ecf20Sopenharmony_ci * Check this, icmp_send is called from the most obscure devices 6218c2ecf20Sopenharmony_ci * sometimes. 6228c2ecf20Sopenharmony_ci */ 6238c2ecf20Sopenharmony_ci iph = ip_hdr(skb_in); 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci if ((u8 *)iph < skb_in->head || 6268c2ecf20Sopenharmony_ci (skb_network_header(skb_in) + sizeof(*iph)) > 6278c2ecf20Sopenharmony_ci skb_tail_pointer(skb_in)) 6288c2ecf20Sopenharmony_ci goto out; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci /* 6318c2ecf20Sopenharmony_ci * No replies to physical multicast/broadcast 6328c2ecf20Sopenharmony_ci */ 6338c2ecf20Sopenharmony_ci if (skb_in->pkt_type != PACKET_HOST) 6348c2ecf20Sopenharmony_ci goto out; 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci /* 6378c2ecf20Sopenharmony_ci * Now check at the protocol level 6388c2ecf20Sopenharmony_ci */ 6398c2ecf20Sopenharmony_ci if (rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) 6408c2ecf20Sopenharmony_ci goto out; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci /* 6438c2ecf20Sopenharmony_ci * Only reply to fragment 0. We byte re-order the constant 6448c2ecf20Sopenharmony_ci * mask for efficiency. 6458c2ecf20Sopenharmony_ci */ 6468c2ecf20Sopenharmony_ci if (iph->frag_off & htons(IP_OFFSET)) 6478c2ecf20Sopenharmony_ci goto out; 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci /* 6508c2ecf20Sopenharmony_ci * If we send an ICMP error to an ICMP error a mess would result.. 6518c2ecf20Sopenharmony_ci */ 6528c2ecf20Sopenharmony_ci if (icmp_pointers[type].error) { 6538c2ecf20Sopenharmony_ci /* 6548c2ecf20Sopenharmony_ci * We are an error, check if we are replying to an 6558c2ecf20Sopenharmony_ci * ICMP error 6568c2ecf20Sopenharmony_ci */ 6578c2ecf20Sopenharmony_ci if (iph->protocol == IPPROTO_ICMP) { 6588c2ecf20Sopenharmony_ci u8 _inner_type, *itp; 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci itp = skb_header_pointer(skb_in, 6618c2ecf20Sopenharmony_ci skb_network_header(skb_in) + 6628c2ecf20Sopenharmony_ci (iph->ihl << 2) + 6638c2ecf20Sopenharmony_ci offsetof(struct icmphdr, 6648c2ecf20Sopenharmony_ci type) - 6658c2ecf20Sopenharmony_ci skb_in->data, 6668c2ecf20Sopenharmony_ci sizeof(_inner_type), 6678c2ecf20Sopenharmony_ci &_inner_type); 6688c2ecf20Sopenharmony_ci if (!itp) 6698c2ecf20Sopenharmony_ci goto out; 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci /* 6728c2ecf20Sopenharmony_ci * Assume any unknown ICMP type is an error. This 6738c2ecf20Sopenharmony_ci * isn't specified by the RFC, but think about it.. 6748c2ecf20Sopenharmony_ci */ 6758c2ecf20Sopenharmony_ci if (*itp > NR_ICMP_TYPES || 6768c2ecf20Sopenharmony_ci icmp_pointers[*itp].error) 6778c2ecf20Sopenharmony_ci goto out; 6788c2ecf20Sopenharmony_ci } 6798c2ecf20Sopenharmony_ci } 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci /* Needed by both icmp_global_allow and icmp_xmit_lock */ 6828c2ecf20Sopenharmony_ci local_bh_disable(); 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci /* Check global sysctl_icmp_msgs_per_sec ratelimit, unless 6858c2ecf20Sopenharmony_ci * incoming dev is loopback. If outgoing dev change to not be 6868c2ecf20Sopenharmony_ci * loopback, then peer ratelimit still work (in icmpv4_xrlim_allow) 6878c2ecf20Sopenharmony_ci */ 6888c2ecf20Sopenharmony_ci if (!(skb_in->dev && (skb_in->dev->flags&IFF_LOOPBACK)) && 6898c2ecf20Sopenharmony_ci !icmpv4_global_allow(net, type, code)) 6908c2ecf20Sopenharmony_ci goto out_bh_enable; 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci sk = icmp_xmit_lock(net); 6938c2ecf20Sopenharmony_ci if (!sk) 6948c2ecf20Sopenharmony_ci goto out_bh_enable; 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci /* 6978c2ecf20Sopenharmony_ci * Construct source address and options. 6988c2ecf20Sopenharmony_ci */ 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci saddr = iph->daddr; 7018c2ecf20Sopenharmony_ci if (!(rt->rt_flags & RTCF_LOCAL)) { 7028c2ecf20Sopenharmony_ci struct net_device *dev = NULL; 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci rcu_read_lock(); 7058c2ecf20Sopenharmony_ci if (rt_is_input_route(rt) && 7068c2ecf20Sopenharmony_ci net->ipv4.sysctl_icmp_errors_use_inbound_ifaddr) 7078c2ecf20Sopenharmony_ci dev = dev_get_by_index_rcu(net, inet_iif(skb_in)); 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci if (dev) 7108c2ecf20Sopenharmony_ci saddr = inet_select_addr(dev, iph->saddr, 7118c2ecf20Sopenharmony_ci RT_SCOPE_LINK); 7128c2ecf20Sopenharmony_ci else 7138c2ecf20Sopenharmony_ci saddr = 0; 7148c2ecf20Sopenharmony_ci rcu_read_unlock(); 7158c2ecf20Sopenharmony_ci } 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci tos = icmp_pointers[type].error ? (RT_TOS(iph->tos) | 7188c2ecf20Sopenharmony_ci IPTOS_PREC_INTERNETCONTROL) : 7198c2ecf20Sopenharmony_ci iph->tos; 7208c2ecf20Sopenharmony_ci mark = IP4_REPLY_MARK(net, skb_in->mark); 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci if (__ip_options_echo(net, &icmp_param.replyopts.opt.opt, skb_in, opt)) 7238c2ecf20Sopenharmony_ci goto out_unlock; 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci /* 7278c2ecf20Sopenharmony_ci * Prepare data for ICMP header. 7288c2ecf20Sopenharmony_ci */ 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci icmp_param.data.icmph.type = type; 7318c2ecf20Sopenharmony_ci icmp_param.data.icmph.code = code; 7328c2ecf20Sopenharmony_ci icmp_param.data.icmph.un.gateway = info; 7338c2ecf20Sopenharmony_ci icmp_param.data.icmph.checksum = 0; 7348c2ecf20Sopenharmony_ci icmp_param.skb = skb_in; 7358c2ecf20Sopenharmony_ci icmp_param.offset = skb_network_offset(skb_in); 7368c2ecf20Sopenharmony_ci inet_sk(sk)->tos = tos; 7378c2ecf20Sopenharmony_ci ipcm_init(&ipc); 7388c2ecf20Sopenharmony_ci ipc.addr = iph->saddr; 7398c2ecf20Sopenharmony_ci ipc.opt = &icmp_param.replyopts.opt; 7408c2ecf20Sopenharmony_ci ipc.sockc.mark = mark; 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci rt = icmp_route_lookup(net, &fl4, skb_in, iph, saddr, tos, mark, 7438c2ecf20Sopenharmony_ci type, code, &icmp_param); 7448c2ecf20Sopenharmony_ci if (IS_ERR(rt)) 7458c2ecf20Sopenharmony_ci goto out_unlock; 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci /* peer icmp_ratelimit */ 7488c2ecf20Sopenharmony_ci if (!icmpv4_xrlim_allow(net, rt, &fl4, type, code)) 7498c2ecf20Sopenharmony_ci goto ende; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci /* RFC says return as much as we can without exceeding 576 bytes. */ 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci room = dst_mtu(&rt->dst); 7548c2ecf20Sopenharmony_ci if (room > 576) 7558c2ecf20Sopenharmony_ci room = 576; 7568c2ecf20Sopenharmony_ci room -= sizeof(struct iphdr) + icmp_param.replyopts.opt.opt.optlen; 7578c2ecf20Sopenharmony_ci room -= sizeof(struct icmphdr); 7588c2ecf20Sopenharmony_ci /* Guard against tiny mtu. We need to include at least one 7598c2ecf20Sopenharmony_ci * IP network header for this message to make any sense. 7608c2ecf20Sopenharmony_ci */ 7618c2ecf20Sopenharmony_ci if (room <= (int)sizeof(struct iphdr)) 7628c2ecf20Sopenharmony_ci goto ende; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci icmp_param.data_len = skb_in->len - icmp_param.offset; 7658c2ecf20Sopenharmony_ci if (icmp_param.data_len > room) 7668c2ecf20Sopenharmony_ci icmp_param.data_len = room; 7678c2ecf20Sopenharmony_ci icmp_param.head_len = sizeof(struct icmphdr); 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci /* if we don't have a source address at this point, fall back to the 7708c2ecf20Sopenharmony_ci * dummy address instead of sending out a packet with a source address 7718c2ecf20Sopenharmony_ci * of 0.0.0.0 7728c2ecf20Sopenharmony_ci */ 7738c2ecf20Sopenharmony_ci if (!fl4.saddr) 7748c2ecf20Sopenharmony_ci fl4.saddr = htonl(INADDR_DUMMY); 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci icmp_push_reply(&icmp_param, &fl4, &ipc, &rt); 7778c2ecf20Sopenharmony_ciende: 7788c2ecf20Sopenharmony_ci ip_rt_put(rt); 7798c2ecf20Sopenharmony_ciout_unlock: 7808c2ecf20Sopenharmony_ci icmp_xmit_unlock(sk); 7818c2ecf20Sopenharmony_ciout_bh_enable: 7828c2ecf20Sopenharmony_ci local_bh_enable(); 7838c2ecf20Sopenharmony_ciout:; 7848c2ecf20Sopenharmony_ci} 7858c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__icmp_send); 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_NF_NAT) 7888c2ecf20Sopenharmony_ci#include <net/netfilter/nf_conntrack.h> 7898c2ecf20Sopenharmony_civoid icmp_ndo_send(struct sk_buff *skb_in, int type, int code, __be32 info) 7908c2ecf20Sopenharmony_ci{ 7918c2ecf20Sopenharmony_ci struct sk_buff *cloned_skb = NULL; 7928c2ecf20Sopenharmony_ci struct ip_options opts = { 0 }; 7938c2ecf20Sopenharmony_ci enum ip_conntrack_info ctinfo; 7948c2ecf20Sopenharmony_ci struct nf_conn *ct; 7958c2ecf20Sopenharmony_ci __be32 orig_ip; 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci ct = nf_ct_get(skb_in, &ctinfo); 7988c2ecf20Sopenharmony_ci if (!ct || !(ct->status & IPS_SRC_NAT)) { 7998c2ecf20Sopenharmony_ci __icmp_send(skb_in, type, code, info, &opts); 8008c2ecf20Sopenharmony_ci return; 8018c2ecf20Sopenharmony_ci } 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci if (skb_shared(skb_in)) 8048c2ecf20Sopenharmony_ci skb_in = cloned_skb = skb_clone(skb_in, GFP_ATOMIC); 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci if (unlikely(!skb_in || skb_network_header(skb_in) < skb_in->head || 8078c2ecf20Sopenharmony_ci (skb_network_header(skb_in) + sizeof(struct iphdr)) > 8088c2ecf20Sopenharmony_ci skb_tail_pointer(skb_in) || skb_ensure_writable(skb_in, 8098c2ecf20Sopenharmony_ci skb_network_offset(skb_in) + sizeof(struct iphdr)))) 8108c2ecf20Sopenharmony_ci goto out; 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci orig_ip = ip_hdr(skb_in)->saddr; 8138c2ecf20Sopenharmony_ci ip_hdr(skb_in)->saddr = ct->tuplehash[0].tuple.src.u3.ip; 8148c2ecf20Sopenharmony_ci __icmp_send(skb_in, type, code, info, &opts); 8158c2ecf20Sopenharmony_ci ip_hdr(skb_in)->saddr = orig_ip; 8168c2ecf20Sopenharmony_ciout: 8178c2ecf20Sopenharmony_ci consume_skb(cloned_skb); 8188c2ecf20Sopenharmony_ci} 8198c2ecf20Sopenharmony_ciEXPORT_SYMBOL(icmp_ndo_send); 8208c2ecf20Sopenharmony_ci#endif 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_cistatic void icmp_socket_deliver(struct sk_buff *skb, u32 info) 8238c2ecf20Sopenharmony_ci{ 8248c2ecf20Sopenharmony_ci const struct iphdr *iph = (const struct iphdr *)skb->data; 8258c2ecf20Sopenharmony_ci const struct net_protocol *ipprot; 8268c2ecf20Sopenharmony_ci int protocol = iph->protocol; 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci /* Checkin full IP header plus 8 bytes of protocol to 8298c2ecf20Sopenharmony_ci * avoid additional coding at protocol handlers. 8308c2ecf20Sopenharmony_ci */ 8318c2ecf20Sopenharmony_ci if (!pskb_may_pull(skb, iph->ihl * 4 + 8)) { 8328c2ecf20Sopenharmony_ci __ICMP_INC_STATS(dev_net(skb->dev), ICMP_MIB_INERRORS); 8338c2ecf20Sopenharmony_ci return; 8348c2ecf20Sopenharmony_ci } 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci raw_icmp_error(skb, protocol, info); 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci ipprot = rcu_dereference(inet_protos[protocol]); 8398c2ecf20Sopenharmony_ci if (ipprot && ipprot->err_handler) 8408c2ecf20Sopenharmony_ci ipprot->err_handler(skb, info); 8418c2ecf20Sopenharmony_ci} 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_cistatic bool icmp_tag_validation(int proto) 8448c2ecf20Sopenharmony_ci{ 8458c2ecf20Sopenharmony_ci bool ok; 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci rcu_read_lock(); 8488c2ecf20Sopenharmony_ci ok = rcu_dereference(inet_protos[proto])->icmp_strict_tag_validation; 8498c2ecf20Sopenharmony_ci rcu_read_unlock(); 8508c2ecf20Sopenharmony_ci return ok; 8518c2ecf20Sopenharmony_ci} 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci/* 8548c2ecf20Sopenharmony_ci * Handle ICMP_DEST_UNREACH, ICMP_TIME_EXCEEDED, ICMP_QUENCH, and 8558c2ecf20Sopenharmony_ci * ICMP_PARAMETERPROB. 8568c2ecf20Sopenharmony_ci */ 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_cistatic bool icmp_unreach(struct sk_buff *skb) 8598c2ecf20Sopenharmony_ci{ 8608c2ecf20Sopenharmony_ci const struct iphdr *iph; 8618c2ecf20Sopenharmony_ci struct icmphdr *icmph; 8628c2ecf20Sopenharmony_ci struct net *net; 8638c2ecf20Sopenharmony_ci u32 info = 0; 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci net = dev_net(skb_dst(skb)->dev); 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci /* 8688c2ecf20Sopenharmony_ci * Incomplete header ? 8698c2ecf20Sopenharmony_ci * Only checks for the IP header, there should be an 8708c2ecf20Sopenharmony_ci * additional check for longer headers in upper levels. 8718c2ecf20Sopenharmony_ci */ 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci if (!pskb_may_pull(skb, sizeof(struct iphdr))) 8748c2ecf20Sopenharmony_ci goto out_err; 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci icmph = icmp_hdr(skb); 8778c2ecf20Sopenharmony_ci iph = (const struct iphdr *)skb->data; 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci if (iph->ihl < 5) /* Mangled header, drop. */ 8808c2ecf20Sopenharmony_ci goto out_err; 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci switch (icmph->type) { 8838c2ecf20Sopenharmony_ci case ICMP_DEST_UNREACH: 8848c2ecf20Sopenharmony_ci switch (icmph->code & 15) { 8858c2ecf20Sopenharmony_ci case ICMP_NET_UNREACH: 8868c2ecf20Sopenharmony_ci case ICMP_HOST_UNREACH: 8878c2ecf20Sopenharmony_ci case ICMP_PROT_UNREACH: 8888c2ecf20Sopenharmony_ci case ICMP_PORT_UNREACH: 8898c2ecf20Sopenharmony_ci break; 8908c2ecf20Sopenharmony_ci case ICMP_FRAG_NEEDED: 8918c2ecf20Sopenharmony_ci /* for documentation of the ip_no_pmtu_disc 8928c2ecf20Sopenharmony_ci * values please see 8938c2ecf20Sopenharmony_ci * Documentation/networking/ip-sysctl.rst 8948c2ecf20Sopenharmony_ci */ 8958c2ecf20Sopenharmony_ci switch (READ_ONCE(net->ipv4.sysctl_ip_no_pmtu_disc)) { 8968c2ecf20Sopenharmony_ci default: 8978c2ecf20Sopenharmony_ci net_dbg_ratelimited("%pI4: fragmentation needed and DF set\n", 8988c2ecf20Sopenharmony_ci &iph->daddr); 8998c2ecf20Sopenharmony_ci break; 9008c2ecf20Sopenharmony_ci case 2: 9018c2ecf20Sopenharmony_ci goto out; 9028c2ecf20Sopenharmony_ci case 3: 9038c2ecf20Sopenharmony_ci if (!icmp_tag_validation(iph->protocol)) 9048c2ecf20Sopenharmony_ci goto out; 9058c2ecf20Sopenharmony_ci fallthrough; 9068c2ecf20Sopenharmony_ci case 0: 9078c2ecf20Sopenharmony_ci info = ntohs(icmph->un.frag.mtu); 9088c2ecf20Sopenharmony_ci } 9098c2ecf20Sopenharmony_ci break; 9108c2ecf20Sopenharmony_ci case ICMP_SR_FAILED: 9118c2ecf20Sopenharmony_ci net_dbg_ratelimited("%pI4: Source Route Failed\n", 9128c2ecf20Sopenharmony_ci &iph->daddr); 9138c2ecf20Sopenharmony_ci break; 9148c2ecf20Sopenharmony_ci default: 9158c2ecf20Sopenharmony_ci break; 9168c2ecf20Sopenharmony_ci } 9178c2ecf20Sopenharmony_ci if (icmph->code > NR_ICMP_UNREACH) 9188c2ecf20Sopenharmony_ci goto out; 9198c2ecf20Sopenharmony_ci break; 9208c2ecf20Sopenharmony_ci case ICMP_PARAMETERPROB: 9218c2ecf20Sopenharmony_ci info = ntohl(icmph->un.gateway) >> 24; 9228c2ecf20Sopenharmony_ci break; 9238c2ecf20Sopenharmony_ci case ICMP_TIME_EXCEEDED: 9248c2ecf20Sopenharmony_ci __ICMP_INC_STATS(net, ICMP_MIB_INTIMEEXCDS); 9258c2ecf20Sopenharmony_ci if (icmph->code == ICMP_EXC_FRAGTIME) 9268c2ecf20Sopenharmony_ci goto out; 9278c2ecf20Sopenharmony_ci break; 9288c2ecf20Sopenharmony_ci } 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci /* 9318c2ecf20Sopenharmony_ci * Throw it at our lower layers 9328c2ecf20Sopenharmony_ci * 9338c2ecf20Sopenharmony_ci * RFC 1122: 3.2.2 MUST extract the protocol ID from the passed 9348c2ecf20Sopenharmony_ci * header. 9358c2ecf20Sopenharmony_ci * RFC 1122: 3.2.2.1 MUST pass ICMP unreach messages to the 9368c2ecf20Sopenharmony_ci * transport layer. 9378c2ecf20Sopenharmony_ci * RFC 1122: 3.2.2.2 MUST pass ICMP time expired messages to 9388c2ecf20Sopenharmony_ci * transport layer. 9398c2ecf20Sopenharmony_ci */ 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci /* 9428c2ecf20Sopenharmony_ci * Check the other end isn't violating RFC 1122. Some routers send 9438c2ecf20Sopenharmony_ci * bogus responses to broadcast frames. If you see this message 9448c2ecf20Sopenharmony_ci * first check your netmask matches at both ends, if it does then 9458c2ecf20Sopenharmony_ci * get the other vendor to fix their kit. 9468c2ecf20Sopenharmony_ci */ 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci if (!net->ipv4.sysctl_icmp_ignore_bogus_error_responses && 9498c2ecf20Sopenharmony_ci inet_addr_type_dev_table(net, skb->dev, iph->daddr) == RTN_BROADCAST) { 9508c2ecf20Sopenharmony_ci net_warn_ratelimited("%pI4 sent an invalid ICMP type %u, code %u error to a broadcast: %pI4 on %s\n", 9518c2ecf20Sopenharmony_ci &ip_hdr(skb)->saddr, 9528c2ecf20Sopenharmony_ci icmph->type, icmph->code, 9538c2ecf20Sopenharmony_ci &iph->daddr, skb->dev->name); 9548c2ecf20Sopenharmony_ci goto out; 9558c2ecf20Sopenharmony_ci } 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci icmp_socket_deliver(skb, info); 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ciout: 9608c2ecf20Sopenharmony_ci return true; 9618c2ecf20Sopenharmony_ciout_err: 9628c2ecf20Sopenharmony_ci __ICMP_INC_STATS(net, ICMP_MIB_INERRORS); 9638c2ecf20Sopenharmony_ci return false; 9648c2ecf20Sopenharmony_ci} 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci/* 9688c2ecf20Sopenharmony_ci * Handle ICMP_REDIRECT. 9698c2ecf20Sopenharmony_ci */ 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_cistatic bool icmp_redirect(struct sk_buff *skb) 9728c2ecf20Sopenharmony_ci{ 9738c2ecf20Sopenharmony_ci if (skb->len < sizeof(struct iphdr)) { 9748c2ecf20Sopenharmony_ci __ICMP_INC_STATS(dev_net(skb->dev), ICMP_MIB_INERRORS); 9758c2ecf20Sopenharmony_ci return false; 9768c2ecf20Sopenharmony_ci } 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci if (!pskb_may_pull(skb, sizeof(struct iphdr))) { 9798c2ecf20Sopenharmony_ci /* there aught to be a stat */ 9808c2ecf20Sopenharmony_ci return false; 9818c2ecf20Sopenharmony_ci } 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci icmp_socket_deliver(skb, ntohl(icmp_hdr(skb)->un.gateway)); 9848c2ecf20Sopenharmony_ci return true; 9858c2ecf20Sopenharmony_ci} 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci/* 9888c2ecf20Sopenharmony_ci * Handle ICMP_ECHO ("ping") requests. 9898c2ecf20Sopenharmony_ci * 9908c2ecf20Sopenharmony_ci * RFC 1122: 3.2.2.6 MUST have an echo server that answers ICMP echo 9918c2ecf20Sopenharmony_ci * requests. 9928c2ecf20Sopenharmony_ci * RFC 1122: 3.2.2.6 Data received in the ICMP_ECHO request MUST be 9938c2ecf20Sopenharmony_ci * included in the reply. 9948c2ecf20Sopenharmony_ci * RFC 1812: 4.3.3.6 SHOULD have a config option for silently ignoring 9958c2ecf20Sopenharmony_ci * echo requests, MUST have default=NOT. 9968c2ecf20Sopenharmony_ci * See also WRT handling of options once they are done and working. 9978c2ecf20Sopenharmony_ci */ 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_cistatic bool icmp_echo(struct sk_buff *skb) 10008c2ecf20Sopenharmony_ci{ 10018c2ecf20Sopenharmony_ci struct net *net; 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci net = dev_net(skb_dst(skb)->dev); 10048c2ecf20Sopenharmony_ci if (!net->ipv4.sysctl_icmp_echo_ignore_all) { 10058c2ecf20Sopenharmony_ci struct icmp_bxm icmp_param; 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci icmp_param.data.icmph = *icmp_hdr(skb); 10088c2ecf20Sopenharmony_ci icmp_param.data.icmph.type = ICMP_ECHOREPLY; 10098c2ecf20Sopenharmony_ci icmp_param.skb = skb; 10108c2ecf20Sopenharmony_ci icmp_param.offset = 0; 10118c2ecf20Sopenharmony_ci icmp_param.data_len = skb->len; 10128c2ecf20Sopenharmony_ci icmp_param.head_len = sizeof(struct icmphdr); 10138c2ecf20Sopenharmony_ci icmp_reply(&icmp_param, skb); 10148c2ecf20Sopenharmony_ci } 10158c2ecf20Sopenharmony_ci /* should there be an ICMP stat for ignored echos? */ 10168c2ecf20Sopenharmony_ci return true; 10178c2ecf20Sopenharmony_ci} 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci/* 10208c2ecf20Sopenharmony_ci * Handle ICMP Timestamp requests. 10218c2ecf20Sopenharmony_ci * RFC 1122: 3.2.2.8 MAY implement ICMP timestamp requests. 10228c2ecf20Sopenharmony_ci * SHOULD be in the kernel for minimum random latency. 10238c2ecf20Sopenharmony_ci * MUST be accurate to a few minutes. 10248c2ecf20Sopenharmony_ci * MUST be updated at least at 15Hz. 10258c2ecf20Sopenharmony_ci */ 10268c2ecf20Sopenharmony_cistatic bool icmp_timestamp(struct sk_buff *skb) 10278c2ecf20Sopenharmony_ci{ 10288c2ecf20Sopenharmony_ci struct icmp_bxm icmp_param; 10298c2ecf20Sopenharmony_ci /* 10308c2ecf20Sopenharmony_ci * Too short. 10318c2ecf20Sopenharmony_ci */ 10328c2ecf20Sopenharmony_ci if (skb->len < 4) 10338c2ecf20Sopenharmony_ci goto out_err; 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci /* 10368c2ecf20Sopenharmony_ci * Fill in the current time as ms since midnight UT: 10378c2ecf20Sopenharmony_ci */ 10388c2ecf20Sopenharmony_ci icmp_param.data.times[1] = inet_current_timestamp(); 10398c2ecf20Sopenharmony_ci icmp_param.data.times[2] = icmp_param.data.times[1]; 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci BUG_ON(skb_copy_bits(skb, 0, &icmp_param.data.times[0], 4)); 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci icmp_param.data.icmph = *icmp_hdr(skb); 10448c2ecf20Sopenharmony_ci icmp_param.data.icmph.type = ICMP_TIMESTAMPREPLY; 10458c2ecf20Sopenharmony_ci icmp_param.data.icmph.code = 0; 10468c2ecf20Sopenharmony_ci icmp_param.skb = skb; 10478c2ecf20Sopenharmony_ci icmp_param.offset = 0; 10488c2ecf20Sopenharmony_ci icmp_param.data_len = 0; 10498c2ecf20Sopenharmony_ci icmp_param.head_len = sizeof(struct icmphdr) + 12; 10508c2ecf20Sopenharmony_ci icmp_reply(&icmp_param, skb); 10518c2ecf20Sopenharmony_ci return true; 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ciout_err: 10548c2ecf20Sopenharmony_ci __ICMP_INC_STATS(dev_net(skb_dst(skb)->dev), ICMP_MIB_INERRORS); 10558c2ecf20Sopenharmony_ci return false; 10568c2ecf20Sopenharmony_ci} 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_cistatic bool icmp_discard(struct sk_buff *skb) 10598c2ecf20Sopenharmony_ci{ 10608c2ecf20Sopenharmony_ci /* pretend it was a success */ 10618c2ecf20Sopenharmony_ci return true; 10628c2ecf20Sopenharmony_ci} 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci/* 10658c2ecf20Sopenharmony_ci * Deal with incoming ICMP packets. 10668c2ecf20Sopenharmony_ci */ 10678c2ecf20Sopenharmony_ciint icmp_rcv(struct sk_buff *skb) 10688c2ecf20Sopenharmony_ci{ 10698c2ecf20Sopenharmony_ci struct icmphdr *icmph; 10708c2ecf20Sopenharmony_ci struct rtable *rt = skb_rtable(skb); 10718c2ecf20Sopenharmony_ci struct net *net = dev_net(rt->dst.dev); 10728c2ecf20Sopenharmony_ci bool success; 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) { 10758c2ecf20Sopenharmony_ci struct sec_path *sp = skb_sec_path(skb); 10768c2ecf20Sopenharmony_ci int nh; 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci if (!(sp && sp->xvec[sp->len - 1]->props.flags & 10798c2ecf20Sopenharmony_ci XFRM_STATE_ICMP)) 10808c2ecf20Sopenharmony_ci goto drop; 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci if (!pskb_may_pull(skb, sizeof(*icmph) + sizeof(struct iphdr))) 10838c2ecf20Sopenharmony_ci goto drop; 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci nh = skb_network_offset(skb); 10868c2ecf20Sopenharmony_ci skb_set_network_header(skb, sizeof(*icmph)); 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci if (!xfrm4_policy_check_reverse(NULL, XFRM_POLICY_IN, skb)) 10898c2ecf20Sopenharmony_ci goto drop; 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci skb_set_network_header(skb, nh); 10928c2ecf20Sopenharmony_ci } 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci __ICMP_INC_STATS(net, ICMP_MIB_INMSGS); 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci if (skb_checksum_simple_validate(skb)) 10978c2ecf20Sopenharmony_ci goto csum_error; 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci if (!pskb_pull(skb, sizeof(*icmph))) 11008c2ecf20Sopenharmony_ci goto error; 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci icmph = icmp_hdr(skb); 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci ICMPMSGIN_INC_STATS(net, icmph->type); 11058c2ecf20Sopenharmony_ci /* 11068c2ecf20Sopenharmony_ci * 18 is the highest 'known' ICMP type. Anything else is a mystery 11078c2ecf20Sopenharmony_ci * 11088c2ecf20Sopenharmony_ci * RFC 1122: 3.2.2 Unknown ICMP messages types MUST be silently 11098c2ecf20Sopenharmony_ci * discarded. 11108c2ecf20Sopenharmony_ci */ 11118c2ecf20Sopenharmony_ci if (icmph->type > NR_ICMP_TYPES) 11128c2ecf20Sopenharmony_ci goto error; 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci /* 11168c2ecf20Sopenharmony_ci * Parse the ICMP message 11178c2ecf20Sopenharmony_ci */ 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci if (rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) { 11208c2ecf20Sopenharmony_ci /* 11218c2ecf20Sopenharmony_ci * RFC 1122: 3.2.2.6 An ICMP_ECHO to broadcast MAY be 11228c2ecf20Sopenharmony_ci * silently ignored (we let user decide with a sysctl). 11238c2ecf20Sopenharmony_ci * RFC 1122: 3.2.2.8 An ICMP_TIMESTAMP MAY be silently 11248c2ecf20Sopenharmony_ci * discarded if to broadcast/multicast. 11258c2ecf20Sopenharmony_ci */ 11268c2ecf20Sopenharmony_ci if ((icmph->type == ICMP_ECHO || 11278c2ecf20Sopenharmony_ci icmph->type == ICMP_TIMESTAMP) && 11288c2ecf20Sopenharmony_ci net->ipv4.sysctl_icmp_echo_ignore_broadcasts) { 11298c2ecf20Sopenharmony_ci goto error; 11308c2ecf20Sopenharmony_ci } 11318c2ecf20Sopenharmony_ci if (icmph->type != ICMP_ECHO && 11328c2ecf20Sopenharmony_ci icmph->type != ICMP_TIMESTAMP && 11338c2ecf20Sopenharmony_ci icmph->type != ICMP_ADDRESS && 11348c2ecf20Sopenharmony_ci icmph->type != ICMP_ADDRESSREPLY) { 11358c2ecf20Sopenharmony_ci goto error; 11368c2ecf20Sopenharmony_ci } 11378c2ecf20Sopenharmony_ci } 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci success = icmp_pointers[icmph->type].handler(skb); 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci if (success) { 11428c2ecf20Sopenharmony_ci consume_skb(skb); 11438c2ecf20Sopenharmony_ci return NET_RX_SUCCESS; 11448c2ecf20Sopenharmony_ci } 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_cidrop: 11478c2ecf20Sopenharmony_ci kfree_skb(skb); 11488c2ecf20Sopenharmony_ci return NET_RX_DROP; 11498c2ecf20Sopenharmony_cicsum_error: 11508c2ecf20Sopenharmony_ci __ICMP_INC_STATS(net, ICMP_MIB_CSUMERRORS); 11518c2ecf20Sopenharmony_cierror: 11528c2ecf20Sopenharmony_ci __ICMP_INC_STATS(net, ICMP_MIB_INERRORS); 11538c2ecf20Sopenharmony_ci goto drop; 11548c2ecf20Sopenharmony_ci} 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_cistatic bool ip_icmp_error_rfc4884_validate(const struct sk_buff *skb, int off) 11578c2ecf20Sopenharmony_ci{ 11588c2ecf20Sopenharmony_ci struct icmp_extobj_hdr *objh, _objh; 11598c2ecf20Sopenharmony_ci struct icmp_ext_hdr *exth, _exth; 11608c2ecf20Sopenharmony_ci u16 olen; 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci exth = skb_header_pointer(skb, off, sizeof(_exth), &_exth); 11638c2ecf20Sopenharmony_ci if (!exth) 11648c2ecf20Sopenharmony_ci return false; 11658c2ecf20Sopenharmony_ci if (exth->version != 2) 11668c2ecf20Sopenharmony_ci return true; 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci if (exth->checksum && 11698c2ecf20Sopenharmony_ci csum_fold(skb_checksum(skb, off, skb->len - off, 0))) 11708c2ecf20Sopenharmony_ci return false; 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ci off += sizeof(_exth); 11738c2ecf20Sopenharmony_ci while (off < skb->len) { 11748c2ecf20Sopenharmony_ci objh = skb_header_pointer(skb, off, sizeof(_objh), &_objh); 11758c2ecf20Sopenharmony_ci if (!objh) 11768c2ecf20Sopenharmony_ci return false; 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci olen = ntohs(objh->length); 11798c2ecf20Sopenharmony_ci if (olen < sizeof(_objh)) 11808c2ecf20Sopenharmony_ci return false; 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci off += olen; 11838c2ecf20Sopenharmony_ci if (off > skb->len) 11848c2ecf20Sopenharmony_ci return false; 11858c2ecf20Sopenharmony_ci } 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci return true; 11888c2ecf20Sopenharmony_ci} 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_civoid ip_icmp_error_rfc4884(const struct sk_buff *skb, 11918c2ecf20Sopenharmony_ci struct sock_ee_data_rfc4884 *out, 11928c2ecf20Sopenharmony_ci int thlen, int off) 11938c2ecf20Sopenharmony_ci{ 11948c2ecf20Sopenharmony_ci int hlen; 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_ci /* original datagram headers: end of icmph to payload (skb->data) */ 11978c2ecf20Sopenharmony_ci hlen = -skb_transport_offset(skb) - thlen; 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci /* per rfc 4884: minimal datagram length of 128 bytes */ 12008c2ecf20Sopenharmony_ci if (off < 128 || off < hlen) 12018c2ecf20Sopenharmony_ci return; 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci /* kernel has stripped headers: return payload offset in bytes */ 12048c2ecf20Sopenharmony_ci off -= hlen; 12058c2ecf20Sopenharmony_ci if (off + sizeof(struct icmp_ext_hdr) > skb->len) 12068c2ecf20Sopenharmony_ci return; 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci out->len = off; 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci if (!ip_icmp_error_rfc4884_validate(skb, off)) 12118c2ecf20Sopenharmony_ci out->flags |= SO_EE_RFC4884_FLAG_INVALID; 12128c2ecf20Sopenharmony_ci} 12138c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ip_icmp_error_rfc4884); 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ciint icmp_err(struct sk_buff *skb, u32 info) 12168c2ecf20Sopenharmony_ci{ 12178c2ecf20Sopenharmony_ci struct iphdr *iph = (struct iphdr *)skb->data; 12188c2ecf20Sopenharmony_ci int offset = iph->ihl<<2; 12198c2ecf20Sopenharmony_ci struct icmphdr *icmph = (struct icmphdr *)(skb->data + offset); 12208c2ecf20Sopenharmony_ci int type = icmp_hdr(skb)->type; 12218c2ecf20Sopenharmony_ci int code = icmp_hdr(skb)->code; 12228c2ecf20Sopenharmony_ci struct net *net = dev_net(skb->dev); 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci /* 12258c2ecf20Sopenharmony_ci * Use ping_err to handle all icmp errors except those 12268c2ecf20Sopenharmony_ci * triggered by ICMP_ECHOREPLY which sent from kernel. 12278c2ecf20Sopenharmony_ci */ 12288c2ecf20Sopenharmony_ci if (icmph->type != ICMP_ECHOREPLY) { 12298c2ecf20Sopenharmony_ci ping_err(skb, offset, info); 12308c2ecf20Sopenharmony_ci return 0; 12318c2ecf20Sopenharmony_ci } 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) 12348c2ecf20Sopenharmony_ci ipv4_update_pmtu(skb, net, info, 0, IPPROTO_ICMP); 12358c2ecf20Sopenharmony_ci else if (type == ICMP_REDIRECT) 12368c2ecf20Sopenharmony_ci ipv4_redirect(skb, net, 0, IPPROTO_ICMP); 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci return 0; 12398c2ecf20Sopenharmony_ci} 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci/* 12428c2ecf20Sopenharmony_ci * This table is the definition of how we handle ICMP. 12438c2ecf20Sopenharmony_ci */ 12448c2ecf20Sopenharmony_cistatic const struct icmp_control icmp_pointers[NR_ICMP_TYPES + 1] = { 12458c2ecf20Sopenharmony_ci [ICMP_ECHOREPLY] = { 12468c2ecf20Sopenharmony_ci .handler = ping_rcv, 12478c2ecf20Sopenharmony_ci }, 12488c2ecf20Sopenharmony_ci [1] = { 12498c2ecf20Sopenharmony_ci .handler = icmp_discard, 12508c2ecf20Sopenharmony_ci .error = 1, 12518c2ecf20Sopenharmony_ci }, 12528c2ecf20Sopenharmony_ci [2] = { 12538c2ecf20Sopenharmony_ci .handler = icmp_discard, 12548c2ecf20Sopenharmony_ci .error = 1, 12558c2ecf20Sopenharmony_ci }, 12568c2ecf20Sopenharmony_ci [ICMP_DEST_UNREACH] = { 12578c2ecf20Sopenharmony_ci .handler = icmp_unreach, 12588c2ecf20Sopenharmony_ci .error = 1, 12598c2ecf20Sopenharmony_ci }, 12608c2ecf20Sopenharmony_ci [ICMP_SOURCE_QUENCH] = { 12618c2ecf20Sopenharmony_ci .handler = icmp_unreach, 12628c2ecf20Sopenharmony_ci .error = 1, 12638c2ecf20Sopenharmony_ci }, 12648c2ecf20Sopenharmony_ci [ICMP_REDIRECT] = { 12658c2ecf20Sopenharmony_ci .handler = icmp_redirect, 12668c2ecf20Sopenharmony_ci .error = 1, 12678c2ecf20Sopenharmony_ci }, 12688c2ecf20Sopenharmony_ci [6] = { 12698c2ecf20Sopenharmony_ci .handler = icmp_discard, 12708c2ecf20Sopenharmony_ci .error = 1, 12718c2ecf20Sopenharmony_ci }, 12728c2ecf20Sopenharmony_ci [7] = { 12738c2ecf20Sopenharmony_ci .handler = icmp_discard, 12748c2ecf20Sopenharmony_ci .error = 1, 12758c2ecf20Sopenharmony_ci }, 12768c2ecf20Sopenharmony_ci [ICMP_ECHO] = { 12778c2ecf20Sopenharmony_ci .handler = icmp_echo, 12788c2ecf20Sopenharmony_ci }, 12798c2ecf20Sopenharmony_ci [9] = { 12808c2ecf20Sopenharmony_ci .handler = icmp_discard, 12818c2ecf20Sopenharmony_ci .error = 1, 12828c2ecf20Sopenharmony_ci }, 12838c2ecf20Sopenharmony_ci [10] = { 12848c2ecf20Sopenharmony_ci .handler = icmp_discard, 12858c2ecf20Sopenharmony_ci .error = 1, 12868c2ecf20Sopenharmony_ci }, 12878c2ecf20Sopenharmony_ci [ICMP_TIME_EXCEEDED] = { 12888c2ecf20Sopenharmony_ci .handler = icmp_unreach, 12898c2ecf20Sopenharmony_ci .error = 1, 12908c2ecf20Sopenharmony_ci }, 12918c2ecf20Sopenharmony_ci [ICMP_PARAMETERPROB] = { 12928c2ecf20Sopenharmony_ci .handler = icmp_unreach, 12938c2ecf20Sopenharmony_ci .error = 1, 12948c2ecf20Sopenharmony_ci }, 12958c2ecf20Sopenharmony_ci [ICMP_TIMESTAMP] = { 12968c2ecf20Sopenharmony_ci .handler = icmp_timestamp, 12978c2ecf20Sopenharmony_ci }, 12988c2ecf20Sopenharmony_ci [ICMP_TIMESTAMPREPLY] = { 12998c2ecf20Sopenharmony_ci .handler = icmp_discard, 13008c2ecf20Sopenharmony_ci }, 13018c2ecf20Sopenharmony_ci [ICMP_INFO_REQUEST] = { 13028c2ecf20Sopenharmony_ci .handler = icmp_discard, 13038c2ecf20Sopenharmony_ci }, 13048c2ecf20Sopenharmony_ci [ICMP_INFO_REPLY] = { 13058c2ecf20Sopenharmony_ci .handler = icmp_discard, 13068c2ecf20Sopenharmony_ci }, 13078c2ecf20Sopenharmony_ci [ICMP_ADDRESS] = { 13088c2ecf20Sopenharmony_ci .handler = icmp_discard, 13098c2ecf20Sopenharmony_ci }, 13108c2ecf20Sopenharmony_ci [ICMP_ADDRESSREPLY] = { 13118c2ecf20Sopenharmony_ci .handler = icmp_discard, 13128c2ecf20Sopenharmony_ci }, 13138c2ecf20Sopenharmony_ci}; 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_cistatic void __net_exit icmp_sk_exit(struct net *net) 13168c2ecf20Sopenharmony_ci{ 13178c2ecf20Sopenharmony_ci int i; 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci for_each_possible_cpu(i) 13208c2ecf20Sopenharmony_ci inet_ctl_sock_destroy(*per_cpu_ptr(net->ipv4.icmp_sk, i)); 13218c2ecf20Sopenharmony_ci free_percpu(net->ipv4.icmp_sk); 13228c2ecf20Sopenharmony_ci net->ipv4.icmp_sk = NULL; 13238c2ecf20Sopenharmony_ci} 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_cistatic int __net_init icmp_sk_init(struct net *net) 13268c2ecf20Sopenharmony_ci{ 13278c2ecf20Sopenharmony_ci int i, err; 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci net->ipv4.icmp_sk = alloc_percpu(struct sock *); 13308c2ecf20Sopenharmony_ci if (!net->ipv4.icmp_sk) 13318c2ecf20Sopenharmony_ci return -ENOMEM; 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci for_each_possible_cpu(i) { 13348c2ecf20Sopenharmony_ci struct sock *sk; 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_ci err = inet_ctl_sock_create(&sk, PF_INET, 13378c2ecf20Sopenharmony_ci SOCK_RAW, IPPROTO_ICMP, net); 13388c2ecf20Sopenharmony_ci if (err < 0) 13398c2ecf20Sopenharmony_ci goto fail; 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci *per_cpu_ptr(net->ipv4.icmp_sk, i) = sk; 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci /* Enough space for 2 64K ICMP packets, including 13448c2ecf20Sopenharmony_ci * sk_buff/skb_shared_info struct overhead. 13458c2ecf20Sopenharmony_ci */ 13468c2ecf20Sopenharmony_ci sk->sk_sndbuf = 2 * SKB_TRUESIZE(64 * 1024); 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci /* 13498c2ecf20Sopenharmony_ci * Speedup sock_wfree() 13508c2ecf20Sopenharmony_ci */ 13518c2ecf20Sopenharmony_ci sock_set_flag(sk, SOCK_USE_WRITE_QUEUE); 13528c2ecf20Sopenharmony_ci inet_sk(sk)->pmtudisc = IP_PMTUDISC_DONT; 13538c2ecf20Sopenharmony_ci } 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci /* Control parameters for ECHO replies. */ 13568c2ecf20Sopenharmony_ci net->ipv4.sysctl_icmp_echo_ignore_all = 0; 13578c2ecf20Sopenharmony_ci net->ipv4.sysctl_icmp_echo_ignore_broadcasts = 1; 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci /* Control parameter - ignore bogus broadcast responses? */ 13608c2ecf20Sopenharmony_ci net->ipv4.sysctl_icmp_ignore_bogus_error_responses = 1; 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci /* 13638c2ecf20Sopenharmony_ci * Configurable global rate limit. 13648c2ecf20Sopenharmony_ci * 13658c2ecf20Sopenharmony_ci * ratelimit defines tokens/packet consumed for dst->rate_token 13668c2ecf20Sopenharmony_ci * bucket ratemask defines which icmp types are ratelimited by 13678c2ecf20Sopenharmony_ci * setting it's bit position. 13688c2ecf20Sopenharmony_ci * 13698c2ecf20Sopenharmony_ci * default: 13708c2ecf20Sopenharmony_ci * dest unreachable (3), source quench (4), 13718c2ecf20Sopenharmony_ci * time exceeded (11), parameter problem (12) 13728c2ecf20Sopenharmony_ci */ 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci net->ipv4.sysctl_icmp_ratelimit = 1 * HZ; 13758c2ecf20Sopenharmony_ci net->ipv4.sysctl_icmp_ratemask = 0x1818; 13768c2ecf20Sopenharmony_ci net->ipv4.sysctl_icmp_errors_use_inbound_ifaddr = 0; 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_ci return 0; 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_cifail: 13818c2ecf20Sopenharmony_ci icmp_sk_exit(net); 13828c2ecf20Sopenharmony_ci return err; 13838c2ecf20Sopenharmony_ci} 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_cistatic struct pernet_operations __net_initdata icmp_sk_ops = { 13868c2ecf20Sopenharmony_ci .init = icmp_sk_init, 13878c2ecf20Sopenharmony_ci .exit = icmp_sk_exit, 13888c2ecf20Sopenharmony_ci}; 13898c2ecf20Sopenharmony_ci 13908c2ecf20Sopenharmony_ciint __init icmp_init(void) 13918c2ecf20Sopenharmony_ci{ 13928c2ecf20Sopenharmony_ci return register_pernet_subsys(&icmp_sk_ops); 13938c2ecf20Sopenharmony_ci} 1394