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 smb_set_close_on_exec(sock
->fd
);
55 sock
->backend_name
= "ipv4";
56 sock
->family
= AF_INET
;
61 static void ip_close(struct socket_context
*sock
)
69 static NTSTATUS
ip_connect_complete(struct socket_context
*sock
, uint32_t flags
)
72 socklen_t len
= sizeof(error
);
74 /* check for any errors that may have occurred - this is needed
75 for non-blocking connect */
76 ret
= getsockopt(sock
->fd
, SOL_SOCKET
, SO_ERROR
, &error
, &len
);
78 return map_nt_error_from_unix_common(errno
);
81 return map_nt_error_from_unix_common(error
);
84 if (!(flags
& SOCKET_FLAG_BLOCK
)) {
85 ret
= set_blocking(sock
->fd
, false);
87 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 if (!(flags
& SOCKET_FLAG_BLOCK
)) {
205 ret
= set_blocking(sock
->fd
, false);
207 return map_nt_error_from_unix_common(errno
);
211 sock
->state
= SOCKET_STATE_SERVER_LISTEN
;
216 static NTSTATUS
ipv4_accept(struct socket_context
*sock
, struct socket_context
**new_sock
)
218 struct sockaddr_in cli_addr
;
219 socklen_t cli_addr_len
= sizeof(cli_addr
);
222 if (sock
->type
!= SOCKET_TYPE_STREAM
) {
223 return NT_STATUS_INVALID_PARAMETER
;
226 new_fd
= accept(sock
->fd
, (struct sockaddr
*)&cli_addr
, &cli_addr_len
);
228 return map_nt_error_from_unix_common(errno
);
231 if (!(sock
->flags
& SOCKET_FLAG_BLOCK
)) {
232 int ret
= set_blocking(new_fd
, false);
235 return map_nt_error_from_unix_common(errno
);
238 smb_set_close_on_exec(new_fd
);
241 /* TODO: we could add a 'accept_check' hook here
242 * which get the black/white lists via socket_set_accept_filter()
243 * or something like that
247 (*new_sock
) = talloc(NULL
, struct socket_context
);
250 return NT_STATUS_NO_MEMORY
;
253 /* copy the socket_context */
254 (*new_sock
)->type
= sock
->type
;
255 (*new_sock
)->state
= SOCKET_STATE_SERVER_CONNECTED
;
256 (*new_sock
)->flags
= sock
->flags
;
258 (*new_sock
)->fd
= new_fd
;
260 (*new_sock
)->private_data
= NULL
;
261 (*new_sock
)->ops
= sock
->ops
;
262 (*new_sock
)->backend_name
= sock
->backend_name
;
267 static NTSTATUS
ip_recv(struct socket_context
*sock
, void *buf
,
268 size_t wantlen
, size_t *nread
)
274 gotlen
= recv(sock
->fd
, buf
, wantlen
, 0);
276 return NT_STATUS_END_OF_FILE
;
277 } else if (gotlen
== -1) {
278 return map_nt_error_from_unix_common(errno
);
287 static NTSTATUS
ipv4_recvfrom(struct socket_context
*sock
, void *buf
,
288 size_t wantlen
, size_t *nread
,
289 TALLOC_CTX
*addr_ctx
, struct socket_address
**_src
)
292 struct sockaddr_in
*from_addr
;
293 socklen_t from_len
= sizeof(*from_addr
);
294 struct socket_address
*src
;
295 char addrstring
[INET_ADDRSTRLEN
];
297 src
= talloc(addr_ctx
, struct socket_address
);
299 return NT_STATUS_NO_MEMORY
;
302 src
->family
= sock
->backend_name
;
304 from_addr
= talloc(src
, struct sockaddr_in
);
307 return NT_STATUS_NO_MEMORY
;
310 src
->sockaddr
= (struct sockaddr
*)from_addr
;
314 gotlen
= recvfrom(sock
->fd
, buf
, wantlen
, 0,
315 src
->sockaddr
, &from_len
);
318 return NT_STATUS_END_OF_FILE
;
322 return map_nt_error_from_unix_common(errno
);
325 src
->sockaddrlen
= from_len
;
327 if (inet_ntop(AF_INET
, &from_addr
->sin_addr
, addrstring
,
328 sizeof(addrstring
)) == NULL
) {
330 return NT_STATUS_INTERNAL_ERROR
;
332 src
->addr
= talloc_strdup(src
, addrstring
);
333 if (src
->addr
== NULL
) {
335 return NT_STATUS_NO_MEMORY
;
337 src
->port
= ntohs(from_addr
->sin_port
);
344 static NTSTATUS
ip_send(struct socket_context
*sock
,
345 const DATA_BLOB
*blob
, size_t *sendlen
)
351 len
= send(sock
->fd
, blob
->data
, blob
->length
, 0);
353 return map_nt_error_from_unix_common(errno
);
361 static NTSTATUS
ipv4_sendto(struct socket_context
*sock
,
362 const DATA_BLOB
*blob
, size_t *sendlen
,
363 const struct socket_address
*dest_addr
)
367 if (dest_addr
->sockaddr
) {
368 len
= sendto(sock
->fd
, blob
->data
, blob
->length
, 0,
369 dest_addr
->sockaddr
, dest_addr
->sockaddrlen
);
371 struct sockaddr_in srv_addr
;
374 SMB_ASSERT(dest_addr
->port
!= 0);
376 ZERO_STRUCT(srv_addr
);
377 #ifdef HAVE_SOCK_SIN_LEN
378 srv_addr
.sin_len
= sizeof(srv_addr
);
380 addr
= interpret_addr2(dest_addr
->addr
);
381 if (addr
.s_addr
== 0) {
382 return NT_STATUS_HOST_UNREACHABLE
;
384 srv_addr
.sin_addr
.s_addr
= addr
.s_addr
;
385 srv_addr
.sin_port
= htons(dest_addr
->port
);
386 srv_addr
.sin_family
= PF_INET
;
390 len
= sendto(sock
->fd
, blob
->data
, blob
->length
, 0,
391 (struct sockaddr
*)&srv_addr
, sizeof(srv_addr
));
394 return map_nt_error_from_unix_common(errno
);
402 static NTSTATUS
ipv4_set_option(struct socket_context
*sock
, const char *option
, const char *val
)
404 set_socket_options(sock
->fd
, option
);
408 static char *ipv4_get_peer_name(struct socket_context
*sock
, TALLOC_CTX
*mem_ctx
)
410 struct sockaddr_in peer_addr
;
411 socklen_t len
= sizeof(peer_addr
);
415 ret
= getpeername(sock
->fd
, (struct sockaddr
*)&peer_addr
, &len
);
420 he
= gethostbyaddr((char *)&peer_addr
.sin_addr
, sizeof(peer_addr
.sin_addr
), AF_INET
);
425 return talloc_strdup(mem_ctx
, he
->h_name
);
428 static struct socket_address
*ipv4_get_peer_addr(struct socket_context
*sock
, TALLOC_CTX
*mem_ctx
)
430 struct sockaddr_in
*peer_addr
;
431 socklen_t len
= sizeof(*peer_addr
);
432 struct socket_address
*peer
;
433 char addrstring
[INET_ADDRSTRLEN
];
436 peer
= talloc(mem_ctx
, struct socket_address
);
441 peer
->family
= sock
->backend_name
;
442 peer_addr
= talloc(peer
, struct sockaddr_in
);
448 peer
->sockaddr
= (struct sockaddr
*)peer_addr
;
450 ret
= getpeername(sock
->fd
, peer
->sockaddr
, &len
);
456 peer
->sockaddrlen
= len
;
458 if (inet_ntop(AF_INET
, &peer_addr
->sin_addr
, addrstring
,
459 sizeof(addrstring
)) == NULL
) {
463 peer
->addr
= talloc_strdup(peer
, addrstring
);
468 peer
->port
= ntohs(peer_addr
->sin_port
);
473 static struct socket_address
*ipv4_get_my_addr(struct socket_context
*sock
, TALLOC_CTX
*mem_ctx
)
475 struct sockaddr_in
*local_addr
;
476 socklen_t len
= sizeof(*local_addr
);
477 struct socket_address
*local
;
478 char addrstring
[INET_ADDRSTRLEN
];
481 local
= talloc(mem_ctx
, struct socket_address
);
486 local
->family
= sock
->backend_name
;
487 local_addr
= talloc(local
, struct sockaddr_in
);
493 local
->sockaddr
= (struct sockaddr
*)local_addr
;
495 ret
= getsockname(sock
->fd
, local
->sockaddr
, &len
);
501 local
->sockaddrlen
= len
;
503 if (inet_ntop(AF_INET
, &local_addr
->sin_addr
, addrstring
,
504 sizeof(addrstring
)) == NULL
) {
508 local
->addr
= talloc_strdup(local
, addrstring
);
513 local
->port
= ntohs(local_addr
->sin_port
);
517 static int ip_get_fd(struct socket_context
*sock
)
522 static NTSTATUS
ip_pending(struct socket_context
*sock
, size_t *npending
)
525 if (ioctl(sock
->fd
, FIONREAD
, &value
) == 0) {
529 return map_nt_error_from_unix_common(errno
);
532 static const struct socket_ops ipv4_ops
= {
534 .fn_init
= ipv4_init
,
535 .fn_connect
= ipv4_connect
,
536 .fn_connect_complete
= ip_connect_complete
,
537 .fn_listen
= ipv4_listen
,
538 .fn_accept
= ipv4_accept
,
540 .fn_recvfrom
= ipv4_recvfrom
,
542 .fn_sendto
= ipv4_sendto
,
543 .fn_pending
= ip_pending
,
544 .fn_close
= ip_close
,
546 .fn_set_option
= ipv4_set_option
,
548 .fn_get_peer_name
= ipv4_get_peer_name
,
549 .fn_get_peer_addr
= ipv4_get_peer_addr
,
550 .fn_get_my_addr
= ipv4_get_my_addr
,
552 .fn_get_fd
= ip_get_fd
555 _PUBLIC_
const struct socket_ops
*socket_ipv4_ops(enum socket_type type
)
562 static struct in6_addr
interpret_addr6(const char *name
)
564 char addr
[INET6_ADDRSTRLEN
];
565 struct in6_addr dest6
;
566 const char *sp
= name
;
570 if (sp
== NULL
) return in6addr_any
;
572 p
= strchr_m(sp
, '%');
574 if (strcasecmp(sp
, "localhost") == 0) {
579 * Cope with link-local.
580 * This is IP:v6:addr%ifname.
583 if (p
&& (p
> sp
) && (if_nametoindex(p
+1) != 0)) {
585 MIN(PTR_DIFF(p
,sp
)+1,
590 ret
= inet_pton(AF_INET6
, sp
, &dest6
);
598 static NTSTATUS
ipv6_init(struct socket_context
*sock
)
602 switch (sock
->type
) {
603 case SOCKET_TYPE_STREAM
:
606 case SOCKET_TYPE_DGRAM
:
610 return NT_STATUS_INVALID_PARAMETER
;
613 sock
->fd
= socket(PF_INET6
, type
, 0);
614 if (sock
->fd
== -1) {
615 return map_nt_error_from_unix_common(errno
);
618 smb_set_close_on_exec(sock
->fd
);
620 sock
->backend_name
= "ipv6";
621 sock
->family
= AF_INET6
;
626 static NTSTATUS
ipv6_tcp_connect(struct socket_context
*sock
,
627 const struct socket_address
*my_address
,
628 const struct socket_address
*srv_address
,
633 if (my_address
&& my_address
->sockaddr
) {
634 ret
= bind(sock
->fd
, my_address
->sockaddr
, my_address
->sockaddrlen
);
636 return map_nt_error_from_unix_common(errno
);
638 } else if (my_address
) {
639 struct in6_addr my_ip
;
640 my_ip
= interpret_addr6(my_address
->addr
);
642 if (memcmp(&my_ip
, &in6addr_any
, sizeof(my_ip
)) || my_address
->port
!= 0) {
643 struct sockaddr_in6 my_addr
;
644 ZERO_STRUCT(my_addr
);
645 my_addr
.sin6_addr
= my_ip
;
646 my_addr
.sin6_port
= htons(my_address
->port
);
647 my_addr
.sin6_family
= PF_INET6
;
649 ret
= bind(sock
->fd
, (struct sockaddr
*)&my_addr
, sizeof(my_addr
));
651 return map_nt_error_from_unix_common(errno
);
656 if (srv_address
->sockaddr
) {
657 ret
= connect(sock
->fd
, srv_address
->sockaddr
, srv_address
->sockaddrlen
);
659 struct in6_addr srv_ip
;
660 struct sockaddr_in6 srv_addr
;
661 srv_ip
= interpret_addr6(srv_address
->addr
);
662 if (memcmp(&srv_ip
, &in6addr_any
, sizeof(srv_ip
)) == 0) {
663 return NT_STATUS_BAD_NETWORK_NAME
;
666 ZERO_STRUCT(srv_addr
);
667 srv_addr
.sin6_addr
= srv_ip
;
668 srv_addr
.sin6_port
= htons(srv_address
->port
);
669 srv_addr
.sin6_family
= PF_INET6
;
671 ret
= connect(sock
->fd
, (const struct sockaddr
*)&srv_addr
, sizeof(srv_addr
));
674 return map_nt_error_from_unix_common(errno
);
677 return ip_connect_complete(sock
, flags
);
681 fix the sin6_scope_id based on the address interface
683 static void fix_scope_id(struct sockaddr_in6
*in6
,
686 const char *p
= strchr(address
, '%');
688 in6
->sin6_scope_id
= if_nametoindex(p
+1);
693 static NTSTATUS
ipv6_listen(struct socket_context
*sock
,
694 const struct socket_address
*my_address
,
695 int queue_size
, uint32_t flags
)
697 struct sockaddr_in6 my_addr
;
698 struct in6_addr ip_addr
;
701 socket_set_option(sock
, "SO_REUSEADDR=1", NULL
);
703 if (my_address
->sockaddr
) {
704 ret
= bind(sock
->fd
, my_address
->sockaddr
, my_address
->sockaddrlen
);
707 ip_addr
= interpret_addr6(my_address
->addr
);
709 ZERO_STRUCT(my_addr
);
710 my_addr
.sin6_addr
= ip_addr
;
711 my_addr
.sin6_port
= htons(my_address
->port
);
712 my_addr
.sin6_family
= PF_INET6
;
713 fix_scope_id(&my_addr
, my_address
->addr
);
715 /* when binding on ipv6 we always want to only bind on v6 */
716 ret
= setsockopt(sock
->fd
, IPPROTO_IPV6
, IPV6_V6ONLY
,
717 (const void *)&one
, sizeof(one
));
719 ret
= bind(sock
->fd
, (struct sockaddr
*)&my_addr
, sizeof(my_addr
));
724 return map_nt_error_from_unix_common(errno
);
727 if (sock
->type
== SOCKET_TYPE_STREAM
) {
728 ret
= listen(sock
->fd
, queue_size
);
730 return map_nt_error_from_unix_common(errno
);
734 if (!(flags
& SOCKET_FLAG_BLOCK
)) {
735 ret
= set_blocking(sock
->fd
, false);
737 return map_nt_error_from_unix_common(errno
);
741 sock
->state
= SOCKET_STATE_SERVER_LISTEN
;
746 static NTSTATUS
ipv6_tcp_accept(struct socket_context
*sock
, struct socket_context
**new_sock
)
748 struct sockaddr_in6 cli_addr
;
749 socklen_t cli_addr_len
= sizeof(cli_addr
);
752 if (sock
->type
!= SOCKET_TYPE_STREAM
) {
753 return NT_STATUS_INVALID_PARAMETER
;
756 new_fd
= accept(sock
->fd
, (struct sockaddr
*)&cli_addr
, &cli_addr_len
);
758 return map_nt_error_from_unix_common(errno
);
761 if (!(sock
->flags
& SOCKET_FLAG_BLOCK
)) {
762 int ret
= set_blocking(new_fd
, false);
765 return map_nt_error_from_unix_common(errno
);
768 smb_set_close_on_exec(new_fd
);
770 /* TODO: we could add a 'accept_check' hook here
771 * which get the black/white lists via socket_set_accept_filter()
772 * or something like that
776 (*new_sock
) = talloc(NULL
, struct socket_context
);
779 return NT_STATUS_NO_MEMORY
;
782 /* copy the socket_context */
783 (*new_sock
)->type
= sock
->type
;
784 (*new_sock
)->state
= SOCKET_STATE_SERVER_CONNECTED
;
785 (*new_sock
)->flags
= sock
->flags
;
787 (*new_sock
)->fd
= new_fd
;
789 (*new_sock
)->private_data
= NULL
;
790 (*new_sock
)->ops
= sock
->ops
;
791 (*new_sock
)->backend_name
= sock
->backend_name
;
796 static NTSTATUS
ipv6_recvfrom(struct socket_context
*sock
, void *buf
,
797 size_t wantlen
, size_t *nread
,
798 TALLOC_CTX
*addr_ctx
, struct socket_address
**_src
)
801 struct sockaddr_in6
*from_addr
;
802 socklen_t from_len
= sizeof(*from_addr
);
803 struct socket_address
*src
;
804 char addrstring
[INET6_ADDRSTRLEN
];
806 src
= talloc(addr_ctx
, struct socket_address
);
808 return NT_STATUS_NO_MEMORY
;
811 src
->family
= sock
->backend_name
;
813 from_addr
= talloc(src
, struct sockaddr_in6
);
816 return NT_STATUS_NO_MEMORY
;
819 src
->sockaddr
= (struct sockaddr
*)from_addr
;
823 gotlen
= recvfrom(sock
->fd
, buf
, wantlen
, 0,
824 src
->sockaddr
, &from_len
);
827 return NT_STATUS_END_OF_FILE
;
828 } else if (gotlen
== -1) {
830 return map_nt_error_from_unix_common(errno
);
833 src
->sockaddrlen
= from_len
;
835 if (inet_ntop(AF_INET6
, &from_addr
->sin6_addr
, addrstring
, sizeof(addrstring
)) == NULL
) {
836 DEBUG(0, ("Unable to convert address to string: %s\n", strerror(errno
)));
838 return NT_STATUS_INTERNAL_ERROR
;
841 src
->addr
= talloc_strdup(src
, addrstring
);
842 if (src
->addr
== NULL
) {
844 return NT_STATUS_NO_MEMORY
;
846 src
->port
= ntohs(from_addr
->sin6_port
);
853 static NTSTATUS
ipv6_sendto(struct socket_context
*sock
,
854 const DATA_BLOB
*blob
, size_t *sendlen
,
855 const struct socket_address
*dest_addr
)
859 if (dest_addr
->sockaddr
) {
860 len
= sendto(sock
->fd
, blob
->data
, blob
->length
, 0,
861 dest_addr
->sockaddr
, dest_addr
->sockaddrlen
);
863 struct sockaddr_in6 srv_addr
;
864 struct in6_addr addr
;
866 ZERO_STRUCT(srv_addr
);
867 addr
= interpret_addr6(dest_addr
->addr
);
868 if (memcmp(&addr
.s6_addr
, &in6addr_any
,
869 sizeof(addr
.s6_addr
)) == 0) {
870 return NT_STATUS_HOST_UNREACHABLE
;
872 srv_addr
.sin6_addr
= addr
;
873 srv_addr
.sin6_port
= htons(dest_addr
->port
);
874 srv_addr
.sin6_family
= PF_INET6
;
878 len
= sendto(sock
->fd
, blob
->data
, blob
->length
, 0,
879 (struct sockaddr
*)&srv_addr
, sizeof(srv_addr
));
882 return map_nt_error_from_unix_common(errno
);
890 static NTSTATUS
ipv6_set_option(struct socket_context
*sock
, const char *option
, const char *val
)
892 set_socket_options(sock
->fd
, option
);
896 static char *ipv6_tcp_get_peer_name(struct socket_context
*sock
, TALLOC_CTX
*mem_ctx
)
898 struct sockaddr_in6 peer_addr
;
899 socklen_t len
= sizeof(peer_addr
);
903 ret
= getpeername(sock
->fd
, (struct sockaddr
*)&peer_addr
, &len
);
908 he
= gethostbyaddr((char *)&peer_addr
.sin6_addr
, sizeof(peer_addr
.sin6_addr
), AF_INET6
);
913 return talloc_strdup(mem_ctx
, he
->h_name
);
916 static struct socket_address
*ipv6_tcp_get_peer_addr(struct socket_context
*sock
, TALLOC_CTX
*mem_ctx
)
918 struct sockaddr_in6
*peer_addr
;
919 socklen_t len
= sizeof(*peer_addr
);
920 struct socket_address
*peer
;
923 const char *addr_ret
;
925 peer
= talloc(mem_ctx
, struct socket_address
);
930 peer
->family
= sock
->backend_name
;
931 peer_addr
= talloc(peer
, struct sockaddr_in6
);
937 peer
->sockaddr
= (struct sockaddr
*)peer_addr
;
939 ret
= getpeername(sock
->fd
, peer
->sockaddr
, &len
);
945 peer
->sockaddrlen
= len
;
947 addr_ret
= inet_ntop(AF_INET6
, &peer_addr
->sin6_addr
, addr
, sizeof(addr
));
948 if (addr_ret
== NULL
) {
953 peer
->addr
= talloc_strdup(peer
, addr_ret
);
954 if (peer
->addr
== NULL
) {
959 peer
->port
= ntohs(peer_addr
->sin6_port
);
964 static struct socket_address
*ipv6_tcp_get_my_addr(struct socket_context
*sock
, TALLOC_CTX
*mem_ctx
)
966 struct sockaddr_in6
*local_addr
;
967 socklen_t len
= sizeof(*local_addr
);
968 struct socket_address
*local
;
970 char addrstring
[INET6_ADDRSTRLEN
];
972 local
= talloc(mem_ctx
, struct socket_address
);
977 local
->family
= sock
->backend_name
;
978 local_addr
= talloc(local
, struct sockaddr_in6
);
984 local
->sockaddr
= (struct sockaddr
*)local_addr
;
986 ret
= getsockname(sock
->fd
, local
->sockaddr
, &len
);
992 local
->sockaddrlen
= len
;
994 if (inet_ntop(AF_INET6
, &local_addr
->sin6_addr
, addrstring
,
995 sizeof(addrstring
)) == NULL
) {
996 DEBUG(0, ("Unable to convert address to string: %s\n",
1002 local
->addr
= talloc_strdup(mem_ctx
, addrstring
);
1007 local
->port
= ntohs(local_addr
->sin6_port
);
1012 static const struct socket_ops ipv6_tcp_ops
= {
1014 .fn_init
= ipv6_init
,
1015 .fn_connect
= ipv6_tcp_connect
,
1016 .fn_connect_complete
= ip_connect_complete
,
1017 .fn_listen
= ipv6_listen
,
1018 .fn_accept
= ipv6_tcp_accept
,
1020 .fn_recvfrom
= ipv6_recvfrom
,
1022 .fn_sendto
= ipv6_sendto
,
1023 .fn_pending
= ip_pending
,
1024 .fn_close
= ip_close
,
1026 .fn_set_option
= ipv6_set_option
,
1028 .fn_get_peer_name
= ipv6_tcp_get_peer_name
,
1029 .fn_get_peer_addr
= ipv6_tcp_get_peer_addr
,
1030 .fn_get_my_addr
= ipv6_tcp_get_my_addr
,
1032 .fn_get_fd
= ip_get_fd
1035 _PUBLIC_
const struct socket_ops
*socket_ipv6_ops(enum socket_type type
)
1037 return &ipv6_tcp_ops
;