87b7bf4911d1171b96278cde61ecffaea553494a
[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         } else if (gotlen == -1) {
320                 talloc_free(src);
321                 return map_nt_error_from_unix_common(errno);
322         }
323
324         src->sockaddrlen = from_len;
325
326         if (inet_ntop(AF_INET, &from_addr->sin_addr, addrstring, 
327                          sizeof(addrstring)) == NULL) {
328                 talloc_free(src);
329                 return NT_STATUS_INTERNAL_ERROR;
330         }
331         src->addr = talloc_strdup(src, addrstring);
332         if (src->addr == NULL) {
333                 talloc_free(src);
334                 return NT_STATUS_NO_MEMORY;
335         }
336         src->port = ntohs(from_addr->sin_port);
337
338         *nread  = gotlen;
339         *_src   = src;
340         return NT_STATUS_OK;
341 }
342
343 static NTSTATUS ip_send(struct socket_context *sock, 
344                               const DATA_BLOB *blob, size_t *sendlen)
345 {
346         ssize_t len;
347
348         *sendlen = 0;
349
350         len = send(sock->fd, blob->data, blob->length, 0);
351         if (len == -1) {
352                 return map_nt_error_from_unix_common(errno);
353         }       
354
355         *sendlen = len;
356
357         return NT_STATUS_OK;
358 }
359
360 static NTSTATUS ipv4_sendto(struct socket_context *sock, 
361                             const DATA_BLOB *blob, size_t *sendlen, 
362                             const struct socket_address *dest_addr)
363 {
364         ssize_t len;
365
366         if (dest_addr->sockaddr) {
367                 len = sendto(sock->fd, blob->data, blob->length, 0, 
368                              dest_addr->sockaddr, dest_addr->sockaddrlen);
369         } else {
370                 struct sockaddr_in srv_addr;
371                 struct in_addr addr;
372
373                 SMB_ASSERT(dest_addr->port != 0);
374                 
375                 ZERO_STRUCT(srv_addr);
376 #ifdef HAVE_SOCK_SIN_LEN
377                 srv_addr.sin_len         = sizeof(srv_addr);
378 #endif
379                 addr                     = interpret_addr2(dest_addr->addr);
380                 if (addr.s_addr == 0) {
381                         return NT_STATUS_HOST_UNREACHABLE;
382                 }
383                 srv_addr.sin_addr.s_addr = addr.s_addr;
384                 srv_addr.sin_port        = htons(dest_addr->port);
385                 srv_addr.sin_family      = PF_INET;
386                 
387                 *sendlen = 0;
388                 
389                 len = sendto(sock->fd, blob->data, blob->length, 0, 
390                              (struct sockaddr *)&srv_addr, sizeof(srv_addr));
391         }
392         if (len == -1) {
393                 return map_nt_error_from_unix_common(errno);
394         }       
395
396         *sendlen = len;
397
398         return NT_STATUS_OK;
399 }
400
401 static NTSTATUS ipv4_set_option(struct socket_context *sock, const char *option, const char *val)
402 {
403         set_socket_options(sock->fd, option);
404         return NT_STATUS_OK;
405 }
406
407 static char *ipv4_get_peer_name(struct socket_context *sock, TALLOC_CTX *mem_ctx)
408 {
409         struct sockaddr_in peer_addr;
410         socklen_t len = sizeof(peer_addr);
411         struct hostent *he;
412         int ret;
413
414         ret = getpeername(sock->fd, (struct sockaddr *)&peer_addr, &len);
415         if (ret == -1) {
416                 return NULL;
417         }
418
419         he = gethostbyaddr((char *)&peer_addr.sin_addr, sizeof(peer_addr.sin_addr), AF_INET);
420         if (he == NULL) {
421                 return NULL;
422         }
423
424         return talloc_strdup(mem_ctx, he->h_name);
425 }
426
427 static struct socket_address *ipv4_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
428 {
429         struct sockaddr_in *peer_addr;
430         socklen_t len = sizeof(*peer_addr);
431         struct socket_address *peer;
432         char addrstring[INET_ADDRSTRLEN];
433         int ret;
434         
435         peer = talloc(mem_ctx, struct socket_address);
436         if (!peer) {
437                 return NULL;
438         }
439         
440         peer->family = sock->backend_name;
441         peer_addr = talloc(peer, struct sockaddr_in);
442         if (!peer_addr) {
443                 talloc_free(peer);
444                 return NULL;
445         }
446
447         peer->sockaddr = (struct sockaddr *)peer_addr;
448
449         ret = getpeername(sock->fd, peer->sockaddr, &len);
450         if (ret == -1) {
451                 talloc_free(peer);
452                 return NULL;
453         }
454
455         peer->sockaddrlen = len;
456
457         if (inet_ntop(AF_INET, &peer_addr->sin_addr, addrstring,
458                          sizeof(addrstring)) == NULL) {
459                 talloc_free(peer);
460                 return NULL;
461         }
462         peer->addr = talloc_strdup(peer, addrstring);
463         if (!peer->addr) {
464                 talloc_free(peer);
465                 return NULL;
466         }
467         peer->port = ntohs(peer_addr->sin_port);
468
469         return peer;
470 }
471
472 static struct socket_address *ipv4_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
473 {
474         struct sockaddr_in *local_addr;
475         socklen_t len = sizeof(*local_addr);
476         struct socket_address *local;
477         char addrstring[INET_ADDRSTRLEN];
478         int ret;
479         
480         local = talloc(mem_ctx, struct socket_address);
481         if (!local) {
482                 return NULL;
483         }
484         
485         local->family = sock->backend_name;
486         local_addr = talloc(local, struct sockaddr_in);
487         if (!local_addr) {
488                 talloc_free(local);
489                 return NULL;
490         }
491
492         local->sockaddr = (struct sockaddr *)local_addr;
493
494         ret = getsockname(sock->fd, local->sockaddr, &len);
495         if (ret == -1) {
496                 talloc_free(local);
497                 return NULL;
498         }
499
500         local->sockaddrlen = len;
501
502         if (inet_ntop(AF_INET, &local_addr->sin_addr, addrstring, 
503                          sizeof(addrstring)) == NULL) {
504                 talloc_free(local);
505                 return NULL;
506         }
507         local->addr = talloc_strdup(local, addrstring);
508         if (!local->addr) {
509                 talloc_free(local);
510                 return NULL;
511         }
512         local->port = ntohs(local_addr->sin_port);
513
514         return local;
515 }
516 static int ip_get_fd(struct socket_context *sock)
517 {
518         return sock->fd;
519 }
520
521 static NTSTATUS ip_pending(struct socket_context *sock, size_t *npending)
522 {
523         int value = 0;
524         if (ioctl(sock->fd, FIONREAD, &value) == 0) {
525                 *npending = value;
526                 return NT_STATUS_OK;
527         }
528         return map_nt_error_from_unix_common(errno);
529 }
530
531 static const struct socket_ops ipv4_ops = {
532         .name                   = "ipv4",
533         .fn_init                = ipv4_init,
534         .fn_connect             = ipv4_connect,
535         .fn_connect_complete    = ip_connect_complete,
536         .fn_listen              = ipv4_listen,
537         .fn_accept              = ipv4_accept,
538         .fn_recv                = ip_recv,
539         .fn_recvfrom            = ipv4_recvfrom,
540         .fn_send                = ip_send,
541         .fn_sendto              = ipv4_sendto,
542         .fn_pending             = ip_pending,
543         .fn_close               = ip_close,
544
545         .fn_set_option          = ipv4_set_option,
546
547         .fn_get_peer_name       = ipv4_get_peer_name,
548         .fn_get_peer_addr       = ipv4_get_peer_addr,
549         .fn_get_my_addr         = ipv4_get_my_addr,
550
551         .fn_get_fd              = ip_get_fd
552 };
553
554 _PUBLIC_ const struct socket_ops *socket_ipv4_ops(enum socket_type type)
555 {
556         return &ipv4_ops;
557 }
558
559 #if HAVE_IPV6
560
561 static struct in6_addr interpret_addr6(const char *name)
562 {
563         char addr[INET6_ADDRSTRLEN];
564         struct in6_addr dest6;
565         const char *sp = name;
566         char *p;
567         int ret;
568
569         if (sp == NULL) return in6addr_any;
570
571         p = strchr_m(sp, '%');
572
573         if (strcasecmp(sp, "localhost") == 0) {
574                 sp = "::1";
575         }
576
577         /*
578          * Cope with link-local.
579          * This is IP:v6:addr%ifname.
580          */
581
582         if (p && (p > sp) && (if_nametoindex(p+1) != 0)) {
583                 strlcpy(addr, sp,
584                         MIN(PTR_DIFF(p,sp)+1,
585                                 sizeof(addr)));
586                 sp = addr;
587         }
588
589         ret = inet_pton(AF_INET6, sp, &dest6);
590         if (ret > 0) {
591                 return dest6;
592         }
593
594         return in6addr_any;
595 }
596
597 static NTSTATUS ipv6_init(struct socket_context *sock)
598 {
599         int type;
600
601         switch (sock->type) {
602         case SOCKET_TYPE_STREAM:
603                 type = SOCK_STREAM;
604                 break;
605         case SOCKET_TYPE_DGRAM:
606                 type = SOCK_DGRAM;
607                 break;
608         default:
609                 return NT_STATUS_INVALID_PARAMETER;
610         }
611
612         sock->fd = socket(PF_INET6, type, 0);
613         if (sock->fd == -1) {
614                 return map_nt_error_from_unix_common(errno);
615         }
616
617         smb_set_close_on_exec(sock->fd);
618
619         sock->backend_name = "ipv6";
620         sock->family = AF_INET6;
621
622         return NT_STATUS_OK;
623 }
624
625 static NTSTATUS ipv6_tcp_connect(struct socket_context *sock,
626                                  const struct socket_address *my_address,
627                                  const struct socket_address *srv_address,
628                                  uint32_t flags)
629 {
630         int ret;
631
632         if (my_address && my_address->sockaddr) {
633                 ret = bind(sock->fd, my_address->sockaddr, my_address->sockaddrlen);
634                 if (ret == -1) {
635                         return map_nt_error_from_unix_common(errno);
636                 }
637         } else if (my_address) {
638                 struct in6_addr my_ip;
639                 my_ip = interpret_addr6(my_address->addr);
640
641                 if (memcmp(&my_ip, &in6addr_any, sizeof(my_ip)) || my_address->port != 0) {
642                         struct sockaddr_in6 my_addr;
643                         ZERO_STRUCT(my_addr);
644                         my_addr.sin6_addr       = my_ip;
645                         my_addr.sin6_port       = htons(my_address->port);
646                         my_addr.sin6_family     = PF_INET6;
647                         
648                         ret = bind(sock->fd, (struct sockaddr *)&my_addr, sizeof(my_addr));
649                         if (ret == -1) {
650                                 return map_nt_error_from_unix_common(errno);
651                         }
652                 }
653         }
654
655         if (srv_address->sockaddr) {
656                 ret = connect(sock->fd, srv_address->sockaddr, srv_address->sockaddrlen);
657         } else {
658                 struct in6_addr srv_ip;
659                 struct sockaddr_in6 srv_addr;
660                 srv_ip = interpret_addr6(srv_address->addr);
661                 if (memcmp(&srv_ip, &in6addr_any, sizeof(srv_ip)) == 0) {
662                         return NT_STATUS_BAD_NETWORK_NAME;
663                 }
664                 
665                 ZERO_STRUCT(srv_addr);
666                 srv_addr.sin6_addr      = srv_ip;
667                 srv_addr.sin6_port      = htons(srv_address->port);
668                 srv_addr.sin6_family    = PF_INET6;
669                 
670                 ret = connect(sock->fd, (const struct sockaddr *)&srv_addr, sizeof(srv_addr));
671         }
672         if (ret == -1) {
673                 return map_nt_error_from_unix_common(errno);
674         }
675
676         return ip_connect_complete(sock, flags);
677 }
678
679 /*
680   fix the sin6_scope_id based on the address interface
681  */
682 static void fix_scope_id(struct sockaddr_in6 *in6,
683                          const char *address)
684 {
685         const char *p = strchr(address, '%');
686         if (p != NULL) {
687                 in6->sin6_scope_id = if_nametoindex(p+1);
688         }
689 }
690
691
692 static NTSTATUS ipv6_listen(struct socket_context *sock,
693                             const struct socket_address *my_address,
694                             int queue_size, uint32_t flags)
695 {
696         struct sockaddr_in6 my_addr;
697         struct in6_addr ip_addr;
698         int ret;
699
700         socket_set_option(sock, "SO_REUSEADDR=1", NULL);
701
702         if (my_address->sockaddr) {
703                 ret = bind(sock->fd, my_address->sockaddr, my_address->sockaddrlen);
704         } else {
705                 int one = 1;
706                 ip_addr = interpret_addr6(my_address->addr);
707                 
708                 ZERO_STRUCT(my_addr);
709                 my_addr.sin6_addr       = ip_addr;
710                 my_addr.sin6_port       = htons(my_address->port);
711                 my_addr.sin6_family     = PF_INET6;
712                 fix_scope_id(&my_addr, my_address->addr);
713
714                 /* when binding on ipv6 we always want to only bind on v6 */
715                 ret = setsockopt(sock->fd, IPPROTO_IPV6, IPV6_V6ONLY,
716                                  (const void *)&one, sizeof(one));
717                 if (ret != -1) {
718                         ret = bind(sock->fd, (struct sockaddr *)&my_addr, sizeof(my_addr));
719                 }
720         }
721
722         if (ret == -1) {
723                 return map_nt_error_from_unix_common(errno);
724         }
725
726         if (sock->type == SOCKET_TYPE_STREAM) {
727                 ret = listen(sock->fd, queue_size);
728                 if (ret == -1) {
729                         return map_nt_error_from_unix_common(errno);
730                 }
731         }
732
733         if (!(flags & SOCKET_FLAG_BLOCK)) {
734                 ret = set_blocking(sock->fd, false);
735                 if (ret == -1) {
736                         return map_nt_error_from_unix_common(errno);
737                 }
738         }
739
740         sock->state= SOCKET_STATE_SERVER_LISTEN;
741
742         return NT_STATUS_OK;
743 }
744
745 static NTSTATUS ipv6_tcp_accept(struct socket_context *sock, struct socket_context **new_sock)
746 {
747         struct sockaddr_in6 cli_addr;
748         socklen_t cli_addr_len = sizeof(cli_addr);
749         int new_fd;
750         
751         if (sock->type != SOCKET_TYPE_STREAM) {
752                 return NT_STATUS_INVALID_PARAMETER;
753         }
754
755         new_fd = accept(sock->fd, (struct sockaddr *)&cli_addr, &cli_addr_len);
756         if (new_fd == -1) {
757                 return map_nt_error_from_unix_common(errno);
758         }
759
760         if (!(sock->flags & SOCKET_FLAG_BLOCK)) {
761                 int ret = set_blocking(new_fd, false);
762                 if (ret == -1) {
763                         close(new_fd);
764                         return map_nt_error_from_unix_common(errno);
765                 }
766         }
767         smb_set_close_on_exec(new_fd);
768
769         /* TODO: we could add a 'accept_check' hook here
770          *       which get the black/white lists via socket_set_accept_filter()
771          *       or something like that
772          *       --metze
773          */
774
775         (*new_sock) = talloc(NULL, struct socket_context);
776         if (!(*new_sock)) {
777                 close(new_fd);
778                 return NT_STATUS_NO_MEMORY;
779         }
780
781         /* copy the socket_context */
782         (*new_sock)->type               = sock->type;
783         (*new_sock)->state              = SOCKET_STATE_SERVER_CONNECTED;
784         (*new_sock)->flags              = sock->flags;
785
786         (*new_sock)->fd                 = new_fd;
787
788         (*new_sock)->private_data       = NULL;
789         (*new_sock)->ops                = sock->ops;
790         (*new_sock)->backend_name       = sock->backend_name;
791
792         return NT_STATUS_OK;
793 }
794
795 static NTSTATUS ipv6_recvfrom(struct socket_context *sock, void *buf, 
796                               size_t wantlen, size_t *nread, 
797                               TALLOC_CTX *addr_ctx, struct socket_address **_src)
798 {
799         ssize_t gotlen;
800         struct sockaddr_in6 *from_addr;
801         socklen_t from_len = sizeof(*from_addr);
802         struct socket_address *src;
803         char addrstring[INET6_ADDRSTRLEN];
804         
805         src = talloc(addr_ctx, struct socket_address);
806         if (!src) {
807                 return NT_STATUS_NO_MEMORY;
808         }
809         
810         src->family = sock->backend_name;
811
812         from_addr = talloc(src, struct sockaddr_in6);
813         if (!from_addr) {
814                 talloc_free(src);
815                 return NT_STATUS_NO_MEMORY;
816         }
817
818         src->sockaddr = (struct sockaddr *)from_addr;
819
820         *nread = 0;
821
822         gotlen = recvfrom(sock->fd, buf, wantlen, 0, 
823                           src->sockaddr, &from_len);
824         if (gotlen == 0) {
825                 talloc_free(src);
826                 return NT_STATUS_END_OF_FILE;
827         } else if (gotlen == -1) {
828                 talloc_free(src);
829                 return map_nt_error_from_unix_common(errno);
830         }
831
832         src->sockaddrlen = from_len;
833
834         if (inet_ntop(AF_INET6, &from_addr->sin6_addr, addrstring, sizeof(addrstring)) == NULL) {
835                 DEBUG(0, ("Unable to convert address to string: %s\n", strerror(errno)));
836                 talloc_free(src);
837                 return NT_STATUS_INTERNAL_ERROR;
838         }
839
840         src->addr = talloc_strdup(src, addrstring);
841         if (src->addr == NULL) {
842                 talloc_free(src);
843                 return NT_STATUS_NO_MEMORY;
844         }
845         src->port = ntohs(from_addr->sin6_port);
846
847         *nread  = gotlen;
848         *_src   = src;
849         return NT_STATUS_OK;
850 }
851
852 static NTSTATUS ipv6_sendto(struct socket_context *sock, 
853                             const DATA_BLOB *blob, size_t *sendlen, 
854                             const struct socket_address *dest_addr)
855 {
856         ssize_t len;
857
858         if (dest_addr->sockaddr) {
859                 len = sendto(sock->fd, blob->data, blob->length, 0, 
860                              dest_addr->sockaddr, dest_addr->sockaddrlen);
861         } else {
862                 struct sockaddr_in6 srv_addr;
863                 struct in6_addr addr;
864                 
865                 ZERO_STRUCT(srv_addr);
866                 addr                     = interpret_addr6(dest_addr->addr);
867                 if (memcmp(&addr.s6_addr, &in6addr_any,
868                            sizeof(addr.s6_addr)) == 0) {
869                         return NT_STATUS_HOST_UNREACHABLE;
870                 }
871                 srv_addr.sin6_addr = addr;
872                 srv_addr.sin6_port        = htons(dest_addr->port);
873                 srv_addr.sin6_family      = PF_INET6;
874                 
875                 *sendlen = 0;
876                 
877                 len = sendto(sock->fd, blob->data, blob->length, 0, 
878                              (struct sockaddr *)&srv_addr, sizeof(srv_addr));
879         }
880         if (len == -1) {
881                 return map_nt_error_from_unix_common(errno);
882         }       
883
884         *sendlen = len;
885
886         return NT_STATUS_OK;
887 }
888
889 static NTSTATUS ipv6_set_option(struct socket_context *sock, const char *option, const char *val)
890 {
891         set_socket_options(sock->fd, option);
892         return NT_STATUS_OK;
893 }
894
895 static char *ipv6_tcp_get_peer_name(struct socket_context *sock, TALLOC_CTX *mem_ctx)
896 {
897         struct sockaddr_in6 peer_addr;
898         socklen_t len = sizeof(peer_addr);
899         struct hostent *he;
900         int ret;
901
902         ret = getpeername(sock->fd, (struct sockaddr *)&peer_addr, &len);
903         if (ret == -1) {
904                 return NULL;
905         }
906
907         he = gethostbyaddr((char *)&peer_addr.sin6_addr, sizeof(peer_addr.sin6_addr), AF_INET6);
908         if (he == NULL) {
909                 return NULL;
910         }
911
912         return talloc_strdup(mem_ctx, he->h_name);
913 }
914
915 static struct socket_address *ipv6_tcp_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
916 {
917         struct sockaddr_in6 *peer_addr;
918         socklen_t len = sizeof(*peer_addr);
919         struct socket_address *peer;
920         int ret;
921         char addr[128];
922         const char *addr_ret;
923         
924         peer = talloc(mem_ctx, struct socket_address);
925         if (!peer) {
926                 return NULL;
927         }
928         
929         peer->family = sock->backend_name;
930         peer_addr = talloc(peer, struct sockaddr_in6);
931         if (!peer_addr) {
932                 talloc_free(peer);
933                 return NULL;
934         }
935
936         peer->sockaddr = (struct sockaddr *)peer_addr;
937
938         ret = getpeername(sock->fd, peer->sockaddr, &len);
939         if (ret == -1) {
940                 talloc_free(peer);
941                 return NULL;
942         }
943
944         peer->sockaddrlen = len;
945
946         addr_ret = inet_ntop(AF_INET6, &peer_addr->sin6_addr, addr, sizeof(addr));
947         if (addr_ret == NULL) {
948                 talloc_free(peer);
949                 return NULL;
950         }
951
952         peer->addr = talloc_strdup(peer, addr_ret);
953         if (peer->addr == NULL) {
954                 talloc_free(peer);
955                 return NULL;
956         }
957
958         peer->port = ntohs(peer_addr->sin6_port);
959
960         return peer;
961 }
962
963 static struct socket_address *ipv6_tcp_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
964 {
965         struct sockaddr_in6 *local_addr;
966         socklen_t len = sizeof(*local_addr);
967         struct socket_address *local;
968         int ret;
969         char addrstring[INET6_ADDRSTRLEN];
970         
971         local = talloc(mem_ctx, struct socket_address);
972         if (!local) {
973                 return NULL;
974         }
975         
976         local->family = sock->backend_name;
977         local_addr = talloc(local, struct sockaddr_in6);
978         if (!local_addr) {
979                 talloc_free(local);
980                 return NULL;
981         }
982
983         local->sockaddr = (struct sockaddr *)local_addr;
984
985         ret = getsockname(sock->fd, local->sockaddr, &len);
986         if (ret == -1) {
987                 talloc_free(local);
988                 return NULL;
989         }
990
991         local->sockaddrlen = len;
992
993         if (inet_ntop(AF_INET6, &local_addr->sin6_addr, addrstring, 
994                        sizeof(addrstring)) == NULL) {
995                 DEBUG(0, ("Unable to convert address to string: %s\n", 
996                           strerror(errno)));
997                 talloc_free(local);
998                 return NULL;
999         }
1000         
1001         local->addr = talloc_strdup(mem_ctx, addrstring);
1002         if (!local->addr) {
1003                 talloc_free(local);
1004                 return NULL;
1005         }
1006         local->port = ntohs(local_addr->sin6_port);
1007
1008         return local;
1009 }
1010
1011 static const struct socket_ops ipv6_tcp_ops = {
1012         .name                   = "ipv6",
1013         .fn_init                = ipv6_init,
1014         .fn_connect             = ipv6_tcp_connect,
1015         .fn_connect_complete    = ip_connect_complete,
1016         .fn_listen              = ipv6_listen,
1017         .fn_accept              = ipv6_tcp_accept,
1018         .fn_recv                = ip_recv,
1019         .fn_recvfrom            = ipv6_recvfrom,
1020         .fn_send                = ip_send,
1021         .fn_sendto              = ipv6_sendto,
1022         .fn_pending             = ip_pending,
1023         .fn_close               = ip_close,
1024
1025         .fn_set_option          = ipv6_set_option,
1026
1027         .fn_get_peer_name       = ipv6_tcp_get_peer_name,
1028         .fn_get_peer_addr       = ipv6_tcp_get_peer_addr,
1029         .fn_get_my_addr         = ipv6_tcp_get_my_addr,
1030
1031         .fn_get_fd              = ip_get_fd
1032 };
1033
1034 _PUBLIC_ const struct socket_ops *socket_ipv6_ops(enum socket_type type)
1035 {
1036         return &ipv6_tcp_ops;
1037 }
1038
1039 #endif