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 29static 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 55static void ip_close(struct socket_context *sock) 56{ 57 close(sock->fd); 58} 59 60static 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 88static 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 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*/ 158static NTSTATUS ipv4_listen(struct socket_context *sock, 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 207static NTSTATUS ipv4_accept(struct socket_context *sock, struct socket_context **new_sock) 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 256static NTSTATUS ip_recv(struct socket_context *sock, void *buf, 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 276static NTSTATUS ipv4_recvfrom(struct socket_context *sock, void *buf, 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 332static NTSTATUS ip_send(struct socket_context *sock, 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 349static NTSTATUS ipv4_sendto(struct socket_context *sock, 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 390static NTSTATUS ipv4_set_option(struct socket_context *sock, const char *option, const char *val) 391{ 392 set_socket_options(sock->fd, option); 393 return NT_STATUS_OK; 394} 395 396static char *ipv4_get_peer_name(struct socket_context *sock, TALLOC_CTX *mem_ctx) 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 416static struct socket_address *ipv4_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx) 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 461static struct socket_address *ipv4_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx) 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} 505static int ip_get_fd(struct socket_context *sock) 506{ 507 return sock->fd; 508} 509 510static NTSTATUS ip_pending(struct socket_context *sock, size_t *npending) 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 520static 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) 544{ 545 return &ipv4_ops; 546} 547 548#if HAVE_IPV6 549 550static struct in6_addr interpret_addr6(const char *name) 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 586static NTSTATUS ipv6_init(struct socket_context *sock) 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 612static NTSTATUS ipv6_tcp_connect(struct socket_context *sock, 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 666static NTSTATUS ipv6_listen(struct socket_context *sock, 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 712static NTSTATUS ipv6_tcp_accept(struct socket_context *sock, struct socket_context **new_sock) 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 761static NTSTATUS ipv6_recvfrom(struct socket_context *sock, void *buf, 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 818static NTSTATUS ipv6_sendto(struct socket_context *sock, 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 854static NTSTATUS ipv6_set_option(struct socket_context *sock, const char *option, const char *val) 855{ 856 set_socket_options(sock->fd, option); 857 return NT_STATUS_OK; 858} 859 860static char *ipv6_tcp_get_peer_name(struct socket_context *sock, TALLOC_CTX *mem_ctx) 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 880static struct socket_address *ipv6_tcp_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx) 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 928static struct socket_address *ipv6_tcp_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx) 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 976static 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) 1000{ 1001 return &ipv6_tcp_ops; 1002} 1003 1004#endif 1005