1
2
3
4
5
6
7
8
9#include "libbb.h"
10
11
12
13
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;
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
53 return sendto(fd, buf, len, flags, to, tolen);
54 }
55
56
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;
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
74
75
76
77
78
79 if ( from->sa_family == AF_INET) {
80 struct in_pktinfo *pktptr;
81 cmsgptr->cmsg_level = IPPROTO_IP;
82 cmsgptr->cmsg_type = IP_PKTINFO;
83 cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
84 pktptr = (struct in_pktinfo *)(CMSG_DATA(cmsgptr));
85
86
87
88
89
90
91
92 pktptr->ipi_spec_dst = ((struct sockaddr_in*)from)->sin_addr;
93 }
94# if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO)
95 else if ( from->sa_family == AF_INET6) {
96 struct in6_pktinfo *pktptr;
97 cmsgptr->cmsg_level = IPPROTO_IPV6;
98 cmsgptr->cmsg_type = IPV6_PKTINFO;
99 cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
100 pktptr = (struct in6_pktinfo *)(CMSG_DATA(cmsgptr));
101
102 pktptr->ipi6_addr = ((struct sockaddr_in6*)from)->sin6_addr;
103 }
104# endif
105 msg.msg_controllen = cmsgptr->cmsg_len;
106
107 return sendmsg(fd, &msg, flags);
108#endif
109}
110
111
112
113
114
115ssize_t FAST_FUNC
116recv_from_to(int fd, void *buf, size_t len, int flags,
117 struct sockaddr *from, struct sockaddr *to,
118 socklen_t sa_size)
119{
120#ifndef IP_PKTINFO
121 (void)to;
122 return recvfrom(fd, buf, len, flags, from, &sa_size);
123#else
124
125 struct iovec iov[1];
126 union {
127 char cmsg[CMSG_SPACE(sizeof(struct in_pktinfo))];
128# if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO)
129 char cmsg6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
130# endif
131 } u;
132 struct cmsghdr *cmsgptr;
133 struct msghdr msg;
134 ssize_t recv_length;
135
136 iov[0].iov_base = buf;
137 iov[0].iov_len = len;
138
139 memset(&msg, 0, sizeof(msg));
140 msg.msg_name = (struct sockaddr *)from;
141 msg.msg_namelen = sa_size;
142 msg.msg_iov = iov;
143 msg.msg_iovlen = 1;
144 msg.msg_control = &u;
145 msg.msg_controllen = sizeof(u);
146
147 recv_length = recvmsg(fd, &msg, flags);
148 if (recv_length < 0)
149 return recv_length;
150
151# define to4 ((struct sockaddr_in*)to)
152# define to6 ((struct sockaddr_in6*)to)
153
154 for (cmsgptr = CMSG_FIRSTHDR(&msg);
155 cmsgptr != NULL;
156 cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)
157 ) {
158 if (cmsgptr->cmsg_level == IPPROTO_IP
159 && cmsgptr->cmsg_type == IP_PKTINFO
160 ) {
161 const int IPI_ADDR_OFF = offsetof(struct in_pktinfo, ipi_addr);
162 to->sa_family = AF_INET;
163
164
165 memcpy(&to4->sin_addr, (char*)(CMSG_DATA(cmsgptr)) + IPI_ADDR_OFF, sizeof(to4->sin_addr));
166
167 break;
168 }
169# if ENABLE_FEATURE_IPV6 && defined(IPV6_PKTINFO)
170 if (cmsgptr->cmsg_level == IPPROTO_IPV6
171 && cmsgptr->cmsg_type == IPV6_PKTINFO
172 ) {
173 const int IPI6_ADDR_OFF = offsetof(struct in6_pktinfo, ipi6_addr);
174 to->sa_family = AF_INET6;
175
176
177 memcpy(&to6->sin6_addr, (char*)(CMSG_DATA(cmsgptr)) + IPI6_ADDR_OFF, sizeof(to6->sin6_addr));
178
179 break;
180 }
181# endif
182 }
183 return recv_length;
184#endif
185}
186