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
)
67 static NTSTATUS
ip_connect_complete(struct socket_context
*sock
, uint32_t flags
)
70 socklen_t len
= sizeof(error
);
72 /* check for any errors that may have occurred - this is needed
73 for non-blocking connect */
74 ret
= getsockopt(sock
->fd
, SOL_SOCKET
, SO_ERROR
, &error
, &len
);
76 return map_nt_error_from_unix_common(errno
);
79 return map_nt_error_from_unix_common(error
);
82 if (!(flags
& SOCKET_FLAG_BLOCK
)) {
83 ret
= set_blocking(sock
->fd
, false);
85 return map_nt_error_from_unix_common(errno
);
89 sock
->state
= SOCKET_STATE_CLIENT_CONNECTED
;
95 static NTSTATUS
ipv4_connect(struct socket_context
*sock
,
96 const struct socket_address
*my_address
,
97 const struct socket_address
*srv_address
,
100 struct sockaddr_in srv_addr
;
101 struct in_addr my_ip
;
102 struct in_addr srv_ip
;
105 if (my_address
&& my_address
->sockaddr
) {
106 ret
= bind(sock
->fd
, my_address
->sockaddr
, my_address
->sockaddrlen
);
108 return map_nt_error_from_unix_common(errno
);
110 } else if (my_address
) {
111 my_ip
= interpret_addr2(my_address
->addr
);
113 if (my_ip
.s_addr
!= 0 || my_address
->port
!= 0) {
114 struct sockaddr_in my_addr
;
115 ZERO_STRUCT(my_addr
);
116 #ifdef HAVE_SOCK_SIN_LEN
117 my_addr
.sin_len
= sizeof(my_addr
);
119 my_addr
.sin_addr
.s_addr
= my_ip
.s_addr
;
120 my_addr
.sin_port
= htons(my_address
->port
);
121 my_addr
.sin_family
= PF_INET
;
123 ret
= bind(sock
->fd
, (struct sockaddr
*)&my_addr
, sizeof(my_addr
));
125 return map_nt_error_from_unix_common(errno
);
130 if (srv_address
->sockaddr
) {
131 ret
= connect(sock
->fd
, srv_address
->sockaddr
, srv_address
->sockaddrlen
);
133 return map_nt_error_from_unix_common(errno
);
136 srv_ip
= interpret_addr2(srv_address
->addr
);
137 if (!srv_ip
.s_addr
) {
138 return NT_STATUS_BAD_NETWORK_NAME
;
141 SMB_ASSERT(srv_address
->port
!= 0);
143 ZERO_STRUCT(srv_addr
);
144 #ifdef HAVE_SOCK_SIN_LEN
145 srv_addr
.sin_len
= sizeof(srv_addr
);
147 srv_addr
.sin_addr
.s_addr
= srv_ip
.s_addr
;
148 srv_addr
.sin_port
= htons(srv_address
->port
);
149 srv_addr
.sin_family
= PF_INET
;
151 ret
= connect(sock
->fd
, (const struct sockaddr
*)&srv_addr
, sizeof(srv_addr
));
153 return map_nt_error_from_unix_common(errno
);
157 return ip_connect_complete(sock
, flags
);
162 note that for simplicity of the API, socket_listen() is also
163 use for DGRAM sockets, but in reality only a bind() is done
165 static NTSTATUS
ipv4_listen(struct socket_context
*sock
,
166 const struct socket_address
*my_address
,
167 int queue_size
, uint32_t flags
)
169 struct sockaddr_in my_addr
;
170 struct in_addr ip_addr
;
173 socket_set_option(sock
, "SO_REUSEADDR=1", NULL
);
175 if (my_address
->sockaddr
) {
176 ret
= bind(sock
->fd
, my_address
->sockaddr
, my_address
->sockaddrlen
);
178 ip_addr
= interpret_addr2(my_address
->addr
);
180 ZERO_STRUCT(my_addr
);
181 #ifdef HAVE_SOCK_SIN_LEN
182 my_addr
.sin_len
= sizeof(my_addr
);
184 my_addr
.sin_addr
.s_addr
= ip_addr
.s_addr
;
185 my_addr
.sin_port
= htons(my_address
->port
);
186 my_addr
.sin_family
= PF_INET
;
188 ret
= bind(sock
->fd
, (struct sockaddr
*)&my_addr
, sizeof(my_addr
));
192 return map_nt_error_from_unix_common(errno
);
195 if (sock
->type
== SOCKET_TYPE_STREAM
) {
196 ret
= listen(sock
->fd
, queue_size
);
198 return map_nt_error_from_unix_common(errno
);
202 if (!(flags
& SOCKET_FLAG_BLOCK
)) {
203 ret
= set_blocking(sock
->fd
, false);
205 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 if (!(sock
->flags
& SOCKET_FLAG_BLOCK
)) {
230 int ret
= set_blocking(new_fd
, false);
233 return map_nt_error_from_unix_common(errno
);
237 /* TODO: we could add a 'accept_check' hook here
238 * which get the black/white lists via socket_set_accept_filter()
239 * or something like that
243 (*new_sock
) = talloc(NULL
, struct socket_context
);
246 return NT_STATUS_NO_MEMORY
;
249 /* copy the socket_context */
250 (*new_sock
)->type
= sock
->type
;
251 (*new_sock
)->state
= SOCKET_STATE_SERVER_CONNECTED
;
252 (*new_sock
)->flags
= sock
->flags
;
254 (*new_sock
)->fd
= new_fd
;
256 (*new_sock
)->private_data
= NULL
;
257 (*new_sock
)->ops
= sock
->ops
;
258 (*new_sock
)->backend_name
= sock
->backend_name
;
263 static NTSTATUS
ip_recv(struct socket_context
*sock
, void *buf
,
264 size_t wantlen
, size_t *nread
)
270 gotlen
= recv(sock
->fd
, buf
, wantlen
, 0);
272 return NT_STATUS_END_OF_FILE
;
273 } else if (gotlen
== -1) {
274 return map_nt_error_from_unix_common(errno
);
283 static NTSTATUS
ipv4_recvfrom(struct socket_context
*sock
, void *buf
,
284 size_t wantlen
, size_t *nread
,
285 TALLOC_CTX
*addr_ctx
, struct socket_address
**_src
)
288 struct sockaddr_in
*from_addr
;
289 socklen_t from_len
= sizeof(*from_addr
);
290 struct socket_address
*src
;
291 char addrstring
[INET_ADDRSTRLEN
];
293 src
= talloc(addr_ctx
, struct socket_address
);
295 return NT_STATUS_NO_MEMORY
;
298 src
->family
= sock
->backend_name
;
300 from_addr
= talloc(src
, struct sockaddr_in
);
303 return NT_STATUS_NO_MEMORY
;
306 src
->sockaddr
= (struct sockaddr
*)from_addr
;
310 gotlen
= recvfrom(sock
->fd
, buf
, wantlen
, 0,
311 src
->sockaddr
, &from_len
);
314 return NT_STATUS_END_OF_FILE
;
315 } else if (gotlen
== -1) {
317 return map_nt_error_from_unix_common(errno
);
320 src
->sockaddrlen
= from_len
;
322 if (inet_ntop(AF_INET
, &from_addr
->sin_addr
, addrstring
,
323 sizeof(addrstring
)) == NULL
) {
325 return NT_STATUS_INTERNAL_ERROR
;
327 src
->addr
= talloc_strdup(src
, addrstring
);
328 if (src
->addr
== NULL
) {
330 return NT_STATUS_NO_MEMORY
;
332 src
->port
= ntohs(from_addr
->sin_port
);
339 static NTSTATUS
ip_send(struct socket_context
*sock
,
340 const DATA_BLOB
*blob
, size_t *sendlen
)
346 len
= send(sock
->fd
, blob
->data
, blob
->length
, 0);
348 return map_nt_error_from_unix_common(errno
);
356 static NTSTATUS
ipv4_sendto(struct socket_context
*sock
,
357 const DATA_BLOB
*blob
, size_t *sendlen
,
358 const struct socket_address
*dest_addr
)
362 if (dest_addr
->sockaddr
) {
363 len
= sendto(sock
->fd
, blob
->data
, blob
->length
, 0,
364 dest_addr
->sockaddr
, dest_addr
->sockaddrlen
);
366 struct sockaddr_in srv_addr
;
369 SMB_ASSERT(dest_addr
->port
!= 0);
371 ZERO_STRUCT(srv_addr
);
372 #ifdef HAVE_SOCK_SIN_LEN
373 srv_addr
.sin_len
= sizeof(srv_addr
);
375 addr
= interpret_addr2(dest_addr
->addr
);
376 if (addr
.s_addr
== 0) {
377 return NT_STATUS_HOST_UNREACHABLE
;
379 srv_addr
.sin_addr
.s_addr
= addr
.s_addr
;
380 srv_addr
.sin_port
= htons(dest_addr
->port
);
381 srv_addr
.sin_family
= PF_INET
;
385 len
= sendto(sock
->fd
, blob
->data
, blob
->length
, 0,
386 (struct sockaddr
*)&srv_addr
, sizeof(srv_addr
));
389 return map_nt_error_from_unix_common(errno
);
397 static NTSTATUS
ipv4_set_option(struct socket_context
*sock
, const char *option
, const char *val
)
399 set_socket_options(sock
->fd
, option
);
403 static char *ipv4_get_peer_name(struct socket_context
*sock
, TALLOC_CTX
*mem_ctx
)
405 struct sockaddr_in peer_addr
;
406 socklen_t len
= sizeof(peer_addr
);
410 ret
= getpeername(sock
->fd
, (struct sockaddr
*)&peer_addr
, &len
);
415 he
= gethostbyaddr((char *)&peer_addr
.sin_addr
, sizeof(peer_addr
.sin_addr
), AF_INET
);
420 return talloc_strdup(mem_ctx
, he
->h_name
);
423 static struct socket_address
*ipv4_get_peer_addr(struct socket_context
*sock
, TALLOC_CTX
*mem_ctx
)
425 struct sockaddr_in
*peer_addr
;
426 socklen_t len
= sizeof(*peer_addr
);
427 struct socket_address
*peer
;
428 char addrstring
[INET_ADDRSTRLEN
];
431 peer
= talloc(mem_ctx
, struct socket_address
);
436 peer
->family
= sock
->backend_name
;
437 peer_addr
= talloc(peer
, struct sockaddr_in
);
443 peer
->sockaddr
= (struct sockaddr
*)peer_addr
;
445 ret
= getpeername(sock
->fd
, peer
->sockaddr
, &len
);
451 peer
->sockaddrlen
= len
;
453 if (inet_ntop(AF_INET
, &peer_addr
->sin_addr
, addrstring
,
454 sizeof(addrstring
)) == NULL
) {
458 peer
->addr
= talloc_strdup(peer
, addrstring
);
463 peer
->port
= ntohs(peer_addr
->sin_port
);
468 static struct socket_address
*ipv4_get_my_addr(struct socket_context
*sock
, TALLOC_CTX
*mem_ctx
)
470 struct sockaddr_in
*local_addr
;
471 socklen_t len
= sizeof(*local_addr
);
472 struct socket_address
*local
;
473 char addrstring
[INET_ADDRSTRLEN
];
476 local
= talloc(mem_ctx
, struct socket_address
);
481 local
->family
= sock
->backend_name
;
482 local_addr
= talloc(local
, struct sockaddr_in
);
488 local
->sockaddr
= (struct sockaddr
*)local_addr
;
490 ret
= getsockname(sock
->fd
, local
->sockaddr
, &len
);
496 local
->sockaddrlen
= len
;
498 if (inet_ntop(AF_INET
, &local_addr
->sin_addr
, addrstring
,
499 sizeof(addrstring
)) == NULL
) {
503 local
->addr
= talloc_strdup(local
, addrstring
);
508 local
->port
= ntohs(local_addr
->sin_port
);
512 static int ip_get_fd(struct socket_context
*sock
)
517 static NTSTATUS
ip_pending(struct socket_context
*sock
, size_t *npending
)
520 if (ioctl(sock
->fd
, FIONREAD
, &value
) == 0) {
524 return map_nt_error_from_unix_common(errno
);
527 static const struct socket_ops ipv4_ops
= {
529 .fn_init
= ipv4_init
,
530 .fn_connect
= ipv4_connect
,
531 .fn_connect_complete
= ip_connect_complete
,
532 .fn_listen
= ipv4_listen
,
533 .fn_accept
= ipv4_accept
,
535 .fn_recvfrom
= ipv4_recvfrom
,
537 .fn_sendto
= ipv4_sendto
,
538 .fn_pending
= ip_pending
,
539 .fn_close
= ip_close
,
541 .fn_set_option
= ipv4_set_option
,
543 .fn_get_peer_name
= ipv4_get_peer_name
,
544 .fn_get_peer_addr
= ipv4_get_peer_addr
,
545 .fn_get_my_addr
= ipv4_get_my_addr
,
547 .fn_get_fd
= ip_get_fd
550 _PUBLIC_
const struct socket_ops
*socket_ipv4_ops(enum socket_type type
)
557 static struct in6_addr
interpret_addr6(const char *name
)
559 char addr
[INET6_ADDRSTRLEN
];
560 struct in6_addr dest6
;
561 const char *sp
= name
;
565 if (sp
== NULL
) return in6addr_any
;
567 p
= strchr_m(sp
, '%');
569 if (strcasecmp(sp
, "localhost") == 0) {
574 * Cope with link-local.
575 * This is IP:v6:addr%ifname.
578 if (p
&& (p
> sp
) && (if_nametoindex(p
+1) != 0)) {
580 MIN(PTR_DIFF(p
,sp
)+1,
585 ret
= inet_pton(AF_INET6
, sp
, &dest6
);
593 static NTSTATUS
ipv6_init(struct socket_context
*sock
)
597 switch (sock
->type
) {
598 case SOCKET_TYPE_STREAM
:
601 case SOCKET_TYPE_DGRAM
:
605 return NT_STATUS_INVALID_PARAMETER
;
608 sock
->fd
= socket(PF_INET6
, type
, 0);
609 if (sock
->fd
== -1) {
610 return map_nt_error_from_unix_common(errno
);
613 sock
->backend_name
= "ipv6";
614 sock
->family
= AF_INET6
;
619 static NTSTATUS
ipv6_tcp_connect(struct socket_context
*sock
,
620 const struct socket_address
*my_address
,
621 const struct socket_address
*srv_address
,
626 if (my_address
&& my_address
->sockaddr
) {
627 ret
= bind(sock
->fd
, my_address
->sockaddr
, my_address
->sockaddrlen
);
629 return map_nt_error_from_unix_common(errno
);
631 } else if (my_address
) {
632 struct in6_addr my_ip
;
633 my_ip
= interpret_addr6(my_address
->addr
);
635 if (memcmp(&my_ip
, &in6addr_any
, sizeof(my_ip
)) || my_address
->port
!= 0) {
636 struct sockaddr_in6 my_addr
;
637 ZERO_STRUCT(my_addr
);
638 my_addr
.sin6_addr
= my_ip
;
639 my_addr
.sin6_port
= htons(my_address
->port
);
640 my_addr
.sin6_family
= PF_INET6
;
642 ret
= bind(sock
->fd
, (struct sockaddr
*)&my_addr
, sizeof(my_addr
));
644 return map_nt_error_from_unix_common(errno
);
649 if (srv_address
->sockaddr
) {
650 ret
= connect(sock
->fd
, srv_address
->sockaddr
, srv_address
->sockaddrlen
);
652 struct in6_addr srv_ip
;
653 struct sockaddr_in6 srv_addr
;
654 srv_ip
= interpret_addr6(srv_address
->addr
);
655 if (memcmp(&srv_ip
, &in6addr_any
, sizeof(srv_ip
)) == 0) {
656 return NT_STATUS_BAD_NETWORK_NAME
;
659 ZERO_STRUCT(srv_addr
);
660 srv_addr
.sin6_addr
= srv_ip
;
661 srv_addr
.sin6_port
= htons(srv_address
->port
);
662 srv_addr
.sin6_family
= PF_INET6
;
664 ret
= connect(sock
->fd
, (const struct sockaddr
*)&srv_addr
, sizeof(srv_addr
));
667 return map_nt_error_from_unix_common(errno
);
670 return ip_connect_complete(sock
, flags
);
674 fix the sin6_scope_id based on the address interface
676 static void fix_scope_id(struct sockaddr_in6
*in6
,
679 const char *p
= strchr(address
, '%');
681 in6
->sin6_scope_id
= if_nametoindex(p
+1);
686 static NTSTATUS
ipv6_listen(struct socket_context
*sock
,
687 const struct socket_address
*my_address
,
688 int queue_size
, uint32_t flags
)
690 struct sockaddr_in6 my_addr
;
691 struct in6_addr ip_addr
;
694 socket_set_option(sock
, "SO_REUSEADDR=1", NULL
);
696 if (my_address
->sockaddr
) {
697 ret
= bind(sock
->fd
, my_address
->sockaddr
, my_address
->sockaddrlen
);
700 ip_addr
= interpret_addr6(my_address
->addr
);
702 ZERO_STRUCT(my_addr
);
703 my_addr
.sin6_addr
= ip_addr
;
704 my_addr
.sin6_port
= htons(my_address
->port
);
705 my_addr
.sin6_family
= PF_INET6
;
706 fix_scope_id(&my_addr
, my_address
->addr
);
708 /* when binding on ipv6 we always want to only bind on v6 */
709 ret
= setsockopt(sock
->fd
, IPPROTO_IPV6
, IPV6_V6ONLY
,
710 (const void *)&one
, sizeof(one
));
712 ret
= bind(sock
->fd
, (struct sockaddr
*)&my_addr
, sizeof(my_addr
));
717 return map_nt_error_from_unix_common(errno
);
720 if (sock
->type
== SOCKET_TYPE_STREAM
) {
721 ret
= listen(sock
->fd
, queue_size
);
723 return map_nt_error_from_unix_common(errno
);
727 if (!(flags
& SOCKET_FLAG_BLOCK
)) {
728 ret
= set_blocking(sock
->fd
, false);
730 return map_nt_error_from_unix_common(errno
);
734 sock
->state
= SOCKET_STATE_SERVER_LISTEN
;
739 static NTSTATUS
ipv6_tcp_accept(struct socket_context
*sock
, struct socket_context
**new_sock
)
741 struct sockaddr_in6 cli_addr
;
742 socklen_t cli_addr_len
= sizeof(cli_addr
);
745 if (sock
->type
!= SOCKET_TYPE_STREAM
) {
746 return NT_STATUS_INVALID_PARAMETER
;
749 new_fd
= accept(sock
->fd
, (struct sockaddr
*)&cli_addr
, &cli_addr_len
);
751 return map_nt_error_from_unix_common(errno
);
754 if (!(sock
->flags
& SOCKET_FLAG_BLOCK
)) {
755 int ret
= set_blocking(new_fd
, false);
758 return map_nt_error_from_unix_common(errno
);
762 /* TODO: we could add a 'accept_check' hook here
763 * which get the black/white lists via socket_set_accept_filter()
764 * or something like that
768 (*new_sock
) = talloc(NULL
, struct socket_context
);
771 return NT_STATUS_NO_MEMORY
;
774 /* copy the socket_context */
775 (*new_sock
)->type
= sock
->type
;
776 (*new_sock
)->state
= SOCKET_STATE_SERVER_CONNECTED
;
777 (*new_sock
)->flags
= sock
->flags
;
779 (*new_sock
)->fd
= new_fd
;
781 (*new_sock
)->private_data
= NULL
;
782 (*new_sock
)->ops
= sock
->ops
;
783 (*new_sock
)->backend_name
= sock
->backend_name
;
788 static NTSTATUS
ipv6_recvfrom(struct socket_context
*sock
, void *buf
,
789 size_t wantlen
, size_t *nread
,
790 TALLOC_CTX
*addr_ctx
, struct socket_address
**_src
)
793 struct sockaddr_in6
*from_addr
;
794 socklen_t from_len
= sizeof(*from_addr
);
795 struct socket_address
*src
;
796 char addrstring
[INET6_ADDRSTRLEN
];
798 src
= talloc(addr_ctx
, struct socket_address
);
800 return NT_STATUS_NO_MEMORY
;
803 src
->family
= sock
->backend_name
;
805 from_addr
= talloc(src
, struct sockaddr_in6
);
808 return NT_STATUS_NO_MEMORY
;
811 src
->sockaddr
= (struct sockaddr
*)from_addr
;
815 gotlen
= recvfrom(sock
->fd
, buf
, wantlen
, 0,
816 src
->sockaddr
, &from_len
);
819 return NT_STATUS_END_OF_FILE
;
820 } else if (gotlen
== -1) {
822 return map_nt_error_from_unix_common(errno
);
825 src
->sockaddrlen
= from_len
;
827 if (inet_ntop(AF_INET6
, &from_addr
->sin6_addr
, addrstring
, sizeof(addrstring
)) == NULL
) {
828 DEBUG(0, ("Unable to convert address to string: %s\n", strerror(errno
)));
830 return NT_STATUS_INTERNAL_ERROR
;
833 src
->addr
= talloc_strdup(src
, addrstring
);
834 if (src
->addr
== NULL
) {
836 return NT_STATUS_NO_MEMORY
;
838 src
->port
= ntohs(from_addr
->sin6_port
);
845 static NTSTATUS
ipv6_sendto(struct socket_context
*sock
,
846 const DATA_BLOB
*blob
, size_t *sendlen
,
847 const struct socket_address
*dest_addr
)
851 if (dest_addr
->sockaddr
) {
852 len
= sendto(sock
->fd
, blob
->data
, blob
->length
, 0,
853 dest_addr
->sockaddr
, dest_addr
->sockaddrlen
);
855 struct sockaddr_in6 srv_addr
;
856 struct in6_addr addr
;
858 ZERO_STRUCT(srv_addr
);
859 addr
= interpret_addr6(dest_addr
->addr
);
860 if (addr
.s6_addr
== 0) {
861 return NT_STATUS_HOST_UNREACHABLE
;
863 srv_addr
.sin6_addr
= addr
;
864 srv_addr
.sin6_port
= htons(dest_addr
->port
);
865 srv_addr
.sin6_family
= PF_INET6
;
869 len
= sendto(sock
->fd
, blob
->data
, blob
->length
, 0,
870 (struct sockaddr
*)&srv_addr
, sizeof(srv_addr
));
873 return map_nt_error_from_unix_common(errno
);
881 static NTSTATUS
ipv6_set_option(struct socket_context
*sock
, const char *option
, const char *val
)
883 set_socket_options(sock
->fd
, option
);
887 static char *ipv6_tcp_get_peer_name(struct socket_context
*sock
, TALLOC_CTX
*mem_ctx
)
889 struct sockaddr_in6 peer_addr
;
890 socklen_t len
= sizeof(peer_addr
);
894 ret
= getpeername(sock
->fd
, (struct sockaddr
*)&peer_addr
, &len
);
899 he
= gethostbyaddr((char *)&peer_addr
.sin6_addr
, sizeof(peer_addr
.sin6_addr
), AF_INET6
);
904 return talloc_strdup(mem_ctx
, he
->h_name
);
907 static struct socket_address
*ipv6_tcp_get_peer_addr(struct socket_context
*sock
, TALLOC_CTX
*mem_ctx
)
909 struct sockaddr_in6
*peer_addr
;
910 socklen_t len
= sizeof(*peer_addr
);
911 struct socket_address
*peer
;
914 const char *addr_ret
;
916 peer
= talloc(mem_ctx
, struct socket_address
);
921 peer
->family
= sock
->backend_name
;
922 peer_addr
= talloc(peer
, struct sockaddr_in6
);
928 peer
->sockaddr
= (struct sockaddr
*)peer_addr
;
930 ret
= getpeername(sock
->fd
, peer
->sockaddr
, &len
);
936 peer
->sockaddrlen
= len
;
938 addr_ret
= inet_ntop(AF_INET6
, &peer_addr
->sin6_addr
, addr
, sizeof(addr
));
939 if (addr_ret
== NULL
) {
944 peer
->addr
= talloc_strdup(peer
, addr_ret
);
945 if (peer
->addr
== NULL
) {
950 peer
->port
= ntohs(peer_addr
->sin6_port
);
955 static struct socket_address
*ipv6_tcp_get_my_addr(struct socket_context
*sock
, TALLOC_CTX
*mem_ctx
)
957 struct sockaddr_in6
*local_addr
;
958 socklen_t len
= sizeof(*local_addr
);
959 struct socket_address
*local
;
961 char addrstring
[INET6_ADDRSTRLEN
];
963 local
= talloc(mem_ctx
, struct socket_address
);
968 local
->family
= sock
->backend_name
;
969 local_addr
= talloc(local
, struct sockaddr_in6
);
975 local
->sockaddr
= (struct sockaddr
*)local_addr
;
977 ret
= getsockname(sock
->fd
, local
->sockaddr
, &len
);
983 local
->sockaddrlen
= len
;
985 if (inet_ntop(AF_INET6
, &local_addr
->sin6_addr
, addrstring
,
986 sizeof(addrstring
)) == NULL
) {
987 DEBUG(0, ("Unable to convert address to string: %s\n",
993 local
->addr
= talloc_strdup(mem_ctx
, addrstring
);
998 local
->port
= ntohs(local_addr
->sin6_port
);
1003 static const struct socket_ops ipv6_tcp_ops
= {
1005 .fn_init
= ipv6_init
,
1006 .fn_connect
= ipv6_tcp_connect
,
1007 .fn_connect_complete
= ip_connect_complete
,
1008 .fn_listen
= ipv6_listen
,
1009 .fn_accept
= ipv6_tcp_accept
,
1011 .fn_recvfrom
= ipv6_recvfrom
,
1013 .fn_sendto
= ipv6_sendto
,
1014 .fn_pending
= ip_pending
,
1015 .fn_close
= ip_close
,
1017 .fn_set_option
= ipv6_set_option
,
1019 .fn_get_peer_name
= ipv6_tcp_get_peer_name
,
1020 .fn_get_peer_addr
= ipv6_tcp_get_peer_addr
,
1021 .fn_get_my_addr
= ipv6_tcp_get_my_addr
,
1023 .fn_get_fd
= ip_get_fd
1026 _PUBLIC_
const struct socket_ops
*socket_ipv6_ops(enum socket_type type
)
1028 return &ipv6_tcp_ops
;