Ticket #1239: udp-send-addr

File udp-send-addr, 3.8 KB (added by Roman Arutyunyan, 9 years ago)
Line 
1# HG changeset patch
2# User Roman Arutyunyan <arut@nginx.com>
3# Date 1491569164 -10800
4# Fri Apr 07 15:46:04 2017 +0300
5# Node ID 213701890e6fefc21f8fd34191006ac79bbd3512
6# Parent 3ff293cfdab85082a9560ab56ea9f16b02a8a8c8
7Set UDP source address.
8
9When multiple IP addresses from the same subnet are configured in a system, and
10nginx is listening on a wildcard address, the response UDP packet might be sent
11from the wrong source address. Now source address is set explicitly if a
12response is sent for a wildcard listener.
13
14diff --git a/src/os/unix/ngx_udp_sendmsg_chain.c b/src/os/unix/ngx_udp_sendmsg_chain.c
15--- a/src/os/unix/ngx_udp_sendmsg_chain.c
16+++ b/src/os/unix/ngx_udp_sendmsg_chain.c
17@@ -203,6 +203,21 @@ ngx_sendmsg(ngx_connection_t *c, ngx_iov
18 ngx_err_t err;
19 struct msghdr msg;
20
21+#if (NGX_HAVE_MSGHDR_MSG_CONTROL)
22+ union {
23+#if (NGX_HAVE_IP_RECVDSTADDR)
24+ u_char msg_control[CMSG_SPACE(sizeof(struct in_addr))];
25+#elif (NGX_HAVE_IP_PKTINFO)
26+ u_char msg_control[CMSG_SPACE(sizeof(struct in_pktinfo))];
27+#endif
28+
29+#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO)
30+ u_char msg_control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
31+#endif
32+ struct cmsghdr align;
33+ } u;
34+#endif
35+
36 ngx_memzero(&msg, sizeof(struct msghdr));
37
38 if (c->socklen) {
39@@ -213,6 +228,82 @@ ngx_sendmsg(ngx_connection_t *c, ngx_iov
40 msg.msg_iov = vec->iovs;
41 msg.msg_iovlen = vec->count;
42
43+#if (NGX_HAVE_MSGHDR_MSG_CONTROL)
44+
45+ if (c->listening && c->listening->wildcard && c->local_sockaddr) {
46+
47+#if (NGX_HAVE_IP_RECVDSTADDR)
48+
49+ if (c->local_sockaddr->sa_family == AF_INET) {
50+ struct cmsghdr *cmsg;
51+ struct in_addr *addr;
52+ struct sockaddr_in *sin;
53+
54+ msg.msg_control = &u.msg_control;
55+ msg.msg_controllen = sizeof(u.msg_control);
56+
57+ cmsg = CMSG_FIRSTHDR(&msg);
58+ cmsg->cmsg_level = IPPROTO_IP;
59+ cmsg->cmsg_type = IP_RECVDSTADDR;
60+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
61+
62+ sin = (struct sockaddr_in *) c->local_sockaddr;
63+
64+ addr = (struct in_addr *) CMSG_DATA(cmsg);
65+ *addr = sin->sin_addr;
66+ }
67+
68+#elif (NGX_HAVE_IP_PKTINFO)
69+
70+ if (c->local_sockaddr->sa_family == AF_INET) {
71+ struct cmsghdr *cmsg;
72+ struct in_pktinfo *pkt;
73+ struct sockaddr_in *sin;
74+
75+ msg.msg_control = &u.msg_control;
76+ msg.msg_controllen = sizeof(u.msg_control);
77+
78+ cmsg = CMSG_FIRSTHDR(&msg);
79+ cmsg->cmsg_level = IPPROTO_IP;
80+ cmsg->cmsg_type = IP_PKTINFO;
81+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
82+
83+ sin = (struct sockaddr_in *) c->local_sockaddr;
84+
85+ pkt = (struct in_pktinfo *) CMSG_DATA(cmsg);
86+ ngx_memzero(pkt, sizeof(struct in_pktinfo));
87+ pkt->ipi_spec_dst = sin->sin_addr;
88+ }
89+
90+#endif
91+
92+#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO)
93+
94+ if (c->local_sockaddr->sa_family == AF_INET6) {
95+ struct cmsghdr *cmsg;
96+ struct in6_pktinfo *pkt6;
97+ struct sockaddr_in6 *sin6;
98+
99+ msg.msg_control = &u.msg_control6;
100+ msg.msg_controllen = sizeof(u.msg_control6);
101+
102+ cmsg = CMSG_FIRSTHDR(&msg);
103+ cmsg->cmsg_level = IPPROTO_IPV6;
104+ cmsg->cmsg_type = IPV6_PKTINFO;
105+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
106+
107+ sin6 = (struct sockaddr_in6 *) c->local_sockaddr;
108+
109+ pkt6 = (struct in6_pktinfo *) CMSG_DATA(cmsg);
110+ ngx_memzero(pkt6, sizeof(struct in6_pktinfo));
111+ pkt6->ipi6_addr = sin6->sin6_addr;
112+ }
113+
114+#endif
115+ }
116+
117+#endif
118+
119 eintr:
120
121 n = sendmsg(c->fd, &msg, 0);