LCOV - code coverage report
Current view: top level - source4/lib/socket - socket_ip.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 340 543 62.6 %
Date: 2024-04-21 15:09:00 Functions: 26 30 86.7 %

          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      111733 : static NTSTATUS ipv4_init(struct socket_context *sock)
      36             : {
      37        3027 :         int type;
      38             : 
      39      111733 :         switch (sock->type) {
      40       78178 :         case SOCKET_TYPE_STREAM:
      41       78178 :                 type = SOCK_STREAM;
      42       78178 :                 break;
      43       31740 :         case SOCKET_TYPE_DGRAM:
      44       31740 :                 type = SOCK_DGRAM;
      45       31740 :                 break;
      46           0 :         default:
      47           0 :                 return NT_STATUS_INVALID_PARAMETER;
      48             :         }
      49             : 
      50      111733 :         sock->fd = socket(PF_INET, type, 0);
      51      111733 :         if (sock->fd == -1) {
      52           0 :                 return map_nt_error_from_unix_common(errno);
      53             :         }
      54             : 
      55      111733 :         smb_set_close_on_exec(sock->fd);
      56             : 
      57      111733 :         sock->backend_name = "ipv4";
      58      111733 :         sock->family = AF_INET;
      59             : 
      60      111733 :         return NT_STATUS_OK;
      61             : }
      62             : 
      63      121895 : static void ip_close(struct socket_context *sock)
      64             : {
      65      121895 :         if (sock->fd != -1) {
      66      106193 :                 close(sock->fd);
      67      106193 :                 sock->fd = -1;
      68             :         }
      69      121895 : }
      70             : 
      71      645069 : static NTSTATUS ip_connect_complete(struct socket_context *sock, uint32_t flags)
      72             : {
      73      645069 :         int error=0, ret;
      74      645069 :         socklen_t len = sizeof(error);
      75             : 
      76             :         /* check for any errors that may have occurred - this is needed
      77             :            for non-blocking connect */
      78      645069 :         ret = getsockopt(sock->fd, SOL_SOCKET, SO_ERROR, &error, &len);
      79      645069 :         if (ret == -1) {
      80           0 :                 return map_nt_error_from_unix_common(errno);
      81             :         }
      82      645069 :         if (error != 0) {
      83           0 :                 return map_nt_error_from_unix_common(error);
      84             :         }
      85             : 
      86      645069 :         ret = set_blocking(sock->fd, false);
      87      645069 :         if (ret == -1) {
      88           0 :                 return map_nt_error_from_unix_common(errno);
      89             :         }
      90             : 
      91      645069 :         sock->state = SOCKET_STATE_CLIENT_CONNECTED;
      92             : 
      93      645069 :         return NT_STATUS_OK;
      94             : }
      95             : 
      96             : 
      97      101062 : 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        2962 :         struct sockaddr_in srv_addr;
     103        2962 :         struct in_addr my_ip;
     104        2962 :         struct in_addr srv_ip;
     105        2962 :         int ret;
     106             : 
     107      101062 :         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      101062 :         } else if (my_address) {
     113         480 :                 my_ip = interpret_addr2(my_address->addr);
     114             :                 
     115         480 :                 if (my_ip.s_addr != 0 || my_address->port != 0) {
     116           0 :                         struct sockaddr_in my_addr;
     117         480 :                         ZERO_STRUCT(my_addr);
     118             : #ifdef HAVE_SOCK_SIN_LEN
     119             :                         my_addr.sin_len         = sizeof(my_addr);
     120             : #endif
     121         480 :                         my_addr.sin_addr.s_addr = my_ip.s_addr;
     122         480 :                         my_addr.sin_port        = htons(my_address->port);
     123         480 :                         my_addr.sin_family      = PF_INET;
     124             :                         
     125         480 :                         ret = bind(sock->fd, (struct sockaddr *)&my_addr, sizeof(my_addr));
     126         480 :                         if (ret == -1) {
     127           0 :                                 return map_nt_error_from_unix_common(errno);
     128             :                         }
     129             :                 }
     130             :         }
     131             : 
     132      101062 :         if (srv_address->sockaddr) {
     133       47952 :                 ret = connect(sock->fd, srv_address->sockaddr, srv_address->sockaddrlen);
     134       47952 :                 if (ret == -1) {
     135           0 :                         return map_nt_error_from_unix_common(errno);
     136             :                 }
     137             :         } else {
     138       53110 :                 srv_ip = interpret_addr2(srv_address->addr);
     139       53110 :                 if (!srv_ip.s_addr) {
     140           0 :                         return NT_STATUS_BAD_NETWORK_NAME;
     141             :                 }
     142             : 
     143       53110 :                 SMB_ASSERT(srv_address->port != 0);
     144             :                 
     145       53110 :                 ZERO_STRUCT(srv_addr);
     146             : #ifdef HAVE_SOCK_SIN_LEN
     147             :                 srv_addr.sin_len        = sizeof(srv_addr);
     148             : #endif
     149       53110 :                 srv_addr.sin_addr.s_addr= srv_ip.s_addr;
     150       53110 :                 srv_addr.sin_port       = htons(srv_address->port);
     151       53110 :                 srv_addr.sin_family     = PF_INET;
     152             : 
     153       53110 :                 ret = connect(sock->fd, (const struct sockaddr *)&srv_addr, sizeof(srv_addr));
     154       53110 :                 if (ret == -1) {
     155           0 :                         return map_nt_error_from_unix_common(errno);
     156             :                 }
     157             :         }
     158             : 
     159      101062 :         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        1134 : static NTSTATUS ipv4_listen(struct socket_context *sock,
     168             :                             const struct socket_address *my_address, 
     169             :                             int queue_size, uint32_t flags)
     170             : {
     171          36 :         struct sockaddr_in my_addr;
     172          36 :         struct in_addr ip_addr;
     173          36 :         int ret;
     174             : 
     175        1134 :         socket_set_option(sock, "SO_REUSEADDR=1", NULL);
     176             : 
     177        1134 :         if (my_address->sockaddr) {
     178           0 :                 ret = bind(sock->fd, my_address->sockaddr, my_address->sockaddrlen);
     179             :         } else {
     180        1134 :                 ip_addr = interpret_addr2(my_address->addr);
     181             :                 
     182        1134 :                 ZERO_STRUCT(my_addr);
     183             : #ifdef HAVE_SOCK_SIN_LEN
     184             :                 my_addr.sin_len         = sizeof(my_addr);
     185             : #endif
     186        1134 :                 my_addr.sin_addr.s_addr = ip_addr.s_addr;
     187        1134 :                 my_addr.sin_port        = htons(my_address->port);
     188        1134 :                 my_addr.sin_family      = PF_INET;
     189             :                 
     190        1134 :                 ret = bind(sock->fd, (struct sockaddr *)&my_addr, sizeof(my_addr));
     191             :         }
     192             : 
     193        1134 :         if (ret == -1) {
     194           0 :                 return map_nt_error_from_unix_common(errno);
     195             :         }
     196             : 
     197        1134 :         if (sock->type == SOCKET_TYPE_STREAM) {
     198         700 :                 ret = listen(sock->fd, queue_size);
     199         700 :                 if (ret == -1) {
     200           0 :                         return map_nt_error_from_unix_common(errno);
     201             :                 }
     202             :         }
     203             : 
     204        1134 :         ret = set_blocking(sock->fd, false);
     205        1134 :         if (ret == -1) {
     206           0 :                 return map_nt_error_from_unix_common(errno);
     207             :         }
     208             : 
     209        1134 :         sock->state= SOCKET_STATE_SERVER_LISTEN;
     210             : 
     211        1134 :         return NT_STATUS_OK;
     212             : }
     213             : 
     214      148897 : static NTSTATUS ipv4_accept(struct socket_context *sock, struct socket_context **new_sock)
     215             : {
     216        3796 :         struct sockaddr_in cli_addr;
     217      148897 :         socklen_t cli_addr_len = sizeof(cli_addr);
     218        3796 :         int new_fd, ret;
     219             : 
     220      148897 :         if (sock->type != SOCKET_TYPE_STREAM) {
     221           0 :                 return NT_STATUS_INVALID_PARAMETER;
     222             :         }
     223             : 
     224      148897 :         new_fd = accept(sock->fd, (struct sockaddr *)&cli_addr, &cli_addr_len);
     225      148897 :         if (new_fd == -1) {
     226       28931 :                 return map_nt_error_from_unix_common(errno);
     227             :         }
     228             : 
     229      119966 :         ret = set_blocking(new_fd, false);
     230      119966 :         if (ret == -1) {
     231           0 :                 close(new_fd);
     232           0 :                 return map_nt_error_from_unix_common(errno);
     233             :         }
     234             : 
     235      119966 :         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      119966 :         (*new_sock) = talloc(NULL, struct socket_context);
     245      119966 :         if (!(*new_sock)) {
     246           0 :                 close(new_fd);
     247           0 :                 return NT_STATUS_NO_MEMORY;
     248             :         }
     249             : 
     250             :         /* copy the socket_context */
     251      119966 :         (*new_sock)->type            = sock->type;
     252      119966 :         (*new_sock)->state           = SOCKET_STATE_SERVER_CONNECTED;
     253      119966 :         (*new_sock)->flags           = sock->flags;
     254             : 
     255      119966 :         (*new_sock)->fd                      = new_fd;
     256             : 
     257      119966 :         (*new_sock)->private_data    = NULL;
     258      119966 :         (*new_sock)->ops             = sock->ops;
     259      119966 :         (*new_sock)->backend_name    = sock->backend_name;
     260             : 
     261      119966 :         return NT_STATUS_OK;
     262             : }
     263             : 
     264     1787687 : static NTSTATUS ip_recv(struct socket_context *sock, void *buf, 
     265             :                               size_t wantlen, size_t *nread)
     266             : {
     267        2368 :         ssize_t gotlen;
     268             : 
     269     1787687 :         *nread = 0;
     270             : 
     271     1787687 :         gotlen = recv(sock->fd, buf, wantlen, 0);
     272     1787687 :         if (gotlen == 0) {
     273        1871 :                 return NT_STATUS_END_OF_FILE;
     274     1785816 :         } else if (gotlen == -1) {
     275         120 :                 return map_nt_error_from_unix_common(errno);
     276             :         }
     277             : 
     278     1785696 :         *nread = gotlen;
     279             : 
     280     1785696 :         return NT_STATUS_OK;
     281             : }
     282             : 
     283             : 
     284       14752 : 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         133 :         ssize_t gotlen;
     289         133 :         struct sockaddr_in *from_addr;
     290       14752 :         socklen_t from_len = sizeof(*from_addr);
     291         133 :         struct socket_address *src;
     292         133 :         char addrstring[INET_ADDRSTRLEN];
     293             :         
     294       14752 :         src = talloc(addr_ctx, struct socket_address);
     295       14752 :         if (!src) {
     296           0 :                 return NT_STATUS_NO_MEMORY;
     297             :         }
     298             :         
     299       14752 :         src->family = sock->backend_name;
     300             : 
     301       14752 :         from_addr = talloc(src, struct sockaddr_in);
     302       14752 :         if (!from_addr) {
     303           0 :                 talloc_free(src);
     304           0 :                 return NT_STATUS_NO_MEMORY;
     305             :         }
     306             : 
     307       14752 :         src->sockaddr = (struct sockaddr *)from_addr;
     308             : 
     309       14752 :         *nread = 0;
     310             : 
     311       14752 :         gotlen = recvfrom(sock->fd, buf, wantlen, 0, 
     312       14619 :                           src->sockaddr, &from_len);
     313       14752 :         if (gotlen == 0) {
     314           2 :                 talloc_free(src);
     315           2 :                 return NT_STATUS_END_OF_FILE;
     316             :         }
     317       14750 :         if (gotlen == -1) {
     318           0 :                 talloc_free(src);
     319           0 :                 return map_nt_error_from_unix_common(errno);
     320             :         }
     321             : 
     322       14750 :         src->sockaddrlen = from_len;
     323             : 
     324       14750 :         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       14750 :         src->addr = talloc_strdup(src, addrstring);
     330       14750 :         if (src->addr == NULL) {
     331           0 :                 talloc_free(src);
     332           0 :                 return NT_STATUS_NO_MEMORY;
     333             :         }
     334       14750 :         src->port = ntohs(from_addr->sin_port);
     335             : 
     336       14750 :         *nread  = gotlen;
     337       14750 :         *_src   = src;
     338       14750 :         return NT_STATUS_OK;
     339             : }
     340             : 
     341    17401604 : static NTSTATUS ip_send(struct socket_context *sock, 
     342             :                               const DATA_BLOB *blob, size_t *sendlen)
     343             : {
     344        1756 :         ssize_t len;
     345             : 
     346    17401604 :         *sendlen = 0;
     347             : 
     348    17401604 :         len = send(sock->fd, blob->data, blob->length, 0);
     349    17401604 :         if (len == -1) {
     350    16431733 :                 return map_nt_error_from_unix_common(errno);
     351             :         }       
     352             : 
     353      969871 :         *sendlen = len;
     354             : 
     355      969871 :         return NT_STATUS_OK;
     356             : }
     357             : 
     358       14057 : 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         120 :         ssize_t len;
     363             : 
     364       14057 :         if (dest_addr->sockaddr) {
     365        1646 :                 len = sendto(sock->fd, blob->data, blob->length, 0, 
     366        1646 :                              dest_addr->sockaddr, dest_addr->sockaddrlen);
     367             :         } else {
     368          93 :                 struct sockaddr_in srv_addr;
     369          93 :                 struct in_addr addr;
     370             : 
     371       12411 :                 SMB_ASSERT(dest_addr->port != 0);
     372             :                 
     373       12411 :                 ZERO_STRUCT(srv_addr);
     374             : #ifdef HAVE_SOCK_SIN_LEN
     375             :                 srv_addr.sin_len         = sizeof(srv_addr);
     376             : #endif
     377       12411 :                 addr                     = interpret_addr2(dest_addr->addr);
     378       12411 :                 if (addr.s_addr == 0) {
     379          65 :                         return NT_STATUS_HOST_UNREACHABLE;
     380             :                 }
     381       12346 :                 srv_addr.sin_addr.s_addr = addr.s_addr;
     382       12346 :                 srv_addr.sin_port        = htons(dest_addr->port);
     383       12346 :                 srv_addr.sin_family      = PF_INET;
     384             :                 
     385       12346 :                 *sendlen = 0;
     386             :                 
     387       12346 :                 len = sendto(sock->fd, blob->data, blob->length, 0, 
     388             :                              (struct sockaddr *)&srv_addr, sizeof(srv_addr));
     389             :         }
     390       13992 :         if (len == -1) {
     391        9095 :                 return map_nt_error_from_unix_common(errno);
     392             :         }       
     393             : 
     394        4897 :         *sendlen = len;
     395             : 
     396        4897 :         return NT_STATUS_OK;
     397             : }
     398             : 
     399       28025 : static NTSTATUS ipv4_set_option(struct socket_context *sock, const char *option, const char *val)
     400             : {
     401       28025 :         set_socket_options(sock->fd, option);
     402       28025 :         return NT_STATUS_OK;
     403             : }
     404             : 
     405           0 : static char *ipv4_get_peer_name(struct socket_context *sock, TALLOC_CTX *mem_ctx)
     406             : {
     407           0 :         struct sockaddr_in peer_addr;
     408           0 :         socklen_t len = sizeof(peer_addr);
     409           0 :         struct hostent *he;
     410           0 :         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      138294 : static struct socket_address *ipv4_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
     426             : {
     427        2608 :         struct sockaddr_in *peer_addr;
     428      138294 :         socklen_t len = sizeof(*peer_addr);
     429        2608 :         struct socket_address *peer;
     430        2608 :         char addrstring[INET_ADDRSTRLEN];
     431        2608 :         int ret;
     432             :         
     433      138294 :         peer = talloc(mem_ctx, struct socket_address);
     434      138294 :         if (!peer) {
     435           0 :                 return NULL;
     436             :         }
     437             :         
     438      138294 :         peer->family = sock->backend_name;
     439      138294 :         peer_addr = talloc(peer, struct sockaddr_in);
     440      138294 :         if (!peer_addr) {
     441           0 :                 talloc_free(peer);
     442           0 :                 return NULL;
     443             :         }
     444             : 
     445      138294 :         peer->sockaddr = (struct sockaddr *)peer_addr;
     446             : 
     447      138294 :         ret = getpeername(sock->fd, peer->sockaddr, &len);
     448      138294 :         if (ret == -1) {
     449           0 :                 talloc_free(peer);
     450           0 :                 return NULL;
     451             :         }
     452             : 
     453      138294 :         peer->sockaddrlen = len;
     454             : 
     455      138294 :         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      138294 :         peer->addr = talloc_strdup(peer, addrstring);
     461      138294 :         if (!peer->addr) {
     462           0 :                 talloc_free(peer);
     463           0 :                 return NULL;
     464             :         }
     465      138294 :         peer->port = ntohs(peer_addr->sin_port);
     466             : 
     467      138294 :         return peer;
     468             : }
     469             : 
     470      176320 : static struct socket_address *ipv4_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
     471             : {
     472        2973 :         struct sockaddr_in *local_addr;
     473      176320 :         socklen_t len = sizeof(*local_addr);
     474        2973 :         struct socket_address *local;
     475        2973 :         char addrstring[INET_ADDRSTRLEN];
     476        2973 :         int ret;
     477             :         
     478      176320 :         local = talloc(mem_ctx, struct socket_address);
     479      176320 :         if (!local) {
     480           0 :                 return NULL;
     481             :         }
     482             :         
     483      176320 :         local->family = sock->backend_name;
     484      176320 :         local_addr = talloc(local, struct sockaddr_in);
     485      176320 :         if (!local_addr) {
     486           0 :                 talloc_free(local);
     487           0 :                 return NULL;
     488             :         }
     489             : 
     490      176320 :         local->sockaddr = (struct sockaddr *)local_addr;
     491             : 
     492      176320 :         ret = getsockname(sock->fd, local->sockaddr, &len);
     493      176320 :         if (ret == -1) {
     494           0 :                 talloc_free(local);
     495           0 :                 return NULL;
     496             :         }
     497             : 
     498      176320 :         local->sockaddrlen = len;
     499             : 
     500      176320 :         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      176320 :         local->addr = talloc_strdup(local, addrstring);
     506      176320 :         if (!local->addr) {
     507           0 :                 talloc_free(local);
     508           0 :                 return NULL;
     509             :         }
     510      176320 :         local->port = ntohs(local_addr->sin_port);
     511             : 
     512      176320 :         return local;
     513             : }
     514      673016 : static int ip_get_fd(struct socket_context *sock)
     515             : {
     516      673016 :         return sock->fd;
     517             : }
     518             : 
     519       62713 : static NTSTATUS ip_pending(struct socket_context *sock, size_t *npending)
     520             : {
     521       62713 :         int value = 0;
     522       62713 :         if (ioctl(sock->fd, FIONREAD, &value) == 0) {
     523       62713 :                 *npending = value;
     524       62713 :                 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      111733 : _PUBLIC_ const struct socket_ops *socket_ipv4_ops(enum socket_type type)
     553             : {
     554      111733 :         return &ipv4_ops;
     555             : }
     556             : 
     557             : #ifdef HAVE_IPV6
     558             : 
     559         752 : static struct in6_addr interpret_addr6(const char *name)
     560             : {
     561          20 :         char addr[INET6_ADDRSTRLEN];
     562          20 :         struct in6_addr dest6;
     563         752 :         const char *sp = name;
     564          20 :         char *p;
     565          20 :         int ret;
     566             : 
     567         752 :         if (sp == NULL) return in6addr_any;
     568             : 
     569         752 :         p = strchr_m(sp, '%');
     570             : 
     571         752 :         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         752 :         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         752 :         ret = inet_pton(AF_INET6, sp, &dest6);
     588         752 :         if (ret > 0) {
     589         752 :                 return dest6;
     590             :         }
     591             : 
     592           0 :         return in6addr_any;
     593             : }
     594             : 
     595         752 : static NTSTATUS ipv6_init(struct socket_context *sock)
     596             : {
     597          20 :         int type;
     598             : 
     599         752 :         switch (sock->type) {
     600         732 :         case SOCKET_TYPE_STREAM:
     601         732 :                 type = SOCK_STREAM;
     602         732 :                 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         752 :         sock->fd = socket(PF_INET6, type, 0);
     611         752 :         if (sock->fd == -1) {
     612           0 :                 return map_nt_error_from_unix_common(errno);
     613             :         }
     614             : 
     615         752 :         smb_set_close_on_exec(sock->fd);
     616             : 
     617         752 :         sock->backend_name = "ipv6";
     618         752 :         sock->family = AF_INET6;
     619             : 
     620         752 :         return NT_STATUS_OK;
     621             : }
     622             : 
     623         122 : 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           0 :         int ret;
     629             : 
     630         122 :         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         122 :         } else if (my_address) {
     636           0 :                 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           0 :                         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         122 :         if (srv_address->sockaddr) {
     654           0 :                 ret = connect(sock->fd, srv_address->sockaddr, srv_address->sockaddrlen);
     655             :         } else {
     656           0 :                 struct in6_addr srv_ip;
     657           0 :                 struct sockaddr_in6 srv_addr;
     658         122 :                 srv_ip = interpret_addr6(srv_address->addr);
     659         122 :                 if (memcmp(&srv_ip, &in6addr_any, sizeof(srv_ip)) == 0) {
     660           0 :                         return NT_STATUS_BAD_NETWORK_NAME;
     661             :                 }
     662             :                 
     663         122 :                 ZERO_STRUCT(srv_addr);
     664         122 :                 srv_addr.sin6_addr      = srv_ip;
     665         122 :                 srv_addr.sin6_port      = htons(srv_address->port);
     666         122 :                 srv_addr.sin6_family    = PF_INET6;
     667             :                 
     668         122 :                 ret = connect(sock->fd, (const struct sockaddr *)&srv_addr, sizeof(srv_addr));
     669             :         }
     670         122 :         if (ret == -1) {
     671           0 :                 return map_nt_error_from_unix_common(errno);
     672             :         }
     673             : 
     674         122 :         return ip_connect_complete(sock, flags);
     675             : }
     676             : 
     677             : /*
     678             :   fix the sin6_scope_id based on the address interface
     679             :  */
     680         630 : static void fix_scope_id(struct sockaddr_in6 *in6,
     681             :                          const char *address)
     682             : {
     683         630 :         const char *p = strchr(address, '%');
     684         630 :         if (p != NULL) {
     685           0 :                 in6->sin6_scope_id = if_nametoindex(p+1);
     686             :         }
     687         630 : }
     688             : 
     689             : 
     690         630 : static NTSTATUS ipv6_listen(struct socket_context *sock,
     691             :                             const struct socket_address *my_address,
     692             :                             int queue_size, uint32_t flags)
     693             : {
     694          20 :         struct sockaddr_in6 my_addr;
     695          20 :         struct in6_addr ip_addr;
     696          20 :         int ret;
     697             : 
     698         630 :         socket_set_option(sock, "SO_REUSEADDR=1", NULL);
     699             : 
     700         630 :         if (my_address->sockaddr) {
     701           0 :                 ret = bind(sock->fd, my_address->sockaddr, my_address->sockaddrlen);
     702             :         } else {
     703         630 :                 int one = 1;
     704         630 :                 ip_addr = interpret_addr6(my_address->addr);
     705             :                 
     706         630 :                 ZERO_STRUCT(my_addr);
     707         630 :                 my_addr.sin6_addr       = ip_addr;
     708         630 :                 my_addr.sin6_port       = htons(my_address->port);
     709         630 :                 my_addr.sin6_family     = PF_INET6;
     710         630 :                 fix_scope_id(&my_addr, my_address->addr);
     711             : 
     712             :                 /* when binding on ipv6 we always want to only bind on v6 */
     713         630 :                 ret = setsockopt(sock->fd, IPPROTO_IPV6, IPV6_V6ONLY,
     714             :                                  (const void *)&one, sizeof(one));
     715         630 :                 if (ret != -1) {
     716         630 :                         ret = bind(sock->fd, (struct sockaddr *)&my_addr, sizeof(my_addr));
     717             :                 }
     718             :         }
     719             : 
     720         630 :         if (ret == -1) {
     721           0 :                 return map_nt_error_from_unix_common(errno);
     722             :         }
     723             : 
     724         630 :         if (sock->type == SOCKET_TYPE_STREAM) {
     725         630 :                 ret = listen(sock->fd, queue_size);
     726         630 :                 if (ret == -1) {
     727           0 :                         return map_nt_error_from_unix_common(errno);
     728             :                 }
     729             :         }
     730             : 
     731         630 :         ret = set_blocking(sock->fd, false);
     732         630 :         if (ret == -1) {
     733           0 :                 return map_nt_error_from_unix_common(errno);
     734             :         }
     735             : 
     736         630 :         sock->state= SOCKET_STATE_SERVER_LISTEN;
     737             : 
     738         630 :         return NT_STATUS_OK;
     739             : }
     740             : 
     741          48 : static NTSTATUS ipv6_tcp_accept(struct socket_context *sock, struct socket_context **new_sock)
     742             : {
     743           0 :         struct sockaddr_in6 cli_addr;
     744          48 :         socklen_t cli_addr_len = sizeof(cli_addr);
     745           0 :         int new_fd, ret;
     746             :         
     747          48 :         if (sock->type != SOCKET_TYPE_STREAM) {
     748           0 :                 return NT_STATUS_INVALID_PARAMETER;
     749             :         }
     750             : 
     751          48 :         new_fd = accept(sock->fd, (struct sockaddr *)&cli_addr, &cli_addr_len);
     752          48 :         if (new_fd == -1) {
     753           2 :                 return map_nt_error_from_unix_common(errno);
     754             :         }
     755             : 
     756          46 :         ret = set_blocking(new_fd, false);
     757          46 :         if (ret == -1) {
     758           0 :                 close(new_fd);
     759           0 :                 return map_nt_error_from_unix_common(errno);
     760             :         }
     761          46 :         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          46 :         (*new_sock) = talloc(NULL, struct socket_context);
     770          46 :         if (!(*new_sock)) {
     771           0 :                 close(new_fd);
     772           0 :                 return NT_STATUS_NO_MEMORY;
     773             :         }
     774             : 
     775             :         /* copy the socket_context */
     776          46 :         (*new_sock)->type            = sock->type;
     777          46 :         (*new_sock)->state           = SOCKET_STATE_SERVER_CONNECTED;
     778          46 :         (*new_sock)->flags           = sock->flags;
     779             : 
     780          46 :         (*new_sock)->fd                      = new_fd;
     781             : 
     782          46 :         (*new_sock)->private_data    = NULL;
     783          46 :         (*new_sock)->ops             = sock->ops;
     784          46 :         (*new_sock)->backend_name    = sock->backend_name;
     785             : 
     786          46 :         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           0 :         ssize_t gotlen;
     794           0 :         struct sockaddr_in6 *from_addr;
     795           0 :         socklen_t from_len = sizeof(*from_addr);
     796           0 :         struct socket_address *src;
     797           0 :         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           0 :         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           0 :                 struct sockaddr_in6 srv_addr;
     857           0 :                 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        1944 : static NTSTATUS ipv6_set_option(struct socket_context *sock, const char *option, const char *val)
     884             : {
     885        1944 :         set_socket_options(sock->fd, option);
     886        1944 :         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           0 :         struct sockaddr_in6 peer_addr;
     892           0 :         socklen_t len = sizeof(peer_addr);
     893           0 :         struct hostent *he;
     894           0 :         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          56 : static struct socket_address *ipv6_tcp_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
     910             : {
     911           0 :         struct sockaddr_in6 *peer_addr;
     912          56 :         socklen_t len = sizeof(*peer_addr);
     913           0 :         struct socket_address *peer;
     914           0 :         int ret;
     915           0 :         char addr[128];
     916           0 :         const char *addr_ret;
     917             :         
     918          56 :         peer = talloc(mem_ctx, struct socket_address);
     919          56 :         if (!peer) {
     920           0 :                 return NULL;
     921             :         }
     922             :         
     923          56 :         peer->family = sock->backend_name;
     924          56 :         peer_addr = talloc(peer, struct sockaddr_in6);
     925          56 :         if (!peer_addr) {
     926           0 :                 talloc_free(peer);
     927           0 :                 return NULL;
     928             :         }
     929             : 
     930          56 :         peer->sockaddr = (struct sockaddr *)peer_addr;
     931             : 
     932          56 :         ret = getpeername(sock->fd, peer->sockaddr, &len);
     933          56 :         if (ret == -1) {
     934           0 :                 talloc_free(peer);
     935           0 :                 return NULL;
     936             :         }
     937             : 
     938          56 :         peer->sockaddrlen = len;
     939             : 
     940          56 :         addr_ret = inet_ntop(AF_INET6, &peer_addr->sin6_addr, addr, sizeof(addr));
     941          56 :         if (addr_ret == NULL) {
     942           0 :                 talloc_free(peer);
     943           0 :                 return NULL;
     944             :         }
     945             : 
     946          56 :         peer->addr = talloc_strdup(peer, addr_ret);
     947          56 :         if (peer->addr == NULL) {
     948           0 :                 talloc_free(peer);
     949           0 :                 return NULL;
     950             :         }
     951             : 
     952          56 :         peer->port = ntohs(peer_addr->sin6_port);
     953             : 
     954          56 :         return peer;
     955             : }
     956             : 
     957          77 : static struct socket_address *ipv6_tcp_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
     958             : {
     959           0 :         struct sockaddr_in6 *local_addr;
     960          77 :         socklen_t len = sizeof(*local_addr);
     961           0 :         struct socket_address *local;
     962           0 :         int ret;
     963           0 :         char addrstring[INET6_ADDRSTRLEN];
     964             :         
     965          77 :         local = talloc(mem_ctx, struct socket_address);
     966          77 :         if (!local) {
     967           0 :                 return NULL;
     968             :         }
     969             :         
     970          77 :         local->family = sock->backend_name;
     971          77 :         local_addr = talloc(local, struct sockaddr_in6);
     972          77 :         if (!local_addr) {
     973           0 :                 talloc_free(local);
     974           0 :                 return NULL;
     975             :         }
     976             : 
     977          77 :         local->sockaddr = (struct sockaddr *)local_addr;
     978             : 
     979          77 :         ret = getsockname(sock->fd, local->sockaddr, &len);
     980          77 :         if (ret == -1) {
     981           0 :                 talloc_free(local);
     982           0 :                 return NULL;
     983             :         }
     984             : 
     985          77 :         local->sockaddrlen = len;
     986             : 
     987          77 :         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          77 :         local->addr = talloc_strdup(local, addrstring);
     996          77 :         if (!local->addr) {
     997           0 :                 talloc_free(local);
     998           0 :                 return NULL;
     999             :         }
    1000          77 :         local->port = ntohs(local_addr->sin6_port);
    1001             : 
    1002          77 :         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         752 : _PUBLIC_ const struct socket_ops *socket_ipv6_ops(enum socket_type type)
    1029             : {
    1030         752 :         return &ipv6_tcp_ops;
    1031             : }
    1032             : 
    1033             : #endif

Generated by: LCOV version 1.14