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