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