"Fossies" - the Fresh Open Source Software Archive

Member "gvm-libs-11.0.1/base/networking.c" (12 May 2020, 18044 Bytes) of package /linux/misc/openvas/gvm-libs-11.0.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "networking.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.0-beta2_vs_1.0.0.

    1 /* Copyright (C) 2013-2019 Greenbone Networks GmbH
    2  *
    3  * SPDX-License-Identifier: GPL-2.0-or-later
    4  *
    5  * This program is free software; you can redistribute it and/or
    6  * modify it under the terms of the GNU General Public License
    7  * as published by the Free Software Foundation; either version 2
    8  * of the License, or (at your option) any later version.
    9  *
   10  * This program is distributed in the hope that it will be useful,
   11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   13  * GNU General Public License for more details.
   14  *
   15  * You should have received a copy of the GNU General Public License
   16  * along with this program; if not, write to the Free Software
   17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   18  */
   19 
   20 /**
   21  * @file
   22  * @brief Implementation of GVM Networking related API.
   23  */
   24 
   25 #include "networking.h"
   26 
   27 #include <arpa/inet.h> /* for inet_ntop */
   28 #include <assert.h>    /* for assert */
   29 #include <ctype.h>     /* for isblank */
   30 #include <errno.h>     /* for errno, EAFNOSUPPORT */
   31 #include <glib/gstdio.h>
   32 #include <ifaddrs.h>    /* for ifaddrs, freeifaddrs, getifaddrs */
   33 #include <net/if.h>     /* for IFNAMSIZ */
   34 #include <stdint.h>     /* for uint32_t, uint8_t */
   35 #include <stdlib.h>     /* for atoi, strtol */
   36 #include <string.h>     /* for memcpy, bzero, strchr, strlen, strcmp, strncpy */
   37 #include <sys/socket.h> /* for AF_INET, AF_INET6, AF_UNSPEC, sockaddr_storage */
   38 #include <unistd.h>     /* for close */
   39 
   40 #ifdef __FreeBSD__
   41 #include <netinet/in.h>
   42 #define s6_addr32 __u6_addr.__u6_addr32
   43 #endif
   44 
   45 /* Global variables */
   46 
   47 /* Source interface name eg. eth1. */
   48 char global_source_iface[IFNAMSIZ] = {'\0'};
   49 
   50 /* Source IPv4 address. */
   51 struct in_addr global_source_addr = {.s_addr = 0};
   52 
   53 /* Source IPv6 address. */
   54 struct in6_addr global_source_addr6 = {.s6_addr32 = {0, 0, 0, 0}};
   55 
   56 /* Source Interface/Address related functions. */
   57 
   58 /**
   59  * @brief Initializes the source network interface name and related information.
   60  *
   61  * @param[in]  iface    Name of network interface to use as source interface.
   62  *
   63  * @return 0 if success. If error, return 1 and reset source values to default.
   64  */
   65 int
   66 gvm_source_iface_init (const char *iface)
   67 {
   68   struct ifaddrs *ifaddr, *ifa;
   69   int ret = 1;
   70 
   71   bzero (global_source_iface, sizeof (global_source_iface));
   72   global_source_addr.s_addr = INADDR_ANY;
   73   global_source_addr6 = in6addr_any;
   74 
   75   if (iface == NULL)
   76     return ret;
   77 
   78   if (getifaddrs (&ifaddr) == -1)
   79     return ret;
   80 
   81   /* Search for the adequate interface/family. */
   82   for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
   83     {
   84       if (ifa->ifa_addr && strcmp (iface, ifa->ifa_name) == 0)
   85         {
   86           if (ifa->ifa_addr->sa_family == AF_INET)
   87             {
   88               struct in_addr *addr =
   89                 &((struct sockaddr_in *) ifa->ifa_addr)->sin_addr;
   90 
   91               memcpy (&global_source_addr, addr, sizeof (global_source_addr));
   92               ret = 0;
   93             }
   94           else if (ifa->ifa_addr->sa_family == AF_INET6)
   95             {
   96               struct sockaddr_in6 *addr;
   97 
   98               addr = (struct sockaddr_in6 *) ifa->ifa_addr;
   99               memcpy (&global_source_addr6.s6_addr, &addr->sin6_addr,
  100                       sizeof (struct in6_addr));
  101               ret = 0;
  102             }
  103         }
  104     }
  105 
  106   /* At least one address for the interface was found. */
  107   if (ret == 0)
  108     strncpy (global_source_iface, iface, sizeof (global_source_iface) - 1);
  109 
  110   freeifaddrs (ifaddr);
  111   return ret;
  112 }
  113 
  114 /**
  115  * @brief Check if global_source @ref global_source_iface is set.
  116  *
  117  * @return 1 if set, 0 otherwise.
  118  */
  119 int
  120 gvm_source_iface_is_set (void)
  121 {
  122   return *global_source_iface != '\0';
  123 }
  124 
  125 /**
  126  * @brief Binds a socket to use the global source address.
  127  *
  128  * @param[in]  socket    Socket to set source address for.
  129  * @param[in]  port      Network port for socket.
  130  * @param[in]  family    Family of socket. AF_INET or AF_INET6.
  131  *
  132  * @return 0 if success, -1 if error.
  133  */
  134 int
  135 gvm_source_set_socket (int socket, int port, int family)
  136 {
  137   if (family == AF_INET)
  138     {
  139       struct sockaddr_in addr;
  140 
  141       bzero (&addr, sizeof (addr));
  142       gvm_source_addr (&addr.sin_addr);
  143       addr.sin_port = htons (port);
  144       addr.sin_family = AF_INET;
  145 
  146       if (bind (socket, (struct sockaddr *) &addr, sizeof (addr)) < 0)
  147         return -1;
  148     }
  149   else if (family == AF_INET6)
  150     {
  151       struct sockaddr_in6 addr6;
  152 
  153       bzero (&addr6, sizeof (addr6));
  154       gvm_source_addr6 (&addr6.sin6_addr);
  155       addr6.sin6_port = htons (port);
  156       addr6.sin6_family = AF_INET6;
  157 
  158       if (bind (socket, (struct sockaddr *) &addr6, sizeof (addr6)) < 0)
  159         return -1;
  160     }
  161   else
  162     return -1;
  163 
  164   return 0;
  165 }
  166 
  167 /**
  168  * @brief Gives the source IPv4 address.
  169  *
  170  * @param[out]  addr  Buffer of at least 4 bytes.
  171  */
  172 void
  173 gvm_source_addr (void *addr)
  174 {
  175   if (addr)
  176     memcpy (addr, &global_source_addr.s_addr, 4);
  177 }
  178 
  179 /**
  180  * @brief Gives the source IPv6 address.
  181  *
  182  * @param[out]  addr6  Buffer of at least 16 bytes.
  183  */
  184 void
  185 gvm_source_addr6 (void *addr6)
  186 {
  187   if (addr6)
  188     memcpy (addr6, &global_source_addr6.s6_addr, 16);
  189 }
  190 
  191 /**
  192  * @brief Gives the source IPv4 mapped as an IPv6 address.
  193  * eg. 192.168.20.10 would map to \::ffff:192.168.20.10.
  194  *
  195  * @param[out]  addr6  Buffer of at least 16 bytes.
  196  */
  197 void
  198 gvm_source_addr_as_addr6 (struct in6_addr *addr6)
  199 {
  200   if (addr6)
  201     ipv4_as_ipv6 (&global_source_addr, addr6);
  202 }
  203 
  204 /**
  205  * @brief Gives the source IPv4 address in string format.
  206  *
  207  * @return Source IPv4 string. Free with g_free().
  208  */
  209 char *
  210 gvm_source_addr_str (void)
  211 {
  212   char *str = g_malloc0 (INET_ADDRSTRLEN);
  213 
  214   inet_ntop (AF_INET, &global_source_addr.s_addr, str, INET_ADDRSTRLEN);
  215   return str;
  216 }
  217 
  218 /**
  219  * @brief Gives the source IPv6 address in string format.
  220  *
  221  * @return Source IPv6 string. Free with g_free().
  222  */
  223 char *
  224 gvm_source_addr6_str (void)
  225 {
  226   char *str = g_malloc0 (INET6_ADDRSTRLEN);
  227 
  228   inet_ntop (AF_INET6, &global_source_addr6, str, INET6_ADDRSTRLEN);
  229   return str;
  230 }
  231 
  232 /* Miscellaneous functions. */
  233 
  234 /**
  235  * @brief Maps an IPv4 address as an IPv6 address.
  236  * eg. 192.168.10.20 would map to \::ffff:192.168.10.20.
  237  *
  238  * @param[in]  ip4  IPv4 address to map.
  239  * @param[out] ip6  Buffer to store the IPv6 address.
  240  */
  241 void
  242 ipv4_as_ipv6 (const struct in_addr *ip4, struct in6_addr *ip6)
  243 {
  244   if (ip4 == NULL || ip6 == NULL)
  245     return;
  246 
  247   ip6->s6_addr32[0] = 0;
  248   ip6->s6_addr32[1] = 0;
  249   ip6->s6_addr32[2] = htonl (0xffff);
  250   memcpy (&ip6->s6_addr32[3], ip4, sizeof (struct in_addr));
  251 }
  252 
  253 /**
  254  * @brief Stringifies an IP address.
  255  *
  256  * @param[in]   addr6   IP address.
  257  * @param[out]  str     Buffer to output IP.
  258  */
  259 void
  260 addr6_to_str (const struct in6_addr *addr6, char *str)
  261 {
  262   if (!addr6)
  263     return;
  264   if (IN6_IS_ADDR_V4MAPPED (addr6))
  265     inet_ntop (AF_INET, &addr6->s6_addr32[3], str, INET6_ADDRSTRLEN);
  266   else
  267     inet_ntop (AF_INET6, addr6, str, INET6_ADDRSTRLEN);
  268 }
  269 
  270 /**
  271  * @brief Stringifies an IP address.
  272  *
  273  * @param[in]   addr6   IP address.
  274  *
  275  * @return      IP as string. NULL otherwise.
  276  */
  277 char *
  278 addr6_as_str (const struct in6_addr *addr6)
  279 {
  280   char *str;
  281 
  282   if (!addr6)
  283     return NULL;
  284 
  285   str = g_malloc0 (INET6_ADDRSTRLEN);
  286   addr6_to_str (addr6, str);
  287   return str;
  288 }
  289 
  290 /**
  291  * @brief Convert an IP address to string format.
  292  *
  293  * @param[in]   addr    Address to convert.
  294  * @param[out]  str     Buffer of INET6_ADDRSTRLEN size.
  295  */
  296 void
  297 sockaddr_as_str (const struct sockaddr_storage *addr, char *str)
  298 {
  299   if (!addr || !str)
  300     return;
  301 
  302   if (addr->ss_family == AF_INET)
  303     {
  304       struct sockaddr_in *saddr = (struct sockaddr_in *) addr;
  305       inet_ntop (AF_INET, &saddr->sin_addr, str, INET6_ADDRSTRLEN);
  306     }
  307   else if (addr->ss_family == AF_INET6)
  308     {
  309       struct sockaddr_in6 *s6addr = (struct sockaddr_in6 *) addr;
  310       if (IN6_IS_ADDR_V4MAPPED (&s6addr->sin6_addr))
  311         inet_ntop (AF_INET, &s6addr->sin6_addr.s6_addr[12], str,
  312                    INET6_ADDRSTRLEN);
  313       else
  314         inet_ntop (AF_INET6, &s6addr->sin6_addr, str, INET6_ADDRSTRLEN);
  315     }
  316   else if (addr->ss_family == AF_UNIX)
  317     {
  318       g_snprintf (str, INET6_ADDRSTRLEN, "unix_socket");
  319     }
  320   else if (addr->ss_family == AF_UNSPEC)
  321     {
  322       g_snprintf (str, INET6_ADDRSTRLEN, "unknown_socket");
  323     }
  324   else
  325     {
  326       g_snprintf (str, INET6_ADDRSTRLEN, "type_%d_socket", addr->ss_family);
  327     }
  328 }
  329 
  330 /**
  331  * @brief Returns a list of addresses that a hostname resolves to.
  332  *
  333  * @param[in]   name    Hostname to resolve.
  334  *
  335  * @return List of addresses, NULL otherwise.
  336  */
  337 GSList *
  338 gvm_resolve_list (const char *name)
  339 {
  340   struct addrinfo hints, *info, *p;
  341   GSList *list = NULL;
  342 
  343   if (name == NULL)
  344     return NULL;
  345 
  346   bzero (&hints, sizeof (hints));
  347   hints.ai_family = AF_UNSPEC;
  348   hints.ai_socktype = SOCK_STREAM;
  349   hints.ai_protocol = 0;
  350   if ((getaddrinfo (name, NULL, &hints, &info)) != 0)
  351     return NULL;
  352 
  353   p = info;
  354   while (p)
  355     {
  356       struct in6_addr dst;
  357 
  358       if (p->ai_family == AF_INET)
  359         {
  360           struct sockaddr_in *addrin = (struct sockaddr_in *) p->ai_addr;
  361           ipv4_as_ipv6 (&(addrin->sin_addr), &dst);
  362           list = g_slist_prepend (list, g_memdup (&dst, sizeof (dst)));
  363         }
  364       else if (p->ai_family == AF_INET6)
  365         {
  366           struct sockaddr_in6 *addrin = (struct sockaddr_in6 *) p->ai_addr;
  367           memcpy (&dst, &(addrin->sin6_addr), sizeof (struct in6_addr));
  368           list = g_slist_prepend (list, g_memdup (&dst, sizeof (dst)));
  369         }
  370       p = p->ai_next;
  371     }
  372 
  373   freeaddrinfo (info);
  374   return list;
  375 }
  376 
  377 /**
  378  * @brief Resolves a hostname to an IPv4 or IPv6 address.
  379  *
  380  * @param[in]   name    Hostname to resolve.
  381  * @param[out]  dst     Buffer to store resolved address. Size must be at least
  382  *                      4 bytes for AF_INET and 16 bytes for AF_INET6.
  383  * @param[in] family    Either AF_INET or AF_INET6.
  384  *
  385  * @return -1 if error, 0 otherwise.
  386  */
  387 int
  388 gvm_resolve (const char *name, void *dst, int family)
  389 {
  390   struct addrinfo hints, *info, *p;
  391 
  392   if (name == NULL || dst == NULL
  393       || (family != AF_INET && family != AF_INET6 && family != AF_UNSPEC))
  394     return -1;
  395 
  396   bzero (&hints, sizeof (hints));
  397   hints.ai_family = family;
  398   hints.ai_socktype = SOCK_STREAM;
  399   hints.ai_protocol = 0;
  400   if ((getaddrinfo (name, NULL, &hints, &info)) != 0)
  401     return -1;
  402 
  403   p = info;
  404   while (p)
  405     {
  406       if (p->ai_family == family || family == AF_UNSPEC)
  407         {
  408           if (p->ai_family == AF_INET && family == AF_UNSPEC)
  409             {
  410               struct sockaddr_in *addrin = (struct sockaddr_in *) p->ai_addr;
  411               ipv4_as_ipv6 (&(addrin->sin_addr), dst);
  412             }
  413           else if (p->ai_family == AF_INET)
  414             {
  415               struct sockaddr_in *addrin = (struct sockaddr_in *) p->ai_addr;
  416               memcpy (dst, &(addrin->sin_addr), sizeof (struct in_addr));
  417             }
  418           else if (p->ai_family == AF_INET6)
  419             {
  420               struct sockaddr_in6 *addrin = (struct sockaddr_in6 *) p->ai_addr;
  421               memcpy (dst, &(addrin->sin6_addr), sizeof (struct in6_addr));
  422             }
  423           break;
  424         }
  425 
  426       p = p->ai_next;
  427     }
  428 
  429   freeaddrinfo (info);
  430   return 0;
  431 }
  432 
  433 /**
  434  * @brief Resolves a hostname to an IPv4-mapped IPv6 or IPv6 address.
  435  *
  436  * @param[in]   name    Hostname to resolve.
  437  * @param[out]  ip6     Buffer to store resolved address.
  438  *
  439  * @return -1 if error, 0 otherwise.
  440  */
  441 int
  442 gvm_resolve_as_addr6 (const char *name, struct in6_addr *ip6)
  443 {
  444   return gvm_resolve (name, ip6, AF_UNSPEC);
  445 }
  446 
  447 /* Ports related. */
  448 
  449 /**
  450  * @brief Validate a port range string.
  451  *
  452  * Accepts ranges in form of "103,U:200-1024,3000-4000,T:3-4,U:7".
  453  *
  454  * @param[in]   port_range  A port range.
  455  *
  456  * @return 0 success, 1 failed.
  457  */
  458 int
  459 validate_port_range (const char *port_range)
  460 {
  461   gchar **split, **point, *range, *range_start;
  462 
  463   if (!port_range)
  464     return 1;
  465 
  466   while (*port_range && isblank (*port_range))
  467     port_range++;
  468   if (*port_range == '\0')
  469     return 1;
  470 
  471   /* Treat newlines like commas. */
  472   range = range_start = g_strdup (port_range);
  473   while (*range)
  474     {
  475       if (*range == '\n')
  476         *range = ',';
  477       range++;
  478     }
  479 
  480   split = g_strsplit (range_start, ",", 0);
  481   g_free (range_start);
  482   point = split;
  483 
  484   while (*point)
  485     {
  486       gchar *hyphen, *element;
  487 
  488       /* Strip off any outer whitespace. */
  489 
  490       element = g_strstrip (*point);
  491 
  492       /* Strip off any leading type specifier. */
  493 
  494       if ((strlen (element) >= 2)
  495           && ((element[0] == 'T') || (element[0] == 'U'))
  496           && (element[1] == ':'))
  497         element = element + 2;
  498 
  499       /* Look for a hyphen. */
  500 
  501       hyphen = strchr (element, '-');
  502       if (hyphen)
  503         {
  504           long int number1, number2;
  505           const char *first;
  506           char *end;
  507 
  508           hyphen++;
  509 
  510           /* Check the first number. */
  511 
  512           first = element;
  513           while (*first && isblank (*first))
  514             first++;
  515           if (*first == '-')
  516             goto fail;
  517 
  518           errno = 0;
  519           number1 = strtol (first, &end, 10);
  520           while (*end && isblank (*end))
  521             end++;
  522           if (errno || (*end != '-'))
  523             goto fail;
  524           if (number1 == 0)
  525             goto fail;
  526           if (number1 > 65535)
  527             goto fail;
  528 
  529           /* Check the second number. */
  530 
  531           while (*hyphen && isblank (*hyphen))
  532             hyphen++;
  533           if (*hyphen == '\0')
  534             goto fail;
  535 
  536           errno = 0;
  537           number2 = strtol (hyphen, &end, 10);
  538           while (*end && isblank (*end))
  539             end++;
  540           if (errno || *end)
  541             goto fail;
  542           if (number2 == 0)
  543             goto fail;
  544           if (number2 > 65535)
  545             goto fail;
  546 
  547           if (number1 > number2)
  548             goto fail;
  549         }
  550       else
  551         {
  552           long int number;
  553           const char *only;
  554           char *end;
  555 
  556           /* Check the single number. */
  557 
  558           only = element;
  559           while (*only && isblank (*only))
  560             only++;
  561           /* Empty ranges are OK. */
  562           if (*only)
  563             {
  564               errno = 0;
  565               number = strtol (only, &end, 10);
  566               while (*end && isblank (*end))
  567                 end++;
  568               if (errno || *end)
  569                 goto fail;
  570               if (number == 0)
  571                 goto fail;
  572               if (number > 65535)
  573                 goto fail;
  574             }
  575         }
  576       point += 1;
  577     }
  578 
  579   g_strfreev (split);
  580   return 0;
  581 
  582 fail:
  583   g_strfreev (split);
  584   return 1;
  585 }
  586 
  587 /**
  588  * @brief Create a range array from a port_range string.
  589  *
  590  * @param[in]   port_range  Valid port_range string.
  591  *
  592  * @return Range array.
  593  */
  594 array_t *
  595 port_range_ranges (const char *port_range)
  596 {
  597   gchar **split, **point, *range_start, *current;
  598   array_t *ranges;
  599   int tcp;
  600 
  601   if (!port_range)
  602     return NULL;
  603 
  604   ranges = make_array ();
  605 
  606   while (*port_range && isblank (*port_range))
  607     port_range++;
  608 
  609   /* Accepts T: and U: before any of the ranges.  This toggles the remaining
  610    * ranges, as in nmap.  Treats a leading naked range as TCP, whereas nmap
  611    * treats it as TCP and UDP. */
  612 
  613   /* Treat newlines like commas. */
  614   range_start = current = g_strdup (port_range);
  615   while (*current)
  616     {
  617       if (*current == '\n')
  618         *current = ',';
  619       current++;
  620     }
  621 
  622   tcp = 1;
  623   split = g_strsplit (range_start, ",", 0);
  624   g_free (range_start);
  625   point = split;
  626 
  627   while (*point)
  628     {
  629       gchar *hyphen, *element;
  630       range_t *range;
  631 
  632       element = g_strstrip (*point);
  633       if (strlen (element) >= 2)
  634         {
  635           if ((element[0] == 'T') && (element[1] == ':'))
  636             {
  637               tcp = 1;
  638               element = element + 2;
  639             }
  640           else if ((element[0] == 'U') && (element[1] == ':'))
  641             {
  642               tcp = 0;
  643               element = element + 2;
  644             }
  645           /* Else tcp stays as it is. */
  646         }
  647 
  648       /* Skip any space that followed the type specifier. */
  649       while (*element && isblank (*element))
  650         element++;
  651 
  652       hyphen = strchr (element, '-');
  653       if (hyphen)
  654         {
  655           *hyphen = '\0';
  656           hyphen++;
  657           while (*hyphen && isblank (*hyphen))
  658             hyphen++;
  659           assert (*hyphen); /* Validation checks this. */
  660 
  661           /* A range. */
  662 
  663           range = (range_t *) g_malloc0 (sizeof (range_t));
  664 
  665           range->start = atoi (element);
  666           range->end = atoi (hyphen);
  667           range->type = tcp ? PORT_PROTOCOL_TCP : PORT_PROTOCOL_UDP;
  668           range->exclude = 0;
  669 
  670           array_add (ranges, range);
  671         }
  672       else if (*element)
  673         {
  674           /* A single port. */
  675 
  676           range = (range_t *) g_malloc0 (sizeof (range_t));
  677 
  678           range->start = atoi (element);
  679           range->end = range->start;
  680           range->type = tcp ? PORT_PROTOCOL_TCP : PORT_PROTOCOL_UDP;
  681           range->exclude = 0;
  682 
  683           array_add (ranges, range);
  684         }
  685       /* Else skip over empty range. */
  686       point += 1;
  687     }
  688   g_strfreev (split);
  689   return ranges;
  690 }
  691 
  692 /**
  693  * @brief Checks if a port num is in port ranges array.
  694  *
  695  * @param[in]  pnum     Port number.
  696  * @param[in]  ptype    Port type.
  697  * @param[in]  pranges  Array of port ranges.
  698  *
  699  * @return 1 if port in port ranges, 0 otherwise.
  700  */
  701 int
  702 port_in_port_ranges (int pnum, port_protocol_t ptype, array_t *pranges)
  703 {
  704   unsigned int i;
  705 
  706   if (pranges == NULL || pnum < 0 || pnum > 65536)
  707     return 0;
  708 
  709   for (i = 0; i < pranges->len; i++)
  710     {
  711       range_t *range = (range_t *) g_ptr_array_index (pranges, i);
  712       if (range->type != ptype)
  713         continue;
  714       if (range->start <= pnum && pnum <= range->end)
  715         return 1;
  716     }
  717   return 0;
  718 }
  719 
  720 /**
  721  * @brief Checks if IPv6 support is enabled.
  722  *
  723  * @return 1 if IPv6 is enabled, 0 if disabled.
  724  */
  725 int
  726 ipv6_is_enabled ()
  727 {
  728   int sock = socket (PF_INET6, SOCK_STREAM, 0);
  729 
  730   if (sock < 0)
  731     {
  732       if (errno == EAFNOSUPPORT)
  733         return 0;
  734     }
  735   else
  736     close (sock);
  737 
  738   return 1;
  739 }