1 /* Copyright (C) 2020-2021 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 #include "pcap.c"
20 
21 #include <cgreen/cgreen.h>
22 #include <cgreen/mocks.h>
23 #include <gvm/base/hosts.h>
24 
25 Describe (pcap);
BeforeEach(pcap)26 BeforeEach (pcap)
27 {
28   cgreen_mocks_are (loose_mocks);
29 }
AfterEach(pcap)30 AfterEach (pcap)
31 {
32 }
33 
34 __attribute__ ((weak)) int
35 __real_socket (__attribute__ ((unused)) int domain,
36                __attribute__ ((unused)) int type,
37                __attribute__ ((unused)) int protocol);
38 
39 __attribute__ ((weak)) int
40 __real_setsockopt (__attribute__ ((unused)) int sockfd,
41                    __attribute__ ((unused)) int level,
42                    __attribute__ ((unused)) int optname,
43                    __attribute__ ((unused)) const void *optval,
44                    __attribute__ ((unused)) socklen_t optlen);
45 
46 bool g_socket_use_real = true;
47 int
__wrap_socket(int domain,int type,int protocol)48 __wrap_socket (__attribute__ ((unused)) int domain,
49                __attribute__ ((unused)) int type,
50                __attribute__ ((unused)) int protocol)
51 {
52   if (g_socket_use_real)
53     return __real_socket (domain, type, protocol);
54 
55   return (int) mock (domain, type, protocol);
56 }
57 
58 bool g_setsockopt_use_real = true;
59 int
__wrap_setsockopt(int sockfd,int level,int optname,const void * optval,socklen_t optlen)60 __wrap_setsockopt (__attribute__ ((unused)) int sockfd,
61                    __attribute__ ((unused)) int level,
62                    __attribute__ ((unused)) int optname,
63                    __attribute__ ((unused)) const void *optval,
64                    __attribute__ ((unused)) socklen_t optlen)
65 {
66   if (g_setsockopt_use_real)
67     return __real_setsockopt (sockfd, level, optname, optval, optlen);
68 
69   return (int) mock (sockfd, level, optname, optval, optlen);
70 }
71 
72 /* If dst for routethrough() is localhost "lo" interface is returned. */
Ensure(pcap,routethrough_dst_is_localhost)73 Ensure (pcap, routethrough_dst_is_localhost)
74 {
75   /* setup */
76   g_socket_use_real = false;
77   gchar *interface = NULL;
78   gchar *ipv4_str = "127.0.0.1";
79   gvm_host_t *gvm_host = NULL;
80   struct in6_addr dst6;
81   struct in6_addr *dst6_p = &dst6;
82   struct in_addr dst4;
83   struct in_addr *dst4_p = &dst4;
84   assert_that ((gvm_host = gvm_host_from_str (ipv4_str)), is_not_null);
85   assert_that (gvm_host_get_addr6 ((gvm_host_t *) gvm_host, dst6_p),
86                is_equal_to (0));
87   assert_that (dst6_p, is_not_null);
88   dst4.s_addr = dst6_p->s6_addr32[3];
89 
90   interface = routethrough (dst4_p, NULL);
91   (void) interface;
92 
93   /* dependent on local environment */
94   // assert_that ((interface = routethrough (dst4_p, NULL)), is_not_null);
95   // assert_that (interface, is_equal_to_string ("lo"));
96   g_socket_use_real = true;
97 }
98 
99 /* If dst is not null for routethrough() then another interface than "lo" is
100  * returned. */
Ensure(pcap,routethrough_dst_is_not_localhost)101 Ensure (pcap, routethrough_dst_is_not_localhost)
102 {
103   g_socket_use_real = false;
104   /* setup */
105   gchar *interface = NULL;
106   gchar *ipv4_str = "93.184.216.34"; /* example.com */
107   gvm_host_t *gvm_host = NULL;
108   struct in6_addr dst6;
109   struct in6_addr *dst6_p = &dst6;
110   struct in_addr dst4;
111   struct in_addr *dst4_p = &dst4;
112   assert_that ((gvm_host = gvm_host_from_str (ipv4_str)), is_not_null);
113   assert_that (gvm_host_get_addr6 ((gvm_host_t *) gvm_host, dst6_p),
114                is_equal_to (0));
115   assert_that (dst6_p, is_not_null);
116   dst4.s_addr = dst6_p->s6_addr32[3];
117 
118   interface = routethrough (dst4_p, NULL);
119   assert_that (interface, is_not_equal_to_string ("lo"));
120   g_socket_use_real = true;
121 }
122 
123 /* If neither dst nor src address are given to routethrough NULL is returned. */
Ensure(pcap,routethrough_no_src_dst_given)124 Ensure (pcap, routethrough_no_src_dst_given)
125 {
126   gchar *interface = NULL;
127   assert_that ((interface = routethrough (NULL, NULL)), is_null);
128 }
129 
130 /* If global_source_addr is present then routethrough writes it into src. */
Ensure(pcap,routethrough_src_globalsource_set)131 Ensure (pcap, routethrough_src_globalsource_set)
132 {
133   /* setup */
134   g_socket_use_real = false;
135   cgreen_mocks_are (learning_mocks);
136 
137   struct in_addr src = {.s_addr = 0}; /* ip src */
138   gchar *interface = NULL;
139   struct in_addr dst;
140   inet_pton (AF_INET, "93.184.216.34", &(dst.s_addr));
141 
142   /* global source address set */
143   gvm_source_iface_init ("lo"); // lo is set but not really used after being set
144   /* dst not given */
145   assert_that ((interface = routethrough (NULL, &src)), is_null);
146   assert_that ((src.s_addr == INADDR_ANY));
147   /* dst localhost given */
148   src.s_addr = 0;
149 
150   interface = routethrough (&dst, &src);
151   /* dependent on local environment */
152   // assert_that ((interface = routethrough (&dst, &src)), is_not_null);
153   assert_that (interface, is_not_equal_to_string ("lo"));
154   assert_that ((src.s_addr != INADDR_ANY));
155   g_socket_use_real = true;
156 }
157 
158 /* If global_source_addr is not present then routethrough writes it into src. */
Ensure(pcap,routethrough_src_globalsource_not_set)159 Ensure (pcap, routethrough_src_globalsource_not_set)
160 {
161   g_socket_use_real = false;
162 
163   struct in_addr src = {.s_addr = 0}; /* ip src */
164   gchar *interface = NULL;
165   struct in_addr dst;
166   inet_pton (AF_INET, "127.0.0.1", &(dst.s_addr));
167 
168   /* global source address not set */
169   gvm_source_iface_init (NULL);
170   /* dst not given */
171   assert_that ((interface = routethrough (NULL, &src)), is_null);
172   assert_that ((src.s_addr == INADDR_ANY));
173   /* dst localhost given */
174   src.s_addr = 0;
175 
176   interface = routethrough (&dst, &src);
177   /* dependent on local environment */
178   // assert_that ((interface = routethrough (&dst, &src)), is_not_null);
179   // assert_that (interface, is_equal_to_string ("lo"));
180   assert_that ((src.s_addr != INADDR_ANY));
181   g_socket_use_real = true;
182 }
183 
Ensure(pcap,v6_islocalhost)184 Ensure (pcap, v6_islocalhost)
185 {
186   /* IPv4 */
187   struct in_addr addr;
188   struct sockaddr_in sin;
189   memset (&sin, 0, sizeof (struct sockaddr_in));
190   sin.sin_family = AF_INET;
191 
192   /* example.com */
193   inet_pton (AF_INET, "93.184.216.34", &(addr.s_addr));
194 
195   /* IPv6 */
196   struct in6_addr addr_6;
197 
198   inet_pton (AF_INET6, "::FFFF:127.0.0.1", &(addr_6));
199   assert_that (v6_islocalhost (&addr_6), is_true);
200   inet_pton (AF_INET6, "::FFFF:0.0.0.0", &(addr_6));
201   assert_that (v6_islocalhost (&addr_6), is_true);
202   inet_pton (AF_INET6, "::FFFF:127.100.5.99", &(addr_6));
203   assert_that (v6_islocalhost (&addr_6), is_true);
204   /* loopback address */
205   inet_pton (AF_INET6, "0:0:0:0:0:0:0:1", &(addr_6));
206   assert_that (v6_islocalhost (&addr_6), is_true);
207 
208   /* dependent on local environment */
209   // inet_pton (AF_INET6, <some local interface address>, &(addr_6));
210   // assert_that (v6_islocalhost (&addr_6), is_true);
211 
212   /* example.com */
213   inet_pton (AF_INET6, "2606:2800:220:1:248:1893:25c8:1946", &(addr_6));
214   assert_that (v6_islocalhost (&addr_6), is_false);
215 }
216 
Ensure(pcap,islocalhost)217 Ensure (pcap, islocalhost)
218 {
219   /* IPv4 */
220   struct in_addr addr;
221 
222   inet_pton (AF_INET, "127.0.0.1", &(addr.s_addr));
223   assert_that (islocalhost (&addr), is_true);
224   inet_pton (AF_INET, "0.0.0.0", &(addr.s_addr));
225   assert_that (islocalhost (&addr), is_true);
226   inet_pton (AF_INET, "127.100.5.99", &(addr.s_addr));
227   assert_that (islocalhost (&addr), is_true);
228 
229   /* dependent on local environment */
230   // // inet_pton (AF_INET, <some local interface address>, &(addr));
231   // // assert_that (islocalhost (&addr), is_true);
232 
233   /* example.com */
234   inet_pton (AF_INET, "93.184.216.34", &(addr.s_addr));
235   assert_that (islocalhost (&addr), is_false);
236 }
237 
238 /**
239  * @brief Apply mask to dest addr.
240  *
241  * @param[out]  network   Masked dest addr.
242  * @param[in]   dest      Destination addr.
243  * @param[in]   mask      Mask to apply.
244  */
245 static void
apply_ipv6_mask(struct in6_addr * network,struct in6_addr * dest,struct in6_addr * mask)246 apply_ipv6_mask (struct in6_addr *network, struct in6_addr *dest,
247                  struct in6_addr *mask)
248 {
249   for (int i = 0; i < (int) sizeof (struct in6_addr); i++)
250     network->s6_addr[i] = dest->s6_addr[i] & mask->s6_addr[i];
251 }
252 
Ensure(pcap,ipv6_prefix_to_mask)253 Ensure (pcap, ipv6_prefix_to_mask)
254 {
255   struct in6_addr dest;
256   struct in6_addr result;
257   struct in6_addr mask;
258   struct in6_addr network;
259   const uint8_t byte_options[9] = {0xFF, 0x00, 0x80, 0xC0, 0xE0,
260                                    0xF0, 0xF8, 0xFC, 0xFE};
261 
262   // create dst addr
263   const uint8_t addr_in[16] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
264                                0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
265   memcpy (dest.s6_addr, addr_in, sizeof addr_in);
266   // create expected result addr
267   const uint8_t result_in[16] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
268                                  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
269                                  0xFF, 0xFF, 0xFF, 0xFF};
270   memcpy (result.s6_addr, result_in, sizeof result_in);
271 
272   // check every possible bit mask
273   for (int i = 128; i > 0; i--)
274     {
275       ipv6_prefix_to_mask (i, &mask);
276       apply_ipv6_mask (&network, &dest, &mask);
277       int byte_to_modify = i / 8;
278       if (byte_to_modify != 16)
279         result.s6_addr[byte_to_modify] = byte_options[(i % 8) + 1];
280 
281       assert_that (IN6_ARE_ADDR_EQUAL (&network, &result));
282     }
283 }
284 
285 TestSuite *
openvas_routethrough()286 openvas_routethrough ()
287 {
288   TestSuite *suite = create_test_suite ();
289   add_test_with_context (suite, pcap, routethrough_dst_is_localhost);
290   add_test_with_context (suite, pcap, routethrough_dst_is_not_localhost);
291   add_test_with_context (suite, pcap, routethrough_no_src_dst_given);
292   add_test_with_context (suite, pcap, routethrough_src_globalsource_set);
293   add_test_with_context (suite, pcap, routethrough_src_globalsource_not_set);
294   add_test_with_context (suite, pcap, v6_islocalhost);
295   add_test_with_context (suite, pcap, islocalhost);
296   add_test_with_context (suite, pcap, ipv6_prefix_to_mask);
297 
298   return suite;
299 }
300 
301 int
main(int argc,char ** argv)302 main (int argc, char **argv)
303 {
304   TestSuite *suite;
305 
306   suite = create_test_suite ();
307   add_suite (suite, openvas_routethrough ());
308 
309   if (argc > 1)
310     return run_single_test (suite, argv[1], create_text_reporter ());
311 
312   return run_test_suite (suite, create_text_reporter ());
313 }
314