1 /*
2  *  Copyright (C) 2015 Adrien Vergé
3  *
4  *  This program is free software: you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation, either version 3 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "ipv4.h"
19 #include "tunnel.h"
20 #include "config.h"
21 #include "log.h"
22 #include "xml.h"
23 
24 #include <unistd.h>
25 #include <arpa/inet.h>
26 #include <fcntl.h>
27 #include <sys/ioctl.h>
28 #include <sys/stat.h>
29 
30 #include <errno.h>
31 #include <limits.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <stdint.h>
35 #include <string.h>
36 
37 #define IPV4_GET_ROUTE_BUFFER_CHUNK_SIZE 65536
38 #define SHOW_ROUTE_BUFFER_SIZE 128
39 
40 static char show_route_buffer[SHOW_ROUTE_BUFFER_SIZE];
41 
42 #define ERR_IPV4_SEE_ERRNO	-1
43 #define ERR_IPV4_NO_MEM		-2
44 #define ERR_IPV4_PERMISSION	-3
45 #define ERR_IPV4_NO_SUCH_ROUTE	-4
46 #define ERR_IPV4_PROC_NET_ROUTE	-5
47 
err_ipv4_str(int code)48 static inline const char *err_ipv4_str(int code)
49 {
50 	if (code == ERR_IPV4_SEE_ERRNO)
51 		return strerror(errno);
52 	else if (code == ERR_IPV4_NO_MEM)
53 		return "Not enough memory";
54 	else if (code == ERR_IPV4_PERMISSION)
55 		return "Permission denied";
56 	else if (code == ERR_IPV4_NO_SUCH_ROUTE)
57 		return "Route not found";
58 	else if (code == ERR_IPV4_PROC_NET_ROUTE)
59 		return "Parsing /proc/net/route failed";
60 	return "unknown";
61 }
62 
63 /*
64  * Returns a string representation of the route, such as:
65  *   to 192.168.1.0/255.255.255.0 via 172.16.0.1 dev eth0
66  *
67  * Warning: the returned buffer is static, so multiple calls will overwrite it.
68  */
ipv4_show_route(struct rtentry_ofvpn * route)69 static char *ipv4_show_route(struct rtentry_ofvpn *route)
70 {
71 	strcpy(show_route_buffer, "to ");
72 	strncat(show_route_buffer, inet_ntoa(route_dest(route)), 15);
73 	strcat(show_route_buffer, "/");
74 	strncat(show_route_buffer, inet_ntoa(route_mask(route)), 15);
75 	if (route->rt_flags & RTF_GATEWAY) {
76 		strcat(show_route_buffer, " via ");
77 		strncat(show_route_buffer, inet_ntoa(route_gtw(route)), 15);
78 	}
79 	if (route_iface(route) != NULL) {
80 		strcat(show_route_buffer, " dev ");
81 		strncat(show_route_buffer, route_iface(route),
82 		        SHOW_ROUTE_BUFFER_SIZE - strlen(show_route_buffer) - 1);
83 	}
84 
85 	return show_route_buffer;
86 }
87 
route_init(struct rtentry_ofvpn * route)88 static inline int route_init(struct rtentry_ofvpn *route)
89 {
90 	memset(route, 0, sizeof(*route));
91 
92 	cast_addr(&(route)->rt_dst)->sin_family = AF_INET;
93 	cast_addr(&(route)->rt_genmask)->sin_family = AF_INET;
94 	cast_addr(&(route)->rt_gateway)->sin_family = AF_INET;
95 
96 	return 0;
97 }
98 
route_destroy(struct rtentry_ofvpn * route)99 static inline void route_destroy(struct rtentry_ofvpn *route)
100 {
101 	free(route_iface(route));
102 	route_iface(route) = NULL;
103 }
104 
105 /*
106  * Finds system IP route to a destination.
107  *
108  * The passed route must have dest and mask set. If the route is found,
109  * the function searches for a match in the routing table and returns
110  * that one. Note that dest and mask contain the network address and
111  * the mask of the corresponding routing table entry after calling.
112  * After calling ipv4_get_route it might be necessary to set dest
113  * and mask again to the desired values for further processing.
114  */
ipv4_get_route(struct rtentry_ofvpn * route)115 static int ipv4_get_route(struct rtentry_ofvpn *route)
116 {
117 	size_t buffer_size = IPV4_GET_ROUTE_BUFFER_CHUNK_SIZE;
118 	char *buffer = malloc(buffer_size);
119 	char *realloc_buffer;
120 	int err = 0;
121 	char *start, *line;
122 	char *saveptr1 = NULL, *saveptr2 = NULL;
123 	uint32_t rtdest, rtmask, rtgtw;
124 	int rtfound = 0;
125 
126 	if (!buffer) {
127 		err = ERR_IPV4_SEE_ERRNO;
128 		goto end;
129 	}
130 
131 	/*
132 	 * initialize the buffer with zeroes, aiming to address the
133 	 * coverity issue "TAINTED_SCALAR passed to a tainted sink"
134 	 *
135 	 * Later on, the routing table is read into this buffer using
136 	 * read() and therefore the content of the buffer is considered
137 	 * tainted. strtok_r internally uses it in a loop boundary.
138 	 * The theoretical problem is that the loop could iterate forever,
139 	 * if the buffer contains a huge string which doesn't contain
140 	 * the token character, which we are parsing for.
141 	 *
142 	 * We can declare this as a false positive, because
143 	 * - the routing table is to some extent trusted input,
144 	 * - it's not that large,
145 	 * - and the loop in strtok_r increments the pointer in each
146 	 *   iteration until it reaches the area where we have ensured
147 	 *   that there is a delimiting '\0' character by proper
148 	 *   initialization. We ensure this also when growing the buffer.
149 	 */
150 	memset(buffer, '\0', IPV4_GET_ROUTE_BUFFER_CHUNK_SIZE);
151 	log_debug("ip route show %s\n", ipv4_show_route(route));
152 
153 	// store what we are looking for
154 	rtdest = route_dest(route).s_addr;
155 	rtmask = route_mask(route).s_addr;
156 	rtgtw = route_gtw(route).s_addr;
157 
158 	// initialize the output record
159 	route_dest(route).s_addr = inet_addr("0.0.0.0");
160 	route_mask(route).s_addr = inet_addr("0.0.0.0");
161 	route_gtw(route).s_addr = inet_addr("0.0.0.0");
162 
163 #if HAVE_PROC_NET_ROUTE
164 	/* this is not present on Mac OS X and FreeBSD */
165 	int fd;
166 	uint32_t total_bytes_read = 0;
167 
168 	// Cannot stat, mmap not lseek this special /proc file
169 	fd = open("/proc/net/route", O_RDONLY);
170 	if (fd == -1) {
171 		err = ERR_IPV4_SEE_ERRNO;
172 		goto end;
173 	}
174 
175 	int bytes_read;
176 
177 	while ((bytes_read = read(fd, buffer + total_bytes_read,
178 	                          buffer_size - total_bytes_read - 1)) > 0) {
179 		total_bytes_read += bytes_read;
180 
181 		if ((buffer_size - total_bytes_read) < 1) {
182 			buffer_size += IPV4_GET_ROUTE_BUFFER_CHUNK_SIZE;
183 
184 			realloc_buffer = realloc(buffer, buffer_size);
185 			if (realloc_buffer) {
186 				buffer = realloc_buffer;
187 			} else {
188 				err = ERR_IPV4_SEE_ERRNO;
189 				goto cleanup;
190 			}
191 			buffer[buffer_size-1] = '\0';
192 		}
193 	}
194 
195 cleanup:
196 	if (close(fd))
197 		log_warn("Could not close /proc/net/route (%s).\n", strerror(errno));
198 	if (err)
199 		goto end;
200 
201 	if (bytes_read < 0) {
202 		err = ERR_IPV4_SEE_ERRNO;
203 		goto end;
204 	}
205 
206 #else
207 	FILE * fp;
208 	uint32_t total_bytes_read = 0;
209 
210 	char *saveptr3 = NULL;
211 	int have_ref = 0;
212 	int have_use = 0;
213 
214 	static const char netstat_path[] = NETSTAT_PATH;
215 
216 	if (access(netstat_path, F_OK) != 0) {
217 		log_error("%s: %s.\n", netstat_path, strerror(errno));
218 		return 1;
219 	}
220 	log_debug("netstat_path: %s\n", netstat_path);
221 
222 	// Open the command for reading
223 	fp = popen(NETSTAT_PATH " -f inet -rn", "r");
224 	if (fp == NULL) {
225 		err = ERR_IPV4_SEE_ERRNO;
226 		goto end;
227 	}
228 
229 	line = buffer;
230 	// Read the output a line at a time
231 	while (fgets(line, buffer_size - total_bytes_read - 1, fp) != NULL) {
232 		uint32_t bytes_read = strlen(line);
233 
234 		total_bytes_read += bytes_read;
235 
236 		if (bytes_read > 0 && line[bytes_read - 1] != '\n') {
237 			buffer_size += IPV4_GET_ROUTE_BUFFER_CHUNK_SIZE;
238 
239 			realloc_buffer = realloc(buffer, buffer_size);
240 			if (realloc_buffer) {
241 				buffer = realloc_buffer;
242 			} else {
243 				err = ERR_IPV4_SEE_ERRNO;
244 				goto cleanup;
245 			}
246 		}
247 
248 		line = buffer + total_bytes_read;
249 	}
250 
251 cleanup:
252 	if (pclose(fp))
253 		log_warn("Could not close netstat pipe (%s).\n", strerror(errno));
254 	if (err)
255 		goto end;
256 
257 	// reserve enough memory (256 shorts)
258 	// to make sure not to access out of bounds later,
259 	// for ipv4 only unsigned short is allowed
260 
261 	unsigned short flag_table[256] = { 0 };
262 
263 	/*
264 	 * Fill the flag_table now. Unfortunately it is not easy
265 	 * to do this in a more elegant way. The problem here
266 	 * is that these are already preprocessor macros and
267 	 * we can't use them as arguments for another macro which
268 	 * would include the #ifdef statements.
269 	 *
270 	 * Also, not all flags might be allowed in the context
271 	 * of ipv4, and the code depends on which ones are
272 	 * actually implemented on the target platform, which
273 	 * might also be varying between Mac OS X versions.
274 	 *
275 	 */
276 
277 #ifdef RTF_PROTO1     // Protocol specific routing flag #1
278 	flag_table['1'] = RTF_PROTO1 & USHRT_MAX;
279 #endif
280 #ifdef RTF_PROTO2     // Protocol specific routing flag #2
281 	flag_table['2'] = RTF_PROTO2 & USHRT_MAX;
282 #endif
283 #ifdef RTF_PROTO3     // Protocol specific routing flag #3
284 	flag_table['3'] = RTF_PROTO3 & USHRT_MAX;
285 #endif
286 #ifdef RTF_BLACKHOLE  // Just discard packets (during updates)
287 	flag_table['B'] = RTF_BLACKHOLE & USHRT_MAX;
288 #endif
289 #ifdef RTF_BROADCAST  // The route represents a broadcast address
290 	flag_table['b'] = RTF_BROADCAST & USHRT_MAX;
291 #endif
292 #ifdef RTF_CLONING    // Generate new routes on use
293 	flag_table['C'] = RTF_CLONING & USHRT_MAX;
294 #endif
295 #ifdef RTF_PRCLONING  // Protocol-specified generate new routes on use
296 	flag_table['c'] = RTF_PRCLONING & USHRT_MAX;
297 #endif
298 #ifdef RTF_DYNAMIC    // Created dynamically (by redirect)
299 	flag_table['D'] = RTF_DYNAMIC & USHRT_MAX;
300 #endif
301 #ifdef RTF_GATEWAY    // Destination requires forwarding by intermediary
302 	flag_table['G'] = RTF_GATEWAY & USHRT_MAX;
303 #endif
304 #ifdef RTF_HOST       // Host entry (net otherwise)
305 	flag_table['H'] = RTF_HOST & USHRT_MAX;
306 #endif
307 #ifdef RTF_IFSCOPE    // Route is associated with an interface scope
308 	flag_table['I'] = RTF_IFSCOPE & USHRT_MAX;
309 #endif
310 #ifdef RTF_IFREF      // Route is holding a reference to the interface
311 	flag_table['i'] = RTF_IFREF & USHRT_MAX;
312 #endif
313 #ifdef RTF_LLINFO     // Valid protocol to link address translation
314 	flag_table['L'] = RTF_LLINFO & USHRT_MAX;
315 #endif
316 #ifdef RTF_MODIFIED   // Modified dynamically (by redirect)
317 	flag_table['M'] = RTF_MODIFIED & USHRT_MAX;
318 #endif
319 #ifdef RTF_MULTICAST  // The route represents a multicast address
320 	flag_table['m'] = RTF_MULTICAST & USHRT_MAX;
321 #endif
322 #ifdef RTF_REJECT     // Host or net unreachable
323 	flag_table['R'] = RTF_REJECT & USHRT_MAX;
324 #endif
325 #ifdef RTF_ROUTER     // Host is a default router
326 	flag_table['r'] = RTF_ROUTER & USHRT_MAX;
327 #endif
328 #ifdef RTF_STATIC     // Manually added
329 	flag_table['S'] = RTF_STATIC & USHRT_MAX;
330 #endif
331 #ifdef RTF_UP	 // Route usable
332 	flag_table['U'] = RTF_UP & USHRT_MAX;
333 #endif
334 #ifdef RTF_WASCLONED  // Route was generated as a result of cloning
335 	flag_table['W'] = RTF_WASCLONED & USHRT_MAX;
336 #endif
337 #ifdef RTF_XRESOLVE   // External daemon translates proto to link address
338 	flag_table['X'] = RTF_XRESOLVE & USHRT_MAX;
339 #endif
340 #ifdef RTF_PROXY      // Proxying; cloned routes will not be scoped
341 	flag_table['Y'] = RTF_PROXY & USHRT_MAX;
342 #endif
343 
344 #endif
345 
346 	if (total_bytes_read == 0) {
347 		log_debug("routing table is empty.\n");
348 		err = ERR_IPV4_PROC_NET_ROUTE;
349 		goto end;
350 	}
351 	buffer[total_bytes_read] = '\0';
352 
353 	// Skip first line
354 	start = strchr(buffer, '\n');
355 	if (start == NULL) {
356 		log_debug("routing table is malformed.\n");
357 		err = ERR_IPV4_PROC_NET_ROUTE;
358 		goto end;
359 	}
360 	start++;
361 
362 #if !HAVE_PROC_NET_ROUTE
363 	if (strstr(buffer, "Ref") != NULL)
364 		have_ref = 1;
365 	if (strstr(buffer, "Use") != NULL)
366 		have_use = 1;
367 	// Skip 3 more lines from netstat output on Mac OS X and on FreeBSD
368 	start = strchr(start, '\n');
369 	start = strchr(++start, '\n');
370 	start = strchr(++start, '\n');
371 	if (start == NULL) {
372 		log_debug("routing table is malformed.\n");
373 		err = ERR_IPV4_PROC_NET_ROUTE;
374 		goto end;
375 	}
376 #endif
377 
378 	if (strchr(start, '\n') == NULL) {
379 		log_debug("routing table is malformed.\n");
380 		err = ERR_IPV4_PROC_NET_ROUTE;
381 		goto end;
382 	}
383 
384 	// Look for the route
385 	line = strtok_r(start, "\n", &saveptr1);
386 	while (line != NULL) {
387 		char *iface;
388 		uint32_t dest, mask, gtw;
389 		unsigned short flags;
390 #if HAVE_PROC_NET_ROUTE
391 		unsigned short irtt;
392 		short metric;
393 		unsigned long mtu, window;
394 
395 		iface = strtok_r(line, "\t", &saveptr2);
396 		dest = strtoul(strtok_r(NULL, "\t", &saveptr2), NULL, 16);
397 		gtw = strtoul(strtok_r(NULL, "\t", &saveptr2), NULL, 16);
398 		flags = strtoul(strtok_r(NULL, "\t", &saveptr2), NULL, 16);
399 		strtok_r(NULL, "\t", &saveptr2); // "RefCnt"
400 		strtok_r(NULL, "\t", &saveptr2); // "Use"
401 		metric = strtoul(strtok_r(NULL, "\t", &saveptr2), NULL, 16);
402 		mask = strtoul(strtok_r(NULL, "\t", &saveptr2), NULL, 16);
403 		mtu = strtoul(strtok_r(NULL, "\t", &saveptr2), NULL, 16);
404 		window = strtoul(strtok_r(NULL, "\t", &saveptr2), NULL, 16);
405 		irtt = strtoul(strtok_r(NULL, "\t", &saveptr2), NULL, 16);
406 #else
407 		/* parse netstat output on Mac OS X and BSD */
408 		char tmp_ip_string[16];
409 		struct in_addr dstaddr;
410 		int pos;
411 		char *tmpstr;
412 
413 		log_debug_details("\n");
414 		log_debug_details("line: %s\n", line);
415 
416 		saveptr3 = NULL;
417 		dest = UINT32_MAX;
418 		mask = UINT32_MAX;
419 		// "Destination"
420 		tmpstr = strtok_r(line, " ", &saveptr2);
421 		if (strncmp(tmpstr, "Internet6", 9) == 0) {
422 			// we have arrived at the end of ipv4 output
423 			goto end;
424 		}
425 		log_debug_details("- Destination: %s\n", tmpstr);
426 		// replace literal "default" route by IPV4 numbers-and-dots notation
427 		if (strncmp(tmpstr, "default", 7) == 0) {
428 			dest = 0;
429 			mask = 0;
430 		} else {
431 			int is_mask_set = 0;
432 			char *tmp_position;
433 			int dot_count = -1;
434 
435 			if (strchr(tmpstr, '/') != NULL) {
436 				// 123.123.123.123/30 style
437 				// 123.123.123/24 style
438 				// 123.123/24 style
439 
440 				// break CIDR up into address and mask part
441 				strcpy(tmp_ip_string, strtok_r(tmpstr, "/", &saveptr3));
442 				mask = strtoul(saveptr3, NULL, 10);
443 				// convert from CIDR to ipv4 mask
444 				mask = 0xffffffff << (32-mask);
445 
446 				is_mask_set = 1;
447 			} else if (inet_aton(tmpstr, &dstaddr)) {
448 				// 123.123.123.123 style
449 				// 123.123.123 style
450 				// 123.123 style
451 
452 				strcpy(tmp_ip_string, tmpstr);
453 				is_mask_set = 0;
454 			}
455 
456 			// Process Destination IP Expression
457 			tmp_position = tmp_ip_string;
458 			while (tmp_position != NULL) {
459 				++dot_count;
460 				tmp_position = strchr(++tmp_position, '.');
461 			}
462 
463 			for (int i = dot_count; i < 3; i++)
464 				strcat(tmp_ip_string, ".0");
465 
466 			if (inet_aton(tmp_ip_string, &dstaddr))
467 				dest = dstaddr.s_addr;
468 
469 			if (!is_mask_set) {
470 				// convert from CIDR to ipv4 mask
471 				mask = 0xffffffff << (32-((dot_count + 1) * 8));
472 			}
473 			// convert mask to reversed byte order
474 			mask = ((mask & 0xff000000) >> 24)
475 			       | ((mask & 0xff0000) >> 8)
476 			       | ((mask & 0xff00) << 8)
477 			       | ((mask & 0xff) << 24);
478 		}
479 		log_debug_details("- Destination IP Hex: %x\n", dest);
480 		log_debug_details("- Destination Mask Hex: %x\n", mask);
481 		// "Gateway"
482 		gtw = 0;
483 		if (inet_aton(strtok_r(NULL, " ", &saveptr2), &dstaddr)) {
484 			gtw = dstaddr.s_addr;
485 			log_debug_details("- Gateway Mask Hex: %x\n", gtw);
486 		}
487 		// "Flags"
488 		tmpstr = strtok_r(NULL, " ", &saveptr2);
489 		flags = 0;
490 		// this is the reason for the 256 entries mentioned above
491 		for (pos = 0; pos < strlen(tmpstr); pos++)
492 			flags |= flag_table[(unsigned char)tmpstr[pos]];
493 
494 		if (have_ref)
495 			strtok_r(NULL, " ", &saveptr2); // "Ref"
496 		if (have_use)
497 			strtok_r(NULL, " ", &saveptr2); // "Use"
498 
499 		iface = strtok_r(NULL, " ", &saveptr2); // "Netif"
500 		log_debug_details("- Interface: %s\n", iface);
501 #endif
502 		/*
503 		 * Now that we have parsed a routing entry, check if it
504 		 * matches the current argument to the function call.
505 		 * In rtentry_ofvpn we have integer representation, i.e.
506 		 * the most significant byte corresponds to the last
507 		 * number of dotted-number representation and vice versa.
508 		 * In this representation ( address & mask ) is the network
509 		 * address.
510 		 * The routing algorithm does the following:
511 		 * First, check if the network address we are looking for
512 		 * falls into the network for the current route.
513 		 * Therefore, calculate the network address for both, the
514 		 * current route and for the destination we are searching.
515 		 * If the destination is a smaller network (for instance a
516 		 * single host), we have to mask again with the netmask of
517 		 * the routing entry that we are checking in order to obtain
518 		 * the network address in the context of the current route.
519 		 * If both network addresses match, we have found a candidate
520 		 * for a route.
521 		 * However, there might be another route for a smaller network,
522 		 * therefore repeat this and only store the resulting route
523 		 * when the mask is at least as large as the one we may
524 		 * have already found in a previous iteration (a larger
525 		 * netmask corresponds to a smaller network in this
526 		 * representation, and has a higher priority by default).
527 		 * Also, only consider routing entries for which the
528 		 * netmask is not larger than the netmask used in the
529 		 * argument when calling the function - so that we can
530 		 * distinguish between different routing entries for subnets
531 		 * of different size but with the same network address.
532 		 * For routing entries with the same destination and
533 		 * the same netmask the metric can be used for adjusting
534 		 * the priority (this is not supported on mac).
535 		 * If the metric is larger than one found for this network
536 		 * size, skip the current route (smaller numbers denote
537 		 * less hops and therefore have a higher priority).
538 		 */
539 
540 		if (((dest & mask) == (rtdest & rtmask & mask))
541 		    && (mask >= route_mask(route).s_addr)
542 		    && (mask <= rtmask)
543 		    && ((route_iface(route) == NULL)
544 		        || (strcmp(iface, route_iface(route)) == 0)
545 		        || (strlen(route_iface(route)) > 0
546 		            && route_iface(route)[0] == '!'
547 		            && strcmp(iface, &route_iface(route)[1]) != 0)
548 		       )) {
549 #if HAVE_PROC_NET_ROUTE
550 			if (((mask == route_mask(route).s_addr)
551 			     && (metric <= route->rt_metric))
552 			    || (rtfound == 0)
553 			    || (mask > route_mask(route).s_addr)) {
554 #endif
555 				rtfound = 1;
556 				// Requested route has been found
557 				route_dest(route).s_addr = dest;
558 				route_mask(route).s_addr = mask;
559 				route_gtw(route).s_addr = gtw;
560 				route->rt_flags = flags;
561 
562 				free(route_iface(route));
563 				route_iface(route) = strdup(iface);
564 				if (!route_iface(route)) {
565 					err = ERR_IPV4_NO_MEM;
566 					goto end;
567 				}
568 
569 #if HAVE_PROC_NET_ROUTE
570 				// we do not have these values from Mac OS X netstat,
571 				// so stay with defaults denoted by values of 0
572 				route->rt_metric = metric;
573 				route->rt_mtu = mtu;
574 				route->rt_window = window;
575 				route->rt_irtt = irtt;
576 			}
577 #else
578 				log_debug_details("- route matches\n");
579 #endif
580 		}
581 		line = strtok_r(NULL, "\n", &saveptr1);
582 	}
583 
584 end:
585 	free(buffer);
586 	if (err)
587 		return err;
588 
589 	if (rtfound == 0) {
590 		// should not occur anymore unless there is no default route
591 		log_debug("Route not found.\n");
592 		// at least restore input values
593 		route_dest(route).s_addr = rtdest;
594 		route_mask(route).s_addr = rtmask;
595 		route_gtw(route).s_addr = rtgtw;
596 
597 		return ERR_IPV4_NO_SUCH_ROUTE;
598 	}
599 
600 	return 0;
601 }
602 
ipv4_set_route(struct rtentry_ofvpn * route)603 static int ipv4_set_route(struct rtentry_ofvpn *route)
604 {
605 #ifdef HAVE_RT_ENTRY_WITH_RT_DST
606 	/* we can copy rtentry_ofvpn struct directly between openfortivpn and kernel */
607 	log_debug("ip route add %s\n", ipv4_show_route(route));
608 
609 	int sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
610 
611 	if (sockfd < 0)
612 		return ERR_IPV4_SEE_ERRNO;
613 	if (ioctl(sockfd, SIOCADDRT, route) == -1) {
614 		if (close(sockfd))
615 			log_warn("Could not close socket for setting route (%s).\n",
616 			         strerror(errno));
617 		return ERR_IPV4_SEE_ERRNO;
618 	}
619 	if (close(sockfd))
620 		log_warn("Could not close socket for setting route: %s\n",
621 		         strerror(errno));
622 #else
623 	/* we have to use the route command as tool for route manipulation */
624 	char cmd[SHOW_ROUTE_BUFFER_SIZE];
625 
626 	if (access("/sbin/route", F_OK) != 0) {
627 		log_error("/sbin/route: %s.\n", strerror(errno));
628 		return 1;
629 	}
630 
631 	strcpy(cmd, "/sbin/route -n add ");
632 	if (route->rt_flags & RTF_HOST)
633 		strcat(cmd, "-host ");
634 	else
635 		strcat(cmd, "-net ");
636 
637 	strncat(cmd, inet_ntoa(route_dest(route)), 15);
638 	if (!(route->rt_flags & RTF_HOST)) {
639 		strcat(cmd, " -netmask ");
640 		strncat(cmd, inet_ntoa(route_mask(route)), 15);
641 	}
642 	if (route->rt_flags & RTF_GATEWAY) {
643 		strcat(cmd, " ");
644 		strncat(cmd, inet_ntoa(route_gtw(route)), 15);
645 	} else {
646 		strcat(cmd, " -interface ");
647 		strncat(cmd, route_iface(route),
648 		        SHOW_ROUTE_BUFFER_SIZE - strlen(cmd) - 1);
649 	}
650 
651 	log_debug("%s\n", cmd);
652 
653 	int res = system(cmd);
654 
655 	if (res == -1)
656 		return ERR_IPV4_SEE_ERRNO;
657 #endif
658 
659 	return 0;
660 }
661 
ipv4_del_route(struct rtentry_ofvpn * route)662 static int ipv4_del_route(struct rtentry_ofvpn *route)
663 {
664 #ifdef HAVE_RT_ENTRY_WITH_RT_DST
665 	/* we can copy rtentry_ofvpn struct directly between openfortivpn and kernel */
666 	struct rtentry_ofvpn tmp;
667 	int sockfd;
668 
669 	log_debug("ip route del %s\n", ipv4_show_route(route));
670 
671 	// Copy route to a temp variable to clear some of its properties
672 	memcpy(&tmp, route, sizeof(tmp));
673 	tmp.rt_metric = 0;
674 	tmp.rt_mtu = 0;
675 	tmp.rt_window = 0;
676 	tmp.rt_irtt = 0;
677 
678 	sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
679 	if (sockfd < 0)
680 		return ERR_IPV4_SEE_ERRNO;
681 	if (ioctl(sockfd, SIOCDELRT, &tmp) == -1) {
682 		if (close(sockfd))
683 			log_warn("Could not close socket for deleting route (%s).\n",
684 			         strerror(errno));
685 		return ERR_IPV4_SEE_ERRNO;
686 	}
687 	if (close(sockfd))
688 		log_warn("Could not close socket for deleting route (%s).\n",
689 		         strerror(errno));
690 #else
691 	char cmd[SHOW_ROUTE_BUFFER_SIZE];
692 
693 	if (access("/sbin/route", F_OK) != 0) {
694 		log_error("/sbin/route: %s.\n", strerror(errno));
695 		return 1;
696 	}
697 
698 	strcpy(cmd, "/sbin/route -n delete ");
699 	if (route->rt_flags & RTF_HOST)
700 		strcat(cmd, "-host ");
701 	else
702 		strcat(cmd, "-net ");
703 
704 	strncat(cmd, inet_ntoa(route_dest(route)), 15);
705 	if (!(route->rt_flags & RTF_HOST)) {
706 		strcat(cmd, " -netmask ");
707 		strncat(cmd, inet_ntoa(route_mask(route)), 15);
708 	}
709 	if (route->rt_flags & RTF_GATEWAY) {
710 		strcat(cmd, " ");
711 		strncat(cmd, inet_ntoa(route_gtw(route)), 15);
712 	} else {
713 		strcat(cmd, " -interface ");
714 		strncat(cmd, route_iface(route),
715 		        SHOW_ROUTE_BUFFER_SIZE - strlen(cmd) - 1);
716 	}
717 
718 	log_debug("%s\n", cmd);
719 
720 	int res = system(cmd);
721 
722 	if (res == -1)
723 		return ERR_IPV4_SEE_ERRNO;
724 #endif
725 	return 0;
726 }
727 
ipv4_protect_tunnel_route(struct tunnel * tunnel)728 int ipv4_protect_tunnel_route(struct tunnel *tunnel)
729 {
730 	struct rtentry_ofvpn *gtw_rt = &tunnel->ipv4.gtw_rt;
731 	struct rtentry_ofvpn *def_rt = &tunnel->ipv4.def_rt;
732 	int ret;
733 
734 	route_init(def_rt);
735 	route_init(gtw_rt);
736 
737 	// Back up default route
738 	route_dest(def_rt).s_addr = inet_addr("0.0.0.0");
739 	route_mask(def_rt).s_addr = inet_addr("0.0.0.0");
740 	route_iface(def_rt) = malloc(strlen(tunnel->ppp_iface) + 2);
741 	if (!route_iface(def_rt)) {
742 		log_error("malloc: %s\n", strerror(errno));
743 		return ERR_IPV4_SEE_ERRNO;
744 	}
745 	sprintf(route_iface(def_rt), "!%s", tunnel->ppp_iface);
746 
747 	ret = ipv4_get_route(def_rt);
748 	if (ret != 0) {
749 		log_warn("Could not get current default route (%s).\n",
750 		         err_ipv4_str(ret));
751 		log_warn("Protecting tunnel route has failed. But this can be working except for some cases.\n");
752 		goto err_destroy_def_rt;
753 	}
754 
755 	// Set the up a route to the tunnel gateway
756 	route_dest(gtw_rt).s_addr = tunnel->config->gateway_ip.s_addr;
757 	route_mask(gtw_rt).s_addr = inet_addr("255.255.255.255");
758 	route_iface(gtw_rt) = malloc(strlen(tunnel->ppp_iface) + 2);
759 	if (!route_iface(gtw_rt)) {
760 		log_error("malloc: %s\n", strerror(errno));
761 		return ERR_IPV4_SEE_ERRNO;
762 	}
763 	sprintf(route_iface(gtw_rt), "%s", tunnel->ppp_iface);
764 	ret = ipv4_get_route(gtw_rt);
765 	if ((ret == 0)
766 	    && (route_dest(gtw_rt).s_addr == tunnel->config->gateway_ip.s_addr)
767 	    && (route_mask(gtw_rt).s_addr == inet_addr("255.255.255.255"))) {
768 		log_debug("removing wrong route to vpn server...\n");
769 		log_debug("ip route show %s\n", ipv4_show_route(gtw_rt));
770 		ipv4_del_route(gtw_rt);
771 	}
772 	sprintf(route_iface(gtw_rt), "!%s", tunnel->ppp_iface);
773 	ret = ipv4_get_route(gtw_rt);
774 	if (ret != 0) {
775 		log_warn("Could not get route to gateway (%s).\n",
776 		         err_ipv4_str(ret));
777 		log_warn("Protecting tunnel route has failed. But this can be working except for some cases.\n");
778 		goto err_destroy_gtw_rt;
779 	}
780 	route_dest(gtw_rt).s_addr = tunnel->config->gateway_ip.s_addr;
781 	route_mask(gtw_rt).s_addr = inet_addr("255.255.255.255");
782 	gtw_rt->rt_flags |= RTF_HOST;
783 	gtw_rt->rt_metric = 0;
784 
785 	tunnel->ipv4.route_to_vpn_is_added = 1;
786 	log_debug("Setting route to vpn server...\n");
787 	log_debug("ip route show %s\n", ipv4_show_route(gtw_rt));
788 	ret = ipv4_set_route(gtw_rt);
789 	if (ret == ERR_IPV4_SEE_ERRNO && errno == EEXIST) {
790 		log_warn("Route to vpn server exists already.\n");
791 
792 		tunnel->ipv4.route_to_vpn_is_added = 0;
793 	} else if (ret != 0)
794 		log_warn("Could not set route to vpn server (%s).\n",
795 		         err_ipv4_str(ret));
796 
797 	return 0;
798 
799 err_destroy_gtw_rt:
800 	route_destroy(gtw_rt);
801 err_destroy_def_rt:
802 	route_destroy(def_rt);
803 	tunnel->ipv4.route_to_vpn_is_added = 0;
804 	return ret;
805 }
806 
807 #if HAVE_USR_SBIN_PPPD
add_text_route(struct tunnel * tunnel,const char * dest,const char * mask,const char * gw)808 static void add_text_route(struct tunnel *tunnel, const char *dest,
809                            const char *mask, const char *gw)
810 {
811 	size_t l0, l1;
812 	static const char fmt[] = ",%s/%s/%s";
813 	static const char trigger[] = "openfortivpn";
814 	char **target = &tunnel->config->pppd_ipparam;
815 	char *ptr;
816 
817 	if (*target == NULL || strncmp(*target, trigger, strlen(trigger)))
818 		return;
819 	if (!dest || !mask || !gw)
820 		return;
821 	log_info("Registering route %s/%s via %s\n", dest, mask, gw);
822 	l0 = strlen(*target);
823 	l1 = strlen(fmt) + strlen(dest) + strlen(mask) + strlen(gw) + 1;
824 	ptr = realloc(*target, l0 + l1);
825 	if (ptr) {
826 		*target = ptr;
827 		snprintf(*target + l0, l1, fmt, dest, mask, gw);
828 	} else {
829 		log_error("realloc: %s\n", strerror(errno));
830 	}
831 }
832 #endif
833 
ipv4_add_split_vpn_route(struct tunnel * tunnel,char * dest,char * mask,char * gateway)834 int ipv4_add_split_vpn_route(struct tunnel *tunnel, char *dest, char *mask,
835                              char *gateway)
836 {
837 	struct rtentry_ofvpn *route;
838 	char env_var[24];
839 
840 #if HAVE_USR_SBIN_PPPD
841 	add_text_route(tunnel, dest, mask, gateway);
842 #endif
843 	if (tunnel->ipv4.split_routes == MAX_SPLIT_ROUTES)
844 		return ERR_IPV4_NO_MEM;
845 	if ((tunnel->ipv4.split_rt == NULL)
846 	    || ((tunnel->ipv4.split_routes % STEP_SPLIT_ROUTES) == 0)) {
847 		void *new_ptr
848 		        = realloc(tunnel->ipv4.split_rt,
849 		                  (size_t) (tunnel->ipv4.split_routes + STEP_SPLIT_ROUTES)
850 		                  * sizeof(*(tunnel->ipv4.split_rt)));
851 		if (new_ptr == NULL)
852 			return ERR_IPV4_NO_MEM;
853 		tunnel->ipv4.split_rt = new_ptr;
854 	}
855 
856 	sprintf(env_var, "VPN_ROUTE_DEST_%d", tunnel->ipv4.split_routes);
857 	setenv(env_var, dest, 0);
858 	sprintf(env_var, "VPN_ROUTE_MASK_%d", tunnel->ipv4.split_routes);
859 	setenv(env_var, mask, 0);
860 	if (gateway != NULL) {
861 		sprintf(env_var, "VPN_ROUTE_GATEWAY_%d",
862 		        tunnel->ipv4.split_routes);
863 		setenv(env_var, gateway, 0);
864 	}
865 
866 	route = &tunnel->ipv4.split_rt[tunnel->ipv4.split_routes++];
867 
868 	route_init(route);
869 	route_dest(route).s_addr = inet_addr(dest);
870 	route_mask(route).s_addr = inet_addr(mask);
871 	if (gateway != NULL) {
872 		route_gtw(route).s_addr = inet_addr(gateway);
873 		route->rt_flags |= RTF_GATEWAY;
874 	} else {
875 		free(route_iface(route));
876 		route_iface(route) = strdup(tunnel->ppp_iface);
877 		if (!route_iface(route))
878 			return ERR_IPV4_NO_MEM;
879 	}
880 
881 	return 0;
882 }
883 
ipv4_set_split_routes(struct tunnel * tunnel)884 static int ipv4_set_split_routes(struct tunnel *tunnel)
885 {
886 	int i;
887 
888 	for (i = 0; i < tunnel->ipv4.split_routes; i++) {
889 		struct rtentry_ofvpn *route;
890 		int ret;
891 
892 		route = &tunnel->ipv4.split_rt[i];
893 		// check if the route to be added is not the one to the gateway itself
894 		if (route_dest(route).s_addr == route_dest(&tunnel->ipv4.gtw_rt).s_addr) {
895 			log_debug("Skipping route to tunnel gateway (%s).\n",
896 			          ipv4_show_route(route));
897 			continue;
898 		}
899 
900 		free(route_iface(route));
901 		route_iface(route) = strdup(tunnel->ppp_iface);
902 		if (!route_iface(route))
903 			return ERR_IPV4_NO_MEM;
904 		if (route_gtw(route).s_addr == tunnel->ipv4.ip_addr.s_addr)
905 			route_gtw(route).s_addr = 0;
906 		if (route_gtw(route).s_addr == 0)
907 			route->rt_flags &= ~RTF_GATEWAY;
908 		if (route_gtw(route).s_addr != 0)
909 			route->rt_flags |= RTF_GATEWAY;
910 		ret = ipv4_set_route(route);
911 		if (ret == ERR_IPV4_SEE_ERRNO && errno == EEXIST)
912 			log_warn("Route to gateway exists already.\n");
913 		else if (ret != 0)
914 			log_warn("Could not set route to tunnel gateway (%s).\n",
915 			         err_ipv4_str(ret));
916 	}
917 	return 0;
918 }
919 
ipv4_set_default_routes(struct tunnel * tunnel)920 static int ipv4_set_default_routes(struct tunnel *tunnel)
921 {
922 	int ret;
923 	struct rtentry_ofvpn *def_rt = &tunnel->ipv4.def_rt;
924 	struct rtentry_ofvpn *ppp_rt = &tunnel->ipv4.ppp_rt;
925 	struct vpn_config *cfg = tunnel->config;
926 
927 	route_init(ppp_rt);
928 
929 	if (cfg->half_internet_routes == 0) {
930 		// Delete the current default route
931 		log_debug("Deleting the current default route...\n");
932 		ret = ipv4_del_route(def_rt);
933 		if (ret != 0)
934 			log_warn("Could not delete the current default route (%s).\n",
935 			         err_ipv4_str(ret));
936 
937 		// Set the new default route
938 		// ip route add to 0/0 dev ppp0
939 		route_dest(ppp_rt).s_addr = inet_addr("0.0.0.0");
940 		route_mask(ppp_rt).s_addr = inet_addr("0.0.0.0");
941 		route_gtw(ppp_rt).s_addr = inet_addr("0.0.0.0");
942 		log_debug("Setting new default route...\n");
943 
944 		free(route_iface(ppp_rt));
945 		route_iface(ppp_rt) = strdup(tunnel->ppp_iface);
946 		if (!route_iface(ppp_rt))
947 			return ERR_IPV4_NO_MEM;
948 		if (route_gtw(ppp_rt).s_addr == tunnel->ipv4.ip_addr.s_addr)
949 			route_gtw(ppp_rt).s_addr = 0;
950 		if (route_gtw(ppp_rt).s_addr == 0)
951 			ppp_rt->rt_flags &= ~RTF_GATEWAY;
952 		if (route_gtw(ppp_rt).s_addr != 0)
953 			ppp_rt->rt_flags |= RTF_GATEWAY;
954 		ret = ipv4_set_route(ppp_rt);
955 		if (ret == ERR_IPV4_SEE_ERRNO && errno == EEXIST) {
956 			log_warn("Default route exists already.\n");
957 		} else if (ret != 0) {
958 			log_warn("Could not set the new default route (%s).\n",
959 			         err_ipv4_str(ret));
960 		}
961 
962 	} else {
963 		// Emulate default routes as two "half internet" routes
964 		// This allows for e.g. DHCP renewing default routes without
965 		// breaking the tunnel
966 		log_debug("Setting new half-internet routes...\n");
967 		route_dest(ppp_rt).s_addr = inet_addr("0.0.0.0");
968 		route_mask(ppp_rt).s_addr = inet_addr("128.0.0.0");
969 
970 		free(route_iface(ppp_rt));
971 		route_iface(ppp_rt) = strdup(tunnel->ppp_iface);
972 		if (!route_iface(ppp_rt))
973 			return ERR_IPV4_NO_MEM;
974 		if (route_gtw(ppp_rt).s_addr == tunnel->ipv4.ip_addr.s_addr)
975 			route_gtw(ppp_rt).s_addr = 0;
976 		if (route_gtw(ppp_rt).s_addr == 0)
977 			ppp_rt->rt_flags &= ~RTF_GATEWAY;
978 		if (route_gtw(ppp_rt).s_addr != 0)
979 			ppp_rt->rt_flags |= RTF_GATEWAY;
980 		ret = ipv4_set_route(ppp_rt);
981 		if (ret == ERR_IPV4_SEE_ERRNO && errno == EEXIST) {
982 			log_warn("0.0.0.0/1 route exists already.\n");
983 		} else if (ret != 0) {
984 			log_warn("Could not set the new 0.0.0.0/1 route (%s).\n",
985 			         err_ipv4_str(ret));
986 		}
987 
988 		route_dest(ppp_rt).s_addr = inet_addr("128.0.0.0");
989 		ret = ipv4_set_route(ppp_rt);
990 		if (ret == ERR_IPV4_SEE_ERRNO && errno == EEXIST) {
991 			log_warn("128.0.0.0/1 route exists already.\n");
992 		} else if (ret != 0) {
993 			log_warn("Could not set the new 128.0.0.0/1 route (%s).\n",
994 			         err_ipv4_str(ret));
995 		}
996 	}
997 
998 	return 0;
999 }
1000 
ipv4_set_tunnel_routes(struct tunnel * tunnel)1001 int ipv4_set_tunnel_routes(struct tunnel *tunnel)
1002 {
1003 	int ret = ipv4_protect_tunnel_route(tunnel);
1004 
1005 	if (tunnel->ipv4.split_routes)
1006 		// try even if ipv4_protect_tunnel_route has failed
1007 		return ipv4_set_split_routes(tunnel);
1008 	else if (ret == 0)
1009 		return ipv4_set_default_routes(tunnel);
1010 	else
1011 		return ret;
1012 }
1013 
ipv4_restore_routes(struct tunnel * tunnel)1014 int ipv4_restore_routes(struct tunnel *tunnel)
1015 {
1016 	struct rtentry_ofvpn *def_rt = &tunnel->ipv4.def_rt;
1017 	struct rtentry_ofvpn *gtw_rt = &tunnel->ipv4.gtw_rt;
1018 	struct rtentry_ofvpn *ppp_rt = &tunnel->ipv4.ppp_rt;
1019 	struct vpn_config *cfg = tunnel->config;
1020 
1021 	if (tunnel->ipv4.route_to_vpn_is_added) {
1022 		int ret;
1023 
1024 		ret = ipv4_del_route(gtw_rt);
1025 		if (ret != 0)
1026 			log_warn("Could not delete route to vpn server (%s).\n",
1027 			         err_ipv4_str(ret));
1028 		if ((cfg->half_internet_routes == 0) &&
1029 		    (tunnel->ipv4.split_routes == 0)) {
1030 			ret = ipv4_del_route(ppp_rt);
1031 			if (ret != 0)
1032 				log_warn("Could not delete route through tunnel (%s).\n",
1033 				         err_ipv4_str(ret));
1034 
1035 			// Restore the default route. It seems not to be
1036 			// automatically restored on all linux distributions
1037 			ret = ipv4_set_route(def_rt);
1038 			if (ret != 0) {
1039 				log_warn("Could not restore default route (%s). Already restored?\n",
1040 				         err_ipv4_str(ret));
1041 			}
1042 		}
1043 	} else {
1044 		log_debug("Route to vpn server was not added\n");
1045 	}
1046 	route_destroy(ppp_rt);
1047 	route_destroy(def_rt);
1048 	route_destroy(gtw_rt);
1049 
1050 	return 0;
1051 }
1052 
replace_char(char * str,char find,char replace)1053 static inline char *replace_char(char *str, char find, char replace)
1054 {
1055 	int i;
1056 
1057 	for (i = 0; i < strlen(str); i++)
1058 		if (str[i] == find)
1059 			str[i] = replace;
1060 	return str;
1061 }
1062 
ipv4_add_nameservers_to_resolv_conf(struct tunnel * tunnel)1063 int ipv4_add_nameservers_to_resolv_conf(struct tunnel *tunnel)
1064 {
1065 	int ret = -1;
1066 	FILE *file;
1067 	struct stat stat;
1068 #define NS_SIZE ARRAY_SIZE("nameserver xxx.xxx.xxx.xxx\n")
1069 	char ns1[NS_SIZE], ns2[NS_SIZE];
1070 #undef NS_SIZE
1071 #define DNS_SUFFIX_SIZE (ARRAY_SIZE("search \n") + MAX_DOMAIN_LENGTH)
1072 	char dns_suffix[DNS_SUFFIX_SIZE];
1073 #undef DNS_SUFFIX_SIZE
1074 	char *buffer = NULL;
1075 #if HAVE_RESOLVCONF
1076 	int use_resolvconf = 0;
1077 #endif
1078 
1079 	tunnel->ipv4.ns1_was_there = 0;
1080 	tunnel->ipv4.ns2_was_there = 0;
1081 	tunnel->ipv4.dns_suffix_was_there = 0;
1082 
1083 	if (tunnel->ipv4.ns1_addr.s_addr == 0)
1084 		tunnel->ipv4.ns1_was_there = -1;
1085 
1086 	if (tunnel->ipv4.ns2_addr.s_addr == 0)
1087 		tunnel->ipv4.ns2_was_there = -1;
1088 
1089 #if HAVE_RESOLVCONF
1090 	if (tunnel->config->use_resolvconf
1091 	    && (access(RESOLVCONF_PATH, F_OK) == 0)) {
1092 		int resolvconf_call_len;
1093 		char *resolvconf_call;
1094 
1095 		log_debug("Attempting to run %s.\n", RESOLVCONF_PATH);
1096 		resolvconf_call_len = strlen(RESOLVCONF_PATH) + 20
1097 		                      + strlen(tunnel->ppp_iface);
1098 		resolvconf_call = malloc(resolvconf_call_len);
1099 		if (resolvconf_call == NULL) {
1100 			log_warn("Could not create command to run resolvconf (%s).\n",
1101 			         strerror(errno));
1102 			return 1;
1103 		}
1104 
1105 		snprintf(resolvconf_call, resolvconf_call_len,
1106 		         "%s -a \"%s.openfortivpn\"",
1107 		         RESOLVCONF_PATH,
1108 		         tunnel->ppp_iface);
1109 
1110 		use_resolvconf = 1;
1111 		log_debug("resolvconf_call: %s\n", resolvconf_call);
1112 		file = popen(resolvconf_call, "w");
1113 		if (file == NULL) {
1114 			log_warn("Could not open pipe %s (%s).\n",
1115 			         resolvconf_call,
1116 			         strerror(errno));
1117 			free(resolvconf_call);
1118 			return 1;
1119 		}
1120 		free(resolvconf_call);
1121 	} else {
1122 #endif
1123 		log_debug("Attempting to modify /etc/resolv.conf directly.\n");
1124 		file = fopen("/etc/resolv.conf", "r+");
1125 		if (file == NULL) {
1126 			log_warn("Could not open /etc/resolv.conf (%s).\n",
1127 			         strerror(errno));
1128 			return 1;
1129 		}
1130 
1131 		if (fstat(fileno(file), &stat) == -1) {
1132 			log_warn("Could not stat /etc/resolv.conf (%s).\n",
1133 			         strerror(errno));
1134 			goto err_close;
1135 		}
1136 
1137 		if (stat.st_size == 0) {
1138 			log_warn("Could not read /etc/resolv.conf (%s).\n",
1139 			         "Empty file");
1140 			goto err_close;
1141 		}
1142 
1143 		buffer = malloc(stat.st_size + 1);
1144 		if (buffer == NULL) {
1145 			log_warn("Could not read /etc/resolv.conf (%s).\n",
1146 			         strerror(errno));
1147 			goto err_close;
1148 		}
1149 
1150 		// Copy all file contents at once
1151 		if (fread(buffer, stat.st_size, 1, file) != 1) {
1152 			log_warn("Could not read /etc/resolv.conf.\n");
1153 			goto err_free;
1154 		}
1155 
1156 		buffer[stat.st_size] = '\0';
1157 #if HAVE_RESOLVCONF
1158 	}
1159 #endif
1160 	if (tunnel->ipv4.ns1_addr.s_addr != 0) {
1161 		strcpy(ns1, "nameserver ");
1162 		strncat(ns1, inet_ntoa(tunnel->ipv4.ns1_addr), 15);
1163 	} else {
1164 		ns1[0] = '\0';
1165 	}
1166 
1167 	if (tunnel->ipv4.ns2_addr.s_addr != 0) {
1168 		strcpy(ns2, "nameserver ");
1169 		strncat(ns2, inet_ntoa(tunnel->ipv4.ns2_addr), 15);
1170 	} else {
1171 		ns2[0] = '\0';
1172 	}
1173 
1174 	if (tunnel->ipv4.dns_suffix != NULL) {
1175 		strcpy(dns_suffix, "search ");
1176 		strncat(dns_suffix, tunnel->ipv4.dns_suffix, MAX_DOMAIN_LENGTH);
1177 		replace_char(dns_suffix, ';', ' ');
1178 	} else {
1179 		dns_suffix[0] = '\0';
1180 	}
1181 
1182 #if HAVE_RESOLVCONF
1183 	if (use_resolvconf == 0) {
1184 #endif
1185 		char *saveptr = NULL;
1186 
1187 		for (const char *line = strtok_r(buffer, "\n", &saveptr);
1188 		     line != NULL;
1189 		     line = strtok_r(NULL, "\n", &saveptr)) {
1190 			if (strcmp(line, ns1) == 0) {
1191 				tunnel->ipv4.ns1_was_there = 1;
1192 				log_debug("ns1 already present in /etc/resolv.conf.\n");
1193 			}
1194 		}
1195 
1196 		if (tunnel->ipv4.ns1_was_there == 0)
1197 			log_debug("Adding \"%s\", to /etc/resolv.conf.\n", ns1);
1198 
1199 		for (const char *line = strtok_r(buffer, "\n", &saveptr);
1200 		     line != NULL;
1201 		     line = strtok_r(NULL, "\n", &saveptr)) {
1202 			if (strcmp(line, ns2) == 0) {
1203 				tunnel->ipv4.ns2_was_there = 1;
1204 				log_debug("ns2 already present in /etc/resolv.conf.\n");
1205 			}
1206 		}
1207 
1208 		if (tunnel->ipv4.ns2_was_there == 0)
1209 			log_debug("Adding \"%s\", to /etc/resolv.conf.\n", ns2);
1210 
1211 		if (dns_suffix[0] == '\0') {
1212 			tunnel->ipv4.dns_suffix_was_there = -1;
1213 		} else {
1214 			for (const char *line = strtok_r(buffer, "\n", &saveptr);
1215 			     line != NULL;
1216 			     line = strtok_r(NULL, "\n", &saveptr)) {
1217 				if (dns_suffix[0] != '\0'
1218 				    && strcmp(line, dns_suffix) == 0) {
1219 					tunnel->ipv4.dns_suffix_was_there = 1;
1220 					log_debug("dns_suffix already present in /etc/resolv.conf.\n");
1221 				}
1222 			}
1223 		}
1224 
1225 		if (tunnel->ipv4.dns_suffix_was_there == 0)
1226 			log_debug("Adding \"%s\", to /etc/resolv.conf.\n", dns_suffix);
1227 
1228 		rewind(file);
1229 		if (fread(buffer, stat.st_size, 1, file) != 1) {
1230 			log_warn("Could not read /etc/resolv.conf.\n");
1231 			goto err_free;
1232 		}
1233 
1234 		buffer[stat.st_size] = '\0';
1235 
1236 		rewind(file);
1237 #if HAVE_RESOLVCONF
1238 	}
1239 #endif
1240 	if (tunnel->ipv4.ns1_was_there == 0) {
1241 		strcat(ns1, "\n");
1242 		fputs(ns1, file);
1243 	}
1244 	if (tunnel->ipv4.ns2_was_there == 0) {
1245 		strcat(ns2, "\n");
1246 		fputs(ns2, file);
1247 	}
1248 	if (tunnel->ipv4.dns_suffix_was_there == 0) {
1249 		strcat(dns_suffix, "\n");
1250 		fputs(dns_suffix, file);
1251 	}
1252 #if HAVE_RESOLVCONF
1253 	if (use_resolvconf == 0)
1254 #endif
1255 		fwrite(buffer, stat.st_size, 1, file);
1256 
1257 	ret = 0;
1258 
1259 err_free:
1260 	free(buffer);
1261 err_close:
1262 #if HAVE_RESOLVCONF
1263 	if (use_resolvconf == 0) {
1264 #endif
1265 		if (fclose(file))
1266 			log_warn("Could not close /etc/resolv.conf: %s\n",
1267 			         strerror(errno));
1268 #if HAVE_RESOLVCONF
1269 	} else {
1270 		if (pclose(file) == -1)
1271 			log_warn("Could not close resolvconf pipe: %s\n",
1272 			         strerror(errno));
1273 	}
1274 #endif
1275 
1276 	return ret;
1277 }
1278 
ipv4_del_nameservers_from_resolv_conf(struct tunnel * tunnel)1279 int ipv4_del_nameservers_from_resolv_conf(struct tunnel *tunnel)
1280 {
1281 	int ret = -1;
1282 	FILE *file;
1283 	struct stat stat;
1284 #define NS_SIZE ARRAY_SIZE("nameserver xxx.xxx.xxx.xxx")
1285 	char ns1[NS_SIZE], ns2[NS_SIZE];
1286 #undef NS_SIZE
1287 #define DNS_SUFFIX_SIZE (ARRAY_SIZE("search ") + MAX_DOMAIN_LENGTH)
1288 	char dns_suffix[DNS_SUFFIX_SIZE];
1289 #undef DNS_SUFFIX_SIZE
1290 	char *buffer = NULL;
1291 	char *saveptr = NULL;
1292 
1293 #if HAVE_RESOLVCONF
1294 	if (tunnel->config->use_resolvconf
1295 	    && (access(RESOLVCONF_PATH, F_OK) == 0)) {
1296 		int resolvconf_call_len;
1297 		char *resolvconf_call;
1298 
1299 		resolvconf_call_len = strlen(RESOLVCONF_PATH) + 20
1300 		                      + strlen(tunnel->ppp_iface);
1301 		resolvconf_call = malloc(resolvconf_call_len);
1302 		if (resolvconf_call == NULL) {
1303 			log_warn("Could not create command to run resolvconf (%s).\n",
1304 			         strerror(errno));
1305 			return ERR_IPV4_SEE_ERRNO;
1306 		}
1307 
1308 		snprintf(resolvconf_call,
1309 		         resolvconf_call_len,
1310 		         "%s -d \"%s.openfortivpn\"",
1311 		         RESOLVCONF_PATH,
1312 		         tunnel->ppp_iface
1313 		        );
1314 
1315 		log_debug("resolvconf_call: %s\n", resolvconf_call);
1316 		ret = system(resolvconf_call);
1317 		free(resolvconf_call);
1318 		if (ret == -1)
1319 			return ERR_IPV4_SEE_ERRNO;
1320 		return 0;
1321 	}
1322 #endif
1323 
1324 	file = fopen("/etc/resolv.conf", "r+");
1325 	if (file == NULL) {
1326 		log_warn("Could not open /etc/resolv.conf (%s).\n",
1327 		         strerror(errno));
1328 		return 1;
1329 	}
1330 
1331 	if (fstat(fileno(file), &stat) == -1) {
1332 		log_warn("Could not stat /etc/resolv.conf (%s).\n",
1333 		         strerror(errno));
1334 		goto err_close;
1335 	}
1336 
1337 	buffer = malloc(stat.st_size + 1);
1338 	if (buffer == NULL) {
1339 		log_warn("Could not read /etc/resolv.conf (%s).\n",
1340 		         strerror(errno));
1341 		goto err_close;
1342 	}
1343 
1344 	// Copy all file contents at once
1345 	if (fread(buffer, stat.st_size, 1, file) != 1) {
1346 		log_warn("Could not read /etc/resolv.conf.\n");
1347 		goto err_free;
1348 	}
1349 
1350 	buffer[stat.st_size] = '\0';
1351 
1352 	ns1[0] = '\0';
1353 	if (tunnel->ipv4.ns1_addr.s_addr != 0) {
1354 		strcpy(ns1, "nameserver ");
1355 		strncat(ns1, inet_ntoa(tunnel->ipv4.ns1_addr), 15);
1356 	}
1357 	ns2[0] = '\0';
1358 	if (tunnel->ipv4.ns2_addr.s_addr != 0) {
1359 		strcpy(ns2, "nameserver ");
1360 		strncat(ns2, inet_ntoa(tunnel->ipv4.ns2_addr), 15);
1361 	}
1362 	dns_suffix[0] = '\0';
1363 	if (tunnel->ipv4.dns_suffix != NULL && tunnel->ipv4.dns_suffix[0] != '\0') {
1364 		strcpy(dns_suffix, "search ");
1365 		strncat(dns_suffix, tunnel->ipv4.dns_suffix, MAX_DOMAIN_LENGTH);
1366 	}
1367 
1368 	file = freopen("/etc/resolv.conf", "w", file);
1369 	if (file == NULL) {
1370 		log_warn("Could not reopen /etc/resolv.conf (%s).\n",
1371 		         strerror(errno));
1372 		goto err_free;
1373 	}
1374 
1375 	for (const char *line = strtok_r(buffer, "\n", &saveptr);
1376 	     line != NULL;
1377 	     line = strtok_r(NULL, "\n", &saveptr)) {
1378 		if (ns1[0] != '\0' && strcmp(line, ns1) == 0
1379 		    && (tunnel->ipv4.ns1_was_there == 0)) {
1380 			log_debug("Deleting \"%s\" from /etc/resolv.conf.\n", ns1);
1381 		} else if (ns2[0] != '\0' && strcmp(line, ns2) == 0
1382 		           && (tunnel->ipv4.ns2_was_there == 0)) {
1383 			log_debug("Deleting \"%s\" from /etc/resolv.conf.\n", ns2);
1384 		} else if (dns_suffix[0] != '\0' && strcmp(line, dns_suffix) == 0
1385 		           && (tunnel->ipv4.dns_suffix_was_there == 0)) {
1386 			log_debug("Deleting \"%s\" from /etc/resolv.conf.\n", dns_suffix);
1387 		} else {
1388 			fputs(line, file);
1389 			fputs("\n", file);
1390 		}
1391 	}
1392 
1393 	ret = 0;
1394 
1395 err_free:
1396 	free(buffer);
1397 err_close:
1398 	if (file && fclose(file))
1399 		log_warn("Could not close /etc/resolv.conf (%s).\n",
1400 		         strerror(errno));
1401 	return ret;
1402 }
1403