Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * INET     An implementation of the TCP/IP protocol suite for the LINUX
0004  *      operating system.  INET is implemented using the  BSD Socket
0005  *      interface as the means of communication with the user level.
0006  *
0007  *      "Ping" sockets
0008  *
0009  * Based on ipv4/ping.c code.
0010  *
0011  * Authors: Lorenzo Colitti (IPv6 support)
0012  *      Vasiliy Kulikov / Openwall (IPv4 implementation, for Linux 2.6),
0013  *      Pavel Kankovsky (IPv4 implementation, for Linux 2.4.32)
0014  */
0015 
0016 #include <net/addrconf.h>
0017 #include <net/ipv6.h>
0018 #include <net/ip6_route.h>
0019 #include <net/protocol.h>
0020 #include <net/udp.h>
0021 #include <net/transp_v6.h>
0022 #include <linux/proc_fs.h>
0023 #include <net/ping.h>
0024 
0025 static void ping_v6_destroy(struct sock *sk)
0026 {
0027     inet6_destroy_sock(sk);
0028 }
0029 
0030 /* Compatibility glue so we can support IPv6 when it's compiled as a module */
0031 static int dummy_ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len,
0032                  int *addr_len)
0033 {
0034     return -EAFNOSUPPORT;
0035 }
0036 static void dummy_ip6_datagram_recv_ctl(struct sock *sk, struct msghdr *msg,
0037                        struct sk_buff *skb)
0038 {
0039 }
0040 static int dummy_icmpv6_err_convert(u8 type, u8 code, int *err)
0041 {
0042     return -EAFNOSUPPORT;
0043 }
0044 static void dummy_ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err,
0045                   __be16 port, u32 info, u8 *payload) {}
0046 static int dummy_ipv6_chk_addr(struct net *net, const struct in6_addr *addr,
0047                    const struct net_device *dev, int strict)
0048 {
0049     return 0;
0050 }
0051 
0052 static int ping_v6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
0053 {
0054     struct inet_sock *inet = inet_sk(sk);
0055     struct ipv6_pinfo *np = inet6_sk(sk);
0056     struct icmp6hdr user_icmph;
0057     int addr_type;
0058     struct in6_addr *daddr;
0059     int oif = 0;
0060     struct flowi6 fl6;
0061     int err;
0062     struct dst_entry *dst;
0063     struct rt6_info *rt;
0064     struct pingfakehdr pfh;
0065     struct ipcm6_cookie ipc6;
0066 
0067     err = ping_common_sendmsg(AF_INET6, msg, len, &user_icmph,
0068                   sizeof(user_icmph));
0069     if (err)
0070         return err;
0071 
0072     memset(&fl6, 0, sizeof(fl6));
0073 
0074     if (msg->msg_name) {
0075         DECLARE_SOCKADDR(struct sockaddr_in6 *, u, msg->msg_name);
0076         if (msg->msg_namelen < sizeof(*u))
0077             return -EINVAL;
0078         if (u->sin6_family != AF_INET6) {
0079             return -EAFNOSUPPORT;
0080         }
0081         daddr = &(u->sin6_addr);
0082         if (np->sndflow)
0083             fl6.flowlabel = u->sin6_flowinfo & IPV6_FLOWINFO_MASK;
0084         if (__ipv6_addr_needs_scope_id(ipv6_addr_type(daddr)))
0085             oif = u->sin6_scope_id;
0086     } else {
0087         if (sk->sk_state != TCP_ESTABLISHED)
0088             return -EDESTADDRREQ;
0089         daddr = &sk->sk_v6_daddr;
0090         fl6.flowlabel = np->flow_label;
0091     }
0092 
0093     if (!oif)
0094         oif = sk->sk_bound_dev_if;
0095 
0096     if (!oif)
0097         oif = np->sticky_pktinfo.ipi6_ifindex;
0098 
0099     if (!oif && ipv6_addr_is_multicast(daddr))
0100         oif = np->mcast_oif;
0101     else if (!oif)
0102         oif = np->ucast_oif;
0103 
0104     addr_type = ipv6_addr_type(daddr);
0105     if ((__ipv6_addr_needs_scope_id(addr_type) && !oif) ||
0106         (addr_type & IPV6_ADDR_MAPPED) ||
0107         (oif && sk->sk_bound_dev_if && oif != sk->sk_bound_dev_if))
0108         return -EINVAL;
0109 
0110     ipcm6_init_sk(&ipc6, np);
0111     ipc6.sockc.tsflags = sk->sk_tsflags;
0112     ipc6.sockc.mark = sk->sk_mark;
0113 
0114     fl6.flowi6_oif = oif;
0115 
0116     if (msg->msg_controllen) {
0117         struct ipv6_txoptions opt = {};
0118 
0119         opt.tot_len = sizeof(opt);
0120         ipc6.opt = &opt;
0121 
0122         err = ip6_datagram_send_ctl(sock_net(sk), sk, msg, &fl6, &ipc6);
0123         if (err < 0)
0124             return err;
0125 
0126         /* Changes to txoptions and flow info are not implemented, yet.
0127          * Drop the options.
0128          */
0129         ipc6.opt = NULL;
0130     }
0131 
0132     fl6.flowi6_proto = IPPROTO_ICMPV6;
0133     fl6.saddr = np->saddr;
0134     fl6.daddr = *daddr;
0135     fl6.flowi6_mark = ipc6.sockc.mark;
0136     fl6.flowi6_uid = sk->sk_uid;
0137     fl6.fl6_icmp_type = user_icmph.icmp6_type;
0138     fl6.fl6_icmp_code = user_icmph.icmp6_code;
0139     security_sk_classify_flow(sk, flowi6_to_flowi_common(&fl6));
0140 
0141     fl6.flowlabel = ip6_make_flowinfo(ipc6.tclass, fl6.flowlabel);
0142 
0143     dst = ip6_sk_dst_lookup_flow(sk, &fl6, daddr, false);
0144     if (IS_ERR(dst))
0145         return PTR_ERR(dst);
0146     rt = (struct rt6_info *) dst;
0147 
0148     if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
0149         fl6.flowi6_oif = np->mcast_oif;
0150     else if (!fl6.flowi6_oif)
0151         fl6.flowi6_oif = np->ucast_oif;
0152 
0153     pfh.icmph.type = user_icmph.icmp6_type;
0154     pfh.icmph.code = user_icmph.icmp6_code;
0155     pfh.icmph.checksum = 0;
0156     pfh.icmph.un.echo.id = inet->inet_sport;
0157     pfh.icmph.un.echo.sequence = user_icmph.icmp6_sequence;
0158     pfh.msg = msg;
0159     pfh.wcheck = 0;
0160     pfh.family = AF_INET6;
0161 
0162     if (ipc6.hlimit < 0)
0163         ipc6.hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst);
0164 
0165     lock_sock(sk);
0166     err = ip6_append_data(sk, ping_getfrag, &pfh, len,
0167                   0, &ipc6, &fl6, rt,
0168                   MSG_DONTWAIT);
0169 
0170     if (err) {
0171         ICMP6_INC_STATS(sock_net(sk), rt->rt6i_idev,
0172                 ICMP6_MIB_OUTERRORS);
0173         ip6_flush_pending_frames(sk);
0174     } else {
0175         icmpv6_push_pending_frames(sk, &fl6,
0176                        (struct icmp6hdr *)&pfh.icmph, len);
0177     }
0178     release_sock(sk);
0179 
0180     dst_release(dst);
0181 
0182     if (err)
0183         return err;
0184 
0185     return len;
0186 }
0187 
0188 struct proto pingv6_prot = {
0189     .name =     "PINGv6",
0190     .owner =    THIS_MODULE,
0191     .init =     ping_init_sock,
0192     .close =    ping_close,
0193     .destroy =  ping_v6_destroy,
0194     .connect =  ip6_datagram_connect_v6_only,
0195     .disconnect =   __udp_disconnect,
0196     .setsockopt =   ipv6_setsockopt,
0197     .getsockopt =   ipv6_getsockopt,
0198     .sendmsg =  ping_v6_sendmsg,
0199     .recvmsg =  ping_recvmsg,
0200     .bind =     ping_bind,
0201     .backlog_rcv =  ping_queue_rcv_skb,
0202     .hash =     ping_hash,
0203     .unhash =   ping_unhash,
0204     .get_port = ping_get_port,
0205     .put_port = ping_unhash,
0206     .obj_size = sizeof(struct raw6_sock),
0207 };
0208 EXPORT_SYMBOL_GPL(pingv6_prot);
0209 
0210 static struct inet_protosw pingv6_protosw = {
0211     .type =      SOCK_DGRAM,
0212     .protocol =  IPPROTO_ICMPV6,
0213     .prot =      &pingv6_prot,
0214     .ops =       &inet6_sockraw_ops,
0215     .flags =     INET_PROTOSW_REUSE,
0216 };
0217 
0218 #ifdef CONFIG_PROC_FS
0219 static void *ping_v6_seq_start(struct seq_file *seq, loff_t *pos)
0220 {
0221     return ping_seq_start(seq, pos, AF_INET6);
0222 }
0223 
0224 static int ping_v6_seq_show(struct seq_file *seq, void *v)
0225 {
0226     if (v == SEQ_START_TOKEN) {
0227         seq_puts(seq, IPV6_SEQ_DGRAM_HEADER);
0228     } else {
0229         int bucket = ((struct ping_iter_state *) seq->private)->bucket;
0230         struct inet_sock *inet = inet_sk(v);
0231         __u16 srcp = ntohs(inet->inet_sport);
0232         __u16 destp = ntohs(inet->inet_dport);
0233         ip6_dgram_sock_seq_show(seq, v, srcp, destp, bucket);
0234     }
0235     return 0;
0236 }
0237 
0238 static const struct seq_operations ping_v6_seq_ops = {
0239     .start      = ping_v6_seq_start,
0240     .show       = ping_v6_seq_show,
0241     .next       = ping_seq_next,
0242     .stop       = ping_seq_stop,
0243 };
0244 
0245 static int __net_init ping_v6_proc_init_net(struct net *net)
0246 {
0247     if (!proc_create_net("icmp6", 0444, net->proc_net, &ping_v6_seq_ops,
0248             sizeof(struct ping_iter_state)))
0249         return -ENOMEM;
0250     return 0;
0251 }
0252 
0253 static void __net_exit ping_v6_proc_exit_net(struct net *net)
0254 {
0255     remove_proc_entry("icmp6", net->proc_net);
0256 }
0257 
0258 static struct pernet_operations ping_v6_net_ops = {
0259     .init = ping_v6_proc_init_net,
0260     .exit = ping_v6_proc_exit_net,
0261 };
0262 #endif
0263 
0264 int __init pingv6_init(void)
0265 {
0266 #ifdef CONFIG_PROC_FS
0267     int ret = register_pernet_subsys(&ping_v6_net_ops);
0268     if (ret)
0269         return ret;
0270 #endif
0271     pingv6_ops.ipv6_recv_error = ipv6_recv_error;
0272     pingv6_ops.ip6_datagram_recv_common_ctl = ip6_datagram_recv_common_ctl;
0273     pingv6_ops.ip6_datagram_recv_specific_ctl =
0274         ip6_datagram_recv_specific_ctl;
0275     pingv6_ops.icmpv6_err_convert = icmpv6_err_convert;
0276     pingv6_ops.ipv6_icmp_error = ipv6_icmp_error;
0277     pingv6_ops.ipv6_chk_addr = ipv6_chk_addr;
0278     return inet6_register_protosw(&pingv6_protosw);
0279 }
0280 
0281 /* This never gets called because it's not possible to unload the ipv6 module,
0282  * but just in case.
0283  */
0284 void pingv6_exit(void)
0285 {
0286     pingv6_ops.ipv6_recv_error = dummy_ipv6_recv_error;
0287     pingv6_ops.ip6_datagram_recv_common_ctl = dummy_ip6_datagram_recv_ctl;
0288     pingv6_ops.ip6_datagram_recv_specific_ctl = dummy_ip6_datagram_recv_ctl;
0289     pingv6_ops.icmpv6_err_convert = dummy_icmpv6_err_convert;
0290     pingv6_ops.ipv6_icmp_error = dummy_ipv6_icmp_error;
0291     pingv6_ops.ipv6_chk_addr = dummy_ipv6_chk_addr;
0292 #ifdef CONFIG_PROC_FS
0293     unregister_pernet_subsys(&ping_v6_net_ops);
0294 #endif
0295     inet6_unregister_protosw(&pingv6_protosw);
0296 }