2 Unix SMB/CIFS implementation.
4 Socket IPv4/IPv6 functions
6 Copyright (C) Stefan Metzmacher 2004
7 Copyright (C) Andrew Tridgell 2004-2005
8 Copyright (C) Jelmer Vernooij 2004
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.
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.
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/>.
25 #include "system/filesys.h"
26 #include "lib/socket/socket.h"
27 #include "system/network.h"
28 #include "lib/util/util_net.h"
32 _PUBLIC_
const struct socket_ops
*socket_ipv4_ops(enum socket_type type
);
33 _PUBLIC_
const struct socket_ops
*socket_ipv6_ops(enum socket_type type
);
35 static NTSTATUS
ipv4_init(struct socket_context
*sock
)
40 case SOCKET_TYPE_STREAM
:
43 case SOCKET_TYPE_DGRAM
:
47 return NT_STATUS_INVALID_PARAMETER
;
50 sock
->fd
= socket(PF_INET
, type
, 0);
52 return map_nt_error_from_unix_common(errno
);
55 smb_set_close_on_exec(sock
->fd
);
57 sock
->backend_name
= "ipv4";
58 sock
->family
= AF_INET
;
63 static void ip_close(struct socket_context
*sock
)
71 static NTSTATUS
ip_connect_complete(struct socket_context
*sock
, uint32_t flags
)
74 socklen_t len
= sizeof(error
);
76 /* check for any errors that may have occurred - this is needed
77 for non-blocking connect */
78 ret
= getsockopt(sock
->fd
, SOL_SOCKET
, SO_ERROR
, &error
, &len
);
80 return map_nt_error_from_unix_common(errno
);
83 return map_nt_error_from_unix_common(error
);
86 ret
= set_blocking(sock
->fd
, false);
88 return map_nt_error_from_unix_common(errno
);
91 sock
->state
= SOCKET_STATE_CLIENT_CONNECTED
;
97 static NTSTATUS
ipv4_connect(struct socket_context
*sock
,
98 const struct socket_address
*my_address
,
99 const struct socket_address
*srv_address
,
102 struct sockaddr_in srv_addr
;
103 struct in_addr my_ip
;
104 struct in_addr srv_ip
;
107 if (my_address
&& my_address
->sockaddr
) {
108 ret
= bind(sock
->fd
, my_address
->sockaddr
, my_address
->sockaddrlen
);
110 return map_nt_error_from_unix_common(errno
);
112 } else if (my_address
) {
113 my_ip
= interpret_addr2(my_address
->addr
);
115 if (my_ip
.s_addr
!= 0 || my_address
->port
!= 0) {
116 struct sockaddr_in my_addr
;
117 ZERO_STRUCT(my_addr
);
118 #ifdef HAVE_SOCK_SIN_LEN
119 my_addr
.sin_len
= sizeof(my_addr
);
121 my_addr
.sin_addr
.s_addr
= my_ip
.s_addr
;
122 my_addr
.sin_port
= htons(my_address
->port
);
123 my_addr
.sin_family
= PF_INET
;
125 ret
= bind(sock
->fd
, (struct sockaddr
*)&my_addr
, sizeof(my_addr
));
127 return map_nt_error_from_unix_common(errno
);
132 if (srv_address
->sockaddr
) {
133 ret
= connect(sock
->fd
, srv_address
->sockaddr
, srv_address
->sockaddrlen
);
135 return map_nt_error_from_unix_common(errno
);
138 srv_ip
= interpret_addr2(srv_address
->addr
);
139 if (!srv_ip
.s_addr
) {
140 return NT_STATUS_BAD_NETWORK_NAME
;
143 SMB_ASSERT(srv_address
->port
!= 0);
145 ZERO_STRUCT(srv_addr
);
146 #ifdef HAVE_SOCK_SIN_LEN
147 srv_addr
.sin_len
= sizeof(srv_addr
);
149 srv_addr
.sin_addr
.s_addr
= srv_ip
.s_addr
;
150 srv_addr
.sin_port
= htons(srv_address
->port
);
151 srv_addr
.sin_family
= PF_INET
;
153 ret
= connect(sock
->fd
, (const struct sockaddr
*)&srv_addr
, sizeof(srv_addr
));
155 return map_nt_error_from_unix_common(errno
);
159 return ip_connect_complete(sock
, flags
);
164 note that for simplicity of the API, socket_listen() is also
165 use for DGRAM sockets, but in reality only a bind() is done
167 static NTSTATUS
ipv4_listen(struct socket_context
*sock
,
168 const struct socket_address
*my_address
,
169 int queue_size
, uint32_t flags
)
171 struct sockaddr_in my_addr
;
172 struct in_addr ip_addr
;
175 socket_set_option(sock
, "SO_REUSEADDR=1", NULL
);
177 if (my_address
->sockaddr
) {
178 ret
= bind(sock
->fd
, my_address
->sockaddr
, my_address
->sockaddrlen
);
180 ip_addr
= interpret_addr2(my_address
->addr
);
182 ZERO_STRUCT(my_addr
);
183 #ifdef HAVE_SOCK_SIN_LEN
184 my_addr
.sin_len
= sizeof(my_addr
);
186 my_addr
.sin_addr
.s_addr
= ip_addr
.s_addr
;
187 my_addr
.sin_port
= htons(my_address
->port
);
188 my_addr
.sin_family
= PF_INET
;
190 ret
= bind(sock
->fd
, (struct sockaddr
*)&my_addr
, sizeof(my_addr
));
194 return map_nt_error_from_unix_common(errno
);
197 if (sock
->type
== SOCKET_TYPE_STREAM
) {
198 ret
= listen(sock
->fd
, queue_size
);
200 return map_nt_error_from_unix_common(errno
);
204 ret
= set_blocking(sock
->fd
, false);
206 return map_nt_error_from_unix_common(errno
);
209 sock
->state
= SOCKET_STATE_SERVER_LISTEN
;
214 static NTSTATUS
ipv4_accept(struct socket_context
*sock
, struct socket_context
**new_sock
)
216 struct sockaddr_in cli_addr
;
217 socklen_t cli_addr_len
= sizeof(cli_addr
);
220 if (sock
->type
!= SOCKET_TYPE_STREAM
) {
221 return NT_STATUS_INVALID_PARAMETER
;
224 new_fd
= accept(sock
->fd
, (struct sockaddr
*)&cli_addr
, &cli_addr_len
);
226 return map_nt_error_from_unix_common(errno
);
229 ret
= set_blocking(new_fd
, false);
232 return map_nt_error_from_unix_common(errno
);
235 smb_set_close_on_exec(new_fd
);
238 /* TODO: we could add a 'accept_check' hook here
239 * which get the black/white lists via socket_set_accept_filter()
240 * or something like that
244 (*new_sock
) = talloc(NULL
, struct socket_context
);
247 return NT_STATUS_NO_MEMORY
;
250 /* copy the socket_context */
251 (*new_sock
)->type
= sock
->type
;
252 (*new_sock
)->state
= SOCKET_STATE_SERVER_CONNECTED
;
253 (*new_sock
)->flags
= sock
->flags
;
255 (*new_sock
)->fd
= new_fd
;
257 (*new_sock
)->private_data
= NULL
;
258 (*new_sock
)->ops
= sock
->ops
;
259 (*new_sock
)->backend_name
= sock
->backend_name
;
264 static NTSTATUS
ip_recv(struct socket_context
*sock
, void *buf
,
265 size_t wantlen
, size_t *nread
)
271 gotlen
= recv(sock
->fd
, buf
, wantlen
, 0);
273 return NT_STATUS_END_OF_FILE
;
274 } else if (gotlen
== -1) {
275 return map_nt_error_from_unix_common(errno
);
284 static NTSTATUS
ipv4_recvfrom(struct socket_context
*sock
, void *buf
,
285 size_t wantlen
, size_t *nread
,
286 TALLOC_CTX
*addr_ctx
, struct socket_address
**_src
)
289 struct sockaddr_in
*from_addr
;
290 socklen_t from_len
= sizeof(*from_addr
);
291 struct socket_address
*src
;
292 char addrstring
[INET_ADDRSTRLEN
];
294 src
= talloc(addr_ctx
, struct socket_address
);
296 return NT_STATUS_NO_MEMORY
;
299 src
->family
= sock
->backend_name
;
301 from_addr
= talloc(src
, struct sockaddr_in
);
304 return NT_STATUS_NO_MEMORY
;
307 src
->sockaddr
= (struct sockaddr
*)from_addr
;
311 gotlen
= recvfrom(sock
->fd
, buf
, wantlen
, 0,
312 src
->sockaddr
, &from_len
);
315 return NT_STATUS_END_OF_FILE
;
319 return map_nt_error_from_unix_common(errno
);
322 src
->sockaddrlen
= from_len
;
324 if (inet_ntop(AF_INET
, &from_addr
->sin_addr
, addrstring
,
325 sizeof(addrstring
)) == NULL
) {
327 return NT_STATUS_INTERNAL_ERROR
;
329 src
->addr
= talloc_strdup(src
, addrstring
);
330 if (src
->addr
== NULL
) {
332 return NT_STATUS_NO_MEMORY
;
334 src
->port
= ntohs(from_addr
->sin_port
);
341 static NTSTATUS
ip_send(struct socket_context
*sock
,
342 const DATA_BLOB
*blob
, size_t *sendlen
)
348 len
= send(sock
->fd
, blob
->data
, blob
->length
, 0);
350 return map_nt_error_from_unix_common(errno
);
358 static NTSTATUS
ipv4_sendto(struct socket_context
*sock
,
359 const DATA_BLOB
*blob
, size_t *sendlen
,
360 const struct socket_address
*dest_addr
)
364 if (dest_addr
->sockaddr
) {
365 len
= sendto(sock
->fd
, blob
->data
, blob
->length
, 0,
366 dest_addr
->sockaddr
, dest_addr
->sockaddrlen
);
368 struct sockaddr_in srv_addr
;
371 SMB_ASSERT(dest_addr
->port
!= 0);
373 ZERO_STRUCT(srv_addr
);
374 #ifdef HAVE_SOCK_SIN_LEN
375 srv_addr
.sin_len
= sizeof(srv_addr
);
377 addr
= interpret_addr2(dest_addr
->addr
);
378 if (addr
.s_addr
== 0) {
379 return NT_STATUS_HOST_UNREACHABLE
;
381 srv_addr
.sin_addr
.s_addr
= addr
.s_addr
;
382 srv_addr
.sin_port
= htons(dest_addr
->port
);
383 srv_addr
.sin_family
= PF_INET
;
387 len
= sendto(sock
->fd
, blob
->data
, blob
->length
, 0,
388 (struct sockaddr
*)&srv_addr
, sizeof(srv_addr
));
391 return map_nt_error_from_unix_common(errno
);
399 static NTSTATUS
ipv4_set_option(struct socket_context
*sock
, const char *option
, const char *val
)
401 set_socket_options(sock
->fd
, option
);
405 static char *ipv4_get_peer_name(struct socket_context
*sock
, TALLOC_CTX
*mem_ctx
)
407 struct sockaddr_in peer_addr
;
408 socklen_t len
= sizeof(peer_addr
);
412 ret
= getpeername(sock
->fd
, (struct sockaddr
*)&peer_addr
, &len
);
417 he
= gethostbyaddr((char *)&peer_addr
.sin_addr
, sizeof(peer_addr
.sin_addr
), AF_INET
);
422 return talloc_strdup(mem_ctx
, he
->h_name
);
425 static struct socket_address
*ipv4_get_peer_addr(struct socket_context
*sock
, TALLOC_CTX
*mem_ctx
)
427 struct sockaddr_in
*peer_addr
;
428 socklen_t len
= sizeof(*peer_addr
);
429 struct socket_address
*peer
;
430 char addrstring
[INET_ADDRSTRLEN
];
433 peer
= talloc(mem_ctx
, struct socket_address
);
438 peer
->family
= sock
->backend_name
;
439 peer_addr
= talloc(peer
, struct sockaddr_in
);
445 peer
->sockaddr
= (struct sockaddr
*)peer_addr
;
447 ret
= getpeername(sock
->fd
, peer
->sockaddr
, &len
);
453 peer
->sockaddrlen
= len
;
455 if (inet_ntop(AF_INET
, &peer_addr
->sin_addr
, addrstring
,
456 sizeof(addrstring
)) == NULL
) {
460 peer
->addr
= talloc_strdup(peer
, addrstring
);
465 peer
->port
= ntohs(peer_addr
->sin_port
);
470 static struct socket_address
*ipv4_get_my_addr(struct socket_context
*sock
, TALLOC_CTX
*mem_ctx
)
472 struct sockaddr_in
*local_addr
;
473 socklen_t len
= sizeof(*local_addr
);
474 struct socket_address
*local
;
475 char addrstring
[INET_ADDRSTRLEN
];
478 local
= talloc(mem_ctx
, struct socket_address
);
483 local
->family
= sock
->backend_name
;
484 local_addr
= talloc(local
, struct sockaddr_in
);
490 local
->sockaddr
= (struct sockaddr
*)local_addr
;
492 ret
= getsockname(sock
->fd
, local
->sockaddr
, &len
);
498 local
->sockaddrlen
= len
;
500 if (inet_ntop(AF_INET
, &local_addr
->sin_addr
, addrstring
,
501 sizeof(addrstring
)) == NULL
) {
505 local
->addr
= talloc_strdup(local
, addrstring
);
510 local
->port
= ntohs(local_addr
->sin_port
);
514 static int ip_get_fd(struct socket_context
*sock
)
519 static NTSTATUS
ip_pending(struct socket_context
*sock
, size_t *npending
)
522 if (ioctl(sock
->fd
, FIONREAD
, &value
) == 0) {
526 return map_nt_error_from_unix_common(errno
);
529 static const struct socket_ops ipv4_ops
= {
531 .fn_init
= ipv4_init
,
532 .fn_connect
= ipv4_connect
,
533 .fn_connect_complete
= ip_connect_complete
,
534 .fn_listen
= ipv4_listen
,
535 .fn_accept
= ipv4_accept
,
537 .fn_recvfrom
= ipv4_recvfrom
,
539 .fn_sendto
= ipv4_sendto
,
540 .fn_pending
= ip_pending
,
541 .fn_close
= ip_close
,
543 .fn_set_option
= ipv4_set_option
,
545 .fn_get_peer_name
= ipv4_get_peer_name
,
546 .fn_get_peer_addr
= ipv4_get_peer_addr
,
547 .fn_get_my_addr
= ipv4_get_my_addr
,
549 .fn_get_fd
= ip_get_fd
552 _PUBLIC_
const struct socket_ops
*socket_ipv4_ops(enum socket_type type
)
559 static struct in6_addr
interpret_addr6(const char *name
)
561 char addr
[INET6_ADDRSTRLEN
];
562 struct in6_addr dest6
;
563 const char *sp
= name
;
567 if (sp
== NULL
) return in6addr_any
;
569 p
= strchr_m(sp
, '%');
571 if (strcasecmp(sp
, "localhost") == 0) {
576 * Cope with link-local.
577 * This is IP:v6:addr%ifname.
580 if (p
&& (p
> sp
) && (if_nametoindex(p
+1) != 0)) {
582 MIN(PTR_DIFF(p
,sp
)+1,
587 ret
= inet_pton(AF_INET6
, sp
, &dest6
);
595 static NTSTATUS
ipv6_init(struct socket_context
*sock
)
599 switch (sock
->type
) {
600 case SOCKET_TYPE_STREAM
:
603 case SOCKET_TYPE_DGRAM
:
607 return NT_STATUS_INVALID_PARAMETER
;
610 sock
->fd
= socket(PF_INET6
, type
, 0);
611 if (sock
->fd
== -1) {
612 return map_nt_error_from_unix_common(errno
);
615 smb_set_close_on_exec(sock
->fd
);
617 sock
->backend_name
= "ipv6";
618 sock
->family
= AF_INET6
;
623 static NTSTATUS
ipv6_tcp_connect(struct socket_context
*sock
,
624 const struct socket_address
*my_address
,
625 const struct socket_address
*srv_address
,
630 if (my_address
&& my_address
->sockaddr
) {
631 ret
= bind(sock
->fd
, my_address
->sockaddr
, my_address
->sockaddrlen
);
633 return map_nt_error_from_unix_common(errno
);
635 } else if (my_address
) {
636 struct in6_addr my_ip
;
637 my_ip
= interpret_addr6(my_address
->addr
);
639 if (memcmp(&my_ip
, &in6addr_any
, sizeof(my_ip
)) || my_address
->port
!= 0) {
640 struct sockaddr_in6 my_addr
;
641 ZERO_STRUCT(my_addr
);
642 my_addr
.sin6_addr
= my_ip
;
643 my_addr
.sin6_port
= htons(my_address
->port
);
644 my_addr
.sin6_family
= PF_INET6
;
646 ret
= bind(sock
->fd
, (struct sockaddr
*)&my_addr
, sizeof(my_addr
));
648 return map_nt_error_from_unix_common(errno
);
653 if (srv_address
->sockaddr
) {
654 ret
= connect(sock
->fd
, srv_address
->sockaddr
, srv_address
->sockaddrlen
);
656 struct in6_addr srv_ip
;
657 struct sockaddr_in6 srv_addr
;
658 srv_ip
= interpret_addr6(srv_address
->addr
);
659 if (memcmp(&srv_ip
, &in6addr_any
, sizeof(srv_ip
)) == 0) {
660 return NT_STATUS_BAD_NETWORK_NAME
;
663 ZERO_STRUCT(srv_addr
);
664 srv_addr
.sin6_addr
= srv_ip
;
665 srv_addr
.sin6_port
= htons(srv_address
->port
);
666 srv_addr
.sin6_family
= PF_INET6
;
668 ret
= connect(sock
->fd
, (const struct sockaddr
*)&srv_addr
, sizeof(srv_addr
));
671 return map_nt_error_from_unix_common(errno
);
674 return ip_connect_complete(sock
, flags
);
678 fix the sin6_scope_id based on the address interface
680 static void fix_scope_id(struct sockaddr_in6
*in6
,
683 const char *p
= strchr(address
, '%');
685 in6
->sin6_scope_id
= if_nametoindex(p
+1);
690 static NTSTATUS
ipv6_listen(struct socket_context
*sock
,
691 const struct socket_address
*my_address
,
692 int queue_size
, uint32_t flags
)
694 struct sockaddr_in6 my_addr
;
695 struct in6_addr ip_addr
;
698 socket_set_option(sock
, "SO_REUSEADDR=1", NULL
);
700 if (my_address
->sockaddr
) {
701 ret
= bind(sock
->fd
, my_address
->sockaddr
, my_address
->sockaddrlen
);
704 ip_addr
= interpret_addr6(my_address
->addr
);
706 ZERO_STRUCT(my_addr
);
707 my_addr
.sin6_addr
= ip_addr
;
708 my_addr
.sin6_port
= htons(my_address
->port
);
709 my_addr
.sin6_family
= PF_INET6
;
710 fix_scope_id(&my_addr
, my_address
->addr
);
712 /* when binding on ipv6 we always want to only bind on v6 */
713 ret
= setsockopt(sock
->fd
, IPPROTO_IPV6
, IPV6_V6ONLY
,
714 (const void *)&one
, sizeof(one
));
716 ret
= bind(sock
->fd
, (struct sockaddr
*)&my_addr
, sizeof(my_addr
));
721 return map_nt_error_from_unix_common(errno
);
724 if (sock
->type
== SOCKET_TYPE_STREAM
) {
725 ret
= listen(sock
->fd
, queue_size
);
727 return map_nt_error_from_unix_common(errno
);
731 ret
= set_blocking(sock
->fd
, false);
733 return map_nt_error_from_unix_common(errno
);
736 sock
->state
= SOCKET_STATE_SERVER_LISTEN
;
741 static NTSTATUS
ipv6_tcp_accept(struct socket_context
*sock
, struct socket_context
**new_sock
)
743 struct sockaddr_in6 cli_addr
;
744 socklen_t cli_addr_len
= sizeof(cli_addr
);
747 if (sock
->type
!= SOCKET_TYPE_STREAM
) {
748 return NT_STATUS_INVALID_PARAMETER
;
751 new_fd
= accept(sock
->fd
, (struct sockaddr
*)&cli_addr
, &cli_addr_len
);
753 return map_nt_error_from_unix_common(errno
);
756 ret
= set_blocking(new_fd
, false);
759 return map_nt_error_from_unix_common(errno
);
761 smb_set_close_on_exec(new_fd
);
763 /* TODO: we could add a 'accept_check' hook here
764 * which get the black/white lists via socket_set_accept_filter()
765 * or something like that
769 (*new_sock
) = talloc(NULL
, struct socket_context
);
772 return NT_STATUS_NO_MEMORY
;
775 /* copy the socket_context */
776 (*new_sock
)->type
= sock
->type
;
777 (*new_sock
)->state
= SOCKET_STATE_SERVER_CONNECTED
;
778 (*new_sock
)->flags
= sock
->flags
;
780 (*new_sock
)->fd
= new_fd
;
782 (*new_sock
)->private_data
= NULL
;
783 (*new_sock
)->ops
= sock
->ops
;
784 (*new_sock
)->backend_name
= sock
->backend_name
;
789 static NTSTATUS
ipv6_recvfrom(struct socket_context
*sock
, void *buf
,
790 size_t wantlen
, size_t *nread
,
791 TALLOC_CTX
*addr_ctx
, struct socket_address
**_src
)
794 struct sockaddr_in6
*from_addr
;
795 socklen_t from_len
= sizeof(*from_addr
);
796 struct socket_address
*src
;
797 char addrstring
[INET6_ADDRSTRLEN
];
799 src
= talloc(addr_ctx
, struct socket_address
);
801 return NT_STATUS_NO_MEMORY
;
804 src
->family
= sock
->backend_name
;
806 from_addr
= talloc(src
, struct sockaddr_in6
);
809 return NT_STATUS_NO_MEMORY
;
812 src
->sockaddr
= (struct sockaddr
*)from_addr
;
816 gotlen
= recvfrom(sock
->fd
, buf
, wantlen
, 0,
817 src
->sockaddr
, &from_len
);
820 return NT_STATUS_END_OF_FILE
;
821 } else if (gotlen
== -1) {
823 return map_nt_error_from_unix_common(errno
);
826 src
->sockaddrlen
= from_len
;
828 if (inet_ntop(AF_INET6
, &from_addr
->sin6_addr
, addrstring
, sizeof(addrstring
)) == NULL
) {
829 DEBUG(0, ("Unable to convert address to string: %s\n", strerror(errno
)));
831 return NT_STATUS_INTERNAL_ERROR
;
834 src
->addr
= talloc_strdup(src
, addrstring
);
835 if (src
->addr
== NULL
) {
837 return NT_STATUS_NO_MEMORY
;
839 src
->port
= ntohs(from_addr
->sin6_port
);
846 static NTSTATUS
ipv6_sendto(struct socket_context
*sock
,
847 const DATA_BLOB
*blob
, size_t *sendlen
,
848 const struct socket_address
*dest_addr
)
852 if (dest_addr
->sockaddr
) {
853 len
= sendto(sock
->fd
, blob
->data
, blob
->length
, 0,
854 dest_addr
->sockaddr
, dest_addr
->sockaddrlen
);
856 struct sockaddr_in6 srv_addr
;
857 struct in6_addr addr
;
859 ZERO_STRUCT(srv_addr
);
860 addr
= interpret_addr6(dest_addr
->addr
);
861 if (memcmp(&addr
.s6_addr
, &in6addr_any
,
862 sizeof(addr
.s6_addr
)) == 0) {
863 return NT_STATUS_HOST_UNREACHABLE
;
865 srv_addr
.sin6_addr
= addr
;
866 srv_addr
.sin6_port
= htons(dest_addr
->port
);
867 srv_addr
.sin6_family
= PF_INET6
;
871 len
= sendto(sock
->fd
, blob
->data
, blob
->length
, 0,
872 (struct sockaddr
*)&srv_addr
, sizeof(srv_addr
));
875 return map_nt_error_from_unix_common(errno
);
883 static NTSTATUS
ipv6_set_option(struct socket_context
*sock
, const char *option
, const char *val
)
885 set_socket_options(sock
->fd
, option
);
889 static char *ipv6_tcp_get_peer_name(struct socket_context
*sock
, TALLOC_CTX
*mem_ctx
)
891 struct sockaddr_in6 peer_addr
;
892 socklen_t len
= sizeof(peer_addr
);
896 ret
= getpeername(sock
->fd
, (struct sockaddr
*)&peer_addr
, &len
);
901 he
= gethostbyaddr((char *)&peer_addr
.sin6_addr
, sizeof(peer_addr
.sin6_addr
), AF_INET6
);
906 return talloc_strdup(mem_ctx
, he
->h_name
);
909 static struct socket_address
*ipv6_tcp_get_peer_addr(struct socket_context
*sock
, TALLOC_CTX
*mem_ctx
)
911 struct sockaddr_in6
*peer_addr
;
912 socklen_t len
= sizeof(*peer_addr
);
913 struct socket_address
*peer
;
916 const char *addr_ret
;
918 peer
= talloc(mem_ctx
, struct socket_address
);
923 peer
->family
= sock
->backend_name
;
924 peer_addr
= talloc(peer
, struct sockaddr_in6
);
930 peer
->sockaddr
= (struct sockaddr
*)peer_addr
;
932 ret
= getpeername(sock
->fd
, peer
->sockaddr
, &len
);
938 peer
->sockaddrlen
= len
;
940 addr_ret
= inet_ntop(AF_INET6
, &peer_addr
->sin6_addr
, addr
, sizeof(addr
));
941 if (addr_ret
== NULL
) {
946 peer
->addr
= talloc_strdup(peer
, addr_ret
);
947 if (peer
->addr
== NULL
) {
952 peer
->port
= ntohs(peer_addr
->sin6_port
);
957 static struct socket_address
*ipv6_tcp_get_my_addr(struct socket_context
*sock
, TALLOC_CTX
*mem_ctx
)
959 struct sockaddr_in6
*local_addr
;
960 socklen_t len
= sizeof(*local_addr
);
961 struct socket_address
*local
;
963 char addrstring
[INET6_ADDRSTRLEN
];
965 local
= talloc(mem_ctx
, struct socket_address
);
970 local
->family
= sock
->backend_name
;
971 local_addr
= talloc(local
, struct sockaddr_in6
);
977 local
->sockaddr
= (struct sockaddr
*)local_addr
;
979 ret
= getsockname(sock
->fd
, local
->sockaddr
, &len
);
985 local
->sockaddrlen
= len
;
987 if (inet_ntop(AF_INET6
, &local_addr
->sin6_addr
, addrstring
,
988 sizeof(addrstring
)) == NULL
) {
989 DEBUG(0, ("Unable to convert address to string: %s\n",
995 local
->addr
= talloc_strdup(local
, addrstring
);
1000 local
->port
= ntohs(local_addr
->sin6_port
);
1005 static const struct socket_ops ipv6_tcp_ops
= {
1007 .fn_init
= ipv6_init
,
1008 .fn_connect
= ipv6_tcp_connect
,
1009 .fn_connect_complete
= ip_connect_complete
,
1010 .fn_listen
= ipv6_listen
,
1011 .fn_accept
= ipv6_tcp_accept
,
1013 .fn_recvfrom
= ipv6_recvfrom
,
1015 .fn_sendto
= ipv6_sendto
,
1016 .fn_pending
= ip_pending
,
1017 .fn_close
= ip_close
,
1019 .fn_set_option
= ipv6_set_option
,
1021 .fn_get_peer_name
= ipv6_tcp_get_peer_name
,
1022 .fn_get_peer_addr
= ipv6_tcp_get_peer_addr
,
1023 .fn_get_my_addr
= ipv6_tcp_get_my_addr
,
1025 .fn_get_fd
= ip_get_fd
1028 _PUBLIC_
const struct socket_ops
*socket_ipv6_ops(enum socket_type type
)
1030 return &ipv6_tcp_ops
;