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