/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (C) 2010 Red Hat, Inc.
*/
#include "nm-default.h"
#include "nm-core-internal.h"
#include "settings/plugins/ifupdown/nms-ifupdown-interface-parser.h"
#include "settings/plugins/ifupdown/nms-ifupdown-parser.h"
#include "nm-test-utils-core.h"
#define TEST_DIR NM_BUILD_SRCDIR "/src/core/settings/plugins/ifupdown/tests"
/*****************************************************************************/
#define _connection_from_if_block(block) \
({ \
NMConnection *_con; \
if_block * _block = (block); \
GError * _local = NULL; \
\
g_assert(_block); \
_con = ifupdown_new_connection_from_if_block(_block, FALSE, &_local); \
nmtst_assert_success(NM_IS_CONNECTION(_con), _local); \
nmtst_assert_connection_verifies_without_normalization(_con); \
_con; \
})
#define _connection_first_from_parser(parser) \
({ \
if_parser *_parser = (parser); \
\
g_assert(_parser); \
_connection_from_if_block(ifparser_getfirst(_parser)); \
})
/*****************************************************************************/
typedef struct {
char *key;
char *data;
} ExpectedKey;
typedef struct {
char * type;
char * name;
GSList *keys;
} ExpectedBlock;
typedef struct {
GSList *blocks;
} Expected;
static ExpectedKey *
expected_key_new(const char *key, const char *data)
{
ExpectedKey *k;
k = g_malloc0(sizeof(ExpectedKey));
k->key = g_strdup(key);
k->data = g_strdup(data);
return k;
}
static void
expected_key_free(gpointer ptr)
{
ExpectedKey *k = ptr;
g_assert(k);
g_free(k->key);
g_free(k->data);
memset(k, 0, sizeof(ExpectedKey));
g_free(k);
}
static ExpectedBlock *
expected_block_new(const char *type, const char *name)
{
ExpectedBlock *b;
g_assert(type);
g_assert(name);
b = g_malloc0(sizeof(ExpectedBlock));
g_assert(b);
b->type = g_strdup(type);
b->name = g_strdup(name);
return b;
}
static void
expected_block_free(gpointer ptr)
{
ExpectedBlock *b = ptr;
g_assert(b);
g_slist_free_full(b->keys, expected_key_free);
g_free(b->type);
g_free(b->name);
memset(b, 0, sizeof(ExpectedBlock));
g_free(b);
}
static void
expected_block_add_key(ExpectedBlock *b, ExpectedKey *k)
{
g_assert(b);
g_assert(k);
b->keys = g_slist_append(b->keys, k);
}
static Expected *
expected_new(void)
{
return g_malloc0(sizeof(Expected));
}
static void
expected_add_block(Expected *e, ExpectedBlock *b)
{
g_assert(e);
g_assert(b);
e->blocks = g_slist_append(e->blocks, b);
}
static void
expected_free(Expected *e)
{
g_assert(e);
g_slist_free_full(e->blocks, expected_block_free);
memset(e, 0, sizeof(Expected));
g_free(e);
}
NM_AUTO_DEFINE_FCN_VOID0(Expected *, _nm_auto_free_expected, expected_free);
#define nm_auto_free_expected nm_auto(_nm_auto_free_expected)
static void
compare_expected_to_ifparser(if_parser *parser, Expected *e)
{
if_block *n;
GSList * biter, *kiter;
g_assert_cmpint(g_slist_length(e->blocks), ==, ifparser_get_num_blocks(parser));
biter = e->blocks;
c_list_for_each_entry (n, &parser->block_lst_head, block_lst) {
if_data * m;
ExpectedBlock *b = biter->data;
g_assert(b->type && n->type);
g_assert_cmpstr(b->type, ==, n->type);
g_assert(b->name);
g_assert_cmpstr(b->name, ==, n->name);
g_assert_cmpint(g_slist_length(b->keys), ==, ifparser_get_num_info(n));
kiter = b->keys;
c_list_for_each_entry (m, &n->data_lst_head, data_lst) {
ExpectedKey *k = kiter->data;
g_assert(k->key);
g_assert_cmpstr(k->key, ==, m->key);
g_assert(k->data && m->data);
g_assert_cmpstr(k->data, ==, m->data);
kiter = g_slist_next(kiter);
}
g_assert(!kiter);
biter = g_slist_next(biter);
}
g_assert(!biter);
}
static void
dump_blocks(if_parser *parser)
{
if_block *n;
g_message("\n***************************************************");
c_list_for_each_entry (n, &parser->block_lst_head, block_lst) {
if_data *m;
// each block start with its type & name
// (single quotes used to show typ & name baoundaries)
g_print("'%s' '%s'\n", n->type, n->name);
// each key-value pair within a block is indented & separated by a tab
// (single quotes used to show type & name boundaries)
c_list_for_each_entry (m, &n->data_lst_head, data_lst)
g_print("\t'%s'\t'%s'\n", m->key, m->data);
// blocks are separated by an empty line
g_print("\n");
}
g_message("##################################################\n");
}
static if_parser *
init_ifparser_with_file(const char *file)
{
if_parser * parser;
gs_free char *tmp = NULL;
tmp = g_strdup_printf("%s/%s", TEST_DIR, file);
parser = ifparser_parse(tmp, 1);
g_assert(parser);
return parser;
}
static void
test1_ignore_line_before_first_block(void)
{
nm_auto_free_expected Expected *e = NULL;
ExpectedBlock * b;
nm_auto_ifparser if_parser *parser = init_ifparser_with_file("test1");
e = expected_new();
b = expected_block_new("auto", "eth0");
expected_add_block(e, b);
b = expected_block_new("iface", "eth0");
expected_add_block(e, b);
expected_block_add_key(b, expected_key_new("inet", "dhcp"));
compare_expected_to_ifparser(parser, e);
}
static void
test2_wrapped_line(void)
{
nm_auto_free_expected Expected *e = NULL;
ExpectedBlock * b;
nm_auto_ifparser if_parser *parser = init_ifparser_with_file("test2");
e = expected_new();
b = expected_block_new("auto", "lo");
expected_add_block(e, b);
compare_expected_to_ifparser(parser, e);
}
static void
test3_wrapped_multiline_multiarg(void)
{
nm_auto_free_expected Expected *e = NULL;
ExpectedBlock * b;
nm_auto_ifparser if_parser *parser = init_ifparser_with_file("test3");
e = expected_new();
b = expected_block_new("allow-hotplug", "eth0");
expected_add_block(e, b);
b = expected_block_new("allow-hotplug", "wlan0");
expected_add_block(e, b);
b = expected_block_new("allow-hotplug", "bnep0");
expected_add_block(e, b);
compare_expected_to_ifparser(parser, e);
}
static void
test4_allow_auto_is_auto(void)
{
nm_auto_free_expected Expected *e = NULL;
ExpectedBlock * b;
nm_auto_ifparser if_parser *parser = init_ifparser_with_file("test4");
e = expected_new();
b = expected_block_new("auto", "eth0");
expected_add_block(e, b);
compare_expected_to_ifparser(parser, e);
}
static void
test5_allow_auto_multiarg(void)
{
nm_auto_free_expected Expected *e = NULL;
ExpectedBlock * b;
nm_auto_ifparser if_parser *parser = init_ifparser_with_file("test5");
e = expected_new();
b = expected_block_new("allow-hotplug", "eth0");
expected_add_block(e, b);
b = expected_block_new("allow-hotplug", "wlan0");
expected_add_block(e, b);
compare_expected_to_ifparser(parser, e);
}
static void
test6_mixed_whitespace(void)
{
nm_auto_free_expected Expected *e = NULL;
ExpectedBlock * b;
nm_auto_ifparser if_parser *parser = init_ifparser_with_file("test6");
e = expected_new();
b = expected_block_new("iface", "lo");
expected_block_add_key(b, expected_key_new("inet", "loopback"));
expected_add_block(e, b);
compare_expected_to_ifparser(parser, e);
}
static void
test7_long_line(void)
{
nm_auto_ifparser if_parser *parser = init_ifparser_with_file("test7");
g_assert_cmpint(ifparser_get_num_blocks(parser), ==, 0);
}
static void
test8_long_line_wrapped(void)
{
nm_auto_ifparser if_parser *parser = init_ifparser_with_file("test8");
g_assert_cmpint(ifparser_get_num_blocks(parser), ==, 0);
}
static void
test9_wrapped_lines_in_block(void)
{
nm_auto_free_expected Expected *e = NULL;
ExpectedBlock * b;
nm_auto_ifparser if_parser *parser = init_ifparser_with_file("test9");
e = expected_new();
b = expected_block_new("iface", "eth0");
expected_add_block(e, b);
expected_block_add_key(b, expected_key_new("inet", "static"));
expected_block_add_key(b, expected_key_new("address", "10.250.2.3"));
expected_block_add_key(b, expected_key_new("netmask", "255.255.255.192"));
expected_block_add_key(b, expected_key_new("broadcast", "10.250.2.63"));
expected_block_add_key(b, expected_key_new("gateway", "10.250.2.50"));
compare_expected_to_ifparser(parser, e);
}
static void
test11_complex_wrap(void)
{
nm_auto_free_expected Expected *e = NULL;
ExpectedBlock * b;
nm_auto_ifparser if_parser *parser = init_ifparser_with_file("test11");
e = expected_new();
b = expected_block_new("iface", "pppoe");
expected_add_block(e, b);
expected_block_add_key(b, expected_key_new("inet", "manual"));
expected_block_add_key(b, expected_key_new("pre-up", "/sbin/ifconfig eth0 up"));
compare_expected_to_ifparser(parser, e);
}
static void
test12_complex_wrap_split_word(void)
{
nm_auto_free_expected Expected *e = NULL;
ExpectedBlock * b;
nm_auto_ifparser if_parser *parser = init_ifparser_with_file("test12");
e = expected_new();
b = expected_block_new("iface", "pppoe");
expected_add_block(e, b);
expected_block_add_key(b, expected_key_new("inet", "manual"));
expected_block_add_key(b, expected_key_new("up", "ifup ppp0=dsl"));
compare_expected_to_ifparser(parser, e);
}
static void
test13_more_mixed_whitespace(void)
{
nm_auto_free_expected Expected *e = NULL;
ExpectedBlock * b;
nm_auto_ifparser if_parser *parser = init_ifparser_with_file("test13");
e = expected_new();
b = expected_block_new("iface", "dsl");
expected_block_add_key(b, expected_key_new("inet", "ppp"));
expected_add_block(e, b);
compare_expected_to_ifparser(parser, e);
}
static void
test14_mixed_whitespace_block_start(void)
{
nm_auto_free_expected Expected *e = NULL;
ExpectedBlock * b;
nm_auto_ifparser if_parser *parser = init_ifparser_with_file("test14");
e = expected_new();
b = expected_block_new("iface", "wlan0");
expected_block_add_key(b, expected_key_new("inet", "manual"));
expected_add_block(e, b);
b = expected_block_new("iface", "wlan-adpm");
expected_block_add_key(b, expected_key_new("inet", "dhcp"));
expected_add_block(e, b);
b = expected_block_new("iface", "wlan-default");
expected_block_add_key(b, expected_key_new("inet", "dhcp"));
expected_add_block(e, b);
compare_expected_to_ifparser(parser, e);
}
static void
test15_trailing_space(void)
{
nm_auto_free_expected Expected *e = NULL;
ExpectedBlock * b;
nm_auto_ifparser if_parser *parser = init_ifparser_with_file("test15");
e = expected_new();
b = expected_block_new("iface", "bnep0");
expected_block_add_key(b, expected_key_new("inet", "static"));
expected_add_block(e, b);
compare_expected_to_ifparser(parser, e);
}
static void
test16_missing_newline(void)
{
nm_auto_free_expected Expected *e = NULL;
nm_auto_ifparser if_parser *parser = init_ifparser_with_file("test16");
e = expected_new();
expected_add_block(e, expected_block_new("mapping", "eth0"));
compare_expected_to_ifparser(parser, e);
}
static void
test17_read_static_ipv4(void)
{
gs_unref_object NMConnection *connection = NULL;
NMSettingConnection * s_con;
NMSettingIPConfig * s_ip4;
NMSettingWired * s_wired;
NMIPAddress * ip4_addr;
nm_auto_ifparser if_parser *parser = init_ifparser_with_file("test17-wired-static-verify-ip4");
connection = _connection_first_from_parser(parser);
/* ===== CONNECTION SETTING ===== */
s_con = nm_connection_get_setting_connection(connection);
g_assert(s_con);
g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "Ifupdown (eth0)");
/* ===== WIRED SETTING ===== */
s_wired = nm_connection_get_setting_wired(connection);
g_assert(s_wired);
/* ===== IPv4 SETTING ===== */
s_ip4 = nm_connection_get_setting_ip4_config(connection);
g_assert(s_ip4);
g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4),
==,
NM_SETTING_IP4_CONFIG_METHOD_MANUAL);
g_assert_cmpint(nm_setting_ip_config_get_num_addresses(s_ip4), ==, 1);
ip4_addr = nm_setting_ip_config_get_address(s_ip4, 0);
g_assert(ip4_addr != NULL);
g_assert_cmpstr(nm_ip_address_get_address(ip4_addr), ==, "10.0.0.3");
g_assert_cmpint(nm_ip_address_get_prefix(ip4_addr), ==, 8);
g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip4), ==, 2);
g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip4, 0), ==, "10.0.0.1");
g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip4, 1), ==, "10.0.0.2");
g_assert_cmpint(nm_setting_ip_config_get_num_dns_searches(s_ip4), ==, 2);
g_assert_cmpstr(nm_setting_ip_config_get_dns_search(s_ip4, 0), ==, "example.com");
g_assert_cmpstr(nm_setting_ip_config_get_dns_search(s_ip4, 1), ==, "foo.example.com");
}
static void
test18_read_static_ipv6(void)
{
gs_unref_object NMConnection *connection = NULL;
NMSettingConnection * s_con;
NMSettingIPConfig * s_ip6;
NMSettingWired * s_wired;
NMIPAddress * ip6_addr;
nm_auto_ifparser if_parser *parser = init_ifparser_with_file("test18-wired-static-verify-ip6");
connection = _connection_first_from_parser(parser);
/* ===== CONNECTION SETTING ===== */
s_con = nm_connection_get_setting_connection(connection);
g_assert(s_con);
g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "Ifupdown (myip6tunnel)");
/* ===== WIRED SETTING ===== */
s_wired = nm_connection_get_setting_wired(connection);
g_assert(s_wired);
/* ===== IPv6 SETTING ===== */
s_ip6 = nm_connection_get_setting_ip6_config(connection);
g_assert(s_ip6);
g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6),
==,
NM_SETTING_IP6_CONFIG_METHOD_MANUAL);
g_assert_cmpint(nm_setting_ip_config_get_num_addresses(s_ip6), ==, 1);
ip6_addr = nm_setting_ip_config_get_address(s_ip6, 0);
g_assert(ip6_addr != NULL);
g_assert_cmpstr(nm_ip_address_get_address(ip6_addr), ==, "fc00::1");
g_assert_cmpint(nm_ip_address_get_prefix(ip6_addr), ==, 64);
g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip6), ==, 2);
g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip6, 0), ==, "fc00::2");
g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip6, 1), ==, "fc00::3");
g_assert_cmpint(nm_setting_ip_config_get_num_dns_searches(s_ip6), ==, 2);
g_assert_cmpstr(nm_setting_ip_config_get_dns_search(s_ip6, 0), ==, "example.com");
g_assert_cmpstr(nm_setting_ip_config_get_dns_search(s_ip6, 1), ==, "foo.example.com");
}
static void
test19_read_static_ipv4_plen(void)
{
gs_unref_object NMConnection *connection = NULL;
NMSettingIPConfig * s_ip4;
NMIPAddress * ip4_addr;
nm_auto_ifparser if_parser *parser =
init_ifparser_with_file("test19-wired-static-verify-ip4-plen");
connection = _connection_first_from_parser(parser);
/* ===== IPv4 SETTING ===== */
s_ip4 = nm_connection_get_setting_ip4_config(connection);
g_assert(s_ip4);
g_assert_cmpint(nm_setting_ip_config_get_num_addresses(s_ip4), ==, 1);
ip4_addr = nm_setting_ip_config_get_address(s_ip4, 0);
g_assert(ip4_addr != NULL);
g_assert_cmpstr(nm_ip_address_get_address(ip4_addr), ==, "10.0.0.3");
g_assert_cmpint(nm_ip_address_get_prefix(ip4_addr), ==, 8);
}
static void
test20_source_stanza(void)
{
nm_auto_free_expected Expected *e = NULL;
ExpectedBlock * b;
nm_auto_ifparser if_parser *parser = init_ifparser_with_file("test20-source-stanza");
e = expected_new();
b = expected_block_new("auto", "eth0");
expected_add_block(e, b);
b = expected_block_new("iface", "eth0");
expected_add_block(e, b);
expected_block_add_key(b, expected_key_new("inet", "dhcp"));
b = expected_block_new("auto", "eth1");
expected_add_block(e, b);
b = expected_block_new("iface", "eth1");
expected_add_block(e, b);
expected_block_add_key(b, expected_key_new("inet", "dhcp"));
compare_expected_to_ifparser(parser, e);
}
static void
test21_source_dir_stanza(void)
{
nm_auto_free_expected Expected *e = NULL;
ExpectedBlock * b;
nm_auto_ifparser if_parser *parser = init_ifparser_with_file("test21-source-dir-stanza");
e = expected_new();
b = expected_block_new("auto", "eth0");
expected_add_block(e, b);
b = expected_block_new("iface", "eth0");
expected_add_block(e, b);
expected_block_add_key(b, expected_key_new("inet", "dhcp"));
compare_expected_to_ifparser(parser, e);
}
static void
test22_duplicate_stanzas(void)
{
nm_auto_free_expected Expected *e = NULL;
ExpectedBlock * b;
nm_auto_ifparser if_parser *parser = init_ifparser_with_file("test22-duplicate-stanzas");
e = expected_new();
b = expected_block_new("iface", "br10");
expected_add_block(e, b);
expected_block_add_key(b, expected_key_new("inet", "manual"));
expected_block_add_key(b, expected_key_new("bridge-ports", "enp6s0.15"));
expected_block_add_key(b, expected_key_new("bridge-stp", "off"));
expected_block_add_key(b, expected_key_new("bridge-maxwait", "0"));
expected_block_add_key(b, expected_key_new("bridge-fd", "0"));
b = expected_block_new("iface", "br10");
expected_add_block(e, b);
expected_block_add_key(b, expected_key_new("inet", "auto"));
expected_block_add_key(b, expected_key_new("bridge-ports", "enp6s0.15"));
compare_expected_to_ifparser(parser, e);
}
/*****************************************************************************/
NMTST_DEFINE();
int
main(int argc, char **argv)
{
nmtst_init_assert_logging(&argc, &argv, "WARN", "DEFAULT");
(void) dump_blocks;
g_test_add_func("/ifupdate/ignore_line_before_first_block",
test1_ignore_line_before_first_block);
g_test_add_func("/ifupdate/wrapped_line", test2_wrapped_line);
g_test_add_func("/ifupdate/wrapped_multiline_multiarg", test3_wrapped_multiline_multiarg);
g_test_add_func("/ifupdate/allow_auto_is_auto", test4_allow_auto_is_auto);
g_test_add_func("/ifupdate/allow_auto_multiarg", test5_allow_auto_multiarg);
g_test_add_func("/ifupdate/mixed_whitespace", test6_mixed_whitespace);
g_test_add_func("/ifupdate/long_line", test7_long_line);
g_test_add_func("/ifupdate/long_line_wrapped", test8_long_line_wrapped);
g_test_add_func("/ifupdate/wrapped_lines_in_block", test9_wrapped_lines_in_block);
g_test_add_func("/ifupdate/complex_wrap", test11_complex_wrap);
g_test_add_func("/ifupdate/complex_wrap_split_word", test12_complex_wrap_split_word);
g_test_add_func("/ifupdate/more_mixed_whitespace", test13_more_mixed_whitespace);
g_test_add_func("/ifupdate/mixed_whitespace_block_start", test14_mixed_whitespace_block_start);
g_test_add_func("/ifupdate/trailing_space", test15_trailing_space);
g_test_add_func("/ifupdate/missing_newline", test16_missing_newline);
g_test_add_func("/ifupdate/read_static_ipv4", test17_read_static_ipv4);
g_test_add_func("/ifupdate/read_static_ipv6", test18_read_static_ipv6);
g_test_add_func("/ifupdate/read_static_ipv4_plen", test19_read_static_ipv4_plen);
g_test_add_func("/ifupdate/source_stanza", test20_source_stanza);
g_test_add_func("/ifupdate/source_dir_stanza", test21_source_dir_stanza);
g_test_add_func("/ifupdate/test22-duplicate-stanzas", test22_duplicate_stanzas);
return g_test_run();
}