root/source4/lib/socket/socket_ip.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ipv4_init
  2. ip_close
  3. ip_connect_complete
  4. ipv4_connect
  5. ipv4_listen
  6. ipv4_accept
  7. ip_recv
  8. ipv4_recvfrom
  9. ip_send
  10. ipv4_sendto
  11. ipv4_set_option
  12. ipv4_get_peer_name
  13. ipv4_get_peer_addr
  14. ipv4_get_my_addr
  15. ip_get_fd
  16. ip_pending
  17. socket_ipv4_ops
  18. interpret_addr6
  19. ipv6_init
  20. ipv6_tcp_connect
  21. ipv6_listen
  22. ipv6_tcp_accept
  23. ipv6_recvfrom
  24. ipv6_sendto
  25. ipv6_set_option
  26. ipv6_tcp_get_peer_name
  27. ipv6_tcp_get_peer_addr
  28. ipv6_tcp_get_my_addr
  29. socket_ipv6_ops

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

/* [<][>][^][v][top][bottom][index][help] */