source: MondoRescue/branches/3.3/mindi-busybox/libbb/udp_io.c@ 3906

Last change on this file since 3906 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

  • Property svn:eol-style set to native
File size: 5.3 KB
Line 
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) 2007 Denys Vlasenko
6 *
7 * Licensed under GPLv2, see file LICENSE in this source tree.
8 */
9#include "libbb.h"
10
11/*
12 * This asks kernel to let us know dst addr/port of incoming packets
13 * We don't check for errors here. Not supported == won't be used
14 */
15void FAST_FUNC
16socket_want_pktinfo(int fd UNUSED_PARAM)
17{
18#ifdef IP_PKTINFO
19 setsockopt_1(fd, IPPROTO_IP, IP_PKTINFO);
20#endif
21#if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO)
22 setsockopt_1(fd, IPPROTO_IPV6, IPV6_PKTINFO);
23#endif
24}
25
26
27ssize_t FAST_FUNC
28send_to_from(int fd, void *buf, size_t len, int flags,
29 const struct sockaddr *to,
30 const struct sockaddr *from,
31 socklen_t tolen)
32{
33#ifndef IP_PKTINFO
34 (void)from; /* suppress "unused from" warning */
35 return sendto(fd, buf, len, flags, to, tolen);
36#else
37 struct iovec iov[1];
38 struct msghdr msg;
39 union {
40 char cmsg[CMSG_SPACE(sizeof(struct in_pktinfo))];
41# if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO)
42 char cmsg6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
43# endif
44 } u;
45 struct cmsghdr* cmsgptr;
46
47 if (from->sa_family != AF_INET
48# if ENABLE_FEATURE_IPV6
49 && from->sa_family != AF_INET6
50# endif
51 ) {
52 /* ANY local address */
53 return sendto(fd, buf, len, flags, to, tolen);
54 }
55
56 /* man recvmsg and man cmsg is needed to make sense of code below */
57
58 iov[0].iov_base = buf;
59 iov[0].iov_len = len;
60
61 memset(&u, 0, sizeof(u));
62
63 memset(&msg, 0, sizeof(msg));
64 msg.msg_name = (void *)(struct sockaddr *)to; /* or compiler will annoy us */
65 msg.msg_namelen = tolen;
66 msg.msg_iov = iov;
67 msg.msg_iovlen = 1;
68 msg.msg_control = &u;
69 msg.msg_controllen = sizeof(u);
70 msg.msg_flags = flags;
71
72 cmsgptr = CMSG_FIRSTHDR(&msg);
73 if (to->sa_family == AF_INET && from->sa_family == AF_INET) {
74 struct in_pktinfo *pktptr;
75 cmsgptr->cmsg_level = IPPROTO_IP;
76 cmsgptr->cmsg_type = IP_PKTINFO;
77 cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
78 pktptr = (struct in_pktinfo *)(CMSG_DATA(cmsgptr));
79 /*pktptr->ipi_ifindex = 0; -- already done by memset(u...) */
80 /* In general, CMSG_DATA() can be unaligned, but in this case
81 * we know for sure it is sufficiently aligned:
82 * CMSG_FIRSTHDR simply returns &u above,
83 * and CMSG_DATA returns &u + size_t + int + int.
84 * Thus direct assignment is ok:
85 */
86 pktptr->ipi_spec_dst = ((struct sockaddr_in*)from)->sin_addr;
87 }
88# if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO)
89 else if (to->sa_family == AF_INET6 && from->sa_family == AF_INET6) {
90 struct in6_pktinfo *pktptr;
91 cmsgptr->cmsg_level = IPPROTO_IPV6;
92 cmsgptr->cmsg_type = IPV6_PKTINFO;
93 cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
94 pktptr = (struct in6_pktinfo *)(CMSG_DATA(cmsgptr));
95 /* pktptr->ipi6_ifindex = 0; -- already done by memset(u...) */
96 pktptr->ipi6_addr = ((struct sockaddr_in6*)from)->sin6_addr;
97 }
98# endif
99 msg.msg_controllen = cmsgptr->cmsg_len;
100
101 return sendmsg(fd, &msg, flags);
102#endif
103}
104
105/* NB: this will never set port# in 'to'!
106 * _Only_ IP/IPv6 address part of 'to' is _maybe_ modified.
107 * Typical usage is to preinit 'to' with "default" value
108 * before calling recv_from_to(). */
109ssize_t FAST_FUNC
110recv_from_to(int fd, void *buf, size_t len, int flags,
111 struct sockaddr *from, struct sockaddr *to,
112 socklen_t sa_size)
113{
114#ifndef IP_PKTINFO
115 (void)to; /* suppress "unused to" warning */
116 return recvfrom(fd, buf, len, flags, from, &sa_size);
117#else
118 /* man recvmsg and man cmsg is needed to make sense of code below */
119 struct iovec iov[1];
120 union {
121 char cmsg[CMSG_SPACE(sizeof(struct in_pktinfo))];
122# if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO)
123 char cmsg6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
124# endif
125 } u;
126 struct cmsghdr *cmsgptr;
127 struct msghdr msg;
128 ssize_t recv_length;
129
130 iov[0].iov_base = buf;
131 iov[0].iov_len = len;
132
133 memset(&msg, 0, sizeof(msg));
134 msg.msg_name = (struct sockaddr *)from;
135 msg.msg_namelen = sa_size;
136 msg.msg_iov = iov;
137 msg.msg_iovlen = 1;
138 msg.msg_control = &u;
139 msg.msg_controllen = sizeof(u);
140
141 recv_length = recvmsg(fd, &msg, flags);
142 if (recv_length < 0)
143 return recv_length;
144
145# define to4 ((struct sockaddr_in*)to)
146# define to6 ((struct sockaddr_in6*)to)
147 /* Here we try to retrieve destination IP and memorize it */
148 for (cmsgptr = CMSG_FIRSTHDR(&msg);
149 cmsgptr != NULL;
150 cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)
151 ) {
152 if (cmsgptr->cmsg_level == IPPROTO_IP
153 && cmsgptr->cmsg_type == IP_PKTINFO
154 ) {
155 const int IPI_ADDR_OFF = offsetof(struct in_pktinfo, ipi_addr);
156 to->sa_family = AF_INET;
157 /*# define pktinfo(cmsgptr) ( (struct in_pktinfo*)(CMSG_DATA(cmsgptr)) )*/
158 /*to4->sin_addr = pktinfo(cmsgptr)->ipi_addr; - may be unaligned */
159 memcpy(&to4->sin_addr, (char*)(CMSG_DATA(cmsgptr)) + IPI_ADDR_OFF, sizeof(to4->sin_addr));
160 /*to4->sin_port = 123; - this data is not supplied by kernel */
161 break;
162 }
163# if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO)
164 if (cmsgptr->cmsg_level == IPPROTO_IPV6
165 && cmsgptr->cmsg_type == IPV6_PKTINFO
166 ) {
167 const int IPI6_ADDR_OFF = offsetof(struct in6_pktinfo, ipi6_addr);
168 to->sa_family = AF_INET6;
169 /*# define pktinfo(cmsgptr) ( (struct in6_pktinfo*)(CMSG_DATA(cmsgptr)) )*/
170 /*to6->sin6_addr = pktinfo(cmsgptr)->ipi6_addr; - may be unaligned */
171 memcpy(&to6->sin6_addr, (char*)(CMSG_DATA(cmsgptr)) + IPI6_ADDR_OFF, sizeof(to6->sin6_addr));
172 /*to6->sin6_port = 123; */
173 break;
174 }
175# endif
176 }
177 return recv_length;
178#endif
179}
Note: See TracBrowser for help on using the repository browser.