pax_global_header00006660000000000000000000000064142273105510014512gustar00rootroot0000000000000052 comment=e08acd6560d33a65d1df01fe54a321cc71fe1583 ifupdown-ng-ifupdown-ng-0.12.1/000077500000000000000000000000001422731055100162635ustar00rootroot00000000000000ifupdown-ng-ifupdown-ng-0.12.1/.github/000077500000000000000000000000001422731055100176235ustar00rootroot00000000000000ifupdown-ng-ifupdown-ng-0.12.1/.github/workflows/000077500000000000000000000000001422731055100216605ustar00rootroot00000000000000ifupdown-ng-ifupdown-ng-0.12.1/.github/workflows/build.yml000066400000000000000000000007241422731055100235050ustar00rootroot00000000000000name: build on: [push, pull_request] jobs: build: runs-on: ubuntu-latest container: image: alpine steps: - name: Update system and add dependencies run: | apk upgrade -Ua apk add build-base git kyua atf scdoc - name: Checkout uses: actions/checkout@v2 - name: Build run: make - name: Build documentation run: make docs - name: Run tests run: make check ifupdown-ng-ifupdown-ng-0.12.1/.gitignore000066400000000000000000000001361422731055100202530ustar00rootroot00000000000000*.o *.a *.1 *.2 *.3 *.4 *.5 *.6 *.7 *.8 ifupdown ifquery ifup ifdown ifctrstat ifparse *.lock ifupdown-ng-ifupdown-ng-0.12.1/CODE_OF_CONDUCT.md000066400000000000000000000064341422731055100210710ustar00rootroot00000000000000# Contributor Covenant Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at ariadne@dereferenced.org. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html [homepage]: https://www.contributor-covenant.org For answers to common questions about this code of conduct, see https://www.contributor-covenant.org/faq ifupdown-ng-ifupdown-ng-0.12.1/COPYING000066400000000000000000000010021422731055100173070ustar00rootroot00000000000000Copyright (c) 2020-2021 Ariadne Conill Copyright (c) 2020-2021 Maximilian Wilhelm Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. This software is provided 'as is' and without any warranty, express or implied. In no event shall the authors be liable for any damages arising from the use of this software. ifupdown-ng-ifupdown-ng-0.12.1/Kyuafile000066400000000000000000000001001422731055100177460ustar00rootroot00000000000000syntax(2) test_suite('ifupdown-ng') include('tests/Kyuafile') ifupdown-ng-ifupdown-ng-0.12.1/Makefile000066400000000000000000000126261422731055100177320ustar00rootroot00000000000000LAYOUT ?= linux SCDOC := scdoc LIBBSD_CFLAGS = LIBBSD_LIBS = PACKAGE_NAME := ifupdown-ng PACKAGE_VERSION := 0.12.1 PACKAGE_BUGREPORT := https://github.com/ifupdown-ng/ifupdown-ng/issues/new SBINDIR := /sbin INTERFACES_FILE := /etc/network/interfaces STATE_FILE := /run/ifstate CONFIG_FILE := /etc/network/ifupdown-ng.conf EXECUTOR_PATH := /usr/libexec/ifupdown-ng CFLAGS ?= -ggdb3 -Os CFLAGS += -Wall -Wextra -Werror CFLAGS += -Wmissing-declarations -Wmissing-prototypes -Wcast-align -Wpointer-arith -Wreturn-type CFLAGS += ${LIBBSD_CFLAGS} CPPFLAGS = -I. CPPFLAGS += -DINTERFACES_FILE=\"${INTERFACES_FILE}\" CPPFLAGS += -DSTATE_FILE=\"${STATE_FILE}\" CPPFLAGS += -DCONFIG_FILE=\"${CONFIG_FILE}\" CPPFLAGS += -DPACKAGE_NAME=\"${PACKAGE_NAME}\" CPPFLAGS += -DPACKAGE_VERSION=\"${PACKAGE_VERSION}\" CPPFLAGS += -DPACKAGE_BUGREPORT=\"${PACKAGE_BUGREPORT}\" CPPFLAGS += -DEXECUTOR_PATH=\"${EXECUTOR_PATH}\" LIBIFUPDOWN_SRC = \ libifupdown/list.c \ libifupdown/dict.c \ libifupdown/interface.c \ libifupdown/interface-file.c \ libifupdown/fgetline.c \ libifupdown/version.c \ libifupdown/state.c \ libifupdown/environment.c \ libifupdown/execute.c \ libifupdown/lifecycle.c \ libifupdown/config-parser.c \ libifupdown/config-file.c \ libifupdown/compat.c LIBIFUPDOWN_OBJ = ${LIBIFUPDOWN_SRC:.c=.o} LIBIFUPDOWN_LIB = libifupdown.a MULTICALL_SRC = \ cmd/multicall.c \ cmd/multicall-options.c \ cmd/multicall-exec-options.c \ cmd/multicall-match-options.c \ cmd/pretty-print-iface.c MULTICALL_OBJ = ${MULTICALL_SRC:.c=.o} MULTICALL = ifupdown # enable ifup/ifdown applets (+16 KB) CONFIG_IFUPDOWN ?= Y IFUPDOWN_SRC = cmd/ifupdown.c MULTICALL_${CONFIG_IFUPDOWN}_OBJ += ${IFUPDOWN_SRC:.c=.o} CMDS_${CONFIG_IFUPDOWN} += ifup ifdown # enable ifquery applet (+4 KB) # [+20 KB without ifup/ifdown] CONFIG_IFQUERY ?= Y IFQUERY_SRC = cmd/ifquery.c MULTICALL_${CONFIG_IFQUERY}_OBJ += ${IFQUERY_SRC:.c=.o} CMDS_${CONFIG_IFQUERY} += ifquery # enable ifctrstat applet (+1 KB) CONFIG_IFCTRSTAT ?= Y IFCTRSTAT_SRC = cmd/ifctrstat.c cmd/ifctrstat-${LAYOUT}.c MULTICALL_${CONFIG_IFCTRSTAT}_OBJ += ${IFCTRSTAT_SRC:.c=.o} CMDS_${CONFIG_IFCTRSTAT} += ifctrstat # enable ifparse applet (+1 KB) CONFIG_IFPARSE ?= Y IFPARSE_SRC = cmd/ifparse.c MULTICALL_${CONFIG_IFPARSE}_OBJ += ${IFPARSE_SRC:.c=.o} CMDS_${CONFIG_IFPARSE} += ifparse # enable YAML support (+2 KB) CONFIG_YAML ?= Y YAML_SRC = \ libifupdown/yaml-base.c \ libifupdown/yaml-writer.c LIBIFUPDOWN_${CONFIG_YAML}_OBJ += ${YAML_SRC:.c=.o} CPPFLAGS_${CONFIG_YAML} += -DCONFIG_YAML LIBIFUPDOWN_OBJ += ${LIBIFUPDOWN_Y_OBJ} MULTICALL_OBJ += ${MULTICALL_Y_OBJ} CMDS += ${CMDS_Y} CPPFLAGS += ${CPPFLAGS_Y} EXECUTOR_SCRIPTS_CORE ?= \ dhcp \ ipv6-ra \ static \ link \ ppp \ forward EXECUTOR_SCRIPTS_OPT ?= \ batman \ bond \ bridge \ ethtool \ gre \ mpls \ tunnel \ vrf \ vxlan \ wifi \ wireguard \ wireguard-quick EXECUTOR_SCRIPTS ?= ${EXECUTOR_SCRIPTS_CORE} ${EXECUTOR_SCRIPTS_OPT} EXECUTOR_SCRIPTS_STUB ?= EXECUTOR_SCRIPTS_NATIVE ?= TARGET_LIBS = ${LIBIFUPDOWN_LIB} LIBS += ${TARGET_LIBS} ${LIBBSD_LIBS} all: ${MULTICALL} ${CMDS} ${CMDS}: ${MULTICALL} ln -sf ifupdown $@ ${MULTICALL}: ${TARGET_LIBS} ${MULTICALL_OBJ} ${CC} -o $@ ${MULTICALL_OBJ} ${LIBS} ${LIBIFUPDOWN_LIB}: ${LIBIFUPDOWN_OBJ} ${AR} -rcs $@ ${LIBIFUPDOWN_OBJ} clean: rm -f ${LIBIFUPDOWN_OBJ} ${MULTICALL_OBJ} rm -f ${LIBIFUPDOWN_LIB} rm -f ${CMDS} ${MULTICALL} rm -f ${MANPAGES} check: ${LIBIFUPDOWN_LIB} ${CMDS} kyua test || (kyua report --verbose && exit 1) install: all install -D -m755 ${MULTICALL} ${DESTDIR}${SBINDIR}/${MULTICALL} for i in ${CMDS}; do \ ln -s ${SBINDIR}/${MULTICALL} ${DESTDIR}${SBINDIR}/$$i; \ done for i in ${EXECUTOR_SCRIPTS}; do \ install -D -m755 executor-scripts/${LAYOUT}/$$i ${DESTDIR}${EXECUTOR_PATH}/$$i; \ done for i in ${EXECUTOR_SCRIPTS_STUB}; do \ install -D -m755 executor-scripts/stub/$$i ${DESTDIR}${EXECUTOR_PATH}/$$i; \ done for i in ${EXECUTOR_SCRIPTS_NATIVE}; do \ install -D -m755 executor-scripts/${LAYOUT}-native/$$i ${DESTDIR}${EXECUTOR_PATH}/$$i; \ done install -D -m644 dist/ifupdown-ng.conf.example ${DESTDIR}${CONFIG_FILE}.example .scd.1 .scd.2 .scd.3 .scd.4 .scd.5 .scd.6 .scd.7 .scd.8: ${SCDOC} < $< > $@ MANPAGES_5 = \ doc/ifstate.5 \ doc/ifupdown-ng.conf.5 \ doc/interfaces.5 \ doc/interfaces-bond.5 \ doc/interfaces-batman.5 \ doc/interfaces-bridge.5 \ doc/interfaces-forward.5 \ doc/interfaces-ppp.5 \ doc/interfaces-tunnel.5 \ doc/interfaces-vrf.5 \ doc/interfaces-vxlan.5 \ doc/interfaces-wifi.5 \ doc/interfaces-wireguard.5 \ doc/interfaces-wireguard-quick.5 MANPAGES_7 = \ doc/ifupdown-executor.7 MANPAGES_8 = \ doc/ifquery.8 \ doc/ifup.8 \ doc/ifdown.8 \ doc/ifctrstat.8 \ doc/ifparse.8 MANPAGES = ${MANPAGES_5} ${MANPAGES_7} ${MANPAGES_8} docs: ${MANPAGES} install_docs: docs for i in ${MANPAGES_5}; do \ target=$$(basename $$i); \ install -D -m644 $$i ${DESTDIR}/usr/share/man/man5/$$target; \ done for i in ${MANPAGES_7}; do \ target=$$(basename $$i); \ install -D -m644 $$i ${DESTDIR}/usr/share/man/man7/$$target; \ done for i in ${MANPAGES_8}; do \ target=$$(basename $$i); \ install -D -m644 $$i ${DESTDIR}/usr/share/man/man8/$$target; \ done .SUFFIXES: .scd .1 .2 .3 .4 .5 .6 .7 .8 DIST_NAME = ${PACKAGE_NAME}-${PACKAGE_VERSION} DIST_TARBALL = ${DIST_NAME}.tar.xz distcheck: check dist dist: ${DIST_TARBALL} ${DIST_TARBALL}: git archive --format=tar --prefix=${DIST_NAME}/ -o ${DIST_NAME}.tar ${DIST_NAME} xz ${DIST_NAME}.tar ifupdown-ng-ifupdown-ng-0.12.1/README.md000066400000000000000000000033321422731055100175430ustar00rootroot00000000000000# ifupdown-ng ifupdown-ng is a network device manager that is largely compatible with Debian ifupdown, BusyBox ifupdown and Cumulus Networks' ifupdown2. For more information read the [admin guide](doc/ADMIN-GUIDE.md). ## Dependency Resolution ![Dependency resolution example](doc/img/dependency-resolution.png) ifupdown-ng uses a dependency resolver to determine interface bring-up order in a deterministic way. This is accomplished through a combination of manual hinting using the `requires` keyword and dependency learning using native executors. For compatibility with some legacy ifupdown executors, we also provide the `requires` keyword under other environment variables in some cases. ## Caveats * ifupdown2 python plugins are not supported at this time. An executor could be written to handle them. * ifupdown-ng retains compatibility with /etc/network/if-X.d scripts, but will prefer using executors in /usr/libexec/ifupdown-ng where appropriate. ## Building On musl systems, simply do `make` and `make install` to build and install. On glibc systems, you must install `libbsd-dev` or equivalent and additionally define `LIBBSD_CFLAGS` and `LIBBSD_LIBS`: # instal packages apt install build-essential libbsd0 libbsd-dev # build ifupdown-ng make LIBBSD_CFLAGS="$(pkg-config --cflags libbsd-overlay)" LIBBSD_LIBS="$(pkg-config --cflags --libs libbsd-overlay)" make install To run the tests, do `make check`. Running the checks requires `kyua` (`apk add kyua` / `apt install kyua`). To build the documentation, do `make docs` and `make install_docs`. Building the documentation requires scdoc (`apk add scdoc` / `apt install scdoc`). ## Discussion Discuss ifupdown-ng on IRC: irc.oftc.net #ifupdown-ng ifupdown-ng-ifupdown-ng-0.12.1/cmd/000077500000000000000000000000001422731055100170265ustar00rootroot00000000000000ifupdown-ng-ifupdown-ng-0.12.1/cmd/ifctrstat-linux.c000066400000000000000000000042101422731055100223270ustar00rootroot00000000000000/* * cmd/ifctrstat-linux.c * Purpose: Implement ifctrstat system-specific routines for Linux * * Copyright (c) 2020 Adélie Software in the Public Benefit, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * This software is provided 'as is' and without any warranty, express or * implied. In no event shall the authors be liable for any damages arising * from the use of this software. */ #define _GNU_SOURCE #include #include #include #include #include "cmd/multicall.h" #include "cmd/ifctrstat-linux.h" struct counter_desc { const char *name; const void *data; } avail_counters[] = { {"rx.discard", "rx_dropped"}, {"rx.errors", "rx_errors"}, {"rx.octets", "rx_bytes"}, {"rx.packets", "rx_packets"}, {"tx.discard", "tx_dropped"}, {"tx.errors", "tx_errors"}, {"tx.octets", "tx_bytes"}, {"tx.packets", "tx_packets"} }; size_t avail_counters_count = ARRAY_SIZE(avail_counters); static int counter_compare(const void *key, const void *candidate) { return strcasecmp((const char *)key, ((struct counter_desc *)candidate)->name); } const char * read_counter(const char *interface, const char *counter) { FILE *fp; const char *path; char *full_path; char buffer[1024]; size_t in_count; struct counter_desc *ctrdata; errno = 0; ctrdata = bsearch(counter, avail_counters, avail_counters_count, sizeof(struct counter_desc), counter_compare); if (ctrdata) { path = (const char *)ctrdata->data; } else { errno = ENOSYS; return NULL; } if (asprintf(&full_path, "/sys/class/net/%s/statistics/%s", interface, path) < 0) { return NULL; } fp = fopen(full_path, "r"); if (!fp) { return NULL; } free(full_path); full_path = NULL; in_count = fread(buffer, 1, sizeof(buffer), fp); if (in_count == sizeof(buffer)) { errno = ENOMEM; fclose(fp); return NULL; } if (ferror(fp)) { return NULL; } fclose(fp); /* take away the \n, we add our own */ buffer[in_count - 1] = '\0'; return strdup(buffer); } ifupdown-ng-ifupdown-ng-0.12.1/cmd/ifctrstat-linux.h000066400000000000000000000013511422731055100223370ustar00rootroot00000000000000/* * cmd/ifctrstat-linux.c * Purpose: Implement ifctrstat system-specific routines for Linux * * Copyright (c) 2021 Maximilian Wilhelm * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * This software is provided 'as is' and without any warranty, express or * implied. In no event shall the authors be liable for any damages arising * from the use of this software. */ #ifndef IFUPDOWN_IFCTRSTAT_LINUX__H__GUARD #define IFUPDOWN_IFCTRSTAT_LINUX__H__GUARD extern const char * read_counter(const char *interface, const char *counter); #endif ifupdown-ng-ifupdown-ng-0.12.1/cmd/ifctrstat.c000066400000000000000000000071021422731055100211750ustar00rootroot00000000000000/* * cmd/ifctrstat.c * Purpose: Display statistics about interfaces on the system * * Copyright (c) 2020 Adélie Software in the Public Benefit, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * This software is provided 'as is' and without any warranty, express or * implied. In no event shall the authors be liable for any damages arising * from the use of this software. */ #include #include #include #include #include #include "libifupdown/libifupdown.h" #include "cmd/multicall.h" #include "cmd/ifctrstat-linux.h" extern struct counter_desc { const char *name; const void *data; } avail_counters[]; extern int avail_counters_count; static bool show_label = true; static bool counter_is_valid(const char *candidate) { for (int i = 0; i < avail_counters_count; i++) { if (strcasecmp(avail_counters[i].name, candidate) == 0) return true; } return false; } static void print_counter(const char *iface, const char *name, const char *value) { (void) iface; if (show_label) fprintf(stdout, "%s: %s\n", name, value); else fprintf(stdout, "%s\n", value); } static int print_all_counters(const char *iface) { int code = EXIT_SUCCESS; const char *res; for (int i = 0; i < avail_counters_count; i++) { const char *ctr = avail_counters[i].name; res = read_counter(iface, ctr); if (!res) { fprintf(stderr, "%s: could not determine value of %s for interface %s: %s\n", argv0, ctr, iface, strerror(errno)); code = EXIT_FAILURE; } else { print_counter(iface, ctr, res); } } return code; } static void ifctrstat_list_counters(const char *opt_arg) { (void) opt_arg; for (int i = 0; i < avail_counters_count; i++) { fprintf(stdout, "%s\n", avail_counters[i].name); } exit(EXIT_SUCCESS); } static void ifctrstat_set_nolabel(const char *opt_arg) { (void) opt_arg; show_label = false; } static int ifctrstat_main(int argc, char *argv[]) { if (optind >= argc) generic_usage(self_applet, EXIT_FAILURE); int idx = optind; if (argc - idx == 0) { fprintf(stderr, "%s: interface required\n", argv0); return EXIT_FAILURE; } const char *iface = argv[idx++]; if (argc - idx == 0) { return print_all_counters(iface); } for (; idx < argc; idx++) { if (!counter_is_valid(argv[idx])) { fprintf(stderr, "%s: counter %s is not valid or not available\n", argv0, argv[idx]); return EXIT_FAILURE; } errno = 0; const char *res = read_counter(iface, argv[idx]); if (!res) { fprintf(stderr, "%s: could not determine value of %s for interface %s: %s\n", argv0, argv[idx], iface, strerror(errno)); return EXIT_FAILURE; } print_counter(iface, argv[idx], res); } return EXIT_SUCCESS; } static struct if_option local_options[] = { {'L', "list", NULL, "list available counters", false, ifctrstat_list_counters}, {'n', "no-label", NULL, "print value without counter label", false, ifctrstat_set_nolabel} }; static struct if_option_group local_option_group = { .desc = "Program-specific options", .group_size = ARRAY_SIZE(local_options), .group = local_options }; struct if_applet ifctrstat_applet = { .name = "ifctrstat", .desc = "display statistics about an interface", .main = ifctrstat_main, .usage = "ifctrstat [options] \n ifctrstat [options] --list", .manpage = "8 ifctrstat", .groups = { &global_option_group, &local_option_group, NULL } }; APPLET_REGISTER(ifctrstat_applet) ifupdown-ng-ifupdown-ng-0.12.1/cmd/ifparse.c000066400000000000000000000124321422731055100206250ustar00rootroot00000000000000/* * cmd/ifparse.c * Purpose: Redisplay /e/n/i in alternative formats. * * Copyright (c) 2020 Ariadne Conill * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * This software is provided 'as is' and without any warranty, express or * implied. In no event shall the authors be liable for any damages arising * from the use of this software. */ #define _GNU_SOURCE #include #include #include #include #include "libifupdown/libifupdown.h" #ifdef CONFIG_YAML # include "libifupdown/yaml-base.h" # include "libifupdown/yaml-writer.h" #endif #include "cmd/multicall.h" #include "cmd/pretty-print-iface.h" static bool show_all = false; static bool allow_undefined = false; static void set_show_all(const char *arg) { (void) arg; show_all = true; } static void set_allow_undefined(const char *arg) { (void) arg; allow_undefined = true; } static const char *output_fmt = "ifupdown"; static void set_output_fmt(const char *arg) { output_fmt = arg; } static struct if_option local_options[] = { {'F', "format", NULL, "output format to use", true, set_output_fmt}, {'A', "all", NULL, "show all interfaces", false, set_show_all}, {'U', "allow-undefined", NULL, "allow querying undefined (virtual) interfaces", false, set_allow_undefined}, }; static struct if_option_group local_option_group = { .desc = "Program-specific options", .group_size = ARRAY_SIZE(local_options), .group = local_options }; #ifdef CONFIG_YAML static void prettyprint_interface_yaml(struct lif_interface *iface) { struct lif_yaml_node doc = {}; lif_yaml_document_init(&doc, "interfaces"); struct lif_yaml_node *iface_node = lif_yaml_node_new_list(iface->ifname); lif_yaml_node_append_child(&doc, iface_node); if (iface->is_auto) { struct lif_yaml_node *iface_entry_node = lif_yaml_node_new_boolean("auto", true); lif_yaml_node_append_child(iface_node, iface_entry_node); } struct lif_node *iter; LIF_DICT_FOREACH(iter, &iface->vars) { struct lif_dict_entry *entry = iter->data; const char *value = entry->data; char addr_buf[512]; if (!strcmp(entry->key, "address")) { struct lif_address *addr = entry->data; if (!lif_address_unparse(addr, addr_buf, sizeof addr_buf, true)) continue; value = addr_buf; } struct lif_yaml_node *iface_entry_node = lif_yaml_node_new_string(entry->key, value); lif_yaml_node_append_child(iface_node, iface_entry_node); } lif_yaml_write(iface_node, stdout, true); lif_yaml_node_free(&doc); } #endif struct prettyprint_impl_map { const char *name; void (*handle)(struct lif_interface *iface); }; struct prettyprint_impl_map pp_impl_map[] = { {"ifupdown", prettyprint_interface_eni}, #ifdef CONFIG_YAML {"yaml-raw", prettyprint_interface_yaml}, #endif }; static int pp_impl_cmp(const void *a, const void *b) { const char *key = a; const struct prettyprint_impl_map *impl = b; return strcmp(key, impl->name); } static int ifparse_main(int argc, char *argv[]) { struct lif_dict state = {}; struct lif_dict collection = {}; struct lif_interface_file_parse_state parse_state = { .collection = &collection, }; lif_interface_collection_init(&collection); if (!lif_state_read_path(&state, exec_opts.state_file)) { fprintf(stderr, "%s: could not parse %s\n", argv0, exec_opts.state_file); return EXIT_FAILURE; } if (!lif_interface_file_parse(&parse_state, exec_opts.interfaces_file)) { fprintf(stderr, "%s: could not parse %s\n", argv0, exec_opts.interfaces_file); return EXIT_FAILURE; } if (match_opts.property == NULL && lif_lifecycle_count_rdepends(&exec_opts, &collection) == -1) { fprintf(stderr, "%s: could not validate dependency tree\n", argv0); return EXIT_FAILURE; } if (!lif_compat_apply(&collection)) { fprintf(stderr, "%s: failed to apply compatibility glue\n", argv0); return EXIT_FAILURE; } struct prettyprint_impl_map *m = bsearch(output_fmt, pp_impl_map, ARRAY_SIZE(pp_impl_map), sizeof(*m), pp_impl_cmp); if (m == NULL) { fprintf(stderr, "%s: %s: output format not supported\n", argv0, output_fmt); return EXIT_FAILURE; } if (show_all) { struct lif_node *n; LIF_DICT_FOREACH(n, &collection) { struct lif_dict_entry *entry = n->data; m->handle(entry->data); } return EXIT_SUCCESS; } if (optind >= argc) generic_usage(self_applet, EXIT_FAILURE); int idx = optind; for (; idx < argc; idx++) { struct lif_dict_entry *entry = lif_dict_find(&collection, argv[idx]); struct lif_interface *iface = NULL; if (entry != NULL) iface = entry->data; if (entry == NULL && allow_undefined) iface = lif_interface_collection_find(&collection, argv[idx]); if (iface == NULL) { fprintf(stderr, "%s: unknown interface %s\n", argv0, argv[idx]); return EXIT_FAILURE; } m->handle(iface); } return EXIT_SUCCESS; } struct if_applet ifparse_applet = { .name = "ifparse", .desc = "redisplay interface configuration", .main = ifparse_main, .usage = "ifparse [options] \n ifparse [options] --all", .manpage = "8 ifparse", .groups = { &global_option_group, &match_option_group, &exec_option_group, &local_option_group }, }; APPLET_REGISTER(ifparse_applet) ifupdown-ng-ifupdown-ng-0.12.1/cmd/ifquery.c000066400000000000000000000170531422731055100206640ustar00rootroot00000000000000/* * cmd/ifquery.c * Purpose: look up information in /etc/network/interfaces * * Copyright (c) 2020 Ariadne Conill * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * This software is provided 'as is' and without any warranty, express or * implied. In no event shall the authors be liable for any damages arising * from the use of this software. */ #define _GNU_SOURCE #include #include #include #include #include "libifupdown/libifupdown.h" #include "cmd/multicall.h" #include "cmd/pretty-print-iface.h" static void print_interface_dot(struct lif_dict *collection, struct lif_interface *iface, struct lif_interface *parent) { if (!lif_lifecycle_query_dependents(&exec_opts, iface, iface->ifname)) return; if (parent != NULL) printf("\"%s (%zu)\" -> ", parent->ifname, parent->rdepends_count); printf("\"%s (%zu)\"", iface->ifname, iface->rdepends_count); printf("\n"); struct lif_dict_entry *entry = lif_dict_find(&iface->vars, "requires"); if (entry == NULL) return; char require_ifs[4096] = {}; strlcpy(require_ifs, entry->data, sizeof require_ifs); char *reqp = require_ifs; for (char *tokenp = lif_next_token(&reqp); *tokenp; tokenp = lif_next_token(&reqp)) { struct lif_interface *child_if = lif_interface_collection_find(collection, tokenp); if (child_if->is_pending) continue; child_if->is_pending = true; print_interface_dot(collection, child_if, iface); child_if->is_pending = false; } } static void print_interface_property(struct lif_interface *iface, const char *property) { struct lif_node *iter; bool printing_address = !strcmp(property, "address"); LIF_DICT_FOREACH(iter, &iface->vars) { struct lif_dict_entry *entry = iter->data; if (strcmp(entry->key, property)) continue; if (printing_address) { char addr_buf[512]; if (!lif_address_format_cidr(iface, entry, addr_buf, sizeof(addr_buf))) continue; printf("%s\n", addr_buf); } else printf("%s\n", (const char *) entry->data); } } static void list_interfaces(struct lif_dict *collection, struct match_options *opts) { struct lif_node *iter; if (opts->dot) { printf("digraph interfaces {\n" "edge [color=blue fontname=Sans fontsize=10]\n" "node [fontname=Sans fontsize=10]\n"); } LIF_DICT_FOREACH(iter, collection) { struct lif_dict_entry *entry = iter->data; struct lif_interface *iface = entry->data; if (opts->is_auto && !iface->is_auto) continue; if (opts->exclude_pattern != NULL && !fnmatch(opts->exclude_pattern, iface->ifname, 0)) continue; if (opts->include_pattern != NULL && fnmatch(opts->include_pattern, iface->ifname, 0)) continue; if (opts->pretty_print) prettyprint_interface_eni(iface); else if (opts->dot) print_interface_dot(collection, iface, NULL); else printf("%s\n", iface->ifname); } if (opts->dot) printf("}\n"); } static bool listing = false, listing_stat = false, listing_running = false; static bool allow_undefined = false; static void list_state(struct lif_dict *state, struct match_options *opts) { struct lif_node *iter; LIF_DICT_FOREACH(iter, state) { struct lif_dict_entry *entry = iter->data; if (opts->exclude_pattern != NULL && !fnmatch(opts->exclude_pattern, entry->key, 0)) continue; if (opts->include_pattern != NULL && fnmatch(opts->include_pattern, entry->key, 0)) continue; struct lif_state_record *rec = entry->data; if (listing_running) printf("%s\n", entry->key); else printf("%s=%s %zu%s\n", entry->key, rec->mapped_if, rec->refcount, rec->is_explicit ? " explicit" : ""); } } static void set_listing(const char *opt_arg) { (void) opt_arg; listing = true; } static void set_show_state(const char *opt_arg) { (void) opt_arg; listing_stat = true; } static void set_show_running(const char *opt_arg) { (void) opt_arg; listing_running = true; } static void set_pretty_print(const char *opt_arg) { (void) opt_arg; match_opts.pretty_print = true; } static void set_output_dot(const char *opt_arg) { (void) opt_arg; match_opts.dot = true; } static void set_property(const char *opt_arg) { match_opts.property = opt_arg; } static void set_allow_undefined(const char *opt_arg) { (void) opt_arg; allow_undefined = true; } static struct if_option local_options[] = { {'r', "running", NULL, "show configured (running) interfaces", false, set_show_running}, {'s', "state", NULL, "show configured state", false, set_show_state}, {'p', "property", "property PROPERTY", "print values of properties matching PROPERTY", true, set_property}, {'D', "dot", NULL, "generate a dependency graph", false, set_output_dot}, {'L', "list", NULL, "list matching interfaces", false, set_listing}, {'P', "pretty-print", NULL, "pretty print the interfaces instead of just listing", false, set_pretty_print}, {'U', "allow-undefined", NULL, "allow querying undefined (virtual) interfaces", false, set_allow_undefined}, }; static struct if_option_group local_option_group = { .desc = "Program-specific options", .group_size = ARRAY_SIZE(local_options), .group = local_options }; static int ifquery_main(int argc, char *argv[]) { struct lif_dict state = {}; struct lif_dict collection = {}; struct lif_interface_file_parse_state parse_state = { .collection = &collection, }; lif_interface_collection_init(&collection); if (!lif_state_read_path(&state, exec_opts.state_file)) { fprintf(stderr, "%s: could not parse %s\n", argv0, exec_opts.state_file); return EXIT_FAILURE; } if (!lif_interface_file_parse(&parse_state, exec_opts.interfaces_file)) { fprintf(stderr, "%s: could not parse %s\n", argv0, exec_opts.interfaces_file); return EXIT_FAILURE; } if (match_opts.property == NULL && lif_lifecycle_count_rdepends(&exec_opts, &collection) == -1) { fprintf(stderr, "%s: could not validate dependency tree\n", argv0); return EXIT_FAILURE; } if (!lif_compat_apply(&collection)) { fprintf(stderr, "%s: failed to apply compatibility glue\n", argv0); return EXIT_FAILURE; } /* --list --state is not allowed */ if (listing && (listing_stat || listing_running)) generic_usage(self_applet, EXIT_FAILURE); if (listing) { list_interfaces(&collection, &match_opts); return EXIT_SUCCESS; } else if (listing_stat || listing_running) { list_state(&state, &match_opts); return EXIT_SUCCESS; } if (optind >= argc) generic_usage(self_applet, EXIT_FAILURE); int idx = optind; for (; idx < argc; idx++) { struct lif_interface *iface = lif_state_lookup(&state, &collection, argv[idx]); if (iface == NULL) { struct lif_dict_entry *entry = lif_dict_find(&collection, argv[idx]); if (entry != NULL) iface = entry->data; if (entry == NULL && allow_undefined) iface = lif_interface_collection_find(&collection, argv[idx]); } if (iface == NULL) { fprintf(stderr, "%s: unknown interface %s\n", argv0, argv[idx]); return EXIT_FAILURE; } if (match_opts.property != NULL) print_interface_property(iface, match_opts.property); else prettyprint_interface_eni(iface); } return EXIT_SUCCESS; } struct if_applet ifquery_applet = { .name = "ifquery", .desc = "query interface configuration", .main = ifquery_main, .usage = "ifquery [options] \n ifquery [options] --list", .manpage = "8 ifquery", .groups = { &global_option_group, &match_option_group, &exec_option_group, &local_option_group }, }; APPLET_REGISTER(ifquery_applet) ifupdown-ng-ifupdown-ng-0.12.1/cmd/ifupdown.c000066400000000000000000000176421422731055100210370ustar00rootroot00000000000000/* * cmd/ifupdown.c * Purpose: bring interfaces up or down * * Copyright (c) 2020 Ariadne Conill * Copyright (c) 2020 Maximilian Wilhelm * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * This software is provided 'as is' and without any warranty, express or * implied. In no event shall the authors be liable for any damages arising * from the use of this software. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include "libifupdown/libifupdown.h" #include "cmd/multicall.h" static bool up; static bool is_ifdown() { if (strstr(argv0, "ifdown") != NULL) return true; return false; } static int acquire_state_lock(const char *state_path, const char *lifname) { if (exec_opts.mock || exec_opts.no_lock) return -1; char lockpath[4096] = {}; snprintf(lockpath, sizeof lockpath, "%s.%s.lock", state_path, lifname); int fd = open(lockpath, O_CREAT | O_WRONLY | O_TRUNC, 0600); if (fd < 0) { if (exec_opts.verbose) fprintf(stderr, "%s: while opening lockfile %s: %s\n", argv0, lockpath, strerror(errno)); return -2; } int flags = fcntl(fd, F_GETFD); if (flags < 0) { close(fd); if (exec_opts.verbose) fprintf(stderr, "%s: while getting flags for lockfile: %s\n", argv0, strerror(errno)); return -2; } flags |= FD_CLOEXEC; if (fcntl(fd, F_SETFD, flags) == -1) { close(fd); if (exec_opts.verbose) fprintf(stderr, "%s: while setting lockfile close-on-exec: %s\n", argv0, strerror(errno)); return -2; } struct flock fl = { .l_type = F_WRLCK, .l_whence = SEEK_SET }; if (exec_opts.verbose) fprintf(stderr, "%s: acquiring lock on %s\n", argv0, lockpath); if (fcntl(fd, F_SETLK, &fl) == -1) { close(fd); if (exec_opts.verbose) fprintf(stderr, "%s: while locking lockfile: %s\n", argv0, strerror(errno)); return -2; } return fd; } static bool skip_interface(struct lif_interface *iface, const char *ifname, struct lif_dict *state, bool update_state) { if (iface->is_template) { fprintf(stderr, "%s: cannot change state on %s (template interface)\n", argv0, ifname); return false; } if (iface->has_config_error) { if (exec_opts.force) { fprintf(stderr, "%s: (de)configuring interface %s despite config errors\n", argv0, ifname); return false; } else { fprintf(stderr, "%s: skipping interface %s due to config errors\n", argv0, ifname); return true; } } if (exec_opts.force) return false; if (up && iface->refcount > 0) { if (exec_opts.verbose) fprintf(stderr, "%s: skipping %sinterface %s (already configured), use --force to force configuration\n", argv0, iface->is_auto ? "auto " : "", ifname); if (update_state) { iface->is_explicit = true; lif_state_upsert(state, ifname, iface); } return true; } if (!up && iface->refcount == 0) { if (exec_opts.verbose) fprintf(stderr, "%s: skipping %sinterface %s (already deconfigured), use --force to force deconfiguration\n", argv0, iface->is_auto ? "auto " : "", ifname); return true; } return false; } static bool change_interface(struct lif_interface *iface, struct lif_dict *collection, struct lif_dict *state, const char *ifname, bool update_state) { int lockfd = acquire_state_lock(exec_opts.state_file, ifname); if (lockfd == -2) { fprintf(stderr, "%s: could not acquire exclusive lock for %s: %s\n", argv0, ifname, strerror(errno)); return false; } if (skip_interface(iface, ifname, state, update_state)) { if (lockfd != -1) close(lockfd); return true; } if (exec_opts.verbose) { fprintf(stderr, "%s: changing state of interface %s to '%s'\n", argv0, ifname, up ? "up" : "down"); } if (!lif_lifecycle_run(&exec_opts, iface, collection, state, ifname, up)) { fprintf(stderr, "%s: failed to change interface %s state to '%s'\n", argv0, ifname, up ? "up" : "down"); if (lockfd != -1) close(lockfd); return false; } if (lockfd != -1) close(lockfd); if (up && update_state) { iface->is_explicit = true; lif_state_upsert(state, ifname, iface); } return true; } static bool change_auto_interfaces(struct lif_dict *collection, struct lif_dict *state, struct match_options *opts) { struct lif_node *iter; LIF_DICT_FOREACH(iter, collection) { struct lif_dict_entry *entry = iter->data; struct lif_interface *iface = entry->data; if (opts->is_auto && !iface->is_auto) continue; if (opts->exclude_pattern != NULL && !fnmatch(opts->exclude_pattern, iface->ifname, 0)) continue; if (opts->include_pattern != NULL && fnmatch(opts->include_pattern, iface->ifname, 0)) continue; if (!change_interface(iface, collection, state, iface->ifname, false)) return false; } return true; } static int update_state_file_and_exit(int rc, struct lif_dict *state) { if (exec_opts.mock) { exit(rc); return rc; } if (!lif_state_write_path(state, exec_opts.state_file)) { fprintf(stderr, "%s: could not update %s\n", argv0, exec_opts.state_file); exit(EXIT_FAILURE); return EXIT_FAILURE; } exit(rc); return rc; } static int ifupdown_main(int argc, char *argv[]) { up = !is_ifdown(); struct lif_dict state = {}; struct lif_dict collection = {}; struct lif_interface_file_parse_state parse_state = { .collection = &collection, }; lif_interface_collection_init(&collection); if (!lif_state_read_path(&state, exec_opts.state_file)) { fprintf(stderr, "%s: could not parse %s\n", argv0, exec_opts.state_file); return EXIT_FAILURE; } if (!lif_interface_file_parse(&parse_state, exec_opts.interfaces_file)) { fprintf(stderr, "%s: could not parse %s\n", argv0, exec_opts.interfaces_file); return EXIT_FAILURE; } if (lif_lifecycle_count_rdepends(&exec_opts, &collection) == -1) { fprintf(stderr, "%s: could not validate dependency tree\n", argv0); return EXIT_FAILURE; } if(!lif_compat_apply(&collection)) { fprintf(stderr, "%s: failed to apply compatibility glue\n", argv0); return EXIT_FAILURE; } if (!lif_state_sync(&state, &collection)) { fprintf(stderr, "%s: could not sync state\n", argv0); return EXIT_FAILURE; } if (match_opts.is_auto) { if (!change_auto_interfaces(&collection, &state, &match_opts)) return update_state_file_and_exit(EXIT_FAILURE, &state); return update_state_file_and_exit(EXIT_SUCCESS, &state); } else if (optind >= argc) generic_usage(self_applet, EXIT_FAILURE); int idx = optind; for (; idx < argc; idx++) { char lifbuf[4096]; strlcpy(lifbuf, argv[idx], sizeof lifbuf); char *ifname = lifbuf; char *lifname = lifbuf; char *p; if ((p = strchr(lifbuf, '=')) != NULL) { *p++ = '\0'; lifname = p; } struct lif_interface *iface = lif_state_lookup(&state, &collection, argv[idx]); if (iface == NULL) { struct lif_dict_entry *entry = lif_dict_find(&collection, lifname); if (entry == NULL) { fprintf(stderr, "%s: unknown interface %s\n", argv0, argv[idx]); return update_state_file_and_exit(EXIT_FAILURE, &state); } iface = entry->data; } if (!change_interface(iface, &collection, &state, ifname, true)) return update_state_file_and_exit(EXIT_FAILURE, &state); } return update_state_file_and_exit(EXIT_SUCCESS, &state); } struct if_applet ifup_applet = { .name = "ifup", .desc = "bring interfaces up", .main = ifupdown_main, .usage = "ifup [options] ", .manpage = "8 ifup", .groups = { &global_option_group, &match_option_group, &exec_option_group, }, }; APPLET_REGISTER(ifup_applet) struct if_applet ifdown_applet = { .name = "ifdown", .desc = "take interfaces down", .main = ifupdown_main, .usage = "ifdown [options] ", .manpage = "8 ifdown", .groups = { &global_option_group, &match_option_group, &exec_option_group, }, }; APPLET_REGISTER(ifdown_applet) ifupdown-ng-ifupdown-ng-0.12.1/cmd/multicall-exec-options.c000066400000000000000000000051351422731055100235770ustar00rootroot00000000000000/* * cmd/multicall-exec-options.c * Purpose: multi-call binary frontend -- option handling * * Copyright (c) 2020 Ariadne Conill * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * This software is provided 'as is' and without any warranty, express or * implied. In no event shall the authors be liable for any damages arising * from the use of this software. */ #define _GNU_SOURCE #include #include #include #include #include #include "cmd/multicall.h" #define DEFAULT_TIMEOUT 300 struct lif_execute_opts exec_opts = { .interfaces_file = INTERFACES_FILE, .executor_path = EXECUTOR_PATH, .state_file = STATE_FILE, .timeout = DEFAULT_TIMEOUT, }; static void set_interfaces_file(const char *opt_arg) { exec_opts.interfaces_file = opt_arg; } static void set_state_file(const char *opt_arg) { exec_opts.state_file = opt_arg; } static void set_no_act(const char *opt_arg) { (void) opt_arg; exec_opts.mock = true; exec_opts.verbose = true; } static void set_verbose(const char *opt_arg) { (void) opt_arg; exec_opts.verbose = true; } static void set_executor_path(const char *opt_arg) { exec_opts.executor_path = opt_arg; } static void set_no_lock(const char *opt_arg) { (void) opt_arg; exec_opts.no_lock = true; } static void set_force(const char *opt_arg) { (void) opt_arg; exec_opts.force = true; } static void set_timeout(const char *opt_arg) { exec_opts.timeout = atoi(opt_arg); if (exec_opts.timeout < 0) exec_opts.timeout = DEFAULT_TIMEOUT; } static struct if_option exec_options[] = { {'f', "force", NULL, "force (de)configuration", false, set_force}, {'i', "interfaces", "interfaces FILE", "use FILE for interface definitions", true, set_interfaces_file}, {'l', "no-lock", NULL, "do not use a lockfile to serialize state changes", false, set_no_lock}, {'n', "no-act", NULL, "do not actually run any commands", false, set_no_act}, {'v', "verbose", NULL, "show what commands are being run", false, set_verbose}, {'E', "executor-path", "executor-path PATH", "use PATH for executor directory", true, set_executor_path}, {'S', "state-file", "state-file FILE", "use FILE for state", true, set_state_file}, {'T', "timeout", "timeout TIMEOUT", "wait TIMEOUT seconds for executors to complete", true, set_timeout}, }; struct if_option_group exec_option_group = { .desc = "Execution", .group_size = ARRAY_SIZE(exec_options), .group = exec_options }; ifupdown-ng-ifupdown-ng-0.12.1/cmd/multicall-match-options.c000066400000000000000000000030331422731055100237420ustar00rootroot00000000000000/* * cmd/multicall-match-options.c * Purpose: multi-call binary frontend -- option handling * * Copyright (c) 2020 Ariadne Conill * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * This software is provided 'as is' and without any warranty, express or * implied. In no event shall the authors be liable for any damages arising * from the use of this software. */ #define _GNU_SOURCE #include #include #include #include #include #include "cmd/multicall.h" struct match_options match_opts = {}; static void set_auto(const char *opt_arg) { (void) opt_arg; match_opts.is_auto = true; } static void set_include_pattern(const char *opt_arg) { match_opts.include_pattern = opt_arg; } static void set_exclude_pattern(const char *opt_arg) { match_opts.exclude_pattern = opt_arg; } static struct if_option match_options[] = { {'a', "auto", NULL, "only match against interfaces hinted as 'auto'", false, set_auto}, {'I', "include", "include PATTERN", "only match against interfaces matching PATTERN", true, set_include_pattern}, {'X', "exclude", "exclude PATTERN", "never match against interfaces matching PATTERN", true, set_exclude_pattern}, }; struct if_option_group match_option_group = { .desc = "Matching interfaces", .group_size = ARRAY_SIZE(match_options), .group = match_options }; ifupdown-ng-ifupdown-ng-0.12.1/cmd/multicall-options.c000066400000000000000000000074511422731055100226600ustar00rootroot00000000000000/* * cmd/multicall-options.c * Purpose: multi-call binary frontend -- option handling * * Copyright (c) 2020 Ariadne Conill * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * This software is provided 'as is' and without any warranty, express or * implied. In no event shall the authors be liable for any damages arising * from the use of this software. */ #define _GNU_SOURCE #include #include #include #include #include #include "cmd/multicall.h" extern const struct if_applet *self_applet; void generic_usage(const struct if_applet *applet, int result) { fprintf(stderr, "%s", applet->name); if (applet->desc != NULL) fprintf(stderr, " - %s", applet->desc); fprintf(stderr, "\n"); if (applet->usage != NULL) fprintf(stderr, "\nUsage:\n %s\n", applet->usage); size_t iter; for (iter = 0; applet->groups[iter] != NULL; iter++) { const struct if_option_group *group = applet->groups[iter]; fprintf(stderr, "\n%s:\n", group->desc); size_t group_iter; for (group_iter = 0; group_iter < group->group_size; group_iter++) { const struct if_option *opt = &group->group[group_iter]; fprintf(stderr, " "); if (opt->short_opt) fprintf(stderr, "-%c", opt->short_opt); else fprintf(stderr, " "); if (opt->long_opt) fprintf(stderr, "%c --%-30s", opt->short_opt ? ',' : ' ', opt->long_opt_desc ? opt->long_opt_desc : opt->long_opt); else fprintf(stderr, "%34s", ""); fprintf(stderr, "%s\n", opt->desc); } } if (applet->manpage != NULL) fprintf(stderr, "\nFor more information: man %s\n", applet->manpage); exit(result); } static void generic_usage_request(const char *opt_arg) { (void) opt_arg; generic_usage(self_applet, EXIT_SUCCESS); } static struct if_option global_options[] = { {'h', "help", NULL, "this help", false, generic_usage_request}, {'V', "version", NULL, "show this program's version", false, (void *) lif_common_version}, }; struct if_option_group global_option_group = { .desc = "Global options", .group_size = ARRAY_SIZE(global_options), .group = global_options }; const struct if_option * lookup_option(const struct if_applet *applet, int opt) { size_t iter; for (iter = 0; applet->groups[iter] != NULL; iter++) { const struct if_option_group *group = applet->groups[iter]; size_t group_iter; for (group_iter = 0; group_iter < group->group_size; group_iter++) { const struct if_option *option = &group->group[group_iter]; if (option->short_opt == opt) return option; } } return NULL; } void process_options(const struct if_applet *applet, int argc, char *argv[]) { char short_opts[256] = {}, *p = short_opts; struct option long_opts[256] = {}; size_t iter, long_opt_iter = 0; for (iter = 0; applet->groups[iter] != NULL; iter++) { const struct if_option_group *group = applet->groups[iter]; size_t group_iter; for (group_iter = 0; group_iter < group->group_size; group_iter++) { const struct if_option *opt = &group->group[group_iter]; if (opt->short_opt) { *p++ = opt->short_opt; if (opt->require_argument) *p++ = ':'; } if (opt->long_opt) { /* XXX: handle long-opts without short-opts */ long_opts[long_opt_iter] = (struct option) { .name = opt->long_opt, .has_arg = opt->require_argument ? required_argument : no_argument, .val = opt->short_opt }; long_opt_iter++; } } } for (;;) { int c = getopt_long(argc, argv, short_opts, long_opts, NULL); if (c == -1) break; const struct if_option *opt = lookup_option(applet, c); if (opt == NULL) break; opt->handle(optarg); } } ifupdown-ng-ifupdown-ng-0.12.1/cmd/multicall.c000066400000000000000000000052301422731055100211600ustar00rootroot00000000000000/* * cmd/multicall.c * Purpose: multi-call binary frontend * * Copyright (c) 2020 Ariadne Conill * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * This software is provided 'as is' and without any warranty, express or * implied. In no event shall the authors be liable for any damages arising * from the use of this software. */ #define _GNU_SOURCE #include #include #include #include #include #include "cmd/multicall.h" char *argv0; struct if_applet ifupdown_applet; const struct if_applet *self_applet = NULL; static struct if_applet **applet_table = NULL; static size_t applet_count = 0; static int applet_cmp(const void *a, const void *b) { const char *key = a; const struct if_applet *applet = *(void **)b; return strcmp(key, applet->name); } static int applet_scmp(const void *a, const void *b) { const struct if_applet *key = *(void **)a; const struct if_applet *applet = *(void **)b; return strcmp(key->name, applet->name); } void applet_register(struct if_applet *applet) { ++applet_count; applet_table = reallocarray(applet_table, applet_count, sizeof (void *)); applet_table[applet_count - 1] = applet; qsort(applet_table, applet_count, sizeof (void *), applet_scmp); } void multicall_usage(int status) __attribute__((noreturn)); struct if_applet ifupdown_applet; int main(int argc, char *argv[]) { argv0 = basename(argv[0]); const struct if_applet **app; lif_config_load(CONFIG_FILE); app = bsearch(argv0, applet_table, applet_count, sizeof (void *), applet_cmp); if (app == NULL) { fprintf(stderr, "%s: applet not found\n", argv0); multicall_usage(EXIT_FAILURE); } self_applet = *app; if (self_applet != &ifupdown_applet) process_options(*app, argc, argv); return self_applet->main(argc, argv); } static int multicall_main(int argc, char *argv[]) { if (argc < 2) multicall_usage(EXIT_FAILURE); return main(argc - 1, argv + 1); } void multicall_usage(int status) { fprintf(stderr, PACKAGE_NAME " " PACKAGE_VERSION "\n" "usage: ifupdown [options]\n" "\n" "Built-in applets:\n"); for (size_t i = 0; i < applet_count; i++) { if (applet_table[i] == &ifupdown_applet) continue; fprintf(stderr, " %-10s %s\n", applet_table[i]->name, applet_table[i]->desc); } exit(status); } struct if_applet ifupdown_applet = { .name = "ifupdown", .main = multicall_main, .groups = { &global_option_group, NULL } }; APPLET_REGISTER(ifupdown_applet) ifupdown-ng-ifupdown-ng-0.12.1/cmd/multicall.h000066400000000000000000000040041422731055100211630ustar00rootroot00000000000000/* * cmd/multicall.h * Purpose: structures for multicall frontend * * Copyright (c) 2020 Ariadne Conill * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * This software is provided 'as is' and without any warranty, express or * implied. In no event shall the authors be liable for any damages arising * from the use of this software. */ #include #ifndef IFUPDOWN_CMD_MULTICALL_H__GUARD #define IFUPDOWN_CMD_MULTICALL_H__GUARD #include "libifupdown/libifupdown.h" struct if_applet; struct if_option { char short_opt; const char *long_opt; const char *long_opt_desc; const char *desc; bool require_argument; void (*const handle)(const char *opt_arg); }; struct if_option_group { const char *desc; size_t group_size; const struct if_option *group; }; struct if_applet { const char *name; const char *desc; const char *usage; const char *manpage; int (*const main)(int argc, char *argv[]); const struct if_option_group *groups[16]; }; extern char *argv0; extern const struct if_applet *self_applet; extern struct if_option_group global_option_group; struct match_options { bool is_auto; const char *exclude_pattern; const char *include_pattern; bool pretty_print; bool dot; const char *property; }; extern struct match_options match_opts; extern void process_options(const struct if_applet *applet, int argc, char *argv[]); extern const struct if_option *lookup_option(const struct if_applet *applet, int opt); extern struct if_option_group match_option_group; extern struct lif_execute_opts exec_opts; extern struct if_option_group exec_option_group; extern void applet_register(struct if_applet *applet); void generic_usage(const struct if_applet *applet, int result); #define APPLET_REGISTER(x) \ __attribute__((constructor)) static void __register_##x(void) { applet_register(&x); } #endif ifupdown-ng-ifupdown-ng-0.12.1/cmd/pretty-print-iface.c000066400000000000000000000027341422731055100227260ustar00rootroot00000000000000/* * cmd/pretty-print-iface.c * Purpose: interface pretty-printer (/e/n/i style) * * Copyright (c) 2020 Ariadne Conill * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * This software is provided 'as is' and without any warranty, express or * implied. In no event shall the authors be liable for any damages arising * from the use of this software. */ #include #include #include "libifupdown/libifupdown.h" #include "cmd/multicall.h" #include "cmd/pretty-print-iface.h" void prettyprint_interface_eni(struct lif_interface *iface) { if (!lif_lifecycle_query_dependents(&exec_opts, iface, iface->ifname)) return; if (iface->is_auto) printf("auto %s\n", iface->ifname); printf("%s %s\n", iface->is_template ? "template" : "iface", iface->ifname); struct lif_node *iter; LIF_DICT_FOREACH(iter, &iface->vars) { struct lif_dict_entry *entry = iter->data; if (!strcmp(entry->key, "address")) { struct lif_address *addr = entry->data; char addr_buf[512]; if (!lif_address_unparse(addr, addr_buf, sizeof addr_buf, true)) { printf(" # warning: failed to unparse address\n"); continue; } printf(" %s %s\n", entry->key, addr_buf); } else printf(" %s %s\n", entry->key, (const char *) entry->data); } printf("\n"); } ifupdown-ng-ifupdown-ng-0.12.1/cmd/pretty-print-iface.h000066400000000000000000000014121422731055100227230ustar00rootroot00000000000000/* * cmd/pretty-print-iface.h * Purpose: interface pretty-printer (/e/n/i style) * * Copyright (c) 2020 Ariadne Conill * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * This software is provided 'as is' and without any warranty, express or * implied. In no event shall the authors be liable for any damages arising * from the use of this software. */ #ifndef IFUPDOWN_CMD_PRETTY_PRINT_IFACE_H__GUARD #define IFUPDOWN_CMD_PRETTY_PRINT_IFACE_H__GUARD #include "libifupdown/libifupdown.h" extern void prettyprint_interface_eni(struct lif_interface *iface); #endif ifupdown-ng-ifupdown-ng-0.12.1/dist/000077500000000000000000000000001422731055100172265ustar00rootroot00000000000000ifupdown-ng-ifupdown-ng-0.12.1/dist/debian/000077500000000000000000000000001422731055100204505ustar00rootroot00000000000000ifupdown-ng-ifupdown-ng-0.12.1/dist/debian/ifupdown-ng.networking.service000066400000000000000000000007151422731055100264600ustar00rootroot00000000000000[Unit] Description=ifupdown-ng networking initialization Documentation=man:interfaces(5) man:ifup(8) man:ifdown(8) [Service] Type=oneshot RemainAfterExit=yes SyslogIdentifier=networking TimeoutStopSec=30s ExecStart=/usr/share/ifupdown-ng/sbin/networking start ExecStop=/usr/share/ifupdown-ng/sbin/networking stop ExecRestart=/usr/share/ifupdown-ng/sbin/networking restart [Install] WantedBy=basic.target network.target multi-user.target network-online.target ifupdown-ng-ifupdown-ng-0.12.1/dist/debian/networking000066400000000000000000000023061422731055100225630ustar00rootroot00000000000000#!/bin/sh # # Wrapper script for networking set up and teardown via unit file # # Thu, 01 Oct 2020 22:47:43 +0200 # -- Maximilian Wilhelm # STATE_DIR="/run/ifsate" # Make sure the state dir is present if [ ! -d "${STATE_DIR}" ]; then mkdir "${STATE_DIR}" fi # Check for require binaries if [ ! -x /sbin/ifup -o ! -x /sbin/ifdown ]; then echo "ifup and/or ifdown not found!" >&2 exit 1 fi # Apply defaults if present (verbose mode, kill switch, etc.) CONFIGURE_INTERFACES=yes if [ -f /etc/default/networking ]; then . /etc/default/networking fi ARGS="" if [ "${VERBOSE}" = yes ]; then ARGS="-v" fi # Let's go case "$1" in start) if [ "${CONFIGURE_INTERFACES}" = no ]; then echo "Not configuring network interfaces, see /etc/default/networking" exit 0 fi ifup -a ${ARGS} ;; stop) if [ "${SKIP_DOWN_AT_SYSRESET}" = "yes" ] && systemctl list-jobs | egrep -q '(shutdown|reboot|halt|poweroff)\.target'; then echo ${NAME}':' "Skipping deconfiguring network interfaces" exit 0 fi ifdown -a ${ARGS} ;; restart) ifupdown_init ifdown -a ${ARGS} ifup -a ${ARGS} ;; # reload missing here! *) echo "Usage: $0 {start|stop|restart}" exit 1 ;; esac exit 0 ifupdown-ng-ifupdown-ng-0.12.1/dist/debian/networking.default000066400000000000000000000007051422731055100242070ustar00rootroot00000000000000# # Defaults for ifupdown-ng networking service # # Change the below to "yes" if you want ifup/ifdown and it's executors to be # verbose about what's going on VERBOSE="no" # Set to "yes" if you want to skip deconfiguring all interfaces during system # reboot and shutdown. This might be of interest in large scale deployments, # where you might not want to wait for interface deconfiguration to speed up # shutdown/reboot. SKIP_DOWN_AT_SYSRESET="yes" ifupdown-ng-ifupdown-ng-0.12.1/dist/ifupdown-ng.conf.example000066400000000000000000000052351422731055100237710ustar00rootroot00000000000000# This is an example configuration file for ifupdown-ng, which allows # the system administrator to configure the behaviour of ifupdown-ng. # # The settings specified here are the defaults of ifupdown-ng. # allow_addon_scripts: # Enable support for /etc/if-X.d addon scripts. These are used for # compatibility with legacy setups, and may be disabled for performance # improvements in setups where only ifupdown-ng executors are used. # Valid values are 0 and 1, the default is 1. allow_addon_scripts = 1 # allow_any_iface_as_template: # Enable any interface to act as a template for another interface. # This is presently the default, but is deprecated. An admin may choose # to disable this setting in order to require inheritance from specified # templates. Valid values are 0 and 1, the default is 1. allow_any_iface_as_template = 1 # auto_executor_selection: # Automatically determine which executors are needed to bring up an # interface. An admin may choose to disable this setting and explicitly # define which executors to use with `use` statements. # Valid values are 0 and 1, the default is 1. auto_executor_selection = 1 # compat_create_interfaces: # Denotes where or not to create interfaces when compat_* settings are # active and it would be necessary to create an interface to be fully # compliant. This could happen when inheriting bridge VLAN settings to # an interface within a bridges bridge-ports setting but no interface # stanza is found. Valid values are 0 and 1, the default is 1. compat_create_interfaces = 1 # compat_ifupdown2_bridge_ports_inherit_vlans: # In ifupdown2 as well as the set on a bridge # interface will be inherited by all member ports if not set explicitly. # When set to 1 ifupdown-ng behaves the same way and will internally copy # both options from the bridge member ports if they are not set on the # member port. Valid values are 0 and 1, the default is 1. compat_ifupdown2_bridge_ports_inherit_vlans = 1 # implicit_template_conversion: # In some legacy configs, a template may be declared as an iface, and # ifupdown-ng automatically converts those declarations to a proper # template. If this setting is disabled, inheritance will continue to # work against non-template interfaces without converting them to a # template. Valid values are 0 and 1, the default is 1. implicit_template_conversion = 1 # use_hostname_for_dhcp: # Automatically learn the hostname property, used for DHCP configuration # by querying the system hostname using uname(2). This is basically # equivalent to `hostname $(hostname)` without having to specify any # configuration. Valid values are 0 and 1, the default is 1. use_hostname_for_dhcp = 1 ifupdown-ng-ifupdown-ng-0.12.1/dist/openrc/000077500000000000000000000000001422731055100205145ustar00rootroot00000000000000ifupdown-ng-ifupdown-ng-0.12.1/dist/openrc/networking.confd000066400000000000000000000003451422731055100237200ustar00rootroot00000000000000# Sets the path used for the interface definitions. #cfgfile="/etc/network/interfaces" # Sets the path used for the state database. #ifstate="/run/ifstate" # Skip taking down networking while shutting down. #keep_network="YES" ifupdown-ng-ifupdown-ng-0.12.1/dist/openrc/networking.initd000066400000000000000000000025221422731055100237350ustar00rootroot00000000000000#!/sbin/openrc-run : ${cfgfile:="/etc/network/interfaces"} ifstate=/run/ifstate single_iface="${RC_SVCNAME#*.}" if [ "$single_iface" = "$RC_SVCNAME" ]; then single_iface= fi depend() { need localmount want dev-settle after bootmisc hwdrivers modules provide net keyword -jail -prefix -vserver -docker } # find interfaces we want to start find_ifaces() { if [ -n "$single_iface" ]; then echo $single_iface else ifquery -L -a -i "$cfgfile" fi } # return the list of interfaces we should try stop find_running_ifaces() { if [ -n "$single_iface" ]; then echo $single_iface else ifquery -r -i "$cfgfile" -S "$ifstate" fi } start() { local iface= ret=1 ebegin "Starting networking" eindent for iface in $(find_ifaces); do local r=0 ebegin "$iface" if ! ifup -i "$cfgfile" -S "$ifstate" $iface >/dev/null; then ifdown -f -i "$cfgfile" -S "$ifstate" $iface >/dev/null 2>&1 r=1 fi # atleast one interface needs to be started for action # to be success eend $r && ret=0 done eoutdent return $ret } stop() { local iface= # Don't stop the network at shutdown. yesno ${keep_network:-YES} && yesno $RC_GOINGDOWN && return 0 ebegin "Stopping networking" eindent for iface in $(find_running_ifaces); do ebegin "$iface" ifdown -i "$cfgfile" -S "$ifstate" -f $iface >/dev/null eend $? done eoutdent return 0 } ifupdown-ng-ifupdown-ng-0.12.1/doc/000077500000000000000000000000001422731055100170305ustar00rootroot00000000000000ifupdown-ng-ifupdown-ng-0.12.1/doc/ADMIN-GUIDE.md000066400000000000000000000176061422731055100210470ustar00rootroot00000000000000# ifupdown-ng for system administrators ifupdown-ng is a network device manager which is backwards compatible with traditional ifup and ifdown as used on Debian and Alpine systems, while solving many design deficits with the original approach through robust error handling and the use of a dependency-solver to determine interface bring-up order. This guide is intended to walk users through using the ifupdown-ng system without any assumption of familiarity with the legacy ifupdown system. ## Important Filesystem Paths The ifupdown-ng system uses the following paths, ranked in order of importance: * `/etc/network/interfaces`: the interface configuration database, which contains information about what interfaces should be configured. * `/etc/network/ifupdown-ng.conf`: the main configuration file which controls ifupdown-ng's behaviour. See the *ifupdown-ng Configuration* section below. * `/run/ifstate`: the interface state file, which denotes what physical interfaces are configured, and what interface definition they are configured as. * `/usr/libexec/ifupdown-ng`: this directory contains the native ifupdown-ng executors, which are run as necessary to configure an interface. See the ifupdown-executor(7) manual page for more information on how these programs are written. * `/etc/network/if-{up|down|pre-up|post-down}.d`: these directories contain scripts that are run when an interface is brought up or down. In general, they follow the same contract described in ifupdown-executor(7). All configuration examples in this guide concern the `/etc/network/interfaces` file. ## ifupdown-ng Configuration ifupdown-ng allows to configure some parts of it's behaviour. Currently the following settings are supported in `/etc/network/ifupdown-ng.conf`: * `allow_addon_scripts`: Enable support for /etc/if-X.d addon scripts. These are used for compatibility with legacy setups, and may be disabled for performance improvements in setups where only ifupdown-ng executors are used. Valid values are `0` and `1`, default is `1`. * `allow_any_iface_as_template`: Enable any interface to act as a template for another interface. This is presently the default, but is deprecated. An admin may choose to disable this setting in order to require inheritance from specified templates. Valid values are `0` and `1`, the default is `1`. * `auto_executor_selection`: Automatically select executors based on the presence of their config options. An admin may choose to disable this setting in order to require explicitly enabling executors through `use` statements. Valid values are `0` and `1`, the default is `1`. * `compat_create_interfaces`: Denotes where or not to create interfaces when compat\_* settings are active and it would be necessary to create an interface to be fully compliant. This could happen when inheriting bridge VLAN settings to an interface within a bridges bridge-ports setting but no interface stanza is found. Valid values are `0` and `1`, the default is `1`. * `compat_ifupdown2_bridge_ports_inherit_vlans`: In ifupdown2 `bridge-vids` as well as the set on a bridge interface will be inherited by all member ports if not set explicitly. When set to `1` ifupdown-ng behaves the same way and will internally copy both options from the bridge member ports if they are not set on the member port. Valid values are `0` and `1`, the default is `1`. * `implicit_template_conversion`: In some legacy configs, a template may be declared as an iface, and ifupdown-ng automatically converts those declarations to a proper template. If this setting is disabled, inheritance will continue to work against non-template interfaces without converting them to a template. Valid values are `0` and `1`, the default is `1`. * `use_hostname_for_dhcp`: A common configuration pattern with DHCP interfaces is to use `hostname $(hostname)`. If this setting is enabled, the `hostname` property will default to the system hostname. Valid values are `0` and `1`, the default is `1`. ## Interface Configuration ### Basic Configuration To begin with, lets look at a basic configuration for a desktop computer. This scenario involves using the DHCP helper to learn an IPv4 address dynamically. In this case, the `/etc/network/interfaces` file would look like: ``` auto eth0 iface eth0 use dhcp ``` These configuration statements do two things: designate that `eth0` should be started automatically with the `auto` keyword, and designate that the `dhcp` executor should be used to configure the interface. As a more detailed explanation, here is a commented version: ``` # Start eth0 automatically. auto eth0 # Begin an interface definition for eth0. iface eth0 # Use the dhcp executor to configure eth0. use dhcp ``` ### IPv6 RA Configuration With IPv6, stateless auto-configuration is typically used to configure network interfaces. If you are not interested in using IPv4 at all, you can simply use the `ipv6-ra` executor to ensure that an interface is configured to accept IPv6 RA advertisements: ``` auto eth0 iface eth0 use ipv6-ra ``` ### Static Configuration We can use the `static` executor to configure static IPv4 and IPv6 addresses. If you use the `address` keyword, the `static` executor will automatically be used to configure the interface: ``` auto eth0 iface eth0 address 203.0.113.2/24 gateway 203.0.113.1 ``` #### Multiple Addresses A typical scenario on servers is where a server has multiple IP addresses on a single interface. In this case you simply add additional `address` lines like this: ``` auto eth0 iface eth0 address 203.0.113.2/24 address 203.0.113.3/24 address 203.0.113.4/24 gateway 203.0.113.1 ``` #### Dual-stack configurations Another typical scenario for servers is to run a dual-stack configuration, where interfaces have both an IPv4 and an IPv6 address. This is accomplished in a similar way as multi-homing. You specify the IPv4 and IPv6 addresses you want, followed by gateways for each: ``` auto eth0 iface eth0 address 203.0.113.2/24 address 203.0.113.3/24 address 203.0.113.4/24 gateway 203.0.113.1 address 2001:db8:1000:2::2/64 address 2001:db8:1000:2::3/64 address 2001:db8:1000:2::4/64 gateway 2001:db8:1000:2::1 ``` ## Relationships As previously mentioned, ifupdown-ng features a dependency resolver that allows for determining the interface configuration order. ![Dependency resolution example](img/dependency-resolution.png) In order to make use of this, dependencies can be managed in one of two ways: ### Explicit dependency management using `requires` The `requires` keyword can be used to manage explicit dependencies: ``` auto eth0 iface eth0 use dhcp auto gre0 iface gre0 requires eth0 use gre gre-endpoint 203.0.113.2 gre-ttl 255 gre-flags ignore-df address 203.0.113.194/30 gateway 203.0.113.193 ``` ### Implicit dependency management using executors Executors can declare implicit dependencies which work the same way as explicit dependencies, but are learned at run-time, for example: ``` auto bond0 iface bond0 use bond bond-members eth0 eth1 [...] ``` Is with respect to dependency equivalent to: ``` auto bond0 iface bond0 use bond requires eth0 eth1 [...] ``` ## Executors The ifupdown-ng system is expanded with additional features via executors. Executors are selected on a per-interface basis using `use` statements, for example: ``` auto eth0 iface eth0 use dhcp ``` Executors are run in the order specified by the `use` statements. Some executors are automatically added based on other statements in an interface definition. To see the full list of executors used for an interface, use the ifquery(8) command. ## Questions If you have further questions about how to use ifupdown-ng to configure a specific scenario, drop by the [ifupdown-ng IRC channel](irc://irc.oftc.net/#ifupdown-ng). ifupdown-ng-ifupdown-ng-0.12.1/doc/ifctrstat.scd000066400000000000000000000012441422731055100215270ustar00rootroot00000000000000ifctrstat(8) # NAME ifctrstat - display interface statistics # SYNOPSIS *ifctrstat* [<_options_>...] <_interface_> <_counter_> *ifctrstat* [<_options_>...] -L|--list # DESCRIPTION *ifctrstat* is used to query interface statistic counters in a kernel-agnostic way. This is useful for heterogenous environments where multiple kernels may be in use. # OPTIONS *-h, --help* Display supported options to ifctrstat. *-n, --no-label* Display the requested counter without its label. *-L, --list* List available counters on this system. *-V, --version* Print the ifupdown-ng version and exit. # SEE ALSO *ifquery*(8) # AUTHORS A. Wilcox ifupdown-ng-ifupdown-ng-0.12.1/doc/ifdown.scd000066400000000000000000000025271422731055100210170ustar00rootroot00000000000000ifdown(8) # NAME ifdown - take interfaces down # SYNOPSIS ifdown [<_options_>...] <_interfaces_> # DESCRIPTION *ifdown* is used to deconfigure interfaces according to how they are configured in the configuration database. # OPTIONS *-a, --auto* Only match interfaces that are marked as _auto_. *-f, --force* Force deconfiguration of the interface. This option exists for compatibility with other implementations. *-h, --help* Display supported options to ifquery. *-i, --interfaces* _FILE_ Use _FILE_ as the config database. *-n, --no-act* Show what commands would be run instead of actually running them. Useful for testing configuration changes. *-v, --verbose* Show what commands are being run as they are executed. *-E, --executor-path* _PATH_ Look for executors in the given _PATH_. *-I, --include* _PATTERN_ Include _PATTERN_ when matching against the config or state database. *-S, --state-file* _FILE_ Use _FILE_ as the state database. *-T, --timeout* _TIMEOUT_ Wait up to _TIMEOUT_ seconds for executors to complete before raising an error. *-V, --version* Print the ifupdown-ng version and exit. *-X, --exclude* _PATTERN_ Exclude _PATTERN_ when matching against the config or state database. # SEE ALSO *ifupdown-ng.conf*(5) *ifup*(8) *ifquery*(8) *interfaces*(5) # AUTHORS Ariadne Conill ifupdown-ng-ifupdown-ng-0.12.1/doc/ifparse.scd000066400000000000000000000025661422731055100211650ustar00rootroot00000000000000ifparse(8) # NAME ifparse - redisplay interface configuration in different formats # SYNOPSIS *ifparse* [<_options_>...] <_interfaces_...> *ifparse* -A|--all # DESCRIPTION *ifparse* is used to extract information from the interface configuration file. It is intended to be used to translate the interface configuration stanzas between different formats. # OPTIONS *-a, --auto* Only match interfaces that are marked as _auto_. *-h, --help* Display supported options to ifquery. *-i, --interfaces* _FILE_ Use _FILE_ as the config database. *-F, --format* _FORMAT_ Use _FORMAT_ to determine what format to use. *ifupdown* and *yaml-raw* formats are available. *-I, --include* _PATTERN_ Include _PATTERN_ when matching against the config or state database. *-U, --allow-undefined* Create virtual interfaces for any interfaces not explicitly defined in the configuration file. This is primarily useful for property queries. *-S, --state-file* _FILE_ Use _FILE_ as the state database. *-T, --timeout* _TIMEOUT_ Wait up to _TIMEOUT_ seconds for executors to complete before raising an error. *-V, --version* Print the ifupdown-ng version and exit. *-X, --exclude* _PATTERN_ Exclude _PATTERN_ when matching against the config or state database. # SEE ALSO *ifup*(8)++ *ifdown*(8)++ *ifquery*(8)++ *interfaces*(5) # AUTHORS Ariadne Conill ifupdown-ng-ifupdown-ng-0.12.1/doc/ifquery.scd000066400000000000000000000034631422731055100212150ustar00rootroot00000000000000ifquery(8) # NAME ifquery - query interface configuration and state # SYNOPSIS *ifquery* [<_options_>...] <_interfaces_...> *ifquery* -L|--list *ifquery* -s|--state # DESCRIPTION *ifquery* is used to extract information from the interface configuration file. It can also be used to convert from old versions of the interface configuration file to the current format. # OPTIONS *-a, --auto* Only match interfaces that are marked as _auto_. *-h, --help* Display supported options to ifquery. *-i, --interfaces* _FILE_ Use _FILE_ as the config database. *-p, --property* _PROPERTY_ Print the values of matching properties for an interface. *-r, --running* Print the interface names that are marked as running in the state database. *-s, --state* Query the state database instead of the config database. *-D, --dot* Generate a dependency graph that can be used with GraphViz *dot*(1). Used with *--list*. *-I, --include* _PATTERN_ Include _PATTERN_ when matching against the config or state database. *-L, --list* List interfaces which exist in the configuration database. *-P, --pretty-print* When listing interfaces, print their configuration in a format that is compatible with *interfaces*(5) files. *-U, --allow-undefined* Create virtual interfaces for any interfaces not explicitly defined in the configuration file. This is primarily useful for property queries. *-S, --state-file* _FILE_ Use _FILE_ as the state database. *-T, --timeout* _TIMEOUT_ Wait up to _TIMEOUT_ seconds for executors to complete before raising an error. *-V, --version* Print the ifupdown-ng version and exit. *-X, --exclude* _PATTERN_ Exclude _PATTERN_ when matching against the config or state database. # SEE ALSO *ifup*(8)++ *ifdown*(8)++ *interfaces*(5) # AUTHORS Ariadne Conill ifupdown-ng-ifupdown-ng-0.12.1/doc/ifstate.scd000066400000000000000000000025401422731055100211630ustar00rootroot00000000000000ifstate(5) # NAME */run/ifstate* - interface state database # DESCRIPTION The */run/ifstate* file describes the present state of the interface configuration -- namely, how many interfaces are up, how many dependencies each interface has which are up (the refcount), and whether or not an interface was explicitly brought up due to request or configuration. # FILE SYNTAX At a minimum, the */run/ifstate* file contains at least one column, the physical to logical interface mapping. This column is formatted as such: ``` lo=lo eth0=eth0 wlan0=work ``` The left side of the mapping is the physical interface, while the right side is the logical interface. This field is required to be present. The next field is the reference count. This is a number that reflects the number of *active* dependencies an interface has. As interfaces are brought up and down, the refcount may change. This field is optional. The final field denotes whether or not an interface was brought up explicitly -- either by being marked as _auto_ or brought up manually using *ifup*(8). The contents of this field if present is the _explicit_ keyword. # EXAMPLES An example from a typical system with localhost, eth0 and a wireguard VPN: ``` lo=lo 1 explicit eth0=eth0 2 explicit wg0=wg0 1 explicit ``` # SEE ALSO *interfaces*(5) # AUTHORS Ariadne Conill ifupdown-ng-ifupdown-ng-0.12.1/doc/ifup.scd000066400000000000000000000026201422731055100204660ustar00rootroot00000000000000ifup(8) # NAME ifup - bring interfaces up # SYNOPSIS ifup [<_options_>...] <_interfaces_> # DESCRIPTION *ifup* is used to configure interfaces according to how they are configured in the configuration database. # OPTIONS *-a, --auto* Only match interfaces that are marked as _auto_. *-f, --force* Force configuration of the interface. This option exists for compatibility with other implementations. *-h, --help* Display supported options to ifquery. *-i, --interfaces* _FILE_ Use _FILE_ as the config database. *-n, --no-act* Show what commands would be run instead of actually running them. Useful for testing configuration changes. *-v, --verbose* Show what commands are being run as they are executed. *-E, --executor-path* _PATH_ Look for executors in the given _PATH_. *-I, --include* _PATTERN_ Include _PATTERN_ when matching against the config or state database. *-L, --no-lock* Do not use a lockfile to serialize state changes. *-S, --state-file* _FILE_ Use _FILE_ as the state database. *-T, --timeout* _TIMEOUT_ Wait up to _TIMEOUT_ seconds for executors to complete before raising an error. *-V, --version* Print the ifupdown-ng version and exit. *-X, --exclude* _PATTERN_ Exclude _PATTERN_ when matching against the config or state database. # SEE ALSO *ifupdown-ng.conf*(5) *ifdown*(8) *ifquery*(8) *interfaces*(5) # AUTHORS Ariadne Conill ifupdown-ng-ifupdown-ng-0.12.1/doc/ifupdown-executor.scd000066400000000000000000000043571422731055100232230ustar00rootroot00000000000000ifupdown-executor(7) # NAME */usr/libexec/ifupdown-ng/program* - ifupdown executor protocol # DESCRIPTION The ifupdown executors are programs that are typically installed into the ifupdown-ng executor path. They follow a specific protocol documented in this man page. # PHASES Executors are run to react to nine different phases and are not required to take any specific action. These phases are: *depend* Called to determine if the executor wishes to change the dependency graph. The executor should write a space-delimited list of interface names it is dependent upon to _stdout_. Those interface names will be merged into the dependency graph. If an executor does not have any dependencies, it may simply exit 0 without doing anything. *create* Called before *pre-up*, to explicitly allow for interface creation if necessary. *pre-up* Called before the interface is going to be brought up. *up* Called when the interface is being brought up. *post-up* Called after the interface was successfully brought up. *pre-down* Called before the interface is going to be taken down. *down* Called when the interface is being taken down. *post-down* Called after the interface was successfully taken down. *destroy* Called after *post-down* to allow for explicitly destroying an interface if necessary. # ENVIRONMENT Executors are guaranteed to run with a core set of environment variables: *IFACE* The name of the interface being configured. *INTERFACES_FILE* The path to the interfaces database file being used. *MODE* Either _start_, _stop_ or _depend_ depending on phase. This environment variable is present for compatibility with legacy ifupdown scripts and should not be used in ifupdown-ng executors. *PHASE* The phase being executed. See the phases section for more information about phases. *VERBOSE* If present, verbose output is expected from the executor. Additionally, the properties associated with an interface are provided to executors. The keys are rewritten to begin with IF_ and are capitalized with dashes converted to underscores. For example, the property _bridge-ports_ will be rewritten as _IF_BRIDGE_PORTS_. # SEE ALSO ifup(8)++ ifdown(8)++ interfaces(5) # AUTHORS Ariadne Conill ifupdown-ng-ifupdown-ng-0.12.1/doc/ifupdown-ng.conf.scd000066400000000000000000000053431422731055100227110ustar00rootroot00000000000000ifupdown-ng.conf(5) # NAME *ifupdown-ng.conf* - Global configuration file for ifupdown-ng # DESCRIPTION ifupdown-ng allows to configure some parts of it's behaviour via global configuration options. # GENERAL CONFIGURATION OPTIONS *allow_addon_scripts* _bool_ Enable support for /etc/if-X.d addon scripts. These are used for compatibility with legacy setups, and may be disabled for performance improvements in setups where only ifupdown-ng executors are used. Valid values are _0_ and _1_, the default is _1_. *auto_executor_selection* _bool_ Automatically determine which executors to use. At present, this is done by inserting `use` statements for the namespace a config option has. The namespace is separated from the config option with a dash (`-`). Valid values are _0_ and _1_, the default is _1_. *use_hostname_for_dhcp* _bool_ Automatically learn the hostname property, used for DHCP configuration by querying the system hostname using uname(2). This is basically equivalent to `hostname $(hostname)` without having to specify any configuration. Valid values are _0_ and _1_, the default is _1_. # TEMPLATE RELATED OPTIONS *allow_any_iface_as_template* _bool_ Enable any interface to act as a template for another interface. This is presently the default, but is deprecated. An admin may choose to disable this setting in order to require inheritance from specified templates. Valid values are _0_ and _1_, the default is _1_. *implicit_template_conversion* _bool_ In some legacy configs, a template may be declared as an iface, and ifupdown-ng automatically converts those declarations to a proper template. If this setting is disabled, inheritance will continue to work against non-template interfaces without converting them to a template. Valid values are _0_ and _1_, the default is _1_. # COMPATIBILITY RELATED OPTIONS *compat_create_interfaces* _bool_ Denotes where or not to create interfaces when compat_\* settings are active and it would be necessary to create an interface to be fully compliant. This could happen when inheriting bridge VLAN settings to an interface within a bridges bridge-ports setting but no interface stanza is found. Valid values are _0_ and _1_, the default is _1_. compat_ifupdown2_bridge_ports_inherit_vlans _bool_ In ifupdown2 as well as the set on a bridge interface will be inherited by all member ports if not set explicitly. When set to 1 ifupdown-ng behaves the same way and will internally copy both options from the bridge member ports if they are not set on the member port. Valid values are _0_ and _1_, the default is _1_. # FILES /etc/network/ifupdown-ng.conf # SEE ALSO *interfaces*(5) # AUTHORS Maximilian Wilhelm ifupdown-ng-ifupdown-ng-0.12.1/doc/img/000077500000000000000000000000001422731055100176045ustar00rootroot00000000000000ifupdown-ng-ifupdown-ng-0.12.1/doc/img/dependency-resolution.png000066400000000000000000000250161422731055100246350ustar00rootroot00000000000000PNG  IHDR!bKGD IDATxyXS׺ !!ABRqBlӣږckk 8Tu: *`hd%L IT$;ٟyL͗^{w cG_f y8m\BբŨVRF-$ R)н{wr%s A}}=qudff"++ wAII Zmcccwww"008p ! xDfNåKp1;wPT&EWWWrBC$* @AA ldee͛Pڵ+ W^yQQQd;>O!-- ;wġCPPP޽{cĈ>|8wi4OHIIArr2Q]]`L2s΅^@<-P*qF߿?ЪUFעR`ҥ D"4iFb$fRI_|) iӦɓ'ٖՌJD5j 0`%&&Nc[YҦMŅhʕT^^ζAQQQ$hȐ!te%m挌 )<<233ٖt:ڱc) 򢴴4%噹FMǙ6gii)7D"ű- ,̹@lgt:JHH +++Zx1i4%DyW^yθpz$#tRx{{c̙(--ݻ!Yl 1f!%%F~'ĉ8v.\b7s]]Ǝ XGɉmIFaذaطov؁UV-814-"gggwRXa$ ٳlK14~<|0 ڿ?RXeԩ~D4RСCm9RYY ___̛7qqql1ܝi&O>a[ 8;;?W_}-`p:֭ŋaв.øKE-C,\ݺuƍٖb08iSN!77oRLXl߾l14={???񿱯b;gF57XLL JJJpY4ɶ6f$m{P^8|/zyy/ 8g沲2ܹs!!!F+. X~/cÙmov!t7/$"D\>o nۂ@y… / 8gk2Ok*=_, Ju?OZHVᵗ6o8TW\k߾}q=3sYYheA0W^u+ZSkZ kuqqAyyaΙUKR:ҵH'T^l,~J r*P̯ƀ*d2jkk ^p^Ƣlqϧ/"!ACJSUz f{Z*9Isfnj^Ȍy6̖w->cVuu-ˀbIiiQ`Ƅsfӧlllp5|l~#vNg A+"~# ;@ѽө0֫WF)prQhh(^xlڴm)&K.裏{-GpsQDD9LI -TTT`ȑlK14sLL qI[nȶI3{{{#<<֭c[߿o&R 'sK>|8N8ѣG-ubbbp9/H$l1Niwʕ+1 Sŋ 1sL n9//AAA={6֯_϶VǏs9#?7{3Maݻm9FG!::J۶m㲑X&3fK.] ""mIFwűc?յvfVKf"{{{:s r Ne˖%%%-Xp;oj1cI$ڽ{7r J3gX,;w-ǘXzҥ$hVٖWݻG`RKX 2s[n%;;;:t(-G/۷) w43Qvv6T*իWSCCےw -Xؖkf"G2|||hǎf/_NR-!1b{XˣhDK~-׳-Urss> LFݺuuqf~۷oӼyH,\.%KDSVӑ#Gh„ deeE 㩶mio(**kR^ъ+(==h͐j:tEGG\.'@@H*( :iii8pp}8::",, aaa8p ;F۷/vt:BBB0ydL<={υqn47HNNFJJ RSSQPP۷/ <<<Э[78::B"JJCqq1rssq-jD"ÇGxx8-5~q dee!''EEEGqq1RPScF?damm {{{888GP(pwwձƀ7ILO(n,x3p<73gx3p<73gx3p<73gx3p<73gx3p<73gx3p<73gx3p<73gx3p<73g-KS*߿/ln\}\7qsj +m-?ϘaM3sv98z, zڶ @p0Ы4Y KZY17laj_7K7hˬVVNalt""9sRl f~r!K8=of1q"`mH89f6 25l@f4R): ر)SC~lQ())Aqq1@D2Μ%:D"uWNEEE|2l塴G M-puuE>}Я_?"00 Ɵ};@EE;3g 55o߆@ W ===WWWt r`gg* j(..ƃPTT[n5QTVVB,cРA Ø1cQ{xx3EYYvڅ :t(1l0޾ChIqy"99 1n8L6 *oiӧiƌ$HfΜI{'''(<|^z%@_Rd[Z O?%OOO 4m4f[ٳD&NHlKjZM۶m#??? Mlb5h^}UqےVK{졞={=}ȶ,L3'&&\.':rr:M]]}G$JiСö$6,3SLL EQmm-ےJvv6dooOwf[3QXX999Çٖc0hɒ%$hդؖd,-2??#GZFZZٖd0$ ֭[???Ŗ-[ hk༙KKK kkk$''CP-(,\nnn:u*R)֯_϶$i3cرPHII#71aܹ3f̀+VX$vCǐ,\Ν;lKaB!>}m)'@@}RLiӦBRDN4"##uV>D~0ydlذm9`'gÇXv-RLGGG|qMΙ_~%bcc;52TGeOni97o|}}`2؄sfP]]7xm)&P(… gTWW-Gp̻v¸qƶAjorQzMcǵÜ9sjqA=4-8efV43m)ꚑX ;AYx=FN Ҵoܸ_*o˜ސ26oަ'  ]>}d*՜ovo7 jh_؊5G7oo(KWN,FXJ ¿ق0oH<m ʯaÆ!5519'III:}7vdmۏ'JI?n!++_u"V݊z);\Ķ8^%Nx@utf$z-ގwV=Ti .k&M5-4yKE4)׶m6yL n4oA/zCaG/jbv4l-+M&"/;H臊sy!Й+E~{4o7e-(Qwڎ=JLnZX'IT3^&\GڋtAJk@(rKm6L;J;B+f&wɀ}_i@r=|6,dN˔QYY K->j ˂A*?ֻPy,=IJ`hUUO\ER?:Hpң2[l7xeee͹=ܥKjfA6;['̌3  ?bt'ϡH3i,ƋG-k |,:s ݫ8\WFFFsy{{#::}RLkOؖO7hԨQHJJb[ɒ7o"22m)zsf?>~g\|m)&ɖ-[#F-EpCEPPٖbra۶mXp!mip|طo'tUVA"`lK1{l"22eeex"$˸NFFBBByf̟?m9srrs⫯b[<|?&؛фlق7bǎla F9s栮;vઑp \ND׮o}(0x3cI!CZ _ϮS7s\_xm5 oVj> b[ _ʌY}-̭kj&e34Z``Ϗm5-y}HH`[i›|-p.l+y;; +m5oPlifVbzf~oaj+V6667y3Ƕӂ; @>L/`[QьyoiP^δIM/}jkkcs@桕_~z2t++mc/l1 ,f~x`j<Z-3;(yc5uNǼ.67{2,++Z96ִ0p ЫpjXŲk>cCJX 8x{mXl̵lψ1,f^l+V19=,ypf=𗿰F5D̚`-XL&$Kjfg dX^ͼz5Ƽ"k.?cQ5d4VR5@FƓK3.ɨ] \x{v4Ne``&!wYY=L3  `}\ɼDf Ɍ'Όn4Eb)k4-'t)|&1нzPpp 3v!) 8y-g0{a!ϤM b wPp̿46>.09skT ,+*b{Y!f6+nnFݻ1-eHZa0%;BE8gfQM&O7&c`eږɞ_c#᜙1k[DSW\"$xprjdžӬ8gBE"-yd5]\k 'ڏ(2}1T/nvsk=*58g;w|+2)vn^^Lw֯=3[LƟ&B`"^-x>3t:ښ)333"XEю;HP-]ʳFMǙ6gii)7D"ű-Mɳ977ìۙm(!!hŤhؖ>Of}6SϮԌHJJ"TJSNF137 2~+ߡoZ "???*--J3ѣdmmM}kw8yѢEL8sd$ ٳǿ>L߯7qԩSx> fVTԻwo5kՙԵkWV&Gt0myݺu$J)77W̐דn|[ҁnfVKtRé{Pѫ YՠR(3'@[x)-.b`h|<$f޳gBBBgP\CjorQz 5 8?@ @ Jj eǿU3?oe۪31c{9^^^Ajj8ݷADuAi/O wAHHAiUXxx/Sj߿ 5aD8x||\U~D [5\m}~lA $ݶ?Łz Ņ ~&1c+ʕ+޽kC3C̯ ڷz,ٺF7O[Ž]"čXGg6N"ki_5$1RM(ֻ5k֐ۄq*~OAt7?XVVpLi.Ю3< PPc{@$"/X *hU7U{,n5\mol'f3fT yd$?Z#!yShe=Z?CL&Cmmۄ<-OJ @( ſLv@u6)o-@oPW!aB X.JKK hoL'ܧOڵkeDw {C*sǔşWV8Z1霦~́HiiN:|p=zaT!yyy$J믿6Jy|[ҁmd@'N0:3c޼yԳgOj0tߒӦ&L@Tƅ ʊvir3t0O7snn.9;;_3#J%Ӈƌc|)޽{7 ڳg Z&OL XǿX%KD"SNu^xbVuP;ffVKf"{{{:sL:-[FVVVĶ>j5͘1$ ޽T*fΜIb|O<[PVKK.%@@˗/'ZlJM{Qhh(988 M*ϗl|֭dggGC9ɱo>rvvOǿUl "TJW6}s]?~< P]]ے:'ܚ&jH&رtEII -_R)3o~NˣhDK~ɾͥ>d2u֍֭[gmO>Du#XLr,YbOZMG &) Z ~DQQ]zEϏVXAF VWWӡC(::r9 DRTFD鐖 )) ߇#"00)k4ܾ}x"Ο?k׮A!$$'OɓѳgO\`a7B$33HIIAjj* fr}BuGGGH$B"@TB@Tyyy(..Fnn.nݺZ H~aGxx8\]]uy&o\3rܸqYYYAQQQ\\jT*BVC&ppp@=P(???1;8vãG:x3p}l?-B IENDB`ifupdown-ng-ifupdown-ng-0.12.1/doc/interfaces-batman.scd000066400000000000000000000046621422731055100231160ustar00rootroot00000000000000interfaces-batman(5) # NAME *interfaces-batman* - B.A.T.M.A.N. adv. extensions for the interfaces(5) file format # DESCRIPTION Better Approach To Mobile Ad-Hoc Networking (B.A.T.M.A.N.) advanced is a mesh protocol which provides an Ethernet overlay network over an Ethernet underlay. The overlay interface is called _meshif_ whereas underlay interfaces are called _hardif_. It's supported in the Linux kernel and thus available in many Linux environments. The ifupdown-ng exectuor relies on the *batctl* tool being installed. Support for setting interface based hop-penalties required Linux Kernel 5.8 or later. B.A.T.M.A.N. adv. adds 30-60 bytes of encapsulation overhead depending on wether netword coding is activated or not. This should be taken into consideration when setting up overlay networks, particularly on underlay networks with a conventional 1500 byte MTU. See https://www.open-mesh.org/projects/open-mesh/wiki for more details and updates. The following options allow to set up B.A.T.M.A.N. adv. interfaces. # BATMAN-RELATED OPTIONS *batman-ifaces* _list of interfaces_ Specifies the underlay interfaces (hardifs) which should be configured for the B.A.T.M.A.N. adv. meshif defined within the iface stanza. *batman-hop-penalty* _hop-penalty_ The _hop-penalty_ defines the cost of traversing a node or an interface. The _hop-penalty_ is a numeric value between 0 and 255. Historically a _hop-penalty_ could only be set on a meshif, since B.A.T.M.A.N adv. v2020.3 (included in Kernel 5.8) it can also be set on a per-interfaces (hardif) basis. *batman-gw-mode* _gw-mode_ Denotes the gateway mode which controls the role this node will play within this B.A.T.M.A.N. adv. instance. The mode can be _off_, _client_, or _server_. *batman-distributed-arp-table* _mode_ Activates or deactivates the Distributed ARP table (DAT) within this B.A.T.M.A.N. adv. instance. Valid values are _enable_ and _disable_. *batman-multicast-mode* _mode_ Activates or deactivates the multicast mode of this B.A.T.M.A.N. adv. instance. Valid values are _enable_ and _disable_. # EXAMPLES A B.A.T.M.A.N. adv. _meshif_: ``` auto bat-pad-cty iface bat-pad-cty batman-ifaces dummy-pad-cty vlan1234 batman-hop-penalty 5 # hwaddress f2:00:c1:01:00:00 mtu 1500 ``` A B.A.T.M.A.N. adv. member interfaces (_hardif_): ``` auto vlan1234 iface vlan1234 mtu 1560 batman-hop-penalty 10 ``` # SEE ALSO *batctl*(8) # AUTHORS Maximilian Wilhelm ifupdown-ng-ifupdown-ng-0.12.1/doc/interfaces-bond.scd000066400000000000000000000160301422731055100225660ustar00rootroot00000000000000interfaces-bond(5) # NAME *interfaces-bond* - Bonding/LAG extensions for the interfaces(5) file format # DESCRIPTION The Linux implementation for Ling Aggregation Groups (LAGs) is called _bonding_, whereas a LAG interface is called _bond_. The Linux bonding implementation supports active/passive setups, classical EtherChannels as well as LACP (802.3ad). The following options set up bonding/LAG interfaces with ifupdown-ng. See https://www.kernel.org/doc/Documentation/networking/bonding.rst and for more information. # BOND-RELATED OPTIONS A bond interface must have at least one member port set. All other options are optional. *bond-members* _list of interfaces_ Denotes the physical member interfaces to form this LAG. For compatiblity to ifupdown1 and ifupdown2 _slaves_ as well as _bond-slaves_ are an alias for this option. This option is required. *bond-mode* _mode_ Denotes the mode for this LAG. The _mode_ can be given as string or as numerical value. Valid values are _balance-rr_ (0), _active-backup_ (1), _balance-xor_ (2), _broadcast_ (3), _802.3ad_ (4), _balance-tlb_ (5), _balance-alb_ (6). The default is _balance-rr_. *bond-xmit-hash-policy* _policy_ Denotes the hash policy/algorithm used to distribute packets across the physical links. This only applies for modes _balance-alb_, _balance-tlb_, _balance-xor_, and _802.3ad_. The _policy_ can be given as string or as numerical value. Valid values are _layer2_ (0), _layer3+4_ (1), _layer2+3_ (2), _encap2+3_ (3), and _encap3+4_ (4). The default is _layer2_. *bond-min-links* _number_ Denotes the minimum number of available links before turning on carrier. *bond-miimon* _interval_ Denotes the MII link monitoring frequency in milliseconds. This determines how often the link state of each slave is inspected for link failures. A value of zero disables MII link monitoring. The default is 0. *bond-use-carrier* _bool_ Denotes wether miimon uses MII or ethtool ioctls vs. the netif_carrier_ok() call to determine member link status. A value of 1 enables the use of netif_carrier_ok(), a value of 0 will use the deprecated MII / ETHTOOL ioctls. The default is 1. *bond-updelay* _delay_ Denotes the delay in milliseconds before considering link up, in milliseconds. The default is 0. *bond-downdelay* _delay_ Denotes the delay in milliseconds before considering link down, in milliseconds. The default is 0. *bond-all-slaves-active* _bool_ Denotes wether duplicate frames (received on inactive ports) should be dropped (0) or delivered (1). The default is 0. *bond-packets-per-slave* _num_packets_ Denotes the number of packets to transmit through a member before moving to the next one. When set to 0 then a slave is chosen at random. The valid range is 0 - 65535; the default value is 1. This option has effect only in balance-rr mode. *bond-lp-interval* _interval_ Denotes the interval in seconds between sending learning packets to each members peer switch. The valid range is 1 - 0x7fffffff; the default value is 1. This option has effect only in modes balance-tlb and balance-alb. *bond-resend-igmp* _number_ Denotes the number of IGMP membership reports to send after a link failover happend. The valid range is 0 - 255; a value of 0 prevents the IGMP membership report from being issued in response to the failover event. The default is 1. This option is useful for bonding modes balance-rr, active-backup balance-tlb and balance-alb, in which a failover can switch the IGMP traffic from one slave to another. # LACP-RELATED OPTIONS The following options are only valid in LACP (802.3ad) mode. *bond-lacp-rate* _rate_ Denotes the _rate_ of LACPDU requested from the peer. The _rate_ can be given as string or as numerical value. Valid values are slow (0) and fast (1). The default is slow. *bond-ad-select* _mode_ Denotes the 802.3ad aggregation selection logic. The _mode_ can be given as string or as numerical value. Valid values are _stable_ (0), _bandwidth_ (1) and _cound_ (2). The default is _stable_. *bond-ad-actor-sys-prio* _priority_ Denotes the LACP system priority. The allowed range is 1 - 65535. The default value is 65535. *bond-ad-user-port-key* _key_ Denotes the upper 10 bits of the port-key. he values can be from 0 - 1023. The default is 0. # ACTIVE/BACKUP-RELATED OPTIONS The following options are only valid in active/passive setups. *bond-primary* _interface_ Denotes the primary member interface The specified device will always be the active slave while it is available. The primary option is only valid for active-backup, balance-tlb and balance-alb mode. *bond-primary-reselect* _policy_ Denotes the reselection policy for the primary member interface. Valid values are _always_ (0), _better_ (1), and _failure_ (2). The default is _always_. *bond-fail-over-mac* _mode_ Denotes whether active-backup mode should set all member interfaces to the same MAC address at enslavement (the traditional behavior), or, when enabled, perform special handling of the bond's MAC address in accordance with the selected policy. Valid values are _none_ (0), _active_ (1), _follow_ (2). The default is _none_. *bond-num-grat-arp* _count_ Denotes the number of peer notifications (gratuitous ARPs and unsolicited IPv6 Neighbor Advertisements) to be issued after a failover event. The valid range is 0 - 255; the default is 1. *bond-num-unsol-na* _count_ This is an alias for _bond-num-grat-arp_ *bond-peer-notif-delay* _interval_ Denotes the interval in milliseconds, between each peer notification (gratuitous ARP and unsolicited IPv6 Neighbor Advertisement) issued after a failover event. The default is 0 which means to match the value of the link monitor interval. # ARP-RELATED OPTIONS The following options configure ARP link monitoring. The ARP monitor works by periodically checking the slave devices to determine whether they have sent or received traffic recently. Regular traffic is generated via ARP probes issued for the addresses specified by the _bond-arp-ip-target_ option. *bond-arp-interval* _interval_ Denotes the frequency in milliseconds to send ARP probes. *bond-arp-ip-target* _IPv4 address_ Denotes the IP addresses to use as ARP monitoring peers when _bond-arp-interval_ is > 0. *bond-arp-validate* _mode_ Specifies whether or not ARP probes and replies should be validated in any mode that supports arp monitoring, or whether non-ARP traffic should be filtered (disregarded) for link monitoring purposes. Valid values are _none_ (0), _active_ (1), _backup_ (2), _all_ (3), _filter_ (4), _filter_active_ (5), and _filter_backup_ (6). The default is _none_. *bond-arp-all-targets* _mode_ Denotes the number of _bond-arp-ip-targets_ that have to be reachable to consider the member interface to be up. Valid options are _any_ (0) and _all_ (1). The default is _any_. # EXAMPLES A bond using two links and LACP (802.3ad): ``` auto bond0 iface bond0 bond-members eth0 eth1 bond-mode 802.3ad bond-xmit-hash-policy layer3+4 bond-min-links 1 # address 192.0.2.42/24 address 2001:db8::42/64 ``` # AUTHORS Maximilian Wilhelm ifupdown-ng-ifupdown-ng-0.12.1/doc/interfaces-bridge.scd000066400000000000000000000111131422731055100230750ustar00rootroot00000000000000interfaces-bridge(5) # NAME *interfaces-bridge* - Bridge extensions for the interfaces(5) file format # DESCRIPTION Linux has support for Ethernet bridging interfaces which act like an Ethernet switch within the Linux Kernel. The following options allow to set up Ethernet bridges and adding configured interfaces to bridges. See *ip-link*(8) for more details about the options listed below. # BRIDGE-RELATED OPTIONS *bridge-ports* _list of interfaces_ A space separated list of interfaces which should be configured as member interfaces of this bridge. This option must be set for the bridge to be configured. *bridge-hw* _MAC address_ Denotes the _MAC address_ the bridge should use. *bridge-ageing* _seconds_ Denotes the time in seconds after which a MAC address will be removed from the Forwarding DataBase (FDB) after not having seen a frame with this source address. *bridge-vlan-aware* _bool_ Denotes wether or not the bridge should be aware of 802.1q VLANs. _bool_ can be given as _yes_/_no_ or _0_/_1_. The defaul is _no_. See related options for configuring vlan-aware bridges, below. # SPANNING TREE RELATED BRIDGE OPTIONS *bridge-stp* _state_ Activates or deactivates IEEE 802.1d Spanning Tree Protocol (STP) support of the bridge. Valid values are _on_/_off_. *bridge-bridgeprio* _priority_ Sets the bridge's priority to _priority_. The priority value is a number between 0 and 65535. Lower priority values are better. The bridge with the lowest priority will be elected _root bridge_. *bridge-fd* _seconds_ Denotes the bridge forward delay in seconds. Valid values are between 2 and 30. *bridge-hello* _seconds_ Denotes the bridge hello time in seconds. Valid values are between 1 and 10. *bridge-maxage* _seconds_ Denotes the seconds until another bridge is considerd dead after reception of its last STP hello message. Valid values are between 6 and 40. # OPTIONS FOR VLAN-AWARE-BRIDGES The following options only have an effect on vlan-aware bridges and their ports. All settings can be applied on the bridge interface itself and all member port iface stanzas. If applied on the bridge interface they take effect for the bridge interface itself and might be inherited to _bridge-ports_ depending on the compatibility settings configured in *ifupdown-ng.conf*(5). Configuring VLAN options on the bridge interface might be required for setting up a VLAN interface to one of the VLANs carried within the bridge. See the EXAMPLES section for an example for this scenario. See *ifupdown-ng.conf*(5) for more information about compatiblity settings mentioned below. *bridge-access* _vlan ID_ Configure the given _vlan ID_ for untagged ingress and egress on this interface. The common description for this kind of configuration is called "access port". *bridge-pvid* _vlan ID_ Denotes the _vlan ID_ to considered a PVID at ingress. Any untagged frames received on this interface will be assigned to this _vlan ID_. The default PVID is _1_. If compatibility to ifupdown2 bridge port inheritance is active a _bridge-pvid_ set on the bridge will be inherited to any interface configured in _bridge-ports_ without a _bridge-pvid_ set. *bridge-vids* _list of vlan IDs_ Denotes the space separated list of VLANs to be allowed tagged ingress/egress on this interface. If compatibility to ifupdown2 bridge port inheritance is active a _bridge-vids_ set on the bridge will be inherited to any interface configured in _bridge-ports_ without _bridge-vids_ set. *bridge-allow-untagged* _bool_ Denotes wether or not the bridge should allow untagged frames on ingress as well as egress. If set to _no_ untagged frames will be droppped on ingress and none will be sent. _bool_ can be given as _yes_/_no_ or _0_/_1_. The defaul is _yes_. # EXAMPLES A simple layer 2 only bridge: ``` auto br0 iface br0 bridge-ports eth0 veth-vm1 tap0 bridge-fd 0 bridge-stp off ``` A bridge with layer 3 configuration: ``` auto br0 iface br0 bridge-ports eth0 veth-vm1 tap0 bridge-fd 0 bridge-stp off # address 192.0.2.42/24 address 2001:db8::42/64 ``` A layer 2 only vlan-aware bridge: ``` auto bond0 iface bond0 bond-members eth0 eth1 bridge-vids 23 42 84 1337 auto br0 iface br0 bridge-ports bond0 ``` A vlan-aware bridge with a VLAN interface on top: ``` auto eth0 iface eth0 bridge-vids 23 42 84 1337 auto br0 iface br0 bridge-ports eth0 bridge-vlan-aware yes bridge-vids 42 auto vlan42 iface vlan42 vlan-raw-device br0 # address 192.0.2.42/24 address 2001:db8::42/64 ``` # SEE ALSO *interfaces*(5) *ifupdown-ng.conf*(5) *ip-link*(8) *bridge*(8) # AUTHORS Maximilian Wilhelm ifupdown-ng-ifupdown-ng-0.12.1/doc/interfaces-forward.scd000066400000000000000000000021171422731055100233110ustar00rootroot00000000000000interfaces-forward(5) # NAME *interfaces-forward* - forwarding vocabulary for the interfaces(5) file format # DESCRIPTION Linux allows for configuration of IP packet forwarding behavior on a protocol and interface basis. The following options allow for this configuration. # FORWARDING-RELATED OPTIONS The forward executor will only modify the sysctl configuration if these options are provided, otherwise other mechanisms such as /etc/sysctl.conf may be used. *forward-ipv4* _yes|no_ Whether the interface should forward unicast IPv4 packets. *forward-ipv6* _yes|no_ Whether the interface should forward unicast IPv6 packets. *forward-ipv4-mc* _yes|no_ Whether the interface should forward multicast IPv4 packets. *forward-ipv6-mc* _yes|no_ Whether the interface should forward multicast IPv6 packets. # EXAMPLES The typical home router scenario will want to forward both IPv4 and IPv6 packets: ``` iface WAN use dhcp forward-ipv4 yes forward-ipv6 yes iface LAN address 192.168.0.1/24 forward-ipv4 yes forward-ipv6 yes ``` # AUTHORS Ariadne Conill ifupdown-ng-ifupdown-ng-0.12.1/doc/interfaces-mpls.scd000066400000000000000000000020411422731055100226140ustar00rootroot00000000000000interfaces-mpls(5) # NAME *interfaces-mpls* - MPLS vocabulary for the interfaces(5) file format # DESCRIPTION Linux allows has support for MultiProtocol Label Switching (MPLS) for a while now. The following options allow for this configuration. # MPLS-RELATED OPTIONS The MPLS executor will only modify the sysctl configuration if these options are provided, otherwise other mechanisms such as /etc/sysctl.conf may be used. If MPLS is enabled on (at least) one interface the executor will load the _mpls_iptunnel_ kernel module. Be aware that you have to set the _platform_labels_ sysctl to make MPLS work. See https://www.kernel.org/doc/Documentation/networking/mpls-sysctl.rst for more details on the MPLS related knobs in the Linux kernel. *mpls-enable* _yes|no_ Control whether packets can be input on this interface. If disabled, packets carrying an MPLS label will be discarded without further processing. # EXAMPLES ``` iface eth0 address 2001:db8:08:15::42/64 # mpls-enable yes ``` # AUTHORS Maximilian Wilhelm ifupdown-ng-ifupdown-ng-0.12.1/doc/interfaces-ppp.scd000066400000000000000000000014531422731055100224460ustar00rootroot00000000000000interfaces-ppp(5) # NAME *interfaces-ppp* - PPP extensions for the interfaces(5) file format # DESCRIPTION The Point-to-Point Protocol (PPP) usually is used for dial-up lines, most common for over Digital Subscriber Lines (DSL) to connect to an Internet Service Provider (ISP). The following options allow to set up PPP dial-up connections. # PPP-RELATED OPTIONS *ppp-provider* _provider_ Denotes the file name of the _provider_ configuration file within the _/etc/ppp/peers/_ directory which should be used to set up the PPP connection. *ppp-physdev* _interfaces_ Denotes the physical (underlay) interface which is used to set up the PPP connection. # EXAMPLES A PPP connection to _local-ISP_: ``` auto ppp0 iface ppp0 ppp-provider local-ISP ``` # AUTHORS Maximilian Wilhelm ifupdown-ng-ifupdown-ng-0.12.1/doc/interfaces-tunnel.scd000066400000000000000000000116301422731055100231520ustar00rootroot00000000000000interfaces-tunnel(5) # NAME *interfaces-tunnel* - Tunnel extensions for the interfaces(5) file format # DESCRIPTION The following options set up tunneling interfaces with ifupdown-ng. # TUNNEL-RELATED OPTIONS A tunnel interface must have a mode, remote IP and a local IP or device set, all other options are optional. *tunnel-mode* _mode_ Denotes the mode for this tunnel. Basically all tunnel modes supported by Linux / iproute2 are supported as well. This includes but is not limited to _gre_/_gretap_, _ip6gre_/_ip6gretap_, _ipip_/_ip6ip_/_sit_. *tunnel-local* _IP_ Denotes the IP address used as the local tunnel endpoint. According to the _tunnel-mode_ an IPv4 or IPv6 address has to be given. For compatiblity to ifupdown1 _local_ is an alias for this option. *tunnel-local-dev* _interface_ When the local IP address the tunnel should be established from isn't static and therefore might change (e.g. configured by DHCP or PPP) it might be desireable to just use the address configured on _interface_. When _tunnel-local-dev_ is given instead of _tunnel-local_ ifupdown-ng will try to determine the IP address set on the given _interface_ with respect to the address family required to set up a tunnel of the given _mode_ and use this to set up the tunnel. *tunnel-remote* _IP_ Denotes the IP address used as the remote tunnel endpoint. According to the _tunnel-mode_ an IPv4 or IPv6 address has to be given. For compatiblity to ifupdown1 _endpoint_ is an alias for this option. *tunnel-physdev* _interface_ Denotes the _interface_ the encapsulated packets should be sent out by. This comes in handy when using VRFs to denote that the local tunnel endpoint should be terminated in VRF _interface_ or the VRF associated with _interface_. Note: Depending on the _mode_ of the tunnel either the VRF interface or the real underlay interface may have to given as _interface_. *tunnel-ttl* _ttl_ Denotes the TTL value to use in outgoing packets. _ttl_ is a number in the range 1 - 255 whereas 0 is a special value meaning that packets inherit the TTL value. The default for IPv4 tunnels is to inherit the TTL, for IPv6 tunnels it's 64. For compatiblity to ifupdown1 _ttl_ is an alias for this option. # IPIP/SIT-RELATED OPTIONS *tunnel-encap* _encap_ Denotes the type of secondary UDP encapsulation to use for this tunnel if any. Supported _encap_ values are _fou_, _gue_, and _none_. _fou_ indicates Foo-Over-UDP, _gue_ indicates Generic UDP Encapsulation. # GRE-RELATED OPTIONS *tunnel-encap* _encap_ Denotes the type of secondary UDP encapsulation to use for this tunnel if any. Supported _encap_ values are _fou_, _gue_, and _none_. _fou_ indicates Foo-Over-UDP, _gue_ indicates Generic UDP Encapsulation. *tunnel-key* _key_ Denotes the_key to used for keyed GRE to allow multiple tunnels between the same two endpoints. _key_ is either a number or an IPv4 address- like dotted quad. The key parameter specifies the same key to use in both directions. The _tunnel-ikey_ and _tunnel-okey_ parameters specify different keys for input and output. For compatiblity to ifupdown1 _key_ is an alias for this option. *tunnel-hoplimit* _ttl_ Denotes the Hop Limit value to use in outgoing packets for _ip6gre_/_ip6gretap_ tunnels. *tunnel-ignore-df* _bool_ Denotes wether to enable/disable IPv4 DF suppression on this tunnel. Normally datagrams that exceed the MTU will be fragmented; the presence of the DF flag inhibits this, resulting instead in an ICMP Unreachable (Fragmentation Required) message. Enabling this attribute causes the DF flag to be ignored. *tunnel-ikey* _key_ Denotes the key to used for keyed GRE for packets received. See _tunnel-key_ for details. *tunnel-okey* _key_ Denotes the key to used for keyed GRE for packets sent out. See _tunnel-key_ for details. *tunnel-pmtudisc* _bool_ Denotes wether to enable/disable Path MTU Discovery on this tunnel. It is enabled by default. Note that a fixed ttl is incompatible with this option: tunneling with a fixed ttl always makes pmtu discovery. *tunnel-tos* _tos_ Denotes the TOS value to use in outgoing packets. # EXAMPLES A simple GRE tunnel ``` auto gre0 iface gre0 tunnel-mode gre tunnel-remote 198.51.100.1 tunnel-local 203.0.113.2 # address 192.0.2.42/24 address 2001:db8::42/64 ``` A GRE tunnel where the local IP is learned from _eth0_ ``` auto gre1 iface gre1 tunnel-mode gre tunnel-remote 198.51.100.1 tunnel-local-dev eth0 # address 192.0.2.42/24 address 2001:db8::42/64 ``` A GRE tunnel which transfers encapasulated packets via _eth0_ which is part of a VRF. ``` auto eth0 iface eth0 address 203.0.113.2/24 gateway 203.0.113.1 vrf vrf_external auto tun-vrf iface tun-vrf tunnel-mode gre tunnel-remote 198.51.100.1 tunnel-local 203.0.113.2 tunnel-physdev eth0 # address 192.0.2.42/24 address 2001:db8::42/64 auto vrf_external iface vrf_external vrf-table 1023 ``` # AUTHORS Maximilian Wilhelm ifupdown-ng-ifupdown-ng-0.12.1/doc/interfaces-vrf.scd000066400000000000000000000022341422731055100224420ustar00rootroot00000000000000interfaces-vrf(5) # NAME *interfaces-vrf* - VRF extensions for the interfaces(5) file format # DESCRIPTION Linux has support for Virtual Routing and Forwarding (VRF) instances since Kernel >= 4.4. The following options allow to set up VRFs and adding configured interfaces to VRFs. Note that in the Linux Kernel VRFs are represented as network interfaces, too. See https://www.kernel.org/doc/Documentation/networking/vrf.rst for more details. # VRF-RELATED OPTIONS *vrf-table* _table id_ The _id_ of the kernel routing table associated with this VRF interface. This parameter indicates that the interface where it is specified shall be a VRF. *vrf* _vrf interface_ The _vrf_ the interface should be assigned to. This parameter is specified on regular interfaces which should be within the given _vrf_. # EXAMPLES A VRF interface: ``` auto vrf_external iface vrf_external vrf-table 1023 ``` A regular interface which should be within a VRF: ``` auto eth0 iface eth0 address 192.2.0.42/24 address 2001:db8::42/64 gateway 192.2.0.1 gateway 2001:db::1 vrf vrf_external ``` # SEE ALSO *ip-vrf*(8) *ip-link*(8) # AUTHORS Maximilian Wilhelm ifupdown-ng-ifupdown-ng-0.12.1/doc/interfaces-vxlan.scd000066400000000000000000000077561422731055100230130ustar00rootroot00000000000000interfaces-vxlan(5) # NAME *interfaces-vxlan* - VXLAN extensions for the interfaces(5) file format # DESCRIPTION Virtual eXtensible LAN (VXLAN) is an overlay network to carry Layer 2 over an IP network while accommodating a very large number of tenants. It is defined in RFC 7348. Be aware that VXLAN encapsulation adds 50 bytes of overhead to the IP packet header (inner Ethernet header + VXLAN + UDP + IP). This should be taken into consideration when setting up overlay networks, particularly on underlay networks with a conventional 1500 byte MTU. The following options set up VXLAN Tunnel EndPoints (VTEP) interfaces with ifupdown-ng. See https://www.kernel.org/doc/Documentation/networking/vxlan.rst and https://vincent.bernat.ch/en/blog/2017-vxlan-linux for more information. # VXLAN-RELATED OPTIONS A VXLAN Virtual Tunnel Endpoint (VTEP) interface must an ID set. All other options are optional. *vxlan-id* _VNI ID_ Denotes the VXLAN Network Identifier (VNI) ID for this interface. This parameter is required for VTEP interfaces. *vxlan-physdev* _interface_ Specifies the physical ("underlay") device to use for tunnel endpoint communication. This is required for setups using multicast. *vxlan-local-ip* _address_ Specifies the source IP address to use in outgoing packets. For compatiblity with ifupdown2 _vxlan-local-tunnelip_ is an alias for this parameter. *vxlan-peer-ips* _list of IP addresses_ Specifies the unicast destination IP address(es) to use in outgoing packets when the destination link layer address is not known in the VXLAN device forwarding database. This option can be used to form Point-to-Point as well as Point-to-Multipoint VXLAN tunnels/ overlays depending on how many peer IPs are given. If more than one IP address is given a Point-to-Multipoint overlay is being set up and ingress / head-end replication will be used by the Linux Kernel. This option cannot be used together with _vxlan-peer-group_ option. For compatiblity with ifupdown2 _vxlan-remoteip_ is an alias for this option and for compatibility with previos versions of ifupdown-ng _vxlan-remote-ip_ is an alias for this option, too. *vxlan-peer-group* _multicast group_ Specifies the multicast group address to join, requires _vxlan-phsydev_ to be set as well. This parameter cannot be specified in combination with the _vxlan-peer-ips_ parameter. For compatibility with ifupdown2 _vxlan-svcnodeip_ is an alias for this option and for compatibility with previos version of ifupdown-ng _vxlan-remote-group_ is an alias, too. *vxlan-learning* _on/off_ Specifies if unknown source link layer addresses and IP addresses are entered into the VXLAN device forwarding database. *vxlan-ageing* _seconds_ Specifies the lifetime in seconds of FDB entries learnt by the kernel. *vxlan-dstport* _port_ Specifies the UDP destination port of the remote VXLAN tunnel endpoint. The default is 4789. # EXAMPLES A VTEP with multiple peers addressed via a multicast group: ``` auto vx_v1001_padcty iface vx_v1001_padcty vxlan-id 655617 vxlan-physdev vlan1001 vxlan-remote-group 225.10.1.1 # hwaddress f2:00:c1:01:10:01 mtu 1560 ``` The same works just fine with IPv6 in the underlay: ``` auto vx_v1400_padcty iface vx_v1400_padcty vxlan-id 917505 vxlan-physdev vlan1400 vxlan-peer-group ff42:1400::1 # hwaddress f2:00:0d:01:14:00 mtu 1560 ``` Note that the underlay must have an MTU of at least 1610 to carry the encapsulated packets of the two VTEPs above. A VTEP with one peer (unicast point-to-point configuration): ``` auto vx_ptp1 iface vx_ptp1 vxlan-id 2342 vxlan-local-ip 192.0.2.42 vxlan-peer-ips 198.51.100.23 # hwaddress f2:00:c1:01:10:01 ``` A VTEP with multiple peers (unicast point-to-multipoint with ingress / head-end replication): ``` auto vx_her iface vx_her vxlan-id 1337 vxlan-local-ip 2001:db8:1::1 vxlan-peer-ips 2001:db8:2::23 2001:db8:3::42 2001:db8:4::84 ``` # AUTHORS Maximilian Wilhelm ifupdown-ng-ifupdown-ng-0.12.1/doc/interfaces-wifi.scd000066400000000000000000000027621422731055100226110ustar00rootroot00000000000000interfaces-wifi(5) # NAME *interfaces-wifi* - WiFi vocabulary for the interfaces(5) file format # DESCRIPTION Wi-Fi (the IEEE 802.11 family of protocols) is a commonly used wireless networking standard. The following options allow for configuration of Wi-Fi client interfaces. WPA-secured networks are managed using *wpa_supplicant*(8), while insecure networks are managed directly with *iwconfig*(8). # WIFI-RELATED OPTIONS *wifi-config-path* _path_ Denotes the absolute _path_ to a *wpa_supplicant* configuration file. If no path is given, _/run/wpa_supplicant..conf_ will be used for a temporary configuration file. This option may not be used with other configuration options. *wifi-ssid* _ssid_ The SSID the Wi-Fi client should connect to. *wifi-psk* _psk_ The passphrase for connecting to the Wi-Fi network. If unset, the client will connect without WPA2 encryption. # EXAMPLES A typical setup may involve connecting to a home and work network. To achieve this, we can define a pair of virtual interfaces called *wifi-home* and *wifi-work*, which connect to their respective wifi networks: ``` iface wifi-home use dhcp wifi-ssid HomeNetwork wifi-psk ExamplePassphrase iface wifi-work use dhcp wifi-config-path /etc/network/wpa-work.conf ``` The virtual interfaces can be used with *ifup* and *ifdown*: ``` # ifup wlan0=wifi-home # ifdown wlan0 # ifup wlan0=wifi-work ``` # SEE ALSO *iwconfig*(8)++ *wpa_supplicant*(8) # AUTHORS Ariadne Conill ifupdown-ng-ifupdown-ng-0.12.1/doc/interfaces-wireguard-quick.scd000066400000000000000000000011451422731055100247500ustar00rootroot00000000000000interfaces-wireguard-quick(5) # NAME *interfaces-wireguard-quick* - wg-quick extensions for the interfaces(5) file format # DESCRIPTION Wireguard is a comtemporary in-Kernel layer 3 VPN protocol implementation which aims to provide fast and secure tunnels. The wireguard-quick executor allows to set up Wireguard VPN tunnels using wg-quick. The configuration file used by wg-quick will be named `/etc/wireguard/_interface_.conf`. # EXAMPLES A Wireguard VPN tunnel configured with wg-quick: ``` auto wg-foo iface wg-foo use wireguard-quick ``` # AUTHORS Ariadne Conill ifupdown-ng-ifupdown-ng-0.12.1/doc/interfaces-wireguard.scd000066400000000000000000000027111422731055100236360ustar00rootroot00000000000000interfaces-wireguard(5) # NAME *interfaces-wireguard* - Wireguard extensions for the interfaces(5) file format # DESCRIPTION Wireguard is a comtemporary in-Kernel layer 3 VPN protocol implementation which aims to provide fast and secure tunnels. The following options allow to set up Wireguard VPN tunnels. # WIREGUARD-RELATED OPTIONS *wireguard-config-path* _path_ Denotes the absolute _path_ to the Wireguard configuration file. If no path is given, _/etc/wireguard/.conf_ will be used. In the latter case _use wireguard_ has to be explicitly set to the interface configuration. Be aware that the given configuration file will be loaded using *wg setconf* and not with *wg-quick*. The file format for both tools isn't compatible so you have to make sure you provide a valid configuration file for the *wg* tool. If you already have a configuration file for *wg-quick* you can set up the tunnel manually once and then dump the configuration using *wg showconf* and save this to _path_. # EXAMPLES A Wireguard VPN tunnel with explicit configuration file specified ``` auto wg-foo iface wg-foo wireguard-config-path /etc/wireguard/foo.conf # address 192.0.2.23/42 address 2001:db8::23/64 ``` A Wireguard VPN tunnel with implicit configuration file: ``` auto wg-bar iface wg-bar use wireguard # address 192.0.2.23/42 address 2001:db8::23/64 ``` # SEE ALSO *interfaces-wireguard-quick*(5) # AUTHORS Maximilian Wilhelm ifupdown-ng-ifupdown-ng-0.12.1/doc/interfaces.scd000066400000000000000000000162641422731055100216570ustar00rootroot00000000000000interfaces(5) # NAME */etc/network/interfaces* - interface configuration database # DESCRIPTION The */etc/network/interfaces* file is used to specify how network interfaces are configured. The file is processed by *ifquery*(8), *ifup*(8) and *ifdown*(8) to introspect and change system state. In most cases, syntax from legacy implementations is supported as well, but that syntax is not discussed in detail here. # FILE SYNTAX The interface configuration database is composed of a series of stanzas. Hash symbols designate comments, which are ignored by the system. A stanza is a collection of triples, where a triple is a key and value combination that is related to an *object*. Triples which are not associated with an *object* are considered to be part of the root of the configuration tree. All keywords are case-sensitive and are expected to be lower-case. The following is a simple example of a stanza: ``` auto eth0 iface eth0 address 203.0.113.2/24 gateway 203.0.113.1 ``` This stanza defines an interface named *eth0* which is configured with an address of *203.0.113.2* and gateway of *203.0.113.1*. # SUPPORTED KEYWORDS FOR UNASSOCIATED TRIPLES *auto* _object_ Designates that _object_ should be automatically configured by the system when appropriate. *iface* _object_ Begins a new declaration for _object_. Any child keyword associated with the declaration will be stored inside _object_. *source* _filename_ Includes the file _filename_ as configuration data. *source-directory* _directory_ Includes the files in _directory_ as configuration data. *template* _object_ Begins a new declaration for _object_, like *iface*, except that _object_ is defined as a *template*. # SUPPORTED KEYWORDS FOR OBJECT TRIPLES Any keyword may be used inside an interface declaration block, but the system will only respond to certain keywords by default: *address* _address_ Associates an IPv4 or IPv6 address in CIDR notation with the parent interface. If an IP address without a prefix length is given a given _netmask_ attribute is used if present. If neither a prefix length nor a _netmask_ are given a /24 or /64 prefix length is presumed for IPv4 / IPv6 as of compatibility reasons to classic ifupdown. *netmask* _netmask_ Associates a fallback netmask with the parent interface for addresses which do not have a CIDR length set. This option is for backwards compatibility and should not be used in new deployments. *point-to-point* _address_ Sets the given IPv4 _address_ as the peer address on the interface. This setting only takes effect for the IPv4 address familiy and only makes sense in combination with a /32 netmask. For compatiblity with ifupdown and ifupdown2, _pointopoint_ is an alias for this parameter. *gateway* _address_ Associates an IPv4 or IPv6 address with the parent interface for use as a default route (gateway). This usually is given once for IPv4 and once for IPv6 (in a Dual-Stack setup). *link-type* _link-type_ Denotes the link-type of the interface. When set to _dummy_, the interface is created as a virtual dummy interfaces. When set to _veth_ the interface is created as virtual veth interface (pair). *veth-peer-name* _peer-name_ Denotes the name of the veth peer interfaces. If not set the kernel will name the veth peer interface as _vethN_ with N being an integer number. *alias* _alias_ Sets the given alias on the interface. *requires* _interfaces_... Designates one or more required interfaces that must be brought up before configuration of the parent interface. Interfaces associated with the parent are taken down at the same time as the parent. *inherit* _object_ Designates that the configured interface should inherit configuration data from _object_. Normally _object_ must be a *template*. *use* _executor_ Designates that an executor should be used. See _EXECUTORS_ section for more information on executors. *pre-down* _command_ Runs _command_ before taking the interface down. *down* _command_ Runs _command_ when the interface is taken down. *post-down* _command_ Runs _command_ after taking the interface down. *pre-up* _command_ Runs _command_ before bringing the interface up. *up* _command_ Runs _command_ when the interface is brought up. *post-up* _command_ Runs _command_ after bringing the interface up. Additional packages such as *bonding*, *bridge*, *tunnel*, *vrf* and *vxlan* add additional keywords to this vocabulary. # EXECUTORS The *use* keyword designates that an _executor_ should be used. This system is extendable by additional packages, but the most common executors are: *batman* The interface is a B.A.T.M.A.N. adv. mesh interface. Configuration of B.A.T.M.A.N. adv. interfaces requires the *batctl* untiliy to be installed. *bond* The interface is a bonded interface. Configuration of bonded interfaces requires the *bonding* package to be installed. *bridge* The interface is an ethernet bridge. Configuration of ethernet bridges requires the *bridge* package to be installed. *dhcp* Use a DHCP client to learn the IPv4 address of an interface. *forward* Configures forwarding settings on the interface. *loopback* Designates the interface as a loopback device. *ppp* Designates the interface as a PPP device. Configuration of PPP interfaces require the *ppp* and probably the *pppoe* packages to be installed. *tunnel* The interface is a tunnel. Configuration of tunnels requires the *tunnel* package to be installed on Alpine Linux. *vrf* The interface is a VRF. Configuration of VRFs requires the *vrf* package to be installed. *vxlan* The interface is a Virtual Extensible LAN (VXLAN) tunnel endpoint. *wifi* The interface is a Wi-Fi (IEEE 802.11) client interface. Configuration of the WiFi client interface requires the *wireless-tools* package to be installed. The *wpa_supplicant* package must also be installed to connect to hotspots using WPA-based security. *wireguard* The interface is a Wireguard VPN tunnel endpoint. Check *interfaces-(5)* for further informaton about a given executor and available configuration parameters. If the _auto\_executor\_selection_ ifupdown-ng.conf option is enabled, *use* statements will automatically be added for executors when their configuration statements are present in the interfaces file. # EXAMPLES Configure a bridge interface *br0* with *bond0* attached to it, which is a failover between *eth0* and *eth1*. This requires the *bonding* and *bridge* packages to be installed: ``` auto br0 iface br0 use bridge requires bond0 address 203.0.113.2/24 gateway 203.0.113.1 iface bond0 use bond requires eth0 eth1 bond-mode 802.3ad bond-xmit-hash-policy layer2+3 ``` Configure a network interface to use DHCP to learn its IPv4 address: ``` auto eth0 iface eth0 use dhcp ``` # SEE ALSO *ifstate*(5) *ifupdown-ng.conf*(5) *ifup*(8) *ifdown*(8) *ifquery*(8) *ifctrstat*(8) *interfaces-batman*(5) *interfaces-bond*(5) *interfaces-bridge*(5) *interfaces-forward*(5) *interfaces-mpls*(5) *interfaces-ppp*(5) *interfaces-tunnel*(5) *interfaces-vrf*(5) *interfaces-vxlan*(5) *interfaces-wifi*(5) *interfaces-wireguard*(5) # AUTHORS Ariadne Conill ++ Maximilian Wilhelm ifupdown-ng-ifupdown-ng-0.12.1/executor-scripts/000077500000000000000000000000001422731055100216065ustar00rootroot00000000000000ifupdown-ng-ifupdown-ng-0.12.1/executor-scripts/linux/000077500000000000000000000000001422731055100227455ustar00rootroot00000000000000ifupdown-ng-ifupdown-ng-0.12.1/executor-scripts/linux/batman000066400000000000000000000063321422731055100241360ustar00rootroot00000000000000#!/bin/sh # # Maximilian Wilhelm # -- Wed 26 Aug 2020 08:15:58 PM CEST # # This executor is responsible for setting up the main B.A.T.M.A.N. adv. interface (eg. bat0) # as well as managing settings of the underlying interfaces (hardifs). # # See interfaces-batman(5) for a list of supported options for hardifs as well as meshifs. # if [ "$VERBOSE" ]; then set -x fi if ! which batctl >/dev/null 2>&1; then echo "Error: batctl utility not found!" >&2 exit 1 fi # # Compatiblity glue: Newer versions of batctl print a deprecation # warning when called with -m . Avoid spamming the log and # producting SPAM by silently handling this here. mesh_if_param="-m" if batctl -h 2>&1 | grep -q "meshif"; then mesh_if_param="meshif" fi # # Functions to manage main B.A.T.M.A.N. adv. interface batctl_if () { for iface in ${IF_BATMAN_IFACES}; do ${MOCK} batctl "${mesh_if_param}" "${IFACE}" interface "$1" "${iface}" done } set_meshif_options () { # We only care for options of format IF_BATMAN_ env | grep '^IF_BATMAN_[A-Z0-9_]\+' | while IFS="=" read opt value; do # Members, ignore-regex, routing-algo, and throughput_override are handled seperately if [ "${opt}" = "IF_BATMAN_IFACES" -o \ "${opt}" = "IF_BATMAN_IFACES_IGNORE_REGEX" -o \ "${opt}" = "IF_BATMAN_ROUTING_ALGO" -o \ "${opt}" = "IF_BATMAN_THROUGHPUT_OVERRIDE" ]; then continue fi # Convert options for the actual name real_opt=$(echo "${opt}" | sed -e 's/^IF_BATMAN_\([A-Z0-9_]\+\)/\1/' | tr '[A-Z]' '[a-z]') ${MOCK} batctl "${mesh_if_param}" "${IFACE}" "${real_opt}" "${value}" done } set_routing_algo () { if [ "${IF_BATMAN_ROUTING_ALGO}" != "BATMAN_IV" -a "${IF_BATMAN_ROUTING_ALGO}" != "BATMAN_V" ]; then echo "Invalid routing algorithm \"$1\"." return fi batctl ra "${IF_BATMAN_ROUTING_ALGO}" } # # Functions to manage B.A.T.M.A.N. adv. underlay interfaces (hardifs) set_hardif_options () { # Query hardif parameter manually for now for hardif in ${IF_BATMAN_IFACES}; do penalty=$(ifquery -p "batman-hop-penalty" "${hardif}") if [ "${penalty}" ]; then ${MOCK} batctl hardif "${hardif}" hop_penalty "${penalty}" fi throughput=$(ifquery -p "batman-throughput-override" "${hardif}") if [ "${throughput}" ]; then ${MOCK} batctl hardif "${hardif}" throughput_override "${througput}" fi done } case "${PHASE}" in depend) if [ "${IF_BATMAN_IFACES}" ]; then echo "${IF_BATMAN_IFACES}" fi ;; create) # Main B.A.T.M.A.N. adv. interface if [ "${IF_BATMAN_IFACES}" ]; then if [ "${IF_BATMAN_ROUTING_ALGO}" ]; then set_routing_algo fi if [ ! -d "/sys/class/net/${IFACE}" ]; then batctl "${mesh_if_param}" "${IFACE}" interface create || true fi fi ;; pre-up) # Main B.A.T.M.A.N. adv. interface (meshif) if [ "${IF_BATMAN_IFACES}" ]; then batctl_if add set_meshif_options set_hardif_options fi ;; destroy) if [ "${IF_BATMAN_IFACES}" -a -d "/sys/class/net/${IFACE}" ]; then # Newer versions of batctl provide the "interface destroy" API, try to use it if ! batctl "${mesh_if_param}" "${IFACE}" interface destroy 2>/dev/null; then # Fall back to old style member interface removal batctl_if del fi fi ;; *) exit 0 ;; esac ifupdown-ng-ifupdown-ng-0.12.1/executor-scripts/linux/bond000077500000000000000000000024211422731055100236140ustar00rootroot00000000000000#!/bin/sh # # This executor is responsible for setting up bond/LAG interfaces. # # Sat, 03 Oct 2020 20:42:19 +0200 # -- Maximilian Wilhelm # [ -n "$VERBOSE" ] && set -x get_bond_options() { # We only care for options of format IF_BOND_ env | grep '^IF_BOND_[A-Z0-9_]\+' | while IFS="=" read opt value; do # Members are handled seperately if [ "${opt}" = "IF_BOND_MEMBERS" ]; then continue fi # Convert options for the actual name real_opt=$(echo "${opt}" | sed -e 's/^IF_BOND_\([A-Z0-9_]\+\)/\1/' | tr '[A-Z]' '[a-z]') echo -n " ${real_opt} ${value}" done } case "$PHASE" in depend) echo "${IF_BOND_MEMBERS}" ;; create) if [ -d "/sys/class/net/${IFACE}" ]; then exit 0 fi # Gather bonding options for this interface options=$(get_bond_options) # Create bond ${MOCK} ip link add "${IFACE}" type bond ${options} # Add members to bundle for member_iface in ${IF_BOND_MEMBERS}; do # Work around the current execution order ${MOCK} ip link set "${member_iface}" down ${MOCK} ip link set master "${IFACE}" "${member_iface}" ${MOCK} ip link set "${member_iface}" up done ;; destroy) if [ -z "${MOCK}" -a ! -d "/sys/class/net/${IFACE}" ]; then exit 0 fi ${MOCK} ip link del "${IFACE}" ;; esac ifupdown-ng-ifupdown-ng-0.12.1/executor-scripts/linux/bridge000077500000000000000000000176001422731055100241330ustar00rootroot00000000000000#!/bin/sh [ -n "$VERBOSE" ] && set -x # Copyright (C) 2012, 2020 Natanael Copa # Copyright (C) 2020 Ariadne Conill # Copyright (C) 2020 Maximilian Wilhelm # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # This software is provided 'as is' and without any warranty, express or # implied. In no event shall the authors be liable for any damages arising # from the use of this software. ################################################################################ # Bridge management functions # ################################################################################ all_ports_exist() { local i= for i in "$@"; do [ -d /sys/class/net/$i ] || return 1 done return 0 } wait_ports() { local timeout= waitports= [ -z "$IF_BRIDGE_WAITPORT" ] && return 0 set -- $IF_BRIDGE_WAITPORT timeout="$1" shift waitports="$@" [ -z "$waitports" ] && waitports="$PORTS" while ! all_ports_exist $waitports; do [ "$timeout" -eq 0 ] && return 0 timeout=$(($timeout - 1)) sleep 1 done } all_ports() { local i= for i in /sys/class/net/*/ifindex; do i=${i%/*} i=${i##*/} case "$i" in lo|$IFACE) continue;; *) echo $i;; esac done } add_ports() { local port= for port in $PORTS; do if [ -n "$IF_BRIDGE_HW" ]; then ip link set dev $port addr $IF_BRIDGE_HW fi ip link set dev $port master $IFACE && ip link set dev $port up done } del_ports() { local port= for port in $PORTS; do ip link set dev $port down ip link set dev $port nomaster done } set_bridge_opts_brctl() { [ -n "$IF_BRIDGE_AGEING" ] \ && brctl setageing $IFACE $IF_BRIDGE_AGEING [ -n "$IF_BRIDGE_BRIDGEPRIO" ] \ && brctl setbridgeprio $IFACE $IF_BRIDGE_BRIDGEPRIO [ -n "$IF_BRIDGE_FD" ] \ && brctl setfd $IFACE $IF_BRIDGE_FD [ -n "$IF_BRIDGE_HELLO" ] \ && brctl sethello $IFACE $IF_BRIDGE_HELLO [ -n "$IF_BRIDGE_MAXAGE" ] \ && brctl setmaxage $IFACE $IF_BRIDGE_MAXAGE [ -n "$IF_BRIDGE_PATHCOST" ] \ && brctl setpathcost $IFACE $IF_BRIDGE_PATHCOST [ -n "$IF_BRIDGE_PORTPRIO" ] \ && brctl setportprio $IFACE $IF_BRIDGE_PORTPRIO [ -n "$IF_BRIDGE_STP" ] \ && brctl stp $IFACE $IF_BRIDGE_STP } yesno() { case "$1" in yes|YES|true|TRUE|1) echo 1 ;; *) echo 0 ;; esac } set_bridge_opts_iproute2() { [ -n "$IF_BRIDGE_AGEING" ] \ && ip link set dev $IFACE type bridge ageing_time $IF_BRIDGE_AGEING [ -n "$IF_BRIDGE_BRIDGEPRIO" ] \ && ip link set dev $IFACE type bridge priority $IF_BRIDGE_BRIDGEPRIO [ -n "$IF_BRIDGE_FD" ] \ && ip link set dev $IFACE type bridge forward_delay $IF_BRIDGE_FD [ -n "$IF_BRIDGE_HELLO" ] \ && ip link set dev $IFACE type bridge hello_time $IF_BRIDGE_HELLO [ -n "$IF_BRIDGE_MAXAGE" ] \ && ip link set dev $IFACE type bridge max_age $IF_BRIDGE_MAXAGE [ -n "$IF_BRIDGE_PATHCOST" ] \ && bridge link set dev $IFACE cost $IF_BRIDGE_PATHCOST [ -n "$IF_BRIDGE_PORTPRIO" ] \ && bridge link set dev $IFACE priority $IF_BRIDGE_PORTPRIO [ -n "$IF_BRIDGE_STP" ] \ && ip link set dev $IFACE type bridge stp $(yesno $IF_BRIDGE_STP) [ -n "$IF_BRIDGE_VLAN_AWARE" ] \ && ip link set dev $IFACE type bridge vlan_filtering $(yesno $IF_BRIDGE_VLAN_AWARE) } set_bridge_opts() { [ -x /sbin/bridge ] && set_bridge_opts_iproute2 && return 0 [ -x /sbin/brctl ] && set_bridge_opts_brctl && return 0 } all_ports_ready() { local port= for port in $PORTS; do case $(cat /sys/class/net/$IFACE/brif/$port/state) in ""|0|3) ;; # 0 = disabled, 3 = forwarding [12]) return 1;; esac done return 0 } find_maxwait() { awk '{printf("%.f\n", 2 * $0 / 100); }' \ /sys/class/net/$IFACE/bridge/forward_delay } wait_bridge() { local timeout=$IF_BRIDGE_MAXWAIT if [ -z "$timeout" ]; then timeout=$(find_maxwait) fi ip link set dev $IFACE up while ! all_ports_ready; do [ $timeout -eq 0 ] && break timeout=$(($timeout - 1)) sleep 1 done } ################################################################################ # Bridge port management functions # ################################################################################ configure_access_port() { port="$1" vlan="$2" self="$3" # Cleans all existing VLANs (probably at least VLAN 1) bridge vlan show dev ${port} | tail -n +2 | grep -v '^$' | sed -e "s/^${port}//" | while read vid flags; do bridge vlan del vid "${vid}" dev "${port}" ${self} done bridge vlan add vid "${vlan}" pvid untagged dev "${port}" ${self} } configure_trunk_port() { port="$1" self="$2" # Working on the bridge itself? if [ "${self}" ]; then allow_untagged="${IF_BRIDGE_ALLOW_UNTAGGED}" pvid="${IF_BRIDGE_PVID}" vids="${IF_BRIDGE_VIDS}" else allow_untagged=$(ifquery -p bridge-allow-untagged ${port} 2>/dev/null || true) pvid=$(ifquery -p bridge-pvid ${port} 2>/dev/null || true) vids=$(ifquery -p bridge-vids ${port} 2>/dev/null || true) fi # If bridge-allow-untagged if set to off, remove untagged VLAN. If it's # one of our bridge-vids, it will be set again later. if [ "${allow_untagged}" -a "$(yesno ${allow_untagged})" = 0 ]; then untagged_vid=$(bridge vlan show dev ${port} | tail -n +2 | grep -v '^$' | sed -e "s/^${port}//" | awk '/Untagged/ { print $1 }') if [ "${untagged_vid}" ]; then bridge vlan del vid "${untagged_vid}" dev "${port}" ${self} fi fi # The vlan specified is to be considered a PVID at ingress. # Any untagged frames will be assigned to this VLAN. if [ "${pvid}" ]; then cur_pvid=$(bridge vlan show dev ${port} | tail -n +2 | grep -v '^$' | sed -e "s/^${port}//" | awk '/PVID/ { print $1 }') if [ "${cur_pvid}" ]; then bridge vlan del vid ${cur_pvid} dev "${port}" ${self} fi bridge vlan add vid "${pvid}" dev "${port}" pvid untagged ${self} fi # Add regular tagged VLANs for vid in ${vids}; do bridge vlan add vid $vid dev "${port}" ${self} done } # Configure VLANs on the bridge interface itself set_bridge_vlans() { # Shall the bridge interface be an untagged port? if [ "${IF_BRIDGE_ACCESS}" ]; then configure_access_port "${IFACE}" "${IF_BRIDGE_ACCESS}" "self" # Configure bridge interface as trunk port else configure_trunk_port "${IFACE}" "self" fi } # Configure VLANs on the bridge-ports set_bridge_port_vlans() { for port in ${PORTS}; do access_vlan=$(ifquery -p bridge-access ${port} 2>/dev/null || true) # Shall this prot interface be an untagged port? if [ "${access_vlan}" ]; then configure_access_port "${port}" "${access_vlan}" # Configure port as trunk else configure_trunk_port "${port}" fi done } case "$IF_BRIDGE_PORTS" in "") ;; none) PORTS="";; all) PORTS=$(all_ports);; *) PORTS="$IF_BRIDGE_PORTS";; esac case "$PHASE" in depend) # Called for the bridge interface if [ "${IF_BRIDGE_PORTS}" ]; then echo "$PORTS" fi ;; create) # Called for the bridge interface if [ "${IF_BRIDGE_PORTS}" -a ! -d "/sys/class/net/${IFACE}" ]; then ip link add "${IFACE}" type bridge fi ;; pre-up) # Called for the bridge interface if [ "${IF_BRIDGE_PORTS}" ]; then wait_ports set_bridge_opts set_bridge_vlans add_ports set_bridge_port_vlans wait_bridge # Called for a bridge member port elif [ "${IF_BRIDGE_VIDS}" -o "${IF_BRIDGE_PVID}" -o "${IF_BRIDGE_ACCESS}" -o "${IF_BRIDGE_ALLOW_UNTAGGED}" ]; then # Eventually we want to configure VLAN settings of member ports here. # The current execution model does not allow this, so this is a no-op # for now and we work around this by configuring ports while configuring # the bridge. true fi ;; post-down) # Called for the bridge interface if [ "${IF_BRIDGE_PORTS}" ]; then del_ports ip link set dev $IFACE down fi ;; destroy) # Called for the bridge interface if [ "${IF_BRIDGE_PORTS}" -a -d "/sys/class/net/${IFACE}" ]; then ip link del "${IFACE}" fi ;; esac ifupdown-ng-ifupdown-ng-0.12.1/executor-scripts/linux/dhcp000077500000000000000000000033671422731055100236220ustar00rootroot00000000000000#!/bin/sh # some users provide a shell fragment for the hostname property. [ -n "$IF_DHCP_HOSTNAME" ] && IF_DHCP_HOSTNAME=$(eval echo $IF_DHCP_HOSTNAME) determine_implementation() { [ -n "$IF_DHCP_PROGRAM" ] && echo "$IF_DHCP_PROGRAM" && return [ -x /sbin/dhcpcd ] && echo "dhcpcd" && return [ -x /usr/sbin/dhclient ] && echo "dhclient" && return [ -x /sbin/udhcpc ] && echo "udhcpc" && return echo "could not find a supported DHCP implementation" exit 1 } start() { case "$1" in dhcpcd) [ -n "$IF_DHCP_HOSTNAME" ] && optargs="$optargs -h $IF_DHCP_HOSTNAME" [ -n "$IF_DHCP_VENDOR" ] && optargs="$optargs -i $IF_DHCP_VENDOR" [ -n "$IF_DHCP_CLIENT_ID" ] && optargs="$optargs -i $IF_DHCP_CLIENT_ID" [ -n "$IF_DHCP_LEASETIME" ] && optargs="$optargs -l $IF_DHCP_LEASETIME" ${MOCK} /sbin/dhcpcd $optargs $IFACE ;; dhclient) # Specific config file given? if [ -n "$IF_DHCP_CONFIG" ]; then optargs="$optargs -cf $IF_DHCP_CONFIG" fi ${MOCK} /usr/sbin/dhclient -pf /var/run/dhclient.$IFACE.pid $optargs $IFACE ;; udhcpc) optargs=$(eval echo $IF_UDHCPC_OPTS) [ -n "$IF_DHCP_HOSTNAME" ] && optargs="$optargs -x hostname:$IF_DHCP_HOSTNAME" [ -n "$IF_DHCP_CLIENT_ID" ] && optargs="$optargs -c $IF_DHCP_CLIENT_ID" [ -n "$IF_DHCP_SCRIPT" ] && optargs="$optargs -s $IF_DHCP_SCRIPT" ${MOCK} /sbin/udhcpc -b -R -p /var/run/udhcpc.$IFACE.pid -i $IFACE $optargs ;; *) ;; esac } stop() { case "$1" in dhcpcd) ${MOCK} /sbin/dhcpcd -k $IFACE ;; dhclient) ${MOCK} kill -9 $(cat /var/run/dhclient.$IFACE.pid) 2>/dev/null ;; udhcpc) ${MOCK} kill $(cat /var/run/udhcpc.$IFACE.pid) ;; *) ;; esac } impl=$(determine_implementation) [ -z "$VERBOSE" ] || set -x case "$PHASE" in up) start $impl ;; down) stop $impl || true ;; *) ;; esac ifupdown-ng-ifupdown-ng-0.12.1/executor-scripts/linux/ethtool000077500000000000000000000032761422731055100243610ustar00rootroot00000000000000#!/bin/sh # gather params for a given prefix, based on executor-scripts/linux/tunnel. gather_params() { env | sed -E " s/^IF_${1}_([A-Z0-9_]+)=(.+)/\1\n\2/ ta d :a h y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ P g s/.*\n//" | sed -E "s/_/-/g" } case "$PHASE" in pre-up) settings="\ ${IF_ETHTOOL_ETHERNET_PORT:+ port $IF_ETHTOOL_ETHERNET_PORT} ${IF_ETHTOOL_MSGLVL:+ msglvl $IF_ETHTOOL_MSGLVL} " [ -z "$settings" ] || $MOCK ethtool --change "$IFACE" $settings ;; up) # first do the link settings. link_settings="${IF_ETHTOOL_LINK_SPEED:+ speed $IF_ETHTOOL_LINK_SPEED}${IF_ETHTOOL_LINK_DUPLEX:+ duplex $IF_ETHTOOL_LINK_DUPLEX}" # ethernet-wol can have a second arg (key), split into $1 and $2 set -- $IF_ETHTOOL_ETHERNET_WOL link_settings="$link_settings${1:+ wol $1}${2:+ sopass $2}" # handle ethtool-ethernet-autoneg like Debian would case "$IF_ETHTOOL_ETHERNET_AUTONEG" in '') ;; on|off) link_settings="$link_settings autoneg $IF_ETHTOOL_ETHERNET_AUTONEG" ;; *) link_settings="$link_settings autoneg on advertise $IF_ETHTOOL_ETHERNET_AUTONEG" ;; esac [ -z "$link_settings" ] || $MOCK ethtool --change "$IFACE" $link_settings pause_settings=$(gather_params ETHTOOL_PAUSE) [ -z "$pause_settings" ] || $MOCK ethtool --pause "$IFACE" $pause_settings offload_settings=$(gather_params ETHTOOL_OFFLOAD) [ -z "$offload_settings" ] || $MOCK ethtool --offload "$IFACE" $offload_settings dma_settings=$(gather_params ETHTOOL_DMA_RING) [ -z "$dma_settings" ] || $MOCK ethtool --set-ring "$IFACE" $dma_settings coalesce_settings=$(gather_params ETHTOOL_COALESCE) [ -z "$coalesce_settings" ] || $MOCK ethtool --coalesce "$IFACE" $coalesce_settings ;; esac ifupdown-ng-ifupdown-ng-0.12.1/executor-scripts/linux/forward000077500000000000000000000012271422731055100243410ustar00rootroot00000000000000#!/bin/sh yesno() { case "$1" in yes|1) echo 1 ;; *) echo 0 ;; esac } [ "$PHASE" != "up" ] && exit 0 [ -z "$VERBOSE" ] || set -x [ -n "$IF_FORWARD_IPV4" ] && ${MOCK} /bin/sh -c "echo $(yesno $IF_FORWARD_IPV4) > /proc/sys/net/ipv4/conf/$IFACE/forwarding" [ -n "$IF_FORWARD_IPV6" ] && ${MOCK} /bin/sh -c "echo $(yesno $IF_FORWARD_IPV6) > /proc/sys/net/ipv6/conf/$IFACE/forwarding" [ -n "$IF_FORWARD_IPV4_MC" ] && ${MOCK} /bin/sh -c "echo $(yesno $IF_FORWARD_IPV4_MC) > /proc/sys/net/ipv4/conf/$IFACE/mc_forwarding" [ -n "$IF_FORWARD_IPV6_MC" ] && ${MOCK} /bin/sh -c "echo $(yesno $IF_FORWARD_IPV6_MC) > /proc/sys/net/ipv6/conf/$IFACE/mc_forwarding" exit 0 ifupdown-ng-ifupdown-ng-0.12.1/executor-scripts/linux/gre000077500000000000000000000011701422731055100234470ustar00rootroot00000000000000#!/bin/sh # Executor for advanced GRE tunnel management. [ -z "$IF_GRE_LOCAL" ] && exit 1 [ -z "$IF_GRE_REMOTE" ] && exit 1 [ -z "$IF_GRE_MODE" ] && IF_GRE_MODE="gre" COMMAND="link" FAMILY="-4" [ "$IF_GRE_MODE" = "ip6gre" ] && FAMILY="-6" PARAMS="mode $IF_GRE_MODE local '$IF_GRE_LOCAL' remote '$IF_GRE_REMOTE'" [ -n "$IF_GRE_TTL" ] && PARAMS="$PARAMS ttl '$IF_GRE_TTL'" [ -n "$IF_GRE_FLAGS" ] && PARAMS="$PARAMS $IF_GRE_FLAGS" [ -n "$PARAMS" ] || exit 0 case "$PHASE" in create) ${MOCK} eval ip $FAMILY $COMMAND add $IFACE $PARAMS ;; destroy) ${MOCK} ip $FAMILY $COMMAND del $IFACE ;; depend) echo "$IF_GRE_DEV" ;; esac ifupdown-ng-ifupdown-ng-0.12.1/executor-scripts/linux/ipv6-ra000077500000000000000000000004231422731055100241560ustar00rootroot00000000000000#!/bin/sh start() { ${MOCK} /bin/sh -c "echo 1 > /proc/sys/net/ipv6/conf/$IFACE/accept_ra" } stop() { ${MOCK} /bin/sh -c "echo 0 > /proc/sys/net/ipv6/conf/$IFACE/accept_ra" } [ -z "$VERBOSE" ] || set -x case "$PHASE" in up) start $impl ;; down) stop $impl ;; *) ;; esac ifupdown-ng-ifupdown-ng-0.12.1/executor-scripts/linux/link000077500000000000000000000050131422731055100236270ustar00rootroot00000000000000#!/bin/sh [ -n "$VERBOSE" ] && set -x is_vlan() { case "$IFACE" in *#*) return 1 ;; *:*) return 1 ;; vlan*.*) return 1 ;; vlan*) IF_VLAN_ID="${IFACE#vlan}" [ -n "${IF_VLAN_RAW_DEVICE:-}" ] && return 0 return 1 ;; *.*) IF_VLAN_RAW_DEVICE="${IFACE%.*}" IF_VLAN_ID="${IFACE##*.}" return 0 ;; *) [ -z "${IF_VLAN_ID:-}" ] && return 1 [ -z "${IF_VLAN_RAW_DEVICE:-}" ] && return 1 return 0 ;; esac } case "$PHASE" in depend) # vlan-raw-device if is_vlan; then echo "$IF_VLAN_RAW_DEVICE" # veth-peer-name elif [ "${IF_LINK_TYPE}" = "veth" -a "${IF_VETH_PEER_NAME}" ]; then echo "${IF_VETH_PEER_NAME}" fi ;; create) if [ "${IF_LINK_TYPE}" = "dummy" ]; then if [ -d "/sys/class/net/${IFACE}" ]; then iface_type=$(ip -d link show dev "${IFACE}" | head -n3 | tail -n1 | awk '{ print $1 }') if [ "${iface_type}" != 'dummy' ]; then echo "Interface ${IFACE} exists but is of type ${iface_type} instead of dummy" exit 1 fi exit 0 fi ${MOCK} ip link add "${IFACE}" type dummy elif [ "${IF_LINK_TYPE}" = "veth" ]; then if [ ! -d "/sys/class/net/${IFACE}" ]; then ARGS="" if [ "${IF_VETH_PEER_NAME}" ]; then ARGS="peer ${IF_VETH_PEER_NAME}" fi ${MOCK} ip link add "${IFACE}" type veth ${ARGS} fi elif is_vlan; then if [ -d "/sys/class/net/${IFACE}" ]; then exit 0 fi if [ -z "${MOCK}" ]; then if [ ! -d "/sys/class/net/${IF_VLAN_RAW_DEVICE}" ]; then echo "Underlay device ${IF_VLAN_RAW_DEVICE} for ${IFACE} does not exist" exit 1 fi if ! [ -d /proc/net/vlan ]; then echo "Loading 8021q kernel module for VLAN support" ${MOCK} modprobe 8021q fi fi ${MOCK} ip link add link "${IF_VLAN_RAW_DEVICE}" name "${IFACE}" type vlan id "${IF_VLAN_ID}" fi ;; up) IF_LINK_OPTIONS="$IF_LINK_OPTIONS" [ -n "$IF_MTU" ] && IF_LINK_OPTIONS="$IF_LINK_OPTIONS mtu $IF_MTU" [ -n "$IF_HWADDRESS" ] && IF_LINK_OPTIONS="$IF_LINK_OPTIONS address $IF_HWADDRESS" ${MOCK} ip link set up dev "${IFACE}" ${IF_LINK_OPTIONS} # Set alias is configured if [ "${IF_ALIAS}" ]; then ${MOCK} ip link set alias "${IF_ALIAS}" dev "${IFACE}" fi ;; down) # Don't complain about a vanished interface when downing it if [ -z "${MOCK}" -a ! -d "/sys/class/net/${IFACE}" ]; then exit 0 fi ${MOCK} ip link set down dev "${IFACE}" ;; destroy) if [ "${IF_LINK_TYPE}" = "dummy" ] || [ "${IF_LINK_TYPE}" = "veth" ] || is_vlan; then if [ -z "${MOCK}" -a ! -d "/sys/class/net/${IFACE}" ]; then exit 0 fi ${MOCK} ip link del "${IFACE}" fi ;; esac ifupdown-ng-ifupdown-ng-0.12.1/executor-scripts/linux/mpls000077500000000000000000000015011422731055100236430ustar00rootroot00000000000000#!/bin/sh # # Maximilian Wilhelm # -- Thu, 17 Dec 2020 03:02:10 +0100 # # This executor is responsible for setting up MPLS decapsulation on a given interface. # # See interfaces-mpls(5) for a list of supported options. # yesno() { case "$1" in yes|1) echo 1 ;; *) echo 0 ;; esac } [ -z "$VERBOSE" ] || set -x # We only operate in pre-up phase [ "$PHASE" != "pre-up" ] && exit 0 if [ "$IF_MPLS_ENABLE" ]; then value=$(yesno $IF_MPLS_ENABLE) # Load mpls module if we should enable MPLS decap on (at least) one interface if [ "${value}" = 1 ]; then ${MOCK} modprobe mpls_iptunnel fi # If MPLS support isn't loaded and we are not MOCKing, carry on if [ -f "/proc/sys/net/mpls/conf/$IFACE/input" -o "${MOCK}" ]; then ${MOCK} /bin/sh -c "echo ${value} > /proc/sys/net/mpls/conf/$IFACE/input" fi fi ifupdown-ng-ifupdown-ng-0.12.1/executor-scripts/linux/ppp000077500000000000000000000002771422731055100235000ustar00rootroot00000000000000#!/bin/sh [ -z "$IF_PPP_PROVIDER" ] && exit 0 case "$PHASE" in create) ${MOCK} pon $IF_PPP_PROVIDER ;; destroy) ${MOCK} poff $IF_PPP_PROVIDER ;; depend) echo "$IF_PPP_PHYSDEV" ;; esac ifupdown-ng-ifupdown-ng-0.12.1/executor-scripts/linux/static000077500000000000000000000020571422731055100241660ustar00rootroot00000000000000#!/bin/sh [ -z "${VERBOSE}" ] || set -x [ -z "${IF_METRIC}" ] && IF_METRIC="1" [ -n "${IF_VRF_TABLE}" ] && VRF_TABLE="table ${IF_VRF_TABLE}" [ -n "${IF_VRF_MEMBER}" ] && VRF_TABLE="vrf ${IF_VRF_MEMBER}" [ -n "${IF_METRIC}" ] && METRIC="metric ${IF_METRIC}" addr_family() { if [ "$1" != "${1#*[0-9].[0-9]}" ]; then echo "-4" elif [ "$1" != "${1#*:[0-9a-fA-F]}" ]; then echo "-6" else exit 1 fi } configure_addresses() { for addr in ${IF_ADDRESSES}; do addrfam=$(addr_family ${addr}) if [ "${IF_POINT_TO_POINT}" -a "${addrfam}" = "-4" ]; then PEER="peer ${IF_POINT_TO_POINT}" else PEER="" fi ${MOCK} ip "${addrfam}" addr add "${addr}" ${PEER} dev "${IFACE}" done } configure_gateways() { for gw in ${IF_GATEWAYS}; do addrfam=$(addr_family ${gw}) ${MOCK} ip "${addrfam}" route add default via "${gw}" ${VRF_TABLE} ${METRIC} dev "${IFACE}" done } flush() { cmd="addr" arg="dev ${IFACE}" ${MOCK} ip ${cmd} flush ${arg} } case "$PHASE" in up) configure_addresses add configure_gateways add ;; down) flush ;; *) exit 0 ;; esac ifupdown-ng-ifupdown-ng-0.12.1/executor-scripts/linux/tunnel000077500000000000000000000062651422731055100242110ustar00rootroot00000000000000#!/bin/sh # Based on alpine's tunnel configuration script. # Copyright (c) 2017 Kaarle Ritvanen # Copyright (c) 2020 Ariadne Conill (extended for ifupdown-ng) # Copyright (c) 2021 Maximilian Wilhelm (make sure mode/type is 1st parameter, add more options) [ -z "$IF_TUNNEL_LOCAL" -a -z "$IF_TUNNEL_LOCAL_DEV" ] && exit 1 [ -z "$IF_TUNNEL_REMOTE" ] && exit 1 [ -z "$IF_TUNNEL_MODE" ] && exit 1 [ -n "$VERBOSE" ] && set -x yesno() { case "$1" in yes|1) echo 1 ;; *) echo 0 ;; esac } # Figure out address familiy FAMILY="4" case "$IF_TUNNEL_MODE" in vti6|ipip6|ip6*) FAMILY="6" ;; esac # Figure out object type - gretap tunnels have to create using ip link # and therefor require 'type' keyword instead of 'mode' OBJECT="tunnel" TYPE_KW="mode" case "${IF_TUNNEL_MODE}" in *gretap) OBJECT="link" TYPE_KW="type" # Strip possible "ip6" from tunnel mode TUNNEL_MODE="gretap" ;; *) # Store tunnel type/mode separaltely and unset input variable to exclude it # from PARAMS below TUNNEL_MODE="$IF_TUNNEL_MODE" unset IF_TUNNEL_MODE ;; esac # If 'tunnel-local ' was not given but 'tunnel-local-dev ' is given try # to figure out the IP of the underlay device (wrt the address family used for this # tunnel) and use this to set up the tunnel if [ ${PHASE} = "create" -a ! "${IF_TUNNEL_LOCAL}" -a "${IF_TUNNEL_LOCAL_DEV}" ]; then if [ "${FAMILY}" = "4" ]; then ip=$(ip -4 -brief addr show dev "${IF_TUNNEL_LOCAL_DEV}" 2>/dev/null | awk '{ print $3 }' | cut -d/ -f1) # For IPv6 we try to use a non-temporary address (-> privacy extensions) else # Get all IPv6 addres configured on $IF_TUNNEL_LOCAL_DEV which are not # temporary (due to privacy extensions). We do not filter for "mgmtaddr" # "scope global" etc. as we don't want to make further assumptions on # whether a user wants to use a link local address configured to this interface. # # The assumption that a temporary address configured by PE isn't suited # to terminate a tunnel should hold in nearly all setups, I hope. ip=$(ip -6 addr show dev "${IF_TUNNEL_LOCAL_DEV}" -temporary | grep inet6 | head -n1 | awk '{ print $2 }' | cut -d/ -f1) fi if [ ! "${ip}" ]; then echo "Unable to determine the IPv${FAMILIY} address of tunnel-local-dev ${IF_TUNNEL_LOCAL_DEV}!" exit 1 fi unset IF_TUNNEL_LOCAL_DEV export IF_TUNNEL_LOCAL="${ip}" fi # Handle boolean switches MORE_PARAMS="" if [ "${IF_TUNNEL_IGNORE_DF}" ]; then if $(yesno "${IF_TUNNEL_IGNORE_DF}"); then MORE_PARAMS="ignore-df" else MORE_PARAMS="noignore-df" fi unset IF_TUNNEL_IGNORE_DF fi if [ "${IF_TUNNEL_PMTUDISC}" ]; then if $(yesno "${IF_TUNNEL_PMTUDISC}"); then MORE_PARAMS="pmtudisc" else MORE_PARAMS="nopmtudisc" fi unset IF_TUNNEL_PMTUDISC fi # Mangle residual IF_TUNNEL_* params into single string PARAMS=$(set | sed -E ' s/^IF_TUNNEL_([A-Z0-9_]+)=(.+)/\1\n\2/ ta d :a h y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ P g s/.*\n// ') [ "$PARAMS" ] || exit 0 case "$PHASE" in create) ${MOCK} eval ip -$FAMILY $OBJECT add $IFACE $TYPE_KW $TUNNEL_MODE $PARAMS $MORE_PARAMS ;; destroy) ${MOCK} ip -$FAMILY $OBJECT del $IFACE ;; depend) echo "${IF_TUNNEL_DEV}" "${IF_TUNNEL_LOCAL_DEV}" ;; esac ifupdown-ng-ifupdown-ng-0.12.1/executor-scripts/linux/vrf000077500000000000000000000010501422731055100234640ustar00rootroot00000000000000#!/bin/sh handle_init() { ${MOCK} /sbin/ip link $1 $IFACE type vrf table $IF_VRF_TABLE ${MOCK} /sbin/ip rule $1 iif $IFACE table $IF_VRF_TABLE ${MOCK} /sbin/ip rule $1 oif $IFACE table $IF_VRF_TABLE } handle_member() { ${MOCK} /sbin/ip link set $IFACE master $IF_VRF_MEMBER } [ -n "$VERBOSE" ] && set -x case "$PHASE" in create) [ -n "$IF_VRF_TABLE" ] && handle_init "add" ;; pre-up) [ -n "$IF_VRF_MEMBER" ] && handle_member ;; destroy) [ -n "$IF_VRF_TABLE" ] && handle_init "del" ;; depend) echo "$IF_VRF_MEMBER" ;; *) exit 0 ;; esac ifupdown-ng-ifupdown-ng-0.12.1/executor-scripts/linux/vxlan000077500000000000000000000055411422731055100240300ustar00rootroot00000000000000#!/bin/sh # # This executor is responsible for setting up the Virtual Extensible LAN (VXLAN) overlay interfaces. # # Fri, 02 Oct 2020 01:10:29 +0200 # -- Maximilian Wilhelm # # Known options for the main interface are: # # IF_VXLAN_ID The VXLAN Network Identifier (VNI) # IF_VXLAN_PHYSDEV Specifies the physical device to use for tunnel endpoint communication # IF_VXLAN_LOCAL_IP Specifies the source IP address to use in outgoing packets # IF_VXLAN_PEER_IPS Space separated list of IPs of the remote VTEP endpoint (for ptp/ptmp mode with ingress replication) # IF_VXLAN_PEER_GROUP Multicast group to use for this VNI (for ptmp mode with multicast) # IF_VXLAN_LEARNING Wether to activate MAC learning on this instance (on/off) # IF_VXLAN_AGEING Specifies the lifetime in seconds of FDB entries learnt by the kernel # IF_VXLAN_DSTPORT UDP destination port to communicate to the remote VXLAN tunnel endpoint (default 4789) # [ -n "$VERBOSE" ] && set -x # No VNI, nuthin' to do for us if [ ! "${IF_VXLAN_ID}" ]; then exit 0 fi case "$PHASE" in depend) if [ "${IF_VXLAN_PHYSDEV}" ]; then echo "${IF_VXLAN_PHYSDEV}" fi ;; create) if [ -d "/sys/class/net/${IFACE}" ]; then exit 0 fi # Input validation if [ "${IF_VXLAN_PEER_IPS}" -a "${IF_VXLAN_PEER_GROUP}" ]; then echo "Error on ${IFACE} (vxlan): Only one of 'vxlan-peer-ips' and 'vxlan-peer-group' can be used!" >&2 exit 1 fi # Check if we should operate in unicast ptp or ptmp mode if [ "${IF_VXLAN_PEER_IPS}" ]; then # If it's only one thing which looks like an IPv4/IPv6 address we assume it's ptp if echo "${IF_VXLAN_PEER_IPS}" | grep -q '^[[:space:]]*[[:xdigit:].:]\+[[:space:]]*$'; then UCAST_MODE="ptp" else UCAST_MODE="ptmp" fi fi # Gather arguments ARGS="" [ "${IF_VXLAN_PHYSDEV}" ] && ARGS="${ARGS} dev ${IF_VXLAN_PHYSDEV}" [ "${IF_VXLAN_LOCAL_IP}" ] && ARGS="${ARGS} local ${IF_VXLAN_LOCAL_IP}" [ "${UCAST_MODE}" = "ptp" ] && ARGS="${ARGS} remote ${IF_VXLAN_PEER_IPS}" [ "${IF_VXLAN_PEER_GROUP}" ] && ARGS="${ARGS} group ${IF_VXLAN_PEER_GROUP}" [ "${IF_VXLAN_AGEING}" ] && ARGS="${ARGS} ageing ${IF_VXLAN_AGEING}" # Linux uses non-standard default port - WTF? if [ "${IF_VXLAN_DSTPORT}" ]; then ARGS="${ARGS} dstport ${IF_VXLAN_DSTPORT}" else ARGS="${ARGS} dstport 4789" fi case "${IF_VXLAN_LEARNING}" in on|yes) ARGS="${ARGS} learning" ;; off|no) ARGS="${ARGS} nolearning" ;; esac ${MOCK} ip link add "${IFACE}" type vxlan id "${IF_VXLAN_ID}" ${ARGS} # Set up FDB entries for peer VTEPs if [ "${UCAST_MODE}" = "ptmp" ]; then for peer in ${IF_VXLAN_PEER_IPS}; do ${MOCK} bridge fdb append 00:00:00:00:00:00 dev "${IFACE}" dst "${peer}" self permanent done fi ;; destroy) if [ -z "${MOCK}" -a ! -d "/sys/class/net/${IFACE}" ]; then exit 0 fi ${MOCK} ip link del "${IFACE}" ;; esac ifupdown-ng-ifupdown-ng-0.12.1/executor-scripts/linux/wifi000077500000000000000000000067261422731055100236440ustar00rootroot00000000000000#!/bin/sh # Copyright (c) 2020 Ariadne Conill # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # This software is provided 'as is' and without any warranty, express or # implied. In no event shall the authors be liable for any damages arising # from the use of this software. # # Manage wifi connections using wpa_supplicant. # # Vocabulary: # wifi-ssid - The SSID name to connect to. # wifi-psk - The pre-shared key to use. # wifi-config - A path to a wpa_supplicant config file, for special configs. # # If wifi-config is not set, wifi-ssid and wifi-psk are required, and a config # will be generated as /run/wpa_supplicant.$IFACE.conf. # # The wpa_supplicant PID is stored in /run/wpa_supplicant.$IFACE.pid. die() { printf "ERROR: %s\n" "$1" >&2 exit 1 } [ -z "$IFACE" ] && die "IFACE not set" [ -z "$PHASE" ] && die "PHASE not set" PIDFILE="/run/wpa_supplicant.$IFACE.pid" # Do not allow mixing wifi-config-path and wifi-ssid/wifi-psk. [ -n "$IF_WIFI_CONFIG_PATH" -a -n "$IF_WIFI_SSID" ] && die "wifi-config-path cannot be used with wifi-ssid" [ -n "$IF_WIFI_CONFIG_PATH" -a -n "$IF_WIFI_PSK" ] && die "wifi-config-path cannot be used with wifi-psk" # Set IF_WIFI_CONFIG_PATH to the default path if not already set. WIFI_CONFIG_PATH="$IF_WIFI_CONFIG_PATH" [ -z "$WIFI_CONFIG_PATH" ] && WIFI_CONFIG_PATH="/run/wpa_supplicant.$IFACE.conf" # Supplicant options. WPA_SUPPLICANT_OPTS="-qq -B -i$IFACE -c$WIFI_CONFIG_PATH -P$PIDFILE" # Given $IF_WIFI_SSID and $IF_WIFI_PSK, generate a config file at $WIFI_CONFIG_PATH. generate_config() { [ -z "$IF_WIFI_SSID" ] && die "wifi-ssid not set" [ -z "$IF_WIFI_PSK" ] && die "wifi-psk not set" # We use a pipeline here to avoid leaking PSK into the process name. (echo "$IF_WIFI_PSK" | /sbin/wpa_passphrase "$IF_WIFI_SSID") >$WIFI_CONFIG_PATH [ ! -e "$WIFI_CONFIG_PATH" ] && die "failed to write temporary config: $WIFI_CONFIG_PATH" } # Should we use the supplicant? use_supplicant() { [ -n "$IF_WIFI_CONFIG_PATH" ] && return 0 [ -n "$IF_WIFI_PSK" ] && return 0 return 1 } # Either start a supplicant process for $IFACE, or use iwconfig to trigger an # association attempt. start() { if use_supplicant; then # If there is no config file located at $WIFI_CONFIG_PATH, generate one. [ ! -e "$WIFI_CONFIG_PATH" ] && generate_config /sbin/wpa_supplicant $WPA_SUPPLICANT_OPTS else /usr/sbin/iwconfig $IFACE essid -- "$IF_WIFI_SSID" ap any fi } # Stop wpa_supplicant safely stop_wpa_supplicant() { # Remove generated config file [ -z "$IF_WIFI_CONFIG_PATH" ] && rm -- "$WIFI_CONFIG_PATH" # If there is no PIDFILE, there is nothing we can do [ ! -f "$PIDFILE" ] && return pid=$(cat "$PIDFILE") rm -- "$PIDFILE" # If there is no process with this PID running, we're done here if [ ! -d "/proc/$pid/" ]; then return fi # Verify that the name of the running process matches wpa_supplicant progname_path=$(readlink -n "/proc/$pid/exe") progname=$(basename "$progname_path") if [ "$progname" = "wpa_supplicant" ]; then kill -9 $pid 2>/dev/null fi } # Either stop the supplicant process for $IFACE, or use iwconfig to dissociate # from the current SSID. stop() { if use_supplicant; then stop_wpa_supplicant else /usr/sbin/iwconfig $IFACE essid any fi } [ -z "$VERBOSE" ] || set -x case "$PHASE" in pre-up) start ;; post-down) stop ;; esac ifupdown-ng-ifupdown-ng-0.12.1/executor-scripts/linux/wireguard000077500000000000000000000005011422731055100246600ustar00rootroot00000000000000#!/bin/sh [ -n "$VERBOSE" ] && set -x [ -z "$IF_WIREGUARD_CONFIG_PATH" ] && IF_WIREGUARD_CONFIG_PATH="/etc/wireguard/$IFACE.conf" case "$PHASE" in create) ${MOCK} ip link add $IFACE type wireguard ;; pre-up) ${MOCK} wg setconf $IFACE $IF_WIREGUARD_CONFIG_PATH ;; destroy) ${MOCK} ip link delete dev $IFACE ;; esac ifupdown-ng-ifupdown-ng-0.12.1/executor-scripts/linux/wireguard-quick000077500000000000000000000002201422731055100257700ustar00rootroot00000000000000#!/bin/sh [ -n "$VERBOSE" ] && set -x case "$PHASE" in create) ${MOCK} wg-quick up $IFACE ;; destroy) ${MOCK} wg-quick down $IFACE ;; esac ifupdown-ng-ifupdown-ng-0.12.1/executor-scripts/stub/000077500000000000000000000000001422731055100225635ustar00rootroot00000000000000ifupdown-ng-ifupdown-ng-0.12.1/executor-scripts/stub/bond000077500000000000000000000002021422731055100234250ustar00rootroot00000000000000#!/bin/sh [ -z "$IF_BOND_MEMBERS" ] && IF_BOND_MEMBERS="$IF_BOND_SLAVES" case "$PHASE" in depend) echo "$IF_BOND_MEMBERS" ;; esac ifupdown-ng-ifupdown-ng-0.12.1/executor-scripts/stub/bridge000077500000000000000000000001651422731055100237470ustar00rootroot00000000000000#!/bin/sh case "$PHASE" in depend) if [ "$IF_BRIDGE_PORTS" != "none" ]; then echo "$IF_BRIDGE_PORTS" fi ;; esac ifupdown-ng-ifupdown-ng-0.12.1/libifupdown/000077500000000000000000000000001422731055100206055ustar00rootroot00000000000000ifupdown-ng-ifupdown-ng-0.12.1/libifupdown/compat.c000066400000000000000000000070011422731055100222320ustar00rootroot00000000000000/* * libifupdown/compat.c * Purpose: compatiblity glue to other implementations * * Copyright (c) 2020 Maximilian Wilhelm * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * This software is provided 'as is' and without any warranty, express or * implied. In no event shall the authors be liable for any damages arising * from the use of this software. */ #include #include #include #include "libifupdown/compat.h" #include "libifupdown/config-file.h" #include "libifupdown/dict.h" #include "libifupdown/interface.h" #include "libifupdown/tokenize.h" static bool compat_ifupdown2_bridge_ports_inherit_vlans(struct lif_dict *collection) { struct lif_node *iter; /* Loop through all interfaces and search for bridges */ LIF_DICT_FOREACH(iter, collection) { struct lif_dict_entry *entry = iter->data; struct lif_interface *bridge = entry->data; /* We only care for bridges */ if (!bridge->is_bridge) continue; struct lif_dict_entry *bridge_pvid = lif_dict_find(&bridge->vars, "bridge-pvid"); struct lif_dict_entry *bridge_vids = lif_dict_find(&bridge->vars, "bridge-vids"); /* If there's nothing to inherit here, carry on */ if (bridge_pvid == NULL && bridge_vids == NULL) continue; struct lif_dict_entry *bridge_ports_entry = lif_dict_find(&bridge->vars, "bridge-ports"); /* This SHOULD not happen, but better save than sorry */ if (bridge_ports_entry == NULL) continue; char bridge_ports_str[4096] = {}; strlcpy(bridge_ports_str, bridge_ports_entry->data, sizeof bridge_ports_str); /* If there are no bridge-ports configured, carry on */ if (strcmp(bridge_ports_str, "none") == 0) continue; /* Loop over all bridge-ports and set bridge-pvid and bridge-vid if not set already */ char *bufp = bridge_ports_str; for (char *tokenp = lif_next_token(&bufp); *tokenp; tokenp = lif_next_token(&bufp)) { entry = lif_dict_find(collection, tokenp); /* There might be interfaces give within the bridge-ports for which there is no * interface stanza. If this is the case, we add one, so we can inherit the * bridge-vids/pvid to it. */ struct lif_interface *bridge_port; if (entry) bridge_port = entry->data; else if (lif_config.compat_create_interfaces) { bridge_port = lif_interface_collection_find(collection, tokenp); if (bridge_port == NULL) { fprintf(stderr, "Failed to add interface \"%s\"", tokenp); return false; } } /* We would have to creaet an interface, but shouldn't */ else { fprintf(stderr, "compat: Missing interface stanza for bridge-port \"%s\" but should not create one.\n", tokenp); continue; } /* Maybe pimp bridge-pvid */ struct lif_dict_entry *port_pvid = lif_dict_find(&bridge_port->vars, "bridge-pvid"); if (bridge_pvid && !port_pvid) lif_dict_add(&bridge_port->vars, "bridge-pvid", bridge_pvid->data); /* Maybe pimp bridge-vids */ struct lif_dict_entry *port_vids = lif_dict_find(&bridge_port->vars, "bridge-vids"); if (bridge_vids && !port_vids) lif_dict_add(&bridge_port->vars, "bridge-vids", bridge_vids->data); } } return true; } bool lif_compat_apply(struct lif_dict *collection) { if (lif_config.compat_ifupdown2_bridge_ports_inherit_vlans && !compat_ifupdown2_bridge_ports_inherit_vlans(collection)) return false; return true; } ifupdown-ng-ifupdown-ng-0.12.1/libifupdown/compat.h000066400000000000000000000013631422731055100222440ustar00rootroot00000000000000/* * libifupdown/compat.h * Purpose: compatiblity glue to other implementations * * Copyright (c) 2020 Maximilian Wilhelm * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * This software is provided 'as is' and without any warranty, express or * implied. In no event shall the authors be liable for any damages arising * from the use of this software. */ #ifndef LIBIFUPDOWN__COMPAT_H #define LIBIFUPDOWN__COMPAT_H #include "libifupdown/config-file.h" #include "libifupdown/dict.h" extern bool lif_compat_apply (struct lif_dict *collection); #endif ifupdown-ng-ifupdown-ng-0.12.1/libifupdown/config-file.c000066400000000000000000000044051422731055100231360ustar00rootroot00000000000000/* * libifupdown/config-file.c * Purpose: config file loading * * Copyright (c) 2020 Ariadne Conill * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * This software is provided 'as is' and without any warranty, express or * implied. In no event shall the authors be liable for any damages arising * from the use of this software. */ #include #include #include #include "libifupdown/libifupdown.h" struct lif_config_file lif_config = { .allow_addon_scripts = true, .allow_any_iface_as_template = true, .auto_executor_selection = true, .compat_create_interfaces = true, .compat_ifupdown2_bridge_ports_inherit_vlans = true, .implicit_template_conversion = true, .use_hostname_for_dhcp = true, }; static bool set_bool_value(const char *key, const char *value, void *opaque) { (void) key; if (*value == '1' || *value == 'Y' || *value == 'y' || *value == 'T' || *value == 't') *(bool *) opaque = true; else if (*value == '0' || *value == 'N' || *value == 'n' || *value == 'F' || *value == 'f') *(bool *) opaque = false; else return false; return true; } static struct lif_config_handler handlers[] = { {"allow_addon_scripts", set_bool_value, &lif_config.allow_addon_scripts}, {"allow_any_iface_as_template", set_bool_value, &lif_config.allow_any_iface_as_template}, {"auto_executor_selection", set_bool_value, &lif_config.auto_executor_selection}, {"compat_create_interfaces", set_bool_value, &lif_config.compat_create_interfaces}, {"compat_ifupdown2_bridge_ports_inherit_vlans", set_bool_value, &lif_config.compat_ifupdown2_bridge_ports_inherit_vlans}, {"implicit_template_conversion", set_bool_value, &lif_config.implicit_template_conversion}, {"use_hostname_for_dhcp", set_bool_value, &lif_config.use_hostname_for_dhcp}, }; bool lif_config_load(const char *filename) { FILE *fd = fopen(filename, "r"); if (fd == NULL) { #if 0 fprintf(stderr, "ifupdown-ng: cannot open config %s: %s\n", filename, strerror(errno)); #endif return false; } return lif_config_parse_file(fd, filename, handlers, ARRAY_SIZE(handlers)); } ifupdown-ng-ifupdown-ng-0.12.1/libifupdown/config-file.h000066400000000000000000000017631422731055100231470ustar00rootroot00000000000000/* * libifupdown/config-file.h * Purpose: config file loading * * Copyright (c) 2020 Ariadne Conill * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * This software is provided 'as is' and without any warranty, express or * implied. In no event shall the authors be liable for any damages arising * from the use of this software. */ #ifndef LIBIFUPDOWN__CONFIG_FILE_H #define LIBIFUPDOWN__CONFIG_FILE_H #include struct lif_config_file { bool allow_addon_scripts; bool allow_any_iface_as_template; bool auto_executor_selection; bool compat_create_interfaces; bool compat_ifupdown2_bridge_ports_inherit_vlans; bool implicit_template_conversion; bool use_hostname_for_dhcp; }; extern struct lif_config_file lif_config; extern bool lif_config_load(const char *filename); #endif ifupdown-ng-ifupdown-ng-0.12.1/libifupdown/config-parser.c000066400000000000000000000037511422731055100235160ustar00rootroot00000000000000/* * libifupdown/config-parser.c * Purpose: config parsing * * Copyright (c) 2020 Ariadne Conill * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * This software is provided 'as is' and without any warranty, express or * implied. In no event shall the authors be liable for any damages arising * from the use of this software. */ #include #include #include #include #include #include "libifupdown/config-parser.h" #include "libifupdown/fgetline.h" #include "libifupdown/tokenize.h" static int handler_cmp(const void *a, const void *b) { const char *key = a; const struct lif_config_handler *hdl = b; return strcmp(key, hdl->key); } bool lif_config_parse_file(FILE *fd, const char *filename, struct lif_config_handler *handlers, size_t handler_count) { char linebuf[4096]; size_t lineno = 0; while (lif_fgetline(linebuf, sizeof linebuf, fd)) { char *bufp = linebuf; char *key = lif_next_token_eq(&bufp); char *value = lif_next_token_eq(&bufp); lineno++; if (!*key || !*value) continue; if (*key == '#') continue; struct lif_config_handler *hdl = bsearch(key, handlers, handler_count, sizeof(*handlers), handler_cmp); if (hdl == NULL) { fprintf(stderr, "ifupdown-ng: %s:%zu: warning: unknown config setting %s\n", filename, lineno, key); continue; } if (!hdl->handle(key, value, hdl->opaque)) { fclose(fd); return false; } } fclose(fd); return true; } bool lif_config_parse(const char *filename, struct lif_config_handler *handlers, size_t handler_count) { FILE *f = fopen(filename, "r"); if (f == NULL) { fprintf(stderr, "ifupdown-ng: unable to parse %s: %s\n", filename, strerror(errno)); return false; } return lif_config_parse_file(f, filename, handlers, handler_count); } ifupdown-ng-ifupdown-ng-0.12.1/libifupdown/config-parser.h000066400000000000000000000020371422731055100235170ustar00rootroot00000000000000/* * libifupdown/config-parser.h * Purpose: config parsing * * Copyright (c) 2020 Ariadne Conill * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * This software is provided 'as is' and without any warranty, express or * implied. In no event shall the authors be liable for any damages arising * from the use of this software. */ #ifndef LIBIFUPDOWN__CONFIG_PARSER_H #define LIBIFUPDOWN__CONFIG_PARSER_H #include #include #include struct lif_config_handler { const char *key; bool (*handle)(const char *key, const char *value, void *opaque); void *opaque; }; extern bool lif_config_parse_file(FILE *f, const char *filename, struct lif_config_handler *handlers, size_t handler_count); extern bool lif_config_parse(const char *filename, struct lif_config_handler *handlers, size_t handler_count); #endif ifupdown-ng-ifupdown-ng-0.12.1/libifupdown/dict.c000066400000000000000000000057401422731055100217020ustar00rootroot00000000000000/* * libifupdown/dict.c * Purpose: wrapping linked lists to provide a naive dictionary * * Copyright (c) 2020 Ariadne Conill * Copyright (c) 2020 Maximilian Wilhelm * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * This software is provided 'as is' and without any warranty, express or * implied. In no event shall the authors be liable for any damages arising * from the use of this software. */ #include #include #include #include "libifupdown/dict.h" void lif_dict_init(struct lif_dict *dict) { memset(dict, 0, sizeof *dict); } void lif_dict_fini(struct lif_dict *dict) { struct lif_node *iter, *iter_next; LIF_DICT_FOREACH_SAFE(iter, iter_next, dict) { struct lif_dict_entry *entry = iter->data; lif_dict_delete_entry(dict, entry); } } struct lif_dict_entry * lif_dict_add(struct lif_dict *dict, const char *key, void *data) { struct lif_dict_entry *entry = calloc(1, sizeof *entry); entry->key = strdup(key); entry->data = data; lif_node_insert_tail(&entry->node, entry, &dict->list); return entry; } struct lif_dict_entry * lif_dict_add_once(struct lif_dict *dict, const char *key, void *data, lif_dict_cmp_t compar) { struct lif_list *existing = lif_dict_find_all(dict, key); if (existing != NULL) { bool found = false; struct lif_node *iter; LIF_LIST_FOREACH(iter, existing->head) { if (!compar(data, iter->data)) { found = true; break; } } lif_list_free_nodes(existing); if (found) return NULL; } struct lif_dict_entry *entry = calloc(1, sizeof *entry); entry->key = strdup(key); entry->data = data; lif_node_insert_tail(&entry->node, entry, &dict->list); return entry; } struct lif_dict_entry * lif_dict_find(const struct lif_dict *dict, const char *key) { struct lif_node *iter; LIF_DICT_FOREACH(iter, dict) { struct lif_dict_entry *entry = iter->data; if (!strcmp(entry->key, key)) return entry; } return NULL; } struct lif_list * lif_dict_find_all(const struct lif_dict *dict, const char *key) { struct lif_list *entries = calloc(1, sizeof *entries); struct lif_node *iter; LIF_LIST_FOREACH(iter, dict->list.head) { struct lif_dict_entry *entry = iter->data; if (!strcmp(entry->key, key)) { struct lif_node *new = calloc(1, sizeof *new); lif_node_insert_tail(new, entry->data, entries); } } if (entries->length == 0) { free(entries); return NULL; } return entries; } void lif_dict_delete(struct lif_dict *dict, const char *key) { struct lif_dict_entry *entry = lif_dict_find(dict, key); if (entry == NULL) return; lif_dict_delete_entry(dict, entry); } void lif_dict_delete_entry(struct lif_dict *dict, struct lif_dict_entry *entry) { lif_node_delete(&entry->node, &dict->list); free(entry->key); free(entry); } ifupdown-ng-ifupdown-ng-0.12.1/libifupdown/dict.h000066400000000000000000000035301422731055100217020ustar00rootroot00000000000000/* * libifupdown/dict.h * Purpose: wrapping linked lists to provide a naive dictionary * * Copyright (c) 2020 Ariadne Conill * Copyright (c) 2020 Maximilian Wilhelm * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * This software is provided 'as is' and without any warranty, express or * implied. In no event shall the authors be liable for any damages arising * from the use of this software. */ #ifndef LIBIFUPDOWN_DICT_H__GUARD #define LIBIFUPDOWN_DICT_H__GUARD #include "libifupdown/list.h" struct lif_dict { struct lif_list list; }; struct lif_dict_entry { struct lif_node node; char *key; void *data; }; #define LIF_DICT_FOREACH(iter, dict) \ LIF_LIST_FOREACH((iter), (dict)->list.head) #define LIF_DICT_FOREACH_SAFE(iter, iter_next, dict) \ LIF_LIST_FOREACH_SAFE((iter), (iter_next), (dict)->list.head) #define LIF_DICT_FOREACH_REVERSE(iter, dict) \ LIF_LIST_FOREACH_REVERSE((iter), (dict)->list.tail) typedef int (*lif_dict_cmp_t)(const void *, const void *); extern void lif_dict_init(struct lif_dict *dict); extern void lif_dict_fini(struct lif_dict *dict); extern struct lif_dict_entry *lif_dict_add(struct lif_dict *dict, const char *key, void *data); extern struct lif_dict_entry *lif_dict_add_once(struct lif_dict *dict, const char *key, void *data, lif_dict_cmp_t compar); extern struct lif_dict_entry *lif_dict_find(const struct lif_dict *dict, const char *key); extern struct lif_list *lif_dict_find_all(const struct lif_dict *dict, const char *key); extern void lif_dict_delete(struct lif_dict *dict, const char *key); extern void lif_dict_delete_entry(struct lif_dict *dict, struct lif_dict_entry *entry); #endif ifupdown-ng-ifupdown-ng-0.12.1/libifupdown/environment.c000066400000000000000000000026001422731055100233130ustar00rootroot00000000000000/* * libifupdown/environment.c * Purpose: environment variable management * * Copyright (c) 2020 Ariadne Conill * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * This software is provided 'as is' and without any warranty, express or * implied. In no event shall the authors be liable for any damages arising * from the use of this software. */ #include #include #include #include "libifupdown/environment.h" bool lif_environment_push(char **env[], const char *name, const char *val) { char buf[4096]; snprintf(buf, sizeof buf, "%s=%s", name, val); /* create an initial envp: {"foo=bar", NULL} */ if (*env == NULL) { *env = calloc(2, sizeof (char *)); (*env)[0] = strdup(buf); (*env)[1] = NULL; return true; } size_t nelems; for (nelems = 0; (*env)[nelems] != NULL; nelems++) ; /* NULL at end, plus next env var */ size_t allocelems = nelems + 2; *env = realloc(*env, ((allocelems + 2) * sizeof (char *))); (*env)[nelems] = strdup(buf); (*env)[nelems + 1] = NULL; return true; } void lif_environment_free(char **env[]) { size_t nelems; for (nelems = 0; (*env)[nelems] != NULL; nelems++) free((*env)[nelems]); free(*env); } ifupdown-ng-ifupdown-ng-0.12.1/libifupdown/environment.h000066400000000000000000000014421422731055100233230ustar00rootroot00000000000000/* * libifupdown/environment.h * Purpose: environment variable management * * Copyright (c) 2020 Ariadne Conill * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * This software is provided 'as is' and without any warranty, express or * implied. In no event shall the authors be liable for any damages arising * from the use of this software. */ #ifndef LIBIFUPDOWN_ENVIRONMENT_H__GUARD #define LIBIFUPDOWN_ENVIRONMENT_H__GUARD #include extern bool lif_environment_push(char **env[], const char *name, const char *val); extern void lif_environment_free(char **env[]); #endif ifupdown-ng-ifupdown-ng-0.12.1/libifupdown/execute.c000066400000000000000000000132341422731055100224160ustar00rootroot00000000000000/* * libifupdown/execute.c * Purpose: execution of individual commands * * Copyright (c) 2020 Ariadne Conill * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * This software is provided 'as is' and without any warranty, express or * implied. In no event shall the authors be liable for any damages arising * from the use of this software. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "libifupdown/execute.h" #define SHELL "/bin/sh" #if defined(__linux__) # include #endif /* POSIX compatible fallback using waitpid(2) and usleep(3) */ static inline bool lif_process_monitor_busyloop(pid_t child, int timeout_sec, int *status) { int ticks = 0; while (ticks < timeout_sec * 20) { /* Ugly hack: most executors finish very quickly, * so give them a chance to finish before sleeping. */ usleep(50); if (waitpid(child, status, WNOHANG) == child) return true; usleep(49950); ticks++; } return false; } #if defined(__linux__) && defined(__NR_pidfd_open) /* TODO: remove this wrapper once musl and glibc gain pidfd_open() directly. */ static inline int lif_pidfd_open(pid_t pid, unsigned int flags) { return syscall(__NR_pidfd_open, pid, flags); } static inline bool lif_process_monitor_procdesc(pid_t child, int timeout_sec, int *status) { int pidfd = lif_pidfd_open(child, 0); /* pidfd_open() not available, fall back to busyloop */ if (pidfd == -1 && errno == ENOSYS) return lif_process_monitor_busyloop(child, timeout_sec, status); struct pollfd pfd = { .fd = pidfd, .events = POLLIN, }; if (poll(&pfd, 1, timeout_sec * 1000) < 1) return false; waitpid(child, status, 0); close(pidfd); return true; } #endif static inline bool lif_process_monitor(const char *cmdbuf, pid_t child, int timeout_sec) { int status; #if defined(__linux__) && defined(__NR_pidfd_open) if (lif_process_monitor_procdesc(child, timeout_sec, &status)) return WIFEXITED(status) && WEXITSTATUS(status) == 0; #else if (lif_process_monitor_busyloop(child, timeout_sec, &status)) return WIFEXITED(status) && WEXITSTATUS(status) == 0; #endif fprintf(stderr, "execution of '%s': timeout after %d seconds\n", cmdbuf, timeout_sec); kill(child, SIGKILL); waitpid(child, &status, 0); return false; } bool lif_execute_fmt(const struct lif_execute_opts *opts, char *const envp[], const char *fmt, ...) { char cmdbuf[4096]; va_list va; va_start(va, fmt); vsnprintf(cmdbuf, sizeof cmdbuf, fmt, va); va_end(va); pid_t child; char *argv[] = { SHELL, "-c", cmdbuf, NULL }; if (opts->verbose) puts(cmdbuf); if (opts->mock) return true; if (posix_spawn(&child, SHELL, NULL, NULL, argv, envp) != 0) { fprintf(stderr, "execute '%s': %s\n", cmdbuf, strerror(errno)); return false; } return lif_process_monitor(cmdbuf, child, opts->timeout); } bool lif_execute_fmt_with_result(const struct lif_execute_opts *opts, char *buf, size_t bufsize, char *const envp[], const char *fmt, ...) { char cmdbuf[4096]; va_list va; va_start(va, fmt); vsnprintf(cmdbuf, sizeof cmdbuf, fmt, va); va_end(va); pid_t child; char *argv[] = { SHELL, "-c", cmdbuf, NULL }; if (opts->verbose) puts(cmdbuf); if (opts->mock) return true; int pipefds[2]; if (pipe(pipefds) < 0) { fprintf(stderr, "execute '%s': %s\n", cmdbuf, strerror(errno)); return false; } posix_spawn_file_actions_t file_actions; posix_spawn_file_actions_init(&file_actions); posix_spawn_file_actions_addclose(&file_actions, pipefds[0]); posix_spawn_file_actions_adddup2(&file_actions, pipefds[1], 1); posix_spawn_file_actions_addclose(&file_actions, pipefds[1]); if (posix_spawn(&child, SHELL, &file_actions, NULL, argv, envp) != 0) { fprintf(stderr, "execute '%s': %s\n", cmdbuf, strerror(errno)); return false; } posix_spawn_file_actions_destroy(&file_actions); close(pipefds[1]); struct pollfd pfd = { .fd = pipefds[0], .events = POLLIN }; if (poll(&pfd, 1, -1) < 1) goto no_result; if (read(pipefds[0], buf, bufsize) < 0) { fprintf(stderr, "reading from pipe: %s\n", strerror(errno)); return false; } no_result: return lif_process_monitor(cmdbuf, child, opts->timeout); } bool lif_file_is_executable(const char *path) { struct stat st; if (stat(path, &st)) return false; if (!S_ISREG(st.st_mode)) return false; return !access(path, X_OK); } bool lif_maybe_run_executor(const struct lif_execute_opts *opts, char *const envp[], const char *executor, const char *phase, const char *lifname) { if (opts->verbose) fprintf(stderr, "ifupdown: %s: attempting to run %s executor for phase %s\n", lifname, executor, phase); char pathbuf[4096]; snprintf(pathbuf, sizeof pathbuf, "%s/%s", opts->executor_path, executor); if (!lif_file_is_executable(pathbuf)) return true; return lif_execute_fmt(opts, envp, "%s", pathbuf); } bool lif_maybe_run_executor_with_result(const struct lif_execute_opts *opts, char *const envp[], const char *executor, char *buf, size_t bufsize, const char *phase, const char *lifname) { if (opts->verbose) fprintf(stderr, "ifupdown: %s: attempting to run %s executor for phase %s\n", lifname, executor, phase); char pathbuf[4096]; snprintf(pathbuf, sizeof pathbuf, "%s/%s", opts->executor_path, executor); if (!lif_file_is_executable(pathbuf)) return true; return lif_execute_fmt_with_result(opts, buf, bufsize, envp, "%s", pathbuf); } ifupdown-ng-ifupdown-ng-0.12.1/libifupdown/execute.h000066400000000000000000000027601422731055100224250ustar00rootroot00000000000000/* * libifupdown/execute.h * Purpose: execution of individual commands * * Copyright (c) 2020 Ariadne Conill * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * This software is provided 'as is' and without any warranty, express or * implied. In no event shall the authors be liable for any damages arising * from the use of this software. */ #ifndef LIBIFUPDOWN_EXECUTE_H__GUARD #define LIBIFUPDOWN_EXECUTE_H__GUARD #include #include struct lif_execute_opts { bool verbose; bool mock; bool no_lock; bool force; const char *executor_path; const char *interfaces_file; const char *state_file; int timeout; }; extern bool lif_execute_fmt(const struct lif_execute_opts *opts, char *const envp[], const char *fmt, ...); extern bool lif_execute_fmt_with_result(const struct lif_execute_opts *opts, char *buf, size_t bufsize, char *const envp[], const char *fmt, ...); extern bool lif_file_is_executable(const char *path); extern bool lif_maybe_run_executor(const struct lif_execute_opts *opts, char *const envp[], const char *executor, const char *phase, const char *lifname); extern bool lif_maybe_run_executor_with_result(const struct lif_execute_opts *opts, char *const envp[], const char *executor, char *buf, size_t bufsize, const char *phase, const char *lifname); #endif ifupdown-ng-ifupdown-ng-0.12.1/libifupdown/fgetline.c000066400000000000000000000037021422731055100225500ustar00rootroot00000000000000/* * libifupdown/fgetline.c * Purpose: portable fgetline(3) * * Copyright (c) 2020 Ariadne Conill * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * This software is provided 'as is' and without any warranty, express or * implied. In no event shall the authors be liable for any damages arising * from the use of this software. */ #include #include #include #include "libifupdown/fgetline.h" char * lif_fgetline(char *line, size_t size, FILE *stream) { char *s = line; char *end = line + size - 2; bool quoted = false; int c = '\0', c2; if (s == NULL) return NULL; while (s < end && (c = getc(stream)) != EOF) { if (c == '\\' && !quoted) { quoted = true; continue; } else if (c == '#') { if (!quoted) { /* Skip the rest of the line */ do { c = getc(stream); } while (c != '\n' && c != EOF); *s++ = c; break; } quoted = false; continue; } else if (c == '\n') { if (quoted) { /* Trim spaces */ do { c2 = getc(stream); } while (c2 == '\t' || c2 == ' '); ungetc(c2, stream); quoted = false; continue; } else { *s++ = c; } break; } else if (c == '\r') { *s++ = '\n'; if ((c2 = getc(stream)) == '\n') { if (quoted) { quoted = false; continue; } break; } ungetc(c2, stream); if (quoted) { quoted = false; continue; } break; } else { if (quoted) { *s++ = '\\'; quoted = false; } *s++ = c; } } if (c == EOF && (s == line || ferror(stream))) return NULL; *s = '\0'; /* Remove newline character. */ if (s > line && *(--s) == '\n') { *s = '\0'; if (s > line && *(--s) == '\r') *s = '\0'; } return line; } ifupdown-ng-ifupdown-ng-0.12.1/libifupdown/fgetline.h000066400000000000000000000013641422731055100225570ustar00rootroot00000000000000/* * libifupdown/fgetline.h * Purpose: portable fgetline(3) * * Copyright (c) 2020 Ariadne Conill * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * This software is provided 'as is' and without any warranty, express or * implied. In no event shall the authors be liable for any damages arising * from the use of this software. */ #include #include #include #ifndef LIBIFUPDOWN_FGETLINE_H__GUARD #define LIBIFUPDOWN_FGETLINE_H__GUARD extern char *lif_fgetline(char *line, size_t size, FILE *stream); #endif ifupdown-ng-ifupdown-ng-0.12.1/libifupdown/interface-file.c000066400000000000000000000414401422731055100236310ustar00rootroot00000000000000/* * libifupdown/interface-file.h * Purpose: /etc/network/interfaces parser * * Copyright (c) 2020 Ariadne Conill * Copyright (c) 2020 Maximilian Wilhelm * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * This software is provided 'as is' and without any warranty, express or * implied. In no event shall the authors be liable for any damages arising * from the use of this software. */ #include #include #include #include #include #include #include "libifupdown/libifupdown.h" /* internally rewrite problematic ifupdown2 tokens to ifupdown-ng equivalents */ struct remap_token { const char *token; const char *alternative; }; /* this list must be in alphabetical order for bsearch */ static const struct remap_token tokens[] = { {"bond-ad-sys-priority", "bond-ad-actor-sys-prio"}, /* ifupdown2 */ {"bond-slaves", "bond-members"}, /* legacy ifupdown, ifupdown2 */ {"client", "dhcp-client-id"}, /* legacy ifupdown */ {"driver-message-level", "ethtool-msglvl"}, /* Debian ethtool integration */ {"endpoint", "tunnel-remote"}, /* legacy ifupdown */ {"ethernet-autoneg", "ethtool-ethernet-autoneg"}, /* Debian ethtool integration */ {"ethernet-pause-autoneg", "ethtool-pause-autoneg"}, /* Debian ethtool integration */ {"ethernet-pause-rx", "ethtool-pause-rx"}, /* Debian ethtool integration */ {"ethernet-pause-tx", "ethtool-pause-tx"}, /* Debian ethtool integration */ {"ethernet-port", "ethtool-ethernet-port"}, /* Debian ethtool integration */ {"ethernet-wol", "ethtool-ethernet-wol"}, /* Debian ethtool integration */ {"gro-offload", "ethtool-offload-gro"}, /* ifupdown2 */ {"gso-offload", "ethtool-offload-gso"}, /* ifupdown2 */ {"hardware-dma-ring-rx", "ethtool-dma-ring-rx"}, /* Debian ethtool integration */ {"hardware-dma-ring-rx-jumbo", "ethtool-dma-ring-rx-jumbo"}, /* Debian ethtool integration */ {"hardware-dma-ring-rx-mini", "ethtool-dma-ring-rx-mini"}, /* Debian ethtool integration */ {"hardware-dma-ring-tx", "ethtool-dma-ring-tx"}, /* Debian ethtool integration */ {"hardware-irq-coalesce-adaptive-rx", "ethtool-coalesce-adaptive-rx"}, /* Debian ethtool integration */ {"hardware-irq-coalesce-adaptive-tx", "ethtool-coalesce-adaptive-tx"}, /* Debian ethtool integration */ {"hardware-irq-coalesce-pkt-rate-high", "ethtool-coalesce-pkt-rate-high"}, /* Debian ethtool integration */ {"hardware-irq-coalesce-pkt-rate-low", "ethtool-coalesce-pkt-rate-low"}, /* Debian ethtool integration */ {"hardware-irq-coalesce-rx-frames", "ethtool-coalesce-rx-frames"}, /* Debian ethtool integration */ {"hardware-irq-coalesce-rx-frames-high", "ethtool-coalesce-rx-frames-high"}, /* Debian ethtool integration */ {"hardware-irq-coalesce-rx-frames-irq", "ethtool-coalesce-rx-frames-irq"}, /* Debian ethtool integration */ {"hardware-irq-coalesce-rx-frames-low", "ethtool-coalesce-rx-frames-low"}, /* Debian ethtool integration */ {"hardware-irq-coalesce-rx-usecs", "ethtool-coalesce-rx-usecs"}, /* Debian ethtool integration */ {"hardware-irq-coalesce-rx-usecs-high", "ethtool-coalesce-rx-usecs-high"}, /* Debian ethtool integration */ {"hardware-irq-coalesce-rx-usecs-irq", "ethtool-coalesce-rx-usecs-irq"}, /* Debian ethtool integration */ {"hardware-irq-coalesce-rx-usecs-low", "ethtool-coalesce-rx-usecs-low"}, /* Debian ethtool integration */ {"hardware-irq-coalesce-sample-interval", "ethtool-coalesce-sample-interval"}, /* Debian ethtool integration */ {"hardware-irq-coalesce-stats-block-usecs", "ethtool-coalesce-stats-block-usecs"}, /* Debian ethtool integration */ {"hardware-irq-coalesce-tx-frames", "ethtool-coalesce-tx-frames"}, /* Debian ethtool integration */ {"hardware-irq-coalesce-tx-frames-high", "ethtool-coalesce-tx-frames-high"}, /* Debian ethtool integration */ {"hardware-irq-coalesce-tx-frames-irq", "ethtool-coalesce-tx-frames-irq"}, /* Debian ethtool integration */ {"hardware-irq-coalesce-tx-frames-low", "ethtool-coalesce-tx-frames-low"}, /* Debian ethtool integration */ {"hardware-irq-coalesce-tx-usecs", "ethtool-coalesce-tx-usecs"}, /* Debian ethtool integration */ {"hardware-irq-coalesce-tx-usecs-high", "ethtool-coalesce-tx-usecs-high"}, /* Debian ethtool integration */ {"hardware-irq-coalesce-tx-usecs-irq", "ethtool-coalesce-tx-usecs-irq"}, /* Debian ethtool integration */ {"hardware-irq-coalesce-tx-usecs-low", "ethtool-coalesce-tx-usecs-low"}, /* Debian ethtool integration */ {"hostname", "dhcp-hostname"}, /* legacy ifupdown */ {"key", "tunnel-key"}, /* legacy ifupdown */ {"leasetime", "dhcp-leasetime"}, /* legacy ifupdown */ {"link-autoneg", "ethtool-ethernet-autoneg"}, /* ifupdown2 */ {"link-duplex", "ethtool-link-duplex"}, /* Debian ethtool integration */ {"link-fec", "ethtool-link-fec"}, /* ifupdown2 */ {"link-speed", "ethtool-link-speed"}, /* Debian ethtool integration */ {"local", "tunnel-local"}, /* legacy ifupdown */ {"lro-offload", "ethtool-offload-lro"}, /* ifupdown2 */ {"mode", "tunnel-mode"}, /* legacy ifupdown */ {"offload-gro", "ethtool-offload-gro"}, /* Debian ethtool integration */ {"offload-gso", "ethtool-offload-gso"}, /* Debian ethtool integration */ {"offload-lro", "ethtool-offload-lro"}, /* Debian ethtool integration */ {"offload-rx", "ethtool-offload-rx"}, /* Debian ethtool integration */ {"offload-sg", "ethtool-offload-sg"}, /* Debian ethtool integration */ {"offload-tso", "ethtool-offload-tso"}, /* Debian ethtool integration */ {"offload-tx", "ethtool-offload-tx"}, /* Debian ethtool integration */ {"offload-ufo", "ethtool-offload-ufo"}, /* Debian ethtool integration */ {"pointopoint", "point-to-point"}, /* legacy ifupdown, ifupdown2 */ {"provider", "ppp-provider"}, /* legacy ifupdown, ifupdown2 */ {"script", "dhcp-script"}, /* legacy ifupdown */ {"rx-offload", "ethtool-offload-rx"}, /* ifupdown2 */ {"tso-offload", "ethtool-offload-tso"}, /* ifupdown2 */ {"ttl", "tunnel-ttl"}, /* legacy ifupdown */ {"tunnel-endpoint", "tunnel-remote"}, /* ifupdown2 */ {"tunnel-physdev", "tunnel-dev"}, /* ifupdown2 */ {"tx-offload", "ethtool-offload-tx"}, /* ifupdown2 */ {"ufo-offload", "ethtool-offload-ufo"}, /* ifupdown2 */ {"vendor", "dhcp-vendor"}, /* legacy ifupdown */ {"vrf", "vrf-member"}, /* ifupdown2 */ {"vxlan-local-tunnelip", "vxlan-local-ip"}, /* ifupdown2 */ {"vxlan-remote-group", "vxlan-peer-group"}, /* ifupdown-ng */ {"vxlan-remoteip", "vxlan-peer-ips"}, /* ifupdown2 */ {"vxlan-remote-ip", "vxlan-peer-ips"}, /* ifupdown-ng */ {"vxlan-svcnodeip", "vxlan-peer-group"}, /* ifupdown2 */ }; static int token_cmp(const void *a, const void *b) { const char *key = a; const struct remap_token *token = b; return strcmp(key, token->token); } static char * maybe_remap_token(const char *token) { const struct remap_token *tok = NULL; static char tokbuf[4096]; tok = bsearch(token, tokens, ARRAY_SIZE(tokens), sizeof(*tokens), token_cmp); strlcpy(tokbuf, tok != NULL ? tok->alternative : token, sizeof tokbuf); return tokbuf; } static void report_error(struct lif_interface_file_parse_state *state, const char *errfmt, ...) { char errbuf[4096]; va_list va; va_start(va, errfmt); vsnprintf(errbuf, sizeof errbuf, errfmt, va); va_end(va); fprintf(stderr, "%s:%zu: %s\n", state->cur_filename, state->cur_lineno, errbuf); } static bool handle_address(struct lif_interface_file_parse_state *state, char *token, char *bufp) { (void) token; char *addr = lif_next_token(&bufp); if (state->cur_iface == NULL) { report_error(state, "%s '%s' without interface", token, addr); /* Ignore this address, but don't fail hard */ return true; } lif_interface_address_add(state->cur_iface, addr); return true; } static bool handle_auto(struct lif_interface_file_parse_state *state, char *token, char *bufp) { (void) token; char *ifname = lif_next_token(&bufp); if (!*ifname && state->cur_iface == NULL) { report_error(state, "auto without interface"); return true; } else { state->cur_iface = lif_interface_collection_find(state->collection, ifname); if (state->cur_iface == NULL) return false; } if (!state->cur_iface->is_template) state->cur_iface->is_auto = true; if (state->cur_iface->is_auto) state->cur_iface->is_explicit = true; return true; } static bool handle_gateway(struct lif_interface_file_parse_state *state, char *token, char *bufp) { (void) token; char *addr = lif_next_token(&bufp); if (state->cur_iface == NULL) { report_error(state, "%s '%s' without interface", token, addr); /* Ignore this gateway, but don't fail hard */ return true; } lif_interface_use_executor(state->cur_iface, "static"); lif_dict_add(&state->cur_iface->vars, token, strdup(addr)); return true; } static bool handle_generic(struct lif_interface_file_parse_state *state, char *token, char *bufp) { if (state->cur_iface == NULL) return true; token = maybe_remap_token(token); /* This smells like a bridge */ if (strcmp(token, "bridge-ports") == 0) state->cur_iface->is_bridge = true; /* Skip any leading whitespaces in value for */ while (isspace (*bufp)) bufp++; lif_dict_add(&state->cur_iface->vars, token, strdup(bufp)); if (!lif_config.auto_executor_selection) return true; /* Check if token looks like - and assume is an addon */ char *word_end = strchr(token, '-'); if (word_end != NULL) { /* Copy word1 to not mangle *token */ char *addon = strndup(token, word_end - token); lif_interface_use_executor(state->cur_iface, addon); free(addon); } return true; } static bool handle_hostname(struct lif_interface_file_parse_state *state, char *token, char *bufp) { char *hostname = lif_next_token(&bufp); if (state->cur_iface == NULL) { report_error(state, "%s '%s' without interface", token, hostname); /* Ignore this hostname, but don't fail hard */ return true; } lif_dict_delete(&state->cur_iface->vars, "dhcp-hostname"); lif_dict_add(&state->cur_iface->vars, "dhcp-hostname", strdup(hostname)); return true; } static bool handle_inherit(struct lif_interface_file_parse_state *state, char *token, char *bufp); static bool handle_iface(struct lif_interface_file_parse_state *state, char *token, char *bufp) { char *ifname = lif_next_token(&bufp); if (!*ifname) { report_error(state, "%s without any other tokens", token); /* This is broken but not fatal */ return true; } /* if we have a current interface, call lif_interface_finalize to finalize any * address properties by converting them to CIDR and flushing the netmask property. */ if (state->cur_iface != NULL) lif_interface_finalize(state->cur_iface); state->cur_iface = lif_interface_collection_find(state->collection, ifname); if (state->cur_iface == NULL) { report_error(state, "could not upsert interface %s", ifname); return false; } /* mark the state->cur_iface as a template iface if `template` keyword * is used. */ if (!strcmp(token, "template")) { state->cur_iface->is_auto = false; state->cur_iface->is_template = true; } /* in original ifupdown config, we can have "inet loopback" * or "inet dhcp" or such to designate hints. lets pick up * those hints here. */ token = lif_next_token(&bufp); while (*token) { if (!strcmp(token, "dhcp")) lif_interface_use_executor(state->cur_iface, "dhcp"); else if (!strcmp(token, "ppp")) lif_interface_use_executor(state->cur_iface, "ppp"); else if (!strcmp(token, "inherits")) { if (!handle_inherit(state, token, bufp)) return false; } token = lif_next_token(&bufp); } return true; } static bool handle_inherit(struct lif_interface_file_parse_state *state, char *token, char *bufp) { char *target = lif_next_token(&bufp); if (state->cur_iface == NULL) { report_error(state, "%s '%s' without interface", token, target); /* This is broken but not fatal */ return true; } if (!*target) { report_error(state, "iface %s: unspecified inherit target", state->cur_iface->ifname); /* Mark this interface as errornous but carry on */ state->cur_iface->has_config_error = true; return true; } struct lif_interface *parent = lif_interface_collection_find(state->collection, target); if (parent == NULL) { report_error(state, "iface %s: could not inherit from %s: not found", state->cur_iface->ifname, target); /* Mark this interface as errornous but carry on */ state->cur_iface->has_config_error = true; return true; } if (!lif_config.allow_any_iface_as_template && !parent->is_template) { report_error(state, "iface %s: could not inherit from %ss: inheritence from non-template interface not allowed", state->cur_iface->ifname, target); /* Mark this interface as errornous but carry on */ state->cur_iface->has_config_error = true; return true; } if (!lif_interface_collection_inherit(state->cur_iface, parent)) { report_error(state, "iface %s: could not inherit from %s", state->cur_iface->ifname, target); /* Mark this interface as errornous but carry on */ state->cur_iface->has_config_error = true; return true; } return true; } static bool handle_source(struct lif_interface_file_parse_state *state, char *token, char *bufp) { (void) token; char *source_filename = lif_next_token(&bufp); if (!*source_filename) { report_error(state, "missing filename to source"); /* Broken but not fatal */ return true; } return lif_interface_file_parse(state, source_filename); } static bool handle_source_directory(struct lif_interface_file_parse_state *state, char *token, char *bufp) { (void) token; char *source_directory = lif_next_token(&bufp); if (!*source_directory) { report_error(state, "missing directory to source"); /* Broken but not fatal */ return true; } DIR *source_dir = opendir(source_directory); if (source_dir == NULL) { report_error(state, "while opening directory %s: %s", source_directory, strerror(errno)); /* Broken but not fatal */ return true; } struct dirent *dirent_p; for (dirent_p = readdir(source_dir); dirent_p != NULL; dirent_p = readdir(source_dir)) { if (dirent_p->d_type != DT_REG) continue; char pathbuf[4096]; snprintf(pathbuf, sizeof pathbuf, "%s/%s", source_directory, dirent_p->d_name); if (!lif_interface_file_parse(state, pathbuf)) { closedir(source_dir); return false; } } closedir(source_dir); return true; } static bool handle_use(struct lif_interface_file_parse_state *state, char *token, char *bufp) { char *executor = lif_next_token(&bufp); if (state->cur_iface == NULL) { report_error(state, "%s '%s' without interface", token, executor); /* Broken but not fatal */ return true; } lif_interface_use_executor(state->cur_iface, executor); return true; } /* map keywords to parser functions */ struct parser_keyword { const char *token; bool (*handle)(struct lif_interface_file_parse_state *state, char *token, char *bufp); }; static const struct parser_keyword keywords[] = { {"address", handle_address}, {"auto", handle_auto}, {"dhcp-hostname", handle_hostname}, {"gateway", handle_gateway}, {"hostname", handle_hostname}, {"iface", handle_iface}, {"inherit", handle_inherit}, {"interface", handle_iface}, {"source", handle_source}, {"source-directory", handle_source_directory}, {"template", handle_iface}, {"use", handle_use}, }; static int keyword_cmp(const void *a, const void *b) { const char *key = a; const struct parser_keyword *token = b; return strcmp(key, token->token); } bool lif_interface_file_parse(struct lif_interface_file_parse_state *state, const char *filename) { struct lif_dict_entry *entry = lif_dict_find(&state->loaded, filename); if (entry != NULL) { report_error(state, "skipping already included file %s", filename); return true; } FILE *f = fopen(filename, "r"); if (f == NULL) return false; const char *old_filename = state->cur_filename; state->cur_filename = filename; size_t old_lineno = state->cur_lineno; state->cur_lineno = 0; lif_dict_add(&state->loaded, filename, NULL); char linebuf[4096]; while (lif_fgetline(linebuf, sizeof linebuf, f) != NULL) { state->cur_lineno++; char *bufp = linebuf; char *token = lif_next_token(&bufp); if (!*token || !isalpha(*token)) continue; const struct parser_keyword *parserkw = bsearch(token, keywords, ARRAY_SIZE(keywords), sizeof(*keywords), keyword_cmp); if (parserkw != NULL) { if (!parserkw->handle(state, token, bufp)) goto parse_error; } else if (!handle_generic(state, token, bufp)) goto parse_error; } fclose(f); /* finalize any open interface */ if (state->cur_iface != NULL) lif_interface_finalize(state->cur_iface); state->cur_filename = old_filename; state->cur_lineno = old_lineno; return true; parse_error: fclose(f); state->cur_filename = old_filename; state->cur_lineno = old_lineno; return false; } ifupdown-ng-ifupdown-ng-0.12.1/libifupdown/interface-file.h000066400000000000000000000020071422731055100236320ustar00rootroot00000000000000/* * libifupdown/interface-file.h * Purpose: /etc/network/interfaces parser * * Copyright (c) 2020 Ariadne Conill * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * This software is provided 'as is' and without any warranty, express or * implied. In no event shall the authors be liable for any damages arising * from the use of this software. */ #ifndef LIBIFUPDOWN_INTERFACE_FILE_H__GUARD #define LIBIFUPDOWN_INTERFACE_FILE_H__GUARD #include #include "libifupdown/interface.h" #include "libifupdown/dict.h" struct lif_interface_file_parse_state { struct lif_interface *cur_iface; struct lif_dict *collection; const char *cur_filename; size_t cur_lineno; struct lif_dict loaded; }; extern bool lif_interface_file_parse(struct lif_interface_file_parse_state *state, const char *filename); #endif ifupdown-ng-ifupdown-ng-0.12.1/libifupdown/interface.c000066400000000000000000000213661422731055100227210ustar00rootroot00000000000000/* * libifupdown/interface.c * Purpose: interface management * * Copyright (c) 2020 Ariadne Conill * Copyright (c) 2020 Maximilian Wilhelm * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * This software is provided 'as is' and without any warranty, express or * implied. In no event shall the authors be liable for any damages arising * from the use of this software. */ #include #include #include #include "libifupdown/interface.h" #include "libifupdown/config-file.h" bool lif_address_parse(struct lif_address *address, const char *presentation) { char buf[512], *netmask_p; strlcpy(buf, presentation, sizeof buf); address->domain = strchr(buf, ':') != NULL ? AF_INET6 : AF_INET; netmask_p = strrchr(buf, '/'); if (netmask_p != NULL) { *netmask_p++ = '\0'; address->netmask = strtol(netmask_p, NULL, 10); } else address->netmask = 0; return !!inet_pton(address->domain, buf, address->addr_buf); } bool lif_address_unparse(const struct lif_address *address, char *buf, size_t buflen, bool with_netmask) { char workbuf[512] = {}; if (!inet_ntop(address->domain, address->addr_buf, workbuf, sizeof workbuf)) return false; if (!with_netmask || !address->netmask) { strlcpy(buf, workbuf, buflen); return true; } snprintf(buf, buflen, "%s/%zu", workbuf, address->netmask); return true; } static inline size_t count_set_bits(const char *netmask) { /* netmask set to CIDR length */ if (strchr(netmask, '.') == NULL) return strtol(netmask, NULL, 10); size_t r = 0; struct in_addr in; if (inet_pton(AF_INET, netmask, &in) == 0) return r; /* take the IP, put it in host endian order, and * flip it so that all the set bits are set to the right. * then we can simply count down from 32 and right-shift * until the bit field is all zero. */ unsigned int bits = htonl(in.s_addr); for (bits = ~bits, r = 32; bits; bits >>= 1, r--) ; return r; } static inline size_t determine_interface_netmask(const struct lif_interface *iface, const struct lif_address *addr) { /* if netmask is not set, default to /24 or /64, ifupdown does so too */ size_t netmask = addr->domain == AF_INET6 ? 64 : 24; struct lif_dict_entry *entry = lif_dict_find(&iface->vars, "netmask"); if (entry != NULL) netmask = count_set_bits(entry->data); return netmask; } bool lif_address_format_cidr(const struct lif_interface *iface, struct lif_dict_entry *entry, char *buf, size_t buflen) { struct lif_address *addr = entry->data; size_t orig_netmask = addr->netmask; if (!addr->netmask) addr->netmask = determine_interface_netmask(iface, addr); if (!lif_address_unparse(addr, buf, buflen, true)) { addr->netmask = orig_netmask; return false; } addr->netmask = orig_netmask; return true; } void lif_interface_init(struct lif_interface *interface, const char *ifname) { memset(interface, '\0', sizeof *interface); interface->ifname = strdup(ifname); lif_interface_use_executor(interface, "link"); /* keep the 'vlan' executor as a config hint for backwards compatibility */ if (strchr(ifname, '.') != NULL) lif_interface_use_executor(interface, "vlan"); } bool lif_interface_address_add(struct lif_interface *interface, const char *address) { struct lif_address *addr = calloc(1, sizeof *addr); if (!lif_address_parse(addr, address)) { free(addr); return false; } lif_interface_use_executor(interface, "static"); lif_dict_add(&interface->vars, "address", addr); return true; } void lif_interface_address_delete(struct lif_interface *interface, const char *address) { struct lif_node *iter, *iter_next; struct lif_address addr; if (!lif_address_parse(&addr, address)) return; LIF_DICT_FOREACH_SAFE(iter, iter_next, &interface->vars) { struct lif_dict_entry *entry = iter->data; if (strcmp(entry->key, "address")) continue; struct lif_address *entry_addr = entry->data; char addr_buf[512] = {}; if (!lif_address_unparse(entry_addr, addr_buf, sizeof addr_buf, addr.netmask != 0)) continue; if (strcmp(addr_buf, address)) continue; lif_dict_delete_entry(&interface->vars, entry); free(entry_addr); } } void lif_interface_fini(struct lif_interface *interface) { struct lif_node *iter, *iter_next; LIF_DICT_FOREACH_SAFE(iter, iter_next, &interface->vars) { struct lif_dict_entry *entry = iter->data; free(entry->data); lif_dict_delete_entry(&interface->vars, entry); } free(interface->ifname); } void lif_interface_use_executor(struct lif_interface *interface, const char *executor) { char *exec_addon = strdup(executor); if (lif_dict_add_once(&interface->vars, "use", exec_addon, (lif_dict_cmp_t) strcmp) == NULL) free(exec_addon); /* pass requires as compatibility env vars to appropriate executors (bridge, bond) */ if (!strcmp(executor, "bridge")) interface->is_bridge = true; else if (!strcmp(executor, "bond")) interface->is_bond = true; if (strcmp(executor, "dhcp") || !lif_config.use_hostname_for_dhcp) return; /* learn a reasonable default hostname */ struct utsname un; if (uname(&un) < 0) return; lif_dict_add(&interface->vars, "dhcp-hostname", strdup(un.nodename)); } void lif_interface_finalize(struct lif_interface *interface) { struct lif_node *iter; /* convert all addresses to CIDR notation. */ LIF_DICT_FOREACH(iter, &interface->vars) { struct lif_dict_entry *entry = iter->data; if (strcmp(entry->key, "address")) continue; struct lif_address *addr = entry->data; if (!addr->netmask) addr->netmask = determine_interface_netmask(interface, addr); } /* with all addresses converted to CIDR, netmask property is no longer needed. */ struct lif_dict_entry *entry = lif_dict_find(&interface->vars, "netmask"); if (entry != NULL) { free(entry->data); lif_dict_delete_entry(&interface->vars, entry); } } void lif_interface_collection_init(struct lif_dict *collection) { struct lif_interface *if_lo; memset(collection, '\0', sizeof *collection); /* always enable loopback interface as part of a collection */ if_lo = lif_interface_collection_find(collection, "lo"); if_lo->is_auto = true; if_lo->is_explicit = true; lif_interface_use_executor(if_lo, "loopback"); } void lif_interface_collection_fini(struct lif_dict *collection) { struct lif_node *iter, *iter_next; LIF_DICT_FOREACH_SAFE(iter, iter_next, collection) { struct lif_dict_entry *entry = iter->data; struct lif_interface *iface = entry->data; lif_interface_fini(iface); free(iface); lif_dict_delete_entry(collection, entry); } } struct lif_interface * lif_interface_collection_find(struct lif_dict *collection, const char *ifname) { struct lif_dict_entry *entry = lif_dict_find(collection, ifname); if (entry == NULL) { struct lif_interface *iface = calloc(1, sizeof *iface); lif_interface_init(iface, ifname); lif_dict_add(collection, ifname, iface); return iface; } return entry->data; } struct lif_interface * lif_interface_collection_upsert(struct lif_dict *collection, struct lif_interface *interface) { struct lif_dict_entry *entry = lif_dict_find(collection, interface->ifname); if (entry == NULL) { lif_dict_add(collection, interface->ifname, interface); return interface; } if (entry->data == interface) return interface; lif_interface_collection_delete(collection, entry->data); lif_dict_add(collection, interface->ifname, interface); return interface; } void lif_interface_collection_delete(struct lif_dict *collection, struct lif_interface *interface) { struct lif_dict_entry *entry = lif_dict_find(collection, interface->ifname); if (entry == NULL) return; lif_interface_fini(interface); free(interface); lif_dict_delete_entry(collection, entry); } bool lif_interface_collection_inherit(struct lif_interface *interface, struct lif_interface *parent) { /* maybe convert any interface we are inheriting from into a template */ if (lif_config.implicit_template_conversion) parent->is_template = true; lif_dict_add(&interface->vars, "inherit", strdup(parent->ifname)); interface->is_bond = parent->is_bond; interface->is_bridge = parent->is_bridge; /* copy the variables */ struct lif_node *iter; LIF_DICT_FOREACH(iter, &parent->vars) { struct lif_dict_entry *entry = iter->data; if (!strcmp(entry->key, "address")) { struct lif_address *addr = calloc(1, sizeof *addr); struct lif_address *other_addr = entry->data; memcpy(addr, other_addr, sizeof *addr); lif_dict_add(&interface->vars, entry->key, addr); } else { char *value = strdup(entry->data); if (lif_dict_add_once(&interface->vars, entry->key, value, (lif_dict_cmp_t) strcmp) == NULL) free(value); } } return true; } ifupdown-ng-ifupdown-ng-0.12.1/libifupdown/interface.h000066400000000000000000000064521422731055100227250ustar00rootroot00000000000000/* * libifupdown/interface.h * Purpose: interface management * * Copyright (c) 2020 Ariadne Conill * Copyright (c) 2020 Maximilian Wilhelm * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * This software is provided 'as is' and without any warranty, express or * implied. In no event shall the authors be liable for any damages arising * from the use of this software. */ #ifndef LIBIFUPDOWN_INTERFACE_H__GUARD #define LIBIFUPDOWN_INTERFACE_H__GUARD #include #include #include #include #include "libifupdown/dict.h" /* * Addresses are stored in a buffer with netmask and type. */ struct lif_address { unsigned char addr_buf[sizeof(struct in6_addr)]; size_t netmask; int domain; }; /* * Interfaces are contained in a dictionary, with the interfaces mapped by * interface name to their `struct lif_interface`. * * Interfaces are simply upserted as needed. This allows for `auto eth0` * to create a placeholder `struct lif_interface` with auto set to true. * * Configuration variables are simply stored in a `struct lif_dict`, which * can act as a multidict. */ struct lif_interface { char *ifname; bool is_auto; bool is_bridge; bool is_bond; bool is_template; bool is_pending; bool is_explicit; bool has_config_error; /* error found in interface configuration */ struct lif_dict vars; size_t refcount; /* > 0 if up, else 0 */ size_t rdepends_count; /* > 0 if any reverse dependency */ }; #define LIF_INTERFACE_COLLECTION_FOREACH(iter, collection) \ LIF_DICT_FOREACH((iter), (collection)) #define LIF_INTERFACE_COLLECTION_FOREACH_SAFE(iter, iter_next, collection) \ LIF_DICT_FOREACH_SAFE((iter), (iter_next), (collection)) extern bool lif_address_parse(struct lif_address *address, const char *presentation); extern bool lif_address_unparse(const struct lif_address *address, char *buf, size_t buflen, bool with_netmask); extern bool lif_address_format_cidr(const struct lif_interface *iface, struct lif_dict_entry *entry, char *buf, size_t buflen); extern void lif_interface_init(struct lif_interface *interface, const char *ifname); extern bool lif_interface_address_add(struct lif_interface *interface, const char *address); extern void lif_interface_address_delete(struct lif_interface *interface, const char *address); extern void lif_interface_fini(struct lif_interface *interface); extern void lif_interface_use_executor(struct lif_interface *interface, const char *executor); extern void lif_interface_finalize(struct lif_interface *interface); extern void lif_interface_collection_init(struct lif_dict *collection); extern void lif_interface_collection_fini(struct lif_dict *collection); extern struct lif_interface *lif_interface_collection_find(struct lif_dict *collection, const char *ifname); extern struct lif_interface *lif_interface_collection_upsert(struct lif_dict *collection, struct lif_interface *interface); extern bool lif_interface_collection_inherit(struct lif_interface *interface, struct lif_interface *parent); extern void lif_interface_collection_delete(struct lif_dict *collection, struct lif_interface *interface); #endif ifupdown-ng-ifupdown-ng-0.12.1/libifupdown/libifupdown.h000066400000000000000000000022671422731055100233070ustar00rootroot00000000000000/* * libifupdown/libifupdown.h * Purpose: main header file for libifupdown * * Copyright (c) 2020 Ariadne Conill * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * This software is provided 'as is' and without any warranty, express or * implied. In no event shall the authors be liable for any damages arising * from the use of this software. */ #ifndef LIBIFUPDOWN_LIBIFUPDOWN_H__GUARD #define LIBIFUPDOWN_LIBIFUPDOWN_H__GUARD #include "libifupdown/list.h" #include "libifupdown/dict.h" #include "libifupdown/interface.h" #include "libifupdown/interface-file.h" #include "libifupdown/fgetline.h" #include "libifupdown/version.h" #include "libifupdown/state.h" #include "libifupdown/environment.h" #include "libifupdown/execute.h" #include "libifupdown/lifecycle.h" #include "libifupdown/tokenize.h" #include "libifupdown/config-file.h" #include "libifupdown/config-parser.h" #include "libifupdown/compat.h" #ifndef ARRAY_SIZE # define ARRAY_SIZE(x) (sizeof(x) / sizeof(*x)) #endif #endif ifupdown-ng-ifupdown-ng-0.12.1/libifupdown/lifecycle.c000066400000000000000000000370371422731055100227220ustar00rootroot00000000000000/* * libifupdown/lifecycle.c * Purpose: management of interface lifecycle (bring up, takedown, reload) * * Copyright (c) 2020 Ariadne Conill * Copyright (c) 2020 Maximilian Wilhelm * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * This software is provided 'as is' and without any warranty, express or * implied. In no event shall the authors be liable for any damages arising * from the use of this software. */ #include #include #include #include #include #include "libifupdown/environment.h" #include "libifupdown/execute.h" #include "libifupdown/interface.h" #include "libifupdown/lifecycle.h" #include "libifupdown/state.h" #include "libifupdown/tokenize.h" #include "libifupdown/config-file.h" #define BUFFER_LEN 4096 static bool handle_commands_for_phase(const struct lif_execute_opts *opts, char *const envp[], const struct lif_interface *iface, const char *phase) { const struct lif_node *iter; LIF_DICT_FOREACH(iter, &iface->vars) { const struct lif_dict_entry *entry = iter->data; if (strcmp(entry->key, phase)) continue; const char *cmd = entry->data; if (!lif_execute_fmt(opts, envp, "%s", cmd)) return false; } return true; } static inline bool handle_single_executor_for_phase(const struct lif_dict_entry *entry, const struct lif_execute_opts *opts, char *const envp[], const char *phase, const char *lifname) { if (strcmp(entry->key, "use")) return true; const char *cmd = entry->data; if (!lif_maybe_run_executor(opts, envp, cmd, phase, lifname)) return false; return true; } static bool handle_executors_for_phase(const struct lif_execute_opts *opts, char *const envp[], const struct lif_interface *iface, bool up, const char *phase) { bool ret = true; const struct lif_node *iter; if (up) { LIF_DICT_FOREACH(iter, &iface->vars) { if (!handle_single_executor_for_phase(iter->data, opts, envp, phase, iface->ifname)) ret = false; } } else { LIF_DICT_FOREACH_REVERSE(iter, &iface->vars) { if (!handle_single_executor_for_phase(iter->data, opts, envp, phase, iface->ifname)) ret = false; } } return ret; } static bool query_dependents_from_executors(const struct lif_execute_opts *opts, char *const envp[], const struct lif_interface *iface, char *buf, size_t bufsize, const char *phase) { const struct lif_node *iter; LIF_DICT_FOREACH(iter, &iface->vars) { char resbuf[1024] = {}; const struct lif_dict_entry *entry = iter->data; struct lif_execute_opts exec_opts = { .verbose = opts->verbose, .executor_path = opts->executor_path, .interfaces_file = opts->interfaces_file, .timeout = opts->timeout, }; if (strcmp(entry->key, "use")) continue; const char *cmd = entry->data; if (!lif_maybe_run_executor_with_result(&exec_opts, envp, cmd, resbuf, sizeof resbuf, phase, iface->ifname)) return false; if (!*resbuf) continue; strlcat(buf, " ", bufsize); strlcat(buf, resbuf, bufsize); } return true; } static bool append_to_buffer(char **buffer, size_t *buffer_len, char **end, const char *value) { size_t value_len = strlen (value); /* Make sure there is enough room to add the value to the buffer */ if (*buffer_len < strlen (*buffer) + value_len + 2) { size_t end_offset = *end - *buffer; char *tmp = realloc (*buffer, *buffer_len * 2); if (tmp != NULL) { *buffer = tmp; *end = tmp + end_offset; *buffer_len = *buffer_len * 2; } else return false; } /* Append value to buffer */ size_t printed = snprintf (*end, value_len + 2, "%s ", value); if (printed < value_len + 1) /* Here be dragons */ return false; /* Move end pointer to last printed byte */ *end += printed; return true; } static void build_environment(char **envp[], const struct lif_execute_opts *opts, const struct lif_interface *iface, const char *lifname, const char *phase, const char *mode) { if (lifname == NULL) lifname = iface->ifname; lif_environment_push(envp, "IFACE", lifname); lif_environment_push(envp, "PHASE", phase); lif_environment_push(envp, "MODE", mode); lif_environment_push(envp, "METHOD", "none"); if (opts->verbose) lif_environment_push(envp, "VERBOSE", "1"); if (opts->interfaces_file) lif_environment_push(envp, "INTERFACES_FILE", opts->interfaces_file); const struct lif_node *iter; bool did_address = false, did_gateway = false; /* Allocate a buffer for all possible addresses, if any */ char *addresses = calloc (BUFFER_LEN, 1); size_t addresses_size = BUFFER_LEN; char *addresses_end = addresses; /* Allocate a buffer for all possible gateways, if any */ char *gateways = calloc (BUFFER_LEN, 1); size_t gateways_size = BUFFER_LEN; char *gateways_end = gateways; LIF_DICT_FOREACH(iter, &iface->vars) { struct lif_dict_entry *entry = iter->data; if (!strcmp(entry->key, "address")) { char addrbuf[4096]; if (!lif_address_format_cidr(iface, entry, addrbuf, sizeof(addrbuf))) continue; /* Append address to buffer */ append_to_buffer(&addresses, &addresses_size, &addresses_end, addrbuf); /* Only print IF_ADDRESS once */ if (did_address) continue; lif_environment_push(envp, "IF_ADDRESS", addrbuf); did_address = true; continue; } else if (!strcmp(entry->key, "gateway")) { /* Append address to buffer */ append_to_buffer(&gateways, &gateways_size, &gateways_end, entry->data); if (did_gateway) continue; did_gateway = true; } else if (!strcmp(entry->key, "requires")) { if (iface->is_bridge) lif_environment_push(envp, "IF_BRIDGE_PORTS", (const char *) entry->data); } char envkey[4096] = "IF_"; strlcat(envkey, entry->key, sizeof envkey); char *ep = envkey + 2; while (*ep++) { *ep = toupper(*ep); if (*ep == '-') *ep = '_'; } lif_environment_push(envp, envkey, (const char *) entry->data); } if (addresses != NULL) lif_environment_push(envp, "IF_ADDRESSES", addresses); if (gateways != NULL) lif_environment_push(envp, "IF_GATEWAYS", gateways); /* Clean up */ free (addresses); free (gateways); } bool lif_lifecycle_query_dependents(const struct lif_execute_opts *opts, struct lif_interface *iface, const char *lifname) { char deps[4096] = {}; char final_deps[4096] = {}; if (lifname == NULL) lifname = iface->ifname; char **envp = NULL; build_environment(&envp, opts, iface, lifname, "depend", "depend"); struct lif_dict_entry *entry = lif_dict_find(&iface->vars, "requires"); if (entry != NULL) strlcpy(deps, entry->data, sizeof deps); if (!query_dependents_from_executors(opts, envp, iface, deps, sizeof deps, "depend")) return false; char *p = deps; while (*p) { char *token = lif_next_token(&p); if (strstr(final_deps, token) != NULL) continue; strlcat(final_deps, token, sizeof final_deps); strlcat(final_deps, " ", sizeof final_deps); } if (entry != NULL) { free(entry->data); entry->data = strdup(final_deps); } else if (*final_deps) lif_dict_add(&iface->vars, "requires", strdup(final_deps)); lif_environment_free(&envp); return true; } bool lif_lifecycle_run_phase(const struct lif_execute_opts *opts, struct lif_interface *iface, const char *phase, const char *lifname, bool up) { char **envp = NULL; build_environment(&envp, opts, iface, lifname, phase, up ? "start" : "stop"); if (!handle_executors_for_phase(opts, envp, iface, up, phase)) goto handle_error; if (!handle_commands_for_phase(opts, envp, iface, phase)) goto handle_error; /* if we don't need to support /etc/if-X.d we're done here */ if (!lif_config.allow_addon_scripts) goto out_free; /* Check if scripts dir for this phase is present and bail out if it isn't */ struct stat dir_stat; char dir_path[4096]; snprintf (dir_path, 4096, "/etc/network/if-%s.d", phase); if (stat (dir_path, &dir_stat) != 0 || S_ISDIR (dir_stat.st_mode) == 0) { goto out_free; } /* we should do error handling here, but ifupdown1 doesn't */ lif_execute_fmt(opts, envp, "/bin/run-parts %s", dir_path); out_free: lif_environment_free(&envp); return true; handle_error: lif_environment_free(&envp); return false; } /* this function returns true if we can skip processing the interface for now, * otherwise false. */ static bool handle_refcounting(struct lif_dict *state, struct lif_interface *iface, bool up) { size_t orig_refcount = iface->refcount; if (up) lif_state_ref_if(state, iface->ifname, iface); else lif_state_unref_if(state, iface->ifname, iface); #ifdef DEBUG_REFCOUNTING fprintf(stderr, "handle_refcounting(): orig_refcount=%zu, refcount=%zu, direction=%s\n", orig_refcount, iface->refcount, up ? "UP" : "DOWN"); #endif /* if going up and orig_refcount > 0 -- we're already configured. */ if (up && orig_refcount > 0) return true; /* if going down and iface->refcount > 1 -- we still have other dependents. */ if (!up && iface->refcount > 1) return true; /* we can change this interface -- no blocking dependents. */ return false; } static bool handle_dependents(const struct lif_execute_opts *opts, struct lif_interface *parent, struct lif_dict *collection, struct lif_dict *state, bool up) { struct lif_dict_entry *requires = lif_dict_find(&parent->vars, "requires"); /* no dependents, nothing to worry about */ if (requires == NULL) return true; /* set the parent's pending flag to break dependency cycles */ parent->is_pending = true; char require_ifs[4096] = {}; strlcpy(require_ifs, requires->data, sizeof require_ifs); char *bufp = require_ifs; for (char *tokenp = lif_next_token(&bufp); *tokenp; tokenp = lif_next_token(&bufp)) { struct lif_interface *iface = lif_interface_collection_find(collection, tokenp); if (iface->has_config_error) { if (opts->force) fprintf (stderr, "ifupdown: (de)configuring dependent interface %s (of %s) despite config errors\n", iface->ifname, parent->ifname); else { fprintf (stderr, "ifupdown: skipping dependent interface %s (of %s) as it has config errors\n", iface->ifname, parent->ifname); continue; } } /* if handle_refcounting returns true, it means we've already * configured the interface, or it is too soon to deconfigure * the interface. */ if (handle_refcounting(state, iface, up)) { if (opts->verbose) fprintf(stderr, "ifupdown: skipping dependent interface %s (of %s) -- %s\n", iface->ifname, parent->ifname, up ? "already configured" : "transient dependencies still exist"); continue; } if (!up && iface->is_explicit) { if (opts->verbose) fprintf(stderr, "ifupdown: skipping dependent interface %s (of %s) -- interface is marked as explicitly configured\n", iface->ifname, parent->ifname); continue; } if (opts->verbose) fprintf(stderr, "ifupdown: changing state of dependent interface %s (of %s) to %s\n", iface->ifname, parent->ifname, up ? "up" : "down"); if (!lif_lifecycle_run(opts, iface, collection, state, iface->ifname, up)) { parent->is_pending = false; return false; } } parent->is_pending = false; return true; } bool lif_lifecycle_run(const struct lif_execute_opts *opts, struct lif_interface *iface, struct lif_dict *collection, struct lif_dict *state, const char *lifname, bool up) { /* if we're already pending, exit */ if (iface->is_pending) return true; if (iface->is_template) return false; if (lifname == NULL) lifname = iface->ifname; if (up) { /* when going up, dependents go up first. */ if (!handle_dependents(opts, iface, collection, state, up)) return false; /* XXX: we should try to recover (take the iface down) if bringing it up fails. * but, right now neither debian ifupdown or busybox ifupdown do any recovery, * so we wont right now. */ if (!lif_lifecycle_run_phase(opts, iface, "create", lifname, up)) return false; if (!lif_lifecycle_run_phase(opts, iface, "pre-up", lifname, up)) return false; if (!lif_lifecycle_run_phase(opts, iface, "up", lifname, up)) return false; if (!lif_lifecycle_run_phase(opts, iface, "post-up", lifname, up)) return false; lif_state_ref_if(state, lifname, iface); } else { if (!lif_lifecycle_run_phase(opts, iface, "pre-down", lifname, up)) return false; if (!lif_lifecycle_run_phase(opts, iface, "down", lifname, up)) return false; if (!lif_lifecycle_run_phase(opts, iface, "post-down", lifname, up)) return false; if (!lif_lifecycle_run_phase(opts, iface, "destroy", lifname, up)) return false; /* when going up, dependents go down last. */ if (!handle_dependents(opts, iface, collection, state, up)) return false; lif_state_unref_if(state, lifname, iface); } return true; } static bool count_interface_rdepends(const struct lif_execute_opts *opts, struct lif_dict *collection, struct lif_interface *parent, size_t depth) { /* if we have looped, return true immediately to break the loop. */ if (parent->is_pending) return true; /* query our dependents if we don't have them already */ if (!lif_lifecycle_query_dependents(opts, parent, parent->ifname)) return false; /* set rdepends_count to depth, dependents will be depth + 1 */ parent->is_pending = true; parent->rdepends_count = depth; struct lif_dict_entry *requires = lif_dict_find(&parent->vars, "requires"); /* no dependents, nothing to worry about */ if (requires == NULL) { parent->is_pending = false; return true; } /* walk any dependents */ char require_ifs[4096] = {}; strlcpy(require_ifs, requires->data, sizeof require_ifs); char *bufp = require_ifs; for (char *tokenp = lif_next_token(&bufp); *tokenp; tokenp = lif_next_token(&bufp)) { struct lif_interface *iface = lif_interface_collection_find(collection, tokenp); if (!count_interface_rdepends(opts, collection, iface, depth + 1)) { parent->is_pending = false; return false; } } parent->is_pending = false; return true; } ssize_t lif_lifecycle_count_rdepends(const struct lif_execute_opts *opts, struct lif_dict *collection) { struct lif_node *iter; LIF_DICT_FOREACH(iter, collection) { struct lif_dict_entry *entry = iter->data; struct lif_interface *iface = entry->data; /* start depth at interface's rdepends_count, which will be 0 for the root, * but will be more if additional rdepends are found... */ if (!count_interface_rdepends(opts, collection, iface, iface->rdepends_count)) { fprintf(stderr, "ifupdown: dependency graph is broken for interface %s\n", iface->ifname); return -1; } } /* figure out the max depth */ size_t maxdepth = 0; LIF_DICT_FOREACH(iter, collection) { struct lif_dict_entry *entry = iter->data; struct lif_interface *iface = entry->data; if (iface->rdepends_count > maxdepth) maxdepth = iface->rdepends_count; } /* move the collection to a temporary list so we can reorder it */ struct lif_list temp_list = {}; struct lif_node *iter_next; LIF_LIST_FOREACH_SAFE(iter, iter_next, collection->list.head) { void *data = iter->data; lif_node_delete(iter, &collection->list); memset(iter, 0, sizeof *iter); lif_node_insert(iter, data, &temp_list); } /* walk backwards from maxdepth to 0, readding nodes */ for (ssize_t curdepth = maxdepth; curdepth > -1; curdepth--) { LIF_LIST_FOREACH_SAFE(iter, iter_next, temp_list.head) { struct lif_dict_entry *entry = iter->data; struct lif_interface *iface = entry->data; if ((ssize_t) iface->rdepends_count != curdepth) continue; lif_node_delete(iter, &temp_list); memset(iter, 0, sizeof *iter); lif_node_insert(iter, entry, &collection->list); } } return maxdepth; } ifupdown-ng-ifupdown-ng-0.12.1/libifupdown/lifecycle.h000066400000000000000000000024461422731055100227230ustar00rootroot00000000000000/* * libifupdown/lifecycle.h * Purpose: management of interface lifecycle (bring up, takedown, reload) * * Copyright (c) 2020 Ariadne Conill * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * This software is provided 'as is' and without any warranty, express or * implied. In no event shall the authors be liable for any damages arising * from the use of this software. */ #ifndef LIBIFUPDOWN_LIFECYCLE_H__GUARD #define LIBIFUPDOWN_LIFECYCLE_H__GUARD #include "libifupdown/interface.h" #include "libifupdown/execute.h" extern bool lif_lifecycle_query_dependents(const struct lif_execute_opts *opts, struct lif_interface *iface, const char *lifname); extern bool lif_lifecycle_run_phase(const struct lif_execute_opts *opts, struct lif_interface *iface, const char *phase, const char *lifname, bool up); extern bool lif_lifecycle_run(const struct lif_execute_opts *opts, struct lif_interface *iface, struct lif_dict *collection, struct lif_dict *state, const char *lifname, bool up); extern ssize_t lif_lifecycle_count_rdepends(const struct lif_execute_opts *opts, struct lif_dict *collection); #endif ifupdown-ng-ifupdown-ng-0.12.1/libifupdown/list.c000066400000000000000000000034141422731055100217260ustar00rootroot00000000000000/* * libifupdown/list.c * Purpose: linked lists * * Copyright (c) 2020 Ariadne Conill * Copyright (c) 2020 Maximilian Wilhelm * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * This software is provided 'as is' and without any warranty, express or * implied. In no event shall the authors be liable for any damages arising * from the use of this software. */ #include #include #include "libifupdown/list.h" void lif_list_free_nodes(struct lif_list *list) { if (list == NULL) return; struct lif_node *iter, *iter_next; LIF_LIST_FOREACH_SAFE(iter, iter_next, list->head) { free (iter); } free (list); } void lif_node_insert(struct lif_node *node, void *data, struct lif_list *list) { struct lif_node *tnode; node->data = data; if (list->head == NULL) { list->head = list->tail = node; list->length = 1; return; } tnode = list->head; node->next = tnode; tnode->prev = node; list->head = node; list->length++; } void lif_node_insert_tail(struct lif_node *node, void *data, struct lif_list *list) { struct lif_node *tnode; node->data = data; if (list->tail == NULL) { list->head = list->tail = node; list->length = 1; return; } tnode = list->tail; node->prev = tnode; tnode->next = node; list->tail = node; list->length++; } void lif_node_delete(struct lif_node *node, struct lif_list *list) { list->length--; if (node->prev == NULL) list->head = node->next; else node->prev->next = node->next; if (node->next == NULL) list->tail = node->prev; else node->next->prev = node->prev; } ifupdown-ng-ifupdown-ng-0.12.1/libifupdown/list.h000066400000000000000000000030631422731055100217330ustar00rootroot00000000000000/* * libifupdown/list.h * Purpose: linked lists * * Copyright (c) 2020 Ariadne Conill * Copyright (c) 2020 Maximilian Wilhelm * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * This software is provided 'as is' and without any warranty, express or * implied. In no event shall the authors be liable for any damages arising * from the use of this software. */ #ifndef LIBIFUPDOWN_LIST_H__GUARD #define LIBIFUPDOWN_LIST_H__GUARD #include #include struct lif_node { struct lif_node *prev, *next; void *data; }; struct lif_list { struct lif_node *head, *tail; size_t length; }; extern void lif_list_free_nodes(struct lif_list *list); extern void lif_node_insert(struct lif_node *node, void *data, struct lif_list *list); extern void lif_node_insert_tail(struct lif_node *node, void *data, struct lif_list *list); extern void lif_node_delete(struct lif_node *node, struct lif_list *list); #define LIF_LIST_FOREACH(iter, head) \ for ((iter) = (head); (iter) != NULL; (iter) = (iter)->next) #define LIF_LIST_FOREACH_SAFE(iter, iter_next, head) \ for ((iter) = (head), (iter_next) = (iter) != NULL ? (iter)->next : NULL; (iter) != NULL; (iter) = (iter_next), (iter_next) = (iter) != NULL ? (iter)->next : NULL) #define LIF_LIST_FOREACH_REVERSE(iter, tail) \ for ((iter) = (tail); (iter) != NULL; (iter) = (iter)->prev) #endif ifupdown-ng-ifupdown-ng-0.12.1/libifupdown/state.c000066400000000000000000000102321422731055100220670ustar00rootroot00000000000000/* * libifupdown/state.c * Purpose: state management * * Copyright (c) 2020 Ariadne Conill * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * This software is provided 'as is' and without any warranty, express or * implied. In no event shall the authors be liable for any damages arising * from the use of this software. */ #include #include #include "libifupdown/state.h" #include "libifupdown/fgetline.h" #include "libifupdown/tokenize.h" bool lif_state_read(struct lif_dict *state, FILE *fd) { char linebuf[4096]; while (lif_fgetline(linebuf, sizeof linebuf, fd)) { char *bufp = linebuf; char *ifname = lif_next_token(&bufp); char *refcount = lif_next_token(&bufp); char *explicit = lif_next_token(&bufp); size_t rc = 1; char *equals_p = strchr(linebuf, '='); bool is_explicit = false; if (*explicit && !strcmp(explicit, "explicit")) is_explicit = true; if (*refcount) { rc = strtoul(refcount, NULL, 10); if (rc == 0 || rc == ULONG_MAX) rc = 1; } if (equals_p == NULL) { lif_state_upsert(state, ifname, &(struct lif_interface){ .ifname = ifname, .refcount = rc, .is_explicit = is_explicit }); continue; } *equals_p++ = '\0'; lif_state_upsert(state, ifname, &(struct lif_interface){ .ifname = equals_p, .refcount = rc, .is_explicit = is_explicit }); } return true; } bool lif_state_read_path(struct lif_dict *state, const char *path) { FILE *fd = fopen(path, "r"); bool ret; /* if file cannot be opened, assume an empty state */ if (fd == NULL) return true; ret = lif_state_read(state, fd); fclose(fd); return ret; } void lif_state_ref_if(struct lif_dict *state, const char *ifname, struct lif_interface *iface) { iface->refcount++; lif_state_upsert(state, ifname, iface); } void lif_state_unref_if(struct lif_dict *state, const char *ifname, struct lif_interface *iface) { if (iface->refcount == 0) return; iface->refcount--; if (iface->refcount) lif_state_upsert(state, ifname, iface); else lif_state_delete(state, ifname); } void lif_state_upsert(struct lif_dict *state, const char *ifname, struct lif_interface *iface) { lif_state_delete(state, ifname); struct lif_state_record *rec = calloc(1, sizeof(*rec)); rec->mapped_if = strdup(iface->ifname); rec->refcount = iface->refcount; rec->is_explicit = iface->is_explicit; lif_dict_add(state, ifname, rec); } void lif_state_delete(struct lif_dict *state, const char *ifname) { struct lif_dict_entry *entry = lif_dict_find(state, ifname); if (entry == NULL) return; struct lif_state_record *rec = entry->data; free(rec->mapped_if); free(rec); lif_dict_delete_entry(state, entry); } void lif_state_write(const struct lif_dict *state, FILE *f) { struct lif_node *iter; LIF_DICT_FOREACH(iter, state) { struct lif_dict_entry *entry = iter->data; struct lif_state_record *rec = entry->data; fprintf(f, "%s=%s %zu%s\n", entry->key, rec->mapped_if, rec->refcount, rec->is_explicit ? " explicit" : ""); } } bool lif_state_write_path(const struct lif_dict *state, const char *path) { FILE *fd = fopen(path, "w"); if (fd == NULL) return false; lif_state_write(state, fd); fclose(fd); return true; } struct lif_interface * lif_state_lookup(struct lif_dict *state, struct lif_dict *if_collection, const char *ifname) { struct lif_dict_entry *entry = lif_dict_find(state, ifname); if (entry == NULL) return NULL; struct lif_state_record *rec = entry->data; struct lif_dict_entry *if_entry = lif_dict_find(if_collection, rec->mapped_if); if (if_entry == NULL) return NULL; return if_entry->data; } bool lif_state_sync(struct lif_dict *state, struct lif_dict *if_collection) { struct lif_node *iter; LIF_DICT_FOREACH(iter, state) { struct lif_dict_entry *entry = iter->data; struct lif_state_record *rec = entry->data; struct lif_interface *iface = lif_interface_collection_find(if_collection, rec->mapped_if); iface->refcount = rec->refcount; iface->is_explicit = rec->is_explicit; } return true; } ifupdown-ng-ifupdown-ng-0.12.1/libifupdown/state.h000066400000000000000000000031701422731055100220770ustar00rootroot00000000000000/* * libifupdown/state.h * Purpose: state management * * Copyright (c) 2020 Ariadne Conill * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * This software is provided 'as is' and without any warranty, express or * implied. In no event shall the authors be liable for any damages arising * from the use of this software. */ #ifndef LIBIFUPDOWN_STATE_H__GUARD #define LIBIFUPDOWN_STATE_H__GUARD #include #include #include "libifupdown/interface.h" struct lif_state_record { char *mapped_if; size_t refcount; bool is_explicit; }; extern bool lif_state_read(struct lif_dict *state, FILE *f); extern bool lif_state_read_path(struct lif_dict *state, const char *path); extern void lif_state_upsert(struct lif_dict *state, const char *ifname, struct lif_interface *iface); extern void lif_state_ref_if(struct lif_dict *state, const char *ifname, struct lif_interface *iface); extern void lif_state_unref_if(struct lif_dict *state, const char *ifname, struct lif_interface *iface); extern void lif_state_delete(struct lif_dict *state, const char *ifname); extern void lif_state_write(const struct lif_dict *state, FILE *f); extern bool lif_state_write_path(const struct lif_dict *state, const char *path); extern struct lif_interface *lif_state_lookup(struct lif_dict *state, struct lif_dict *if_collection, const char *ifname); extern bool lif_state_sync(struct lif_dict *state, struct lif_dict *if_collection); #endif ifupdown-ng-ifupdown-ng-0.12.1/libifupdown/tokenize.h000066400000000000000000000021341422731055100226060ustar00rootroot00000000000000/* * libifupdown/tokenize.h * Purpose: tokenization helper * * Copyright (c) 2020 Ariadne Conill * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * This software is provided 'as is' and without any warranty, express or * implied. In no event shall the authors be liable for any damages arising * from the use of this software. */ #ifndef LIBIFUPDOWN_TOKENIZE_H__GUARD #define LIBIFUPDOWN_TOKENIZE_H__GUARD #include static inline char * lif_next_token_eq(char **buf) { char *out = *buf; while (*out && (isspace(*out) || *out == '=')) out++; char *end = out; while (*end && !isspace(*end) && *end != '=') end++; *end++ = '\0'; *buf = end; return out; } static inline char * lif_next_token(char **buf) { char *out = *buf; while (*out && isspace(*out)) out++; char *end = out; while (*end && !isspace(*end)) end++; *end++ = '\0'; *buf = end; return out; } #endif ifupdown-ng-ifupdown-ng-0.12.1/libifupdown/version.c000066400000000000000000000026511422731055100224420ustar00rootroot00000000000000/* * libifupdown/version.c * Purpose: lif_common_version() header * * Copyright (c) 2020 Ariadne Conill * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * This software is provided 'as is' and without any warranty, express or * implied. In no event shall the authors be liable for any damages arising * from the use of this software. */ #include #include #include #include "libifupdown/version.h" void lif_common_version(void) { printf(PACKAGE_NAME " " PACKAGE_VERSION "\n" "\n" "Copyright (c) 2020 Ariadne Conill \n" "Copyright (c) 2020 Maximilian Wilhelm \n" "\n" "Permission to use, copy, modify, and/or distribute this software for any\n" "purpose with or without fee is hereby granted, provided that the above\n" "copyright notice and this permission notice appear in all copies.\n" "\n" "This software is provided 'as is' and without any warranty, express or\n" "implied. In no event shall the authors be liable for any damages arising\n" "from the use of this software.\n" "\n" "Report bugs at <" PACKAGE_BUGREPORT ">.\n"); exit(EXIT_SUCCESS); } ifupdown-ng-ifupdown-ng-0.12.1/libifupdown/version.h000066400000000000000000000012371422731055100224460ustar00rootroot00000000000000/* * libifupdown/version.h * Purpose: lif_common_version() header * * Copyright (c) 2020 Ariadne Conill * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * This software is provided 'as is' and without any warranty, express or * implied. In no event shall the authors be liable for any damages arising * from the use of this software. */ #ifndef LIBIFUPDOWN_VERSION_H__GUARD #define LIBIFUPDOWN_VERSION_H__GUARD extern void lif_common_version(void); #endif ifupdown-ng-ifupdown-ng-0.12.1/libifupdown/yaml-base.c000066400000000000000000000052011422731055100226210ustar00rootroot00000000000000/* * libifupdown/yaml-base.c * Purpose: YAML implementation -- base * * Copyright (c) 2020 Ariadne Conill * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * This software is provided 'as is' and without any warranty, express or * implied. In no event shall the authors be liable for any damages arising * from the use of this software. */ #include #include "libifupdown/libifupdown.h" #include "libifupdown/yaml-base.h" void lif_yaml_document_init(struct lif_yaml_node *doc, const char *name) { memset(doc, '\0', sizeof *doc); doc->value_type = LIF_YAML_OBJECT; if (name != NULL) doc->name = strdup(name); } struct lif_yaml_node * lif_yaml_document_new(const char *name) { struct lif_yaml_node *doc = calloc(1, sizeof *doc); lif_yaml_document_init(doc, name); doc->malloced = true; return doc; } struct lif_yaml_node * lif_yaml_node_new_boolean(const char *name, bool value) { struct lif_yaml_node *node = calloc(1, sizeof *node); node->malloced = true; node->value_type = LIF_YAML_BOOLEAN; if (name != NULL) node->name = strdup(name); node->value.bool_value = value; return node; } struct lif_yaml_node * lif_yaml_node_new_string(const char *name, const char *value) { struct lif_yaml_node *node = calloc(1, sizeof *node); node->malloced = true; node->value_type = LIF_YAML_STRING; if (name != NULL) node->name = strdup(name); if (value != NULL) node->value.str_value = strdup(value); return node; } struct lif_yaml_node * lif_yaml_node_new_object(const char *name) { struct lif_yaml_node *node = calloc(1, sizeof *node); node->malloced = true; node->value_type = LIF_YAML_OBJECT; if (name != NULL) node->name = strdup(name); return node; } struct lif_yaml_node * lif_yaml_node_new_list(const char *name) { struct lif_yaml_node *node = calloc(1, sizeof *node); node->malloced = true; node->value_type = LIF_YAML_LIST; if (name != NULL) node->name = strdup(name); return node; } void lif_yaml_node_free(struct lif_yaml_node *node) { struct lif_node *iter, *next; LIF_LIST_FOREACH_SAFE(iter, next, node->children.head) { struct lif_yaml_node *iter_node = iter->data; lif_yaml_node_free(iter_node); } free(node->name); if (node->value_type == LIF_YAML_STRING) free(node->value.str_value); if (node->malloced) free(node); } void lif_yaml_node_append_child(struct lif_yaml_node *parent, struct lif_yaml_node *child) { lif_node_insert_tail(&child->node, child, &parent->children); } ifupdown-ng-ifupdown-ng-0.12.1/libifupdown/yaml-base.h000066400000000000000000000033261422731055100226340ustar00rootroot00000000000000/* * libifupdown/yaml-base.h * Purpose: YAML implementation -- base * * Copyright (c) 2020 Ariadne Conill * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * This software is provided 'as is' and without any warranty, express or * implied. In no event shall the authors be liable for any damages arising * from the use of this software. */ #ifndef LIBIFUPDOWN_YAML_BASE_H__GUARD #define LIBIFUPDOWN_YAML_BASE_H__GUARD #include "libifupdown/libifupdown.h" /* this is a subset of types supported by our implementation */ enum lif_yaml_value { LIF_YAML_STRING, LIF_YAML_LIST, LIF_YAML_OBJECT, LIF_YAML_BOOLEAN }; struct lif_yaml_node { struct lif_node node; bool malloced; char *name; enum lif_yaml_value value_type; union { char *str_value; /* for string nodes */ bool bool_value; /* for boolean nodes */ } value; struct lif_list children; /* for list and object nodes */ }; extern void lif_yaml_document_init(struct lif_yaml_node *doc, const char *name); extern struct lif_yaml_node *lif_yaml_document_new(const char *name); extern struct lif_yaml_node *lif_yaml_node_new_boolean(const char *name, bool value); extern struct lif_yaml_node *lif_yaml_node_new_string(const char *name, const char *value); extern struct lif_yaml_node *lif_yaml_node_new_object(const char *name); extern struct lif_yaml_node *lif_yaml_node_new_list(const char *name); extern void lif_yaml_node_free(struct lif_yaml_node *node); extern void lif_yaml_node_append_child(struct lif_yaml_node *parent, struct lif_yaml_node *child); #endif ifupdown-ng-ifupdown-ng-0.12.1/libifupdown/yaml-writer.c000066400000000000000000000035041422731055100232270ustar00rootroot00000000000000/* * libifupdown/yaml-writer.c * Purpose: YAML implementation -- writer * * Copyright (c) 2020 Ariadne Conill * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * This software is provided 'as is' and without any warranty, express or * implied. In no event shall the authors be liable for any damages arising * from the use of this software. */ #include #include #include "libifupdown/libifupdown.h" #include "libifupdown/yaml-base.h" #include "libifupdown/yaml-writer.h" static const size_t INDENT_WIDTH = 2; static void lif_yaml_write_node(const struct lif_yaml_node *node, FILE *f, size_t indent, bool type_annotations) { const struct lif_node *iter; if (node->name != NULL) fprintf(f, "%*s%s: ", (int) indent, "", node->name); size_t child_indent = indent + INDENT_WIDTH; switch (node->value_type) { case LIF_YAML_BOOLEAN: fprintf(f, "%s%s\n", type_annotations ? "!!bool " : "", node->value.bool_value ? "true" : "false"); break; case LIF_YAML_STRING: fprintf(f, "%s%s\n", type_annotations ? "!!str " : "", node->value.str_value); break; case LIF_YAML_OBJECT: fprintf(f, "\n"); break; case LIF_YAML_LIST: fprintf(f, "\n"); child_indent += INDENT_WIDTH; break; } LIF_LIST_FOREACH(iter, node->children.head) { const struct lif_yaml_node *iter_node = iter->data; if (node->value_type == LIF_YAML_LIST) fprintf(f, "%*s-\n", (int) (child_indent - INDENT_WIDTH), ""); lif_yaml_write_node(iter_node, f, child_indent, type_annotations); } } void lif_yaml_write(const struct lif_yaml_node *doc, FILE *f, bool type_annotations) { lif_yaml_write_node(doc, f, 0, type_annotations); } ifupdown-ng-ifupdown-ng-0.12.1/libifupdown/yaml-writer.h000066400000000000000000000014551422731055100232370ustar00rootroot00000000000000/* * libifupdown/yaml-writer.h * Purpose: YAML implementation -- writer * * Copyright (c) 2020 Ariadne Conill * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * This software is provided 'as is' and without any warranty, express or * implied. In no event shall the authors be liable for any damages arising * from the use of this software. */ #ifndef LIBIFUPDOWN_YAML_WRITER_H__GUARD #define LIBIFUPDOWN_YAML_WRITER_H__GUARD #include "libifupdown/libifupdown.h" #include "libifupdown/yaml-base.h" extern void lif_yaml_write(const struct lif_yaml_node *doc, FILE *f, bool type_annotations); #endif ifupdown-ng-ifupdown-ng-0.12.1/tests/000077500000000000000000000000001422731055100174255ustar00rootroot00000000000000ifupdown-ng-ifupdown-ng-0.12.1/tests/Kyuafile000066400000000000000000000003271422731055100211230ustar00rootroot00000000000000syntax(2) test_suite('ifupdown-ng') atf_test_program{name='multicall_test'} atf_test_program{name='ifquery_test'} atf_test_program{name='ifup_test'} atf_test_program{name='ifdown_test'} include('linux/Kyuafile') ifupdown-ng-ifupdown-ng-0.12.1/tests/executors/000077500000000000000000000000001422731055100214465ustar00rootroot00000000000000ifupdown-ng-ifupdown-ng-0.12.1/tests/executors/bond000077700000000000000000000000001422731055100250162mock-executorustar00rootroot00000000000000ifupdown-ng-ifupdown-ng-0.12.1/tests/executors/bridge000077700000000000000000000000001422731055100253302mock-executorustar00rootroot00000000000000ifupdown-ng-ifupdown-ng-0.12.1/tests/executors/dhcp000077700000000000000000000000001422731055100250122mock-executorustar00rootroot00000000000000ifupdown-ng-ifupdown-ng-0.12.1/tests/executors/link000077700000000000000000000000001422731055100250312mock-executorustar00rootroot00000000000000ifupdown-ng-ifupdown-ng-0.12.1/tests/executors/mock-dependency-generator000077500000000000000000000002151422731055100264230ustar00rootroot00000000000000#!/bin/sh [ -z "$IF_MOCK_DEPENDS" ] && IF_MOCK_DEPENDS="eth0 eth1 eth2 eth3 eth4" case "$PHASE" in depend) echo "$IF_MOCK_DEPENDS" ;; esac ifupdown-ng-ifupdown-ng-0.12.1/tests/executors/mock-executor000077500000000000000000000000211422731055100241520ustar00rootroot00000000000000#!/bin/sh exit 0 ifupdown-ng-ifupdown-ng-0.12.1/tests/executors/static000077700000000000000000000000001422731055100253632mock-executorustar00rootroot00000000000000ifupdown-ng-ifupdown-ng-0.12.1/tests/executors/vlan000077500000000000000000000001321422731055100223300ustar00rootroot00000000000000#!/bin/sh case "$PHASE" in depend) RAW_DEVICE="${IFACE%.*}" echo "$RAW_DEVICE" ;; esac ifupdown-ng-ifupdown-ng-0.12.1/tests/fixtures/000077500000000000000000000000001422731055100212765ustar00rootroot00000000000000ifupdown-ng-ifupdown-ng-0.12.1/tests/fixtures/alias-home-work.interfaces000066400000000000000000000002111422731055100263340ustar00rootroot00000000000000iface home inet dhcp iface work address 203.0.113.2/24 address 2001:db8:1000:2::2/64 gateway 203.0.113.1 gateway 2001:db8:1000:2::1 ifupdown-ng-ifupdown-ng-0.12.1/tests/fixtures/alias-home.ifstate000066400000000000000000000000131422731055100246700ustar00rootroot00000000000000wlan0=home ifupdown-ng-ifupdown-ng-0.12.1/tests/fixtures/alias-work.ifstate000066400000000000000000000000131422731055100247220ustar00rootroot00000000000000wlan0=work ifupdown-ng-ifupdown-ng-0.12.1/tests/fixtures/bonded-bridge.ifstate000066400000000000000000000000501422731055100253370ustar00rootroot00000000000000eth0=eth0 eth1=eth1 bond0=bond0 br0=br0 ifupdown-ng-ifupdown-ng-0.12.1/tests/fixtures/bonded-bridge.interfaces000066400000000000000000000003671422731055100260360ustar00rootroot00000000000000iface bond0 use bond requires eth0 eth1 bond-mode 802.3ad bond-xmit-hash-policy layer2+3 auto br0 iface br0 use bridge requires bond0 address 203.0.113.2/24 address 2001:db8:1000:2::2/64 gateway 203.0.113.1 gateway 2001:db8:1000:2::1 ifupdown-ng-ifupdown-ng-0.12.1/tests/fixtures/deferred-teardown-1.ifstate000066400000000000000000000001041422731055100264110ustar00rootroot00000000000000lo=lo 1 br0=br0 1 bond0=bond0 2 eth0=eth0 3 eth1=eth1 2 tun0=tun0 1 ifupdown-ng-ifupdown-ng-0.12.1/tests/fixtures/deferred-teardown-1.interfaces000066400000000000000000000001371422731055100271030ustar00rootroot00000000000000auto br0 iface br0 requires bond0 iface bond0 requires eth0 eth1 iface tun0 requires eth0 ifupdown-ng-ifupdown-ng-0.12.1/tests/fixtures/deferred-teardown-2.ifstate000066400000000000000000000000741422731055100264200ustar00rootroot00000000000000eth0=eth0 5 tun0=tun0 1 tun1=tun1 1 tun2=tun2 1 tun3=tun3 1 ifupdown-ng-ifupdown-ng-0.12.1/tests/fixtures/deferred-teardown-2.interfaces000066400000000000000000000001531422731055100271020ustar00rootroot00000000000000iface tun0 requires eth0 iface tun1 requires eth0 iface tun2 requires eth0 iface tun3 requires eth0 ifupdown-ng-ifupdown-ng-0.12.1/tests/fixtures/dependency-loop.ifstate000066400000000000000000000000161422731055100257410ustar00rootroot00000000000000lo=lo a=a b=b ifupdown-ng-ifupdown-ng-0.12.1/tests/fixtures/dependency-loop.interfaces000066400000000000000000000001131422731055100264230ustar00rootroot00000000000000auto a iface a use link requires b auto b iface b use link requires a ifupdown-ng-ifupdown-ng-0.12.1/tests/fixtures/dhcp-eth0.interfaces000066400000000000000000000000371422731055100251170ustar00rootroot00000000000000auto eth0 iface eth0 inet dhcp ifupdown-ng-ifupdown-ng-0.12.1/tests/fixtures/dhcp-hostname-rewrite.interfaces000066400000000000000000000001411422731055100275500ustar00rootroot00000000000000iface eth0 use dhcp hostname foo iface eth1 use dhcp iface eth2 use dhcp dhcp-hostname barifupdown-ng-ifupdown-ng-0.12.1/tests/fixtures/gre.interfaces000066400000000000000000000003211422731055100241140ustar00rootroot00000000000000auto tun0 iface tun0 gre-local 203.0.113.2 gre-remote 203.0.113.1 gre-dev eth0 gre-ttl 255 gre-flags nopmtudisc ignore-df address 203.0.113.10/30 gateway 203.0.113.9 iface eth0 address 203.0.113.2/30 ifupdown-ng-ifupdown-ng-0.12.1/tests/fixtures/inheritance.interfaces000066400000000000000000000002771422731055100256420ustar00rootroot00000000000000iface base0 address 203.0.113.2/24 address 2001:db8:1000:2::2/64 iface inherit0 inherits base0 address 203.0.113.3/24 iface inherit1 inherit base0 address 203.0.113.4/24 ifupdown-ng-ifupdown-ng-0.12.1/tests/fixtures/mock-dependency-generator-2.ifstate000066400000000000000000000000501422731055100300420ustar00rootroot00000000000000eth0=eth0 eth1=eth1 bond0=bond0 br0=br0 ifupdown-ng-ifupdown-ng-0.12.1/tests/fixtures/mock-dependency-generator-2.interfaces000066400000000000000000000002011422731055100305240ustar00rootroot00000000000000iface br0 use mock-dependency-generator mock-depends bond0 iface bond0 use mock-dependency-generator mock-depends eth0 eth1 ifupdown-ng-ifupdown-ng-0.12.1/tests/fixtures/mock-dependency-generator.ifstate000066400000000000000000000000721422731055100277070ustar00rootroot00000000000000eth0=eth0 eth1=eth1 eth2=eth2 eth3=eth3 eth4=eth4 br0=br0 ifupdown-ng-ifupdown-ng-0.12.1/tests/fixtures/mock-dependency-generator.interfaces000066400000000000000000000000511422731055100303700ustar00rootroot00000000000000iface br0 use mock-dependency-generator ifupdown-ng-ifupdown-ng-0.12.1/tests/fixtures/ppp-legacy.interfaces000066400000000000000000000001051422731055100254000ustar00rootroot00000000000000auto ppp0 iface ppp0 inet ppp requires eth0 provider someisp ifupdown-ng-ifupdown-ng-0.12.1/tests/fixtures/ppp.interfaces000066400000000000000000000001001422731055100241310ustar00rootroot00000000000000auto ppp0 iface ppp0 requires eth0 ppp-provider someisp ifupdown-ng-ifupdown-ng-0.12.1/tests/fixtures/stanza-merging.interfaces000066400000000000000000000003361422731055100262730ustar00rootroot00000000000000# cidr and without-cidr should be equivalent iface cidr address 203.0.113.1/32 iface cidr address 203.0.113.2/24 iface without-cidr address 203.0.113.1 netmask 32 iface without-cidr address 203.0.113.2 netmask 24 ifupdown-ng-ifupdown-ng-0.12.1/tests/fixtures/static-eth0-ptp.interfaces000066400000000000000000000002221422731055100262650ustar00rootroot00000000000000auto eth0 iface eth0 address 203.0.113.2/32 pointopoint 192.0.2.1 gateway 192.0.2.1 address 2001:db8:1000:2::2/64 gateway 2001:db8:1000:2::1 ifupdown-ng-ifupdown-ng-0.12.1/tests/fixtures/static-eth0-v4-netmask.interfaces000066400000000000000000000001301422731055100274510ustar00rootroot00000000000000auto eth0 iface eth0 address 203.0.113.2 netmask 255.255.255.248 gateway 203.0.113.1 ifupdown-ng-ifupdown-ng-0.12.1/tests/fixtures/static-eth0-v4.interfaces000066400000000000000000000001021422731055100260100ustar00rootroot00000000000000auto eth0 iface eth0 address 203.0.113.2/24 gateway 203.0.113.1 ifupdown-ng-ifupdown-ng-0.12.1/tests/fixtures/static-eth0-v6-netmask.interfaces000066400000000000000000000001321422731055100274550ustar00rootroot00000000000000auto eth0 iface eth0 address 2001:db8:1000:2::2 netmask 112 gateway 2001:db8:1000:2::1 ifupdown-ng-ifupdown-ng-0.12.1/tests/fixtures/static-eth0-v6.interfaces000066400000000000000000000001201422731055100260120ustar00rootroot00000000000000auto eth0 iface eth0 address 2001:db8:1000:2::2/64 gateway 2001:db8:1000:2::1 ifupdown-ng-ifupdown-ng-0.12.1/tests/fixtures/static-eth0.interfaces000066400000000000000000000001751422731055100254730ustar00rootroot00000000000000auto eth0 iface eth0 address 203.0.113.2/24 address 2001:db8:1000:2::2/64 gateway 203.0.113.1 gateway 2001:db8:1000:2::1 ifupdown-ng-ifupdown-ng-0.12.1/tests/fixtures/teardown-dep-ordering.ifstate000066400000000000000000000000401422731055100270510ustar00rootroot00000000000000dummy=dummy 2 bat=bat 2 br=br 1 ifupdown-ng-ifupdown-ng-0.12.1/tests/fixtures/teardown-dep-ordering.interfaces000066400000000000000000000002161422731055100275420ustar00rootroot00000000000000auto dummy iface dummy link-type dummy auto bat iface bat link-type dummy requires dummy auto br iface br link-type dummy requires bat ifupdown-ng-ifupdown-ng-0.12.1/tests/fixtures/tunnel-ifupdown2.interfaces000066400000000000000000000003241422731055100265620ustar00rootroot00000000000000auto tun0 iface tun0 tunnel-local 203.0.113.2 tunnel-endpoint 203.0.113.1 tunnel-mode gre tunnel-physdev eth0 tunnel-ttl 255 address 203.0.113.10/30 gateway 203.0.113.9 iface eth0 address 203.0.113.2/30 ifupdown-ng-ifupdown-ng-0.12.1/tests/fixtures/tunnel-legacy.interfaces000066400000000000000000000002641422731055100261140ustar00rootroot00000000000000auto tun0 iface tun0 local 203.0.113.2 endpoint 203.0.113.1 mode gre tunnel-dev eth0 ttl 255 address 203.0.113.10/30 gateway 203.0.113.9 iface eth0 address 203.0.113.2/30 ifupdown-ng-ifupdown-ng-0.12.1/tests/fixtures/tunnel.interfaces000066400000000000000000000003161422731055100246500ustar00rootroot00000000000000auto tun0 iface tun0 tunnel-local 203.0.113.2 tunnel-remote 203.0.113.1 tunnel-mode gre tunnel-dev eth0 tunnel-ttl 255 address 203.0.113.10/30 gateway 203.0.113.9 iface eth0 address 203.0.113.2/30 ifupdown-ng-ifupdown-ng-0.12.1/tests/fixtures/use-dhcp-eth0.interfaces000066400000000000000000000000371422731055100257110ustar00rootroot00000000000000auto eth0 iface eth0 use dhcp ifupdown-ng-ifupdown-ng-0.12.1/tests/fixtures/vlan-complex.interfaces000066400000000000000000000005221422731055100257470ustar00rootroot00000000000000# From Alpine issue #11885. iface lo inet loopback auto eth0 iface eth0 address 1.2.3.4/24 address abcd:ef12:3456:3::4/64 mtu 8000 auto servers iface servers address 1.2.10.4/24 gateway 1.2.10.1 address abcd:ef12:3456:10::4/64 gateway abcd:ef12:3456:10::1 mtu 8000 vlan-raw-device eth0 vlan_id 5 ifupdown-ng-ifupdown-ng-0.12.1/tests/fixtures/vlan-named.interfaces000066400000000000000000000001161422731055100253630ustar00rootroot00000000000000iface servers vlan-raw-device eth0 vlan-id 8 address 2001:db8:1000:2::2/64 ifupdown-ng-ifupdown-ng-0.12.1/tests/fixtures/vlan.ifstate000066400000000000000000000000301422731055100236100ustar00rootroot00000000000000eth0=eth0 eth0.8=eth0.8 ifupdown-ng-ifupdown-ng-0.12.1/tests/fixtures/vlan.interfaces000066400000000000000000000000541422731055100243020ustar00rootroot00000000000000iface eth0.8 address 2001:db8:1000:2::2/64 ifupdown-ng-ifupdown-ng-0.12.1/tests/fixtures/vrf-ifupdown2.interfaces000066400000000000000000000001211422731055100260450ustar00rootroot00000000000000iface vrf-red vrf-table 1 auto eth0 iface eth0 use dhcp vrf vrf-red ifupdown-ng-ifupdown-ng-0.12.1/tests/fixtures/vrf.interfaces000066400000000000000000000001601422731055100241350ustar00rootroot00000000000000iface vrf-red vrf-table 1 gateway 203.0.113.2 auto eth0 iface eth0 use dhcp vrf-member vrf-red ifupdown-ng-ifupdown-ng-0.12.1/tests/fixtures/wireguard.interfaces000066400000000000000000000001761422731055100253400ustar00rootroot00000000000000iface eth0 address 203.0.113.2/24 gateway 203.0.113.1 auto wg0 iface wg0 use wireguard address 1.2.3.4/24 requires eth0 ifupdown-ng-ifupdown-ng-0.12.1/tests/fixtures/without-netmask.interfaces000066400000000000000000000001021422731055100264770ustar00rootroot00000000000000iface v6 address 2001:470:1f10::1 iface v4 address 203.0.113.2 ifupdown-ng-ifupdown-ng-0.12.1/tests/ifdown_test000077500000000000000000000137001422731055100217010ustar00rootroot00000000000000#!/usr/bin/env atf-sh . $(atf_get_srcdir)/test_env.sh tests_init \ noargs \ lo_always_auto \ dual_stack \ static_ipv4 \ static_ipv4_netmask \ static_ipv6 \ static_ipv6_netmask \ inet_dhcp \ use_dhcp \ alias_eth0_home \ alias_eth0_work \ bonded_bridge \ learned_dependency \ learned_dependency_2 \ learned_executor \ implicit_vlan \ deferred_teardown_1 \ deferred_teardown_2 \ deferred_teardown_3 \ teardown_dep_ordering \ regress_opt_f \ dependency_loop_breaking noargs_body() { atf_check -s exit:1 -e ignore ifdown -S/dev/null } lo_always_auto_body() { atf_check -s exit:0 -e ignore -o match:'executors/link' \ ifdown -f -S/dev/null -E $EXECUTORS -i/dev/null -n -a } dual_stack_body() { atf_check -s exit:0 -e ignore \ -o match:'executors/link' \ -o match:'executors/static' \ ifdown -f -S/dev/null -E $EXECUTORS -i $FIXTURES/static-eth0.interfaces -n -a } static_ipv4_body() { atf_check -s exit:0 -e ignore \ -o match:'executors/link' \ -o match:'executors/static' \ ifdown -f -S/dev/null -E $EXECUTORS -i $FIXTURES/static-eth0-v4.interfaces -n -a } static_ipv4_netmask_body() { atf_check -s exit:0 -e ignore \ -o match:'executors/link' \ -o match:'executors/static' \ ifdown -f -S/dev/null -E $EXECUTORS -i $FIXTURES/static-eth0-v4-netmask.interfaces -n -a } static_ipv6_body() { atf_check -s exit:0 -e ignore \ -o match:'executors/link' \ -o match:'executors/static' \ ifdown -f -S/dev/null -E $EXECUTORS -i $FIXTURES/static-eth0-v6.interfaces -n -a } static_ipv6_netmask_body() { atf_check -s exit:0 -e ignore \ -o match:'executors/link' \ -o match:'executors/static' \ ifdown -f -S/dev/null -E $EXECUTORS -i $FIXTURES/static-eth0-v6-netmask.interfaces -n -a } inet_dhcp_body() { atf_check -s exit:0 -e ignore \ -o match:'executors/link' \ -o match:'executors/dhcp' \ ifdown -f -S/dev/null -E $EXECUTORS -i $FIXTURES/dhcp-eth0.interfaces -n -a } use_dhcp_body() { atf_check -s exit:0 -e ignore \ -o match:'executors/link' \ -o match:'executors/dhcp' \ ifdown -f -S/dev/null -E $EXECUTORS -i $FIXTURES/use-dhcp-eth0.interfaces -n -a } alias_eth0_home_body() { atf_check -s exit:0 -e ignore \ -o match:'executors/link' \ -o match:'executors/dhcp' \ ifdown -S $FIXTURES/alias-home.ifstate \ -E $EXECUTORS -i $FIXTURES/alias-home-work.interfaces -n wlan0 } alias_eth0_work_body() { atf_check -s exit:0 -e ignore \ -o match:'executors/link' \ -o match:'executors/static' \ ifdown -S $FIXTURES/alias-work.ifstate \ -E $EXECUTORS -i $FIXTURES/alias-home-work.interfaces -n wlan0 } bonded_bridge_body() { atf_check -s exit:0 -e ignore \ -o match:'executors/link' \ -o match:'executors/bond' \ -o match:'executors/bridge' \ -o match:'executors/static' \ ifdown -S $FIXTURES/bonded-bridge.ifstate \ -E $EXECUTORS -i $FIXTURES/bonded-bridge.interfaces -n br0 } learned_dependency_body() { atf_check -s exit:0 -o ignore \ -e match:"eth0" \ -e match:"eth1" \ -e match:"eth2" \ -e match:"eth3" \ -e match:"eth4" \ ifdown -n -S $FIXTURES/mock-dependency-generator.ifstate \ -E $EXECUTORS \ -i $FIXTURES/mock-dependency-generator.interfaces br0 } learned_dependency_2_body() { atf_check -s exit:0 -o ignore \ -e match:"bond0" \ -e match:"eth0" \ -e match:"eth1" \ ifdown -n -S $FIXTURES/mock-dependency-generator-2.ifstate \ -E $EXECUTORS \ -i $FIXTURES/mock-dependency-generator-2.interfaces br0 } learned_executor_body() { atf_check -s exit:0 -o ignore \ -e match:"attempting to run mock executor" \ ifdown -n -S $FIXTURES/mock-dependency-generator-2.ifstate \ -E $EXECUTORS \ -i $FIXTURES/mock-dependency-generator-2.interfaces br0 } implicit_vlan_body() { atf_check -s exit:0 -o ignore \ -e match:"attempting to run vlan executor" \ -e match:"attempting to run link executor" \ ifdown -n -S $FIXTURES/vlan.ifstate -E $EXECUTORS -i $FIXTURES/vlan.interfaces eth0.8 } deferred_teardown_1_body() { atf_check -s exit:0 -o ignore \ -e match:"skipping dependent interface eth0 \\(of bond0\\) -- transient dependencies still exist" \ -e match:"changing state of dependent interface eth1 \\(of bond0\\) to down" \ ifdown -n -S $FIXTURES/deferred-teardown-1.ifstate -E $EXECUTORS \ -i $FIXTURES/deferred-teardown-1.interfaces br0 } deferred_teardown_2_body() { atf_check -s exit:0 -o ignore \ -e match:"skipping dependent interface eth0 \\(of tun0\\) -- transient dependencies still exist" \ -e match:"skipping dependent interface eth0 \\(of tun1\\) -- transient dependencies still exist" \ -e match:"skipping dependent interface eth0 \\(of tun2\\) -- transient dependencies still exist" \ ifdown -n -S $FIXTURES/deferred-teardown-2.ifstate -E $EXECUTORS \ -i $FIXTURES/deferred-teardown-2.interfaces tun0 tun1 tun2 } deferred_teardown_3_body() { atf_check -s exit:0 -o ignore \ -e match:"skipping dependent interface eth0 \\(of tun0\\) -- transient dependencies still exist" \ -e match:"skipping dependent interface eth0 \\(of tun1\\) -- transient dependencies still exist" \ -e match:"skipping dependent interface eth0 \\(of tun2\\) -- transient dependencies still exist" \ -e match:"changing state of dependent interface eth0 \\(of tun3\\) to down" \ ifdown -n -S $FIXTURES/deferred-teardown-2.ifstate -E $EXECUTORS \ -i $FIXTURES/deferred-teardown-2.interfaces tun0 tun1 tun2 tun3 } teardown_dep_ordering_body() { atf_check -s exit:0 -o ignore \ -e match:"skipping auto interface bat" \ -e match:"skipping auto interface dummy" \ ifdown -n -i $FIXTURES/teardown-dep-ordering.interfaces \ -S $FIXTURES/teardown-dep-ordering.ifstate -E $EXECUTORS -a } regress_opt_f_body() { atf_check -s exit:0 -o ignore -e ignore \ ifdown -n -S $FIXTURES/vlan.ifstate -E $EXECUTORS -i $FIXTURES/vlan.interfaces -f eth0.8 } dependency_loop_breaking_body() { atf_check -s exit:0 -o ignore \ -e match:"ifdown: skipping auto interface a \\(already deconfigured\\), use --force to force deconfiguration" \ ifdown -n -i $FIXTURES/dependency-loop.interfaces -E $EXECUTORS -a } ifupdown-ng-ifupdown-ng-0.12.1/tests/ifquery_test000077500000000000000000000202451422731055100221010ustar00rootroot00000000000000#!/usr/bin/env atf-sh . $(atf_get_srcdir)/test_env.sh tests_init \ noargs \ loopback_always_configured \ static_dual_stack \ static_ipv4 \ static_ipv6 \ dhcp_ipv4 \ use_dhcp \ state_query_home \ state_query_work \ state_print \ learned_dependency \ learned_dependency_2 \ learned_executor \ inheritance_0 \ inheritance_1 \ implicit_vlan \ vrf_dependency \ vrf_ifupdown2_rewrite \ vrf_ifupdown2_dependency \ vrf_implicit_static_gateway \ ppp_dependency \ ppp_legacy_rewrite \ tunnel_dependency \ tunnel_legacy_dependency \ tunnel_legacy_rewrite \ tunnel_ifupdown2_dependency \ tunnel_ifupdown2_rewrite \ gre_dependency \ vlan_explicit_learned_dependency \ vlan_guessed_learned_dependency \ vlan_complex_learned_dependency \ wireguard \ allow_undefined_positive \ allow_undefined_negative \ default_netmask_v4 \ default_netmask_v6 \ stanza_merging_with_cidr \ stanza_merging_without_cidr \ dhcp_hostname_rewrite \ dhcp_hostname_inference \ dhcp_hostname_replacement noargs_body() { atf_check -s exit:1 -e ignore ifquery -S/dev/null } loopback_always_configured_body() { atf_check -s exit:0 -o match:"use loopback" \ ifquery -S/dev/null -i $FIXTURES/static-eth0.interfaces lo } static_dual_stack_body() { atf_check -s exit:0 -o match:"address 203.0.113.2/24" \ -o match:"address 2001:db8:1000:2::2/64" \ -o match:"gateway 203.0.113.1" \ -o match:"gateway 2001:db8:1000:2::1" \ ifquery -S/dev/null -i $FIXTURES/static-eth0.interfaces eth0 } static_ipv4_body() { atf_check -s exit:0 -o match:"address 203.0.113.2/24" \ -o match:"gateway 203.0.113.1" \ ifquery -S/dev/null -i $FIXTURES/static-eth0-v4.interfaces eth0 } static_ipv6_body() { atf_check -s exit:0 -o match:"address 2001:db8:1000:2::2/64" \ -o match:"gateway 2001:db8:1000:2::1" \ ifquery -S/dev/null -i $FIXTURES/static-eth0-v6.interfaces eth0 } dhcp_ipv4_body() { atf_check -s exit:0 -o match:"use dhcp" \ ifquery -S/dev/null -i $FIXTURES/dhcp-eth0.interfaces eth0 } use_dhcp_body() { atf_check -s exit:0 -o match:"use dhcp" \ ifquery -S/dev/null -i $FIXTURES/use-dhcp-eth0.interfaces eth0 } state_query_home_body() { atf_check -s exit:0 -o match:"iface home" \ ifquery -S $FIXTURES/alias-home.ifstate -i $FIXTURES/alias-home-work.interfaces wlan0 } state_query_work_body() { atf_check -s exit:0 -o match:"iface work" \ ifquery -S $FIXTURES/alias-work.ifstate -i $FIXTURES/alias-home-work.interfaces wlan0 } state_print_body() { atf_check -s exit:0 -o match:"wlan0=home" \ ifquery -S $FIXTURES/alias-home.ifstate -i $FIXTURES/alias-home-work.interfaces -s atf_check -s exit:0 -o match:"wlan0=work" \ ifquery -S $FIXTURES/alias-work.ifstate -i $FIXTURES/alias-home-work.interfaces -s } learned_dependency_body() { atf_check -s exit:0 -o match:"requires eth0 eth1 eth2 eth3 eth4" \ ifquery -E $EXECUTORS -i $FIXTURES/mock-dependency-generator.interfaces br0 } learned_dependency_2_body() { atf_check -s exit:0 -o match:"requires bond0" \ ifquery -E $EXECUTORS -i $FIXTURES/mock-dependency-generator-2.interfaces br0 } learned_executor_body() { atf_check -s exit:0 -o match:"use mock" \ ifquery -E $EXECUTORS -i $FIXTURES/mock-dependency-generator-2.interfaces br0 } inheritance_0_body() { atf_check -s exit:0 -o match:"inherit base0" \ -o match:"address 203.0.113.2/24" \ -o match:"address 203.0.113.3/24" \ -o match:"address 2001:db8:1000:2::2/64" \ ifquery -E $EXECUTORS -i $FIXTURES/inheritance.interfaces inherit0 } inheritance_1_body() { atf_check -s exit:0 -o match:"inherit base0" \ -o match:"address 203.0.113.2/24" \ -o match:"address 203.0.113.4/24" \ -o match:"address 2001:db8:1000:2::2/64" \ ifquery -E $EXECUTORS -i $FIXTURES/inheritance.interfaces inherit1 } implicit_vlan_body() { atf_check -s exit:0 -o match:"requires eth0" \ -o match:"use vlan" \ ifquery -E $EXECUTORS -i $FIXTURES/vlan.interfaces eth0.8 } vrf_dependency_body() { atf_check -s exit:0 -o match:"requires vrf-red" \ ifquery -E $EXECUTORS_LINUX -i $FIXTURES/vrf.interfaces eth0 } vrf_ifupdown2_rewrite_body() { atf_check -s exit:0 -o match:"vrf-member vrf-red" \ ifquery -E $EXECUTORS -i $FIXTURES/vrf-ifupdown2.interfaces eth0 } vrf_ifupdown2_dependency_body() { atf_check -s exit:0 -o match:"requires vrf-red" \ ifquery -E $EXECUTORS_LINUX -i $FIXTURES/vrf-ifupdown2.interfaces eth0 } vrf_implicit_static_gateway_body() { atf_check -s exit:0 -o match:"use static" \ ifquery -E $EXECUTORS_LINUX -i $FIXTURES/vrf.interfaces vrf-red } ppp_dependency_body() { atf_check -s exit:0 -o match:"requires eth0" \ ifquery -E $EXECUTORS_LINUX -i $FIXTURES/ppp.interfaces ppp0 } ppp_legacy_rewrite_body() { atf_check -s exit:0 -o match:"ppp-provider someisp" \ ifquery -E $EXECUTORS_LINUX -i $FIXTURES/ppp-legacy.interfaces ppp0 } tunnel_dependency_body() { atf_check -s exit:0 -o match:"requires eth0" \ ifquery -E $EXECUTORS_LINUX -i $FIXTURES/tunnel.interfaces tun0 } tunnel_legacy_dependency_body() { atf_check -s exit:0 -o match:"requires eth0" \ ifquery -E $EXECUTORS_LINUX -i $FIXTURES/tunnel-legacy.interfaces tun0 } tunnel_ifupdown2_dependency_body() { atf_check -s exit:0 -o match:"requires eth0" \ ifquery -E $EXECUTORS_LINUX -i $FIXTURES/tunnel-ifupdown2.interfaces tun0 } tunnel_legacy_rewrite_body() { atf_check -s exit:0 \ -o match:"tunnel-local 203.0.113.2" \ -o match:"tunnel-remote 203.0.113.1" \ -o match:"tunnel-mode gre" \ -o match:"tunnel-ttl 255" \ ifquery -E $EXECUTORS_LINUX -i $FIXTURES/tunnel-legacy.interfaces tun0 } tunnel_ifupdown2_rewrite_body() { atf_check -s exit:0 \ -o match:"tunnel-local 203.0.113.2" \ -o match:"tunnel-remote 203.0.113.1" \ -o match:"tunnel-mode gre" \ -o match:"tunnel-ttl 255" \ ifquery -E $EXECUTORS_LINUX -i $FIXTURES/tunnel-ifupdown2.interfaces tun0 } gre_dependency_body() { atf_check -s exit:0 -o match:"requires eth0" \ ifquery -E $EXECUTORS_LINUX -i $FIXTURES/gre.interfaces tun0 } vlan_explicit_learned_dependency_body() { atf_check -s exit:0 -o match:"requires eth0" \ -o match:"use vlan" \ ifquery -E $EXECUTORS_LINUX -i $FIXTURES/vlan-named.interfaces servers } vlan_guessed_learned_dependency_body() { atf_check -s exit:0 -o match:"requires eth0" \ -o match:"use vlan" \ ifquery -E $EXECUTORS_LINUX -i $FIXTURES/vlan.interfaces eth0.8 } vlan_complex_learned_dependency_body() { atf_check -s exit:0 -o match:"requires eth0" \ -o match:"use vlan" \ -o match:"address 1.2.10.4/24" \ -o match:"gateway 1.2.10.1" \ -o match:"address abcd:ef12:3456:10::4/64" \ -o match:"gateway abcd:ef12:3456:10::1" \ -o match:"vlan-raw-device eth0" \ ifquery -E $EXECUTORS_LINUX -i $FIXTURES/vlan-complex.interfaces servers } wireguard_body() { atf_check -s exit:0 \ -o match:"requires eth0" \ -o match:"use wireguard" \ ifquery -E $EXECUTORS_LINUX -i $FIXTURES/wireguard.interfaces wg0 } allow_undefined_positive_body() { atf_check -s exit:0 \ -o ignore \ -e ignore \ ifquery -U -i /dev/null -p address foo } allow_undefined_negative_body() { atf_check -s exit:1 \ -o ignore \ -e ignore \ ifquery -i /dev/null -p address foo } default_netmask_v4_body() { atf_check -s exit:0 \ -o match:"203.0.113.2/24" \ ifquery -i $FIXTURES/without-netmask.interfaces -p address v4 } default_netmask_v6_body() { atf_check -s exit:0 \ -o match:"2001:470:1f10::1/64" \ ifquery -i $FIXTURES/without-netmask.interfaces -p address v6 } stanza_merging_with_cidr_body() { atf_check -s exit:0 \ -o match:"203.0.113.1/32" \ -o match:"203.0.113.2/24" \ ifquery -i $FIXTURES/stanza-merging.interfaces -p address cidr } stanza_merging_without_cidr_body() { atf_check -s exit:0 \ -o match:"203.0.113.1/32" \ -o match:"203.0.113.2/24" \ ifquery -i $FIXTURES/stanza-merging.interfaces -p address without-cidr } dhcp_hostname_rewrite_body() { atf_check -s exit:0 \ -o match:"dhcp-hostname foo" \ ifquery -i $FIXTURES/dhcp-hostname-rewrite.interfaces -P eth0 } dhcp_hostname_inference_body() { hostname=$(uname -n) atf_check -s exit:0 \ -o match:"dhcp-hostname $hostname" \ ifquery -i $FIXTURES/dhcp-hostname-rewrite.interfaces -P eth1 } dhcp_hostname_replacement_body() { atf_check -s exit:0 \ -o match:"dhcp-hostname bar" \ ifquery -i $FIXTURES/dhcp-hostname-rewrite.interfaces -P eth2 }ifupdown-ng-ifupdown-ng-0.12.1/tests/ifup_test000077500000000000000000000077201422731055100213630ustar00rootroot00000000000000#!/usr/bin/env atf-sh . $(atf_get_srcdir)/test_env.sh tests_init \ noargs \ lo_always_auto \ dual_stack \ static_ipv4 \ static_ipv4_netmask \ static_ipv6 \ static_ipv6_netmask \ inet_dhcp \ use_dhcp \ alias_eth0_home \ alias_eth0_work \ bonded_bridge \ learned_dependency \ learned_dependency_2 \ learned_executor \ implicit_vlan \ teardown_dep_ordering \ dependency_loop_breaking noargs_body() { atf_check -s exit:1 -e ignore ifup -S/dev/null } lo_always_auto_body() { atf_check -s exit:0 -e ignore -o match:'executors/link' \ ifup -S/dev/null -E $EXECUTORS -i/dev/null -n -a } dual_stack_body() { atf_check -s exit:0 -e ignore \ -o match:'executors/link' \ -o match:'executors/static' \ ifup -S/dev/null -E $EXECUTORS -i $FIXTURES/static-eth0.interfaces -n -a } static_ipv4_body() { atf_check -s exit:0 -e ignore \ -o match:'executors/link' \ -o match:'executors/static' \ ifup -S/dev/null -E $EXECUTORS -i $FIXTURES/static-eth0-v4.interfaces -n -a } static_ipv4_netmask_body() { atf_check -s exit:0 -e ignore \ -o match:'executors/link' \ -o match:'executors/static' \ ifup -S/dev/null -E $EXECUTORS -i $FIXTURES/static-eth0-v4-netmask.interfaces -n -a } static_ipv6_body() { atf_check -s exit:0 -e ignore \ -o match:'executors/link' \ -o match:'executors/static' \ ifup -S/dev/null -E $EXECUTORS -i $FIXTURES/static-eth0-v6.interfaces -n -a } static_ipv6_netmask_body() { atf_check -s exit:0 -e ignore \ -o match:'executors/link' \ -o match:'executors/static' \ ifup -S/dev/null -E $EXECUTORS -i $FIXTURES/static-eth0-v6-netmask.interfaces -n -a } inet_dhcp_body() { atf_check -s exit:0 -e ignore \ -o match:'executors/link' \ -o match:'executors/dhcp' \ ifup -S/dev/null -E $EXECUTORS -i $FIXTURES/dhcp-eth0.interfaces -n -a } use_dhcp_body() { atf_check -s exit:0 -e ignore \ -o match:'executors/link' \ -o match:'executors/dhcp' \ ifup -S/dev/null -E $EXECUTORS -i $FIXTURES/use-dhcp-eth0.interfaces -n -a } alias_eth0_home_body() { atf_check -s exit:0 -e ignore \ -o match:'executors/link' \ -o match:'executors/dhcp' \ ifup -S/dev/null -E $EXECUTORS -i $FIXTURES/alias-home-work.interfaces -n wlan0=home } alias_eth0_work_body() { atf_check -s exit:0 -e ignore \ -o match:'executors/link' \ -o match:'executors/static' \ ifup -S/dev/null -E $EXECUTORS -i $FIXTURES/alias-home-work.interfaces -n wlan0=work } bonded_bridge_body() { atf_check -s exit:0 -e ignore \ -o match:'executors/link' \ -o match:'executors/bond' \ -o match:'executors/bridge' \ -o match:'executors/static' \ ifup -S/dev/null -E $EXECUTORS -i $FIXTURES/bonded-bridge.interfaces -n br0 } learned_dependency_body() { atf_check -s exit:0 -o ignore \ -e match:"eth0" \ -e match:"eth1" \ -e match:"eth2" \ -e match:"eth3" \ -e match:"eth4" \ ifup -n -S/dev/null -E $EXECUTORS -i $FIXTURES/mock-dependency-generator.interfaces br0 } learned_dependency_2_body() { atf_check -s exit:0 -o ignore \ -e match:"bond0" \ -e match:"eth0" \ -e match:"eth1" \ ifup -n -S/dev/null -E $EXECUTORS -i $FIXTURES/mock-dependency-generator-2.interfaces br0 } learned_executor_body() { atf_check -s exit:0 -o ignore \ -e match:"attempting to run mock executor" \ ifup -n -S/dev/null -E $EXECUTORS -i $FIXTURES/mock-dependency-generator-2.interfaces br0 } implicit_vlan_body() { atf_check -s exit:0 -o ignore \ -e match:"attempting to run vlan executor" \ -e match:"attempting to run link executor" \ ifup -n -S/dev/null -E $EXECUTORS -i $FIXTURES/vlan.interfaces eth0.8 } teardown_dep_ordering_body() { atf_check -s exit:0 -o ignore \ -e match:"skipping auto interface bat" \ -e match:"skipping auto interface dummy" \ ifup -n -i $FIXTURES/teardown-dep-ordering.interfaces -E $EXECUTORS -a } dependency_loop_breaking_body() { atf_check -s exit:0 -o ignore \ -e match:"ifup: skipping auto interface a \\(already configured\\), use --force to force configuration" \ ifup -n -i $FIXTURES/dependency-loop.interfaces -E $EXECUTORS -a } ifupdown-ng-ifupdown-ng-0.12.1/tests/linux/000077500000000000000000000000001422731055100205645ustar00rootroot00000000000000ifupdown-ng-ifupdown-ng-0.12.1/tests/linux/Kyuafile000066400000000000000000000010401422731055100222530ustar00rootroot00000000000000syntax(2) test_suite('ifupdown-ng') atf_test_program{name='bond_test'} atf_test_program{name='dhcp_test'} atf_test_program{name='ethtool_test'} atf_test_program{name='forward_test'} atf_test_program{name='gre_test'} atf_test_program{name='ipv6-ra_test'} atf_test_program{name='link_test'} atf_test_program{name='mpls_test'} atf_test_program{name='ppp_test'} atf_test_program{name='static_test'} atf_test_program{name='tunnel_test'} atf_test_program{name='vrf_test'} atf_test_program{name='vxlan_test'} atf_test_program{name='wireguard_test'} ifupdown-ng-ifupdown-ng-0.12.1/tests/linux/bond_test000077500000000000000000000016171422731055100225000ustar00rootroot00000000000000#!/usr/bin/env atf-sh . $(atf_get_srcdir)/../test_env.sh EXECUTOR="$(atf_get_srcdir)/../../executor-scripts/linux/bond" tests_init \ create_lacp_basic \ create_lacp_real create_lacp_basic_body() { export IFACE=bond0 PHASE=create MOCK=echo IF_BOND_MODE=802.3ad IF_BOND_MEMBERS="eth0 eth1" atf_check -s exit:0 \ -o match:'ip link add bond0 type bond mode 802.3ad' \ -o match:'ip link set eth0 down' \ -o match:'ip link set master bond0 eth0' \ -o match:'ip link set eth0 up' \ -o match:'ip link set master bond0 eth1' \ ${EXECUTOR} } create_lacp_real_body() { export IFACE=bond0 PHASE=create MOCK=echo IF_BOND_MODE=802.3ad IF_BOND_MEMBERS="eth0 eth1" \ IF_BOND_MIN_LINKS="1" IF_BOND_XMIT_HASH_POLICY="layer3+4" atf_check -s exit:0 \ -o match:'ip link add bond0 type bond' \ -o match:'mode 802.3ad' \ -o match:'min_links 1' \ -o match:'xmit_hash_policy layer3\+4' \ ${EXECUTOR} } ifupdown-ng-ifupdown-ng-0.12.1/tests/linux/dhcp_test000077500000000000000000000032251422731055100224710ustar00rootroot00000000000000#!/usr/bin/env atf-sh . $(atf_get_srcdir)/../test_env.sh EXECUTOR="$(atf_get_srcdir)/../../executor-scripts/linux/dhcp" tests_init udhcpc_up \ dhcpcd_up \ dhcpcd_down \ dhclient_up \ udhcpc_opts_up \ udhcpc_opts_up_subshell \ hostname_subshell udhcpc_up_body() { export IFACE=eth0 PHASE=up MOCK=echo IF_DHCP_PROGRAM=udhcpc atf_check -s exit:0 -o match:'/sbin/udhcpc -b -R -p /var/run/udhcpc.eth0.pid -i eth0' \ ${EXECUTOR} } dhcpcd_up_body() { export IFACE=eth0 PHASE=up MOCK=echo IF_DHCP_PROGRAM=dhcpcd atf_check -s exit:0 -o match:'/sbin/dhcpcd eth0' \ ${EXECUTOR} } dhcpcd_down_body() { export IFACE=eth0 PHASE=down MOCK=echo IF_DHCP_PROGRAM=dhcpcd atf_check -s exit:0 -o match:'/sbin/dhcpcd -k eth0' \ ${EXECUTOR} } dhclient_up_body() { export IFACE=eth0 PHASE=up MOCK=echo IF_DHCP_PROGRAM=dhclient atf_check -s exit:0 -o match:'/usr/sbin/dhclient -pf /var/run/dhclient.eth0.pid eth0' \ ${EXECUTOR} } udhcpc_opts_up_body() { export IFACE=eth0 PHASE=up MOCK=echo IF_DHCP_PROGRAM=udhcpc IF_UDHCPC_OPTS="-O search" atf_check -s exit:0 -o match:'/sbin/udhcpc -b -R -p /var/run/udhcpc.eth0.pid -i eth0 -O search' \ ${EXECUTOR} } udhcpc_opts_up_subshell_body() { export IFACE=eth0 PHASE=up MOCK=echo IF_DHCP_PROGRAM=udhcpc IF_UDHCPC_OPTS="-O search -x hostname:\$(echo test)" atf_check -s exit:0 -o match:'/sbin/udhcpc -b -R -p /var/run/udhcpc.eth0.pid -i eth0 -O search -x hostname:test' \ ${EXECUTOR} } hostname_subshell_body() { export IFACE=eth0 PHASE=up MOCK=echo IF_DHCP_PROGRAM=udhcpc IF_DHCP_HOSTNAME="\$(echo test)" atf_check -s exit:0 -o match:'/sbin/udhcpc -b -R -p /var/run/udhcpc.eth0.pid -i eth0 -x hostname:test' \ ${EXECUTOR} } ifupdown-ng-ifupdown-ng-0.12.1/tests/linux/ethtool_test000077500000000000000000000311351422731055100232320ustar00rootroot00000000000000#!/usr/bin/env atf-sh . $(atf_get_srcdir)/../test_env.sh EXECUTOR="$(atf_get_srcdir)/../../executor-scripts/linux/ethtool" tests_init \ pre_up_msglvl \ pre_up_ethernet_port \ up_speed \ up_duplex \ up_wol \ up_wol_sopass \ up_autoneg_simple \ up_autoneg_mask \ up_pause_autoneg \ up_pause_tx \ up_pause_rx \ up_offload_gro \ up_offload_gso \ up_offload_lro \ up_offload_rx \ up_offload_sg \ up_offload_tso \ up_offload_tx \ up_offload_ufo \ up_dma_ring_rx \ up_dma_ring_rx_jumbo \ up_dma_ring_rx_mini \ up_dma_ring_tx \ up_coalesce_adaptive_rx \ up_coalesce_adaptive_tx \ up_coalesce_pkt_rate_low \ up_coalesce_pkt_rate_high \ up_coalesce_sample_interval \ up_coalesce_stats_block_usecs \ up_coalesce_rx_frames \ up_coalesce_rx_frames_low \ up_coalesce_rx_frames_irq \ up_coalesce_rx_frames_high \ up_coalesce_rx_usecs \ up_coalesce_rx_usecs_low \ up_coalesce_rx_usecs_irq \ up_coalesce_rx_usecs_high \ up_coalesce_tx_frames \ up_coalesce_tx_frames_low \ up_coalesce_tx_frames_irq \ up_coalesce_tx_frames_high \ up_coalesce_tx_usecs \ up_coalesce_tx_usecs_low \ up_coalesce_tx_usecs_irq \ up_coalesce_tx_usecs_high pre_up_msglvl_body() { export IFACE="eth0" PHASE="pre-up" IF_ETHTOOL_MSGLVL="debug on" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --change eth0' \ -o match:'msglvl debug on' \ ${EXECUTOR} } pre_up_ethernet_port_body() { export IFACE="eth0" PHASE="pre-up" IF_ETHTOOL_ETHERNET_PORT="4" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --change eth0' \ -o match:'port 4' \ ${EXECUTOR} } up_speed_body() { export IFACE="eth0" PHASE="up" IF_ETHTOOL_LINK_SPEED="1000" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --change eth0' \ -o match:'speed 1000' \ ${EXECUTOR} } up_duplex_body() { export IFACE="eth0" PHASE="up" IF_ETHTOOL_LINK_DUPLEX="full" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --change eth0' \ -o match:'duplex full' \ ${EXECUTOR} } up_wol_body() { export IFACE="eth0" PHASE="up" IF_ETHTOOL_ETHERNET_WOL="g" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --change eth0' \ -o match:'wol g' \ ${EXECUTOR} } up_wol_sopass_body() { export IFACE="eth0" PHASE="up" IF_ETHTOOL_ETHERNET_WOL="s abc123" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --change eth0' \ -o match:'wol s sopass abc123' \ ${EXECUTOR} } up_autoneg_simple_body() { export IFACE="eth0" PHASE="up" IF_ETHTOOL_ETHERNET_AUTONEG="on" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --change eth0' \ -o match:'autoneg on' \ ${EXECUTOR} export IFACE="eth0" PHASE="up" IF_ETHTOOL_ETHERNET_AUTONEG="off" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --change eth0' \ -o match:'autoneg off' \ ${EXECUTOR} } up_autoneg_mask_body() { export IFACE="eth0" PHASE="up" IF_ETHTOOL_ETHERNET_AUTONEG="1000/full" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --change eth0' \ -o match:'autoneg on advertise 1000/full' \ ${EXECUTOR} } up_pause_autoneg_body() { export IFACE="eth0" PHASE="up" IF_ETHTOOL_PAUSE_AUTONEG="on" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --pause eth0' \ -o match:"autoneg on" \ ${EXECUTOR} export IFACE="eth0" PHASE="up" IF_ETHTOOL_PAUSE_AUTONEG="off" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --pause eth0' \ -o match:"autoneg off" \ ${EXECUTOR} } up_pause_tx_body() { export IFACE="eth0" PHASE="up" IF_ETHTOOL_PAUSE_TX="on" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --pause eth0' \ -o match:"tx on" \ ${EXECUTOR} export IFACE="eth0" PHASE="up" IF_ETHTOOL_PAUSE_TX="off" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --pause eth0' \ -o match:"tx off" \ ${EXECUTOR} } up_pause_rx_body() { export IFACE="eth0" PHASE="up" IF_ETHTOOL_PAUSE_RX="on" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --pause eth0' \ -o match:"rx on" \ ${EXECUTOR} export IFACE="eth0" PHASE="up" IF_ETHTOOL_PAUSE_RX="off" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --pause eth0' \ -o match:"rx off" \ ${EXECUTOR} } up_offload_gro_body() { export IFACE="eth0" PHASE="up" IF_ETHTOOL_OFFLOAD_GRO="on" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --offload eth0' \ -o match:"gro on" \ ${EXECUTOR} export IFACE="eth0" PHASE="up" IF_ETHTOOL_OFFLOAD_GRO="off" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --offload eth0' \ -o match:"gro off" \ ${EXECUTOR} } up_offload_gso_body() { export IFACE="eth0" PHASE="up" IF_ETHTOOL_OFFLOAD_GSO="on" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --offload eth0' \ -o match:"gso on" \ ${EXECUTOR} export IFACE="eth0" PHASE="up" IF_ETHTOOL_OFFLOAD_GSO="off" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --offload eth0' \ -o match:"gso off" \ ${EXECUTOR} } up_offload_lro_body() { export IFACE="eth0" PHASE="up" IF_ETHTOOL_OFFLOAD_LRO="on" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --offload eth0' \ -o match:"lro on" \ ${EXECUTOR} export IFACE="eth0" PHASE="up" IF_ETHTOOL_OFFLOAD_LRO="off" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --offload eth0' \ -o match:"lro off" \ ${EXECUTOR} } up_offload_rx_body() { export IFACE="eth0" PHASE="up" IF_ETHTOOL_OFFLOAD_RX="on" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --offload eth0' \ -o match:"rx on" \ ${EXECUTOR} export IFACE="eth0" PHASE="up" IF_ETHTOOL_OFFLOAD_RX="off" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --offload eth0' \ -o match:"rx off" \ ${EXECUTOR} } up_offload_sg_body() { export IFACE="eth0" PHASE="up" IF_ETHTOOL_OFFLOAD_SG="on" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --offload eth0' \ -o match:"sg on" \ ${EXECUTOR} export IFACE="eth0" PHASE="up" IF_ETHTOOL_OFFLOAD_SG="off" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --offload eth0' \ -o match:"sg off" \ ${EXECUTOR} } up_offload_tso_body() { export IFACE="eth0" PHASE="up" IF_ETHTOOL_OFFLOAD_TSO="on" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --offload eth0' \ -o match:"tso on" \ ${EXECUTOR} export IFACE="eth0" PHASE="up" IF_ETHTOOL_OFFLOAD_TSO="off" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --offload eth0' \ -o match:"tso off" \ ${EXECUTOR} } up_offload_tx_body() { export IFACE="eth0" PHASE="up" IF_ETHTOOL_OFFLOAD_TX="on" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --offload eth0' \ -o match:"tx on" \ ${EXECUTOR} export IFACE="eth0" PHASE="up" IF_ETHTOOL_OFFLOAD_TX="off" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --offload eth0' \ -o match:"tx off" \ ${EXECUTOR} } up_offload_ufo_body() { export IFACE="eth0" PHASE="up" IF_ETHTOOL_OFFLOAD_UFO="on" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --offload eth0' \ -o match:"ufo on" \ ${EXECUTOR} export IFACE="eth0" PHASE="up" IF_ETHTOOL_OFFLOAD_UFO="off" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --offload eth0' \ -o match:"ufo off" \ ${EXECUTOR} } up_dma_ring_rx_body() { export IFACE="eth0" PHASE="up" IF_ETHTOOL_DMA_RING_RX="1024" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --set-ring eth0' \ -o match:"rx 1024" \ ${EXECUTOR} } up_dma_ring_rx_jumbo_body() { export IFACE="eth0" PHASE="up" IF_ETHTOOL_DMA_RING_RX_JUMBO="1024" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --set-ring eth0' \ -o match:"rx-jumbo 1024" \ ${EXECUTOR} } up_dma_ring_rx_mini_body() { export IFACE="eth0" PHASE="up" IF_ETHTOOL_DMA_RING_RX_MINI="1024" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --set-ring eth0' \ -o match:"rx-mini 1024" \ ${EXECUTOR} } up_dma_ring_tx_body() { export IFACE="eth0" PHASE="up" IF_ETHTOOL_DMA_RING_TX="1024" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --set-ring eth0' \ -o match:"tx 1024" \ ${EXECUTOR} } up_coalesce_adaptive_rx_body() { export IFACE="eth0" PHASE="up" IF_ETHTOOL_COALESCE_ADAPTIVE_RX="on" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --coalesce eth0' \ -o match:"adaptive-rx on" \ ${EXECUTOR} } up_coalesce_adaptive_tx_body() { export IFACE="eth0" PHASE="up" IF_ETHTOOL_COALESCE_ADAPTIVE_TX="on" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --coalesce eth0' \ -o match:"adaptive-tx on" \ ${EXECUTOR} } up_coalesce_pkt_rate_low_body() { export IFACE="eth0" PHASE="up" IF_ETHTOOL_COALESCE_PKT_RATE_LOW="1024" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --coalesce eth0' \ -o match:"pkt-rate-low 1024" \ ${EXECUTOR} } up_coalesce_pkt_rate_high_body() { export IFACE="eth0" PHASE="up" IF_ETHTOOL_COALESCE_PKT_RATE_HIGH="1024" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --coalesce eth0' \ -o match:"pkt-rate-high 1024" \ ${EXECUTOR} } up_coalesce_sample_interval_body() { export IFACE="eth0" PHASE="up" IF_ETHTOOL_COALESCE_SAMPLE_INTERVAL="1024" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --coalesce eth0' \ -o match:"sample-interval 1024" \ ${EXECUTOR} } up_coalesce_stats_block_usecs_body() { export IFACE="eth0" PHASE="up" IF_ETHTOOL_COALESCE_STATS_BLOCK_USECS="1024" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --coalesce eth0' \ -o match:"stats-block-usecs 1024" \ ${EXECUTOR} } up_coalesce_rx_frames_body() { export IFACE="eth0" PHASE="up" IF_ETHTOOL_COALESCE_RX_FRAMES="1024" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --coalesce eth0' \ -o match:"rx-frames 1024" \ ${EXECUTOR} } up_coalesce_rx_frames_low_body() { export IFACE="eth0" PHASE="up" IF_ETHTOOL_COALESCE_RX_FRAMES_LOW="1024" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --coalesce eth0' \ -o match:"rx-frames-low 1024" \ ${EXECUTOR} } up_coalesce_rx_frames_irq_body() { export IFACE="eth0" PHASE="up" IF_ETHTOOL_COALESCE_RX_FRAMES_IRQ="1024" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --coalesce eth0' \ -o match:"rx-frames-irq 1024" \ ${EXECUTOR} } up_coalesce_rx_frames_high_body() { export IFACE="eth0" PHASE="up" IF_ETHTOOL_COALESCE_RX_FRAMES_HIGH="1024" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --coalesce eth0' \ -o match:"rx-frames-high 1024" \ ${EXECUTOR} } up_coalesce_rx_usecs_body() { export IFACE="eth0" PHASE="up" IF_ETHTOOL_COALESCE_RX_USECS="1024" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --coalesce eth0' \ -o match:"rx-usecs 1024" \ ${EXECUTOR} } up_coalesce_rx_usecs_low_body() { export IFACE="eth0" PHASE="up" IF_ETHTOOL_COALESCE_RX_USECS_LOW="1024" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --coalesce eth0' \ -o match:"rx-usecs-low 1024" \ ${EXECUTOR} } up_coalesce_rx_usecs_irq_body() { export IFACE="eth0" PHASE="up" IF_ETHTOOL_COALESCE_RX_USECS_IRQ="1024" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --coalesce eth0' \ -o match:"rx-usecs-irq 1024" \ ${EXECUTOR} } up_coalesce_rx_usecs_high_body() { export IFACE="eth0" PHASE="up" IF_ETHTOOL_COALESCE_RX_USECS_HIGH="1024" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --coalesce eth0' \ -o match:"rx-usecs-high 1024" \ ${EXECUTOR} } up_coalesce_tx_frames_body() { export IFACE="eth0" PHASE="up" IF_ETHTOOL_COALESCE_TX_FRAMES="1024" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --coalesce eth0' \ -o match:"tx-frames 1024" \ ${EXECUTOR} } up_coalesce_tx_frames_low_body() { export IFACE="eth0" PHASE="up" IF_ETHTOOL_COALESCE_TX_FRAMES_LOW="1024" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --coalesce eth0' \ -o match:"tx-frames-low 1024" \ ${EXECUTOR} } up_coalesce_tx_frames_irq_body() { export IFACE="eth0" PHASE="up" IF_ETHTOOL_COALESCE_TX_FRAMES_IRQ="1024" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --coalesce eth0' \ -o match:"tx-frames-irq 1024" \ ${EXECUTOR} } up_coalesce_tx_frames_high_body() { export IFACE="eth0" PHASE="up" IF_ETHTOOL_COALESCE_TX_FRAMES_HIGH="1024" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --coalesce eth0' \ -o match:"tx-frames-high 1024" \ ${EXECUTOR} } up_coalesce_tx_usecs_body() { export IFACE="eth0" PHASE="up" IF_ETHTOOL_COALESCE_TX_USECS="1024" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --coalesce eth0' \ -o match:"tx-usecs 1024" \ ${EXECUTOR} } up_coalesce_tx_usecs_low_body() { export IFACE="eth0" PHASE="up" IF_ETHTOOL_COALESCE_TX_USECS_LOW="1024" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --coalesce eth0' \ -o match:"tx-usecs-low 1024" \ ${EXECUTOR} } up_coalesce_tx_usecs_irq_body() { export IFACE="eth0" PHASE="up" IF_ETHTOOL_COALESCE_TX_USECS_IRQ="1024" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --coalesce eth0' \ -o match:"tx-usecs-irq 1024" \ ${EXECUTOR} } up_coalesce_tx_usecs_high_body() { export IFACE="eth0" PHASE="up" IF_ETHTOOL_COALESCE_TX_USECS_HIGH="1024" MOCK="echo" atf_check -s exit:0 \ -o match:'ethtool --coalesce eth0' \ -o match:"tx-usecs-high 1024" \ ${EXECUTOR} } ifupdown-ng-ifupdown-ng-0.12.1/tests/linux/forward_test000077500000000000000000000061441422731055100232220ustar00rootroot00000000000000#!/usr/bin/env atf-sh . $(atf_get_srcdir)/../test_env.sh EXECUTOR="$(atf_get_srcdir)/../../executor-scripts/linux/forward" tests_init \ up_forward_v4 \ up_forward_v6 \ up_forward_v4_mc \ up_forward_v6_mc up_forward_v4_body() { export IF_FORWARD_IPV4= IF_FORWARD_IPV6= IF_FORWARD_IPV4_MC= IF_FORWARD_IPV6_MC= export IFACE=eth0 PHASE=up MOCK=echo IF_FORWARD_IPV4=1 atf_check -s exit:0 -o match:'echo 1 > /proc/sys/net/ipv4/conf/eth0/forwarding' \ ${EXECUTOR} export IFACE=eth0 PHASE=up MOCK=echo IF_FORWARD_IPV4=yes atf_check -s exit:0 -o match:'echo 1 > /proc/sys/net/ipv4/conf/eth0/forwarding' \ ${EXECUTOR} export IFACE=eth0 PHASE=up MOCK=echo IF_FORWARD_IPV4=0 atf_check -s exit:0 -o match:'echo 0 > /proc/sys/net/ipv4/conf/eth0/forwarding' \ ${EXECUTOR} export IFACE=eth0 PHASE=up MOCK=echo IF_FORWARD_IPV4=no atf_check -s exit:0 -o match:'echo 0 > /proc/sys/net/ipv4/conf/eth0/forwarding' \ ${EXECUTOR} } up_forward_v6_body() { export IF_FORWARD_IPV4= IF_FORWARD_IPV6= IF_FORWARD_IPV4_MC= IF_FORWARD_IPV6_MC= export IFACE=eth0 PHASE=up MOCK=echo IF_FORWARD_IPV6=1 atf_check -s exit:0 -o match:'echo 1 > /proc/sys/net/ipv6/conf/eth0/forwarding' \ ${EXECUTOR} export IFACE=eth0 PHASE=up MOCK=echo IF_FORWARD_IPV6=yes atf_check -s exit:0 -o match:'echo 1 > /proc/sys/net/ipv6/conf/eth0/forwarding' \ ${EXECUTOR} export IFACE=eth0 PHASE=up MOCK=echo IF_FORWARD_IPV6=0 atf_check -s exit:0 -o match:'echo 0 > /proc/sys/net/ipv6/conf/eth0/forwarding' \ ${EXECUTOR} export IFACE=eth0 PHASE=up MOCK=echo IF_FORWARD_IPV6=no atf_check -s exit:0 -o match:'echo 0 > /proc/sys/net/ipv6/conf/eth0/forwarding' \ ${EXECUTOR} } up_forward_v4_mc_body() { export IF_FORWARD_IPV4= IF_FORWARD_IPV6= IF_FORWARD_IPV4_MC= IF_FORWARD_IPV6_MC= export IFACE=eth0 PHASE=up MOCK=echo IF_FORWARD_IPV4_MC=1 atf_check -s exit:0 -o match:'echo 1 > /proc/sys/net/ipv4/conf/eth0/mc_forwarding' \ ${EXECUTOR} export IFACE=eth0 PHASE=up MOCK=echo IF_FORWARD_IPV4_MC=yes atf_check -s exit:0 -o match:'echo 1 > /proc/sys/net/ipv4/conf/eth0/mc_forwarding' \ ${EXECUTOR} export IFACE=eth0 PHASE=up MOCK=echo IF_FORWARD_IPV4_MC=0 atf_check -s exit:0 -o match:'echo 0 > /proc/sys/net/ipv4/conf/eth0/mc_forwarding' \ ${EXECUTOR} export IFACE=eth0 PHASE=up MOCK=echo IF_FORWARD_IPV4_MC=no atf_check -s exit:0 -o match:'echo 0 > /proc/sys/net/ipv4/conf/eth0/mc_forwarding' \ ${EXECUTOR} } up_forward_v6_mc_body() { export IF_FORWARD_IPV4= IF_FORWARD_IPV6= IF_FORWARD_IPV4_MC= IF_FORWARD_IPV6_MC= export IFACE=eth0 PHASE=up MOCK=echo IF_FORWARD_IPV6_MC=1 atf_check -s exit:0 -o match:'echo 1 > /proc/sys/net/ipv6/conf/eth0/mc_forwarding' \ ${EXECUTOR} export IFACE=eth0 PHASE=up MOCK=echo IF_FORWARD_IPV6_MC=yes atf_check -s exit:0 -o match:'echo 1 > /proc/sys/net/ipv6/conf/eth0/mc_forwarding' \ ${EXECUTOR} export IFACE=eth0 PHASE=up MOCK=echo IF_FORWARD_IPV6_MC=0 atf_check -s exit:0 -o match:'echo 0 > /proc/sys/net/ipv6/conf/eth0/mc_forwarding' \ ${EXECUTOR} export IFACE=eth0 PHASE=up MOCK=echo IF_FORWARD_IPV6_MC=no atf_check -s exit:0 -o match:'echo 0 > /proc/sys/net/ipv6/conf/eth0/mc_forwarding' \ ${EXECUTOR} } ifupdown-ng-ifupdown-ng-0.12.1/tests/linux/gre_test000077500000000000000000000021141422731055100223240ustar00rootroot00000000000000#!/usr/bin/env atf-sh . $(atf_get_srcdir)/../test_env.sh EXECUTOR="$(atf_get_srcdir)/../../executor-scripts/linux/gre" tests_init \ basic_bringup \ basic_teardown \ flags_bringup basic_bringup_body() { export MOCK=echo IFACE=tun0 PHASE=create \ IF_GRE_LOCAL=1.2.3.4 IF_GRE_REMOTE=5.6.7.8 \ IF_GRE_TTL=255 atf_check -s exit:0 \ -o match:"ip -4 link add tun0" \ -o match:"mode gre" \ -o match:"ttl '255'" \ -o match:"local '1.2.3.4'" \ -o match:"remote '5.6.7.8'" \ ${EXECUTOR} } basic_teardown_body() { export MOCK=echo IFACE=tun0 PHASE=destroy \ IF_GRE_LOCAL=1.2.3.4 IF_GRE_REMOTE=5.6.7.8 \ IF_GRE_TTL=255 atf_check -s exit:0 \ -o match:"ip -4 link del tun0" \ ${EXECUTOR} } flags_bringup_body() { export MOCK=echo IFACE=tun0 PHASE=create \ IF_GRE_LOCAL=1.2.3.4 IF_GRE_REMOTE=5.6.7.8 \ IF_GRE_TTL=255 IF_GRE_FLAGS="nopmtudisc ignore-df" atf_check -s exit:0 \ -o match:"ip -4 link add tun0" \ -o match:"mode gre" \ -o match:"ttl '255'" \ -o match:"local '1.2.3.4'" \ -o match:"remote '5.6.7.8'" \ -o match:"nopmtudisc ignore-df" \ ${EXECUTOR} } ifupdown-ng-ifupdown-ng-0.12.1/tests/linux/ipv6-ra_test000077500000000000000000000007161422731055100230410ustar00rootroot00000000000000#!/usr/bin/env atf-sh . $(atf_get_srcdir)/../test_env.sh EXECUTOR="$(atf_get_srcdir)/../../executor-scripts/linux/ipv6-ra" tests_init up down up_body() { export IFACE=lo PHASE=up MOCK=echo MOCK_ESC=\\ atf_check -s exit:0 -o match:'echo 1 > /proc/sys/net/ipv6/conf/lo/accept_ra' \ ${EXECUTOR} } down_body() { export IFACE=lo PHASE=down MOCK=echo MOCK_ESC=\\ atf_check -s exit:0 -o match:'echo 0 > /proc/sys/net/ipv6/conf/lo/accept_ra' \ ${EXECUTOR} } ifupdown-ng-ifupdown-ng-0.12.1/tests/linux/link_test000077500000000000000000000040611422731055100225070ustar00rootroot00000000000000#!/usr/bin/env atf-sh . $(atf_get_srcdir)/../test_env.sh EXECUTOR="$(atf_get_srcdir)/../../executor-scripts/linux/link" tests_init \ up \ down \ mtu \ hwaddress \ vlan_explicit_create \ vlan_explicit_destroy \ vlan_guessed_create \ vlan_guessed_destroy \ vlan_explicit_depend \ vlan_guessed_depend \ dummy_create up_body() { export IFACE=lo PHASE=up MOCK=echo atf_check -s exit:0 -o match:'ip link set up dev lo' \ ${EXECUTOR} } down_body() { export IFACE=lo PHASE=down MOCK=echo atf_check -s exit:0 -o match:'ip link set down dev lo' \ ${EXECUTOR} } mtu_body() { export IFACE=eth0 PHASE=up MOCK=echo IF_MTU=1492 atf_check -s exit:0 -o match:'ip link set up dev eth0 mtu 1492' \ ${EXECUTOR} } hwaddress_body() { export IFACE=eth0 PHASE=up MOCK=echo IF_HWADDRESS=12:34:56:78:90:ab atf_check -s exit:0 -o match:'ip link set up dev eth0 address 12:34:56:78:90:ab' \ ${EXECUTOR} } vlan_explicit_create_body() { export IFACE=servers PHASE=create MOCK=echo \ IF_VLAN_RAW_DEVICE="eth0" IF_VLAN_ID="123" atf_check -s exit:0 -o match:'ip link add link eth0 name servers type vlan id 123' \ ${EXECUTOR} } vlan_explicit_destroy_body() { export IFACE=servers PHASE=destroy MOCK=echo \ IF_VLAN_RAW_DEVICE="eth0" IF_VLAN_ID="123" atf_check -s exit:0 -o match:'ip link del servers' \ ${EXECUTOR} } vlan_guessed_create_body() { export IFACE=eth0.8 PHASE=create MOCK=echo atf_check -s exit:0 -o match:'ip link add link eth0 name eth0.8 type vlan id 8' \ ${EXECUTOR} } vlan_guessed_destroy_body() { export IFACE=eth0.8 PHASE=destroy MOCK=echo atf_check -s exit:0 -o match:'ip link del eth0.8' \ ${EXECUTOR} } vlan_explicit_depend_body() { export IFACE=servers PHASE=depend \ IF_VLAN_RAW_DEVICE="eth0" IF_VLAN_ID="123" atf_check -s exit:0 -o match:'eth0' \ ${EXECUTOR} } vlan_guessed_depend_body() { export IFACE=eth0.8 PHASE=depend atf_check -s exit:0 -o match:'eth0' \ ${EXECUTOR} } dummy_create_body() { export IFACE=yolo IF_LINK_TYPE=dummy PHASE=create MOCK=echo atf_check -s exit:0 -o match:'ip link add yolo type dummy' \ ${EXECUTOR} } ifupdown-ng-ifupdown-ng-0.12.1/tests/linux/mpls_test000077500000000000000000000011041422731055100225200ustar00rootroot00000000000000#!/usr/bin/env atf-sh . $(atf_get_srcdir)/../test_env.sh EXECUTOR="$(atf_get_srcdir)/../../executor-scripts/linux/mpls" tests_init \ mpls_enable \ mpls_disable mpls_enable_body() { export MOCK=echo IFACE=vlan2342 PHASE=pre-up IF_MPLS_ENABLE=yes atf_check -s exit:0 \ -o match:"modprobe mpls_iptunnel" \ -o match:"echo 1 > /proc/sys/net/mpls/conf/vlan2342/input" \ ${EXECUTOR} } mpls_disable_body() { export MOCK=echo IFACE=vlan2342 PHASE=pre-up IF_MPLS_ENABLE=no atf_check -s exit:0 \ -o match:"echo 0 > /proc/sys/net/mpls/conf/vlan2342/input" \ ${EXECUTOR} } ifupdown-ng-ifupdown-ng-0.12.1/tests/linux/ppp_test000077500000000000000000000007141422731055100223520ustar00rootroot00000000000000#!/usr/bin/env atf-sh . $(atf_get_srcdir)/../test_env.sh EXECUTOR="$(atf_get_srcdir)/../../executor-scripts/linux/ppp" tests_init \ bringup \ teardown \ bringup_body() { export MOCK=echo IFACE=ppp0 PHASE=create IF_PPP_PROVIDER=someisp atf_check -s exit:0 \ -o match:'pon someisp' \ ${EXECUTOR} } teardown_body() { export MOCK=echo IFACE=ppp0 PHASE=destroy IF_PPP_PROVIDER=someisp atf_check -s exit:0 \ -o match:'poff someisp' \ ${EXECUTOR} } ifupdown-ng-ifupdown-ng-0.12.1/tests/linux/static_test000077500000000000000000000033131422731055100230400ustar00rootroot00000000000000#!/usr/bin/env atf-sh . $(atf_get_srcdir)/../test_env.sh EXECUTOR="$(atf_get_srcdir)/../../executor-scripts/linux/static" tests_init \ up \ up_ptp \ down \ vrf_up \ metric_up up_body() { export IFACE=eth0 PHASE=up MOCK=echo IF_ADDRESSES="203.0.113.2/24 2001:db8:1000:2::2/64" \ IF_GATEWAYS="203.0.113.1 2001:db8:1000:2::1" atf_check -s exit:0 \ -o match:'addr add 203.0.113.2/24 dev eth0' \ -o match:'addr add 2001:db8:1000:2::2/64 dev eth0' \ -o match:'route add default via 203.0.113.1 metric 1 dev eth0' \ -o match:'route add default via 2001:db8:1000:2::1 metric 1 dev eth0' \ ${EXECUTOR} } up_ptp_body() { export IFACE=eth0 PHASE=up MOCK=echo IF_ADDRESSES="203.0.113.2/32 2001:db8:1000:2::2/64" \ IF_GATEWAYS="192.0.2.1 2001:db8:1000:2::1" IF_POINT_TO_POINT="192.0.2.1" atf_check -s exit:0 \ -o match:'addr add 203.0.113.2/32 peer 192.0.2.1 dev eth0' \ -o match:'route add default via 192.0.2.1 metric 1 dev eth0' \ -o match:'addr add 2001:db8:1000:2::2/64 dev eth0' \ -o match:'route add default via 2001:db8:1000:2::1 metric 1 dev eth0' \ ${EXECUTOR} } down_body() { export IFACE=eth0 PHASE=down MOCK=echo IF_ADDRESSES="203.0.113.2/24 2001:db8:1000:2::2/64" \ IF_GATEWAYS="203.0.113.1 2001:db8:1000:2::1" atf_check -s exit:0 \ -o match:'addr flush dev eth0' \ ${EXECUTOR} } vrf_up_body() { export IFACE=vrf-red PHASE=up MOCK=echo IF_GATEWAYS=203.0.113.2 IF_VRF_TABLE=1 atf_check -s exit:0 \ -o match:'route add default via 203.0.113.2 table 1' \ ${EXECUTOR} } metric_up_body() { export IFACE=vrf-red PHASE=up MOCK=echo IF_GATEWAYS=203.0.113.2 IF_VRF_TABLE=1 IF_METRIC=20 atf_check -s exit:0 \ -o match:'route add default via 203.0.113.2 table 1 metric 20' \ ${EXECUTOR} } ifupdown-ng-ifupdown-ng-0.12.1/tests/linux/tunnel_test000077500000000000000000000031621422731055100230600ustar00rootroot00000000000000#!/usr/bin/env atf-sh . $(atf_get_srcdir)/../test_env.sh EXECUTOR="$(atf_get_srcdir)/../../executor-scripts/linux/tunnel" tests_init \ tunnel_bringup \ tunnel_teardown \ gretap_up \ gretap_down \ ip6gretap_up tunnel_bringup_body() { export MOCK=echo IFACE=tun0 PHASE=create IF_TUNNEL_MODE=gre \ IF_TUNNEL_LOCAL=1.2.3.4 IF_TUNNEL_REMOTE=5.6.7.8 \ IF_TUNNEL_TTL=255 atf_check -s exit:0 \ -o match:"ip -4 tunnel add tun0" \ -o match:"mode gre" \ -o match:"ttl '255'" \ -o match:"local '1.2.3.4'" \ -o match:"remote '5.6.7.8'" \ ${EXECUTOR} } tunnel_teardown_body() { export MOCK=echo IFACE=tun0 PHASE=destroy IF_TUNNEL_MODE=gre \ IF_TUNNEL_LOCAL=1.2.3.4 IF_TUNNEL_REMOTE=5.6.7.8 \ IF_TUNNEL_TTL=255 atf_check -s exit:0 \ -o match:"ip -4 tunnel del tun0" \ ${EXECUTOR} } gretap_up_body() { export MOCK=echo IFACE=foo PHASE=create IF_TUNNEL_MODE=gretap \ IF_TUNNEL_LOCAL=1.2.3.4 IF_TUNNEL_REMOTE=5.6.7.8 atf_check -s exit:0 \ -o match:"ip -4 link add foo" \ -o match:"type gretap" \ -o match:"local '1.2.3.4'" \ -o match:"remote '5.6.7.8'" \ ${EXECUTOR} } gretap_down_body() { export MOCK=echo IFACE=foo PHASE=destroy IF_TUNNEL_MODE=gretap \ IF_TUNNEL_LOCAL=1.2.3.4 IF_TUNNEL_REMOTE=5.6.7.8 atf_check -s exit:0 \ -o match:"ip -4 link del foo" \ ${EXECUTOR} } ip6gretap_up_body() { export MOCK=echo IFACE=foo PHASE=create IF_TUNNEL_MODE=ip6gretap \ IF_TUNNEL_LOCAL=2001:db8::aaaa IF_TUNNEL_REMOTE=2001:db8::eeee atf_check -s exit:0 \ -o match:"ip -6 link add foo" \ -o match:"type gretap" \ -o match:"local '2001:db8::aaaa'" \ -o match:"remote '2001:db8::eeee'" \ ${EXECUTOR} } ifupdown-ng-ifupdown-ng-0.12.1/tests/linux/vrf_test000077500000000000000000000016641422731055100223550ustar00rootroot00000000000000#!/usr/bin/env atf-sh . $(atf_get_srcdir)/../test_env.sh EXECUTOR="$(atf_get_srcdir)/../../executor-scripts/linux/vrf" tests_init \ leader_bringup \ leader_teardown \ member_bringup leader_bringup_body() { export MOCK=echo IFACE=vrf-red PHASE=create IF_VRF_TABLE=1 IF_VRF_MEMBER= atf_check -s exit:0 \ -o match:'ip link add vrf-red type vrf table 1' \ -o match:'ip rule add iif vrf-red table 1' \ -o match:'ip rule add oif vrf-red table 1' \ ${EXECUTOR} } leader_teardown_body() { export MOCK=echo IFACE=vrf-red PHASE=destroy IF_VRF_TABLE=1 IF_VRF_MEMBER= atf_check -s exit:0 \ -o match:'ip link del vrf-red type vrf table 1' \ -o match:'ip rule del iif vrf-red table 1' \ -o match:'ip rule del oif vrf-red table 1' \ ${EXECUTOR} } member_bringup_body() { export MOCK=echo IFACE=eth0 PHASE=pre-up IF_VRF_MEMBER=vrf-red IF_VRF_TABLE= atf_check -s exit:0 \ -o match:'ip link set eth0 master vrf-red' \ ${EXECUTOR} } ifupdown-ng-ifupdown-ng-0.12.1/tests/linux/vxlan_test000077500000000000000000000042331422731055100227030ustar00rootroot00000000000000#!/usr/bin/env atf-sh . $(atf_get_srcdir)/../test_env.sh EXECUTOR="$(atf_get_srcdir)/../../executor-scripts/linux/vxlan" tests_init \ create_simple \ create_ucast_ptp \ create_ucast_ptmp \ create_mcast \ create_physdev \ create_dstport \ create_nolearning \ destroy \ create_simple_body() { export IFACE=vx_foo PHASE=create MOCK=echo IF_VXLAN_ID=2342 atf_check -s exit:0 -o match:'ip link add vx_foo type vxlan id 2342 dstport 4789' \ ${EXECUTOR} } create_ucast_ptp_body() { export IFACE=vx_foo PHASE=create MOCK=echo IF_VXLAN_ID=2342 IF_VXLAN_PEER_IPS=192.2.0.42 atf_check -s exit:0 -o match:'ip link add vx_foo type vxlan id 2342 remote 192.2.0.42' \ ${EXECUTOR} } create_ucast_ptmp_body() { export IFACE=vx_foo PHASE=create MOCK=echo IF_VXLAN_ID=2342 IF_VXLAN_PEER_IPS="10.0.0.1 10.0.0.2 10.0.0.3" atf_check -s exit:0 \ -o match:'ip link add vx_foo type vxlan id 2342 dstport 4789' \ -o match:'bridge fdb append 00:00:00:00:00:00 dev vx_foo dst 10.0.0.1 self permanent' \ -o match:'bridge fdb append 00:00:00:00:00:00 dev vx_foo dst 10.0.0.2 self permanent' \ -o match:'bridge fdb append 00:00:00:00:00:00 dev vx_foo dst 10.0.0.3 self permanent' \ ${EXECUTOR} } create_mcast_body() { export IFACE=vx_foo PHASE=create MOCK=echo IF_VXLAN_ID=2342 IF_VXLAN_PEER_GROUP=225.0.8.15 atf_check -s exit:0 -o match:'ip link add vx_foo type vxlan id 2342 group 225.0.8.15' \ ${EXECUTOR} } create_physdev_body() { export IFACE=vx_foo PHASE=create MOCK=echo IF_VXLAN_ID=2342 IF_VXLAN_PHYSDEV=eth0 atf_check -s exit:0 -o match:'ip link add vx_foo type vxlan id 2342 dev eth0' \ ${EXECUTOR} } create_dstport_body() { export IFACE=vx_foo PHASE=create MOCK=echo IF_VXLAN_ID=2342 IF_VXLAN_DSTPORT=1234 atf_check -s exit:0 -o match:'ip link add vx_foo type vxlan id 2342 dstport 1234' \ ${EXECUTOR} } create_nolearning_body() { export IFACE=vx_foo PHASE=create MOCK=echo IF_VXLAN_ID=2342 IF_VXLAN_LEARNING=no atf_check -s exit:0 -o match:'ip link add vx_foo type vxlan id 2342 dstport 4789 nolearning' \ ${EXECUTOR} } destroy_body() { export IFACE=vx_foo PHASE=destroy MOCK=echo IF_VXLAN_ID=2342 atf_check -s exit:0 -o match:'ip link del vx_foo' \ ${EXECUTOR} } ifupdown-ng-ifupdown-ng-0.12.1/tests/linux/wireguard_test000077500000000000000000000015201422731055100235400ustar00rootroot00000000000000#!/usr/bin/env atf-sh . $(atf_get_srcdir)/../test_env.sh EXECUTOR="$(atf_get_srcdir)/../../executor-scripts/linux/wireguard" tests_init \ create \ pre_up \ pre_up_specified_config \ destroy create_body() { export IFACE=wg0 PHASE=create MOCK=echo atf_check -s exit:0 \ -o match:'ip link add wg0 type wireguard' \ ${EXECUTOR} } pre_up_body() { export IFACE=wg0 PHASE=pre-up MOCK=echo atf_check -s exit:0 \ -o match:'wg setconf wg0 /etc/wireguard/wg0.conf' \ ${EXECUTOR} } pre_up_specified_config_body() { export IFACE=wg0 PHASE=pre-up MOCK=echo \ IF_WIREGUARD_CONFIG_PATH=/etc/wireguard/vpn.conf atf_check -s exit:0 \ -o match:'wg setconf wg0 /etc/wireguard/vpn.conf' \ ${EXECUTOR} } destroy_body() { export IFACE=wg0 PHASE=destroy MOCK=echo atf_check -s exit:0 \ -o match:'ip link delete dev wg0' \ ${EXECUTOR} } ifupdown-ng-ifupdown-ng-0.12.1/tests/multicall_test000077500000000000000000000003141422731055100223760ustar00rootroot00000000000000#!/usr/bin/env atf-sh . $(atf_get_srcdir)/test_env.sh tests_init \ regress_getopt regress_getopt_body() { atf_check -e not-inline:'-F: applet not found' -o ignore -s exit:1 \ ifupdown ifquery -F } ifupdown-ng-ifupdown-ng-0.12.1/tests/test_env.sh000066400000000000000000000005461422731055100216150ustar00rootroot00000000000000PATH="$(atf_get_srcdir)/..:$(atf_get_srcdir)/../..:$PATH" FIXTURES="$(atf_get_srcdir)/fixtures" EXECUTORS="$(atf_get_srcdir)/executors" EXECUTORS_LINUX="$(atf_get_srcdir)/../executor-scripts/linux" tests_init() { TESTS="$@" export TESTS for t ; do atf_test_case $t done } atf_init_test_cases() { for t in ${TESTS}; do atf_add_test_case $t done }