OpenVAS Libraries  9.0.3
openvas_networking.c
Go to the documentation of this file.
1 /* openvas-libraries/base
2  * $Id$
3  * Description: Implementation of OpenVAS Networking related API.
4  *
5  * Authors:
6  * Hani Benhabiles <hani.benhabiles@greenbone.net>
7  *
8  * Copyright:
9  * Copyright (C) 2013 Greenbone Networks GmbH
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24  */
25 
26 #include "openvas_networking.h"
27 
28 #include <fcntl.h>
29 #include <unistd.h>
30 #include <glib/gstdio.h>
31 
32  /* Global variables */
33 
34 /* Source interface name eg. eth1. */
35 char global_source_iface[IFNAMSIZ] = { '\0' };
36 
37 /* Source IPv4 address. */
38 struct in_addr global_source_addr = { .s_addr = 0 };
39 
40 /* Source IPv6 address. */
41 struct in6_addr global_source_addr6 = { .s6_addr32 = { 0, 0, 0, 0 } };
42 
43  /* Source Interface/Address related functions. */
44 
52 int
53 openvas_source_iface_init (const char *iface)
54 {
55  struct ifaddrs *ifaddr, *ifa;
56  int ret = 1;
57 
58  bzero (global_source_iface, sizeof (global_source_iface));
59  global_source_addr.s_addr = INADDR_ANY;
60  global_source_addr6 = in6addr_any;
61 
62  if (iface == NULL)
63  return ret;
64 
65  if (getifaddrs (&ifaddr) == -1)
66  return ret;
67 
68  /* Search for the adequate interface/family. */
69  for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
70  {
71  if (ifa->ifa_addr && strcmp (iface, ifa->ifa_name) == 0)
72  {
73  if (ifa->ifa_addr->sa_family == AF_INET)
74  {
75  struct in_addr *addr = &((struct sockaddr_in *)
76  ifa->ifa_addr)->sin_addr;
77 
78  memcpy (&global_source_addr, addr, sizeof (global_source_addr));
79  ret = 0;
80  }
81  else if (ifa->ifa_addr->sa_family == AF_INET6)
82  {
83  struct sockaddr_in6 *addr;
84 
85  addr = (struct sockaddr_in6 *) ifa->ifa_addr;
86  memcpy (&global_source_addr6.s6_addr, &addr->sin6_addr,
87  sizeof (struct in6_addr));
88  ret = 0;
89  }
90  }
91  }
92 
93  /* At least one address for the interface was found. */
94  if (ret == 0)
95  strncpy (global_source_iface, iface, sizeof (global_source_iface) - 1);
96 
97  freeifaddrs (ifaddr);
98  return ret;
99 }
100 
101 int
103 {
104  return *global_source_iface != '\0';
105 }
106 
116 int
117 openvas_source_set_socket (int socket, int port, int family)
118 {
119  if (family == AF_INET)
120  {
121  struct sockaddr_in addr;
122 
123  openvas_source_addr (&addr.sin_addr);
124  addr.sin_port = htons (port);
125  addr.sin_family = AF_INET;
126 
127  if (bind (socket, (struct sockaddr *) &addr, sizeof (addr)) < 0)
128  return -1;
129  }
130  else if (family == AF_INET6)
131  {
132  struct sockaddr_in6 addr6;
133 
134  openvas_source_addr6 (&addr6.sin6_addr);
135  addr6.sin6_port = htons (port);
136  addr6.sin6_family = AF_INET6;
137 
138  if (bind (socket, (struct sockaddr *) &addr6, sizeof (addr6)) < 0)
139  return -1;
140  }
141  else
142  return -1;
143 
144  return 0;
145 }
146 
152 void
154 {
155  if (addr)
156  memcpy (addr, &global_source_addr.s_addr, 4);
157 }
158 
164 void
165 openvas_source_addr6 (void *addr6)
166 {
167  if (addr6)
168  memcpy (addr6, &global_source_addr6.s6_addr, 16);
169 }
170 
177 void
178 openvas_source_addr_as_addr6 (struct in6_addr *addr6)
179 {
180  if (addr6)
182 }
183 
189 char *
191 {
192  char *str = g_malloc0 (INET_ADDRSTRLEN);
193 
194  inet_ntop (AF_INET, &global_source_addr.s_addr, str, INET_ADDRSTRLEN);
195  return str;
196 }
197 
203 char *
205 {
206  char *str = g_malloc0 (INET6_ADDRSTRLEN);
207 
208  inet_ntop (AF_INET6, &global_source_addr6, str, INET6_ADDRSTRLEN);
209  return str;
210 }
211 
212  /* Miscellaneous functions. */
213 
221 void
222 ipv4_as_ipv6 (const struct in_addr *ip4, struct in6_addr *ip6)
223 {
224  if (ip4 == NULL || ip6 == NULL)
225  return;
226 
227  ip6->s6_addr32[0] = 0;
228  ip6->s6_addr32[1] = 0;
229  ip6->s6_addr32[2] = htonl (0xffff);
230  memcpy (&ip6->s6_addr32[3], ip4, sizeof (struct in_addr));
231 }
232 
233 char *
234 addr6_as_str (const struct in6_addr *addr6)
235 {
236  char *str;
237 
238  if (!addr6)
239  return NULL;
240 
241  str = g_malloc0 (INET6_ADDRSTRLEN);
242  if (IN6_IS_ADDR_V4MAPPED (addr6))
243  inet_ntop (AF_INET, &addr6->s6_addr32[3], str, INET6_ADDRSTRLEN);
244  else
245  inet_ntop (AF_INET6, addr6, str, INET6_ADDRSTRLEN);
246  return str;
247 }
248 
255 void
256 sockaddr_as_str (const struct sockaddr_storage *addr, char *str)
257 {
258  if (!addr || !str)
259  return;
260 
261  if (addr->ss_family == AF_INET)
262  {
263  struct sockaddr_in *saddr = (struct sockaddr_in *) addr;
264  inet_ntop (AF_INET, &saddr->sin_addr, str, INET6_ADDRSTRLEN);
265  }
266  else if (addr->ss_family == AF_INET6)
267  {
268  struct sockaddr_in6 *s6addr = (struct sockaddr_in6 *) addr;
269  if (IN6_IS_ADDR_V4MAPPED (&s6addr->sin6_addr))
270  inet_ntop (AF_INET, &s6addr->sin6_addr.s6_addr[12],
271  str, INET6_ADDRSTRLEN);
272  else
273  inet_ntop (AF_INET6, &s6addr->sin6_addr, str, INET6_ADDRSTRLEN);
274  }
275  else if (addr->ss_family == AF_UNIX)
276  {
277  g_snprintf (str, INET6_ADDRSTRLEN, "unix_socket");
278  }
279  else if (addr->ss_family == AF_UNSPEC)
280  {
281  g_snprintf (str, INET6_ADDRSTRLEN, "unknown_socket");
282  }
283  else
284  {
285  g_snprintf (str, INET6_ADDRSTRLEN,
286  "type_%d_socket", addr->ss_family);
287  }
288 }
289 
300 int
301 openvas_resolve (const char *name, void *dst, int family)
302 {
303  struct addrinfo hints, *info, *p;
304 
305  if (name == NULL || dst == NULL
306  || (family != AF_INET && family != AF_INET6 && family != AF_UNSPEC))
307  return -1;
308 
309  bzero (&hints, sizeof (hints));
310  hints.ai_family = family;
311  hints.ai_socktype = SOCK_STREAM;
312  hints.ai_protocol = 0;
313  if ((getaddrinfo (name, NULL, &hints, &info)) != 0)
314  return -1;
315 
316  p = info;
317  while (p)
318  {
319  if (p->ai_family == family || family == AF_UNSPEC)
320  {
321  if (p->ai_family == AF_INET && family == AF_UNSPEC)
322  {
323  struct sockaddr_in *addrin = (struct sockaddr_in *) p->ai_addr;
324  ipv4_as_ipv6 (&(addrin->sin_addr), dst);
325  }
326  else if (p->ai_family == AF_INET)
327  {
328  struct sockaddr_in *addrin = (struct sockaddr_in *) p->ai_addr;
329  memcpy (dst, &(addrin->sin_addr), sizeof (struct in_addr));
330  }
331  else if (p->ai_family == AF_INET6)
332  {
333  struct sockaddr_in6 *addrin = (struct sockaddr_in6 *) p->ai_addr;
334  memcpy (dst, &(addrin->sin6_addr), sizeof (struct in6_addr));
335  }
336  break;
337  }
338 
339  p = p->ai_next;
340  }
341 
342  freeaddrinfo (info);
343  return 0;
344 }
345 
354 int
355 openvas_resolve_as_addr6 (const char *name, struct in6_addr *ip6)
356 {
357  return openvas_resolve (name, ip6, AF_UNSPEC);
358 }
359 
360 /* Ports related. */
361 
371 int
372 validate_port_range (const char* port_range)
373 {
374  gchar **split, **point, *range, *range_start;
375 
376  if (!port_range)
377  return 1;
378 
379  while (*port_range && isblank (*port_range)) port_range++;
380  if (*port_range == '\0')
381  return 1;
382 
383  /* Treat newlines like commas. */
384  range = range_start = g_strdup (port_range);
385  while (*range)
386  {
387  if (*range == '\n') *range = ',';
388  range++;
389  }
390 
391  split = g_strsplit (range_start, ",", 0);
392  g_free (range_start);
393  point = split;
394 
395  while (*point)
396  {
397  gchar *hyphen, *element;
398 
399  /* Strip off any outer whitespace. */
400 
401  element = g_strstrip (*point);
402 
403  /* Strip off any leading type specifier. */
404 
405  if ((strlen (element) >= 2)
406  && ((element[0] == 'T') || (element[0] == 'U'))
407  && (element[1] == ':'))
408  element = element + 2;
409 
410  /* Look for a hyphen. */
411 
412  hyphen = strchr (element, '-');
413  if (hyphen)
414  {
415  long int number1, number2;
416  const char *first;
417  char *end;
418 
419  hyphen++;
420 
421  /* Check the first number. */
422 
423  first = element;
424  while (*first && isblank (*first)) first++;
425  if (*first == '-')
426  goto fail;
427 
428  errno = 0;
429  number1 = strtol (first, &end, 10);
430  while (*end && isblank (*end)) end++;
431  if (errno || (*end != '-'))
432  goto fail;
433  if (number1 == 0)
434  goto fail;
435  if (number1 > 65535)
436  goto fail;
437 
438  /* Check the second number. */
439 
440  while (*hyphen && isblank (*hyphen)) hyphen++;
441  if (*hyphen == '\0')
442  goto fail;
443 
444  errno = 0;
445  number2 = strtol (hyphen, &end, 10);
446  while (*end && isblank (*end)) end++;
447  if (errno || *end)
448  goto fail;
449  if (number2 == 0)
450  goto fail;
451  if (number2 > 65535)
452  goto fail;
453 
454  if (number1 > number2)
455  goto fail;
456  }
457  else
458  {
459  long int number;
460  const char *only;
461  char *end;
462 
463  /* Check the single number. */
464 
465  only = element;
466  while (*only && isblank (*only)) only++;
467  /* Empty ranges are OK. */
468  if (*only)
469  {
470  errno = 0;
471  number = strtol (only, &end, 10);
472  while (*end && isblank (*end)) end++;
473  if (errno || *end)
474  goto fail;
475  if (number == 0)
476  goto fail;
477  if (number > 65535)
478  goto fail;
479  }
480  }
481  point += 1;
482  }
483 
484  g_strfreev (split);
485  return 0;
486 
487  fail:
488  g_strfreev (split);
489  return 1;
490 }
491 
499 array_t*
500 port_range_ranges (const char *port_range)
501 {
502  gchar **split, **point, *range_start, *current;
503  array_t *ranges;
504  int tcp;
505 
506  if (!port_range)
507  return NULL;
508 
509  ranges = make_array ();
510 
511  while (*port_range && isblank (*port_range)) port_range++;
512 
513  /* Accepts T: and U: before any of the ranges. This toggles the remaining
514  * ranges, as in nmap. Treats a leading naked range as TCP, whereas nmap
515  * treats it as TCP and UDP. */
516 
517  /* Treat newlines like commas. */
518  range_start = current = g_strdup (port_range);
519  while (*current)
520  {
521  if (*current == '\n') *current = ',';
522  current++;
523  }
524 
525  tcp = 1;
526  split = g_strsplit (range_start, ",", 0);
527  g_free (range_start);
528  point = split;
529 
530  while (*point)
531  {
532  gchar *hyphen, *element;
533  range_t *range;
534 
535  element = g_strstrip (*point);
536  if (strlen (element) >= 2)
537  {
538  if ((element[0] == 'T') && (element[1] == ':'))
539  {
540  tcp = 1;
541  element = element + 2;
542  }
543  else if ((element[0] == 'U') && (element[1] == ':'))
544  {
545  tcp = 0;
546  element = element + 2;
547  }
548  /* Else tcp stays as it is. */
549  }
550 
551  /* Skip any space that followed the type specifier. */
552  while (*element && isblank (*element)) element++;
553 
554  hyphen = strchr (element, '-');
555  if (hyphen)
556  {
557  *hyphen = '\0';
558  hyphen++;
559  while (*hyphen && isblank (*hyphen)) hyphen++;
560  assert (*hyphen); /* Validation checks this. */
561 
562  /* A range. */
563 
564  range = (range_t*) g_malloc0 (sizeof (range_t));
565 
566  range->start = atoi (element);
567  range->end = atoi (hyphen);
569  range->exclude = 0;
570 
571  array_add (ranges, range);
572  }
573  else if (*element)
574  {
575  /* A single port. */
576 
577  range = (range_t*) g_malloc0 (sizeof (range_t));
578 
579  range->start = atoi (element);
580  range->end = range->start;
582  range->exclude = 0;
583 
584  array_add (ranges, range);
585  }
586  /* Else skip over empty range. */
587  point += 1;
588  }
589  g_strfreev (split);
590  return ranges;
591 }
592 
602 int
603 port_in_port_ranges (int pnum, port_protocol_t ptype, array_t *pranges)
604 {
605  unsigned int i;
606 
607  if (pranges == NULL || pnum < 0 || pnum > 65536)
608  return 0;
609 
610  for (i = 0; i < pranges->len; i++)
611  {
612  range_t *range = (range_t *) g_ptr_array_index (pranges, i);
613  if (range->type != ptype)
614  continue;
615  if (range->start <= pnum && pnum <= range->end)
616  return 1;
617  }
618  return 0;
619 }
620 
626 int
628 {
629  int sock = socket (PF_INET6, SOCK_STREAM, 0);
630 
631  if (sock == -1 && errno == EAFNOSUPPORT)
632  return 0;
633  close (sock);
634  return 1;
635 }
void openvas_source_addr6(void *addr6)
Gives the source IPv6 address.
int port_in_port_ranges(int pnum, port_protocol_t ptype, array_t *pranges)
Checks if a port num is in port ranges array.
char * openvas_source_addr_str(void)
Gives the source IPv4 address in string format.
void sockaddr_as_str(const struct sockaddr_storage *addr, char *str)
Convert an IP address to string format.
int validate_port_range(const char *port_range)
Validate a port range string.
void openvas_source_addr(void *addr)
Gives the source IPv4 address.
char * openvas_source_addr6_str(void)
Gives the source IPv6 address in string format.
int openvas_resolve(const char *name, void *dst, int family)
Resolves a hostname to an IPv4 or IPv6 address.
GPtrArray array_t
Definition: array.h:31
char * addr6_as_str(const struct in6_addr *addr6)
port_protocol_t
Possible port types.
A port range.
const char * name
Definition: nasl_init.c:524
char global_source_iface[IFNAMSIZ]
int openvas_source_set_socket(int socket, int port, int family)
Binds a socket to use the global source address.
int ipv6_is_enabled()
Checks if IPv6 support is enabled.
int openvas_resolve_as_addr6(const char *name, struct in6_addr *ip6)
Resolves a hostname to an IPv4-mapped IPv6 or IPv6 address.
void openvas_source_addr_as_addr6(struct in6_addr *addr6)
Gives the source IPv4 mapped as an IPv6 address. eg. 192.168.20.10 would map to ::ffff:192.168.20.10.
void array_add(array_t *array, gpointer pointer)
Push a generic pointer onto an array.
Definition: array.c:82
int openvas_source_iface_is_set(void)
struct in6_addr global_source_addr6
int openvas_source_iface_init(const char *iface)
Initializes the source network interface name and related information.
GPtrArray * make_array()
Make a global array.
Definition: array.c:39
void ipv4_as_ipv6(const struct in_addr *ip4, struct in6_addr *ip6)
Maps an IPv4 address as an IPv6 address. eg. 192.168.10.20 would map to ::ffff:192.168.10.20.
port_protocol_t type
struct in_addr global_source_addr
array_t * port_range_ranges(const char *port_range)
Create a range array from a port_range string.