LCOV - code coverage report
Current view: top level - builds/gnutls/coverage/gnutls-git/lib/x509 - ip.c (source / functions) Hit Total Coverage
Test: GnuTLS-3.6.14 Code Coverage Lines: 91 104 87.5 %
Date: 2020-10-30 04:50:48 Functions: 6 6 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (C) 2007-2016 Free Software Foundation, Inc.
       3             :  * Copyright (C) 2015-2016 Red Hat, Inc.
       4             :  *
       5             :  * Author: Simon Josefsson, Nikos Mavrogiannopoulos, Martin Ukrop
       6             :  *
       7             :  * This file is part of GnuTLS.
       8             :  *
       9             :  * The GnuTLS is free software; you can redistribute it and/or
      10             :  * modify it under the terms of the GNU Lesser General Public License
      11             :  * as published by the Free Software Foundation; either version 2.1 of
      12             :  * the License, or (at your option) any later version.
      13             :  *
      14             :  * This library is distributed in the hope that it will be useful, but
      15             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      17             :  * Lesser General Public License for more details.
      18             :  *
      19             :  * You should have received a copy of the GNU Lesser General Public License
      20             :  * along with this program.  If not, see <https://www.gnu.org/licenses/>
      21             :  *
      22             :  */
      23             : 
      24             : #include "gnutls_int.h"
      25             : #include "ip.h"
      26             : #include <gnutls/x509.h>
      27             : #include <arpa/inet.h>
      28             : 
      29             : /*-
      30             :  * _gnutls_mask_to_prefix:
      31             :  * @mask: CIDR mask
      32             :  * @mask_size: number of bytes in @mask
      33             :  *
      34             :  * Check for mask validity (form of 1*0*) and return its prefix numerically.
      35             :  *
      36             :  * Returns: Length of 1-prefix (0 -- mask_size*8), -1 in case of invalid mask
      37             :  -*/
      38         124 : int _gnutls_mask_to_prefix(const unsigned char *mask, unsigned mask_size)
      39             : {
      40         124 :         unsigned i, prefix_length = 0;
      41         502 :         for (i=0; i<mask_size; i++) {
      42         498 :                 if (mask[i] == 0xFF) {
      43         378 :                         prefix_length += 8;
      44             :                 } else {
      45         120 :                         switch(mask[i]) {
      46           6 :                                 case 0xFE: prefix_length += 7; break;
      47           1 :                                 case 0xFC: prefix_length += 6; break;
      48          10 :                                 case 0xF8: prefix_length += 5; break;
      49           4 :                                 case 0xF0: prefix_length += 4; break;
      50          11 :                                 case 0xE0: prefix_length += 3; break;
      51          18 :                                 case 0xC0: prefix_length += 2; break;
      52           1 :                                 case 0x80: prefix_length += 1; break;
      53             :                                 case 0x00: break;
      54             :                                 default:
      55             :                                         return -1;
      56             :                         }
      57             :                         break;
      58             :                 }
      59             :         }
      60         121 :         i++;
      61             :         // mask is invalid, if there follows something else than 0x00
      62         600 :         for ( ; i<mask_size; i++) {
      63         487 :                 if (mask[i] != 0)
      64             :                         return -1;
      65             :         }
      66         113 :         return prefix_length;
      67             : }
      68             : 
      69             : /*-
      70             :  * _gnutls_ip_to_string:
      71             :  * @_ip: IP address (RFC5280 format)
      72             :  * @ip_size: Size of @_ip (4 or 16)
      73             :  * @out: Resulting string
      74             :  * @out_size: Size of @out
      75             :  *
      76             :  * Transform IP address into human-readable string.
      77             :  * @string must be already allocated and
      78             :  * at least 16/48 bytes for IPv4/v6 address respectively.
      79             :  *
      80             :  * Returns: Address of result string.
      81             :  -*/
      82         559 : const char *_gnutls_ip_to_string(const void *_ip, unsigned int ip_size, char *out, unsigned int out_size)
      83             : {
      84             : 
      85         559 :         if (ip_size != 4 && ip_size != 16) {
      86          15 :                 gnutls_assert();
      87          15 :                 return NULL;
      88             :         }
      89             : 
      90         544 :         if (ip_size == 4 && out_size < 16) {
      91           0 :                 gnutls_assert();
      92           0 :                 return NULL;
      93             :         }
      94             : 
      95         544 :         if (ip_size == 16 && out_size < 48) {
      96           0 :                 gnutls_assert();
      97           0 :                 return NULL;
      98             :         }
      99             : 
     100         544 :         if (ip_size == 4)
     101         526 :                 return inet_ntop(AF_INET, _ip, out, out_size);
     102             :         else
     103          18 :                 return inet_ntop(AF_INET6, _ip, out, out_size);
     104             : }
     105             : 
     106             : /*-
     107             :  * _gnutls_cidr_to_string:
     108             :  * @_ip: CIDR range (RFC5280 format)
     109             :  * @ip_size: Size of @_ip (8 or 32)
     110             :  * @out: Resulting string
     111             :  * @out_size: Size of @out
     112             :  *
     113             :  * Transform CIDR IP address range into human-readable string.
     114             :  * The input @_ip must be in RFC5280 format (IP address in network byte
     115             :  * order, followed by its network mask which is 4 bytes in IPv4 and
     116             :  * 16 bytes in IPv6). @string must be already allocated and
     117             :  * at least 33/97 bytes for IPv4/v6 address respectively.
     118             :  *
     119             :  * Returns: Address of result string.
     120             :  -*/
     121          31 : const char *_gnutls_cidr_to_string(const void *_ip, unsigned int ip_size, char *out, unsigned int out_size)
     122             : {
     123          31 :         const unsigned char *ip = _ip;
     124          31 :         char tmp[64];
     125          31 :         const char *p;
     126             : 
     127          31 :         if (ip_size != 8 && ip_size != 32) {
     128           0 :                 gnutls_assert();
     129           0 :                 return NULL;
     130             :         }
     131             : 
     132          31 :         if (ip_size == 8) {
     133          20 :                 p = inet_ntop(AF_INET, ip, tmp, sizeof(tmp));
     134             : 
     135          20 :                 if (p)
     136          20 :                         snprintf(out, out_size, "%s/%d", tmp, _gnutls_mask_to_prefix(ip+4, 4));
     137             :         } else {
     138          11 :                 p = inet_ntop(AF_INET6, ip, tmp, sizeof(tmp));
     139             : 
     140          11 :                 if (p)
     141          11 :                         snprintf(out, out_size, "%s/%d", tmp, _gnutls_mask_to_prefix(ip+16, 16));
     142             :         }
     143             : 
     144          31 :         if (p == NULL)
     145           0 :                 return NULL;
     146             : 
     147             :         return out;
     148             : }
     149             : 
     150         104 : static void prefix_to_mask(unsigned prefix, unsigned char *mask, size_t mask_size)
     151             : {
     152         104 :         int i;
     153         104 :         unsigned j;
     154         104 :         memset(mask, 0, mask_size);
     155             : 
     156         714 :         for (i = prefix, j = 0; i > 0 && j < mask_size; i -= 8, j++) {
     157         610 :                 if (i >= 8) {
     158         591 :                         mask[j] = 0xff;
     159             :                 } else {
     160          19 :                         mask[j] = (unsigned long)(0xffU << (8 - i));
     161             :                 }
     162             :         }
     163         104 : }
     164             : 
     165             : /*-
     166             :  * _gnutls_mask_ip:
     167             :  * @ip: IP of @ipsize bytes
     168             :  * @mask: netmask of @ipsize bytes
     169             :  * @ipsize: IP length (4 or 16)
     170             :  *
     171             :  * Mask given IP in place according to the given mask.
     172             :  *
     173             :  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a negative error value.
     174             :  -*/
     175         116 : int _gnutls_mask_ip(unsigned char *ip, const unsigned char *mask, unsigned ipsize)
     176             : {
     177         116 :         unsigned i;
     178             : 
     179         116 :         if (ipsize != 4 && ipsize != 16)
     180             :                 return GNUTLS_E_MALFORMED_CIDR;
     181        1036 :         for (i = 0; i < ipsize; i++)
     182         920 :                 ip[i] &= mask[i];
     183             :         return GNUTLS_E_SUCCESS;
     184             : }
     185             : 
     186             : /**
     187             :  * gnutls_x509_cidr_to_rfc5280:
     188             :  * @cidr: CIDR in RFC4632 format (IP/prefix), null-terminated
     189             :  * @cidr_rfc5280: CIDR range converted to RFC5280 format
     190             :  *
     191             :  * This function will convert text CIDR range with prefix (such as '10.0.0.0/8')
     192             :  * to RFC5280 (IP address in network byte order followed by its network mask).
     193             :  * Works for both IPv4 and IPv6.
     194             :  *
     195             :  * The resulting object is directly usable for IP name constraints usage,
     196             :  * for example in functions %gnutls_x509_name_constraints_add_permitted
     197             :  * or %gnutls_x509_name_constraints_add_excluded.
     198             :  *
     199             :  * The data in datum needs to be deallocated using gnutls_free().
     200             :  *
     201             :  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a negative error value.
     202             :  *
     203             :  * Since: 3.5.4
     204             :  */
     205         115 : int gnutls_x509_cidr_to_rfc5280(const char *cidr, gnutls_datum_t *cidr_rfc5280)
     206             : {
     207         115 :         unsigned iplength, prefix;
     208         115 :         int ret;
     209         115 :         char *p;
     210         115 :         char *p_end = NULL;
     211         115 :         char *cidr_tmp;
     212             : 
     213         115 :         p = strchr(cidr, '/');
     214         115 :         if (p != NULL) {
     215         114 :                 prefix = strtol(p+1, &p_end, 10);
     216         114 :                 if (prefix == 0 && p_end == p+1) {
     217           3 :                         _gnutls_debug_log("Cannot parse prefix given in CIDR %s\n", cidr);
     218           3 :                         gnutls_assert();
     219           3 :                         return GNUTLS_E_MALFORMED_CIDR;
     220             :                 }
     221         111 :                 unsigned length = p-cidr+1;
     222         111 :                 cidr_tmp = gnutls_malloc(length);
     223         111 :                 if (cidr_tmp == NULL) {
     224           0 :                         return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
     225             :                 }
     226         111 :                 memcpy(cidr_tmp, cidr, length);
     227         111 :                 cidr_tmp[length-1] = 0;
     228             :         } else {
     229           1 :                 _gnutls_debug_log("No prefix given in CIDR %s\n", cidr);
     230           1 :                 gnutls_assert();
     231           1 :                 return GNUTLS_E_MALFORMED_CIDR;
     232             :         }
     233             : 
     234         111 :         if (strchr(cidr, ':') != 0) { /* IPv6 */
     235             :                 iplength = 16;
     236             :         } else { /* IPv4 */
     237          74 :                 iplength = 4;
     238             :         }
     239         111 :         cidr_rfc5280->size = 2*iplength;
     240             : 
     241         111 :         if (prefix > iplength*8) {
     242           7 :                 _gnutls_debug_log("Invalid prefix given in CIDR %s (%d)\n", cidr, prefix);
     243           7 :                 ret = gnutls_assert_val(GNUTLS_E_MALFORMED_CIDR);
     244           7 :                 goto cleanup;
     245             :         }
     246             : 
     247         104 :         cidr_rfc5280->data = gnutls_malloc(cidr_rfc5280->size);
     248         104 :         if (cidr_rfc5280->data == NULL) {
     249           0 :                 ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
     250           0 :                 goto cleanup;
     251             :         }
     252             : 
     253         140 :         ret = inet_pton(iplength == 4 ? AF_INET : AF_INET6, cidr_tmp, cidr_rfc5280->data);
     254         104 :         if (ret == 0) {
     255           0 :                 _gnutls_debug_log("Cannot parse IP from CIDR %s\n", cidr_tmp);
     256           0 :                 ret = gnutls_assert_val(GNUTLS_E_MALFORMED_CIDR);
     257           0 :                 goto cleanup;
     258             :         }
     259             : 
     260         104 :         prefix_to_mask(prefix, &cidr_rfc5280->data[iplength], iplength);
     261         104 :         _gnutls_mask_ip(cidr_rfc5280->data, &cidr_rfc5280->data[iplength], iplength);
     262             : 
     263         104 :         ret = GNUTLS_E_SUCCESS;
     264             : 
     265         111 : cleanup:
     266         111 :         gnutls_free(cidr_tmp);
     267         111 :         return ret;
     268             : }

Generated by: LCOV version 1.14