1 /*
2 * TCP/IP or UDP/IP networking functions
3 * modified for LWIP support on ESP32
4 *
5 * SPDX-FileCopyrightText: The Mbed TLS Contributors
6 *
7 * SPDX-License-Identifier: Apache-2.0
8 *
9 * SPDX-FileContributor: 2015 Angus Gratton
10 */
11
12 #include <mbedtls/build_info.h>
13
14 #if !defined(MBEDTLS_NET_C)
15
16 #if defined(MBEDTLS_PLATFORM_C)
17 #include "mbedtls/platform.h"
18 #else
19 #include <stdlib.h>
20 #define mbedtls_calloc calloc
21 #define mbedtls_free free
22 #define mbedtls_time time
23 #define mbedtls_time_t time_t
24 #endif
25
26 #include "mbedtls/net_sockets.h"
27
28 #include <string.h>
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <unistd.h>
32 #include <netdb.h>
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <time.h>
36 #include <stdint.h>
37 #include <fcntl.h>
38 #include <errno.h>
39
40 /*
41 * Prepare for using the sockets interface
42 */
net_prepare(void)43 static int net_prepare( void )
44 {
45 return ( 0 );
46 }
47
48 /*
49 * Initialize a context
50 */
mbedtls_net_init(mbedtls_net_context * ctx)51 void mbedtls_net_init( mbedtls_net_context *ctx )
52 {
53 ctx->fd = -1;
54 }
55
56 /*
57 * Initiate a TCP connection with host:port and the given protocol
58 */
mbedtls_net_connect(mbedtls_net_context * ctx,const char * host,const char * port,int proto)59 int mbedtls_net_connect( mbedtls_net_context *ctx, const char *host, const char *port, int proto )
60 {
61 int ret;
62 struct addrinfo hints, *addr_list, *cur;
63
64 if ( ( ret = net_prepare() ) != 0 ) {
65 return ( ret );
66 }
67
68 /* Do name resolution with both IPv6 and IPv4 */
69 memset( &hints, 0, sizeof( hints ) );
70 hints.ai_family = AF_UNSPEC;
71 hints.ai_socktype = proto == MBEDTLS_NET_PROTO_UDP ? SOCK_DGRAM : SOCK_STREAM;
72 hints.ai_protocol = proto == MBEDTLS_NET_PROTO_UDP ? IPPROTO_UDP : IPPROTO_TCP;
73
74 if ( getaddrinfo( host, port, &hints, &addr_list ) != 0 ) {
75 return ( MBEDTLS_ERR_NET_UNKNOWN_HOST );
76 }
77
78 /* Try the sockaddrs until a connection succeeds */
79 ret = MBEDTLS_ERR_NET_UNKNOWN_HOST;
80 for ( cur = addr_list; cur != NULL; cur = cur->ai_next ) {
81 int fd = socket( cur->ai_family, cur->ai_socktype, cur->ai_protocol );
82
83 if ( fd < 0 ) {
84 ret = MBEDTLS_ERR_NET_SOCKET_FAILED;
85 continue;
86 }
87
88 if ( connect( fd, cur->ai_addr, cur->ai_addrlen ) == 0 ) {
89 ctx->fd = fd; // connected!
90 ret = 0;
91 break;
92 }
93
94 close( fd );
95 ret = MBEDTLS_ERR_NET_CONNECT_FAILED;
96 }
97
98 freeaddrinfo( addr_list );
99
100 return ( ret );
101 }
102
103 /*
104 * Create a listening socket on bind_ip:port
105 */
mbedtls_net_bind(mbedtls_net_context * ctx,const char * bind_ip,const char * port,int proto)106 int mbedtls_net_bind( mbedtls_net_context *ctx, const char *bind_ip, const char *port, int proto )
107 {
108 int ret;
109 struct addrinfo hints, *addr_list, *cur;
110 struct sockaddr_storage *serv_addr = NULL;
111 #if SO_REUSE
112 int n = 1;
113 #endif
114
115 if ( ( ret = net_prepare() ) != 0 ) {
116 return ( ret );
117 }
118
119 /* Bind to IPv6 and/or IPv4, but only in the desired protocol */
120 memset( &hints, 0, sizeof( hints ) );
121 hints.ai_family = AF_UNSPEC;
122 hints.ai_socktype = proto == MBEDTLS_NET_PROTO_UDP ? SOCK_DGRAM : SOCK_STREAM;
123 hints.ai_protocol = proto == MBEDTLS_NET_PROTO_UDP ? IPPROTO_UDP : IPPROTO_TCP;
124
125 if ( getaddrinfo( bind_ip, port, &hints, &addr_list ) != 0 ) {
126 return ( MBEDTLS_ERR_NET_UNKNOWN_HOST );
127 }
128
129 /* Try the sockaddrs until a binding succeeds */
130 ret = MBEDTLS_ERR_NET_UNKNOWN_HOST;
131 for ( cur = addr_list; cur != NULL; cur = cur->ai_next ) {
132 int fd = socket( cur->ai_family, cur->ai_socktype, cur->ai_protocol );
133 if ( fd < 0 ) {
134 ret = MBEDTLS_ERR_NET_SOCKET_FAILED;
135 continue;
136 }
137
138 /*SO_REUSEADDR option dafault is disable in source code(lwip)*/
139 #if SO_REUSE
140 if ( setsockopt( fd, SOL_SOCKET, SO_REUSEADDR,
141 (const char *) &n, sizeof( n ) ) != 0 ) {
142 close( fd );
143 ret = MBEDTLS_ERR_NET_SOCKET_FAILED;
144 continue;
145 }
146 #endif
147 serv_addr = (struct sockaddr_storage *) cur->ai_addr;
148 #if CONFIG_LWIP_IPV4
149 if (cur->ai_family == AF_INET) {
150 /*bind interface dafault don't process the addr is 0xffffffff for TCP Protocol*/
151 struct sockaddr_in *p = (struct sockaddr_in *)serv_addr;
152 p->sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */
153 }
154 #endif // CONFIG_LWIP_IPV4
155 #if CONFIG_LWIP_IPV6
156 if (cur->ai_family == AF_INET6) {
157 struct sockaddr_in6 *p = (struct sockaddr_in6 *) serv_addr;
158 struct in6_addr inaddr_any = IN6ADDR_ANY_INIT;
159 p->sin6_addr = inaddr_any;
160 }
161 #endif // CONFIG_LWIP_IPV6
162
163 if ( bind( fd, (struct sockaddr *)serv_addr, cur->ai_addrlen ) != 0 ) {
164 close( fd );
165 ret = MBEDTLS_ERR_NET_BIND_FAILED;
166 continue;
167 }
168
169 /* Listen only makes sense for TCP */
170 if ( proto == MBEDTLS_NET_PROTO_TCP ) {
171 if ( listen( fd, MBEDTLS_NET_LISTEN_BACKLOG ) != 0 ) {
172 close( fd );
173 ret = MBEDTLS_ERR_NET_LISTEN_FAILED;
174 continue;
175 }
176 }
177
178 /* I we ever get there, it's a success */
179 ctx->fd = fd;
180 ret = 0;
181 break;
182 }
183
184 freeaddrinfo( addr_list );
185
186 return ( ret );
187
188 }
189
190 /*
191 * Check if the requested operation would be blocking on a non-blocking socket
192 * and thus 'failed' with a negative return value.
193 *
194 * Note: on a blocking socket this function always returns 0!
195 */
net_would_block(const mbedtls_net_context * ctx)196 static int net_would_block( const mbedtls_net_context *ctx )
197 {
198 int error = errno;
199
200 switch ( errno = error ) {
201 #if defined EAGAIN
202 case EAGAIN:
203 #endif
204 #if defined EWOULDBLOCK && EWOULDBLOCK != EAGAIN
205 case EWOULDBLOCK:
206 #endif
207 return ( 1 );
208 }
209 return ( 0 );
210 }
211
212 /*
213 * Accept a connection from a remote client
214 */
mbedtls_net_accept(mbedtls_net_context * bind_ctx,mbedtls_net_context * client_ctx,void * client_ip,size_t buf_size,size_t * ip_len)215 int mbedtls_net_accept( mbedtls_net_context *bind_ctx,
216 mbedtls_net_context *client_ctx,
217 void *client_ip, size_t buf_size, size_t *ip_len )
218 {
219 int ret;
220 int type;
221
222 struct sockaddr_storage client_addr;
223
224 socklen_t n = (socklen_t) sizeof( client_addr );
225 socklen_t type_len = (socklen_t) sizeof( type );
226
227 /* Is this a TCP or UDP socket? */
228 if ( getsockopt( bind_ctx->fd, SOL_SOCKET, SO_TYPE,
229 (void *) &type, (socklen_t *) &type_len ) != 0 ||
230 ( type != SOCK_STREAM && type != SOCK_DGRAM ) ) {
231 return ( MBEDTLS_ERR_NET_ACCEPT_FAILED );
232 }
233
234 if ( type == SOCK_STREAM ) {
235 /* TCP: actual accept() */
236 ret = client_ctx->fd = (int) accept( bind_ctx->fd,
237 (struct sockaddr *) &client_addr, &n );
238 } else {
239 /* UDP: wait for a message, but keep it in the queue */
240 char buf[1] = { 0 };
241
242 ret = recvfrom( bind_ctx->fd, buf, sizeof( buf ), MSG_PEEK,
243 (struct sockaddr *) &client_addr, &n );
244
245 }
246
247 if ( ret < 0 ) {
248 if ( net_would_block( bind_ctx ) != 0 ) {
249 return ( MBEDTLS_ERR_SSL_WANT_READ );
250 }
251
252 return ( MBEDTLS_ERR_NET_ACCEPT_FAILED );
253 }
254
255 /* UDP: hijack the listening socket to communicate with the client,
256 * then bind a new socket to accept new connections */
257 if ( type != SOCK_STREAM ) {
258 struct sockaddr_storage local_addr;
259 int one = 1;
260
261 if ( connect( bind_ctx->fd, (struct sockaddr *) &client_addr, n ) != 0 ) {
262 return ( MBEDTLS_ERR_NET_ACCEPT_FAILED );
263 }
264
265 client_ctx->fd = bind_ctx->fd;
266 bind_ctx->fd = -1; /* In case we exit early */
267
268 n = sizeof( struct sockaddr_storage );
269 if ( getsockname( client_ctx->fd,
270 (struct sockaddr *) &local_addr, &n ) != 0 ||
271 ( bind_ctx->fd = (int) socket( local_addr.ss_family,
272 SOCK_DGRAM, IPPROTO_UDP ) ) < 0 ||
273 setsockopt( bind_ctx->fd, SOL_SOCKET, SO_REUSEADDR,
274 (const char *) &one, sizeof( one ) ) != 0 ) {
275 return ( MBEDTLS_ERR_NET_SOCKET_FAILED );
276 }
277
278 if ( bind( bind_ctx->fd, (struct sockaddr *) &local_addr, n ) != 0 ) {
279 return ( MBEDTLS_ERR_NET_BIND_FAILED );
280 }
281 }
282
283 if ( client_ip != NULL ) {
284 #ifdef CONFIG_LWIP_IPV4
285 if( client_addr.ss_family == AF_INET )
286 {
287 struct sockaddr_in *addr4 = (struct sockaddr_in *) &client_addr;
288 *ip_len = sizeof( addr4->sin_addr.s_addr );
289
290 if ( buf_size < *ip_len ) {
291 return ( MBEDTLS_ERR_NET_BUFFER_TOO_SMALL );
292 }
293
294 memcpy( client_ip, &addr4->sin_addr.s_addr, *ip_len );
295 }
296 #endif // CONFIG_LWIP_IPV4
297 #ifdef CONFIG_LWIP_IPV6
298 if( client_addr.ss_family == AF_INET6 )
299 {
300 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) &client_addr;
301 *ip_len = sizeof( addr6->sin6_addr.s6_addr );
302
303 if( buf_size < *ip_len ) {
304 return( MBEDTLS_ERR_NET_BUFFER_TOO_SMALL );
305 }
306
307 memcpy( client_ip, &addr6->sin6_addr.s6_addr, *ip_len);
308 }
309 #endif // CONFIG_LWIP_IPV6
310 }
311
312 return ( 0 );
313 }
314
315 /*
316 * Set the socket blocking or non-blocking
317 */
mbedtls_net_set_block(mbedtls_net_context * ctx)318 int mbedtls_net_set_block( mbedtls_net_context *ctx )
319 {
320 return ( fcntl( ctx->fd, F_SETFL, fcntl( ctx->fd, F_GETFL, 0 ) & ~O_NONBLOCK ) );
321 }
322
mbedtls_net_set_nonblock(mbedtls_net_context * ctx)323 int mbedtls_net_set_nonblock( mbedtls_net_context *ctx )
324 {
325 return ( fcntl( ctx->fd, F_SETFL, fcntl( ctx->fd, F_GETFL, 0 ) | O_NONBLOCK ) );
326 }
327
328 /*
329 * Portable usleep helper
330 */
mbedtls_net_usleep(unsigned long usec)331 void mbedtls_net_usleep( unsigned long usec )
332 {
333 struct timeval tv;
334 tv.tv_sec = usec / 1000000;
335 tv.tv_usec = usec % 1000000;
336 select( 0, NULL, NULL, NULL, &tv );
337 }
338
339 /*
340 * Read at most 'len' characters
341 */
mbedtls_net_recv(void * ctx,unsigned char * buf,size_t len)342 int mbedtls_net_recv( void *ctx, unsigned char *buf, size_t len )
343 {
344 int ret;
345 int fd = ((mbedtls_net_context *) ctx)->fd;
346
347 if ( fd < 0 ) {
348 return ( MBEDTLS_ERR_NET_INVALID_CONTEXT );
349 }
350
351 ret = (int) read( fd, buf, len );
352
353 if ( ret < 0 ) {
354 if ( net_would_block( ctx ) != 0 ) {
355 return ( MBEDTLS_ERR_SSL_WANT_READ );
356 }
357
358 if ( errno == EPIPE || errno == ECONNRESET ) {
359 return ( MBEDTLS_ERR_NET_CONN_RESET );
360 }
361
362 if ( errno == EINTR ) {
363 return ( MBEDTLS_ERR_SSL_WANT_READ );
364 }
365
366 return ( MBEDTLS_ERR_NET_RECV_FAILED );
367 }
368
369 return ( ret );
370 }
371
372 /*
373 * Read at most 'len' characters, blocking for at most 'timeout' ms
374 */
mbedtls_net_recv_timeout(void * ctx,unsigned char * buf,size_t len,uint32_t timeout)375 int mbedtls_net_recv_timeout( void *ctx, unsigned char *buf, size_t len,
376 uint32_t timeout )
377 {
378 int ret;
379 struct timeval tv;
380 fd_set read_fds;
381 int fd = ((mbedtls_net_context *) ctx)->fd;
382
383 if ( fd < 0 ) {
384 return ( MBEDTLS_ERR_NET_INVALID_CONTEXT );
385 }
386
387 FD_ZERO( &read_fds );
388 FD_SET( fd, &read_fds );
389
390 tv.tv_sec = timeout / 1000;
391 tv.tv_usec = ( timeout % 1000 ) * 1000;
392
393 ret = select( fd + 1, &read_fds, NULL, NULL, timeout == 0 ? NULL : &tv );
394
395 /* Zero fds ready means we timed out */
396 if ( ret == 0 ) {
397 return ( MBEDTLS_ERR_SSL_TIMEOUT );
398 }
399
400 if ( ret < 0 ) {
401 if ( errno == EINTR ) {
402 return ( MBEDTLS_ERR_SSL_WANT_READ );
403 }
404
405 return ( MBEDTLS_ERR_NET_RECV_FAILED );
406 }
407
408 /* This call will not block */
409 return ( mbedtls_net_recv( ctx, buf, len ) );
410 }
411
412 /*
413 * Write at most 'len' characters
414 */
mbedtls_net_send(void * ctx,const unsigned char * buf,size_t len)415 int mbedtls_net_send( void *ctx, const unsigned char *buf, size_t len )
416 {
417 int ret;
418 int fd = ((mbedtls_net_context *) ctx)->fd;
419
420 if ( fd < 0 ) {
421 return ( MBEDTLS_ERR_NET_INVALID_CONTEXT );
422 }
423
424 ret = (int) write( fd, buf, len );
425
426 if ( ret < 0 ) {
427 if ( net_would_block( ctx ) != 0 ) {
428 return ( MBEDTLS_ERR_SSL_WANT_WRITE );
429 }
430
431 if ( errno == EPIPE || errno == ECONNRESET ) {
432 return ( MBEDTLS_ERR_NET_CONN_RESET );
433 }
434
435 if ( errno == EINTR ) {
436 return ( MBEDTLS_ERR_SSL_WANT_WRITE );
437 }
438
439 return ( MBEDTLS_ERR_NET_SEND_FAILED );
440 }
441
442 return ( ret );
443 }
444
445 /*
446 * Gracefully close the connection
447 */
mbedtls_net_free(mbedtls_net_context * ctx)448 void mbedtls_net_free( mbedtls_net_context *ctx )
449 {
450 if ( ctx->fd == -1) {
451 return;
452 }
453
454 shutdown( ctx->fd, 2);
455 close(ctx->fd);
456
457 ctx->fd = -1;
458 }
459
460 #endif /* MBEDTLS_NET_C */
461