[nginx] Set UDP datagram source address (ticket #1239).

Roman Arutyunyan arut at nginx.com
Tue Apr 18 12:02:13 UTC 2017


details:   http://hg.nginx.org/nginx/rev/dbb0c854e308
branches:  
changeset: 6980:dbb0c854e308
user:      Roman Arutyunyan <arut at nginx.com>
date:      Tue Apr 11 16:41:53 2017 +0300
description:
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:

 auto/unix                           |  13 +++++
 src/os/unix/ngx_udp_sendmsg_chain.c |  90 +++++++++++++++++++++++++++++++++++++
 2 files changed, 103 insertions(+), 0 deletions(-)

diffs (130 lines):

diff -r ef935cd7ed8d -r dbb0c854e308 auto/unix
--- a/auto/unix	Tue Apr 18 13:01:19 2017 +0300
+++ b/auto/unix	Tue Apr 11 16:41:53 2017 +0300
@@ -394,6 +394,19 @@ ngx_feature_test="setsockopt(0, IPPROTO_
 . auto/feature
 
 
+# BSD way to set IPv4 datagram source address
+
+ngx_feature="IP_SENDSRCADDR"
+ngx_feature_name="NGX_HAVE_IP_SENDSRCADDR"
+ngx_feature_run=no
+ngx_feature_incs="#include <sys/socket.h>
+                  #include <netinet/in.h>"
+ngx_feature_path=
+ngx_feature_libs=
+ngx_feature_test="setsockopt(0, IPPROTO_IP, IP_SENDSRCADDR, NULL, 0)"
+. auto/feature
+
+
 # Linux way to get IPv4 datagram destination address
 
 ngx_feature="IP_PKTINFO"
diff -r ef935cd7ed8d -r dbb0c854e308 src/os/unix/ngx_udp_sendmsg_chain.c
--- a/src/os/unix/ngx_udp_sendmsg_chain.c	Tue Apr 18 13:01:19 2017 +0300
+++ b/src/os/unix/ngx_udp_sendmsg_chain.c	Tue Apr 11 16:41:53 2017 +0300
@@ -203,6 +203,20 @@ ngx_sendmsg(ngx_connection_t *c, ngx_iov
     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_iov
     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);


More information about the nginx-devel mailing list