OpenVAS Libraries  9.0.3
openvas_hosts.c
Go to the documentation of this file.
1 /* openvas-libraries/base
2  * $Id$
3  * Description: Implementation of API to handle Hosts objects
4  *
5  * Authors:
6  * Hani Benhabiles <hani.benhabiles@greenbone.net>
7  * Jan-Oliver Wagner <jan-oliver.wagner@greenbone.net>
8  *
9  * Copyright:
10  * Copyright (C) 2013 Greenbone Networks GmbH
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
25  */
26 
37 #include "openvas_hosts.h"
38 
39 /* Static variables */
40 
42  [HOST_TYPE_NAME] = "Hostname",
43  [HOST_TYPE_IPV4] = "IPv4",
44  [HOST_TYPE_IPV6] = "IPv6",
45  [HOST_TYPE_CIDR_BLOCK] = "IPv4 CIDR block",
46  [HOST_TYPE_RANGE_SHORT] = "IPv4 short range",
47  [HOST_TYPE_RANGE_LONG] = "IPv4 long range"
48 };
49 
50 /* Function definitions */
51 
60 static int
61 is_ipv4_address (const char *str)
62 {
63  struct sockaddr_in sa;
64 
65  return inet_pton(AF_INET, str, &(sa.sin_addr)) == 1;
66 }
67 
76 static int
77 is_ipv6_address (const char *str)
78 {
79  struct sockaddr_in6 sa6;
80 
81  return inet_pton(AF_INET6, str, &(sa6.sin6_addr)) == 1;
82 }
83 
92 static int
93 is_cidr_block (const char *str)
94 {
95  long block;
96  char *addr_str, *block_str, *p;
97 
98  addr_str = g_strdup (str);
99  block_str = strchr (addr_str, '/');
100  if (block_str == NULL)
101  {
102  g_free (addr_str);
103  return 0;
104  }
105 
106  /* Separate the address from the block value. */
107  *block_str = '\0';
108  block_str++;
109 
110  if (!is_ipv4_address (addr_str) || !isdigit (*block_str))
111  {
112  g_free (addr_str);
113  return 0;
114  }
115 
116  p = NULL;
117  block = strtol (block_str, &p, 10);
118  g_free (addr_str);
119 
120  if (*p || block <= 0 || block > 30)
121  return 0;
122 
123  return 1;
124 }
125 
135 static int
136 cidr_get_block (const char *str, unsigned int *block)
137 {
138  if (str == NULL || block == NULL)
139  return -1;
140 
141  if (sscanf (str, "%*[0-9.]/%2u", block)
142  != 1)
143  return -1;
144 
145  return 0;
146 }
147 
157 static int
158 cidr_get_ip (const char *str, struct in_addr *addr)
159 {
160  gchar *addr_str, *tmp;
161 
162  if (str == NULL || addr == NULL)
163  return -1;
164 
165  addr_str = g_strdup (str);
166  tmp = strchr (addr_str, '/');
167  if (tmp == NULL)
168  {
169  g_free (addr_str);
170  return -1;
171  }
172  *tmp = '\0';
173 
174  if (inet_pton (AF_INET, addr_str, addr) != 1)
175  return -1;
176 
177  g_free (addr_str);
178  return 0;
179 }
180 
197 static int
198 cidr_block_ips (const char *str, struct in_addr *first, struct in_addr *last)
199 {
200  unsigned int block;
201 
202  if (str == NULL || first == NULL || last == NULL)
203  return -1;
204 
205  /* Get IP and block values. */
206  if (cidr_get_block (str, &block) == -1)
207  return -1;
208  if (cidr_get_ip (str, first) == -1)
209  return -1;
210 
211  /* First IP: And with mask and increment. */
212  first->s_addr &= htonl (0xffffffff ^ ((1 << (32 - block)) - 1));
213  first->s_addr = htonl (ntohl (first->s_addr) + 1);
214 
215  /* Last IP: First IP + Number of usable hosts - 1. */
216  last->s_addr = htonl (ntohl (first->s_addr) + (1 << (32 - block)) - 3);
217  return 0;
218 }
219 
228 static int
229 is_long_range_network (const char *str)
230 {
231  char *first_str, *second_str;
232  int ret;
233 
234  first_str = g_strdup (str);
235  second_str = strchr (first_str, '-');
236  if (second_str == NULL)
237  {
238  g_free (first_str);
239  return 0;
240  }
241 
242  /* Separate the addresses. */
243  *second_str = '\0';
244  second_str++;
245 
246  ret = is_ipv4_address (first_str) && is_ipv4_address (second_str);
247  g_free (first_str);
248 
249  return ret;
250 }
251 
263 static int
264 long_range_network_ips (const char *str, struct in_addr *first,
265  struct in_addr *last)
266 {
267  char *first_str, *last_str;
268 
269  if (str == NULL || first == NULL || last == NULL)
270  return -1;
271 
272  first_str = g_strdup (str);
273  last_str = strchr (first_str, '-');
274  if (last_str == NULL)
275  {
276  g_free (first_str);
277  return -1;
278  }
279 
280  /* Separate the two IPs. */
281  *last_str = '\0';
282  last_str++;
283 
284  if (inet_pton (AF_INET, first_str, first) != 1
285  || inet_pton (AF_INET, last_str, last) != 1)
286  {
287  g_free (first_str);
288  return -1;
289  }
290 
291  g_free (first_str);
292  return 0;
293 }
294 
303 static int
304 is_short_range_network (const char *str)
305 {
306  long end;
307  char *ip_str, *end_str, *p;
308 
309  ip_str = g_strdup (str);
310  end_str = strchr (ip_str, '-');
311  if (end_str == NULL)
312  {
313  g_free (ip_str);
314  return 0;
315  }
316 
317  /* Separate the addreses. */
318  *end_str = '\0';
319  end_str++;
320 
321  if (!is_ipv4_address (ip_str) || !isdigit (*end_str))
322  {
323  g_free (ip_str);
324  return 0;
325  }
326 
327  p = NULL;
328  end = strtol (end_str, &p, 10);
329  g_free (ip_str);
330 
331  if (*p || end < 0 || end > 255)
332  return 0;
333 
334  return 1;
335 }
336 
348 static int
349 short_range_network_ips (const char *str, struct in_addr *first,
350  struct in_addr *last)
351 {
352  char *first_str, *last_str;
353  int end;
354 
355  if (str == NULL || first == NULL || last == NULL)
356  return -1;
357 
358  first_str = g_strdup (str);
359  last_str = strchr (first_str, '-');
360  if (last_str == NULL)
361  {
362  g_free (first_str);
363  return -1;
364  }
365 
366  /* Separate the two IPs. */
367  *last_str = '\0';
368  last_str++;
369  end = atoi (last_str);
370 
371  /* Get the first IP */
372  if (inet_pton (AF_INET, first_str, first) != 1)
373  {
374  g_free (first_str);
375  return -1;
376  }
377 
378  /* Get the last IP */
379  last->s_addr = htonl ((ntohl (first->s_addr) & 0xffffff00) + end);
380 
381  g_free (first_str);
382  return 0;
383 }
384 
394 static int
395 is_hostname (const char *str)
396 {
397  const char *h = str;
398 
399  while (*h && (isalnum (*h) || strchr ("-_.", *h)))
400  h++;
401 
402  /* Valid string if no other chars, and length is 255 at most. */
403  if (*h == '\0' && h - str < 256)
404  return 1;
405 
406  return 0;
407 }
408 
417 static int
418 is_cidr6_block (const char *str)
419 {
420  long block;
421  char *addr6_str, *block_str, *p;
422 
423  addr6_str = g_strdup (str);
424  block_str = strchr (addr6_str, '/');
425  if (block_str == NULL)
426  {
427  g_free (addr6_str);
428  return 0;
429  }
430 
431  /* Separate the address from the block value. */
432  *block_str = '\0';
433  block_str++;
434 
435  if (!is_ipv6_address (addr6_str) || !isdigit (*block_str))
436  {
437  g_free (addr6_str);
438  return 0;
439  }
440 
441  p = NULL;
442  block = strtol (block_str, &p, 10);
443  g_free (addr6_str);
444 
445  if (*p || block <= 0 || block > 128)
446  return 0;
447 
448  return 1;
449 }
450 
460 static int
461 cidr6_get_block (const char *str, unsigned int *block)
462 {
463  if (str == NULL || block == NULL)
464  return -1;
465 
466  if (sscanf (str, "%*[0-9a-fA-F.:]/%3u", block)
467  != 1)
468  return -1;
469 
470  return 0;
471 }
472 
482 static int
483 cidr6_get_ip (const char *str, struct in6_addr *addr6)
484 {
485  gchar *addr6_str, *tmp;
486 
487  if (str == NULL || addr6 == NULL)
488  return -1;
489 
490  addr6_str = g_strdup (str);
491  tmp = strchr (addr6_str, '/');
492  if (tmp == NULL)
493  {
494  g_free (addr6_str);
495  return -1;
496  }
497  *tmp = '\0';
498 
499  if (inet_pton (AF_INET6, addr6_str, addr6) != 1)
500  return -1;
501 
502  g_free (addr6_str);
503  return 0;
504 }
505 
517 static int
518 cidr6_block_ips (const char *str, struct in6_addr *first, struct in6_addr *last)
519 {
520  unsigned int block;
521  int i, j;
522 
523  if (str == NULL || first == NULL || last == NULL)
524  return -1;
525 
526  /* Get IP and block values. */
527  if (cidr6_get_block (str, &block) == -1)
528  return -1;
529  if (cidr6_get_ip (str, first) == -1)
530  return -1;
531  memcpy (&last->s6_addr, &first->s6_addr, 16);
532 
533  /* /128 => Specified address is the first and last one. */
534  if (block == 128)
535  return 0;
536 
537  /* First IP: And with mask and increment to skip network address. */
538  j = 15;
539  for (i = (128 - block) / 8; i > 0; i--)
540  {
541  first->s6_addr[j] = 0;
542  j--;
543  }
544  first->s6_addr[j] &= 0xff ^ ((1 << ((128 - block) % 8)) - 1);
545 
546  /* Last IP: Broadcast address - 1. */
547  j = 15;
548  for (i = (128 - block) / 8; i > 0; i--)
549  {
550  last->s6_addr[j] = 0xff;
551  j--;
552  }
553  last->s6_addr[j] |= (1 << ((128 - block) % 8)) - 1;
554 
555  /* /127 => Only two addresses. Don't skip network / broadcast addresses.*/
556  if (block == 127)
557  return 0;
558 
559  /* Increment first IP. */
560  for (i = 15; i >= 0; --i)
561  if (first->s6_addr[i] < 255)
562  {
563  first->s6_addr[i]++;
564  break;
565  }
566  else
567  first->s6_addr[i] = 0;
568  /* Decrement last IP. */
569  for (i = 15; i >= 0; --i)
570  if (last->s6_addr[i] > 0)
571  {
572  last->s6_addr[i]--;
573  break;
574  }
575  else
576  last->s6_addr[i] = 0xff;
577 
578  return 0;
579 }
580 
589 static int
590 is_long_range6_network (const char *str)
591 {
592  char *first_str, *second_str;
593  int ret;
594 
595  first_str = g_strdup (str);
596  second_str = strchr (first_str, '-');
597  if (second_str == NULL)
598  {
599  g_free (first_str);
600  return 0;
601  }
602 
603  /* Separate the addreses. */
604  *second_str = '\0';
605  second_str++;
606 
607  ret = is_ipv6_address (first_str) && is_ipv6_address (second_str);
608  g_free (first_str);
609 
610  return ret;
611 }
612 
624 static int
625 long_range6_network_ips (const char *str, struct in6_addr *first,
626  struct in6_addr *last)
627 {
628  char *first_str, *last_str;
629 
630  if (str == NULL || first == NULL || last == NULL)
631  return -1;
632 
633  first_str = g_strdup (str);
634  last_str = strchr (first_str, '-');
635  if (last_str == NULL)
636  {
637  g_free (first_str);
638  return -1;
639  }
640 
641  /* Separate the two IPs. */
642  *last_str = '\0';
643  last_str++;
644 
645  if (inet_pton (AF_INET6, first_str, first) != 1
646  || inet_pton (AF_INET6, last_str, last) != 1)
647  {
648  g_free (first_str);
649  return -1;
650  }
651 
652  g_free (first_str);
653  return 0;
654 }
655 
664 static int
665 is_short_range6_network (const char *str)
666 {
667  char *ip_str, *end_str, *p;
668 
669  ip_str = g_strdup (str);
670  end_str = strchr (ip_str, '-');
671  if (end_str == NULL)
672  {
673  g_free (ip_str);
674  return 0;
675  }
676 
677  /* Separate the addresses. */
678  *end_str = '\0';
679  end_str++;
680 
681  if (!is_ipv6_address (ip_str) || *end_str == '\0')
682  {
683  g_free (ip_str);
684  return 0;
685  }
686 
687  p = end_str;
688  /* Check that the 2nd part is at most 4 hexadecimal characters. */
689  while (isxdigit (*p) && p++);
690  if (*p || p - end_str > 4)
691  {
692  g_free (ip_str);
693  return 0;
694  }
695 
696  g_free (ip_str);
697  return 1;
698 }
699 
711 static int
712 short_range6_network_ips (const char *str, struct in6_addr *first,
713  struct in6_addr *last)
714 {
715  char *first_str, *last_str;
716  long int end;
717 
718  if (str == NULL || first == NULL || last == NULL)
719  return -1;
720 
721  first_str = g_strdup (str);
722  last_str = strchr (first_str, '-');
723  if (last_str == NULL)
724  {
725  g_free (first_str);
726  return -1;
727  }
728 
729  /* Separate the first IP. */
730  *last_str = '\0';
731  last_str++;
732 
733  if (inet_pton (AF_INET6, first_str, first) != 1)
734  {
735  g_free (first_str);
736  return -1;
737  }
738 
739  /* Calculate the last IP. */
740  memcpy (last, first, sizeof (*last));
741  end = strtol (last_str, NULL, 16);
742  memcpy (&last->s6_addr[15], &end, 1);
743  memcpy (&last->s6_addr[14], ((char *) &end) + 1, 1);
744 
745  g_free (first_str);
746  return 0;
747 }
748 
757 int
758 openvas_get_host_type (const gchar *str_stripped)
759 {
760  /*
761  * We have a single element with no leading or trailing
762  * white spaces. This element could represent different host
763  * definitions: single IPs, host names, CIDR-expressed blocks,
764  * range-expressed networks, IPv6 addresses.
765  */
766 
767  /* Null or empty string. */
768  if (str_stripped == NULL || *str_stripped == '\0')
769  return -1;
770 
771  /* Check for regular single IPv4 address. */
772  if (is_ipv4_address (str_stripped))
773  return HOST_TYPE_IPV4;
774 
775  /* Check for regular single IPv6 address. */
776  if (is_ipv6_address (str_stripped))
777  return HOST_TYPE_IPV6;
778 
779  /* Check for regular IPv4 CIDR-expressed block like "192.168.12.0/24" */
780  if (is_cidr_block (str_stripped))
781  return HOST_TYPE_CIDR_BLOCK;
782 
783  /* Check for short range-expressed networks "192.168.12.5-40" */
784  if (is_short_range_network (str_stripped))
785  return HOST_TYPE_RANGE_SHORT;
786 
787  /* Check for long range-expressed networks "192.168.1.0-192.168.3.44" */
788  if (is_long_range_network (str_stripped))
789  return HOST_TYPE_RANGE_LONG;
790 
791  /* Check for regular IPv6 CIDR-expressed block like "2620:0:2d0:200::7/120" */
792  if (is_cidr6_block (str_stripped))
793  return HOST_TYPE_CIDR6_BLOCK;
794 
795  /* Check for short range-expressed networks "::1-ef12" */
796  if (is_short_range6_network (str_stripped))
797  return HOST_TYPE_RANGE6_SHORT;
798 
799  /* Check for long IPv6 range-expressed networks like "::1:20:7-::1:25:3" */
800  if (is_long_range6_network (str_stripped))
801  return HOST_TYPE_RANGE6_LONG;
802 
803  /* Check for hostname. */
804  if (is_hostname (str_stripped))
805  return HOST_TYPE_NAME;
806 
807  /* @todo: If everything else fails, fallback to hostname ? */
808  return -1;
809 }
810 
816 static openvas_host_t *
817 openvas_host_new ()
818 {
819  openvas_host_t *host;
820 
821  host = g_malloc0 (sizeof (openvas_host_t));
822 
823  return host;
824 }
825 
831 static void
832 openvas_host_free (gpointer host)
833 {
834  openvas_host_t *h = host;
835  if (h == NULL)
836  return;
837 
838  /* If host of type hostname, free the name buffer, first. */
839  if (h->type == HOST_TYPE_NAME)
840  g_free (h->name);
841 
842  g_free (h);
843 }
844 
851 static void
852 openvas_hosts_deduplicate (openvas_hosts_t *hosts)
853 {
857  GList *element;
858  GHashTable *name_table;
859  int duplicates = 0;
860 
861  if (hosts == NULL)
862  return;
863  element = hosts->hosts;
864  name_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
865 
866  while (element)
867  {
868  gchar *name;
869 
870  if ((name = openvas_host_value_str (element->data)))
871  {
872  if (g_hash_table_lookup (name_table, name))
873  {
874  GList *tmp;
875 
876  tmp = element;
877  element = element->next;
878  openvas_host_free (tmp->data);
879  hosts->hosts = g_list_delete_link (hosts->hosts, tmp);
880  duplicates++;
881  g_free (name);
882  }
883  else
884  {
885  /* Insert in hash table. Value not important, but not NULL. */
886  g_hash_table_insert (name_table, name, hosts);
887  element = element->next;
888  }
889  }
890  else
891  element = element->next;
892  }
893 
894  g_hash_table_destroy (name_table);
895  hosts->count -= duplicates;
896  hosts->removed += duplicates;
897  hosts->current = hosts->hosts;
898 }
899 
912 openvas_hosts_new_with_max (const gchar *hosts_str, unsigned int max_hosts)
913 {
914  openvas_hosts_t *hosts;
915  gchar **host_element, **split;
916  gchar *str;
917 
918  if (hosts_str == NULL)
919  return NULL;
920 
921  hosts = g_malloc0 (sizeof (openvas_hosts_t));
922  if (hosts == NULL)
923  return NULL;
924 
925  hosts->orig_str = g_strdup (hosts_str);
926  /* Normalize separator: Transform newlines into commas. */
927  str = hosts->orig_str;
928  while (*str)
929  {
930  if (*str == '\n') *str = ',';
931  str++;
932  }
933 
934  /* Split comma-separeted list into single host-specifications */
935  split = g_strsplit (hosts->orig_str, ",", 0);
936 
937  /* first element of the splitted list */
938  host_element = split;
939  while (*host_element)
940  {
941  int host_type;
942  gchar *stripped = g_strstrip (*host_element);
943 
944  if (stripped == NULL || *stripped == '\0')
945  {
946  host_element++;
947  continue;
948  }
949 
950  /* IPv4, hostname, IPv6, collection (short/long range, cidr block) etc,. ? */
951  /* -1 if error. */
952  host_type = openvas_get_host_type (stripped);
953 
954  switch (host_type)
955  {
956  case HOST_TYPE_NAME:
957  case HOST_TYPE_IPV4:
958  case HOST_TYPE_IPV6:
959  {
960  /* New host. */
961  openvas_host_t *host = openvas_host_new ();
962  host->type = host_type;
963  if (host_type == HOST_TYPE_NAME)
964  host->name = g_strdup (stripped);
965  else if (host_type == HOST_TYPE_IPV4)
966  inet_pton (AF_INET, stripped, &host->addr);
967  else if (host_type == HOST_TYPE_IPV6)
968  inet_pton (AF_INET6, stripped, &host->addr6);
969  /* Prepend to list of hosts. */
970  hosts->hosts = g_list_prepend (hosts->hosts, host);
971  hosts->count++;
972  break;
973  }
977  {
978  struct in_addr first, last;
979  uint32_t current;
980  int (*ips_func) (const char *, struct in_addr *, struct in_addr *);
981 
983  ips_func = cidr_block_ips;
984  else if (host_type == HOST_TYPE_RANGE_SHORT)
985  ips_func = short_range_network_ips;
986  else if (host_type == HOST_TYPE_RANGE_LONG)
987  ips_func = long_range_network_ips;
988  else
989  break;
990 
991  if (ips_func (stripped, &first, &last) == -1)
992  break;
993 
994  /* Make sure that first actually comes before last */
995  if (ntohl (first.s_addr) > ntohl (last.s_addr))
996  break;
997 
998  /* Add addresses from first to last as single hosts. */
999  current = first.s_addr;
1000  while (ntohl (current) <= ntohl (last.s_addr))
1001  {
1002  openvas_host_t *host = openvas_host_new ();
1003  host->type = HOST_TYPE_IPV4;
1004  host->addr.s_addr = current;
1005  hosts->hosts = g_list_prepend (hosts->hosts, host);
1006  hosts->count++;
1007  if (max_hosts > 0 && hosts->count > max_hosts)
1008  {
1009  g_strfreev (split);
1010  openvas_hosts_free (hosts);
1011  return NULL;
1012  }
1013  /* Next IP address. */
1014  current = htonl (ntohl (current) + 1);
1015  }
1016  break;
1017  }
1018  case HOST_TYPE_CIDR6_BLOCK:
1019  case HOST_TYPE_RANGE6_LONG:
1021  {
1022  struct in6_addr first, last;
1023  unsigned char current[16];
1024  int (*ips_func) (const char *, struct in6_addr *, struct in6_addr *);
1025 
1027  ips_func = cidr6_block_ips;
1028  else if (host_type == HOST_TYPE_RANGE6_SHORT)
1029  ips_func = short_range6_network_ips;
1030  else if (host_type == HOST_TYPE_RANGE6_LONG)
1031  ips_func = long_range6_network_ips;
1032  else
1033  continue;
1034 
1035  if (ips_func (stripped, &first, &last) == -1)
1036  break;
1037 
1038  /* Make sure the first comes before the last. */
1039  if (memcmp (&first.s6_addr, &last.s6_addr, 16) > 0)
1040  break;
1041 
1042  /* Add addresses from first to last as single hosts. */
1043  memcpy (current, &first.s6_addr, 16);
1044  while (memcmp (current, &last.s6_addr, 16) <= 0)
1045  {
1046  int i;
1047 
1048  openvas_host_t *host = openvas_host_new ();
1049  host->type = HOST_TYPE_IPV6;
1050  memcpy (host->addr6.s6_addr, current, 16);
1051  hosts->hosts = g_list_prepend (hosts->hosts, host);
1052  hosts->count++;
1053  if (max_hosts > 0 && hosts->count > max_hosts)
1054  {
1055  g_strfreev (split);
1056  openvas_hosts_free (hosts);
1057  return NULL;
1058  }
1059  /* Next IPv6 address. */
1060  for (i = 15; i >= 0; --i)
1061  if (current[i] < 255)
1062  {
1063  current[i]++;
1064  break;
1065  }
1066  else
1067  current[i] = 0;
1068  }
1069  break;
1070  }
1071  case -1:
1072  default:
1073  /* Invalid host string. */
1074  g_strfreev (split);
1075  openvas_hosts_free (hosts);
1076  return NULL;
1077  }
1078  host_element++; /* move on to next element of splitted list */
1079  if (max_hosts > 0 && hosts->count > max_hosts)
1080  {
1081  g_strfreev (split);
1082  openvas_hosts_free (hosts);
1083  return NULL;
1084  }
1085  }
1086 
1087  /* Reverse list, as we were prepending (for performance) to the list. */
1088  hosts->hosts = g_list_reverse (hosts->hosts);
1089 
1090  /* Remove duplicated values. */
1091  openvas_hosts_deduplicate (hosts);
1092 
1093  /* Set current to start of hosts list. */
1094  hosts->current = hosts->hosts;
1095 
1096  g_strfreev (split);
1097  return hosts;
1098 }
1099 
1111 openvas_hosts_new (const gchar *hosts_str)
1112 {
1113  return openvas_hosts_new_with_max (hosts_str, 0);
1114 }
1115 
1126 {
1127  openvas_host_t *next;
1128 
1129  if (hosts == NULL || hosts->current == NULL)
1130  return NULL;
1131 
1132  next = hosts->current->data;
1133  hosts->current = g_list_next (hosts->current);
1134 
1135  return next;
1136 }
1137 
1144 void
1146 {
1147  if (hosts == NULL)
1148  return;
1149 
1150  if (hosts->orig_str)
1151  g_free (hosts->orig_str);
1152 
1153  g_list_free_full (hosts->hosts, openvas_host_free);
1154 
1155  g_free (hosts);
1156 }
1157 
1165 void
1167 {
1168  int count;
1169  GList *new_list;
1170  GRand *rand;
1171 
1172  if (hosts == NULL)
1173  return;
1174 
1175  count = openvas_hosts_count (hosts);
1176  new_list = NULL;
1177 
1178  rand = g_rand_new ();
1179 
1180  while (count)
1181  {
1182  GList *element;
1183 
1184  /* Get element from random position [0, count[. */
1185  element = g_list_nth (hosts->hosts, g_rand_int_range (rand, 0, count));
1186  /* Remove it. */
1187  hosts->hosts = g_list_remove_link (hosts->hosts, element);
1188  /* Insert it in new list */
1189  new_list = g_list_concat (element, new_list);
1190  count--;
1191  }
1192  hosts->hosts = new_list;
1193  hosts->current = hosts->hosts;
1194 
1195  g_rand_free (rand);
1196 }
1197 
1205 void
1207 {
1208  if (hosts == NULL || hosts->hosts == NULL)
1209  return;
1210 
1211  hosts->hosts = g_list_reverse (hosts->hosts);
1212  hosts->current = hosts->hosts;
1213 }
1214 
1223 static GList *
1224 openvas_hosts_remove_element (openvas_hosts_t *hosts, GList *element)
1225 {
1226  GList *tmp;
1227 
1228  tmp = element;
1229  element = element->next;
1230  openvas_host_free (tmp->data);
1231  hosts->hosts = g_list_delete_link (hosts->hosts, tmp);
1232  return element;
1233 }
1234 
1243 void
1245 {
1246  openvas_host_t *host;
1247 
1248  hosts->current = hosts->hosts;
1249 
1250  while ((host = openvas_hosts_next (hosts)))
1251  {
1252  struct in_addr addr;
1253 
1254  if (host->type != HOST_TYPE_NAME)
1255  continue;
1256 
1257  if (openvas_host_resolve (host, &addr, AF_INET) == 0)
1258  {
1259  g_free (host->name);
1260  host->type = HOST_TYPE_IPV4;
1261  memcpy (&host->addr, &addr, sizeof (host->addr));
1262  }
1263  }
1264 
1265  hosts->current = hosts->hosts;
1266 }
1267 
1279 int
1280 openvas_hosts_exclude (openvas_hosts_t *hosts, const char *excluded_str,
1281  int resolve)
1282 {
1286  openvas_hosts_t *excluded_hosts;
1287  GList *element;
1288  GHashTable *name_table;
1289  int excluded = 0;
1290 
1291  if (hosts == NULL || excluded_str == NULL)
1292  return -1;
1293 
1294  excluded_hosts = openvas_hosts_new (excluded_str);
1295  if (excluded_hosts == NULL)
1296  return -1;
1297 
1298  if (resolve)
1299  openvas_hosts_resolve (excluded_hosts);
1300 
1301  if (openvas_hosts_count (excluded_hosts) == 0)
1302  {
1303  openvas_hosts_free (excluded_hosts);
1304  return 0;
1305  }
1306 
1307  /* Hash host values from excluded hosts list. */
1308  element = excluded_hosts->hosts;
1309  name_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
1310  while (element)
1311  {
1312  gchar *name;
1313 
1314  if ((name = openvas_host_value_str (element->data)))
1315  g_hash_table_insert (name_table, name, hosts);
1316  element = element->next;
1317  }
1318 
1319  /* Check for hosts values in hash table. */
1320  element = hosts->hosts;
1321  while (element)
1322  {
1323  gchar *name;
1324  struct in_addr addr;
1325  openvas_host_t *host = element->data;
1326 
1327  if ((name = openvas_host_value_str (host)))
1328  {
1329  if (g_hash_table_lookup (name_table, name))
1330  {
1331  element = openvas_hosts_remove_element (hosts, element);
1332  excluded++;
1333  g_free (name);
1334  continue;
1335  }
1336  g_free (name);
1337  }
1338 
1339  /* If hostname, try to resolve it and check if IP is excluded. */
1340  if (resolve && host->type == HOST_TYPE_NAME
1341  && openvas_host_resolve (host, &addr, AF_INET) == 0)
1342  {
1343  struct in6_addr addr6;
1344 
1345  ipv4_as_ipv6 (&addr, &addr6);
1346  name = addr6_as_str (&addr6);
1347  if (g_hash_table_lookup (name_table, name))
1348  {
1349  element = openvas_hosts_remove_element (hosts, element);
1350  excluded++;
1351  g_free (name);
1352  continue;
1353  }
1354  g_free (name);
1355  }
1356 
1357  element = element->next;
1358  }
1359 
1360  /* Cleanup. */
1361  hosts->count -= excluded;
1362  hosts->removed += excluded;
1363  hosts->current = hosts->hosts;
1364  g_hash_table_destroy (name_table);
1365  openvas_hosts_free (excluded_hosts);
1366  return excluded;
1367 }
1368 
1377 char *
1379 {
1380 
1381  if (host == NULL)
1382  return NULL;
1383 
1384  if (host->type == HOST_TYPE_NAME)
1385  return g_strdup (host->name);
1386  else if (host->type == HOST_TYPE_IPV4)
1387  {
1388  struct sockaddr_in sa;
1389  int retry = 2;
1390  gchar hostname[1000];
1391 
1392  bzero (&sa, sizeof (struct sockaddr));
1393  sa.sin_addr = host->addr;
1394  sa.sin_family = AF_INET;
1395  while (retry--)
1396  {
1397  int ret = getnameinfo ((struct sockaddr *) &sa, sizeof (sa), hostname,
1398  sizeof (hostname), NULL, 0, NI_NAMEREQD);
1399  if (!ret)
1400  return g_strdup (hostname);
1401  if (ret != EAI_AGAIN)
1402  break;
1403  }
1404  return NULL;
1405  }
1406  else if (host->type == HOST_TYPE_IPV6)
1407  {
1408  struct sockaddr_in6 sa;
1409  char hostname[1000];
1410 
1411  bzero (&sa, sizeof (struct sockaddr));
1412  memcpy (&sa.sin6_addr, &host->addr6, 16);
1413  sa.sin6_family = AF_INET6;
1414 
1415  if (getnameinfo ((struct sockaddr *) &sa, sizeof (sa), hostname,
1416  sizeof (hostname), NULL, 0, NI_NAMEREQD))
1417  return NULL;
1418  else
1419  return g_strdup (hostname);
1420  }
1421  else
1422  return NULL;
1423 }
1424 
1434 int
1436 {
1437  int count;
1438  GList *element;
1439 
1440  if (hosts == NULL)
1441  return -1;
1442 
1443  count = 0;
1444  element = hosts->hosts;
1445  while (element)
1446  {
1447  gchar *name = openvas_host_reverse_lookup (element->data);
1448 
1449  if (name == NULL)
1450  {
1451  element = openvas_hosts_remove_element (hosts, element);
1452  count++;
1453  }
1454  else
1455  {
1456  g_free (name);
1457  element = element->next;
1458  }
1459  }
1460 
1461  hosts->count -= count;
1462  hosts->removed += count;
1463  hosts->current = hosts->hosts;
1464  return count;
1465 }
1466 
1476 int
1478 {
1482  int count;
1483  GList *element;
1484  GHashTable *name_table;
1485 
1486  if (hosts == NULL)
1487  return -1;
1488 
1489  name_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
1490  count = 0;
1491  element = hosts->hosts;
1492  while (element)
1493  {
1494  gchar *name;
1495 
1496  if ((name = openvas_host_reverse_lookup (element->data)))
1497  {
1498  if (g_hash_table_lookup (name_table, name))
1499  {
1500  element = openvas_hosts_remove_element (hosts, element);
1501  count++;
1502  g_free (name);
1503  }
1504  else
1505  {
1506  /* Insert in the hash table. Value not important. */
1507  g_hash_table_insert (name_table, name, hosts);
1508  element = element->next;
1509  }
1510  }
1511  else
1512  element = element->next;
1513  }
1514 
1515  g_hash_table_destroy (name_table);
1516  hosts->removed += count;
1517  hosts->count -= count;
1518  hosts->current = hosts->hosts;
1519  return count;
1520 }
1521 
1529 unsigned int
1531 {
1532  return hosts ? hosts->count : 0;
1533 }
1534 
1543 unsigned int
1545 {
1546  return hosts ? hosts->removed : 0;
1547 }
1548 
1561 int
1562 openvas_host_in_hosts (const openvas_host_t *host, const struct in6_addr *addr,
1563  const openvas_hosts_t *hosts)
1564 {
1565  char *host_str;
1566  GList *element;
1567 
1568  if (host == NULL || hosts == NULL)
1569  return 0;
1570 
1571  host_str = openvas_host_value_str (host);
1572 
1573  element = hosts->hosts;
1574  while (element)
1575  {
1576  char *tmp = openvas_host_value_str (element->data);
1577 
1578  if (strcasecmp (host_str, tmp) == 0)
1579  {
1580  g_free (host_str);
1581  g_free (tmp);
1582  return 1;
1583  }
1584  g_free (tmp);
1585 
1586  /* Hostnames in hosts list shouldn't be resolved. */
1587  if (addr && openvas_host_type (element->data) != HOST_TYPE_NAME)
1588  {
1589  struct in6_addr tmpaddr;
1590  openvas_host_get_addr6 (element->data, &tmpaddr);
1591 
1592  if (memcmp (addr->s6_addr, &tmpaddr.s6_addr, 16) == 0)
1593  {
1594  g_free (host_str);
1595  return 1;
1596  }
1597 
1598  }
1599  element = element->next;
1600  }
1601 
1602  g_free (host_str);
1603  return 0;
1604 }
1605 
1613 enum host_type
1615 {
1616  assert (host);
1617  return host->type;
1618 }
1619 
1628 gchar *
1630 {
1631  if (host == NULL)
1632  return NULL;
1633 
1634  return host_type_str[host->type];
1635 }
1636 
1644 gchar *
1646 {
1647  if (host == NULL)
1648  return NULL;
1649 
1650  switch (host->type)
1651  {
1652  case HOST_TYPE_NAME:
1653  return g_strdup (host->name);
1654  break;
1655  case HOST_TYPE_IPV4:
1656  case HOST_TYPE_IPV6:
1657  /* Handle both cases using inet_ntop(). */
1658  {
1659  int family, size;
1660  gchar *str;
1661  const void *srcaddr;
1662 
1663  if (host->type == HOST_TYPE_IPV4)
1664  {
1665  family = AF_INET;
1666  size = INET_ADDRSTRLEN;
1667  srcaddr = &host->addr;
1668  }
1669  else
1670  {
1671  family = AF_INET6;
1672  size = INET6_ADDRSTRLEN;
1673  srcaddr = &host->addr6;
1674  }
1675 
1676  str = g_malloc0 (size);
1677  if (inet_ntop (family, srcaddr, str, size) == NULL)
1678  {
1679  perror ("inet_ntop");
1680  g_free (str);
1681  return NULL;
1682  }
1683  return str;
1684  }
1685  default:
1686  return g_strdup ("Erroneous host type: Should be Hostname/IPv4/IPv6.");
1687  }
1688 }
1689 
1701 int
1702 openvas_host_resolve (const openvas_host_t *host, void *dst, int family)
1703 {
1704  if (host == NULL || dst == NULL || host->type != HOST_TYPE_NAME)
1705  return -1;
1706 
1707  return openvas_resolve (host->name, dst, family);
1708 }
1709 
1722 int
1723 openvas_host_get_addr6 (const openvas_host_t *host, struct in6_addr *ip6)
1724 {
1725  if (host == NULL || ip6 == NULL)
1726  return -1;
1727 
1728  switch (openvas_host_type (host))
1729  {
1730  case HOST_TYPE_IPV6:
1731  memcpy (ip6, &host->addr6, sizeof (struct in6_addr));
1732  return 0;
1733 
1734  case HOST_TYPE_IPV4:
1735  ipv4_as_ipv6 (&host->addr, ip6);
1736  return 0;
1737 
1738  case HOST_TYPE_NAME:
1739  {
1740  struct in_addr ip4;
1741 
1742  /* Fail if IPv4 and IPv6 both don't resolve. */
1743  if (openvas_host_resolve (host, &ip4, AF_INET) == 0)
1744  ipv4_as_ipv6 (&ip4, ip6);
1745  else if (openvas_host_resolve (host, ip6, AF_INET6) == -1)
1746  return -1;
1747  return 0;
1748  }
1749 
1750  default:
1751  return -1;
1752  }
1753 }
1754 
openvas_hosts_t * openvas_hosts_new_with_max(const gchar *hosts_str, unsigned int max_hosts)
Creates a new openvas_hosts_t structure and the associated hosts objects from the provided hosts_str.
The structure for a single host object.
Definition: openvas_hosts.h:76
gchar * openvas_host_value_str(const openvas_host_t *host)
Gets a host's value in printable format.
Protos and data structures for Hosts collections and single hosts objects.
void openvas_hosts_free(openvas_hosts_t *hosts)
Frees memory occupied by an openvas_hosts_t structure.
int openvas_host_in_hosts(const openvas_host_t *host, const struct in6_addr *addr, const openvas_hosts_t *hosts)
Returns whether a host has an equal host in a hosts collection. eg. 192.168.10.1 has an equal in list...
unsigned int removed
Definition: openvas_hosts.h:98
int openvas_resolve(const char *name, void *dst, int family)
Resolves a hostname to an IPv4 or IPv6 address.
openvas_host_t * openvas_hosts_next(openvas_hosts_t *hosts)
Gets the next openvas_host_t from a openvas_hosts_t structure. The state of iteration is kept interna...
gchar * openvas_host_type_str(const openvas_host_t *host)
Gets a host's type in printable format.
int openvas_hosts_reverse_lookup_only(openvas_hosts_t *hosts)
Removes hosts that don't reverse-lookup from the hosts collection. Not to be used while iterating ove...
GList * current
Definition: openvas_hosts.h:96
gchar * orig_str
Definition: openvas_hosts.h:94
openvas_hosts_t * openvas_hosts_new(const gchar *hosts_str)
Creates a new openvas_hosts_t structure and the associated hosts objects from the provided hosts_str.
void openvas_hosts_resolve(openvas_hosts_t *hosts)
Resolves host objects of type name in a hosts collection, replacing hostnames with IPv4 values....
char * addr6_as_str(const struct in6_addr *addr6)
int openvas_host_resolve(const openvas_host_t *host, void *dst, int family)
Resolves a host object's name to an IPv4 or IPv6 address. Host object should be of type HOST_TYPE_NAM...
struct in_addr addr
Definition: openvas_hosts.h:80
struct in6_addr addr6
Definition: openvas_hosts.h:81
enum host_type openvas_host_type(const openvas_host_t *host)
Gets a host object's type.
gchar * host_type_str[HOST_TYPE_MAX]
Definition: openvas_hosts.c:41
host_type
Definition: openvas_hosts.h:51
const char * name
Definition: nasl_init.c:524
unsigned int openvas_hosts_count(const openvas_hosts_t *hosts)
Gets the count of single hosts objects in a hosts collection.
unsigned int openvas_hosts_removed(const openvas_hosts_t *hosts)
Gets the count of single values in hosts string that were removed (duplicates / excluded....
int openvas_hosts_reverse_lookup_unify(openvas_hosts_t *hosts)
Removes hosts duplicates that reverse-lookup to the same value. Not to be used while iterating over t...
The structure for Hosts collection.
Definition: openvas_hosts.h:92
int openvas_hosts_exclude(openvas_hosts_t *hosts, const char *excluded_str, int resolve)
Excludes a set of hosts provided as a string from a hosts collection. Not to be used while iterating ...
enum host_type type
Definition: openvas_hosts.h:83
gchar * name
Definition: openvas_hosts.h:79
void openvas_hosts_reverse(openvas_hosts_t *hosts)
Reverses the order of the hosts objects in the collection. Not to be used while iterating over the si...
int openvas_host_get_addr6(const openvas_host_t *host, struct in6_addr *ip6)
Gives a host object's value as an IPv6 address. If the host type is hostname, it resolves the IPv4 ad...
unsigned int count
Definition: openvas_hosts.h:97
int openvas_get_host_type(const gchar *str_stripped)
Determines the host type in a buffer.
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....
void openvas_hosts_shuffle(openvas_hosts_t *hosts)
Randomizes the order of the hosts objects in the collection. Not to be used while iterating over the ...
char * openvas_host_reverse_lookup(openvas_host_t *host)
Checks for a host object reverse dns lookup existence.