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