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"
29 static NTSTATUS
ipv4_init(struct socket_context
*sock
)
34 case SOCKET_TYPE_STREAM
:
37 case SOCKET_TYPE_DGRAM
:
41 return NT_STATUS_INVALID_PARAMETER
;
44 sock
->fd
= socket(PF_INET
, type
, 0);
46 return map_nt_error_from_unix(errno
);
49 sock
->backend_name
= "ipv4";
50 sock
->family
= AF_INET
;
55 static void ip_close(struct socket_context
*sock
)
60 static NTSTATUS
ip_connect_complete(struct socket_context
*sock
, uint32_t flags
)
63 socklen_t len
= sizeof(error
);
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
);
69 return map_nt_error_from_unix(errno
);
72 return map_nt_error_from_unix(error
);
75 if (!(flags
& SOCKET_FLAG_BLOCK
)) {
76 ret
= set_blocking(sock
->fd
, false);
78 return map_nt_error_from_unix(errno
);
82 sock
->state
= SOCKET_STATE_CLIENT_CONNECTED
;
88 static NTSTATUS
ipv4_connect(struct socket_context
*sock
,
89 const struct socket_address
*my_address
,
90 const struct socket_address
*srv_address
,
93 struct sockaddr_in srv_addr
;
95 struct in_addr srv_ip
;
98 if (my_address
&& my_address
->sockaddr
) {
99 ret
= bind(sock
->fd
, my_address
->sockaddr
, my_address
->sockaddrlen
);
101 return map_nt_error_from_unix(errno
);
103 } else if (my_address
) {
104 my_ip
= interpret_addr2(my_address
->addr
);
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
);
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
;
116 ret
= bind(sock
->fd
, (struct sockaddr
*)&my_addr
, sizeof(my_addr
));
118 return map_nt_error_from_unix(errno
);
123 if (srv_address
->sockaddr
) {
124 ret
= connect(sock
->fd
, srv_address
->sockaddr
, srv_address
->sockaddrlen
);
126 return map_nt_error_from_unix(errno
);
129 srv_ip
= interpret_addr2(srv_address
->addr
);
130 if (!srv_ip
.s_addr
) {
131 return NT_STATUS_BAD_NETWORK_NAME
;
134 SMB_ASSERT(srv_address
->port
!= 0);
136 ZERO_STRUCT(srv_addr
);
137 #ifdef HAVE_SOCK_SIN_LEN
138 srv_addr
.sin_len
= sizeof(srv_addr
);
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
;
144 ret
= connect(sock
->fd
, (const struct sockaddr
*)&srv_addr
, sizeof(srv_addr
));
146 return map_nt_error_from_unix(errno
);
150 return ip_connect_complete(sock
, flags
);
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
158 static NTSTATUS
ipv4_listen(struct socket_context
*sock
,
159 const struct socket_address
*my_address
,
160 int queue_size
, uint32_t flags
)
162 struct sockaddr_in my_addr
;
163 struct in_addr ip_addr
;
166 socket_set_option(sock
, "SO_REUSEADDR=1", NULL
);
168 if (my_address
->sockaddr
) {
169 ret
= bind(sock
->fd
, my_address
->sockaddr
, my_address
->sockaddrlen
);
171 ip_addr
= interpret_addr2(my_address
->addr
);
173 ZERO_STRUCT(my_addr
);
174 #ifdef HAVE_SOCK_SIN_LEN
175 my_addr
.sin_len
= sizeof(my_addr
);
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
;
181 ret
= bind(sock
->fd
, (struct sockaddr
*)&my_addr
, sizeof(my_addr
));
185 return map_nt_error_from_unix(errno
);
188 if (sock
->type
== SOCKET_TYPE_STREAM
) {
189 ret
= listen(sock
->fd
, queue_size
);
191 return map_nt_error_from_unix(errno
);
195 if (!(flags
& SOCKET_FLAG_BLOCK
)) {
196 ret
= set_blocking(sock
->fd
, false);
198 return map_nt_error_from_unix(errno
);
202 sock
->state
= SOCKET_STATE_SERVER_LISTEN
;
207 static NTSTATUS
ipv4_accept(struct socket_context
*sock
, struct socket_context
**new_sock
)
209 struct sockaddr_in cli_addr
;
210 socklen_t cli_addr_len
= sizeof(cli_addr
);
213 if (sock
->type
!= SOCKET_TYPE_STREAM
) {
214 return NT_STATUS_INVALID_PARAMETER
;
217 new_fd
= accept(sock
->fd
, (struct sockaddr
*)&cli_addr
, &cli_addr_len
);
219 return map_nt_error_from_unix(errno
);
222 if (!(sock
->flags
& SOCKET_FLAG_BLOCK
)) {
223 int ret
= set_blocking(new_fd
, false);
226 return map_nt_error_from_unix(errno
);
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
236 (*new_sock
) = talloc(NULL
, struct socket_context
);
239 return NT_STATUS_NO_MEMORY
;
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
;
247 (*new_sock
)->fd
= new_fd
;
249 (*new_sock
)->private_data
= NULL
;
250 (*new_sock
)->ops
= sock
->ops
;
251 (*new_sock
)->backend_name
= sock
->backend_name
;
256 static NTSTATUS
ip_recv(struct socket_context
*sock
, void *buf
,
257 size_t wantlen
, size_t *nread
)
263 gotlen
= recv(sock
->fd
, buf
, wantlen
, 0);
265 return NT_STATUS_END_OF_FILE
;
266 } else if (gotlen
== -1) {
267 return map_nt_error_from_unix(errno
);
276 static 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
)
281 struct sockaddr_in
*from_addr
;
282 socklen_t from_len
= sizeof(*from_addr
);
283 struct socket_address
*src
;
284 char addrstring
[INET_ADDRSTRLEN
];
286 src
= talloc(addr_ctx
, struct socket_address
);
288 return NT_STATUS_NO_MEMORY
;
291 src
->family
= sock
->backend_name
;
293 from_addr
= talloc(src
, struct sockaddr_in
);
296 return NT_STATUS_NO_MEMORY
;
299 src
->sockaddr
= (struct sockaddr
*)from_addr
;
303 gotlen
= recvfrom(sock
->fd
, buf
, wantlen
, 0,
304 src
->sockaddr
, &from_len
);
307 return NT_STATUS_END_OF_FILE
;
308 } else if (gotlen
== -1) {
310 return map_nt_error_from_unix(errno
);
313 src
->sockaddrlen
= from_len
;
315 if (inet_ntop(AF_INET
, &from_addr
->sin_addr
, addrstring
,
316 sizeof(addrstring
)) == NULL
) {
318 return NT_STATUS_INTERNAL_ERROR
;
320 src
->addr
= talloc_strdup(src
, addrstring
);
321 if (src
->addr
== NULL
) {
323 return NT_STATUS_NO_MEMORY
;
325 src
->port
= ntohs(from_addr
->sin_port
);
332 static NTSTATUS
ip_send(struct socket_context
*sock
,
333 const DATA_BLOB
*blob
, size_t *sendlen
)
339 len
= send(sock
->fd
, blob
->data
, blob
->length
, 0);
341 return map_nt_error_from_unix(errno
);
349 static NTSTATUS
ipv4_sendto(struct socket_context
*sock
,
350 const DATA_BLOB
*blob
, size_t *sendlen
,
351 const struct socket_address
*dest_addr
)
355 if (dest_addr
->sockaddr
) {
356 len
= sendto(sock
->fd
, blob
->data
, blob
->length
, 0,
357 dest_addr
->sockaddr
, dest_addr
->sockaddrlen
);
359 struct sockaddr_in srv_addr
;
362 SMB_ASSERT(dest_addr
->port
!= 0);
364 ZERO_STRUCT(srv_addr
);
365 #ifdef HAVE_SOCK_SIN_LEN
366 srv_addr
.sin_len
= sizeof(srv_addr
);
368 addr
= interpret_addr2(dest_addr
->addr
);
369 if (addr
.s_addr
== 0) {
370 return NT_STATUS_HOST_UNREACHABLE
;
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
;
378 len
= sendto(sock
->fd
, blob
->data
, blob
->length
, 0,
379 (struct sockaddr
*)&srv_addr
, sizeof(srv_addr
));
382 return map_nt_error_from_unix(errno
);
390 static NTSTATUS
ipv4_set_option(struct socket_context
*sock
, const char *option
, const char *val
)
392 set_socket_options(sock
->fd
, option
);
396 static char *ipv4_get_peer_name(struct socket_context
*sock
, TALLOC_CTX
*mem_ctx
)
398 struct sockaddr_in peer_addr
;
399 socklen_t len
= sizeof(peer_addr
);
403 ret
= getpeername(sock
->fd
, (struct sockaddr
*)&peer_addr
, &len
);
408 he
= gethostbyaddr((char *)&peer_addr
.sin_addr
, sizeof(peer_addr
.sin_addr
), AF_INET
);
413 return talloc_strdup(mem_ctx
, he
->h_name
);
416 static struct socket_address
*ipv4_get_peer_addr(struct socket_context
*sock
, TALLOC_CTX
*mem_ctx
)
418 struct sockaddr_in
*peer_addr
;
419 socklen_t len
= sizeof(*peer_addr
);
420 struct socket_address
*peer
;
421 char addrstring
[INET_ADDRSTRLEN
];
424 peer
= talloc(mem_ctx
, struct socket_address
);
429 peer
->family
= sock
->backend_name
;
430 peer_addr
= talloc(peer
, struct sockaddr_in
);
436 peer
->sockaddr
= (struct sockaddr
*)peer_addr
;
438 ret
= getpeername(sock
->fd
, peer
->sockaddr
, &len
);
444 peer
->sockaddrlen
= len
;
446 if (inet_ntop(AF_INET
, &peer_addr
->sin_addr
, addrstring
,
447 sizeof(addrstring
)) == NULL
) {
451 peer
->addr
= talloc_strdup(peer
, addrstring
);
456 peer
->port
= ntohs(peer_addr
->sin_port
);
461 static struct socket_address
*ipv4_get_my_addr(struct socket_context
*sock
, TALLOC_CTX
*mem_ctx
)
463 struct sockaddr_in
*local_addr
;
464 socklen_t len
= sizeof(*local_addr
);
465 struct socket_address
*local
;
466 char addrstring
[INET_ADDRSTRLEN
];
469 local
= talloc(mem_ctx
, struct socket_address
);
474 local
->family
= sock
->backend_name
;
475 local_addr
= talloc(local
, struct sockaddr_in
);
481 local
->sockaddr
= (struct sockaddr
*)local_addr
;
483 ret
= getsockname(sock
->fd
, local
->sockaddr
, &len
);
489 local
->sockaddrlen
= len
;
491 if (inet_ntop(AF_INET
, &local_addr
->sin_addr
, addrstring
,
492 sizeof(addrstring
)) == NULL
) {
496 local
->addr
= talloc_strdup(local
, addrstring
);
501 local
->port
= ntohs(local_addr
->sin_port
);
505 static int ip_get_fd(struct socket_context
*sock
)
510 static NTSTATUS
ip_pending(struct socket_context
*sock
, size_t *npending
)
513 if (ioctl(sock
->fd
, FIONREAD
, &value
) == 0) {
517 return map_nt_error_from_unix(errno
);
520 static const struct socket_ops ipv4_ops
= {
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
,
528 .fn_recvfrom
= ipv4_recvfrom
,
530 .fn_sendto
= ipv4_sendto
,
531 .fn_pending
= ip_pending
,
532 .fn_close
= ip_close
,
534 .fn_set_option
= ipv4_set_option
,
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
,
540 .fn_get_fd
= ip_get_fd
543 _PUBLIC_
const struct socket_ops
*socket_ipv4_ops(enum socket_type type
)
550 static struct in6_addr
interpret_addr6(const char *name
)
552 char addr
[INET6_ADDRSTRLEN
];
553 struct in6_addr dest6
;
554 const char *sp
= name
;
558 if (sp
== NULL
) return in6addr_any
;
560 p
= strchr_m(sp
, '%');
562 if (strcasecmp(sp
, "localhost") == 0) {
567 * Cope with link-local.
568 * This is IP:v6:addr%ifname.
571 if (p
&& (p
> sp
) && (if_nametoindex(p
+1) != 0)) {
573 MIN(PTR_DIFF(p
,sp
)+1,
578 ret
= inet_pton(AF_INET6
, sp
, &dest6
);
586 static NTSTATUS
ipv6_init(struct socket_context
*sock
)
590 switch (sock
->type
) {
591 case SOCKET_TYPE_STREAM
:
594 case SOCKET_TYPE_DGRAM
:
598 return NT_STATUS_INVALID_PARAMETER
;
601 sock
->fd
= socket(PF_INET6
, type
, 0);
602 if (sock
->fd
== -1) {
603 return map_nt_error_from_unix(errno
);
606 sock
->backend_name
= "ipv6";
607 sock
->family
= AF_INET6
;
612 static NTSTATUS
ipv6_tcp_connect(struct socket_context
*sock
,
613 const struct socket_address
*my_address
,
614 const struct socket_address
*srv_address
,
619 if (my_address
&& my_address
->sockaddr
) {
620 ret
= bind(sock
->fd
, my_address
->sockaddr
, my_address
->sockaddrlen
);
622 return map_nt_error_from_unix(errno
);
624 } else if (my_address
) {
625 struct in6_addr my_ip
;
626 my_ip
= interpret_addr6(my_address
->addr
);
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
;
635 ret
= bind(sock
->fd
, (struct sockaddr
*)&my_addr
, sizeof(my_addr
));
637 return map_nt_error_from_unix(errno
);
642 if (srv_address
->sockaddr
) {
643 ret
= connect(sock
->fd
, srv_address
->sockaddr
, srv_address
->sockaddrlen
);
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
;
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
;
657 ret
= connect(sock
->fd
, (const struct sockaddr
*)&srv_addr
, sizeof(srv_addr
));
660 return map_nt_error_from_unix(errno
);
663 return ip_connect_complete(sock
, flags
);
666 static NTSTATUS
ipv6_listen(struct socket_context
*sock
,
667 const struct socket_address
*my_address
,
668 int queue_size
, uint32_t flags
)
670 struct sockaddr_in6 my_addr
;
671 struct in6_addr ip_addr
;
674 socket_set_option(sock
, "SO_REUSEADDR=1", NULL
);
676 if (my_address
->sockaddr
) {
677 ret
= bind(sock
->fd
, my_address
->sockaddr
, my_address
->sockaddrlen
);
679 ip_addr
= interpret_addr6(my_address
->addr
);
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
;
686 ret
= bind(sock
->fd
, (struct sockaddr
*)&my_addr
, sizeof(my_addr
));
690 return map_nt_error_from_unix(errno
);
693 if (sock
->type
== SOCKET_TYPE_STREAM
) {
694 ret
= listen(sock
->fd
, queue_size
);
696 return map_nt_error_from_unix(errno
);
700 if (!(flags
& SOCKET_FLAG_BLOCK
)) {
701 ret
= set_blocking(sock
->fd
, false);
703 return map_nt_error_from_unix(errno
);
707 sock
->state
= SOCKET_STATE_SERVER_LISTEN
;
712 static NTSTATUS
ipv6_tcp_accept(struct socket_context
*sock
, struct socket_context
**new_sock
)
714 struct sockaddr_in cli_addr
;
715 socklen_t cli_addr_len
= sizeof(cli_addr
);
718 if (sock
->type
!= SOCKET_TYPE_STREAM
) {
719 return NT_STATUS_INVALID_PARAMETER
;
722 new_fd
= accept(sock
->fd
, (struct sockaddr
*)&cli_addr
, &cli_addr_len
);
724 return map_nt_error_from_unix(errno
);
727 if (!(sock
->flags
& SOCKET_FLAG_BLOCK
)) {
728 int ret
= set_blocking(new_fd
, false);
731 return map_nt_error_from_unix(errno
);
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
741 (*new_sock
) = talloc(NULL
, struct socket_context
);
744 return NT_STATUS_NO_MEMORY
;
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
;
752 (*new_sock
)->fd
= new_fd
;
754 (*new_sock
)->private_data
= NULL
;
755 (*new_sock
)->ops
= sock
->ops
;
756 (*new_sock
)->backend_name
= sock
->backend_name
;
761 static 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
)
766 struct sockaddr_in6
*from_addr
;
767 socklen_t from_len
= sizeof(*from_addr
);
768 struct socket_address
*src
;
769 char addrstring
[INET6_ADDRSTRLEN
];
771 src
= talloc(addr_ctx
, struct socket_address
);
773 return NT_STATUS_NO_MEMORY
;
776 src
->family
= sock
->backend_name
;
778 from_addr
= talloc(src
, struct sockaddr_in6
);
781 return NT_STATUS_NO_MEMORY
;
784 src
->sockaddr
= (struct sockaddr
*)from_addr
;
788 gotlen
= recvfrom(sock
->fd
, buf
, wantlen
, 0,
789 src
->sockaddr
, &from_len
);
792 return NT_STATUS_END_OF_FILE
;
793 } else if (gotlen
== -1) {
795 return map_nt_error_from_unix(errno
);
798 src
->sockaddrlen
= from_len
;
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
)));
803 return NT_STATUS_INTERNAL_ERROR
;
806 src
->addr
= talloc_strdup(src
, addrstring
);
807 if (src
->addr
== NULL
) {
809 return NT_STATUS_NO_MEMORY
;
811 src
->port
= ntohs(from_addr
->sin6_port
);
818 static NTSTATUS
ipv6_sendto(struct socket_context
*sock
,
819 const DATA_BLOB
*blob
, size_t *sendlen
,
820 const struct socket_address
*dest_addr
)
824 if (dest_addr
->sockaddr
) {
825 len
= sendto(sock
->fd
, blob
->data
, blob
->length
, 0,
826 dest_addr
->sockaddr
, dest_addr
->sockaddrlen
);
828 struct sockaddr_in6 srv_addr
;
829 struct in6_addr addr
;
831 ZERO_STRUCT(srv_addr
);
832 addr
= interpret_addr6(dest_addr
->addr
);
833 if (addr
.s6_addr
== 0) {
834 return NT_STATUS_HOST_UNREACHABLE
;
836 srv_addr
.sin6_addr
= addr
;
837 srv_addr
.sin6_port
= htons(dest_addr
->port
);
838 srv_addr
.sin6_family
= PF_INET6
;
842 len
= sendto(sock
->fd
, blob
->data
, blob
->length
, 0,
843 (struct sockaddr
*)&srv_addr
, sizeof(srv_addr
));
846 return map_nt_error_from_unix(errno
);
854 static NTSTATUS
ipv6_set_option(struct socket_context
*sock
, const char *option
, const char *val
)
856 set_socket_options(sock
->fd
, option
);
860 static char *ipv6_tcp_get_peer_name(struct socket_context
*sock
, TALLOC_CTX
*mem_ctx
)
862 struct sockaddr_in6 peer_addr
;
863 socklen_t len
= sizeof(peer_addr
);
867 ret
= getpeername(sock
->fd
, (struct sockaddr
*)&peer_addr
, &len
);
872 he
= gethostbyaddr((char *)&peer_addr
.sin6_addr
, sizeof(peer_addr
.sin6_addr
), AF_INET6
);
877 return talloc_strdup(mem_ctx
, he
->h_name
);
880 static struct socket_address
*ipv6_tcp_get_peer_addr(struct socket_context
*sock
, TALLOC_CTX
*mem_ctx
)
882 struct sockaddr_in6
*peer_addr
;
883 socklen_t len
= sizeof(*peer_addr
);
884 struct socket_address
*peer
;
887 const char *addr_ret
;
889 peer
= talloc(mem_ctx
, struct socket_address
);
894 peer
->family
= sock
->backend_name
;
895 peer_addr
= talloc(peer
, struct sockaddr_in6
);
901 peer
->sockaddr
= (struct sockaddr
*)peer_addr
;
903 ret
= getpeername(sock
->fd
, peer
->sockaddr
, &len
);
909 peer
->sockaddrlen
= len
;
911 addr_ret
= inet_ntop(AF_INET6
, &peer_addr
->sin6_addr
, addr
, sizeof(addr
));
912 if (addr_ret
== NULL
) {
917 peer
->addr
= talloc_strdup(peer
, addr_ret
);
918 if (peer
->addr
== NULL
) {
923 peer
->port
= ntohs(peer_addr
->sin6_port
);
928 static struct socket_address
*ipv6_tcp_get_my_addr(struct socket_context
*sock
, TALLOC_CTX
*mem_ctx
)
930 struct sockaddr_in6
*local_addr
;
931 socklen_t len
= sizeof(*local_addr
);
932 struct socket_address
*local
;
934 char addrstring
[INET6_ADDRSTRLEN
];
936 local
= talloc(mem_ctx
, struct socket_address
);
941 local
->family
= sock
->backend_name
;
942 local_addr
= talloc(local
, struct sockaddr_in6
);
948 local
->sockaddr
= (struct sockaddr
*)local_addr
;
950 ret
= getsockname(sock
->fd
, local
->sockaddr
, &len
);
956 local
->sockaddrlen
= len
;
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",
966 local
->addr
= talloc_strdup(mem_ctx
, addrstring
);
971 local
->port
= ntohs(local_addr
->sin6_port
);
976 static const struct socket_ops ipv6_tcp_ops
= {
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
,
984 .fn_recvfrom
= ipv6_recvfrom
,
986 .fn_sendto
= ipv6_sendto
,
987 .fn_pending
= ip_pending
,
988 .fn_close
= ip_close
,
990 .fn_set_option
= ipv6_set_option
,
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
,
996 .fn_get_fd
= ip_get_fd
999 _PUBLIC_
const struct socket_ops
*socket_ipv6_ops(enum socket_type type
)
1001 return &ipv6_tcp_ops
;