Make more module init functions public, since they are compiled with -fvisibility...
[jelmer/samba4-debian.git] / source / lib / socket / socket_ip.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Socket IPv4/IPv6 functions
5
6    Copyright (C) Stefan Metzmacher 2004
7    Copyright (C) Andrew Tridgell 2004-2005
8    Copyright (C) Jelmer Vernooij 2004
9    
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.
14    
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.
19    
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/>.
22 */
23
24 #include "includes.h"
25 #include "system/filesys.h"
26 #include "lib/socket/socket.h"
27 #include "system/network.h"
28
29 static NTSTATUS ipv4_init(struct socket_context *sock)
30 {
31         int type;
32
33         switch (sock->type) {
34         case SOCKET_TYPE_STREAM:
35                 type = SOCK_STREAM;
36                 break;
37         case SOCKET_TYPE_DGRAM:
38                 type = SOCK_DGRAM;
39                 break;
40         default:
41                 return NT_STATUS_INVALID_PARAMETER;
42         }
43
44         sock->fd = socket(PF_INET, type, 0);
45         if (sock->fd == -1) {
46                 return map_nt_error_from_unix(errno);
47         }
48
49         sock->backend_name = "ipv4";
50         sock->family = AF_INET;
51
52         return NT_STATUS_OK;
53 }
54
55 static void ip_close(struct socket_context *sock)
56 {
57         close(sock->fd);
58 }
59
60 static NTSTATUS ip_connect_complete(struct socket_context *sock, uint32_t flags)
61 {
62         int error=0, ret;
63         socklen_t len = sizeof(error);
64
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);
68         if (ret == -1) {
69                 return map_nt_error_from_unix(errno);
70         }
71         if (error != 0) {
72                 return map_nt_error_from_unix(error);
73         }
74
75         if (!(flags & SOCKET_FLAG_BLOCK)) {
76                 ret = set_blocking(sock->fd, false);
77                 if (ret == -1) {
78                         return map_nt_error_from_unix(errno);
79                 }
80         }
81
82         sock->state = SOCKET_STATE_CLIENT_CONNECTED;
83
84         return NT_STATUS_OK;
85 }
86
87
88 static NTSTATUS ipv4_connect(struct socket_context *sock,
89                              const struct socket_address *my_address, 
90                              const struct socket_address *srv_address,
91                              uint32_t flags)
92 {
93         struct sockaddr_in srv_addr;
94         struct in_addr my_ip;
95         struct in_addr srv_ip;
96         int ret;
97
98         if (my_address && my_address->sockaddr) {
99                 ret = bind(sock->fd, my_address->sockaddr, my_address->sockaddrlen);
100                 if (ret == -1) {
101                         return map_nt_error_from_unix(errno);
102                 }
103         } else if (my_address) {
104                 my_ip = interpret_addr2(my_address->addr);
105                 
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);
111 #endif
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;
115                         
116                         ret = bind(sock->fd, (struct sockaddr *)&my_addr, sizeof(my_addr));
117                         if (ret == -1) {
118                                 return map_nt_error_from_unix(errno);
119                         }
120                 }
121         }
122
123         if (srv_address->sockaddr) {
124                 ret = connect(sock->fd, srv_address->sockaddr, srv_address->sockaddrlen);
125                 if (ret == -1) {
126                         return map_nt_error_from_unix(errno);
127                 }
128         } else {
129                 srv_ip = interpret_addr2(srv_address->addr);
130                 if (!srv_ip.s_addr) {
131                         return NT_STATUS_BAD_NETWORK_NAME;
132                 }
133
134                 SMB_ASSERT(srv_address->port != 0);
135                 
136                 ZERO_STRUCT(srv_addr);
137 #ifdef HAVE_SOCK_SIN_LEN
138                 srv_addr.sin_len        = sizeof(srv_addr);
139 #endif
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;
143
144                 ret = connect(sock->fd, (const struct sockaddr *)&srv_addr, sizeof(srv_addr));
145                 if (ret == -1) {
146                         return map_nt_error_from_unix(errno);
147                 }
148         }
149
150         return ip_connect_complete(sock, flags);
151 }
152
153
154 /*
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
157 */
158 static NTSTATUS ipv4_listen(struct socket_context *sock,
159                             const struct socket_address *my_address, 
160                             int queue_size, uint32_t flags)
161 {
162         struct sockaddr_in my_addr;
163         struct in_addr ip_addr;
164         int ret;
165
166         socket_set_option(sock, "SO_REUSEADDR=1", NULL);
167
168         if (my_address->sockaddr) {
169                 ret = bind(sock->fd, my_address->sockaddr, my_address->sockaddrlen);
170         } else {
171                 ip_addr = interpret_addr2(my_address->addr);
172                 
173                 ZERO_STRUCT(my_addr);
174 #ifdef HAVE_SOCK_SIN_LEN
175                 my_addr.sin_len         = sizeof(my_addr);
176 #endif
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;
180                 
181                 ret = bind(sock->fd, (struct sockaddr *)&my_addr, sizeof(my_addr));
182         }
183
184         if (ret == -1) {
185                 return map_nt_error_from_unix(errno);
186         }
187
188         if (sock->type == SOCKET_TYPE_STREAM) {
189                 ret = listen(sock->fd, queue_size);
190                 if (ret == -1) {
191                         return map_nt_error_from_unix(errno);
192                 }
193         }
194
195         if (!(flags & SOCKET_FLAG_BLOCK)) {
196                 ret = set_blocking(sock->fd, false);
197                 if (ret == -1) {
198                         return map_nt_error_from_unix(errno);
199                 }
200         }
201
202         sock->state= SOCKET_STATE_SERVER_LISTEN;
203
204         return NT_STATUS_OK;
205 }
206
207 static NTSTATUS ipv4_accept(struct socket_context *sock, struct socket_context **new_sock)
208 {
209         struct sockaddr_in cli_addr;
210         socklen_t cli_addr_len = sizeof(cli_addr);
211         int new_fd;
212
213         if (sock->type != SOCKET_TYPE_STREAM) {
214                 return NT_STATUS_INVALID_PARAMETER;
215         }
216
217         new_fd = accept(sock->fd, (struct sockaddr *)&cli_addr, &cli_addr_len);
218         if (new_fd == -1) {
219                 return map_nt_error_from_unix(errno);
220         }
221
222         if (!(sock->flags & SOCKET_FLAG_BLOCK)) {
223                 int ret = set_blocking(new_fd, false);
224                 if (ret == -1) {
225                         close(new_fd);
226                         return map_nt_error_from_unix(errno);
227                 }
228         }
229
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
233          *       --metze
234          */
235
236         (*new_sock) = talloc(NULL, struct socket_context);
237         if (!(*new_sock)) {
238                 close(new_fd);
239                 return NT_STATUS_NO_MEMORY;
240         }
241
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;
246
247         (*new_sock)->fd                 = new_fd;
248
249         (*new_sock)->private_data       = NULL;
250         (*new_sock)->ops                = sock->ops;
251         (*new_sock)->backend_name       = sock->backend_name;
252
253         return NT_STATUS_OK;
254 }
255
256 static NTSTATUS ip_recv(struct socket_context *sock, void *buf, 
257                               size_t wantlen, size_t *nread)
258 {
259         ssize_t gotlen;
260
261         *nread = 0;
262
263         gotlen = recv(sock->fd, buf, wantlen, 0);
264         if (gotlen == 0) {
265                 return NT_STATUS_END_OF_FILE;
266         } else if (gotlen == -1) {
267                 return map_nt_error_from_unix(errno);
268         }
269
270         *nread = gotlen;
271
272         return NT_STATUS_OK;
273 }
274
275
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)
279 {
280         ssize_t gotlen;
281         struct sockaddr_in *from_addr;
282         socklen_t from_len = sizeof(*from_addr);
283         struct socket_address *src;
284         char addrstring[INET_ADDRSTRLEN];
285         
286         src = talloc(addr_ctx, struct socket_address);
287         if (!src) {
288                 return NT_STATUS_NO_MEMORY;
289         }
290         
291         src->family = sock->backend_name;
292
293         from_addr = talloc(src, struct sockaddr_in);
294         if (!from_addr) {
295                 talloc_free(src);
296                 return NT_STATUS_NO_MEMORY;
297         }
298
299         src->sockaddr = (struct sockaddr *)from_addr;
300
301         *nread = 0;
302
303         gotlen = recvfrom(sock->fd, buf, wantlen, 0, 
304                           src->sockaddr, &from_len);
305         if (gotlen == 0) {
306                 talloc_free(src);
307                 return NT_STATUS_END_OF_FILE;
308         } else if (gotlen == -1) {
309                 talloc_free(src);
310                 return map_nt_error_from_unix(errno);
311         }
312
313         src->sockaddrlen = from_len;
314
315         if (inet_ntop(AF_INET, &from_addr->sin_addr, addrstring, 
316                          sizeof(addrstring)) == NULL) {
317                 talloc_free(src);
318                 return NT_STATUS_INTERNAL_ERROR;
319         }
320         src->addr = talloc_strdup(src, addrstring);
321         if (src->addr == NULL) {
322                 talloc_free(src);
323                 return NT_STATUS_NO_MEMORY;
324         }
325         src->port = ntohs(from_addr->sin_port);
326
327         *nread  = gotlen;
328         *_src   = src;
329         return NT_STATUS_OK;
330 }
331
332 static NTSTATUS ip_send(struct socket_context *sock, 
333                               const DATA_BLOB *blob, size_t *sendlen)
334 {
335         ssize_t len;
336
337         *sendlen = 0;
338
339         len = send(sock->fd, blob->data, blob->length, 0);
340         if (len == -1) {
341                 return map_nt_error_from_unix(errno);
342         }       
343
344         *sendlen = len;
345
346         return NT_STATUS_OK;
347 }
348
349 static NTSTATUS ipv4_sendto(struct socket_context *sock, 
350                             const DATA_BLOB *blob, size_t *sendlen, 
351                             const struct socket_address *dest_addr)
352 {
353         ssize_t len;
354
355         if (dest_addr->sockaddr) {
356                 len = sendto(sock->fd, blob->data, blob->length, 0, 
357                              dest_addr->sockaddr, dest_addr->sockaddrlen);
358         } else {
359                 struct sockaddr_in srv_addr;
360                 struct in_addr addr;
361
362                 SMB_ASSERT(dest_addr->port != 0);
363                 
364                 ZERO_STRUCT(srv_addr);
365 #ifdef HAVE_SOCK_SIN_LEN
366                 srv_addr.sin_len         = sizeof(srv_addr);
367 #endif
368                 addr                     = interpret_addr2(dest_addr->addr);
369                 if (addr.s_addr == 0) {
370                         return NT_STATUS_HOST_UNREACHABLE;
371                 }
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;
375                 
376                 *sendlen = 0;
377                 
378                 len = sendto(sock->fd, blob->data, blob->length, 0, 
379                              (struct sockaddr *)&srv_addr, sizeof(srv_addr));
380         }
381         if (len == -1) {
382                 return map_nt_error_from_unix(errno);
383         }       
384
385         *sendlen = len;
386
387         return NT_STATUS_OK;
388 }
389
390 static NTSTATUS ipv4_set_option(struct socket_context *sock, const char *option, const char *val)
391 {
392         set_socket_options(sock->fd, option);
393         return NT_STATUS_OK;
394 }
395
396 static char *ipv4_get_peer_name(struct socket_context *sock, TALLOC_CTX *mem_ctx)
397 {
398         struct sockaddr_in peer_addr;
399         socklen_t len = sizeof(peer_addr);
400         struct hostent *he;
401         int ret;
402
403         ret = getpeername(sock->fd, (struct sockaddr *)&peer_addr, &len);
404         if (ret == -1) {
405                 return NULL;
406         }
407
408         he = gethostbyaddr((char *)&peer_addr.sin_addr, sizeof(peer_addr.sin_addr), AF_INET);
409         if (he == NULL) {
410                 return NULL;
411         }
412
413         return talloc_strdup(mem_ctx, he->h_name);
414 }
415
416 static struct socket_address *ipv4_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
417 {
418         struct sockaddr_in *peer_addr;
419         socklen_t len = sizeof(*peer_addr);
420         struct socket_address *peer;
421         char addrstring[INET_ADDRSTRLEN];
422         int ret;
423         
424         peer = talloc(mem_ctx, struct socket_address);
425         if (!peer) {
426                 return NULL;
427         }
428         
429         peer->family = sock->backend_name;
430         peer_addr = talloc(peer, struct sockaddr_in);
431         if (!peer_addr) {
432                 talloc_free(peer);
433                 return NULL;
434         }
435
436         peer->sockaddr = (struct sockaddr *)peer_addr;
437
438         ret = getpeername(sock->fd, peer->sockaddr, &len);
439         if (ret == -1) {
440                 talloc_free(peer);
441                 return NULL;
442         }
443
444         peer->sockaddrlen = len;
445
446         if (inet_ntop(AF_INET, &peer_addr->sin_addr, addrstring,
447                          sizeof(addrstring)) == NULL) {
448                 talloc_free(peer);
449                 return NULL;
450         }
451         peer->addr = talloc_strdup(peer, addrstring);
452         if (!peer->addr) {
453                 talloc_free(peer);
454                 return NULL;
455         }
456         peer->port = ntohs(peer_addr->sin_port);
457
458         return peer;
459 }
460
461 static struct socket_address *ipv4_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
462 {
463         struct sockaddr_in *local_addr;
464         socklen_t len = sizeof(*local_addr);
465         struct socket_address *local;
466         char addrstring[INET_ADDRSTRLEN];
467         int ret;
468         
469         local = talloc(mem_ctx, struct socket_address);
470         if (!local) {
471                 return NULL;
472         }
473         
474         local->family = sock->backend_name;
475         local_addr = talloc(local, struct sockaddr_in);
476         if (!local_addr) {
477                 talloc_free(local);
478                 return NULL;
479         }
480
481         local->sockaddr = (struct sockaddr *)local_addr;
482
483         ret = getsockname(sock->fd, local->sockaddr, &len);
484         if (ret == -1) {
485                 talloc_free(local);
486                 return NULL;
487         }
488
489         local->sockaddrlen = len;
490
491         if (inet_ntop(AF_INET, &local_addr->sin_addr, addrstring, 
492                          sizeof(addrstring)) == NULL) {
493                 talloc_free(local);
494                 return NULL;
495         }
496         local->addr = talloc_strdup(local, addrstring);
497         if (!local->addr) {
498                 talloc_free(local);
499                 return NULL;
500         }
501         local->port = ntohs(local_addr->sin_port);
502
503         return local;
504 }
505 static int ip_get_fd(struct socket_context *sock)
506 {
507         return sock->fd;
508 }
509
510 static NTSTATUS ip_pending(struct socket_context *sock, size_t *npending)
511 {
512         int value = 0;
513         if (ioctl(sock->fd, FIONREAD, &value) == 0) {
514                 *npending = value;
515                 return NT_STATUS_OK;
516         }
517         return map_nt_error_from_unix(errno);
518 }
519
520 static const struct socket_ops ipv4_ops = {
521         .name                   = "ipv4",
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,
527         .fn_recv                = ip_recv,
528         .fn_recvfrom            = ipv4_recvfrom,
529         .fn_send                = ip_send,
530         .fn_sendto              = ipv4_sendto,
531         .fn_pending             = ip_pending,
532         .fn_close               = ip_close,
533
534         .fn_set_option          = ipv4_set_option,
535
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,
539
540         .fn_get_fd              = ip_get_fd
541 };
542
543 _PUBLIC_ const struct socket_ops *socket_ipv4_ops(enum socket_type type)
544 {
545         return &ipv4_ops;
546 }
547
548 #if HAVE_IPV6
549
550 static struct in6_addr interpret_addr6(const char *name)
551 {
552         struct hostent *he;
553         
554         if (name == NULL) return in6addr_any;
555
556         if (strcasecmp(name, "localhost") == 0) {
557                 name = "::1";
558         }
559
560         he = gethostbyname2(name, PF_INET6);
561
562         if (he == NULL) return in6addr_any;
563
564         return *((struct in6_addr *)he->h_addr);
565 }
566
567 static NTSTATUS ipv6_init(struct socket_context *sock)
568 {
569         int type;
570
571         switch (sock->type) {
572         case SOCKET_TYPE_STREAM:
573                 type = SOCK_STREAM;
574                 break;
575         case SOCKET_TYPE_DGRAM:
576                 type = SOCK_DGRAM;
577                 break;
578         default:
579                 return NT_STATUS_INVALID_PARAMETER;
580         }
581
582         sock->fd = socket(PF_INET6, type, 0);
583         if (sock->fd == -1) {
584                 return map_nt_error_from_unix(errno);
585         }
586
587         sock->backend_name = "ipv6";
588         sock->family = AF_INET6;
589
590         return NT_STATUS_OK;
591 }
592
593 static NTSTATUS ipv6_tcp_connect(struct socket_context *sock,
594                                  const struct socket_address *my_address,
595                                  const struct socket_address *srv_address,
596                                  uint32_t flags)
597 {
598         int ret;
599
600         if (my_address && my_address->sockaddr) {
601                 ret = bind(sock->fd, my_address->sockaddr, my_address->sockaddrlen);
602                 if (ret == -1) {
603                         return map_nt_error_from_unix(errno);
604                 }
605         } else if (my_address) {
606                 struct in6_addr my_ip;
607                 my_ip = interpret_addr6(my_address->addr);
608
609                 if (memcmp(&my_ip, &in6addr_any, sizeof(my_ip)) || my_address->port != 0) {
610                         struct sockaddr_in6 my_addr;
611                         ZERO_STRUCT(my_addr);
612                         my_addr.sin6_addr       = my_ip;
613                         my_addr.sin6_port       = htons(my_address->port);
614                         my_addr.sin6_family     = PF_INET6;
615                         
616                         ret = bind(sock->fd, (struct sockaddr *)&my_addr, sizeof(my_addr));
617                         if (ret == -1) {
618                                 return map_nt_error_from_unix(errno);
619                         }
620                 }
621         }
622
623         if (srv_address->sockaddr) {
624                 ret = connect(sock->fd, srv_address->sockaddr, srv_address->sockaddrlen);
625         } else {
626                 struct in6_addr srv_ip;
627                 struct sockaddr_in6 srv_addr;
628                 srv_ip = interpret_addr6(srv_address->addr);
629                 if (memcmp(&srv_ip, &in6addr_any, sizeof(srv_ip)) == 0) {
630                         return NT_STATUS_BAD_NETWORK_NAME;
631                 }
632                 
633                 ZERO_STRUCT(srv_addr);
634                 srv_addr.sin6_addr      = srv_ip;
635                 srv_addr.sin6_port      = htons(srv_address->port);
636                 srv_addr.sin6_family    = PF_INET6;
637                 
638                 ret = connect(sock->fd, (const struct sockaddr *)&srv_addr, sizeof(srv_addr));
639         }
640         if (ret == -1) {
641                 return map_nt_error_from_unix(errno);
642         }
643
644         return ip_connect_complete(sock, flags);
645 }
646
647 static NTSTATUS ipv6_listen(struct socket_context *sock,
648                                 const struct socket_address *my_address,
649                                 int queue_size, uint32_t flags)
650 {
651         struct sockaddr_in6 my_addr;
652         struct in6_addr ip_addr;
653         int ret;
654
655         socket_set_option(sock, "SO_REUSEADDR=1", NULL);
656
657         if (my_address->sockaddr) {
658                 ret = bind(sock->fd, my_address->sockaddr, my_address->sockaddrlen);
659         } else {
660                 ip_addr = interpret_addr6(my_address->addr);
661                 
662                 ZERO_STRUCT(my_addr);
663                 my_addr.sin6_addr       = ip_addr;
664                 my_addr.sin6_port       = htons(my_address->port);
665                 my_addr.sin6_family     = PF_INET6;
666                 
667                 ret = bind(sock->fd, (struct sockaddr *)&my_addr, sizeof(my_addr));
668         }
669
670         if (ret == -1) {
671                 return map_nt_error_from_unix(errno);
672         }
673
674         if (sock->type == SOCKET_TYPE_STREAM) {
675                 ret = listen(sock->fd, queue_size);
676                 if (ret == -1) {
677                         return map_nt_error_from_unix(errno);
678                 }
679         }
680
681         if (!(flags & SOCKET_FLAG_BLOCK)) {
682                 ret = set_blocking(sock->fd, false);
683                 if (ret == -1) {
684                         return map_nt_error_from_unix(errno);
685                 }
686         }
687
688         sock->state= SOCKET_STATE_SERVER_LISTEN;
689
690         return NT_STATUS_OK;
691 }
692
693 static NTSTATUS ipv6_tcp_accept(struct socket_context *sock, struct socket_context **new_sock)
694 {
695         struct sockaddr_in cli_addr;
696         socklen_t cli_addr_len = sizeof(cli_addr);
697         int new_fd;
698         
699         if (sock->type != SOCKET_TYPE_STREAM) {
700                 return NT_STATUS_INVALID_PARAMETER;
701         }
702
703         new_fd = accept(sock->fd, (struct sockaddr *)&cli_addr, &cli_addr_len);
704         if (new_fd == -1) {
705                 return map_nt_error_from_unix(errno);
706         }
707
708         if (!(sock->flags & SOCKET_FLAG_BLOCK)) {
709                 int ret = set_blocking(new_fd, false);
710                 if (ret == -1) {
711                         close(new_fd);
712                         return map_nt_error_from_unix(errno);
713                 }
714         }
715
716         /* TODO: we could add a 'accept_check' hook here
717          *       which get the black/white lists via socket_set_accept_filter()
718          *       or something like that
719          *       --metze
720          */
721
722         (*new_sock) = talloc(NULL, struct socket_context);
723         if (!(*new_sock)) {
724                 close(new_fd);
725                 return NT_STATUS_NO_MEMORY;
726         }
727
728         /* copy the socket_context */
729         (*new_sock)->type               = sock->type;
730         (*new_sock)->state              = SOCKET_STATE_SERVER_CONNECTED;
731         (*new_sock)->flags              = sock->flags;
732
733         (*new_sock)->fd                 = new_fd;
734
735         (*new_sock)->private_data       = NULL;
736         (*new_sock)->ops                = sock->ops;
737         (*new_sock)->backend_name       = sock->backend_name;
738
739         return NT_STATUS_OK;
740 }
741
742 static NTSTATUS ipv6_recvfrom(struct socket_context *sock, void *buf, 
743                               size_t wantlen, size_t *nread, 
744                               TALLOC_CTX *addr_ctx, struct socket_address **_src)
745 {
746         ssize_t gotlen;
747         struct sockaddr_in6 *from_addr;
748         socklen_t from_len = sizeof(*from_addr);
749         struct socket_address *src;
750         char addrstring[INET6_ADDRSTRLEN];
751         
752         src = talloc(addr_ctx, struct socket_address);
753         if (!src) {
754                 return NT_STATUS_NO_MEMORY;
755         }
756         
757         src->family = sock->backend_name;
758
759         from_addr = talloc(src, struct sockaddr_in6);
760         if (!from_addr) {
761                 talloc_free(src);
762                 return NT_STATUS_NO_MEMORY;
763         }
764
765         src->sockaddr = (struct sockaddr *)from_addr;
766
767         *nread = 0;
768
769         gotlen = recvfrom(sock->fd, buf, wantlen, 0, 
770                           src->sockaddr, &from_len);
771         if (gotlen == 0) {
772                 talloc_free(src);
773                 return NT_STATUS_END_OF_FILE;
774         } else if (gotlen == -1) {
775                 talloc_free(src);
776                 return map_nt_error_from_unix(errno);
777         }
778
779         src->sockaddrlen = from_len;
780
781         if (inet_ntop(AF_INET6, &from_addr->sin6_addr, addrstring, sizeof(addrstring)) == NULL) {
782                 DEBUG(0, ("Unable to convert address to string: %s\n", strerror(errno)));
783                 talloc_free(src);
784                 return NT_STATUS_INTERNAL_ERROR;
785         }
786
787         src->addr = talloc_strdup(src, addrstring);
788         if (src->addr == NULL) {
789                 talloc_free(src);
790                 return NT_STATUS_NO_MEMORY;
791         }
792         src->port = ntohs(from_addr->sin6_port);
793
794         *nread  = gotlen;
795         *_src   = src;
796         return NT_STATUS_OK;
797 }
798
799 static NTSTATUS ipv6_sendto(struct socket_context *sock, 
800                             const DATA_BLOB *blob, size_t *sendlen, 
801                             const struct socket_address *dest_addr)
802 {
803         ssize_t len;
804
805         if (dest_addr->sockaddr) {
806                 len = sendto(sock->fd, blob->data, blob->length, 0, 
807                              dest_addr->sockaddr, dest_addr->sockaddrlen);
808         } else {
809                 struct sockaddr_in6 srv_addr;
810                 struct in6_addr addr;
811                 
812                 ZERO_STRUCT(srv_addr);
813                 addr                     = interpret_addr6(dest_addr->addr);
814                 if (addr.s6_addr == 0) {
815                         return NT_STATUS_HOST_UNREACHABLE;
816                 }
817                 srv_addr.sin6_addr = addr;
818                 srv_addr.sin6_port        = htons(dest_addr->port);
819                 srv_addr.sin6_family      = PF_INET6;
820                 
821                 *sendlen = 0;
822                 
823                 len = sendto(sock->fd, blob->data, blob->length, 0, 
824                              (struct sockaddr *)&srv_addr, sizeof(srv_addr));
825         }
826         if (len == -1) {
827                 return map_nt_error_from_unix(errno);
828         }       
829
830         *sendlen = len;
831
832         return NT_STATUS_OK;
833 }
834
835 static NTSTATUS ipv6_set_option(struct socket_context *sock, const char *option, const char *val)
836 {
837         set_socket_options(sock->fd, option);
838         return NT_STATUS_OK;
839 }
840
841 static char *ipv6_tcp_get_peer_name(struct socket_context *sock, TALLOC_CTX *mem_ctx)
842 {
843         struct sockaddr_in6 peer_addr;
844         socklen_t len = sizeof(peer_addr);
845         struct hostent *he;
846         int ret;
847
848         ret = getpeername(sock->fd, (struct sockaddr *)&peer_addr, &len);
849         if (ret == -1) {
850                 return NULL;
851         }
852
853         he = gethostbyaddr((char *)&peer_addr.sin6_addr, sizeof(peer_addr.sin6_addr), AF_INET6);
854         if (he == NULL) {
855                 return NULL;
856         }
857
858         return talloc_strdup(mem_ctx, he->h_name);
859 }
860
861 static struct socket_address *ipv6_tcp_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
862 {
863         struct sockaddr_in6 *peer_addr;
864         socklen_t len = sizeof(*peer_addr);
865         struct socket_address *peer;
866         int ret;
867         char addr[128];
868         const char *addr_ret;
869         
870         peer = talloc(mem_ctx, struct socket_address);
871         if (!peer) {
872                 return NULL;
873         }
874         
875         peer->family = sock->backend_name;
876         peer_addr = talloc(peer, struct sockaddr_in6);
877         if (!peer_addr) {
878                 talloc_free(peer);
879                 return NULL;
880         }
881
882         peer->sockaddr = (struct sockaddr *)peer_addr;
883
884         ret = getpeername(sock->fd, peer->sockaddr, &len);
885         if (ret == -1) {
886                 talloc_free(peer);
887                 return NULL;
888         }
889
890         peer->sockaddrlen = len;
891
892         addr_ret = inet_ntop(AF_INET6, &peer_addr->sin6_addr, addr, sizeof(addr));
893         if (addr_ret == NULL) {
894                 talloc_free(peer);
895                 return NULL;
896         }
897
898         peer->addr = talloc_strdup(peer, addr_ret);
899         if (peer->addr == NULL) {
900                 talloc_free(peer);
901                 return NULL;
902         }
903
904         peer->port = ntohs(peer_addr->sin6_port);
905
906         return peer;
907 }
908
909 static struct socket_address *ipv6_tcp_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
910 {
911         struct sockaddr_in6 *local_addr;
912         socklen_t len = sizeof(*local_addr);
913         struct socket_address *local;
914         int ret;
915         char addrstring[INET6_ADDRSTRLEN];
916         
917         local = talloc(mem_ctx, struct socket_address);
918         if (!local) {
919                 return NULL;
920         }
921         
922         local->family = sock->backend_name;
923         local_addr = talloc(local, struct sockaddr_in6);
924         if (!local_addr) {
925                 talloc_free(local);
926                 return NULL;
927         }
928
929         local->sockaddr = (struct sockaddr *)local_addr;
930
931         ret = getsockname(sock->fd, local->sockaddr, &len);
932         if (ret == -1) {
933                 talloc_free(local);
934                 return NULL;
935         }
936
937         local->sockaddrlen = len;
938
939         if (inet_ntop(AF_INET6, &local_addr->sin6_addr, addrstring, 
940                        sizeof(addrstring)) == NULL) {
941                 DEBUG(0, ("Unable to convert address to string: %s\n", 
942                           strerror(errno)));
943                 talloc_free(local);
944                 return NULL;
945         }
946         
947         local->addr = talloc_strdup(mem_ctx, addrstring);
948         if (!local->addr) {
949                 talloc_free(local);
950                 return NULL;
951         }
952         local->port = ntohs(local_addr->sin6_port);
953
954         return local;
955 }
956
957 static const struct socket_ops ipv6_tcp_ops = {
958         .name                   = "ipv6",
959         .fn_init                = ipv6_init,
960         .fn_connect             = ipv6_tcp_connect,
961         .fn_connect_complete    = ip_connect_complete,
962         .fn_listen              = ipv6_listen,
963         .fn_accept              = ipv6_tcp_accept,
964         .fn_recv                = ip_recv,
965         .fn_recvfrom            = ipv6_recvfrom,
966         .fn_send                = ip_send,
967         .fn_sendto              = ipv6_sendto,
968         .fn_pending             = ip_pending,
969         .fn_close               = ip_close,
970
971         .fn_set_option          = ipv6_set_option,
972
973         .fn_get_peer_name       = ipv6_tcp_get_peer_name,
974         .fn_get_peer_addr       = ipv6_tcp_get_peer_addr,
975         .fn_get_my_addr         = ipv6_tcp_get_my_addr,
976
977         .fn_get_fd              = ip_get_fd
978 };
979
980 _PUBLIC_ const struct socket_ops *socket_ipv6_ops(enum socket_type type)
981 {
982         return &ipv6_tcp_ops;
983 }
984
985 #endif