Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nginx/nginx.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src/os
diff options
context:
space:
mode:
authorRoman Arutyunyan <arut@nginx.com>2017-04-11 16:41:53 +0300
committerRoman Arutyunyan <arut@nginx.com>2017-04-11 16:41:53 +0300
commit05841adfb2e5d50dee066b6f92cbb95b78c5b725 (patch)
tree5c719a5c7ae8d897244cfa94639cf65337342fba /src/os
parent62b20ce87ae9dda51010742523ccad9650380f11 (diff)
Set UDP datagram source address (ticket #1239).
Previously, the source IP address of a response UDP datagram could differ from the original datagram destination address. This could happen if the server UDP socket is bound to a wildcard address and the network interface chosen to output the response packet has a different default address than the destination address of the original packet. For example, if two addresses from the same network are configured on an interface. Now source address is set explicitly if a response is sent for a server UDP socket bound to a wildcard address.
Diffstat (limited to 'src/os')
-rw-r--r--src/os/unix/ngx_udp_sendmsg_chain.c90
1 files changed, 90 insertions, 0 deletions
diff --git a/src/os/unix/ngx_udp_sendmsg_chain.c b/src/os/unix/ngx_udp_sendmsg_chain.c
index 65bde6f97..5f1cfa54e 100644
--- a/src/os/unix/ngx_udp_sendmsg_chain.c
+++ b/src/os/unix/ngx_udp_sendmsg_chain.c
@@ -203,6 +203,20 @@ ngx_sendmsg(ngx_connection_t *c, ngx_iovec_t *vec)
ngx_err_t err;
struct msghdr msg;
+#if (NGX_HAVE_MSGHDR_MSG_CONTROL)
+
+#if (NGX_HAVE_IP_SENDSRCADDR)
+ u_char msg_control[CMSG_SPACE(sizeof(struct in_addr))];
+#elif (NGX_HAVE_IP_PKTINFO)
+ u_char msg_control[CMSG_SPACE(sizeof(struct in_pktinfo))];
+#endif
+
+#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO)
+ u_char msg_control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
+#endif
+
+#endif
+
ngx_memzero(&msg, sizeof(struct msghdr));
if (c->socklen) {
@@ -213,6 +227,82 @@ ngx_sendmsg(ngx_connection_t *c, ngx_iovec_t *vec)
msg.msg_iov = vec->iovs;
msg.msg_iovlen = vec->count;
+#if (NGX_HAVE_MSGHDR_MSG_CONTROL)
+
+ if (c->listening && c->listening->wildcard && c->local_sockaddr) {
+
+#if (NGX_HAVE_IP_SENDSRCADDR)
+
+ if (c->local_sockaddr->sa_family == AF_INET) {
+ struct cmsghdr *cmsg;
+ struct in_addr *addr;
+ struct sockaddr_in *sin;
+
+ msg.msg_control = &msg_control;
+ msg.msg_controllen = sizeof(msg_control);
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_level = IPPROTO_IP;
+ cmsg->cmsg_type = IP_SENDSRCADDR;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
+
+ sin = (struct sockaddr_in *) c->local_sockaddr;
+
+ addr = (struct in_addr *) CMSG_DATA(cmsg);
+ *addr = sin->sin_addr;
+ }
+
+#elif (NGX_HAVE_IP_PKTINFO)
+
+ if (c->local_sockaddr->sa_family == AF_INET) {
+ struct cmsghdr *cmsg;
+ struct in_pktinfo *pkt;
+ struct sockaddr_in *sin;
+
+ msg.msg_control = &msg_control;
+ msg.msg_controllen = sizeof(msg_control);
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_level = IPPROTO_IP;
+ cmsg->cmsg_type = IP_PKTINFO;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
+
+ sin = (struct sockaddr_in *) c->local_sockaddr;
+
+ pkt = (struct in_pktinfo *) CMSG_DATA(cmsg);
+ ngx_memzero(pkt, sizeof(struct in_pktinfo));
+ pkt->ipi_spec_dst = sin->sin_addr;
+ }
+
+#endif
+
+#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO)
+
+ if (c->local_sockaddr->sa_family == AF_INET6) {
+ struct cmsghdr *cmsg;
+ struct in6_pktinfo *pkt6;
+ struct sockaddr_in6 *sin6;
+
+ msg.msg_control = &msg_control6;
+ msg.msg_controllen = sizeof(msg_control6);
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_level = IPPROTO_IPV6;
+ cmsg->cmsg_type = IPV6_PKTINFO;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
+
+ sin6 = (struct sockaddr_in6 *) c->local_sockaddr;
+
+ pkt6 = (struct in6_pktinfo *) CMSG_DATA(cmsg);
+ ngx_memzero(pkt6, sizeof(struct in6_pktinfo));
+ pkt6->ipi6_addr = sin6->sin6_addr;
+ }
+
+#endif
+ }
+
+#endif
+
eintr:
n = sendmsg(c->fd, &msg, 0);