• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt/router/samba-3.5.8/source4/lib/socket/
1/*
2   Unix SMB/CIFS implementation.
3
4   Socket IPv4/IPv6 functions
5
6   Copyright (C) Stefan Metzmacher 2004
7   Copyright (C) Andrew Tridgell 2004-2005
8   Copyright (C) Jelmer Vernooij 2004
9
10   This program is free software; you can redistribute it and/or modify
11   it under the terms of the GNU General Public License as published by
12   the Free Software Foundation; either version 3 of the License, or
13   (at your option) any later version.
14
15   This program is distributed in the hope that it will be useful,
16   but WITHOUT ANY WARRANTY; without even the implied warranty of
17   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18   GNU General Public License for more details.
19
20   You should have received a copy of the GNU General Public License
21   along with this program.  If not, see <http://www.gnu.org/licenses/>.
22*/
23
24#include "includes.h"
25#include "system/filesys.h"
26#include "lib/socket/socket.h"
27#include "system/network.h"
28
29static NTSTATUS ipv4_init(struct socket_context *sock)
30{
31	int type;
32
33	switch (sock->type) {
34	case SOCKET_TYPE_STREAM:
35		type = SOCK_STREAM;
36		break;
37	case SOCKET_TYPE_DGRAM:
38		type = SOCK_DGRAM;
39		break;
40	default:
41		return NT_STATUS_INVALID_PARAMETER;
42	}
43
44	sock->fd = socket(PF_INET, type, 0);
45	if (sock->fd == -1) {
46		return map_nt_error_from_unix(errno);
47	}
48
49	sock->backend_name = "ipv4";
50	sock->family = AF_INET;
51
52	return NT_STATUS_OK;
53}
54
55static void ip_close(struct socket_context *sock)
56{
57	close(sock->fd);
58}
59
60static NTSTATUS ip_connect_complete(struct socket_context *sock, uint32_t flags)
61{
62	int error=0, ret;
63	socklen_t len = sizeof(error);
64
65	/* check for any errors that may have occurred - this is needed
66	   for non-blocking connect */
67	ret = getsockopt(sock->fd, SOL_SOCKET, SO_ERROR, &error, &len);
68	if (ret == -1) {
69		return map_nt_error_from_unix(errno);
70	}
71	if (error != 0) {
72		return map_nt_error_from_unix(error);
73	}
74
75	if (!(flags & SOCKET_FLAG_BLOCK)) {
76		ret = set_blocking(sock->fd, false);
77		if (ret == -1) {
78			return map_nt_error_from_unix(errno);
79		}
80	}
81
82	sock->state = SOCKET_STATE_CLIENT_CONNECTED;
83
84	return NT_STATUS_OK;
85}
86
87
88static NTSTATUS ipv4_connect(struct socket_context *sock,
89			     const struct socket_address *my_address,
90			     const struct socket_address *srv_address,
91			     uint32_t flags)
92{
93	struct sockaddr_in srv_addr;
94	struct in_addr my_ip;
95	struct in_addr srv_ip;
96	int ret;
97
98	if (my_address && my_address->sockaddr) {
99		ret = bind(sock->fd, my_address->sockaddr, my_address->sockaddrlen);
100		if (ret == -1) {
101			return map_nt_error_from_unix(errno);
102		}
103	} else if (my_address) {
104		my_ip = interpret_addr2(my_address->addr);
105
106		if (my_ip.s_addr != 0 || my_address->port != 0) {
107			struct sockaddr_in my_addr;
108			ZERO_STRUCT(my_addr);
109#ifdef HAVE_SOCK_SIN_LEN
110			my_addr.sin_len		= sizeof(my_addr);
111#endif
112			my_addr.sin_addr.s_addr	= my_ip.s_addr;
113			my_addr.sin_port	= htons(my_address->port);
114			my_addr.sin_family	= PF_INET;
115
116			ret = bind(sock->fd, (struct sockaddr *)&my_addr, sizeof(my_addr));
117			if (ret == -1) {
118				return map_nt_error_from_unix(errno);
119			}
120		}
121	}
122
123	if (srv_address->sockaddr) {
124		ret = connect(sock->fd, srv_address->sockaddr, srv_address->sockaddrlen);
125		if (ret == -1) {
126			return map_nt_error_from_unix(errno);
127		}
128	} else {
129		srv_ip = interpret_addr2(srv_address->addr);
130		if (!srv_ip.s_addr) {
131			return NT_STATUS_BAD_NETWORK_NAME;
132		}
133
134		SMB_ASSERT(srv_address->port != 0);
135
136		ZERO_STRUCT(srv_addr);
137#ifdef HAVE_SOCK_SIN_LEN
138		srv_addr.sin_len	= sizeof(srv_addr);
139#endif
140		srv_addr.sin_addr.s_addr= srv_ip.s_addr;
141		srv_addr.sin_port	= htons(srv_address->port);
142		srv_addr.sin_family	= PF_INET;
143
144		ret = connect(sock->fd, (const struct sockaddr *)&srv_addr, sizeof(srv_addr));
145		if (ret == -1) {
146			return map_nt_error_from_unix(errno);
147		}
148	}
149
150	return ip_connect_complete(sock, flags);
151}
152
153
154/*
155  note that for simplicity of the API, socket_listen() is also
156  use for DGRAM sockets, but in reality only a bind() is done
157*/
158static NTSTATUS ipv4_listen(struct socket_context *sock,
159			    const struct socket_address *my_address,
160			    int queue_size, uint32_t flags)
161{
162	struct sockaddr_in my_addr;
163	struct in_addr ip_addr;
164	int ret;
165
166	socket_set_option(sock, "SO_REUSEADDR=1", NULL);
167
168	if (my_address->sockaddr) {
169		ret = bind(sock->fd, my_address->sockaddr, my_address->sockaddrlen);
170	} else {
171		ip_addr = interpret_addr2(my_address->addr);
172
173		ZERO_STRUCT(my_addr);
174#ifdef HAVE_SOCK_SIN_LEN
175		my_addr.sin_len		= sizeof(my_addr);
176#endif
177		my_addr.sin_addr.s_addr	= ip_addr.s_addr;
178		my_addr.sin_port	= htons(my_address->port);
179		my_addr.sin_family	= PF_INET;
180
181		ret = bind(sock->fd, (struct sockaddr *)&my_addr, sizeof(my_addr));
182	}
183
184	if (ret == -1) {
185		return map_nt_error_from_unix(errno);
186	}
187
188	if (sock->type == SOCKET_TYPE_STREAM) {
189		ret = listen(sock->fd, queue_size);
190		if (ret == -1) {
191			return map_nt_error_from_unix(errno);
192		}
193	}
194
195	if (!(flags & SOCKET_FLAG_BLOCK)) {
196		ret = set_blocking(sock->fd, false);
197		if (ret == -1) {
198			return map_nt_error_from_unix(errno);
199		}
200	}
201
202	sock->state= SOCKET_STATE_SERVER_LISTEN;
203
204	return NT_STATUS_OK;
205}
206
207static NTSTATUS ipv4_accept(struct socket_context *sock, struct socket_context **new_sock)
208{
209	struct sockaddr_in cli_addr;
210	socklen_t cli_addr_len = sizeof(cli_addr);
211	int new_fd;
212
213	if (sock->type != SOCKET_TYPE_STREAM) {
214		return NT_STATUS_INVALID_PARAMETER;
215	}
216
217	new_fd = accept(sock->fd, (struct sockaddr *)&cli_addr, &cli_addr_len);
218	if (new_fd == -1) {
219		return map_nt_error_from_unix(errno);
220	}
221
222	if (!(sock->flags & SOCKET_FLAG_BLOCK)) {
223		int ret = set_blocking(new_fd, false);
224		if (ret == -1) {
225			close(new_fd);
226			return map_nt_error_from_unix(errno);
227		}
228	}
229
230	/* TODO: we could add a 'accept_check' hook here
231	 *	 which get the black/white lists via socket_set_accept_filter()
232	 *	 or something like that
233	 *	 --metze
234	 */
235
236	(*new_sock) = talloc(NULL, struct socket_context);
237	if (!(*new_sock)) {
238		close(new_fd);
239		return NT_STATUS_NO_MEMORY;
240	}
241
242	/* copy the socket_context */
243	(*new_sock)->type		= sock->type;
244	(*new_sock)->state		= SOCKET_STATE_SERVER_CONNECTED;
245	(*new_sock)->flags		= sock->flags;
246
247	(*new_sock)->fd			= new_fd;
248
249	(*new_sock)->private_data	= NULL;
250	(*new_sock)->ops		= sock->ops;
251	(*new_sock)->backend_name	= sock->backend_name;
252
253	return NT_STATUS_OK;
254}
255
256static NTSTATUS ip_recv(struct socket_context *sock, void *buf,
257			      size_t wantlen, size_t *nread)
258{
259	ssize_t gotlen;
260
261	*nread = 0;
262
263	gotlen = recv(sock->fd, buf, wantlen, 0);
264	if (gotlen == 0) {
265		return NT_STATUS_END_OF_FILE;
266	} else if (gotlen == -1) {
267		return map_nt_error_from_unix(errno);
268	}
269
270	*nread = gotlen;
271
272	return NT_STATUS_OK;
273}
274
275
276static NTSTATUS ipv4_recvfrom(struct socket_context *sock, void *buf,
277			      size_t wantlen, size_t *nread,
278			      TALLOC_CTX *addr_ctx, struct socket_address **_src)
279{
280	ssize_t gotlen;
281	struct sockaddr_in *from_addr;
282	socklen_t from_len = sizeof(*from_addr);
283	struct socket_address *src;
284	char addrstring[INET_ADDRSTRLEN];
285
286	src = talloc(addr_ctx, struct socket_address);
287	if (!src) {
288		return NT_STATUS_NO_MEMORY;
289	}
290
291	src->family = sock->backend_name;
292
293	from_addr = talloc(src, struct sockaddr_in);
294	if (!from_addr) {
295		talloc_free(src);
296		return NT_STATUS_NO_MEMORY;
297	}
298
299	src->sockaddr = (struct sockaddr *)from_addr;
300
301	*nread = 0;
302
303	gotlen = recvfrom(sock->fd, buf, wantlen, 0,
304			  src->sockaddr, &from_len);
305	if (gotlen == 0) {
306		talloc_free(src);
307		return NT_STATUS_END_OF_FILE;
308	} else if (gotlen == -1) {
309		talloc_free(src);
310		return map_nt_error_from_unix(errno);
311	}
312
313	src->sockaddrlen = from_len;
314
315	if (inet_ntop(AF_INET, &from_addr->sin_addr, addrstring,
316			 sizeof(addrstring)) == NULL) {
317		talloc_free(src);
318		return NT_STATUS_INTERNAL_ERROR;
319	}
320	src->addr = talloc_strdup(src, addrstring);
321	if (src->addr == NULL) {
322		talloc_free(src);
323		return NT_STATUS_NO_MEMORY;
324	}
325	src->port = ntohs(from_addr->sin_port);
326
327	*nread	= gotlen;
328	*_src	= src;
329	return NT_STATUS_OK;
330}
331
332static NTSTATUS ip_send(struct socket_context *sock,
333			      const DATA_BLOB *blob, size_t *sendlen)
334{
335	ssize_t len;
336
337	*sendlen = 0;
338
339	len = send(sock->fd, blob->data, blob->length, 0);
340	if (len == -1) {
341		return map_nt_error_from_unix(errno);
342	}
343
344	*sendlen = len;
345
346	return NT_STATUS_OK;
347}
348
349static NTSTATUS ipv4_sendto(struct socket_context *sock,
350			    const DATA_BLOB *blob, size_t *sendlen,
351			    const struct socket_address *dest_addr)
352{
353	ssize_t len;
354
355	if (dest_addr->sockaddr) {
356		len = sendto(sock->fd, blob->data, blob->length, 0,
357			     dest_addr->sockaddr, dest_addr->sockaddrlen);
358	} else {
359		struct sockaddr_in srv_addr;
360		struct in_addr addr;
361
362		SMB_ASSERT(dest_addr->port != 0);
363
364		ZERO_STRUCT(srv_addr);
365#ifdef HAVE_SOCK_SIN_LEN
366		srv_addr.sin_len         = sizeof(srv_addr);
367#endif
368		addr                     = interpret_addr2(dest_addr->addr);
369		if (addr.s_addr == 0) {
370			return NT_STATUS_HOST_UNREACHABLE;
371		}
372		srv_addr.sin_addr.s_addr = addr.s_addr;
373		srv_addr.sin_port        = htons(dest_addr->port);
374		srv_addr.sin_family      = PF_INET;
375
376		*sendlen = 0;
377
378		len = sendto(sock->fd, blob->data, blob->length, 0,
379			     (struct sockaddr *)&srv_addr, sizeof(srv_addr));
380	}
381	if (len == -1) {
382		return map_nt_error_from_unix(errno);
383	}
384
385	*sendlen = len;
386
387	return NT_STATUS_OK;
388}
389
390static NTSTATUS ipv4_set_option(struct socket_context *sock, const char *option, const char *val)
391{
392	set_socket_options(sock->fd, option);
393	return NT_STATUS_OK;
394}
395
396static char *ipv4_get_peer_name(struct socket_context *sock, TALLOC_CTX *mem_ctx)
397{
398	struct sockaddr_in peer_addr;
399	socklen_t len = sizeof(peer_addr);
400	struct hostent *he;
401	int ret;
402
403	ret = getpeername(sock->fd, (struct sockaddr *)&peer_addr, &len);
404	if (ret == -1) {
405		return NULL;
406	}
407
408	he = gethostbyaddr((char *)&peer_addr.sin_addr, sizeof(peer_addr.sin_addr), AF_INET);
409	if (he == NULL) {
410		return NULL;
411	}
412
413	return talloc_strdup(mem_ctx, he->h_name);
414}
415
416static struct socket_address *ipv4_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
417{
418	struct sockaddr_in *peer_addr;
419	socklen_t len = sizeof(*peer_addr);
420	struct socket_address *peer;
421	char addrstring[INET_ADDRSTRLEN];
422	int ret;
423
424	peer = talloc(mem_ctx, struct socket_address);
425	if (!peer) {
426		return NULL;
427	}
428
429	peer->family = sock->backend_name;
430	peer_addr = talloc(peer, struct sockaddr_in);
431	if (!peer_addr) {
432		talloc_free(peer);
433		return NULL;
434	}
435
436	peer->sockaddr = (struct sockaddr *)peer_addr;
437
438	ret = getpeername(sock->fd, peer->sockaddr, &len);
439	if (ret == -1) {
440		talloc_free(peer);
441		return NULL;
442	}
443
444	peer->sockaddrlen = len;
445
446	if (inet_ntop(AF_INET, &peer_addr->sin_addr, addrstring,
447			 sizeof(addrstring)) == NULL) {
448		talloc_free(peer);
449		return NULL;
450	}
451	peer->addr = talloc_strdup(peer, addrstring);
452	if (!peer->addr) {
453		talloc_free(peer);
454		return NULL;
455	}
456	peer->port = ntohs(peer_addr->sin_port);
457
458	return peer;
459}
460
461static struct socket_address *ipv4_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
462{
463	struct sockaddr_in *local_addr;
464	socklen_t len = sizeof(*local_addr);
465	struct socket_address *local;
466	char addrstring[INET_ADDRSTRLEN];
467	int ret;
468
469	local = talloc(mem_ctx, struct socket_address);
470	if (!local) {
471		return NULL;
472	}
473
474	local->family = sock->backend_name;
475	local_addr = talloc(local, struct sockaddr_in);
476	if (!local_addr) {
477		talloc_free(local);
478		return NULL;
479	}
480
481	local->sockaddr = (struct sockaddr *)local_addr;
482
483	ret = getsockname(sock->fd, local->sockaddr, &len);
484	if (ret == -1) {
485		talloc_free(local);
486		return NULL;
487	}
488
489	local->sockaddrlen = len;
490
491	if (inet_ntop(AF_INET, &local_addr->sin_addr, addrstring,
492			 sizeof(addrstring)) == NULL) {
493		talloc_free(local);
494		return NULL;
495	}
496	local->addr = talloc_strdup(local, addrstring);
497	if (!local->addr) {
498		talloc_free(local);
499		return NULL;
500	}
501	local->port = ntohs(local_addr->sin_port);
502
503	return local;
504}
505static int ip_get_fd(struct socket_context *sock)
506{
507	return sock->fd;
508}
509
510static NTSTATUS ip_pending(struct socket_context *sock, size_t *npending)
511{
512	int value = 0;
513	if (ioctl(sock->fd, FIONREAD, &value) == 0) {
514		*npending = value;
515		return NT_STATUS_OK;
516	}
517	return map_nt_error_from_unix(errno);
518}
519
520static const struct socket_ops ipv4_ops = {
521	.name			= "ipv4",
522	.fn_init		= ipv4_init,
523	.fn_connect		= ipv4_connect,
524	.fn_connect_complete	= ip_connect_complete,
525	.fn_listen		= ipv4_listen,
526	.fn_accept		= ipv4_accept,
527	.fn_recv		= ip_recv,
528	.fn_recvfrom		= ipv4_recvfrom,
529	.fn_send		= ip_send,
530	.fn_sendto		= ipv4_sendto,
531	.fn_pending		= ip_pending,
532	.fn_close		= ip_close,
533
534	.fn_set_option		= ipv4_set_option,
535
536	.fn_get_peer_name	= ipv4_get_peer_name,
537	.fn_get_peer_addr	= ipv4_get_peer_addr,
538	.fn_get_my_addr		= ipv4_get_my_addr,
539
540	.fn_get_fd		= ip_get_fd
541};
542
543_PUBLIC_ const struct socket_ops *socket_ipv4_ops(enum socket_type type)
544{
545	return &ipv4_ops;
546}
547
548#if HAVE_IPV6
549
550static struct in6_addr interpret_addr6(const char *name)
551{
552	char addr[INET6_ADDRSTRLEN];
553	struct in6_addr dest6;
554	const char *sp = name;
555	char *p;
556	int ret;
557
558	if (sp == NULL) return in6addr_any;
559
560	p = strchr_m(sp, '%');
561
562	if (strcasecmp(sp, "localhost") == 0) {
563		sp = "::1";
564	}
565
566	/*
567	 * Cope with link-local.
568	 * This is IP:v6:addr%ifname.
569	 */
570
571	if (p && (p > sp) && (if_nametoindex(p+1) != 0)) {
572		strlcpy(addr, sp,
573			MIN(PTR_DIFF(p,sp)+1,
574				sizeof(addr)));
575		sp = addr;
576	}
577
578	ret = inet_pton(AF_INET6, sp, &dest6);
579	if (ret > 0) {
580		return dest6;
581	}
582
583	return in6addr_any;
584}
585
586static NTSTATUS ipv6_init(struct socket_context *sock)
587{
588	int type;
589
590	switch (sock->type) {
591	case SOCKET_TYPE_STREAM:
592		type = SOCK_STREAM;
593		break;
594	case SOCKET_TYPE_DGRAM:
595		type = SOCK_DGRAM;
596		break;
597	default:
598		return NT_STATUS_INVALID_PARAMETER;
599	}
600
601	sock->fd = socket(PF_INET6, type, 0);
602	if (sock->fd == -1) {
603		return map_nt_error_from_unix(errno);
604	}
605
606	sock->backend_name = "ipv6";
607	sock->family = AF_INET6;
608
609	return NT_STATUS_OK;
610}
611
612static NTSTATUS ipv6_tcp_connect(struct socket_context *sock,
613				 const struct socket_address *my_address,
614				 const struct socket_address *srv_address,
615				 uint32_t flags)
616{
617	int ret;
618
619	if (my_address && my_address->sockaddr) {
620		ret = bind(sock->fd, my_address->sockaddr, my_address->sockaddrlen);
621		if (ret == -1) {
622			return map_nt_error_from_unix(errno);
623		}
624	} else if (my_address) {
625		struct in6_addr my_ip;
626		my_ip = interpret_addr6(my_address->addr);
627
628		if (memcmp(&my_ip, &in6addr_any, sizeof(my_ip)) || my_address->port != 0) {
629			struct sockaddr_in6 my_addr;
630			ZERO_STRUCT(my_addr);
631			my_addr.sin6_addr	= my_ip;
632			my_addr.sin6_port	= htons(my_address->port);
633			my_addr.sin6_family	= PF_INET6;
634
635			ret = bind(sock->fd, (struct sockaddr *)&my_addr, sizeof(my_addr));
636			if (ret == -1) {
637				return map_nt_error_from_unix(errno);
638			}
639		}
640	}
641
642	if (srv_address->sockaddr) {
643		ret = connect(sock->fd, srv_address->sockaddr, srv_address->sockaddrlen);
644	} else {
645		struct in6_addr srv_ip;
646		struct sockaddr_in6 srv_addr;
647		srv_ip = interpret_addr6(srv_address->addr);
648		if (memcmp(&srv_ip, &in6addr_any, sizeof(srv_ip)) == 0) {
649			return NT_STATUS_BAD_NETWORK_NAME;
650		}
651
652		ZERO_STRUCT(srv_addr);
653		srv_addr.sin6_addr	= srv_ip;
654		srv_addr.sin6_port	= htons(srv_address->port);
655		srv_addr.sin6_family	= PF_INET6;
656
657		ret = connect(sock->fd, (const struct sockaddr *)&srv_addr, sizeof(srv_addr));
658	}
659	if (ret == -1) {
660		return map_nt_error_from_unix(errno);
661	}
662
663	return ip_connect_complete(sock, flags);
664}
665
666static NTSTATUS ipv6_listen(struct socket_context *sock,
667				const struct socket_address *my_address,
668				int queue_size, uint32_t flags)
669{
670	struct sockaddr_in6 my_addr;
671	struct in6_addr ip_addr;
672	int ret;
673
674	socket_set_option(sock, "SO_REUSEADDR=1", NULL);
675
676	if (my_address->sockaddr) {
677		ret = bind(sock->fd, my_address->sockaddr, my_address->sockaddrlen);
678	} else {
679		ip_addr = interpret_addr6(my_address->addr);
680
681		ZERO_STRUCT(my_addr);
682		my_addr.sin6_addr	= ip_addr;
683		my_addr.sin6_port	= htons(my_address->port);
684		my_addr.sin6_family	= PF_INET6;
685
686		ret = bind(sock->fd, (struct sockaddr *)&my_addr, sizeof(my_addr));
687	}
688
689	if (ret == -1) {
690		return map_nt_error_from_unix(errno);
691	}
692
693	if (sock->type == SOCKET_TYPE_STREAM) {
694		ret = listen(sock->fd, queue_size);
695		if (ret == -1) {
696			return map_nt_error_from_unix(errno);
697		}
698	}
699
700	if (!(flags & SOCKET_FLAG_BLOCK)) {
701		ret = set_blocking(sock->fd, false);
702		if (ret == -1) {
703			return map_nt_error_from_unix(errno);
704		}
705	}
706
707	sock->state= SOCKET_STATE_SERVER_LISTEN;
708
709	return NT_STATUS_OK;
710}
711
712static NTSTATUS ipv6_tcp_accept(struct socket_context *sock, struct socket_context **new_sock)
713{
714	struct sockaddr_in cli_addr;
715	socklen_t cli_addr_len = sizeof(cli_addr);
716	int new_fd;
717
718	if (sock->type != SOCKET_TYPE_STREAM) {
719		return NT_STATUS_INVALID_PARAMETER;
720	}
721
722	new_fd = accept(sock->fd, (struct sockaddr *)&cli_addr, &cli_addr_len);
723	if (new_fd == -1) {
724		return map_nt_error_from_unix(errno);
725	}
726
727	if (!(sock->flags & SOCKET_FLAG_BLOCK)) {
728		int ret = set_blocking(new_fd, false);
729		if (ret == -1) {
730			close(new_fd);
731			return map_nt_error_from_unix(errno);
732		}
733	}
734
735	/* TODO: we could add a 'accept_check' hook here
736	 *	 which get the black/white lists via socket_set_accept_filter()
737	 *	 or something like that
738	 *	 --metze
739	 */
740
741	(*new_sock) = talloc(NULL, struct socket_context);
742	if (!(*new_sock)) {
743		close(new_fd);
744		return NT_STATUS_NO_MEMORY;
745	}
746
747	/* copy the socket_context */
748	(*new_sock)->type		= sock->type;
749	(*new_sock)->state		= SOCKET_STATE_SERVER_CONNECTED;
750	(*new_sock)->flags		= sock->flags;
751
752	(*new_sock)->fd			= new_fd;
753
754	(*new_sock)->private_data	= NULL;
755	(*new_sock)->ops		= sock->ops;
756	(*new_sock)->backend_name	= sock->backend_name;
757
758	return NT_STATUS_OK;
759}
760
761static NTSTATUS ipv6_recvfrom(struct socket_context *sock, void *buf,
762			      size_t wantlen, size_t *nread,
763			      TALLOC_CTX *addr_ctx, struct socket_address **_src)
764{
765	ssize_t gotlen;
766	struct sockaddr_in6 *from_addr;
767	socklen_t from_len = sizeof(*from_addr);
768	struct socket_address *src;
769	char addrstring[INET6_ADDRSTRLEN];
770
771	src = talloc(addr_ctx, struct socket_address);
772	if (!src) {
773		return NT_STATUS_NO_MEMORY;
774	}
775
776	src->family = sock->backend_name;
777
778	from_addr = talloc(src, struct sockaddr_in6);
779	if (!from_addr) {
780		talloc_free(src);
781		return NT_STATUS_NO_MEMORY;
782	}
783
784	src->sockaddr = (struct sockaddr *)from_addr;
785
786	*nread = 0;
787
788	gotlen = recvfrom(sock->fd, buf, wantlen, 0,
789			  src->sockaddr, &from_len);
790	if (gotlen == 0) {
791		talloc_free(src);
792		return NT_STATUS_END_OF_FILE;
793	} else if (gotlen == -1) {
794		talloc_free(src);
795		return map_nt_error_from_unix(errno);
796	}
797
798	src->sockaddrlen = from_len;
799
800	if (inet_ntop(AF_INET6, &from_addr->sin6_addr, addrstring, sizeof(addrstring)) == NULL) {
801		DEBUG(0, ("Unable to convert address to string: %s\n", strerror(errno)));
802		talloc_free(src);
803	    	return NT_STATUS_INTERNAL_ERROR;
804	}
805
806	src->addr = talloc_strdup(src, addrstring);
807	if (src->addr == NULL) {
808		talloc_free(src);
809		return NT_STATUS_NO_MEMORY;
810	}
811	src->port = ntohs(from_addr->sin6_port);
812
813	*nread	= gotlen;
814	*_src	= src;
815	return NT_STATUS_OK;
816}
817
818static NTSTATUS ipv6_sendto(struct socket_context *sock,
819			    const DATA_BLOB *blob, size_t *sendlen,
820			    const struct socket_address *dest_addr)
821{
822	ssize_t len;
823
824	if (dest_addr->sockaddr) {
825		len = sendto(sock->fd, blob->data, blob->length, 0,
826			     dest_addr->sockaddr, dest_addr->sockaddrlen);
827	} else {
828		struct sockaddr_in6 srv_addr;
829		struct in6_addr addr;
830
831		ZERO_STRUCT(srv_addr);
832		addr                     = interpret_addr6(dest_addr->addr);
833		if (addr.s6_addr == 0) {
834			return NT_STATUS_HOST_UNREACHABLE;
835		}
836		srv_addr.sin6_addr = addr;
837		srv_addr.sin6_port        = htons(dest_addr->port);
838		srv_addr.sin6_family      = PF_INET6;
839
840		*sendlen = 0;
841
842		len = sendto(sock->fd, blob->data, blob->length, 0,
843			     (struct sockaddr *)&srv_addr, sizeof(srv_addr));
844	}
845	if (len == -1) {
846		return map_nt_error_from_unix(errno);
847	}
848
849	*sendlen = len;
850
851	return NT_STATUS_OK;
852}
853
854static NTSTATUS ipv6_set_option(struct socket_context *sock, const char *option, const char *val)
855{
856	set_socket_options(sock->fd, option);
857	return NT_STATUS_OK;
858}
859
860static char *ipv6_tcp_get_peer_name(struct socket_context *sock, TALLOC_CTX *mem_ctx)
861{
862	struct sockaddr_in6 peer_addr;
863	socklen_t len = sizeof(peer_addr);
864	struct hostent *he;
865	int ret;
866
867	ret = getpeername(sock->fd, (struct sockaddr *)&peer_addr, &len);
868	if (ret == -1) {
869		return NULL;
870	}
871
872	he = gethostbyaddr((char *)&peer_addr.sin6_addr, sizeof(peer_addr.sin6_addr), AF_INET6);
873	if (he == NULL) {
874		return NULL;
875	}
876
877	return talloc_strdup(mem_ctx, he->h_name);
878}
879
880static struct socket_address *ipv6_tcp_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
881{
882	struct sockaddr_in6 *peer_addr;
883	socklen_t len = sizeof(*peer_addr);
884	struct socket_address *peer;
885	int ret;
886	char addr[128];
887	const char *addr_ret;
888
889	peer = talloc(mem_ctx, struct socket_address);
890	if (!peer) {
891		return NULL;
892	}
893
894	peer->family = sock->backend_name;
895	peer_addr = talloc(peer, struct sockaddr_in6);
896	if (!peer_addr) {
897		talloc_free(peer);
898		return NULL;
899	}
900
901	peer->sockaddr = (struct sockaddr *)peer_addr;
902
903	ret = getpeername(sock->fd, peer->sockaddr, &len);
904	if (ret == -1) {
905		talloc_free(peer);
906		return NULL;
907	}
908
909	peer->sockaddrlen = len;
910
911	addr_ret = inet_ntop(AF_INET6, &peer_addr->sin6_addr, addr, sizeof(addr));
912	if (addr_ret == NULL) {
913		talloc_free(peer);
914		return NULL;
915	}
916
917	peer->addr = talloc_strdup(peer, addr_ret);
918	if (peer->addr == NULL) {
919		talloc_free(peer);
920		return NULL;
921	}
922
923	peer->port = ntohs(peer_addr->sin6_port);
924
925	return peer;
926}
927
928static struct socket_address *ipv6_tcp_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
929{
930	struct sockaddr_in6 *local_addr;
931	socklen_t len = sizeof(*local_addr);
932	struct socket_address *local;
933	int ret;
934	char addrstring[INET6_ADDRSTRLEN];
935
936	local = talloc(mem_ctx, struct socket_address);
937	if (!local) {
938		return NULL;
939	}
940
941	local->family = sock->backend_name;
942	local_addr = talloc(local, struct sockaddr_in6);
943	if (!local_addr) {
944		talloc_free(local);
945		return NULL;
946	}
947
948	local->sockaddr = (struct sockaddr *)local_addr;
949
950	ret = getsockname(sock->fd, local->sockaddr, &len);
951	if (ret == -1) {
952		talloc_free(local);
953		return NULL;
954	}
955
956	local->sockaddrlen = len;
957
958	if (inet_ntop(AF_INET6, &local_addr->sin6_addr, addrstring,
959		       sizeof(addrstring)) == NULL) {
960		DEBUG(0, ("Unable to convert address to string: %s\n",
961			  strerror(errno)));
962		talloc_free(local);
963		return NULL;
964	}
965
966	local->addr = talloc_strdup(mem_ctx, addrstring);
967	if (!local->addr) {
968		talloc_free(local);
969		return NULL;
970	}
971	local->port = ntohs(local_addr->sin6_port);
972
973	return local;
974}
975
976static const struct socket_ops ipv6_tcp_ops = {
977	.name			= "ipv6",
978	.fn_init		= ipv6_init,
979	.fn_connect		= ipv6_tcp_connect,
980	.fn_connect_complete	= ip_connect_complete,
981	.fn_listen		= ipv6_listen,
982	.fn_accept		= ipv6_tcp_accept,
983	.fn_recv		= ip_recv,
984	.fn_recvfrom 		= ipv6_recvfrom,
985	.fn_send		= ip_send,
986	.fn_sendto		= ipv6_sendto,
987	.fn_pending		= ip_pending,
988	.fn_close		= ip_close,
989
990	.fn_set_option		= ipv6_set_option,
991
992	.fn_get_peer_name	= ipv6_tcp_get_peer_name,
993	.fn_get_peer_addr	= ipv6_tcp_get_peer_addr,
994	.fn_get_my_addr		= ipv6_tcp_get_my_addr,
995
996	.fn_get_fd		= ip_get_fd
997};
998
999_PUBLIC_ const struct socket_ops *socket_ipv6_ops(enum socket_type type)
1000{
1001	return &ipv6_tcp_ops;
1002}
1003
1004#endif
1005