diff --git a/newip/src/common/nip_addr.c b/newip/src/common/nip_addr.c index 32bc36040c62e3eabc27e11b828248cec7521eb2..03f9e8299e678250c0bd011f0175c021cb44240e 100644 --- a/newip/src/common/nip_addr.c +++ b/newip/src/common/nip_addr.c @@ -26,6 +26,12 @@ const struct nip_addr nip_broadcast_addr_arp = { .nip_addr_field8[1] = 0x04, }; +static const struct nip_addr nip_local_addr = { + .bitlen = NIP_ADDR_BIT_LEN_16, + .nip_addr_field8[0] = 0xFF, /* 0xFF00 addr, big-endian */ + .nip_addr_field8[1] = 0x00, +}; + enum addr_check_ret { NOT_CURRENT_ADDR = -1, CURRENT_ADDR_VALID = 0, @@ -122,6 +128,18 @@ static inline int is_public_addr_flag(unsigned char first_byte) return first_byte == ADDR_FIRST_FF ? NIP_TRUE : NIP_FALSE; } +int is_nip_local_addr(const struct nip_addr *ad) +{ + int result = 0; + + if (ad->bitlen == NIP_ADDR_BIT_LEN_16) { + if (ad->nip_addr_field16[0] == nip_local_addr.nip_addr_field16[0] && + ad->nip_addr_field16[1] == nip_local_addr.nip_addr_field16[1]) + result = 1; + } + return result; +} + /* Short address range: * 【1-byte】0 ~ 220 * 00 ~ DC diff --git a/newip/src/common/nip_addr.h b/newip/src/common/nip_addr.h index 5ae142532ad3bda0ce0115d1f00779d9556db601..3d9f21d424b62c66eb59e63380f6a9cb155d885b 100644 --- a/newip/src/common/nip_addr.h +++ b/newip/src/common/nip_addr.h @@ -115,6 +115,7 @@ int nip_addr_any(const struct nip_addr *ad); int get_nip_addr_len(const struct nip_addr *addr); unsigned char *build_nip_addr(const struct nip_addr *addr, unsigned char *buf); unsigned char *decode_nip_addr(unsigned char *buf, struct nip_addr *addr); +int is_nip_local_addr(const struct nip_addr *addr); #endif /* _UAPI_NEWIP_ADDR_H */ diff --git a/newip/src/linux-5.10/net/newip/nip_hooks_register.c b/newip/src/linux-5.10/net/newip/nip_hooks_register.c index 46b9bc0d4866956d7b8ba74961924cfdc80cf1f3..0541c4565a13769488db7c64291ce5f163fb9078 100644 --- a/newip/src/linux-5.10/net/newip/nip_hooks_register.c +++ b/newip/src/linux-5.10/net/newip/nip_hooks_register.c @@ -17,12 +17,18 @@ #include #include "tcp_nip_parameter.h" +/* call the newip hook function in sk_ehashfn function (net\ipv4\inet_hashtables.c): + * if trace_vendor_ninet_ehashfn_enabled() then call trace_vendor_ninet_ehashfn function. + */ void vendor_ninet_ehashfn(void *data, const struct sock *sk, u32 *ret) { *ret = ninet_ehashfn(sock_net(sk), &sk->sk_nip_rcv_saddr, sk->sk_num, &sk->sk_nip_daddr, sk->sk_dport); } +/* call the newip hook function in inet_gifconf function (net\ipv4\devinet.c): + * call the newip trace_vendor_ninet_gifconf function after the IPv4 process. + */ void vendor_ninet_gifconf(void *data, struct net_device *dev, char __user *buf, int len, int size, int *ret) { diff --git a/newip/third_party/linux-5.10/include/net/if_ninet.h b/newip/third_party/linux-5.10/include/net/if_ninet.h index d0d99ad6fe971c1e3055c5418149b7892b954ac7..21c44988dc733b1268d9be98749f9b04423bebb7 100644 --- a/newip/third_party/linux-5.10/include/net/if_ninet.h +++ b/newip/third_party/linux-5.10/include/net/if_ninet.h @@ -12,6 +12,8 @@ #include +#define NIP_IOCTL_FLAG_INVALID 35 + enum { NINET_IFADDR_STATE_NEW, NINET_IFADDR_STATE_DEAD, @@ -62,5 +64,6 @@ struct ninet_dev { }; int ninet_gifconf(struct net_device *dev, char __user *buf, int len, int size); +int ninet_ioctl_cmd(struct socket *sock, const struct iovec *iov); #endif diff --git a/newip/third_party/linux-5.10/include/net/tcp_nip.h b/newip/third_party/linux-5.10/include/net/tcp_nip.h index a70379b35bdcc36297c0dcc97d7d22262ad15797..dfd38a78bba1f2ed1a8aeae05f6a2b9fa0419eee 100644 --- a/newip/third_party/linux-5.10/include/net/tcp_nip.h +++ b/newip/third_party/linux-5.10/include/net/tcp_nip.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* - * Based on include/net/tcp.h + * Based on include/net/tcp.h * Authors: Ross Biro * Fred N. van Kempen, * diff --git a/newip/third_party/linux-5.10/net/newip/af_ninet.c b/newip/third_party/linux-5.10/net/newip/af_ninet.c index 05aa1ce72b4a3774a2afe81988a1ee63cd56149a..5718b1c5510a1dc6bb7ed35cde19d39e79ea954f 100644 --- a/newip/third_party/linux-5.10/net/newip/af_ninet.c +++ b/newip/third_party/linux-5.10/net/newip/af_ninet.c @@ -57,6 +57,10 @@ #endif #include "tcp_nip_parameter.h" +#define NINET_IOCTL_FLAG_LEN 8 +#define NINET_IOCTL_HEAD_LEN 12 +#define NINET_IOCTL_FLAG_VALUE {0xea, 0xdd, 0xea, 0xdd, 0xea, 0xdd, 0xea, 0xdd} + MODULE_DESCRIPTION("NewIP protocol stack"); /* The inetsw_nip table contains everything that ninet_create needs to @@ -507,8 +511,67 @@ int ninet_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) } } EXPORT_SYMBOL_GPL(ninet_compat_ioctl); + +static int compat_select_ninet_ioctl(struct socket *sock, unsigned int cmd, + unsigned long arg, int arglen) +{ + switch (cmd) { + case SIOCADDRT: + case SIOCDELRT: + if (sizeof(struct nip_rtmsg) != arglen) { + void __user *argp = compat_ptr(arg); + struct sock *sk = sock->sk; + + return ninet_compat_routing_ioctl(sk, cmd, argp); + } + return ninet_ioctl(sock, cmd, arg); + default: + return ninet_ioctl(sock, cmd, arg); + } +} #endif /* CONFIG_COMPAT */ +static int __ninet_ioctl_cmd(struct socket *sock, unsigned int cmd, + void __user *iov_base, __kernel_size_t iov_len) +{ + unsigned long arg = (unsigned long)(iov_base + NINET_IOCTL_HEAD_LEN); +#ifdef CONFIG_COMPAT + int arglen = iov_len - NINET_IOCTL_HEAD_LEN; + + return compat_select_ninet_ioctl(sock, cmd, arg, arglen); +#else + return ninet_ioctl(sock, cmd, arg); +#endif +} + +int ninet_ioctl_cmd(struct socket *sock, const struct iovec *iov) +{ + char ioctl_flag[NINET_IOCTL_FLAG_LEN] = NINET_IOCTL_FLAG_VALUE; + char ioctl_head[NINET_IOCTL_HEAD_LEN]; + int i; + unsigned int cmd; + + if (!iov || !iov->iov_base || !sock || + iov->iov_len < NINET_IOCTL_HEAD_LEN) { + nip_dbg("invalid parameter"); + return -NIP_IOCTL_FLAG_INVALID; + } + + if (copy_from_user(ioctl_head, (void __user *)iov->iov_base, NINET_IOCTL_HEAD_LEN)) { + nip_dbg("fail to copy ioctl head"); + return -NIP_IOCTL_FLAG_INVALID; + } + + for (i = 0; i < NINET_IOCTL_FLAG_LEN; i++) { + if (ioctl_head[i] != ioctl_flag[i]) { + nip_dbg("not ninet ioctl cmd"); + return -NIP_IOCTL_FLAG_INVALID; + } + } + cmd = *(unsigned int *)(ioctl_head + NINET_IOCTL_FLAG_LEN); + return __ninet_ioctl_cmd(sock, cmd, iov->iov_base, iov->iov_len); +} + /* register new IP socket */ const struct proto_ops ninet_dgram_ops = { .family = PF_NINET, diff --git a/newip/third_party/linux-5.10/net/newip/nip_addrconf.c b/newip/third_party/linux-5.10/net/newip/nip_addrconf.c index 231cf690e88d92211468b9767c2d34ca51ce8bca..043cf0337546836b696fdb7afd15d150ae63477d 100644 --- a/newip/third_party/linux-5.10/net/newip/nip_addrconf.c +++ b/newip/third_party/linux-5.10/net/newip/nip_addrconf.c @@ -417,11 +417,6 @@ static int ninet_addr_del(struct net *net, int ifindex, u32 ifa_flags, int nip_addrconf_ifaddr_check(struct net *net, void __user *arg, struct nip_ifreq *ireq) { - if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) { - nip_dbg("not admin can`t cfg"); - return -EPERM; - } - if (copy_from_user(ireq, arg, sizeof(struct nip_ifreq))) { nip_dbg("fail to copy cfg data"); return -EFAULT; diff --git a/newip/third_party/linux-5.10/net/newip/route.c b/newip/third_party/linux-5.10/net/newip/route.c index c10b32a17ba4a45588cf5f439f6120cdfcdf8e39..d98c9abb2ee823f1da7854685932cb28c4d16dac 100644 --- a/newip/third_party/linux-5.10/net/newip/route.c +++ b/newip/third_party/linux-5.10/net/newip/route.c @@ -656,11 +656,6 @@ int nip_route_ioctl(struct net *net, unsigned int cmd, struct nip_rtmsg *rtmsg) struct nip_fib_config cfg; int err; - if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) { - nip_dbg("not admin can`t cfg"); - return -EPERM; - } - rtmsg_to_fibni_config(net, rtmsg, &cfg); if (nip_addr_invalid(&cfg.fc_dst)) { nip_dbg("nip daddr invalid, bitlen=%u", cfg.fc_dst.bitlen); diff --git a/newip/third_party/linux-5.10/net/newip/udp.c b/newip/third_party/linux-5.10/net/newip/udp.c index 899f65f8d614aebb7cb7331c402c9ecb64517387..b2619a94787a0bb9f21c4b134f15634fee1cd86c 100644 --- a/newip/third_party/linux-5.10/net/newip/udp.c +++ b/newip/third_party/linux-5.10/net/newip/udp.c @@ -398,7 +398,7 @@ int nip_udp_output(struct sock *sk, struct msghdr *msg, size_t len) struct flow_nip fln; u_short sport, dport; struct dst_entry *dst; - int err = 0; + int err; struct inet_sock *inet; if (!sin) @@ -415,6 +415,16 @@ int nip_udp_output(struct sock *sk, struct msghdr *msg, size_t len) nip_dbg("sin_addr false"); return -EFAULT; } + if (is_nip_local_addr(&sin->sin_addr)) { + err = ninet_ioctl_cmd(sk->sk_socket, msg->msg_iter.iov); + if (!err) { + nip_dbg("ninet_ioctl_cmd succeed"); + return err; + } else if (err != -NIP_IOCTL_FLAG_INVALID) { + nip_dbg("ninet_ioctl_cmd failed"); + return err; + } + } inet = inet_sk(sk); /* Destination address, port (network order) must be specified when sendto */