diff options
author | Tobias Brunner <tobias@strongswan.org> | 2015-11-02 16:22:38 +0100 |
---|---|---|
committer | Tobias Brunner <tobias@strongswan.org> | 2015-11-09 16:43:21 +0100 |
commit | 47e113a63905305fdb7eee8304a5eb1adcb216d4 (patch) | |
tree | 768ae0d047d6989b01de795cb1015618f58e99a5 /src/libcharon/plugins/socket_default/socket_default_socket.c | |
parent | 99747bed8f0aea9427bd17820dbde79342bb9ce9 (diff) | |
download | strongswan-47e113a63905305fdb7eee8304a5eb1adcb216d4.tar.bz2 strongswan-47e113a63905305fdb7eee8304a5eb1adcb216d4.tar.xz |
socket-default: Refactor setting source address when sending messages
This ensures we don't pass data (via msg_control) defined in a different
scope to sendmsg(). Actually, some compilers (e.g. GCC 5.2.1) might
optimize the memcpy() call away causing the packets not to get sent from
the intended source address.
It also makes the code clearer than with all these ifdefs.
Fixes #1171.
Diffstat (limited to 'src/libcharon/plugins/socket_default/socket_default_socket.c')
-rw-r--r-- | src/libcharon/plugins/socket_default/socket_default_socket.c | 153 |
1 files changed, 107 insertions, 46 deletions
diff --git a/src/libcharon/plugins/socket_default/socket_default_socket.c b/src/libcharon/plugins/socket_default/socket_default_socket.c index 421593cac..13bf3e775 100644 --- a/src/libcharon/plugins/socket_default/socket_default_socket.c +++ b/src/libcharon/plugins/socket_default/socket_default_socket.c @@ -355,6 +355,107 @@ METHOD(socket_t, receiver, status_t, return SUCCESS; } +/** + * Generic function to send a message. + */ +static ssize_t send_msg_generic(int skt, struct msghdr *msg) +{ + return sendmsg(skt, msg, 0); +} + +/** + * Send a message with the IPv4 source address set, if possible. + */ +#ifdef IP_PKTINFO + +static ssize_t send_msg_v4(int skt, struct msghdr *msg, host_t *src) +{ + char buf[CMSG_SPACE(sizeof(struct in_pktinfo))] = {}; + struct cmsghdr *cmsg; + struct in_addr *addr; + struct in_pktinfo *pktinfo; + struct sockaddr_in *sin; + + msg->msg_control = buf; + msg->msg_controllen = sizeof(buf); + cmsg = CMSG_FIRSTHDR(msg); + cmsg->cmsg_level = SOL_IP; + cmsg->cmsg_type = IP_PKTINFO; + cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); + + pktinfo = (struct in_pktinfo*)CMSG_DATA(cmsg); + addr = &pktinfo->ipi_spec_dst; + + sin = (struct sockaddr_in*)src->get_sockaddr(src); + memcpy(addr, &sin->sin_addr, sizeof(struct in_addr)); + return send_msg_generic(skt, msg); +} + +#elif defined(IP_SENDSRCADDR) + +static ssize_t send_msg_v4(int skt, struct msghdr *msg, host_t *src) +{ + char buf[CMSG_SPACE(sizeof(struct in_addr))] = {}; + struct cmsghdr *cmsg; + struct in_addr *addr; + struct sockaddr_in *sin; + + msg->msg_control = buf; + msg->msg_controllen = sizeof(buf); + cmsg = CMSG_FIRSTHDR(msg); + cmsg->cmsg_level = SOL_IP; + cmsg->cmsg_type = IP_SENDSRCADDR; + cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr)); + + addr = (struct in_addr*)CMSG_DATA(cmsg); + + sin = (struct sockaddr_in*)src->get_sockaddr(src); + memcpy(addr, &sin->sin_addr, sizeof(struct in_addr)); + return send_msg_generic(skt, msg); +} + +#else /* IP_PKTINFO || IP_RECVDSTADDR */ + +static ssize_t send_msg_v4(int skt, struct msghdr *msg, host_t *src) +{ + return send_msg_generic(skt, msg); +} + +#endif /* IP_PKTINFO || IP_RECVDSTADDR */ + +/** + * Send a message with the IPv6 source address set, if possible. + */ +#ifdef HAVE_IN6_PKTINFO + +static ssize_t send_msg_v6(int skt, struct msghdr *msg, host_t *src) +{ + char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))] = {}; + struct cmsghdr *cmsg; + struct in6_pktinfo *pktinfo; + struct sockaddr_in6 *sin; + + msg->msg_control = buf; + msg->msg_controllen = sizeof(buf); + cmsg = CMSG_FIRSTHDR(msg); + cmsg->cmsg_level = SOL_IPV6; + cmsg->cmsg_type = IPV6_PKTINFO; + cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); + pktinfo = (struct in6_pktinfo*)CMSG_DATA(cmsg); + sin = (struct sockaddr_in6*)src->get_sockaddr(src); + memcpy(&pktinfo->ipi6_addr, &sin->sin6_addr, sizeof(struct in6_addr)); + return send_msg_generic(skt, msg); +} + +#else /* HAVE_IN6_PKTINFO */ + +static ssize_t send_msg_v6(int skt, struct msghdr *msg, host_t *src) +{ + return send_msg_generic(skt, msg); +} + +#endif /* HAVE_IN6_PKTINFO */ + METHOD(socket_t, sender, status_t, private_socket_default_socket_t *this, packet_t *packet) { @@ -363,7 +464,6 @@ METHOD(socket_t, sender, status_t, chunk_t data; host_t *src, *dst; struct msghdr msg; - struct cmsghdr *cmsg; struct iovec iov; u_int8_t *dscp; @@ -465,56 +565,17 @@ METHOD(socket_t, sender, status_t, { if (family == AF_INET) { -#if defined(IP_PKTINFO) || defined(IP_SENDSRCADDR) - struct in_addr *addr; - struct sockaddr_in *sin; -#ifdef IP_PKTINFO - char buf[CMSG_SPACE(sizeof(struct in_pktinfo))]; - struct in_pktinfo *pktinfo; -#elif defined(IP_SENDSRCADDR) - char buf[CMSG_SPACE(sizeof(struct in_addr))]; -#endif - memset(buf, 0, sizeof(buf)); - msg.msg_control = buf; - msg.msg_controllen = sizeof(buf); - cmsg = CMSG_FIRSTHDR(&msg); - cmsg->cmsg_level = SOL_IP; -#ifdef IP_PKTINFO - cmsg->cmsg_type = IP_PKTINFO; - cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); - pktinfo = (struct in_pktinfo*)CMSG_DATA(cmsg); - addr = &pktinfo->ipi_spec_dst; -#elif defined(IP_SENDSRCADDR) - cmsg->cmsg_type = IP_SENDSRCADDR; - cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr)); - addr = (struct in_addr*)CMSG_DATA(cmsg); -#endif - sin = (struct sockaddr_in*)src->get_sockaddr(src); - memcpy(addr, &sin->sin_addr, sizeof(struct in_addr)); -#endif /* IP_PKTINFO || IP_SENDSRCADDR */ + bytes_sent = send_msg_v4(skt, &msg, src); } -#ifdef HAVE_IN6_PKTINFO else { - char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))]; - struct in6_pktinfo *pktinfo; - struct sockaddr_in6 *sin; - - memset(buf, 0, sizeof(buf)); - msg.msg_control = buf; - msg.msg_controllen = sizeof(buf); - cmsg = CMSG_FIRSTHDR(&msg); - cmsg->cmsg_level = SOL_IPV6; - cmsg->cmsg_type = IPV6_PKTINFO; - cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); - pktinfo = (struct in6_pktinfo*)CMSG_DATA(cmsg); - sin = (struct sockaddr_in6*)src->get_sockaddr(src); - memcpy(&pktinfo->ipi6_addr, &sin->sin6_addr, sizeof(struct in6_addr)); + bytes_sent = send_msg_v6(skt, &msg, src); } -#endif /* HAVE_IN6_PKTINFO */ } - - bytes_sent = sendmsg(skt, &msg, 0); + else + { + bytes_sent = send_msg_generic(skt, &msg); + } if (bytes_sent != data.len) { |