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"
30 _PUBLIC_
const struct socket_ops
*socket_ipv4_ops(enum socket_type type
);
31 _PUBLIC_
const struct socket_ops
*socket_ipv6_ops(enum socket_type type
);
33 static NTSTATUS
ipv4_init(struct socket_context
*sock
)
38 case SOCKET_TYPE_STREAM
:
41 case SOCKET_TYPE_DGRAM
:
45 return NT_STATUS_INVALID_PARAMETER
;
48 sock
->fd
= socket(PF_INET
, type
, 0);
50 return map_nt_error_from_unix_common(errno
);
53 sock
->backend_name
= "ipv4";
54 sock
->family
= AF_INET
;
59 static void ip_close(struct socket_context
*sock
)
64 static NTSTATUS
ip_connect_complete(struct socket_context
*sock
, uint32_t flags
)
67 socklen_t len
= sizeof(error
);
69 /* check for any errors that may have occurred - this is needed
70 for non-blocking connect */
71 ret
= getsockopt(sock
->fd
, SOL_SOCKET
, SO_ERROR
, &error
, &len
);
73 return map_nt_error_from_unix_common(errno
);
76 return map_nt_error_from_unix_common(error
);
79 if (!(flags
& SOCKET_FLAG_BLOCK
)) {
80 ret
= set_blocking(sock
->fd
, false);
82 return map_nt_error_from_unix_common(errno
);
86 sock
->state
= SOCKET_STATE_CLIENT_CONNECTED
;
92 static NTSTATUS
ipv4_connect(struct socket_context
*sock
,
93 const struct socket_address
*my_address
,
94 const struct socket_address
*srv_address
,
97 struct sockaddr_in srv_addr
;
99 struct in_addr srv_ip
;
102 if (my_address
&& my_address
->sockaddr
) {
103 ret
= bind(sock
->fd
, my_address
->sockaddr
, my_address
->sockaddrlen
);
105 return map_nt_error_from_unix_common(errno
);
107 } else if (my_address
) {
108 my_ip
= interpret_addr2(my_address
->addr
);
110 if (my_ip
.s_addr
!= 0 || my_address
->port
!= 0) {
111 struct sockaddr_in my_addr
;
112 ZERO_STRUCT(my_addr
);
113 #ifdef HAVE_SOCK_SIN_LEN
114 my_addr
.sin_len
= sizeof(my_addr
);
116 my_addr
.sin_addr
.s_addr
= my_ip
.s_addr
;
117 my_addr
.sin_port
= htons(my_address
->port
);
118 my_addr
.sin_family
= PF_INET
;
120 ret
= bind(sock
->fd
, (struct sockaddr
*)&my_addr
, sizeof(my_addr
));
122 return map_nt_error_from_unix_common(errno
);
127 if (srv_address
->sockaddr
) {
128 ret
= connect(sock
->fd
, srv_address
->sockaddr
, srv_address
->sockaddrlen
);
130 return map_nt_error_from_unix_common(errno
);
133 srv_ip
= interpret_addr2(srv_address
->addr
);
134 if (!srv_ip
.s_addr
) {
135 return NT_STATUS_BAD_NETWORK_NAME
;
138 SMB_ASSERT(srv_address
->port
!= 0);
140 ZERO_STRUCT(srv_addr
);
141 #ifdef HAVE_SOCK_SIN_LEN
142 srv_addr
.sin_len
= sizeof(srv_addr
);
144 srv_addr
.sin_addr
.s_addr
= srv_ip
.s_addr
;
145 srv_addr
.sin_port
= htons(srv_address
->port
);
146 srv_addr
.sin_family
= PF_INET
;
148 ret
= connect(sock
->fd
, (const struct sockaddr
*)&srv_addr
, sizeof(srv_addr
));
150 return map_nt_error_from_unix_common(errno
);
154 return ip_connect_complete(sock
, flags
);
159 note that for simplicity of the API, socket_listen() is also
160 use for DGRAM sockets, but in reality only a bind() is done
162 static NTSTATUS
ipv4_listen(struct socket_context
*sock
,
163 const struct socket_address
*my_address
,
164 int queue_size
, uint32_t flags
)
166 struct sockaddr_in my_addr
;
167 struct in_addr ip_addr
;
170 socket_set_option(sock
, "SO_REUSEADDR=1", NULL
);
172 if (my_address
->sockaddr
) {
173 ret
= bind(sock
->fd
, my_address
->sockaddr
, my_address
->sockaddrlen
);
175 ip_addr
= interpret_addr2(my_address
->addr
);
177 ZERO_STRUCT(my_addr
);
178 #ifdef HAVE_SOCK_SIN_LEN
179 my_addr
.sin_len
= sizeof(my_addr
);
181 my_addr
.sin_addr
.s_addr
= ip_addr
.s_addr
;
182 my_addr
.sin_port
= htons(my_address
->port
);
183 my_addr
.sin_family
= PF_INET
;
185 ret
= bind(sock
->fd
, (struct sockaddr
*)&my_addr
, sizeof(my_addr
));
189 return map_nt_error_from_unix_common(errno
);
192 if (sock
->type
== SOCKET_TYPE_STREAM
) {
193 ret
= listen(sock
->fd
, queue_size
);
195 return map_nt_error_from_unix_common(errno
);
199 if (!(flags
& SOCKET_FLAG_BLOCK
)) {
200 ret
= set_blocking(sock
->fd
, false);
202 return map_nt_error_from_unix_common(errno
);
206 sock
->state
= SOCKET_STATE_SERVER_LISTEN
;
211 static NTSTATUS
ipv4_accept(struct socket_context
*sock
, struct socket_context
**new_sock
)
213 struct sockaddr_in cli_addr
;
214 socklen_t cli_addr_len
= sizeof(cli_addr
);
217 if (sock
->type
!= SOCKET_TYPE_STREAM
) {
218 return NT_STATUS_INVALID_PARAMETER
;
221 new_fd
= accept(sock
->fd
, (struct sockaddr
*)&cli_addr
, &cli_addr_len
);
223 return map_nt_error_from_unix_common(errno
);
226 if (!(sock
->flags
& SOCKET_FLAG_BLOCK
)) {
227 int ret
= set_blocking(new_fd
, false);
230 return map_nt_error_from_unix_common(errno
);
234 /* TODO: we could add a 'accept_check' hook here
235 * which get the black/white lists via socket_set_accept_filter()
236 * or something like that
240 (*new_sock
) = talloc(NULL
, struct socket_context
);
243 return NT_STATUS_NO_MEMORY
;
246 /* copy the socket_context */
247 (*new_sock
)->type
= sock
->type
;
248 (*new_sock
)->state
= SOCKET_STATE_SERVER_CONNECTED
;
249 (*new_sock
)->flags
= sock
->flags
;
251 (*new_sock
)->fd
= new_fd
;
253 (*new_sock
)->private_data
= NULL
;
254 (*new_sock
)->ops
= sock
->ops
;
255 (*new_sock
)->backend_name
= sock
->backend_name
;
260 static NTSTATUS
ip_recv(struct socket_context
*sock
, void *buf
,
261 size_t wantlen
, size_t *nread
)
267 gotlen
= recv(sock
->fd
, buf
, wantlen
, 0);
269 return NT_STATUS_END_OF_FILE
;
270 } else if (gotlen
== -1) {
271 return map_nt_error_from_unix_common(errno
);
280 static NTSTATUS
ipv4_recvfrom(struct socket_context
*sock
, void *buf
,
281 size_t wantlen
, size_t *nread
,
282 TALLOC_CTX
*addr_ctx
, struct socket_address
**_src
)
285 struct sockaddr_in
*from_addr
;
286 socklen_t from_len
= sizeof(*from_addr
);
287 struct socket_address
*src
;
288 char addrstring
[INET_ADDRSTRLEN
];
290 src
= talloc(addr_ctx
, struct socket_address
);
292 return NT_STATUS_NO_MEMORY
;
295 src
->family
= sock
->backend_name
;
297 from_addr
= talloc(src
, struct sockaddr_in
);
300 return NT_STATUS_NO_MEMORY
;
303 src
->sockaddr
= (struct sockaddr
*)from_addr
;
307 gotlen
= recvfrom(sock
->fd
, buf
, wantlen
, 0,
308 src
->sockaddr
, &from_len
);
311 return NT_STATUS_END_OF_FILE
;
312 } else if (gotlen
== -1) {
314 return map_nt_error_from_unix_common(errno
);
317 src
->sockaddrlen
= from_len
;
319 if (inet_ntop(AF_INET
, &from_addr
->sin_addr
, addrstring
,
320 sizeof(addrstring
)) == NULL
) {
322 return NT_STATUS_INTERNAL_ERROR
;
324 src
->addr
= talloc_strdup(src
, addrstring
);
325 if (src
->addr
== NULL
) {
327 return NT_STATUS_NO_MEMORY
;
329 src
->port
= ntohs(from_addr
->sin_port
);
336 static NTSTATUS
ip_send(struct socket_context
*sock
,
337 const DATA_BLOB
*blob
, size_t *sendlen
)
343 len
= send(sock
->fd
, blob
->data
, blob
->length
, 0);
345 return map_nt_error_from_unix_common(errno
);
353 static NTSTATUS
ipv4_sendto(struct socket_context
*sock
,
354 const DATA_BLOB
*blob
, size_t *sendlen
,
355 const struct socket_address
*dest_addr
)
359 if (dest_addr
->sockaddr
) {
360 len
= sendto(sock
->fd
, blob
->data
, blob
->length
, 0,
361 dest_addr
->sockaddr
, dest_addr
->sockaddrlen
);
363 struct sockaddr_in srv_addr
;
366 SMB_ASSERT(dest_addr
->port
!= 0);
368 ZERO_STRUCT(srv_addr
);
369 #ifdef HAVE_SOCK_SIN_LEN
370 srv_addr
.sin_len
= sizeof(srv_addr
);
372 addr
= interpret_addr2(dest_addr
->addr
);
373 if (addr
.s_addr
== 0) {
374 return NT_STATUS_HOST_UNREACHABLE
;
376 srv_addr
.sin_addr
.s_addr
= addr
.s_addr
;
377 srv_addr
.sin_port
= htons(dest_addr
->port
);
378 srv_addr
.sin_family
= PF_INET
;
382 len
= sendto(sock
->fd
, blob
->data
, blob
->length
, 0,
383 (struct sockaddr
*)&srv_addr
, sizeof(srv_addr
));
386 return map_nt_error_from_unix_common(errno
);
394 static NTSTATUS
ipv4_set_option(struct socket_context
*sock
, const char *option
, const char *val
)
396 set_socket_options(sock
->fd
, option
);
400 static char *ipv4_get_peer_name(struct socket_context
*sock
, TALLOC_CTX
*mem_ctx
)
402 struct sockaddr_in peer_addr
;
403 socklen_t len
= sizeof(peer_addr
);
407 ret
= getpeername(sock
->fd
, (struct sockaddr
*)&peer_addr
, &len
);
412 he
= gethostbyaddr((char *)&peer_addr
.sin_addr
, sizeof(peer_addr
.sin_addr
), AF_INET
);
417 return talloc_strdup(mem_ctx
, he
->h_name
);
420 static struct socket_address
*ipv4_get_peer_addr(struct socket_context
*sock
, TALLOC_CTX
*mem_ctx
)
422 struct sockaddr_in
*peer_addr
;
423 socklen_t len
= sizeof(*peer_addr
);
424 struct socket_address
*peer
;
425 char addrstring
[INET_ADDRSTRLEN
];
428 peer
= talloc(mem_ctx
, struct socket_address
);
433 peer
->family
= sock
->backend_name
;
434 peer_addr
= talloc(peer
, struct sockaddr_in
);
440 peer
->sockaddr
= (struct sockaddr
*)peer_addr
;
442 ret
= getpeername(sock
->fd
, peer
->sockaddr
, &len
);
448 peer
->sockaddrlen
= len
;
450 if (inet_ntop(AF_INET
, &peer_addr
->sin_addr
, addrstring
,
451 sizeof(addrstring
)) == NULL
) {
455 peer
->addr
= talloc_strdup(peer
, addrstring
);
460 peer
->port
= ntohs(peer_addr
->sin_port
);
465 static struct socket_address
*ipv4_get_my_addr(struct socket_context
*sock
, TALLOC_CTX
*mem_ctx
)
467 struct sockaddr_in
*local_addr
;
468 socklen_t len
= sizeof(*local_addr
);
469 struct socket_address
*local
;
470 char addrstring
[INET_ADDRSTRLEN
];
473 local
= talloc(mem_ctx
, struct socket_address
);
478 local
->family
= sock
->backend_name
;
479 local_addr
= talloc(local
, struct sockaddr_in
);
485 local
->sockaddr
= (struct sockaddr
*)local_addr
;
487 ret
= getsockname(sock
->fd
, local
->sockaddr
, &len
);
493 local
->sockaddrlen
= len
;
495 if (inet_ntop(AF_INET
, &local_addr
->sin_addr
, addrstring
,
496 sizeof(addrstring
)) == NULL
) {
500 local
->addr
= talloc_strdup(local
, addrstring
);
505 local
->port
= ntohs(local_addr
->sin_port
);
509 static int ip_get_fd(struct socket_context
*sock
)
514 static NTSTATUS
ip_pending(struct socket_context
*sock
, size_t *npending
)
517 if (ioctl(sock
->fd
, FIONREAD
, &value
) == 0) {
521 return map_nt_error_from_unix_common(errno
);
524 static const struct socket_ops ipv4_ops
= {
526 .fn_init
= ipv4_init
,
527 .fn_connect
= ipv4_connect
,
528 .fn_connect_complete
= ip_connect_complete
,
529 .fn_listen
= ipv4_listen
,
530 .fn_accept
= ipv4_accept
,
532 .fn_recvfrom
= ipv4_recvfrom
,
534 .fn_sendto
= ipv4_sendto
,
535 .fn_pending
= ip_pending
,
536 .fn_close
= ip_close
,
538 .fn_set_option
= ipv4_set_option
,
540 .fn_get_peer_name
= ipv4_get_peer_name
,
541 .fn_get_peer_addr
= ipv4_get_peer_addr
,
542 .fn_get_my_addr
= ipv4_get_my_addr
,
544 .fn_get_fd
= ip_get_fd
547 _PUBLIC_
const struct socket_ops
*socket_ipv4_ops(enum socket_type type
)
554 static struct in6_addr
interpret_addr6(const char *name
)
556 char addr
[INET6_ADDRSTRLEN
];
557 struct in6_addr dest6
;
558 const char *sp
= name
;
562 if (sp
== NULL
) return in6addr_any
;
564 p
= strchr_m(sp
, '%');
566 if (strcasecmp(sp
, "localhost") == 0) {
571 * Cope with link-local.
572 * This is IP:v6:addr%ifname.
575 if (p
&& (p
> sp
) && (if_nametoindex(p
+1) != 0)) {
577 MIN(PTR_DIFF(p
,sp
)+1,
582 ret
= inet_pton(AF_INET6
, sp
, &dest6
);
590 static NTSTATUS
ipv6_init(struct socket_context
*sock
)
594 switch (sock
->type
) {
595 case SOCKET_TYPE_STREAM
:
598 case SOCKET_TYPE_DGRAM
:
602 return NT_STATUS_INVALID_PARAMETER
;
605 sock
->fd
= socket(PF_INET6
, type
, 0);
606 if (sock
->fd
== -1) {
607 return map_nt_error_from_unix_common(errno
);
610 sock
->backend_name
= "ipv6";
611 sock
->family
= AF_INET6
;
616 static NTSTATUS
ipv6_tcp_connect(struct socket_context
*sock
,
617 const struct socket_address
*my_address
,
618 const struct socket_address
*srv_address
,
623 if (my_address
&& my_address
->sockaddr
) {
624 ret
= bind(sock
->fd
, my_address
->sockaddr
, my_address
->sockaddrlen
);
626 return map_nt_error_from_unix_common(errno
);
628 } else if (my_address
) {
629 struct in6_addr my_ip
;
630 my_ip
= interpret_addr6(my_address
->addr
);
632 if (memcmp(&my_ip
, &in6addr_any
, sizeof(my_ip
)) || my_address
->port
!= 0) {
633 struct sockaddr_in6 my_addr
;
634 ZERO_STRUCT(my_addr
);
635 my_addr
.sin6_addr
= my_ip
;
636 my_addr
.sin6_port
= htons(my_address
->port
);
637 my_addr
.sin6_family
= PF_INET6
;
639 ret
= bind(sock
->fd
, (struct sockaddr
*)&my_addr
, sizeof(my_addr
));
641 return map_nt_error_from_unix_common(errno
);
646 if (srv_address
->sockaddr
) {
647 ret
= connect(sock
->fd
, srv_address
->sockaddr
, srv_address
->sockaddrlen
);
649 struct in6_addr srv_ip
;
650 struct sockaddr_in6 srv_addr
;
651 srv_ip
= interpret_addr6(srv_address
->addr
);
652 if (memcmp(&srv_ip
, &in6addr_any
, sizeof(srv_ip
)) == 0) {
653 return NT_STATUS_BAD_NETWORK_NAME
;
656 ZERO_STRUCT(srv_addr
);
657 srv_addr
.sin6_addr
= srv_ip
;
658 srv_addr
.sin6_port
= htons(srv_address
->port
);
659 srv_addr
.sin6_family
= PF_INET6
;
661 ret
= connect(sock
->fd
, (const struct sockaddr
*)&srv_addr
, sizeof(srv_addr
));
664 return map_nt_error_from_unix_common(errno
);
667 return ip_connect_complete(sock
, flags
);
671 fix the sin6_scope_id based on the address interface
673 static void fix_scope_id(struct sockaddr_in6
*in6
,
676 const char *p
= strchr(address
, '%');
678 in6
->sin6_scope_id
= if_nametoindex(p
+1);
683 static NTSTATUS
ipv6_listen(struct socket_context
*sock
,
684 const struct socket_address
*my_address
,
685 int queue_size
, uint32_t flags
)
687 struct sockaddr_in6 my_addr
;
688 struct in6_addr ip_addr
;
691 socket_set_option(sock
, "SO_REUSEADDR=1", NULL
);
693 if (my_address
->sockaddr
) {
694 ret
= bind(sock
->fd
, my_address
->sockaddr
, my_address
->sockaddrlen
);
697 ip_addr
= interpret_addr6(my_address
->addr
);
699 ZERO_STRUCT(my_addr
);
700 my_addr
.sin6_addr
= ip_addr
;
701 my_addr
.sin6_port
= htons(my_address
->port
);
702 my_addr
.sin6_family
= PF_INET6
;
703 fix_scope_id(&my_addr
, my_address
->addr
);
705 /* when binding on ipv6 we always want to only bind on v6 */
706 ret
= setsockopt(sock
->fd
, IPPROTO_IPV6
, IPV6_V6ONLY
,
707 (const void *)&one
, sizeof(one
));
709 ret
= bind(sock
->fd
, (struct sockaddr
*)&my_addr
, sizeof(my_addr
));
714 return map_nt_error_from_unix_common(errno
);
717 if (sock
->type
== SOCKET_TYPE_STREAM
) {
718 ret
= listen(sock
->fd
, queue_size
);
720 return map_nt_error_from_unix_common(errno
);
724 if (!(flags
& SOCKET_FLAG_BLOCK
)) {
725 ret
= set_blocking(sock
->fd
, false);
727 return map_nt_error_from_unix_common(errno
);
731 sock
->state
= SOCKET_STATE_SERVER_LISTEN
;
736 static NTSTATUS
ipv6_tcp_accept(struct socket_context
*sock
, struct socket_context
**new_sock
)
738 struct sockaddr_in6 cli_addr
;
739 socklen_t cli_addr_len
= sizeof(cli_addr
);
742 if (sock
->type
!= SOCKET_TYPE_STREAM
) {
743 return NT_STATUS_INVALID_PARAMETER
;
746 new_fd
= accept(sock
->fd
, (struct sockaddr
*)&cli_addr
, &cli_addr_len
);
748 return map_nt_error_from_unix_common(errno
);
751 if (!(sock
->flags
& SOCKET_FLAG_BLOCK
)) {
752 int ret
= set_blocking(new_fd
, false);
755 return map_nt_error_from_unix_common(errno
);
759 /* TODO: we could add a 'accept_check' hook here
760 * which get the black/white lists via socket_set_accept_filter()
761 * or something like that
765 (*new_sock
) = talloc(NULL
, struct socket_context
);
768 return NT_STATUS_NO_MEMORY
;
771 /* copy the socket_context */
772 (*new_sock
)->type
= sock
->type
;
773 (*new_sock
)->state
= SOCKET_STATE_SERVER_CONNECTED
;
774 (*new_sock
)->flags
= sock
->flags
;
776 (*new_sock
)->fd
= new_fd
;
778 (*new_sock
)->private_data
= NULL
;
779 (*new_sock
)->ops
= sock
->ops
;
780 (*new_sock
)->backend_name
= sock
->backend_name
;
785 static NTSTATUS
ipv6_recvfrom(struct socket_context
*sock
, void *buf
,
786 size_t wantlen
, size_t *nread
,
787 TALLOC_CTX
*addr_ctx
, struct socket_address
**_src
)
790 struct sockaddr_in6
*from_addr
;
791 socklen_t from_len
= sizeof(*from_addr
);
792 struct socket_address
*src
;
793 char addrstring
[INET6_ADDRSTRLEN
];
795 src
= talloc(addr_ctx
, struct socket_address
);
797 return NT_STATUS_NO_MEMORY
;
800 src
->family
= sock
->backend_name
;
802 from_addr
= talloc(src
, struct sockaddr_in6
);
805 return NT_STATUS_NO_MEMORY
;
808 src
->sockaddr
= (struct sockaddr
*)from_addr
;
812 gotlen
= recvfrom(sock
->fd
, buf
, wantlen
, 0,
813 src
->sockaddr
, &from_len
);
816 return NT_STATUS_END_OF_FILE
;
817 } else if (gotlen
== -1) {
819 return map_nt_error_from_unix_common(errno
);
822 src
->sockaddrlen
= from_len
;
824 if (inet_ntop(AF_INET6
, &from_addr
->sin6_addr
, addrstring
, sizeof(addrstring
)) == NULL
) {
825 DEBUG(0, ("Unable to convert address to string: %s\n", strerror(errno
)));
827 return NT_STATUS_INTERNAL_ERROR
;
830 src
->addr
= talloc_strdup(src
, addrstring
);
831 if (src
->addr
== NULL
) {
833 return NT_STATUS_NO_MEMORY
;
835 src
->port
= ntohs(from_addr
->sin6_port
);
842 static NTSTATUS
ipv6_sendto(struct socket_context
*sock
,
843 const DATA_BLOB
*blob
, size_t *sendlen
,
844 const struct socket_address
*dest_addr
)
848 if (dest_addr
->sockaddr
) {
849 len
= sendto(sock
->fd
, blob
->data
, blob
->length
, 0,
850 dest_addr
->sockaddr
, dest_addr
->sockaddrlen
);
852 struct sockaddr_in6 srv_addr
;
853 struct in6_addr addr
;
855 ZERO_STRUCT(srv_addr
);
856 addr
= interpret_addr6(dest_addr
->addr
);
857 if (addr
.s6_addr
== 0) {
858 return NT_STATUS_HOST_UNREACHABLE
;
860 srv_addr
.sin6_addr
= addr
;
861 srv_addr
.sin6_port
= htons(dest_addr
->port
);
862 srv_addr
.sin6_family
= PF_INET6
;
866 len
= sendto(sock
->fd
, blob
->data
, blob
->length
, 0,
867 (struct sockaddr
*)&srv_addr
, sizeof(srv_addr
));
870 return map_nt_error_from_unix_common(errno
);
878 static NTSTATUS
ipv6_set_option(struct socket_context
*sock
, const char *option
, const char *val
)
880 set_socket_options(sock
->fd
, option
);
884 static char *ipv6_tcp_get_peer_name(struct socket_context
*sock
, TALLOC_CTX
*mem_ctx
)
886 struct sockaddr_in6 peer_addr
;
887 socklen_t len
= sizeof(peer_addr
);
891 ret
= getpeername(sock
->fd
, (struct sockaddr
*)&peer_addr
, &len
);
896 he
= gethostbyaddr((char *)&peer_addr
.sin6_addr
, sizeof(peer_addr
.sin6_addr
), AF_INET6
);
901 return talloc_strdup(mem_ctx
, he
->h_name
);
904 static struct socket_address
*ipv6_tcp_get_peer_addr(struct socket_context
*sock
, TALLOC_CTX
*mem_ctx
)
906 struct sockaddr_in6
*peer_addr
;
907 socklen_t len
= sizeof(*peer_addr
);
908 struct socket_address
*peer
;
911 const char *addr_ret
;
913 peer
= talloc(mem_ctx
, struct socket_address
);
918 peer
->family
= sock
->backend_name
;
919 peer_addr
= talloc(peer
, struct sockaddr_in6
);
925 peer
->sockaddr
= (struct sockaddr
*)peer_addr
;
927 ret
= getpeername(sock
->fd
, peer
->sockaddr
, &len
);
933 peer
->sockaddrlen
= len
;
935 addr_ret
= inet_ntop(AF_INET6
, &peer_addr
->sin6_addr
, addr
, sizeof(addr
));
936 if (addr_ret
== NULL
) {
941 peer
->addr
= talloc_strdup(peer
, addr_ret
);
942 if (peer
->addr
== NULL
) {
947 peer
->port
= ntohs(peer_addr
->sin6_port
);
952 static struct socket_address
*ipv6_tcp_get_my_addr(struct socket_context
*sock
, TALLOC_CTX
*mem_ctx
)
954 struct sockaddr_in6
*local_addr
;
955 socklen_t len
= sizeof(*local_addr
);
956 struct socket_address
*local
;
958 char addrstring
[INET6_ADDRSTRLEN
];
960 local
= talloc(mem_ctx
, struct socket_address
);
965 local
->family
= sock
->backend_name
;
966 local_addr
= talloc(local
, struct sockaddr_in6
);
972 local
->sockaddr
= (struct sockaddr
*)local_addr
;
974 ret
= getsockname(sock
->fd
, local
->sockaddr
, &len
);
980 local
->sockaddrlen
= len
;
982 if (inet_ntop(AF_INET6
, &local_addr
->sin6_addr
, addrstring
,
983 sizeof(addrstring
)) == NULL
) {
984 DEBUG(0, ("Unable to convert address to string: %s\n",
990 local
->addr
= talloc_strdup(mem_ctx
, addrstring
);
995 local
->port
= ntohs(local_addr
->sin6_port
);
1000 static const struct socket_ops ipv6_tcp_ops
= {
1002 .fn_init
= ipv6_init
,
1003 .fn_connect
= ipv6_tcp_connect
,
1004 .fn_connect_complete
= ip_connect_complete
,
1005 .fn_listen
= ipv6_listen
,
1006 .fn_accept
= ipv6_tcp_accept
,
1008 .fn_recvfrom
= ipv6_recvfrom
,
1010 .fn_sendto
= ipv6_sendto
,
1011 .fn_pending
= ip_pending
,
1012 .fn_close
= ip_close
,
1014 .fn_set_option
= ipv6_set_option
,
1016 .fn_get_peer_name
= ipv6_tcp_get_peer_name
,
1017 .fn_get_peer_addr
= ipv6_tcp_get_peer_addr
,
1018 .fn_get_my_addr
= ipv6_tcp_get_my_addr
,
1020 .fn_get_fd
= ip_get_fd
1023 _PUBLIC_
const struct socket_ops
*socket_ipv6_ops(enum socket_type type
)
1025 return &ipv6_tcp_ops
;