LCOV - code coverage report
Current view: top level - source4/lib/socket - socket_ip.c (source / functions) Hit Total Coverage
Test: coverage report for support-claim-type-attributes 6b5c566e Lines: 340 543 62.6 %
Date: 2023-11-21 12:31:41 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      108374 : static NTSTATUS ipv4_init(struct socket_context *sock)
      36             : {
      37        3027 :         int type;
      38             : 
      39      108374 :         switch (sock->type) {
      40       75669 :         case SOCKET_TYPE_STREAM:
      41       75669 :                 type = SOCK_STREAM;
      42       75669 :                 break;
      43       30890 :         case SOCKET_TYPE_DGRAM:
      44       30890 :                 type = SOCK_DGRAM;
      45       30890 :                 break;
      46           0 :         default:
      47           0 :                 return NT_STATUS_INVALID_PARAMETER;
      48             :         }
      49             : 
      50      108374 :         sock->fd = socket(PF_INET, type, 0);
      51      108374 :         if (sock->fd == -1) {
      52           0 :                 return map_nt_error_from_unix_common(errno);
      53             :         }
      54             : 
      55      108374 :         smb_set_close_on_exec(sock->fd);
      56             : 
      57      108374 :         sock->backend_name = "ipv4";
      58      108374 :         sock->family = AF_INET;
      59             : 
      60      108374 :         return NT_STATUS_OK;
      61             : }
      62             : 
      63      119167 : static void ip_close(struct socket_context *sock)
      64             : {
      65      119167 :         if (sock->fd != -1) {
      66      103503 :                 close(sock->fd);
      67      103503 :                 sock->fd = -1;
      68             :         }
      69      119167 : }
      70             : 
      71      747136 : static NTSTATUS ip_connect_complete(struct socket_context *sock, uint32_t flags)
      72             : {
      73      747136 :         int error=0, ret;
      74      747136 :         socklen_t len = sizeof(error);
      75             : 
      76             :         /* check for any errors that may have occurred - this is needed
      77             :            for non-blocking connect */
      78      747136 :         ret = getsockopt(sock->fd, SOL_SOCKET, SO_ERROR, &error, &len);
      79      747136 :         if (ret == -1) {
      80           0 :                 return map_nt_error_from_unix_common(errno);
      81             :         }
      82      747136 :         if (error != 0) {
      83           0 :                 return map_nt_error_from_unix_common(error);
      84             :         }
      85             : 
      86      747136 :         ret = set_blocking(sock->fd, false);
      87      747136 :         if (ret == -1) {
      88           0 :                 return map_nt_error_from_unix_common(errno);
      89             :         }
      90             : 
      91      747136 :         sock->state = SOCKET_STATE_CLIENT_CONNECTED;
      92             : 
      93      747136 :         return NT_STATUS_OK;
      94             : }
      95             : 
      96             : 
      97       97804 : 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       97804 :         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       97804 :         } else if (my_address) {
     113         472 :                 my_ip = interpret_addr2(my_address->addr);
     114             :                 
     115         472 :                 if (my_ip.s_addr != 0 || my_address->port != 0) {
     116           0 :                         struct sockaddr_in my_addr;
     117         472 :                         ZERO_STRUCT(my_addr);
     118             : #ifdef HAVE_SOCK_SIN_LEN
     119             :                         my_addr.sin_len         = sizeof(my_addr);
     120             : #endif
     121         472 :                         my_addr.sin_addr.s_addr = my_ip.s_addr;
     122         472 :                         my_addr.sin_port        = htons(my_address->port);
     123         472 :                         my_addr.sin_family      = PF_INET;
     124             :                         
     125         472 :                         ret = bind(sock->fd, (struct sockaddr *)&my_addr, sizeof(my_addr));
     126         472 :                         if (ret == -1) {
     127           0 :                                 return map_nt_error_from_unix_common(errno);
     128             :                         }
     129             :                 }
     130             :         }
     131             : 
     132       97804 :         if (srv_address->sockaddr) {
     133       45169 :                 ret = connect(sock->fd, srv_address->sockaddr, srv_address->sockaddrlen);
     134       45169 :                 if (ret == -1) {
     135           0 :                         return map_nt_error_from_unix_common(errno);
     136             :                 }
     137             :         } else {
     138       52635 :                 srv_ip = interpret_addr2(srv_address->addr);
     139       52635 :                 if (!srv_ip.s_addr) {
     140           0 :                         return NT_STATUS_BAD_NETWORK_NAME;
     141             :                 }
     142             : 
     143       52635 :                 SMB_ASSERT(srv_address->port != 0);
     144             :                 
     145       52635 :                 ZERO_STRUCT(srv_addr);
     146             : #ifdef HAVE_SOCK_SIN_LEN
     147             :                 srv_addr.sin_len        = sizeof(srv_addr);
     148             : #endif
     149       52635 :                 srv_addr.sin_addr.s_addr= srv_ip.s_addr;
     150       52635 :                 srv_addr.sin_port       = htons(srv_address->port);
     151       52635 :                 srv_addr.sin_family     = PF_INET;
     152             : 
     153       52635 :                 ret = connect(sock->fd, (const struct sockaddr *)&srv_addr, sizeof(srv_addr));
     154       52635 :                 if (ret == -1) {
     155           0 :                         return map_nt_error_from_unix_common(errno);
     156             :                 }
     157             :         }
     158             : 
     159       97804 :         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      143136 : static NTSTATUS ipv4_accept(struct socket_context *sock, struct socket_context **new_sock)
     215             : {
     216        3859 :         struct sockaddr_in cli_addr;
     217      143136 :         socklen_t cli_addr_len = sizeof(cli_addr);
     218        3859 :         int new_fd, ret;
     219             : 
     220      143136 :         if (sock->type != SOCKET_TYPE_STREAM) {
     221           0 :                 return NT_STATUS_INVALID_PARAMETER;
     222             :         }
     223             : 
     224      143136 :         new_fd = accept(sock->fd, (struct sockaddr *)&cli_addr, &cli_addr_len);
     225      143136 :         if (new_fd == -1) {
     226       26136 :                 return map_nt_error_from_unix_common(errno);
     227             :         }
     228             : 
     229      117000 :         ret = set_blocking(new_fd, false);
     230      117000 :         if (ret == -1) {
     231           0 :                 close(new_fd);
     232           0 :                 return map_nt_error_from_unix_common(errno);
     233             :         }
     234             : 
     235      117000 :         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      117000 :         (*new_sock) = talloc(NULL, struct socket_context);
     245      117000 :         if (!(*new_sock)) {
     246           0 :                 close(new_fd);
     247           0 :                 return NT_STATUS_NO_MEMORY;
     248             :         }
     249             : 
     250             :         /* copy the socket_context */
     251      117000 :         (*new_sock)->type            = sock->type;
     252      117000 :         (*new_sock)->state           = SOCKET_STATE_SERVER_CONNECTED;
     253      117000 :         (*new_sock)->flags           = sock->flags;
     254             : 
     255      117000 :         (*new_sock)->fd                      = new_fd;
     256             : 
     257      117000 :         (*new_sock)->private_data    = NULL;
     258      117000 :         (*new_sock)->ops             = sock->ops;
     259      117000 :         (*new_sock)->backend_name    = sock->backend_name;
     260             : 
     261      117000 :         return NT_STATUS_OK;
     262             : }
     263             : 
     264     1781292 : 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     1781292 :         *nread = 0;
     270             : 
     271     1781292 :         gotlen = recv(sock->fd, buf, wantlen, 0);
     272     1781292 :         if (gotlen == 0) {
     273        1873 :                 return NT_STATUS_END_OF_FILE;
     274     1779419 :         } else if (gotlen == -1) {
     275         213 :                 return map_nt_error_from_unix_common(errno);
     276             :         }
     277             : 
     278     1779206 :         *nread = gotlen;
     279             : 
     280     1779206 :         return NT_STATUS_OK;
     281             : }
     282             : 
     283             : 
     284       13916 : 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       13916 :         socklen_t from_len = sizeof(*from_addr);
     291         133 :         struct socket_address *src;
     292         133 :         char addrstring[INET_ADDRSTRLEN];
     293             :         
     294       13916 :         src = talloc(addr_ctx, struct socket_address);
     295       13916 :         if (!src) {
     296           0 :                 return NT_STATUS_NO_MEMORY;
     297             :         }
     298             :         
     299       13916 :         src->family = sock->backend_name;
     300             : 
     301       13916 :         from_addr = talloc(src, struct sockaddr_in);
     302       13916 :         if (!from_addr) {
     303           0 :                 talloc_free(src);
     304           0 :                 return NT_STATUS_NO_MEMORY;
     305             :         }
     306             : 
     307       13916 :         src->sockaddr = (struct sockaddr *)from_addr;
     308             : 
     309       13916 :         *nread = 0;
     310             : 
     311       13916 :         gotlen = recvfrom(sock->fd, buf, wantlen, 0, 
     312       13783 :                           src->sockaddr, &from_len);
     313       13916 :         if (gotlen == 0) {
     314           2 :                 talloc_free(src);
     315           2 :                 return NT_STATUS_END_OF_FILE;
     316             :         }
     317       13914 :         if (gotlen == -1) {
     318           0 :                 talloc_free(src);
     319           0 :                 return map_nt_error_from_unix_common(errno);
     320             :         }
     321             : 
     322       13914 :         src->sockaddrlen = from_len;
     323             : 
     324       13914 :         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       13914 :         src->addr = talloc_strdup(src, addrstring);
     330       13914 :         if (src->addr == NULL) {
     331           0 :                 talloc_free(src);
     332           0 :                 return NT_STATUS_NO_MEMORY;
     333             :         }
     334       13914 :         src->port = ntohs(from_addr->sin_port);
     335             : 
     336       13914 :         *nread  = gotlen;
     337       13914 :         *_src   = src;
     338       13914 :         return NT_STATUS_OK;
     339             : }
     340             : 
     341    16017151 : static NTSTATUS ip_send(struct socket_context *sock, 
     342             :                               const DATA_BLOB *blob, size_t *sendlen)
     343             : {
     344        1756 :         ssize_t len;
     345             : 
     346    16017151 :         *sendlen = 0;
     347             : 
     348    16017151 :         len = send(sock->fd, blob->data, blob->length, 0);
     349    16017151 :         if (len == -1) {
     350    15050650 :                 return map_nt_error_from_unix_common(errno);
     351             :         }       
     352             : 
     353      966501 :         *sendlen = len;
     354             : 
     355      966501 :         return NT_STATUS_OK;
     356             : }
     357             : 
     358       13927 : 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       13927 :         if (dest_addr->sockaddr) {
     365        1642 :                 len = sendto(sock->fd, blob->data, blob->length, 0, 
     366        1642 :                              dest_addr->sockaddr, dest_addr->sockaddrlen);
     367             :         } else {
     368          93 :                 struct sockaddr_in srv_addr;
     369          93 :                 struct in_addr addr;
     370             : 
     371       12285 :                 SMB_ASSERT(dest_addr->port != 0);
     372             :                 
     373       12285 :                 ZERO_STRUCT(srv_addr);
     374             : #ifdef HAVE_SOCK_SIN_LEN
     375             :                 srv_addr.sin_len         = sizeof(srv_addr);
     376             : #endif
     377       12285 :                 addr                     = interpret_addr2(dest_addr->addr);
     378       12285 :                 if (addr.s_addr == 0) {
     379          66 :                         return NT_STATUS_HOST_UNREACHABLE;
     380             :                 }
     381       12219 :                 srv_addr.sin_addr.s_addr = addr.s_addr;
     382       12219 :                 srv_addr.sin_port        = htons(dest_addr->port);
     383       12219 :                 srv_addr.sin_family      = PF_INET;
     384             :                 
     385       12219 :                 *sendlen = 0;
     386             :                 
     387       12219 :                 len = sendto(sock->fd, blob->data, blob->length, 0, 
     388             :                              (struct sockaddr *)&srv_addr, sizeof(srv_addr));
     389             :         }
     390       13861 :         if (len == -1) {
     391        8989 :                 return map_nt_error_from_unix_common(errno);
     392             :         }       
     393             : 
     394        4872 :         *sendlen = len;
     395             : 
     396        4872 :         return NT_STATUS_OK;
     397             : }
     398             : 
     399       27886 : static NTSTATUS ipv4_set_option(struct socket_context *sock, const char *option, const char *val)
     400             : {
     401       27886 :         set_socket_options(sock->fd, option);
     402       27886 :         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      135271 : 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      135271 :         socklen_t len = sizeof(*peer_addr);
     429        2608 :         struct socket_address *peer;
     430        2608 :         char addrstring[INET_ADDRSTRLEN];
     431        2608 :         int ret;
     432             :         
     433      135271 :         peer = talloc(mem_ctx, struct socket_address);
     434      135271 :         if (!peer) {
     435           0 :                 return NULL;
     436             :         }
     437             :         
     438      135271 :         peer->family = sock->backend_name;
     439      135271 :         peer_addr = talloc(peer, struct sockaddr_in);
     440      135271 :         if (!peer_addr) {
     441           0 :                 talloc_free(peer);
     442           0 :                 return NULL;
     443             :         }
     444             : 
     445      135271 :         peer->sockaddr = (struct sockaddr *)peer_addr;
     446             : 
     447      135271 :         ret = getpeername(sock->fd, peer->sockaddr, &len);
     448      135271 :         if (ret == -1) {
     449           0 :                 talloc_free(peer);
     450           0 :                 return NULL;
     451             :         }
     452             : 
     453      135271 :         peer->sockaddrlen = len;
     454             : 
     455      135271 :         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      135271 :         peer->addr = talloc_strdup(peer, addrstring);
     461      135271 :         if (!peer->addr) {
     462           0 :                 talloc_free(peer);
     463           0 :                 return NULL;
     464             :         }
     465      135271 :         peer->port = ntohs(peer_addr->sin_port);
     466             : 
     467      135271 :         return peer;
     468             : }
     469             : 
     470      172806 : 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      172806 :         socklen_t len = sizeof(*local_addr);
     474        2973 :         struct socket_address *local;
     475        2973 :         char addrstring[INET_ADDRSTRLEN];
     476        2973 :         int ret;
     477             :         
     478      172806 :         local = talloc(mem_ctx, struct socket_address);
     479      172806 :         if (!local) {
     480           0 :                 return NULL;
     481             :         }
     482             :         
     483      172806 :         local->family = sock->backend_name;
     484      172806 :         local_addr = talloc(local, struct sockaddr_in);
     485      172806 :         if (!local_addr) {
     486           0 :                 talloc_free(local);
     487           0 :                 return NULL;
     488             :         }
     489             : 
     490      172806 :         local->sockaddr = (struct sockaddr *)local_addr;
     491             : 
     492      172806 :         ret = getsockname(sock->fd, local->sockaddr, &len);
     493      172806 :         if (ret == -1) {
     494           0 :                 talloc_free(local);
     495           0 :                 return NULL;
     496             :         }
     497             : 
     498      172806 :         local->sockaddrlen = len;
     499             : 
     500      172806 :         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      172806 :         local->addr = talloc_strdup(local, addrstring);
     506      172806 :         if (!local->addr) {
     507           0 :                 talloc_free(local);
     508           0 :                 return NULL;
     509             :         }
     510      172806 :         local->port = ntohs(local_addr->sin_port);
     511             : 
     512      172806 :         return local;
     513             : }
     514      653525 : static int ip_get_fd(struct socket_context *sock)
     515             : {
     516      653525 :         return sock->fd;
     517             : }
     518             : 
     519       59084 : static NTSTATUS ip_pending(struct socket_context *sock, size_t *npending)
     520             : {
     521       59084 :         int value = 0;
     522       59084 :         if (ioctl(sock->fd, FIONREAD, &value) == 0) {
     523       59084 :                 *npending = value;
     524       59084 :                 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      108374 : _PUBLIC_ const struct socket_ops *socket_ipv4_ops(enum socket_type type)
     553             : {
     554      108374 :         return &ipv4_ops;
     555             : }
     556             : 
     557             : #ifdef HAVE_IPV6
     558             : 
     559         747 : static struct in6_addr interpret_addr6(const char *name)
     560             : {
     561          20 :         char addr[INET6_ADDRSTRLEN];
     562          20 :         struct in6_addr dest6;
     563         747 :         const char *sp = name;
     564          20 :         char *p;
     565          20 :         int ret;
     566             : 
     567         747 :         if (sp == NULL) return in6addr_any;
     568             : 
     569         747 :         p = strchr_m(sp, '%');
     570             : 
     571         747 :         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         747 :         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         747 :         ret = inet_pton(AF_INET6, sp, &dest6);
     588         747 :         if (ret > 0) {
     589         747 :                 return dest6;
     590             :         }
     591             : 
     592           0 :         return in6addr_any;
     593             : }
     594             : 
     595         747 : static NTSTATUS ipv6_init(struct socket_context *sock)
     596             : {
     597          20 :         int type;
     598             : 
     599         747 :         switch (sock->type) {
     600         727 :         case SOCKET_TYPE_STREAM:
     601         727 :                 type = SOCK_STREAM;
     602         727 :                 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         747 :         sock->fd = socket(PF_INET6, type, 0);
     611         747 :         if (sock->fd == -1) {
     612           0 :                 return map_nt_error_from_unix_common(errno);
     613             :         }
     614             : 
     615         747 :         smb_set_close_on_exec(sock->fd);
     616             : 
     617         747 :         sock->backend_name = "ipv6";
     618         747 :         sock->family = AF_INET6;
     619             : 
     620         747 :         return NT_STATUS_OK;
     621             : }
     622             : 
     623         117 : 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         117 :         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         117 :         } 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         117 :         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         117 :                 srv_ip = interpret_addr6(srv_address->addr);
     659         117 :                 if (memcmp(&srv_ip, &in6addr_any, sizeof(srv_ip)) == 0) {
     660           0 :                         return NT_STATUS_BAD_NETWORK_NAME;
     661             :                 }
     662             :                 
     663         117 :                 ZERO_STRUCT(srv_addr);
     664         117 :                 srv_addr.sin6_addr      = srv_ip;
     665         117 :                 srv_addr.sin6_port      = htons(srv_address->port);
     666         117 :                 srv_addr.sin6_family    = PF_INET6;
     667             :                 
     668         117 :                 ret = connect(sock->fd, (const struct sockaddr *)&srv_addr, sizeof(srv_addr));
     669             :         }
     670         117 :         if (ret == -1) {
     671           0 :                 return map_nt_error_from_unix_common(errno);
     672             :         }
     673             : 
     674         117 :         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          53 : static NTSTATUS ipv6_tcp_accept(struct socket_context *sock, struct socket_context **new_sock)
     742             : {
     743           0 :         struct sockaddr_in6 cli_addr;
     744          53 :         socklen_t cli_addr_len = sizeof(cli_addr);
     745           0 :         int new_fd, ret;
     746             :         
     747          53 :         if (sock->type != SOCKET_TYPE_STREAM) {
     748           0 :                 return NT_STATUS_INVALID_PARAMETER;
     749             :         }
     750             : 
     751          53 :         new_fd = accept(sock->fd, (struct sockaddr *)&cli_addr, &cli_addr_len);
     752          53 :         if (new_fd == -1) {
     753           3 :                 return map_nt_error_from_unix_common(errno);
     754             :         }
     755             : 
     756          50 :         ret = set_blocking(new_fd, false);
     757          50 :         if (ret == -1) {
     758           0 :                 close(new_fd);
     759           0 :                 return map_nt_error_from_unix_common(errno);
     760             :         }
     761          50 :         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          50 :         (*new_sock) = talloc(NULL, struct socket_context);
     770          50 :         if (!(*new_sock)) {
     771           0 :                 close(new_fd);
     772           0 :                 return NT_STATUS_NO_MEMORY;
     773             :         }
     774             : 
     775             :         /* copy the socket_context */
     776          50 :         (*new_sock)->type            = sock->type;
     777          50 :         (*new_sock)->state           = SOCKET_STATE_SERVER_CONNECTED;
     778          50 :         (*new_sock)->flags           = sock->flags;
     779             : 
     780          50 :         (*new_sock)->fd                      = new_fd;
     781             : 
     782          50 :         (*new_sock)->private_data    = NULL;
     783          50 :         (*new_sock)->ops             = sock->ops;
     784          50 :         (*new_sock)->backend_name    = sock->backend_name;
     785             : 
     786          50 :         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          60 : 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          60 :         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          60 :         peer = talloc(mem_ctx, struct socket_address);
     919          60 :         if (!peer) {
     920           0 :                 return NULL;
     921             :         }
     922             :         
     923          60 :         peer->family = sock->backend_name;
     924          60 :         peer_addr = talloc(peer, struct sockaddr_in6);
     925          60 :         if (!peer_addr) {
     926           0 :                 talloc_free(peer);
     927           0 :                 return NULL;
     928             :         }
     929             : 
     930          60 :         peer->sockaddr = (struct sockaddr *)peer_addr;
     931             : 
     932          60 :         ret = getpeername(sock->fd, peer->sockaddr, &len);
     933          60 :         if (ret == -1) {
     934           0 :                 talloc_free(peer);
     935           0 :                 return NULL;
     936             :         }
     937             : 
     938          60 :         peer->sockaddrlen = len;
     939             : 
     940          60 :         addr_ret = inet_ntop(AF_INET6, &peer_addr->sin6_addr, addr, sizeof(addr));
     941          60 :         if (addr_ret == NULL) {
     942           0 :                 talloc_free(peer);
     943           0 :                 return NULL;
     944             :         }
     945             : 
     946          60 :         peer->addr = talloc_strdup(peer, addr_ret);
     947          60 :         if (peer->addr == NULL) {
     948           0 :                 talloc_free(peer);
     949           0 :                 return NULL;
     950             :         }
     951             : 
     952          60 :         peer->port = ntohs(peer_addr->sin6_port);
     953             : 
     954          60 :         return peer;
     955             : }
     956             : 
     957          81 : 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          81 :         socklen_t len = sizeof(*local_addr);
     961           0 :         struct socket_address *local;
     962           0 :         int ret;
     963           0 :         char addrstring[INET6_ADDRSTRLEN];
     964             :         
     965          81 :         local = talloc(mem_ctx, struct socket_address);
     966          81 :         if (!local) {
     967           0 :                 return NULL;
     968             :         }
     969             :         
     970          81 :         local->family = sock->backend_name;
     971          81 :         local_addr = talloc(local, struct sockaddr_in6);
     972          81 :         if (!local_addr) {
     973           0 :                 talloc_free(local);
     974           0 :                 return NULL;
     975             :         }
     976             : 
     977          81 :         local->sockaddr = (struct sockaddr *)local_addr;
     978             : 
     979          81 :         ret = getsockname(sock->fd, local->sockaddr, &len);
     980          81 :         if (ret == -1) {
     981           0 :                 talloc_free(local);
     982           0 :                 return NULL;
     983             :         }
     984             : 
     985          81 :         local->sockaddrlen = len;
     986             : 
     987          81 :         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          81 :         local->addr = talloc_strdup(local, addrstring);
     996          81 :         if (!local->addr) {
     997           0 :                 talloc_free(local);
     998           0 :                 return NULL;
     999             :         }
    1000          81 :         local->port = ntohs(local_addr->sin6_port);
    1001             : 
    1002          81 :         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         747 : _PUBLIC_ const struct socket_ops *socket_ipv6_ops(enum socket_type type)
    1029             : {
    1030         747 :         return &ipv6_tcp_ops;
    1031             : }
    1032             : 
    1033             : #endif

Generated by: LCOV version 1.14