LCOV - code coverage report
Current view: top level - source4/lib/socket - socket_ip.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 307 478 64.2 %
Date: 2021-09-23 10:06:22 Functions: 27 31 87.1 %

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

Generated by: LCOV version 1.13