4
4
*/
5
5
#include <sys/types.h>
6
6
#include <sys/socket.h>
7
+ #include <sys/un.h>
7
8
#include <arpa/inet.h>
8
9
#include <errno.h>
9
10
#include <fcntl.h>
10
11
#include <libubox/list.h>
11
12
#include <libubox/uloop.h>
13
+ #include <libubox/usock.h>
12
14
#include <netinet/in.h>
13
15
#include <netinet/ip.h>
14
16
#include <netinet/ip6.h>
19
21
20
22
static char pex_tx_buf [PEX_BUF_SIZE ];
21
23
static FILE * pex_urandom ;
22
- static struct uloop_fd pex_fd ;
24
+ static struct uloop_fd pex_fd , pex_unix_fd ;
23
25
static LIST_HEAD (requests );
24
26
static struct uloop_timeout gc_timer ;
25
27
static int pex_raw_v4_fd = -1 , pex_raw_v6_fd = -1 ;
26
28
27
29
static pex_recv_cb_t pex_recv_cb ;
30
+ static pex_recv_control_cb_t pex_control_cb ;
31
+ static int pex_unix_tx_fd = -1 ;
32
+
33
+ static const void *
34
+ get_mapped_sockaddr (const void * addr )
35
+ {
36
+ static struct sockaddr_in6 sin6 ;
37
+ const struct sockaddr_in * sin = addr ;
38
+
39
+ if (!sin || sin -> sin_family != AF_INET )
40
+ return addr ;
41
+
42
+ memset (& sin6 , 0 , sizeof (sin6 ));
43
+ sin6 .sin6_family = AF_INET6 ;
44
+ sin6 .sin6_addr .s6_addr [10 ] = 0xff ;
45
+ sin6 .sin6_addr .s6_addr [11 ] = 0xff ;
46
+ memcpy (& sin6 .sin6_addr .s6_addr [12 ], & sin -> sin_addr , sizeof (struct in_addr ));
47
+ sin6 .sin6_port = sin -> sin_port ;
48
+
49
+ return & sin6 ;
50
+ }
28
51
29
52
struct pex_msg_update_recv_ctx {
30
53
struct list_head list ;
@@ -112,12 +135,20 @@ void *pex_msg_append(size_t len)
112
135
static void
113
136
pex_fd_cb (struct uloop_fd * fd , unsigned int events )
114
137
{
115
- struct sockaddr_in6 sin6 ;
116
- static char buf [PEX_BUF_SIZE ];
138
+ static struct sockaddr_in6 sin6 ;
139
+ static char buf [PEX_RX_BUF_SIZE ];
117
140
struct pex_hdr * hdr = (struct pex_hdr * )buf ;
118
141
ssize_t len ;
119
142
120
143
while (1 ) {
144
+ static struct iovec iov [2 ] = {
145
+ { .iov_base = & sin6 },
146
+ { .iov_base = buf },
147
+ };
148
+ static struct msghdr msg = {
149
+ .msg_iov = iov ,
150
+ .msg_iovlen = ARRAY_SIZE (iov ),
151
+ };
121
152
socklen_t slen = sizeof (sin6 );
122
153
123
154
len = recvfrom (fd -> fd , buf , sizeof (buf ), 0 , (struct sockaddr * )& sin6 , & slen );
@@ -135,6 +166,39 @@ pex_fd_cb(struct uloop_fd *fd, unsigned int events)
135
166
if (!len )
136
167
continue ;
137
168
169
+ if (IN6_IS_ADDR_V4MAPPED (& sin6 .sin6_addr )) {
170
+ struct sockaddr_in * sin = (struct sockaddr_in * )& sin6 ;
171
+ struct in_addr in = * (struct in_addr * )& sin6 .sin6_addr .s6_addr [12 ];
172
+ int port = sin6 .sin6_port ;
173
+
174
+ memset (& sin6 , 0 , sizeof (sin6 ));
175
+ sin -> sin_port = port ;
176
+ sin -> sin_family = AF_INET ;
177
+ sin -> sin_addr = in ;
178
+ slen = sizeof (* sin );
179
+ }
180
+
181
+ retry :
182
+ if (pex_unix_tx_fd >= 0 ) {
183
+ iov [0 ].iov_len = slen ;
184
+ iov [1 ].iov_len = len ;
185
+ if (sendmsg (pex_unix_tx_fd , & msg , 0 ) < 0 ) {
186
+ switch (errno ) {
187
+ case EINTR :
188
+ goto retry ;
189
+ case EMSGSIZE :
190
+ case ENOBUFS :
191
+ case EAGAIN :
192
+ continue ;
193
+ default :
194
+ perror ("sendmsg" );
195
+ close (pex_unix_tx_fd );
196
+ pex_unix_tx_fd = -1 ;
197
+ break ;
198
+ }
199
+ }
200
+ }
201
+
138
202
if (len < sizeof (* hdr ) + sizeof (struct pex_ext_hdr ))
139
203
continue ;
140
204
@@ -146,6 +210,86 @@ pex_fd_cb(struct uloop_fd *fd, unsigned int events)
146
210
}
147
211
}
148
212
213
+ static void
214
+ pex_unix_cb (struct uloop_fd * fd , unsigned int events )
215
+ {
216
+ static char buf [PEX_RX_BUF_SIZE ];
217
+ static struct iovec iov = {
218
+ .iov_base = buf ,
219
+ .iov_len = sizeof (buf ),
220
+ };
221
+ ssize_t len ;
222
+
223
+ while (1 ) {
224
+ const struct sockaddr * sa = (struct sockaddr * )buf ;
225
+ uint8_t fd_buf [CMSG_SPACE (sizeof (int ))] = { 0 };
226
+ struct msghdr msg = {
227
+ .msg_iov = & iov ,
228
+ .msg_iovlen = 1 ,
229
+ .msg_control = fd_buf ,
230
+ .msg_controllen = CMSG_LEN (sizeof (int )),
231
+ };
232
+ struct cmsghdr * cmsg ;
233
+ socklen_t slen ;
234
+ int * pfd ;
235
+
236
+ cmsg = CMSG_FIRSTHDR (& msg );
237
+ cmsg -> cmsg_type = SCM_RIGHTS ;
238
+ cmsg -> cmsg_level = SOL_SOCKET ;
239
+ cmsg -> cmsg_len = CMSG_LEN (sizeof (int ));
240
+
241
+ pfd = (int * )CMSG_DATA (cmsg );
242
+ * pfd = -1 ;
243
+
244
+ len = recvmsg (fd -> fd , & msg , 0 );
245
+ if (len < 0 ) {
246
+ if (errno == EINTR )
247
+ continue ;
248
+
249
+ if (errno == EAGAIN )
250
+ break ;
251
+
252
+ pex_close ();
253
+ return ;
254
+ }
255
+
256
+ if (* pfd >= 0 ) {
257
+ if (pex_unix_tx_fd >= 0 )
258
+ close (pex_unix_tx_fd );
259
+
260
+ pex_unix_tx_fd = * pfd ;
261
+ }
262
+
263
+ if (!len )
264
+ continue ;
265
+
266
+ if (len < sizeof (* sa ))
267
+ continue ;
268
+
269
+ if (sa -> sa_family == AF_LOCAL ) {
270
+ slen = sizeof (struct sockaddr );
271
+ len -= slen ;
272
+ if (len < sizeof (struct pex_msg_local_control ))
273
+ continue ;
274
+
275
+ if (pex_control_cb )
276
+ pex_control_cb ((struct pex_msg_local_control * )& buf [slen ], len );
277
+
278
+ continue ;
279
+ }
280
+
281
+ if (sa -> sa_family == AF_INET )
282
+ slen = sizeof (struct sockaddr_in );
283
+ else if (sa -> sa_family == AF_INET6 )
284
+ slen = sizeof (struct sockaddr_in6 );
285
+ else
286
+ continue ;
287
+
288
+ sa = get_mapped_sockaddr (sa );
289
+ sendto (pex_fd .fd , buf + slen , len - slen , 0 , sa , sizeof (struct sockaddr_in6 ));
290
+ }
291
+ }
292
+
149
293
static inline uint32_t
150
294
csum_tcpudp_nofold (uint32_t saddr , uint32_t daddr , uint32_t len , uint8_t proto )
151
295
{
@@ -268,8 +412,10 @@ int __pex_msg_send(int fd, const void *addr, void *ip_hdr, size_t ip_hdrlen)
268
412
hdr -> len -= sizeof (struct pex_ext_hdr );
269
413
if (ip_hdrlen )
270
414
fd = sa -> sa_family == AF_INET6 ? pex_raw_v6_fd : pex_raw_v4_fd ;
271
- else
415
+ else {
272
416
fd = pex_fd .fd ;
417
+ sa = addr = get_mapped_sockaddr (addr );
418
+ }
273
419
274
420
if (fd < 0 )
275
421
return -1 ;
@@ -612,21 +758,50 @@ int pex_open(void *addr, size_t addr_len, pex_recv_cb_t cb, bool server)
612
758
return -1 ;
613
759
}
614
760
615
- void pex_close ( void )
761
+ int pex_unix_open ( const char * path , pex_recv_control_cb_t cb )
616
762
{
617
- if (!pex_fd .cb )
618
- return ;
763
+ mode_t prev_mask ;
764
+ int fd ;
765
+
766
+ pex_control_cb = cb ;
767
+ unlink (path );
619
768
769
+ prev_mask = umask (0177 );
770
+ fd = usock (USOCK_UDP | USOCK_UNIX | USOCK_SERVER | USOCK_NONBLOCK , path , NULL );
771
+ umask (prev_mask );
772
+ if (fd < 0 )
773
+ return -1 ;
774
+
775
+ pex_unix_fd .cb = pex_unix_cb ;
776
+ pex_unix_fd .fd = fd ;
777
+ uloop_fd_add (& pex_unix_fd , ULOOP_READ );
778
+
779
+ return 0 ;
780
+ }
781
+
782
+ void pex_close (void )
783
+ {
620
784
if (pex_raw_v4_fd >= 0 )
621
785
close (pex_raw_v4_fd );
622
786
if (pex_raw_v6_fd >= 0 )
623
787
close (pex_raw_v6_fd );
624
788
pex_raw_v4_fd = -1 ;
625
789
pex_raw_v6_fd = -1 ;
626
790
627
- fclose (pex_urandom );
628
- uloop_fd_delete (& pex_fd );
629
- close (pex_fd .fd );
791
+ if (pex_urandom )
792
+ fclose (pex_urandom );
793
+
794
+ if (pex_fd .cb ) {
795
+ uloop_fd_delete (& pex_fd );
796
+ close (pex_fd .fd );
797
+ }
798
+
799
+ if (pex_unix_fd .cb ) {
800
+ uloop_fd_delete (& pex_unix_fd );
801
+ close (pex_unix_fd .fd );
802
+ }
803
+
630
804
pex_fd .cb = NULL ;
805
+ pex_unix_fd .cb = NULL ;
631
806
pex_urandom = NULL ;
632
807
}
0 commit comments