diff --git a/src/libcharon/plugins/socket_dynamic/socket_dynamic_socket.c b/src/libcharon/plugins/socket_dynamic/socket_dynamic_socket.c index b82a69e1b..a032134c3 100644 --- a/src/libcharon/plugins/socket_dynamic/socket_dynamic_socket.c +++ b/src/libcharon/plugins/socket_dynamic/socket_dynamic_socket.c @@ -527,6 +527,62 @@ static dynsock_t *find_socket(private_socket_dynamic_socket_t *this, return skt; } +/** + * 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. + */ +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); +} + +/** + * Send a message with the IPv6 source address set. + */ +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); +} + METHOD(socket_t, sender, status_t, private_socket_dynamic_socket_t *this, packet_t *packet) { @@ -536,7 +592,6 @@ METHOD(socket_t, sender, status_t, ssize_t len; chunk_t data; struct msghdr msg; - struct cmsghdr *cmsg; struct iovec iov; src = packet->get_source(packet); @@ -564,43 +619,18 @@ METHOD(socket_t, sender, status_t, { if (family == AF_INET) { - struct in_addr *addr; - struct sockaddr_in *sin; - char buf[CMSG_SPACE(sizeof(struct in_pktinfo))]; - struct in_pktinfo *pktinfo; - - memset(buf, 0, sizeof(buf)); - 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)); + len = send_msg_v4(skt->fd, &msg, src); } 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)); + len = send_msg_v6(skt->fd, &msg, src); } } + else + { + len = send_msg_generic(skt->fd, &msg); + } - len = sendmsg(skt->fd, &msg, 0); if (len != data.len) { DBG1(DBG_NET, "error writing to socket: %s", strerror(errno));