comparison src/os/unix/ngx_udp_sendmsg_chain.c @ 6980:dbb0c854e308

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.
author Roman Arutyunyan <arut@nginx.com>
date Tue, 11 Apr 2017 16:41:53 +0300
parents 56fc55e32f23
children 8ce1a34f160b
comparison
equal deleted inserted replaced
6979:ef935cd7ed8d 6980:dbb0c854e308
201 { 201 {
202 ssize_t n; 202 ssize_t n;
203 ngx_err_t err; 203 ngx_err_t err;
204 struct msghdr msg; 204 struct msghdr msg;
205 205
206 #if (NGX_HAVE_MSGHDR_MSG_CONTROL)
207
208 #if (NGX_HAVE_IP_SENDSRCADDR)
209 u_char msg_control[CMSG_SPACE(sizeof(struct in_addr))];
210 #elif (NGX_HAVE_IP_PKTINFO)
211 u_char msg_control[CMSG_SPACE(sizeof(struct in_pktinfo))];
212 #endif
213
214 #if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO)
215 u_char msg_control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
216 #endif
217
218 #endif
219
206 ngx_memzero(&msg, sizeof(struct msghdr)); 220 ngx_memzero(&msg, sizeof(struct msghdr));
207 221
208 if (c->socklen) { 222 if (c->socklen) {
209 msg.msg_name = c->sockaddr; 223 msg.msg_name = c->sockaddr;
210 msg.msg_namelen = c->socklen; 224 msg.msg_namelen = c->socklen;
211 } 225 }
212 226
213 msg.msg_iov = vec->iovs; 227 msg.msg_iov = vec->iovs;
214 msg.msg_iovlen = vec->count; 228 msg.msg_iovlen = vec->count;
229
230 #if (NGX_HAVE_MSGHDR_MSG_CONTROL)
231
232 if (c->listening && c->listening->wildcard && c->local_sockaddr) {
233
234 #if (NGX_HAVE_IP_SENDSRCADDR)
235
236 if (c->local_sockaddr->sa_family == AF_INET) {
237 struct cmsghdr *cmsg;
238 struct in_addr *addr;
239 struct sockaddr_in *sin;
240
241 msg.msg_control = &msg_control;
242 msg.msg_controllen = sizeof(msg_control);
243
244 cmsg = CMSG_FIRSTHDR(&msg);
245 cmsg->cmsg_level = IPPROTO_IP;
246 cmsg->cmsg_type = IP_SENDSRCADDR;
247 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
248
249 sin = (struct sockaddr_in *) c->local_sockaddr;
250
251 addr = (struct in_addr *) CMSG_DATA(cmsg);
252 *addr = sin->sin_addr;
253 }
254
255 #elif (NGX_HAVE_IP_PKTINFO)
256
257 if (c->local_sockaddr->sa_family == AF_INET) {
258 struct cmsghdr *cmsg;
259 struct in_pktinfo *pkt;
260 struct sockaddr_in *sin;
261
262 msg.msg_control = &msg_control;
263 msg.msg_controllen = sizeof(msg_control);
264
265 cmsg = CMSG_FIRSTHDR(&msg);
266 cmsg->cmsg_level = IPPROTO_IP;
267 cmsg->cmsg_type = IP_PKTINFO;
268 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
269
270 sin = (struct sockaddr_in *) c->local_sockaddr;
271
272 pkt = (struct in_pktinfo *) CMSG_DATA(cmsg);
273 ngx_memzero(pkt, sizeof(struct in_pktinfo));
274 pkt->ipi_spec_dst = sin->sin_addr;
275 }
276
277 #endif
278
279 #if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO)
280
281 if (c->local_sockaddr->sa_family == AF_INET6) {
282 struct cmsghdr *cmsg;
283 struct in6_pktinfo *pkt6;
284 struct sockaddr_in6 *sin6;
285
286 msg.msg_control = &msg_control6;
287 msg.msg_controllen = sizeof(msg_control6);
288
289 cmsg = CMSG_FIRSTHDR(&msg);
290 cmsg->cmsg_level = IPPROTO_IPV6;
291 cmsg->cmsg_type = IPV6_PKTINFO;
292 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
293
294 sin6 = (struct sockaddr_in6 *) c->local_sockaddr;
295
296 pkt6 = (struct in6_pktinfo *) CMSG_DATA(cmsg);
297 ngx_memzero(pkt6, sizeof(struct in6_pktinfo));
298 pkt6->ipi6_addr = sin6->sin6_addr;
299 }
300
301 #endif
302 }
303
304 #endif
215 305
216 eintr: 306 eintr:
217 307
218 n = sendmsg(c->fd, &msg, 0); 308 n = sendmsg(c->fd, &msg, 0);
219 309