|
@@ -44,6 +44,10 @@ struct inet_diag_entry {
|
|
|
u16 dport;
|
|
|
u16 family;
|
|
|
u16 userlocks;
|
|
|
+#if IS_ENABLED(CONFIG_IPV6)
|
|
|
+ struct in6_addr saddr_storage; /* for IPv4-mapped-IPv6 addresses */
|
|
|
+ struct in6_addr daddr_storage; /* for IPv4-mapped-IPv6 addresses */
|
|
|
+#endif
|
|
|
};
|
|
|
|
|
|
static DEFINE_MUTEX(inet_diag_table_mutex);
|
|
@@ -596,6 +600,36 @@ static int inet_twsk_diag_dump(struct inet_timewait_sock *tw,
|
|
|
cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh);
|
|
|
}
|
|
|
|
|
|
+/* Get the IPv4, IPv6, or IPv4-mapped-IPv6 local and remote addresses
|
|
|
+ * from a request_sock. For IPv4-mapped-IPv6 we must map IPv4 to IPv6.
|
|
|
+ */
|
|
|
+static inline void inet_diag_req_addrs(const struct sock *sk,
|
|
|
+ const struct request_sock *req,
|
|
|
+ struct inet_diag_entry *entry)
|
|
|
+{
|
|
|
+ struct inet_request_sock *ireq = inet_rsk(req);
|
|
|
+
|
|
|
+#if IS_ENABLED(CONFIG_IPV6)
|
|
|
+ if (sk->sk_family == AF_INET6) {
|
|
|
+ if (req->rsk_ops->family == AF_INET6) {
|
|
|
+ entry->saddr = inet6_rsk(req)->loc_addr.s6_addr32;
|
|
|
+ entry->daddr = inet6_rsk(req)->rmt_addr.s6_addr32;
|
|
|
+ } else if (req->rsk_ops->family == AF_INET) {
|
|
|
+ ipv6_addr_set_v4mapped(ireq->loc_addr,
|
|
|
+ &entry->saddr_storage);
|
|
|
+ ipv6_addr_set_v4mapped(ireq->rmt_addr,
|
|
|
+ &entry->daddr_storage);
|
|
|
+ entry->saddr = entry->saddr_storage.s6_addr32;
|
|
|
+ entry->daddr = entry->daddr_storage.s6_addr32;
|
|
|
+ }
|
|
|
+ } else
|
|
|
+#endif
|
|
|
+ {
|
|
|
+ entry->saddr = &ireq->loc_addr;
|
|
|
+ entry->daddr = &ireq->rmt_addr;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static int inet_diag_fill_req(struct sk_buff *skb, struct sock *sk,
|
|
|
struct request_sock *req,
|
|
|
struct user_namespace *user_ns,
|
|
@@ -637,8 +671,10 @@ static int inet_diag_fill_req(struct sk_buff *skb, struct sock *sk,
|
|
|
r->idiag_inode = 0;
|
|
|
#if IS_ENABLED(CONFIG_IPV6)
|
|
|
if (r->idiag_family == AF_INET6) {
|
|
|
- *(struct in6_addr *)r->id.idiag_src = inet6_rsk(req)->loc_addr;
|
|
|
- *(struct in6_addr *)r->id.idiag_dst = inet6_rsk(req)->rmt_addr;
|
|
|
+ struct inet_diag_entry entry;
|
|
|
+ inet_diag_req_addrs(sk, req, &entry);
|
|
|
+ memcpy(r->id.idiag_src, entry.saddr, sizeof(struct in6_addr));
|
|
|
+ memcpy(r->id.idiag_dst, entry.daddr, sizeof(struct in6_addr));
|
|
|
}
|
|
|
#endif
|
|
|
|
|
@@ -691,18 +727,7 @@ static int inet_diag_dump_reqs(struct sk_buff *skb, struct sock *sk,
|
|
|
continue;
|
|
|
|
|
|
if (bc) {
|
|
|
- entry.saddr =
|
|
|
-#if IS_ENABLED(CONFIG_IPV6)
|
|
|
- (entry.family == AF_INET6) ?
|
|
|
- inet6_rsk(req)->loc_addr.s6_addr32 :
|
|
|
-#endif
|
|
|
- &ireq->loc_addr;
|
|
|
- entry.daddr =
|
|
|
-#if IS_ENABLED(CONFIG_IPV6)
|
|
|
- (entry.family == AF_INET6) ?
|
|
|
- inet6_rsk(req)->rmt_addr.s6_addr32 :
|
|
|
-#endif
|
|
|
- &ireq->rmt_addr;
|
|
|
+ inet_diag_req_addrs(sk, req, &entry);
|
|
|
entry.dport = ntohs(ireq->rmt_port);
|
|
|
|
|
|
if (!inet_diag_bc_run(bc, &entry))
|