1 /*
2    Unix SMB/CIFS implementation.
3    Socket functions
4    Copyright (C) Andrew Tridgell 1992-1998
5    Copyright (C) Tim Potter      2000-2001
6    Copyright (C) Stefan Metzmacher 2004
7 
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12 
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17 
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21 
22 #include "includes.h"
23 #include "lib/socket/socket.h"
24 #include "system/filesys.h"
25 #include "system/network.h"
26 #include "param/param.h"
27 #include "../lib/tsocket/tsocket.h"
28 #include "lib/util/util_net.h"
29 
30 /*
31   auto-close sockets on free
32 */
socket_destructor(struct socket_context * sock)33 static int socket_destructor(struct socket_context *sock)
34 {
35 	if (sock->ops->fn_close &&
36 	    !(sock->flags & SOCKET_FLAG_NOCLOSE)) {
37 		sock->ops->fn_close(sock);
38 	}
39 	return 0;
40 }
41 
socket_tevent_fd_close_fn(struct tevent_context * ev,struct tevent_fd * fde,int fd,void * private_data)42 _PUBLIC_ void socket_tevent_fd_close_fn(struct tevent_context *ev,
43 					struct tevent_fd *fde,
44 					int fd,
45 					void *private_data)
46 {
47 	/* this might be the socket_wrapper swrap_close() */
48 	close(fd);
49 }
50 
socket_create_with_ops(TALLOC_CTX * mem_ctx,const struct socket_ops * ops,struct socket_context ** new_sock,enum socket_type type,uint32_t flags)51 _PUBLIC_ NTSTATUS socket_create_with_ops(TALLOC_CTX *mem_ctx, const struct socket_ops *ops,
52 					 struct socket_context **new_sock,
53 					 enum socket_type type, uint32_t flags)
54 {
55 	NTSTATUS status;
56 
57 	(*new_sock) = talloc(mem_ctx, struct socket_context);
58 	if (!(*new_sock)) {
59 		return NT_STATUS_NO_MEMORY;
60 	}
61 
62 	(*new_sock)->type = type;
63 	(*new_sock)->state = SOCKET_STATE_UNDEFINED;
64 	(*new_sock)->flags = flags;
65 
66 	(*new_sock)->fd = -1;
67 
68 	(*new_sock)->private_data = NULL;
69 	(*new_sock)->ops = ops;
70 	(*new_sock)->backend_name = NULL;
71 
72 	status = (*new_sock)->ops->fn_init((*new_sock));
73 	if (!NT_STATUS_IS_OK(status)) {
74 		talloc_free(*new_sock);
75 		return status;
76 	}
77 
78 	/* by enabling "testnonblock" mode, all socket receive and
79 	   send calls on non-blocking sockets will randomly recv/send
80 	   less data than requested */
81 
82 	if (!(flags & SOCKET_FLAG_BLOCK) &&
83 	    type == SOCKET_TYPE_STREAM &&
84 		getenv("SOCKET_TESTNONBLOCK") != NULL) {
85 		(*new_sock)->flags |= SOCKET_FLAG_TESTNONBLOCK;
86 	}
87 
88 	/* we don't do a connect() on dgram sockets, so need to set
89 	   non-blocking at socket create time */
90 	if (!(flags & SOCKET_FLAG_BLOCK) && type == SOCKET_TYPE_DGRAM) {
91 		set_blocking(socket_get_fd(*new_sock), false);
92 	}
93 
94 	talloc_set_destructor(*new_sock, socket_destructor);
95 
96 	return NT_STATUS_OK;
97 }
98 
socket_create(TALLOC_CTX * mem_ctx,const char * name,enum socket_type type,struct socket_context ** new_sock,uint32_t flags)99 _PUBLIC_ NTSTATUS socket_create(TALLOC_CTX *mem_ctx,
100 				const char *name, enum socket_type type,
101 			        struct socket_context **new_sock, uint32_t flags)
102 {
103 	const struct socket_ops *ops;
104 
105 	ops = socket_getops_byname(name, type);
106 	if (!ops) {
107 		return NT_STATUS_INVALID_PARAMETER;
108 	}
109 
110 	return socket_create_with_ops(mem_ctx, ops, new_sock, type, flags);
111 }
112 
socket_connect(struct socket_context * sock,const struct socket_address * my_address,const struct socket_address * server_address,uint32_t flags)113 _PUBLIC_ NTSTATUS socket_connect(struct socket_context *sock,
114 				 const struct socket_address *my_address,
115 				 const struct socket_address *server_address,
116 				 uint32_t flags)
117 {
118 	if (sock == NULL) {
119 		return NT_STATUS_CONNECTION_DISCONNECTED;
120 	}
121 	if (sock->state != SOCKET_STATE_UNDEFINED) {
122 		return NT_STATUS_INVALID_PARAMETER;
123 	}
124 
125 	if (!sock->ops->fn_connect) {
126 		return NT_STATUS_NOT_IMPLEMENTED;
127 	}
128 
129 	return sock->ops->fn_connect(sock, my_address, server_address, flags);
130 }
131 
socket_connect_complete(struct socket_context * sock,uint32_t flags)132 _PUBLIC_ NTSTATUS socket_connect_complete(struct socket_context *sock, uint32_t flags)
133 {
134 	if (!sock->ops->fn_connect_complete) {
135 		return NT_STATUS_NOT_IMPLEMENTED;
136 	}
137 	return sock->ops->fn_connect_complete(sock, flags);
138 }
139 
socket_listen(struct socket_context * sock,const struct socket_address * my_address,int queue_size,uint32_t flags)140 _PUBLIC_ NTSTATUS socket_listen(struct socket_context *sock,
141 			        const struct socket_address *my_address,
142 			        int queue_size, uint32_t flags)
143 {
144 	if (sock == NULL) {
145 		return NT_STATUS_CONNECTION_DISCONNECTED;
146 	}
147 	if (sock->state != SOCKET_STATE_UNDEFINED) {
148 		return NT_STATUS_INVALID_PARAMETER;
149 	}
150 
151 	if (!sock->ops->fn_listen) {
152 		return NT_STATUS_NOT_IMPLEMENTED;
153 	}
154 
155 	return sock->ops->fn_listen(sock, my_address, queue_size, flags);
156 }
157 
socket_accept(struct socket_context * sock,struct socket_context ** new_sock)158 _PUBLIC_ NTSTATUS socket_accept(struct socket_context *sock, struct socket_context **new_sock)
159 {
160 	NTSTATUS status;
161 
162 	if (sock == NULL) {
163 		return NT_STATUS_CONNECTION_DISCONNECTED;
164 	}
165 	if (sock->type != SOCKET_TYPE_STREAM) {
166 		return NT_STATUS_INVALID_PARAMETER;
167 	}
168 
169 	if (sock->state != SOCKET_STATE_SERVER_LISTEN) {
170 		return NT_STATUS_INVALID_PARAMETER;
171 	}
172 
173 	if (!sock->ops->fn_accept) {
174 		return NT_STATUS_NOT_IMPLEMENTED;
175 	}
176 
177 	status = sock->ops->fn_accept(sock, new_sock);
178 
179 	if (NT_STATUS_IS_OK(status)) {
180 		talloc_set_destructor(*new_sock, socket_destructor);
181 		(*new_sock)->flags = 0;
182 	}
183 
184 	return status;
185 }
186 
socket_recv(struct socket_context * sock,void * buf,size_t wantlen,size_t * nread)187 _PUBLIC_ NTSTATUS socket_recv(struct socket_context *sock, void *buf,
188 			      size_t wantlen, size_t *nread)
189 {
190 	if (sock == NULL) {
191 		return NT_STATUS_CONNECTION_DISCONNECTED;
192 	}
193 	if (sock->state != SOCKET_STATE_CLIENT_CONNECTED &&
194 	    sock->state != SOCKET_STATE_SERVER_CONNECTED &&
195 	    sock->type  != SOCKET_TYPE_DGRAM) {
196 		return NT_STATUS_INVALID_PARAMETER;
197 	}
198 
199 	if (!sock->ops->fn_recv) {
200 		return NT_STATUS_NOT_IMPLEMENTED;
201 	}
202 
203 	if ((sock->flags & SOCKET_FLAG_TESTNONBLOCK)
204 	    && wantlen > 1) {
205 
206 		if (random() % 10 == 0) {
207 			*nread = 0;
208 			return STATUS_MORE_ENTRIES;
209 		}
210 		return sock->ops->fn_recv(sock, buf, 1+(random() % wantlen), nread);
211 	}
212 	return sock->ops->fn_recv(sock, buf, wantlen, nread);
213 }
214 
socket_recvfrom(struct socket_context * sock,void * buf,size_t wantlen,size_t * nread,TALLOC_CTX * mem_ctx,struct socket_address ** src_addr)215 _PUBLIC_ NTSTATUS socket_recvfrom(struct socket_context *sock, void *buf,
216 				  size_t wantlen, size_t *nread,
217 				  TALLOC_CTX *mem_ctx, struct socket_address **src_addr)
218 {
219 	if (sock == NULL) {
220 		return NT_STATUS_CONNECTION_DISCONNECTED;
221 	}
222 	if (sock->type != SOCKET_TYPE_DGRAM) {
223 		return NT_STATUS_INVALID_PARAMETER;
224 	}
225 
226 	if (!sock->ops->fn_recvfrom) {
227 		return NT_STATUS_NOT_IMPLEMENTED;
228 	}
229 
230 	return sock->ops->fn_recvfrom(sock, buf, wantlen, nread,
231 				      mem_ctx, src_addr);
232 }
233 
socket_send(struct socket_context * sock,const DATA_BLOB * blob,size_t * sendlen)234 _PUBLIC_ NTSTATUS socket_send(struct socket_context *sock,
235 			      const DATA_BLOB *blob, size_t *sendlen)
236 {
237 	if (sock == NULL) {
238 		return NT_STATUS_CONNECTION_DISCONNECTED;
239 	}
240 	if (sock->state != SOCKET_STATE_CLIENT_CONNECTED &&
241 	    sock->state != SOCKET_STATE_SERVER_CONNECTED) {
242 		return NT_STATUS_INVALID_PARAMETER;
243 	}
244 
245 	if (!sock->ops->fn_send) {
246 		return NT_STATUS_NOT_IMPLEMENTED;
247 	}
248 
249 	if ((sock->flags & SOCKET_FLAG_TESTNONBLOCK)
250 	    && blob->length > 1) {
251 		DATA_BLOB blob2 = *blob;
252 		if (random() % 10 == 0) {
253 			*sendlen = 0;
254 			return STATUS_MORE_ENTRIES;
255 		}
256 		/* The random size sends are incompatible with TLS and SASL
257 		 * sockets, which require re-sends to be consistant */
258 		if (!(sock->flags & SOCKET_FLAG_ENCRYPT)) {
259 			blob2.length = 1+(random() % blob2.length);
260 		} else {
261 			/* This is particularly stressful on buggy
262 			 * LDAP clients, that don't expect on LDAP
263 			 * packet in many SASL packets */
264 			blob2.length = 1 + blob2.length/2;
265 		}
266 		return sock->ops->fn_send(sock, &blob2, sendlen);
267 	}
268 	return sock->ops->fn_send(sock, blob, sendlen);
269 }
270 
271 
socket_sendto(struct socket_context * sock,const DATA_BLOB * blob,size_t * sendlen,const struct socket_address * dest_addr)272 _PUBLIC_ NTSTATUS socket_sendto(struct socket_context *sock,
273 			        const DATA_BLOB *blob, size_t *sendlen,
274 			        const struct socket_address *dest_addr)
275 {
276 	if (sock == NULL) {
277 		return NT_STATUS_CONNECTION_DISCONNECTED;
278 	}
279 	if (sock->type != SOCKET_TYPE_DGRAM) {
280 		return NT_STATUS_INVALID_PARAMETER;
281 	}
282 
283 	if (sock->state == SOCKET_STATE_CLIENT_CONNECTED ||
284 	    sock->state == SOCKET_STATE_SERVER_CONNECTED) {
285 		return NT_STATUS_INVALID_PARAMETER;
286 	}
287 
288 	if (!sock->ops->fn_sendto) {
289 		return NT_STATUS_NOT_IMPLEMENTED;
290 	}
291 
292 	return sock->ops->fn_sendto(sock, blob, sendlen, dest_addr);
293 }
294 
295 
296 /*
297   ask for the number of bytes in a pending incoming packet
298 */
socket_pending(struct socket_context * sock,size_t * npending)299 _PUBLIC_ NTSTATUS socket_pending(struct socket_context *sock, size_t *npending)
300 {
301 	if (sock == NULL) {
302 		return NT_STATUS_CONNECTION_DISCONNECTED;
303 	}
304 	if (!sock->ops->fn_pending) {
305 		return NT_STATUS_NOT_IMPLEMENTED;
306 	}
307 	return sock->ops->fn_pending(sock, npending);
308 }
309 
310 
socket_set_option(struct socket_context * sock,const char * option,const char * val)311 _PUBLIC_ NTSTATUS socket_set_option(struct socket_context *sock, const char *option, const char *val)
312 {
313 	if (sock == NULL) {
314 		return NT_STATUS_CONNECTION_DISCONNECTED;
315 	}
316 	if (!sock->ops->fn_set_option) {
317 		return NT_STATUS_NOT_IMPLEMENTED;
318 	}
319 
320 	return sock->ops->fn_set_option(sock, option, val);
321 }
322 
socket_get_peer_name(struct socket_context * sock,TALLOC_CTX * mem_ctx)323 _PUBLIC_ char *socket_get_peer_name(struct socket_context *sock, TALLOC_CTX *mem_ctx)
324 {
325 	if (!sock->ops->fn_get_peer_name) {
326 		return NULL;
327 	}
328 
329 	return sock->ops->fn_get_peer_name(sock, mem_ctx);
330 }
331 
socket_get_peer_addr(struct socket_context * sock,TALLOC_CTX * mem_ctx)332 _PUBLIC_ struct socket_address *socket_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
333 {
334 	if (!sock->ops->fn_get_peer_addr) {
335 		return NULL;
336 	}
337 
338 	return sock->ops->fn_get_peer_addr(sock, mem_ctx);
339 }
340 
socket_get_my_addr(struct socket_context * sock,TALLOC_CTX * mem_ctx)341 _PUBLIC_ struct socket_address *socket_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
342 {
343 	if (!sock->ops->fn_get_my_addr) {
344 		return NULL;
345 	}
346 
347 	return sock->ops->fn_get_my_addr(sock, mem_ctx);
348 }
349 
socket_address_to_tsocket_address(TALLOC_CTX * mem_ctx,const struct socket_address * a)350 _PUBLIC_ struct tsocket_address *socket_address_to_tsocket_address(TALLOC_CTX *mem_ctx,
351 								   const struct socket_address *a)
352 {
353 	struct tsocket_address *r;
354 	int ret;
355 
356 	if (!a) {
357 		return NULL;
358 	}
359 	if (a->sockaddr) {
360 		ret = tsocket_address_bsd_from_sockaddr(mem_ctx,
361 							a->sockaddr,
362 							a->sockaddrlen,
363 							&r);
364 	} else {
365 		ret = tsocket_address_inet_from_strings(mem_ctx,
366 							a->family,
367 							a->addr,
368 							a->port,
369 							&r);
370 	}
371 
372 	if (ret != 0) {
373 		return NULL;
374 	}
375 
376 	return r;
377 }
378 
socket_address_set_port(struct socket_address * a,uint16_t port)379 _PUBLIC_ void socket_address_set_port(struct socket_address *a,
380 				      uint16_t port)
381 {
382 	if (a->sockaddr) {
383 		set_sockaddr_port(a->sockaddr, port);
384 	} else {
385 		a->port = port;
386 	}
387 
388 }
389 
tsocket_address_to_socket_address(TALLOC_CTX * mem_ctx,const struct tsocket_address * a)390 _PUBLIC_ struct socket_address *tsocket_address_to_socket_address(TALLOC_CTX *mem_ctx,
391 								  const struct tsocket_address *a)
392 {
393 	ssize_t ret;
394 	struct sockaddr_storage ss;
395 	size_t sslen = sizeof(ss);
396 
397 	ret = tsocket_address_bsd_sockaddr(a, (struct sockaddr *)(void *)&ss, sslen);
398 	if (ret < 0) {
399 		return NULL;
400 	}
401 
402 	return socket_address_from_sockaddr(mem_ctx, (struct sockaddr *)(void *)&ss, ret);
403 }
404 
socket_get_remote_addr(struct socket_context * sock,TALLOC_CTX * mem_ctx)405 _PUBLIC_ struct tsocket_address *socket_get_remote_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
406 {
407 	struct socket_address *a;
408 	struct tsocket_address *r;
409 
410 	a = socket_get_peer_addr(sock, mem_ctx);
411 	if (a == NULL) {
412 		return NULL;
413 	}
414 
415 	r = socket_address_to_tsocket_address(mem_ctx, a);
416 	talloc_free(a);
417 	return r;
418 }
419 
socket_get_local_addr(struct socket_context * sock,TALLOC_CTX * mem_ctx)420 _PUBLIC_ struct tsocket_address *socket_get_local_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
421 {
422 	struct socket_address *a;
423 	struct tsocket_address *r;
424 
425 	a = socket_get_my_addr(sock, mem_ctx);
426 	if (a == NULL) {
427 		return NULL;
428 	}
429 
430 	r = socket_address_to_tsocket_address(mem_ctx, a);
431 	talloc_free(a);
432 	return r;
433 }
434 
socket_get_fd(struct socket_context * sock)435 _PUBLIC_ int socket_get_fd(struct socket_context *sock)
436 {
437 	if (!sock->ops->fn_get_fd) {
438 		return -1;
439 	}
440 
441 	return sock->ops->fn_get_fd(sock);
442 }
443 
444 /*
445   call dup() on a socket, and close the old fd. This is used to change
446   the fd to the lowest available number, to make select() more
447   efficient (select speed depends on the maxiumum fd number passed to
448   it)
449 */
socket_dup(struct socket_context * sock)450 _PUBLIC_ NTSTATUS socket_dup(struct socket_context *sock)
451 {
452 	int fd;
453 	if (sock->fd == -1) {
454 		return NT_STATUS_INVALID_HANDLE;
455 	}
456 	fd = dup(sock->fd);
457 	if (fd == -1) {
458 		return map_nt_error_from_unix_common(errno);
459 	}
460 	close(sock->fd);
461 	sock->fd = fd;
462 	return NT_STATUS_OK;
463 
464 }
465 
466 /* Create a new socket_address.  The type must match the socket type.
467  * The host parameter may be an IP or a hostname
468  */
469 
socket_address_from_strings(TALLOC_CTX * mem_ctx,const char * family,const char * host,int port)470 _PUBLIC_ struct socket_address *socket_address_from_strings(TALLOC_CTX *mem_ctx,
471 							    const char *family,
472 							    const char *host,
473 							    int port)
474 {
475 	struct socket_address *addr = talloc(mem_ctx, struct socket_address);
476 	if (!addr) {
477 		return NULL;
478 	}
479 
480 	if (strcmp(family, "ip") == 0 && is_ipaddress_v6(host)) {
481 		/* leaving as "ip" would force IPv4 */
482 		family = "ipv6";
483 	}
484 
485 	addr->family = family;
486 	addr->addr = talloc_strdup(addr, host);
487 	if (!addr->addr) {
488 		talloc_free(addr);
489 		return NULL;
490 	}
491 	addr->port = port;
492 	addr->sockaddr = NULL;
493 	addr->sockaddrlen = 0;
494 
495 	return addr;
496 }
497 
498 /* Create a new socket_address.  Copy the struct sockaddr into the new
499  * structure.  Used for hooks in the kerberos libraries, where they
500  * supply only a struct sockaddr */
501 
socket_address_from_sockaddr(TALLOC_CTX * mem_ctx,struct sockaddr * sockaddr,size_t sockaddrlen)502 _PUBLIC_ struct socket_address *socket_address_from_sockaddr(TALLOC_CTX *mem_ctx,
503 							     struct sockaddr *sockaddr,
504 							     size_t sockaddrlen)
505 {
506 	struct socket_address *addr = talloc(mem_ctx, struct socket_address);
507 	if (!addr) {
508 		return NULL;
509 	}
510 	switch (sockaddr->sa_family) {
511 	case AF_INET:
512 		addr->family = "ipv4";
513 		break;
514 #ifdef HAVE_IPV6
515 	case AF_INET6:
516 		addr->family = "ipv6";
517 		break;
518 #endif
519 	case AF_UNIX:
520 		addr->family = "unix";
521 		break;
522 	}
523 	addr->addr = NULL;
524 	addr->port = 0;
525 	addr->sockaddr = (struct sockaddr *)talloc_memdup(addr, sockaddr, sockaddrlen);
526 	if (!addr->sockaddr) {
527 		talloc_free(addr);
528 		return NULL;
529 	}
530 	addr->sockaddrlen = sockaddrlen;
531 	return addr;
532 }
533 
534 
535 /*
536    Create a new socket_address from sockaddr_storage
537  */
socket_address_from_sockaddr_storage(TALLOC_CTX * mem_ctx,const struct sockaddr_storage * sockaddr,uint16_t port)538 _PUBLIC_ struct socket_address *socket_address_from_sockaddr_storage(TALLOC_CTX *mem_ctx,
539 								     const struct sockaddr_storage *sockaddr,
540 	uint16_t port)
541 {
542 	struct socket_address *addr = talloc_zero(mem_ctx, struct socket_address);
543 	char addr_str[INET6_ADDRSTRLEN+1];
544 	const char *str;
545 
546 	if (!addr) {
547 		return NULL;
548 	}
549 	addr->port = port;
550 	switch (sockaddr->ss_family) {
551 	case AF_INET:
552 		addr->family = "ipv4";
553 		break;
554 #ifdef HAVE_IPV6
555 	case AF_INET6:
556 		addr->family = "ipv6";
557 		break;
558 #endif
559 	default:
560 		talloc_free(addr);
561 		return NULL;
562 	}
563 
564 	str = print_sockaddr(addr_str, sizeof(addr_str), sockaddr);
565 	if (str == NULL) {
566 		talloc_free(addr);
567 		return NULL;
568 	}
569 	addr->addr = talloc_strdup(addr, str);
570 	if (addr->addr == NULL) {
571 		talloc_free(addr);
572 		return NULL;
573 	}
574 
575 	return addr;
576 }
577 
578 /* Copy a socket_address structure */
socket_address_copy(TALLOC_CTX * mem_ctx,const struct socket_address * oaddr)579 struct socket_address *socket_address_copy(TALLOC_CTX *mem_ctx,
580 					   const struct socket_address *oaddr)
581 {
582 	struct socket_address *addr = talloc_zero(mem_ctx, struct socket_address);
583 	if (!addr) {
584 		return NULL;
585 	}
586 	addr->family	= oaddr->family;
587 	if (oaddr->addr) {
588 		addr->addr	= talloc_strdup(addr, oaddr->addr);
589 		if (!addr->addr) {
590 			goto nomem;
591 		}
592 	}
593 	addr->port	= oaddr->port;
594 	if (oaddr->sockaddr) {
595 		addr->sockaddr = (struct sockaddr *)talloc_memdup(addr,
596 								  oaddr->sockaddr,
597 								  oaddr->sockaddrlen);
598 		if (!addr->sockaddr) {
599 			goto nomem;
600 		}
601 		addr->sockaddrlen = oaddr->sockaddrlen;
602 	}
603 
604 	return addr;
605 
606 nomem:
607 	talloc_free(addr);
608 	return NULL;
609 }
610 
socket_getops_byname(const char * family,enum socket_type type)611 _PUBLIC_ const struct socket_ops *socket_getops_byname(const char *family, enum socket_type type)
612 {
613 	extern const struct socket_ops *socket_ipv4_ops(enum socket_type);
614 	extern const struct socket_ops *socket_ipv6_ops(enum socket_type);
615 	extern const struct socket_ops *socket_unixdom_ops(enum socket_type);
616 
617 	if (strcmp("ip", family) == 0 ||
618 	    strcmp("ipv4", family) == 0) {
619 		return socket_ipv4_ops(type);
620 	}
621 
622 #ifdef HAVE_IPV6
623 	if (strcmp("ipv6", family) == 0) {
624 		return socket_ipv6_ops(type);
625 	}
626 #endif
627 
628 	if (strcmp("unix", family) == 0) {
629 		return socket_unixdom_ops(type);
630 	}
631 
632 	return NULL;
633 }
634 
635 /*
636   set some flags on a socket
637  */
socket_set_flags(struct socket_context * sock,unsigned flags)638 void socket_set_flags(struct socket_context *sock, unsigned flags)
639 {
640 	sock->flags |= flags;
641 }
642