Merge 2610c05b5b95cc7036b3d6dfb894c6cfbdb68483 as Samba-4.0alpha16
[mat/samba.git] / source4 / 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 #include "lib/util/util_net.h"
29
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);
32
33 static NTSTATUS ipv4_init(struct socket_context *sock)
34 {
35         int type;
36
37         switch (sock->type) {
38         case SOCKET_TYPE_STREAM:
39                 type = SOCK_STREAM;
40                 break;
41         case SOCKET_TYPE_DGRAM:
42                 type = SOCK_DGRAM;
43                 break;
44         default:
45                 return NT_STATUS_INVALID_PARAMETER;
46         }
47
48         sock->fd = socket(PF_INET, type, 0);
49         if (sock->fd == -1) {
50                 return map_nt_error_from_unix_common(errno);
51         }
52
53         sock->backend_name = "ipv4";
54         sock->family = AF_INET;
55
56         return NT_STATUS_OK;
57 }
58
59 static void ip_close(struct socket_context *sock)
60 {
61         close(sock->fd);
62 }
63
64 static NTSTATUS ip_connect_complete(struct socket_context *sock, uint32_t flags)
65 {
66         int error=0, ret;
67         socklen_t len = sizeof(error);
68
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);
72         if (ret == -1) {
73                 return map_nt_error_from_unix_common(errno);
74         }
75         if (error != 0) {
76                 return map_nt_error_from_unix_common(error);
77         }
78
79         if (!(flags & SOCKET_FLAG_BLOCK)) {
80                 ret = set_blocking(sock->fd, false);
81                 if (ret == -1) {
82                         return map_nt_error_from_unix_common(errno);
83                 }
84         }
85
86         sock->state = SOCKET_STATE_CLIENT_CONNECTED;
87
88         return NT_STATUS_OK;
89 }
90
91
92 static NTSTATUS ipv4_connect(struct socket_context *sock,
93                              const struct socket_address *my_address, 
94                              const struct socket_address *srv_address,
95                              uint32_t flags)
96 {
97         struct sockaddr_in srv_addr;
98         struct in_addr my_ip;
99         struct in_addr srv_ip;
100         int ret;
101
102         if (my_address && my_address->sockaddr) {
103                 ret = bind(sock->fd, my_address->sockaddr, my_address->sockaddrlen);
104                 if (ret == -1) {
105                         return map_nt_error_from_unix_common(errno);
106                 }
107         } else if (my_address) {
108                 my_ip = interpret_addr2(my_address->addr);
109                 
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);
115 #endif
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;
119                         
120                         ret = bind(sock->fd, (struct sockaddr *)&my_addr, sizeof(my_addr));
121                         if (ret == -1) {
122                                 return map_nt_error_from_unix_common(errno);
123                         }
124                 }
125         }
126
127         if (srv_address->sockaddr) {
128                 ret = connect(sock->fd, srv_address->sockaddr, srv_address->sockaddrlen);
129                 if (ret == -1) {
130                         return map_nt_error_from_unix_common(errno);
131                 }
132         } else {
133                 srv_ip = interpret_addr2(srv_address->addr);
134                 if (!srv_ip.s_addr) {
135                         return NT_STATUS_BAD_NETWORK_NAME;
136                 }
137
138                 SMB_ASSERT(srv_address->port != 0);
139                 
140                 ZERO_STRUCT(srv_addr);
141 #ifdef HAVE_SOCK_SIN_LEN
142                 srv_addr.sin_len        = sizeof(srv_addr);
143 #endif
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;
147
148                 ret = connect(sock->fd, (const struct sockaddr *)&srv_addr, sizeof(srv_addr));
149                 if (ret == -1) {
150                         return map_nt_error_from_unix_common(errno);
151                 }
152         }
153
154         return ip_connect_complete(sock, flags);
155 }
156
157
158 /*
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
161 */
162 static NTSTATUS ipv4_listen(struct socket_context *sock,
163                             const struct socket_address *my_address, 
164                             int queue_size, uint32_t flags)
165 {
166         struct sockaddr_in my_addr;
167         struct in_addr ip_addr;
168         int ret;
169
170         socket_set_option(sock, "SO_REUSEADDR=1", NULL);
171
172         if (my_address->sockaddr) {
173                 ret = bind(sock->fd, my_address->sockaddr, my_address->sockaddrlen);
174         } else {
175                 ip_addr = interpret_addr2(my_address->addr);
176                 
177                 ZERO_STRUCT(my_addr);
178 #ifdef HAVE_SOCK_SIN_LEN
179                 my_addr.sin_len         = sizeof(my_addr);
180 #endif
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;
184                 
185                 ret = bind(sock->fd, (struct sockaddr *)&my_addr, sizeof(my_addr));
186         }
187
188         if (ret == -1) {
189                 return map_nt_error_from_unix_common(errno);
190         }
191
192         if (sock->type == SOCKET_TYPE_STREAM) {
193                 ret = listen(sock->fd, queue_size);
194                 if (ret == -1) {
195                         return map_nt_error_from_unix_common(errno);
196                 }
197         }
198
199         if (!(flags & SOCKET_FLAG_BLOCK)) {
200                 ret = set_blocking(sock->fd, false);
201                 if (ret == -1) {
202                         return map_nt_error_from_unix_common(errno);
203                 }
204         }
205
206         sock->state= SOCKET_STATE_SERVER_LISTEN;
207
208         return NT_STATUS_OK;
209 }
210
211 static NTSTATUS ipv4_accept(struct socket_context *sock, struct socket_context **new_sock)
212 {
213         struct sockaddr_in cli_addr;
214         socklen_t cli_addr_len = sizeof(cli_addr);
215         int new_fd;
216
217         if (sock->type != SOCKET_TYPE_STREAM) {
218                 return NT_STATUS_INVALID_PARAMETER;
219         }
220
221         new_fd = accept(sock->fd, (struct sockaddr *)&cli_addr, &cli_addr_len);
222         if (new_fd == -1) {
223                 return map_nt_error_from_unix_common(errno);
224         }
225
226         if (!(sock->flags & SOCKET_FLAG_BLOCK)) {
227                 int ret = set_blocking(new_fd, false);
228                 if (ret == -1) {
229                         close(new_fd);
230                         return map_nt_error_from_unix_common(errno);
231                 }
232         }
233
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
237          *       --metze
238          */
239
240         (*new_sock) = talloc(NULL, struct socket_context);
241         if (!(*new_sock)) {
242                 close(new_fd);
243                 return NT_STATUS_NO_MEMORY;
244         }
245
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;
250
251         (*new_sock)->fd                 = new_fd;
252
253         (*new_sock)->private_data       = NULL;
254         (*new_sock)->ops                = sock->ops;
255         (*new_sock)->backend_name       = sock->backend_name;
256
257         return NT_STATUS_OK;
258 }
259
260 static NTSTATUS ip_recv(struct socket_context *sock, void *buf, 
261                               size_t wantlen, size_t *nread)
262 {
263         ssize_t gotlen;
264
265         *nread = 0;
266
267         gotlen = recv(sock->fd, buf, wantlen, 0);
268         if (gotlen == 0) {
269                 return NT_STATUS_END_OF_FILE;
270         } else if (gotlen == -1) {
271                 return map_nt_error_from_unix_common(errno);
272         }
273
274         *nread = gotlen;
275
276         return NT_STATUS_OK;
277 }
278
279
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)
283 {
284         ssize_t gotlen;
285         struct sockaddr_in *from_addr;
286         socklen_t from_len = sizeof(*from_addr);
287         struct socket_address *src;
288         char addrstring[INET_ADDRSTRLEN];
289         
290         src = talloc(addr_ctx, struct socket_address);
291         if (!src) {
292                 return NT_STATUS_NO_MEMORY;
293         }
294         
295         src->family = sock->backend_name;
296
297         from_addr = talloc(src, struct sockaddr_in);
298         if (!from_addr) {
299                 talloc_free(src);
300                 return NT_STATUS_NO_MEMORY;
301         }
302
303         src->sockaddr = (struct sockaddr *)from_addr;
304
305         *nread = 0;
306
307         gotlen = recvfrom(sock->fd, buf, wantlen, 0, 
308                           src->sockaddr, &from_len);
309         if (gotlen == 0) {
310                 talloc_free(src);
311                 return NT_STATUS_END_OF_FILE;
312         } else if (gotlen == -1) {
313                 talloc_free(src);
314                 return map_nt_error_from_unix_common(errno);
315         }
316
317         src->sockaddrlen = from_len;
318
319         if (inet_ntop(AF_INET, &from_addr->sin_addr, addrstring, 
320                          sizeof(addrstring)) == NULL) {
321                 talloc_free(src);
322                 return NT_STATUS_INTERNAL_ERROR;
323         }
324         src->addr = talloc_strdup(src, addrstring);
325         if (src->addr == NULL) {
326                 talloc_free(src);
327                 return NT_STATUS_NO_MEMORY;
328         }
329         src->port = ntohs(from_addr->sin_port);
330
331         *nread  = gotlen;
332         *_src   = src;
333         return NT_STATUS_OK;
334 }
335
336 static NTSTATUS ip_send(struct socket_context *sock, 
337                               const DATA_BLOB *blob, size_t *sendlen)
338 {
339         ssize_t len;
340
341         *sendlen = 0;
342
343         len = send(sock->fd, blob->data, blob->length, 0);
344         if (len == -1) {
345                 return map_nt_error_from_unix_common(errno);
346         }       
347
348         *sendlen = len;
349
350         return NT_STATUS_OK;
351 }
352
353 static NTSTATUS ipv4_sendto(struct socket_context *sock, 
354                             const DATA_BLOB *blob, size_t *sendlen, 
355                             const struct socket_address *dest_addr)
356 {
357         ssize_t len;
358
359         if (dest_addr->sockaddr) {
360                 len = sendto(sock->fd, blob->data, blob->length, 0, 
361                              dest_addr->sockaddr, dest_addr->sockaddrlen);
362         } else {
363                 struct sockaddr_in srv_addr;
364                 struct in_addr addr;
365
366                 SMB_ASSERT(dest_addr->port != 0);
367                 
368                 ZERO_STRUCT(srv_addr);
369 #ifdef HAVE_SOCK_SIN_LEN
370                 srv_addr.sin_len         = sizeof(srv_addr);
371 #endif
372                 addr                     = interpret_addr2(dest_addr->addr);
373                 if (addr.s_addr == 0) {
374                         return NT_STATUS_HOST_UNREACHABLE;
375                 }
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;
379                 
380                 *sendlen = 0;
381                 
382                 len = sendto(sock->fd, blob->data, blob->length, 0, 
383                              (struct sockaddr *)&srv_addr, sizeof(srv_addr));
384         }
385         if (len == -1) {
386                 return map_nt_error_from_unix_common(errno);
387         }       
388
389         *sendlen = len;
390
391         return NT_STATUS_OK;
392 }
393
394 static NTSTATUS ipv4_set_option(struct socket_context *sock, const char *option, const char *val)
395 {
396         set_socket_options(sock->fd, option);
397         return NT_STATUS_OK;
398 }
399
400 static char *ipv4_get_peer_name(struct socket_context *sock, TALLOC_CTX *mem_ctx)
401 {
402         struct sockaddr_in peer_addr;
403         socklen_t len = sizeof(peer_addr);
404         struct hostent *he;
405         int ret;
406
407         ret = getpeername(sock->fd, (struct sockaddr *)&peer_addr, &len);
408         if (ret == -1) {
409                 return NULL;
410         }
411
412         he = gethostbyaddr((char *)&peer_addr.sin_addr, sizeof(peer_addr.sin_addr), AF_INET);
413         if (he == NULL) {
414                 return NULL;
415         }
416
417         return talloc_strdup(mem_ctx, he->h_name);
418 }
419
420 static struct socket_address *ipv4_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
421 {
422         struct sockaddr_in *peer_addr;
423         socklen_t len = sizeof(*peer_addr);
424         struct socket_address *peer;
425         char addrstring[INET_ADDRSTRLEN];
426         int ret;
427         
428         peer = talloc(mem_ctx, struct socket_address);
429         if (!peer) {
430                 return NULL;
431         }
432         
433         peer->family = sock->backend_name;
434         peer_addr = talloc(peer, struct sockaddr_in);
435         if (!peer_addr) {
436                 talloc_free(peer);
437                 return NULL;
438         }
439
440         peer->sockaddr = (struct sockaddr *)peer_addr;
441
442         ret = getpeername(sock->fd, peer->sockaddr, &len);
443         if (ret == -1) {
444                 talloc_free(peer);
445                 return NULL;
446         }
447
448         peer->sockaddrlen = len;
449
450         if (inet_ntop(AF_INET, &peer_addr->sin_addr, addrstring,
451                          sizeof(addrstring)) == NULL) {
452                 talloc_free(peer);
453                 return NULL;
454         }
455         peer->addr = talloc_strdup(peer, addrstring);
456         if (!peer->addr) {
457                 talloc_free(peer);
458                 return NULL;
459         }
460         peer->port = ntohs(peer_addr->sin_port);
461
462         return peer;
463 }
464
465 static struct socket_address *ipv4_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
466 {
467         struct sockaddr_in *local_addr;
468         socklen_t len = sizeof(*local_addr);
469         struct socket_address *local;
470         char addrstring[INET_ADDRSTRLEN];
471         int ret;
472         
473         local = talloc(mem_ctx, struct socket_address);
474         if (!local) {
475                 return NULL;
476         }
477         
478         local->family = sock->backend_name;
479         local_addr = talloc(local, struct sockaddr_in);
480         if (!local_addr) {
481                 talloc_free(local);
482                 return NULL;
483         }
484
485         local->sockaddr = (struct sockaddr *)local_addr;
486
487         ret = getsockname(sock->fd, local->sockaddr, &len);
488         if (ret == -1) {
489                 talloc_free(local);
490                 return NULL;
491         }
492
493         local->sockaddrlen = len;
494
495         if (inet_ntop(AF_INET, &local_addr->sin_addr, addrstring, 
496                          sizeof(addrstring)) == NULL) {
497                 talloc_free(local);
498                 return NULL;
499         }
500         local->addr = talloc_strdup(local, addrstring);
501         if (!local->addr) {
502                 talloc_free(local);
503                 return NULL;
504         }
505         local->port = ntohs(local_addr->sin_port);
506
507         return local;
508 }
509 static int ip_get_fd(struct socket_context *sock)
510 {
511         return sock->fd;
512 }
513
514 static NTSTATUS ip_pending(struct socket_context *sock, size_t *npending)
515 {
516         int value = 0;
517         if (ioctl(sock->fd, FIONREAD, &value) == 0) {
518                 *npending = value;
519                 return NT_STATUS_OK;
520         }
521         return map_nt_error_from_unix_common(errno);
522 }
523
524 static const struct socket_ops ipv4_ops = {
525         .name                   = "ipv4",
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,
531         .fn_recv                = ip_recv,
532         .fn_recvfrom            = ipv4_recvfrom,
533         .fn_send                = ip_send,
534         .fn_sendto              = ipv4_sendto,
535         .fn_pending             = ip_pending,
536         .fn_close               = ip_close,
537
538         .fn_set_option          = ipv4_set_option,
539
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,
543
544         .fn_get_fd              = ip_get_fd
545 };
546
547 _PUBLIC_ const struct socket_ops *socket_ipv4_ops(enum socket_type type)
548 {
549         return &ipv4_ops;
550 }
551
552 #if HAVE_IPV6
553
554 static struct in6_addr interpret_addr6(const char *name)
555 {
556         char addr[INET6_ADDRSTRLEN];
557         struct in6_addr dest6;
558         const char *sp = name;
559         char *p;
560         int ret;
561
562         if (sp == NULL) return in6addr_any;
563
564         p = strchr_m(sp, '%');
565
566         if (strcasecmp(sp, "localhost") == 0) {
567                 sp = "::1";
568         }
569
570         /*
571          * Cope with link-local.
572          * This is IP:v6:addr%ifname.
573          */
574
575         if (p && (p > sp) && (if_nametoindex(p+1) != 0)) {
576                 strlcpy(addr, sp,
577                         MIN(PTR_DIFF(p,sp)+1,
578                                 sizeof(addr)));
579                 sp = addr;
580         }
581
582         ret = inet_pton(AF_INET6, sp, &dest6);
583         if (ret > 0) {
584                 return dest6;
585         }
586
587         return in6addr_any;
588 }
589
590 static NTSTATUS ipv6_init(struct socket_context *sock)
591 {
592         int type;
593
594         switch (sock->type) {
595         case SOCKET_TYPE_STREAM:
596                 type = SOCK_STREAM;
597                 break;
598         case SOCKET_TYPE_DGRAM:
599                 type = SOCK_DGRAM;
600                 break;
601         default:
602                 return NT_STATUS_INVALID_PARAMETER;
603         }
604
605         sock->fd = socket(PF_INET6, type, 0);
606         if (sock->fd == -1) {
607                 return map_nt_error_from_unix_common(errno);
608         }
609
610         sock->backend_name = "ipv6";
611         sock->family = AF_INET6;
612
613         return NT_STATUS_OK;
614 }
615
616 static NTSTATUS ipv6_tcp_connect(struct socket_context *sock,
617                                  const struct socket_address *my_address,
618                                  const struct socket_address *srv_address,
619                                  uint32_t flags)
620 {
621         int ret;
622
623         if (my_address && my_address->sockaddr) {
624                 ret = bind(sock->fd, my_address->sockaddr, my_address->sockaddrlen);
625                 if (ret == -1) {
626                         return map_nt_error_from_unix_common(errno);
627                 }
628         } else if (my_address) {
629                 struct in6_addr my_ip;
630                 my_ip = interpret_addr6(my_address->addr);
631
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;
638                         
639                         ret = bind(sock->fd, (struct sockaddr *)&my_addr, sizeof(my_addr));
640                         if (ret == -1) {
641                                 return map_nt_error_from_unix_common(errno);
642                         }
643                 }
644         }
645
646         if (srv_address->sockaddr) {
647                 ret = connect(sock->fd, srv_address->sockaddr, srv_address->sockaddrlen);
648         } else {
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;
654                 }
655                 
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;
660                 
661                 ret = connect(sock->fd, (const struct sockaddr *)&srv_addr, sizeof(srv_addr));
662         }
663         if (ret == -1) {
664                 return map_nt_error_from_unix_common(errno);
665         }
666
667         return ip_connect_complete(sock, flags);
668 }
669
670 /*
671   fix the sin6_scope_id based on the address interface
672  */
673 static void fix_scope_id(struct sockaddr_in6 *in6,
674                          const char *address)
675 {
676         const char *p = strchr(address, '%');
677         if (p != NULL) {
678                 in6->sin6_scope_id = if_nametoindex(p+1);
679         }
680 }
681
682
683 static NTSTATUS ipv6_listen(struct socket_context *sock,
684                             const struct socket_address *my_address,
685                             int queue_size, uint32_t flags)
686 {
687         struct sockaddr_in6 my_addr;
688         struct in6_addr ip_addr;
689         int ret;
690
691         socket_set_option(sock, "SO_REUSEADDR=1", NULL);
692
693         if (my_address->sockaddr) {
694                 ret = bind(sock->fd, my_address->sockaddr, my_address->sockaddrlen);
695         } else {
696                 int one = 1;
697                 ip_addr = interpret_addr6(my_address->addr);
698                 
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);
704
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));
708                 if (ret != -1) {
709                         ret = bind(sock->fd, (struct sockaddr *)&my_addr, sizeof(my_addr));
710                 }
711         }
712
713         if (ret == -1) {
714                 return map_nt_error_from_unix_common(errno);
715         }
716
717         if (sock->type == SOCKET_TYPE_STREAM) {
718                 ret = listen(sock->fd, queue_size);
719                 if (ret == -1) {
720                         return map_nt_error_from_unix_common(errno);
721                 }
722         }
723
724         if (!(flags & SOCKET_FLAG_BLOCK)) {
725                 ret = set_blocking(sock->fd, false);
726                 if (ret == -1) {
727                         return map_nt_error_from_unix_common(errno);
728                 }
729         }
730
731         sock->state= SOCKET_STATE_SERVER_LISTEN;
732
733         return NT_STATUS_OK;
734 }
735
736 static NTSTATUS ipv6_tcp_accept(struct socket_context *sock, struct socket_context **new_sock)
737 {
738         struct sockaddr_in6 cli_addr;
739         socklen_t cli_addr_len = sizeof(cli_addr);
740         int new_fd;
741         
742         if (sock->type != SOCKET_TYPE_STREAM) {
743                 return NT_STATUS_INVALID_PARAMETER;
744         }
745
746         new_fd = accept(sock->fd, (struct sockaddr *)&cli_addr, &cli_addr_len);
747         if (new_fd == -1) {
748                 return map_nt_error_from_unix_common(errno);
749         }
750
751         if (!(sock->flags & SOCKET_FLAG_BLOCK)) {
752                 int ret = set_blocking(new_fd, false);
753                 if (ret == -1) {
754                         close(new_fd);
755                         return map_nt_error_from_unix_common(errno);
756                 }
757         }
758
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
762          *       --metze
763          */
764
765         (*new_sock) = talloc(NULL, struct socket_context);
766         if (!(*new_sock)) {
767                 close(new_fd);
768                 return NT_STATUS_NO_MEMORY;
769         }
770
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;
775
776         (*new_sock)->fd                 = new_fd;
777
778         (*new_sock)->private_data       = NULL;
779         (*new_sock)->ops                = sock->ops;
780         (*new_sock)->backend_name       = sock->backend_name;
781
782         return NT_STATUS_OK;
783 }
784
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)
788 {
789         ssize_t gotlen;
790         struct sockaddr_in6 *from_addr;
791         socklen_t from_len = sizeof(*from_addr);
792         struct socket_address *src;
793         char addrstring[INET6_ADDRSTRLEN];
794         
795         src = talloc(addr_ctx, struct socket_address);
796         if (!src) {
797                 return NT_STATUS_NO_MEMORY;
798         }
799         
800         src->family = sock->backend_name;
801
802         from_addr = talloc(src, struct sockaddr_in6);
803         if (!from_addr) {
804                 talloc_free(src);
805                 return NT_STATUS_NO_MEMORY;
806         }
807
808         src->sockaddr = (struct sockaddr *)from_addr;
809
810         *nread = 0;
811
812         gotlen = recvfrom(sock->fd, buf, wantlen, 0, 
813                           src->sockaddr, &from_len);
814         if (gotlen == 0) {
815                 talloc_free(src);
816                 return NT_STATUS_END_OF_FILE;
817         } else if (gotlen == -1) {
818                 talloc_free(src);
819                 return map_nt_error_from_unix_common(errno);
820         }
821
822         src->sockaddrlen = from_len;
823
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)));
826                 talloc_free(src);
827                 return NT_STATUS_INTERNAL_ERROR;
828         }
829
830         src->addr = talloc_strdup(src, addrstring);
831         if (src->addr == NULL) {
832                 talloc_free(src);
833                 return NT_STATUS_NO_MEMORY;
834         }
835         src->port = ntohs(from_addr->sin6_port);
836
837         *nread  = gotlen;
838         *_src   = src;
839         return NT_STATUS_OK;
840 }
841
842 static NTSTATUS ipv6_sendto(struct socket_context *sock, 
843                             const DATA_BLOB *blob, size_t *sendlen, 
844                             const struct socket_address *dest_addr)
845 {
846         ssize_t len;
847
848         if (dest_addr->sockaddr) {
849                 len = sendto(sock->fd, blob->data, blob->length, 0, 
850                              dest_addr->sockaddr, dest_addr->sockaddrlen);
851         } else {
852                 struct sockaddr_in6 srv_addr;
853                 struct in6_addr addr;
854                 
855                 ZERO_STRUCT(srv_addr);
856                 addr                     = interpret_addr6(dest_addr->addr);
857                 if (addr.s6_addr == 0) {
858                         return NT_STATUS_HOST_UNREACHABLE;
859                 }
860                 srv_addr.sin6_addr = addr;
861                 srv_addr.sin6_port        = htons(dest_addr->port);
862                 srv_addr.sin6_family      = PF_INET6;
863                 
864                 *sendlen = 0;
865                 
866                 len = sendto(sock->fd, blob->data, blob->length, 0, 
867                              (struct sockaddr *)&srv_addr, sizeof(srv_addr));
868         }
869         if (len == -1) {
870                 return map_nt_error_from_unix_common(errno);
871         }       
872
873         *sendlen = len;
874
875         return NT_STATUS_OK;
876 }
877
878 static NTSTATUS ipv6_set_option(struct socket_context *sock, const char *option, const char *val)
879 {
880         set_socket_options(sock->fd, option);
881         return NT_STATUS_OK;
882 }
883
884 static char *ipv6_tcp_get_peer_name(struct socket_context *sock, TALLOC_CTX *mem_ctx)
885 {
886         struct sockaddr_in6 peer_addr;
887         socklen_t len = sizeof(peer_addr);
888         struct hostent *he;
889         int ret;
890
891         ret = getpeername(sock->fd, (struct sockaddr *)&peer_addr, &len);
892         if (ret == -1) {
893                 return NULL;
894         }
895
896         he = gethostbyaddr((char *)&peer_addr.sin6_addr, sizeof(peer_addr.sin6_addr), AF_INET6);
897         if (he == NULL) {
898                 return NULL;
899         }
900
901         return talloc_strdup(mem_ctx, he->h_name);
902 }
903
904 static struct socket_address *ipv6_tcp_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
905 {
906         struct sockaddr_in6 *peer_addr;
907         socklen_t len = sizeof(*peer_addr);
908         struct socket_address *peer;
909         int ret;
910         char addr[128];
911         const char *addr_ret;
912         
913         peer = talloc(mem_ctx, struct socket_address);
914         if (!peer) {
915                 return NULL;
916         }
917         
918         peer->family = sock->backend_name;
919         peer_addr = talloc(peer, struct sockaddr_in6);
920         if (!peer_addr) {
921                 talloc_free(peer);
922                 return NULL;
923         }
924
925         peer->sockaddr = (struct sockaddr *)peer_addr;
926
927         ret = getpeername(sock->fd, peer->sockaddr, &len);
928         if (ret == -1) {
929                 talloc_free(peer);
930                 return NULL;
931         }
932
933         peer->sockaddrlen = len;
934
935         addr_ret = inet_ntop(AF_INET6, &peer_addr->sin6_addr, addr, sizeof(addr));
936         if (addr_ret == NULL) {
937                 talloc_free(peer);
938                 return NULL;
939         }
940
941         peer->addr = talloc_strdup(peer, addr_ret);
942         if (peer->addr == NULL) {
943                 talloc_free(peer);
944                 return NULL;
945         }
946
947         peer->port = ntohs(peer_addr->sin6_port);
948
949         return peer;
950 }
951
952 static struct socket_address *ipv6_tcp_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
953 {
954         struct sockaddr_in6 *local_addr;
955         socklen_t len = sizeof(*local_addr);
956         struct socket_address *local;
957         int ret;
958         char addrstring[INET6_ADDRSTRLEN];
959         
960         local = talloc(mem_ctx, struct socket_address);
961         if (!local) {
962                 return NULL;
963         }
964         
965         local->family = sock->backend_name;
966         local_addr = talloc(local, struct sockaddr_in6);
967         if (!local_addr) {
968                 talloc_free(local);
969                 return NULL;
970         }
971
972         local->sockaddr = (struct sockaddr *)local_addr;
973
974         ret = getsockname(sock->fd, local->sockaddr, &len);
975         if (ret == -1) {
976                 talloc_free(local);
977                 return NULL;
978         }
979
980         local->sockaddrlen = len;
981
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", 
985                           strerror(errno)));
986                 talloc_free(local);
987                 return NULL;
988         }
989         
990         local->addr = talloc_strdup(mem_ctx, addrstring);
991         if (!local->addr) {
992                 talloc_free(local);
993                 return NULL;
994         }
995         local->port = ntohs(local_addr->sin6_port);
996
997         return local;
998 }
999
1000 static const struct socket_ops ipv6_tcp_ops = {
1001         .name                   = "ipv6",
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,
1007         .fn_recv                = ip_recv,
1008         .fn_recvfrom            = ipv6_recvfrom,
1009         .fn_send                = ip_send,
1010         .fn_sendto              = ipv6_sendto,
1011         .fn_pending             = ip_pending,
1012         .fn_close               = ip_close,
1013
1014         .fn_set_option          = ipv6_set_option,
1015
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,
1019
1020         .fn_get_fd              = ip_get_fd
1021 };
1022
1023 _PUBLIC_ const struct socket_ops *socket_ipv6_ops(enum socket_type type)
1024 {
1025         return &ipv6_tcp_ops;
1026 }
1027
1028 #endif