Skip to content

Commit c8e6ad0

Browse files
strssndktndavem330
authored andcommitted
ipv6: honor IPV6_PKTINFO with v4 mapped addresses on sendmsg
In case we decide in udp6_sendmsg to send the packet down the ipv4 udp_sendmsg path because the destination is either of family AF_INET or the destination is an ipv4 mapped ipv6 address, we don't honor the maybe specified ipv4 mapped ipv6 address in IPV6_PKTINFO. We simply can check for this option in ip_cmsg_send because no calls to ipv6 module functions are needed to do so. Reported-by: Gert Doering <[email protected]> Cc: Tore Anderson <[email protected]> Signed-off-by: Hannes Frederic Sowa <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 21f374c commit c8e6ad0

File tree

5 files changed

+24
-5
lines changed

5 files changed

+24
-5
lines changed

include/net/ip.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -489,7 +489,8 @@ int ip_options_rcv_srr(struct sk_buff *skb);
489489

490490
void ipv4_pktinfo_prepare(const struct sock *sk, struct sk_buff *skb);
491491
void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb);
492-
int ip_cmsg_send(struct net *net, struct msghdr *msg, struct ipcm_cookie *ipc);
492+
int ip_cmsg_send(struct net *net, struct msghdr *msg,
493+
struct ipcm_cookie *ipc, bool allow_ipv6);
493494
int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
494495
unsigned int optlen);
495496
int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval,

net/ipv4/ip_sockglue.c

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,14 +186,31 @@ void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb)
186186
}
187187
EXPORT_SYMBOL(ip_cmsg_recv);
188188

189-
int ip_cmsg_send(struct net *net, struct msghdr *msg, struct ipcm_cookie *ipc)
189+
int ip_cmsg_send(struct net *net, struct msghdr *msg, struct ipcm_cookie *ipc,
190+
bool allow_ipv6)
190191
{
191192
int err, val;
192193
struct cmsghdr *cmsg;
193194

194195
for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
195196
if (!CMSG_OK(msg, cmsg))
196197
return -EINVAL;
198+
#if defined(CONFIG_IPV6)
199+
if (allow_ipv6 &&
200+
cmsg->cmsg_level == SOL_IPV6 &&
201+
cmsg->cmsg_type == IPV6_PKTINFO) {
202+
struct in6_pktinfo *src_info;
203+
204+
if (cmsg->cmsg_len < CMSG_LEN(sizeof(*src_info)))
205+
return -EINVAL;
206+
src_info = (struct in6_pktinfo *)CMSG_DATA(cmsg);
207+
if (!ipv6_addr_v4mapped(&src_info->ipi6_addr))
208+
return -EINVAL;
209+
ipc->oif = src_info->ipi6_ifindex;
210+
ipc->addr = src_info->ipi6_addr.s6_addr32[3];
211+
continue;
212+
}
213+
#endif
197214
if (cmsg->cmsg_level != SOL_IP)
198215
continue;
199216
switch (cmsg->cmsg_type) {

net/ipv4/ping.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -727,7 +727,7 @@ static int ping_v4_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *m
727727
sock_tx_timestamp(sk, &ipc.tx_flags);
728728

729729
if (msg->msg_controllen) {
730-
err = ip_cmsg_send(sock_net(sk), msg, &ipc);
730+
err = ip_cmsg_send(sock_net(sk), msg, &ipc, false);
731731
if (err)
732732
return err;
733733
if (ipc.opt)

net/ipv4/raw.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -524,7 +524,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
524524
ipc.oif = sk->sk_bound_dev_if;
525525

526526
if (msg->msg_controllen) {
527-
err = ip_cmsg_send(sock_net(sk), msg, &ipc);
527+
err = ip_cmsg_send(sock_net(sk), msg, &ipc, false);
528528
if (err)
529529
goto out;
530530
if (ipc.opt)

net/ipv4/udp.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -931,7 +931,8 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
931931
sock_tx_timestamp(sk, &ipc.tx_flags);
932932

933933
if (msg->msg_controllen) {
934-
err = ip_cmsg_send(sock_net(sk), msg, &ipc);
934+
err = ip_cmsg_send(sock_net(sk), msg, &ipc,
935+
sk->sk_family == AF_INET6);
935936
if (err)
936937
return err;
937938
if (ipc.opt)

0 commit comments

Comments
 (0)