LCOV - code coverage report
Current view: top level - resolve - resolvconf-compat.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 0 119 0.0 %
Date: 2019-08-22 15:41:25 Functions: 0 4 0.0 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include <getopt.h>
       4             : #include <net/if.h>
       5             : 
       6             : #include "alloc-util.h"
       7             : #include "def.h"
       8             : #include "dns-domain.h"
       9             : #include "extract-word.h"
      10             : #include "fileio.h"
      11             : #include "parse-util.h"
      12             : #include "pretty-print.h"
      13             : #include "resolvconf-compat.h"
      14             : #include "resolvectl.h"
      15             : #include "resolved-def.h"
      16             : #include "string-util.h"
      17             : #include "strv.h"
      18             : #include "terminal-util.h"
      19             : 
      20           0 : static int resolvconf_help(void) {
      21           0 :         _cleanup_free_ char *link = NULL;
      22             :         int r;
      23             : 
      24           0 :         r = terminal_urlify_man("resolvectl", "1", &link);
      25           0 :         if (r < 0)
      26           0 :                 return log_oom();
      27             : 
      28           0 :         printf("%1$s -a INTERFACE < FILE\n"
      29             :                "%1$s -d INTERFACE\n"
      30             :                "\n"
      31             :                "Register DNS server and domain configuration with systemd-resolved.\n\n"
      32             :                "  -h --help     Show this help\n"
      33             :                "     --version  Show package version\n"
      34             :                "  -a            Register per-interface DNS server and domain data\n"
      35             :                "  -d            Unregister per-interface DNS server and domain data\n"
      36             :                "  -f            Ignore if specified interface does not exist\n"
      37             :                "  -x            Send DNS traffic preferably over this interface\n"
      38             :                "\n"
      39             :                "This is a compatibility alias for the resolvectl(1) tool, providing native\n"
      40             :                "command line compatibility with the resolvconf(8) tool of various Linux\n"
      41             :                "distributions and BSD systems. Some options supported by other implementations\n"
      42             :                "are not supported and are ignored: -m, -p. Various options supported by other\n"
      43             :                "implementations are not supported and will cause the invocation to fail: -u,\n"
      44             :                "-I, -i, -l, -R, -r, -v, -V, --enable-updates, --disable-updates,\n"
      45             :                "--updates-are-enabled.\n"
      46             :                "\nSee the %2$s for details.\n"
      47             :                , program_invocation_short_name
      48             :                , link
      49             :         );
      50             : 
      51           0 :         return 0;
      52             : }
      53             : 
      54           0 : static int parse_nameserver(const char *string) {
      55             :         int r;
      56             : 
      57           0 :         assert(string);
      58             : 
      59           0 :         for (;;) {
      60           0 :                 _cleanup_free_ char *word = NULL;
      61             : 
      62           0 :                 r = extract_first_word(&string, &word, NULL, 0);
      63           0 :                 if (r < 0)
      64           0 :                         return r;
      65           0 :                 if (r == 0)
      66           0 :                         break;
      67             : 
      68           0 :                 if (strv_push(&arg_set_dns, word) < 0)
      69           0 :                         return log_oom();
      70             : 
      71           0 :                 word = NULL;
      72             :         }
      73             : 
      74           0 :         return 0;
      75             : }
      76             : 
      77           0 : static int parse_search_domain(const char *string) {
      78             :         int r;
      79             : 
      80           0 :         assert(string);
      81             : 
      82           0 :         for (;;) {
      83           0 :                 _cleanup_free_ char *word = NULL;
      84             : 
      85           0 :                 r = extract_first_word(&string, &word, NULL, EXTRACT_UNQUOTE);
      86           0 :                 if (r < 0)
      87           0 :                         return r;
      88           0 :                 if (r == 0)
      89           0 :                         break;
      90             : 
      91           0 :                 if (strv_push(&arg_set_domain, word) < 0)
      92           0 :                         return log_oom();
      93             : 
      94           0 :                 word = NULL;
      95             :         }
      96             : 
      97           0 :         return 0;
      98             : }
      99             : 
     100           0 : int resolvconf_parse_argv(int argc, char *argv[]) {
     101             : 
     102             :         enum {
     103             :                 ARG_VERSION = 0x100,
     104             :                 ARG_ENABLE_UPDATES,
     105             :                 ARG_DISABLE_UPDATES,
     106             :                 ARG_UPDATES_ARE_ENABLED,
     107             :         };
     108             : 
     109             :         static const struct option options[] = {
     110             :                 { "help",                no_argument, NULL, 'h'                     },
     111             :                 { "version",             no_argument, NULL, ARG_VERSION             },
     112             : 
     113             :                 /* The following are specific to Debian's original resolvconf */
     114             :                 { "enable-updates",      no_argument, NULL, ARG_ENABLE_UPDATES      },
     115             :                 { "disable-updates",     no_argument, NULL, ARG_DISABLE_UPDATES     },
     116             :                 { "updates-are-enabled", no_argument, NULL, ARG_UPDATES_ARE_ENABLED },
     117             :                 {}
     118             :         };
     119             : 
     120             :         enum {
     121             :                 TYPE_REGULAR,
     122             :                 TYPE_PRIVATE,   /* -p: Not supported, treated identically to TYPE_REGULAR */
     123             :                 TYPE_EXCLUSIVE, /* -x */
     124           0 :         } type = TYPE_REGULAR;
     125             : 
     126             :         int c, r;
     127             : 
     128           0 :         assert(argc >= 0);
     129           0 :         assert(argv);
     130             : 
     131             :         /* openresolv checks these environment variables */
     132           0 :         if (getenv("IF_EXCLUSIVE"))
     133           0 :                 type = TYPE_EXCLUSIVE;
     134           0 :         if (getenv("IF_PRIVATE"))
     135           0 :                 type = TYPE_PRIVATE; /* not actually supported */
     136             : 
     137           0 :         arg_mode = _MODE_INVALID;
     138             : 
     139           0 :         while ((c = getopt_long(argc, argv, "hadxpfm:uIi:l:Rr:vV", options, NULL)) >= 0)
     140           0 :                 switch(c) {
     141             : 
     142           0 :                 case 'h':
     143           0 :                         return resolvconf_help();
     144             : 
     145           0 :                 case ARG_VERSION:
     146           0 :                         return version();
     147             : 
     148             :                 /* -a and -d is what everybody can agree on */
     149           0 :                 case 'a':
     150           0 :                         arg_mode = MODE_SET_LINK;
     151           0 :                         break;
     152             : 
     153           0 :                 case 'd':
     154           0 :                         arg_mode = MODE_REVERT_LINK;
     155           0 :                         break;
     156             : 
     157             :                 /* The exclusive/private/force stuff is an openresolv invention, we support in some skewed way */
     158           0 :                 case 'x':
     159           0 :                         type = TYPE_EXCLUSIVE;
     160           0 :                         break;
     161             : 
     162           0 :                 case 'p':
     163           0 :                         type = TYPE_PRIVATE; /* not actually supported */
     164           0 :                         break;
     165             : 
     166           0 :                 case 'f':
     167           0 :                         arg_ifindex_permissive = true;
     168           0 :                         break;
     169             : 
     170             :                 /* The metrics stuff is an openresolv invention we ignore (and don't really need) */
     171           0 :                 case 'm':
     172           0 :                         log_debug("Switch -%c ignored.", c);
     173           0 :                         break;
     174             : 
     175             :                 /* Everybody else can agree on the existence of -u but we don't support it. */
     176           0 :                 case 'u':
     177             : 
     178             :                 /* The following options are openresolv inventions we don't support. */
     179             :                 case 'I':
     180             :                 case 'i':
     181             :                 case 'l':
     182             :                 case 'R':
     183             :                 case 'r':
     184             :                 case 'v':
     185             :                 case 'V':
     186           0 :                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     187             :                                                "Switch -%c not supported.", c);
     188             : 
     189             :                 /* The Debian resolvconf commands we don't support. */
     190           0 :                 case ARG_ENABLE_UPDATES:
     191           0 :                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     192             :                                                "Switch --enable-updates not supported.");
     193           0 :                 case ARG_DISABLE_UPDATES:
     194           0 :                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     195             :                                                "Switch --disable-updates not supported.");
     196           0 :                 case ARG_UPDATES_ARE_ENABLED:
     197           0 :                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     198             :                                                "Switch --updates-are-enabled not supported.");
     199             : 
     200           0 :                 case '?':
     201           0 :                         return -EINVAL;
     202             : 
     203           0 :                 default:
     204           0 :                         assert_not_reached("Unhandled option");
     205             :                 }
     206             : 
     207           0 :         if (arg_mode == _MODE_INVALID)
     208           0 :                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     209             :                                        "Expected either -a or -d on the command line.");
     210             : 
     211           0 :         if (optind+1 != argc)
     212           0 :                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     213             :                                        "Expected interface name as argument.");
     214             : 
     215           0 :         r = ifname_mangle(argv[optind]);
     216           0 :         if (r <= 0)
     217           0 :                 return r;
     218             : 
     219           0 :         optind++;
     220             : 
     221           0 :         if (arg_mode == MODE_SET_LINK) {
     222           0 :                 unsigned n = 0;
     223             : 
     224           0 :                 for (;;) {
     225           0 :                         _cleanup_free_ char *line = NULL;
     226             :                         const char *a, *l;
     227             : 
     228           0 :                         r = read_line(stdin, LONG_LINE_MAX, &line);
     229           0 :                         if (r < 0)
     230           0 :                                 return log_error_errno(r, "Failed to read from stdin: %m");
     231           0 :                         if (r == 0)
     232           0 :                                 break;
     233             : 
     234           0 :                         n++;
     235             : 
     236           0 :                         l = strstrip(line);
     237           0 :                         if (IN_SET(*l, '#', ';', 0))
     238           0 :                                 continue;
     239             : 
     240           0 :                         a = first_word(l, "nameserver");
     241           0 :                         if (a) {
     242           0 :                                 (void) parse_nameserver(a);
     243           0 :                                 continue;
     244             :                         }
     245             : 
     246           0 :                         a = first_word(l, "domain");
     247           0 :                         if (!a)
     248           0 :                                 a = first_word(l, "search");
     249           0 :                         if (a) {
     250           0 :                                 (void) parse_search_domain(a);
     251           0 :                                 continue;
     252             :                         }
     253             : 
     254           0 :                         log_syntax(NULL, LOG_DEBUG, "stdin", n, 0, "Ignoring resolv.conf line: %s", l);
     255             :                 }
     256             : 
     257           0 :                 if (type == TYPE_EXCLUSIVE) {
     258             : 
     259             :                         /* If -x mode is selected, let's preferably route non-suffixed lookups to this interface. This
     260             :                          * somewhat matches the original -x behaviour */
     261             : 
     262           0 :                         r = strv_extend(&arg_set_domain, "~.");
     263           0 :                         if (r < 0)
     264           0 :                                 return log_oom();
     265             : 
     266           0 :                 } else if (type == TYPE_PRIVATE)
     267           0 :                         log_debug("Private DNS server data not supported, ignoring.");
     268             : 
     269           0 :                 if (!arg_set_dns)
     270           0 :                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     271             :                                                "No DNS servers specified, refusing operation.");
     272             :         }
     273             : 
     274           0 :         return 1; /* work to do */
     275             : }

Generated by: LCOV version 1.14