hosts: always check and update /etc/hosts if needed (rh #569914)

If the hostname was changed while NM wasn't running, and thus /etc/hosts
was out of sync with the new hostname, NM wouldn't make sure that
the new hostname was mapped in /etc/hosts.  Make sure that happens
and add a bunch of testcases for /etc/hosts rewriting.
This commit is contained in:
Dan Williams 2010-03-02 14:44:02 -08:00
parent a542bba20a
commit e8b5bcca56
7 changed files with 708 additions and 188 deletions

1
.gitignore vendored
View file

@ -92,6 +92,7 @@ libnm-util/tests/test-general
libnm-util/tests/test-need-secrets
libnm-util/tests/test-setting-8021x
src/tests/test-dhcp-options
src/tests/test-policy-hosts
system-settings/plugins/keyfile/tests/test-keyfile
system-settings/plugins/ifcfg-rh/tests/test-ifcfg-rh

View file

@ -30,10 +30,14 @@ INCLUDES = -I${top_srcdir} \
-I${top_srcdir}/callouts
###########################################
# DHCP test library
# Test libraries
###########################################
noinst_LTLIBRARIES = libtest-dhcp.la
noinst_LTLIBRARIES = libtest-dhcp.la libtest-policy-hosts.la
###########################################
# DHCP test library
###########################################
libtest_dhcp_la_SOURCES = \
nm-ip4-config.c \
@ -53,6 +57,20 @@ libtest_dhcp_la_LIBADD = \
$(DBUS_LIBS) \
$(LIBNL_LIBS)
###########################################
# Hosts policy test library
###########################################
libtest_policy_hosts_la_SOURCES = \
nm-policy-hosts.c \
nm-policy-hosts.h
libtest_policy_hosts_la_CPPFLAGS = \
$(GLIB_CFLAGS)
libtest_policy_hosts_la_LIBADD = \
$(GLIB_LIBS)
###########################################
# NetworkManager
@ -99,6 +117,8 @@ NetworkManager_SOURCES = \
NetworkManager.c \
NetworkManagerPolicy.c \
NetworkManagerPolicy.h \
nm-policy-hosts.c \
nm-policy-hosts.h \
NetworkManagerUtils.c \
NetworkManagerUtils.h \
NetworkManagerSystem.c \

View file

@ -15,7 +15,7 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2004 - 2008 Red Hat, Inc.
* Copyright (C) 2004 - 2010 Red Hat, Inc.
* Copyright (C) 2007 - 2008 Novell, Inc.
*/
@ -41,6 +41,7 @@
#include "nm-named-manager.h"
#include "nm-vpn-manager.h"
#include "nm-modem.h"
#include "nm-policy-hosts.h"
typedef struct LookupThread LookupThread;
@ -252,195 +253,64 @@ get_best_device (NMManager *manager, NMActRequest **out_req)
return best;
}
static gboolean
is_localhost_mapping (const char *str)
{
return (!strncmp (str, "127.0.0.1", strlen ("127.0.0.1")) && strstr (str, "localhost"));
}
static gboolean
find_token (const char *line, const char *token)
{
const char *start = line, *p = line;
g_return_val_if_fail (line != NULL, FALSE);
g_return_val_if_fail (token != NULL, FALSE);
g_return_val_if_fail (strlen (token) > 0, FALSE);
/* Walk through the line to find the next whitespace character */
while (p <= line + strlen (line)) {
if (isblank (*p) || (*p == '\0')) {
/* Token starts with 'start' and ends with 'end' */
if ((p > start) && *start && !strncmp (start, token, (p - start)))
return TRUE; /* found */
/* not found; advance start and continue looking */
start = p + 1;
}
p++;
}
return FALSE;
}
#if 0
/* Testcase for find_token; break it out and add it to the testsuite */
typedef struct {
const char *line;
const char *token;
gboolean expected;
} Foo;
static Foo foo[] = {
{ "127.0.0.1\tfoobar\tblah", "blah", TRUE },
{ "", "blah", FALSE },
{ "1.1.1.1\tbork\tfoo", "blah", FALSE },
{ "127.0.0.1 foobar\tblah", "blah", TRUE },
{ "127.0.0.1 foobar blah", "blah", TRUE },
{ "192.168.1.1 blah borkbork", "blah", TRUE },
{ "192.168.1.1 foobar\tblah borkbork", "blah", TRUE },
{ "192.168.1.1\tfoobar\tblah\tborkbork", "blah", TRUE },
{ "192.168.1.1 \tfoobar \tblah \tborkbork\t ", "blah", TRUE },
{ "\t\t\t\t \t\t\tasdfadf a\t\t\t\t\t \t\t\t\t\t ", "blah", FALSE },
{ NULL, NULL, FALSE }
};
int main(int argc, char **argv)
{
Foo *iter = &foo[0];
while (iter->line) {
if (find_token (iter->line, iter->token) != iter->expected) {
g_message ("Failed: '%s' <= '%s' (%d)", iter->line, iter->token, iter->expected);
return 1;
}
iter++;
}
g_message ("Success");
return 0;
}
#endif
#define FALLBACK_HOSTNAME "localhost.localdomain"
static gboolean
update_etc_hosts (const char *hostname)
update_etc_hosts (const char *hostname, gboolean *out_changed)
{
char *contents = NULL;
char **lines = NULL, **line, **host_mapping = NULL;
char **lines = NULL;
GError *error = NULL;
gboolean initial_comments = TRUE;
gboolean added = FALSE;
GString *new_contents = NULL;
gsize contents_len = 0;
GString *new_contents;
gboolean success = FALSE;
g_return_val_if_fail (hostname != NULL, FALSE);
g_return_val_if_fail (out_changed != NULL, FALSE);
if (!g_file_get_contents (SYSCONFDIR "/hosts", &contents, &contents_len, &error)) {
nm_warning ("%s: couldn't read " SYSCONFDIR "/hosts: (%d) %s",
__func__, error ? error->code : 0,
(error && error->message) ? error->message : "(unknown)");
if (error)
g_error_free (error);
} else {
lines = g_strsplit_set (contents, "\n\r", 0);
g_free (contents);
}
new_contents = g_string_sized_new (contents_len ? contents_len + 100 : 200);
if (!new_contents) {
nm_warning ("%s: not enough memory to update " SYSCONFDIR "/hosts", __func__);
g_clear_error (&error);
return FALSE;
}
/* Two-pass modification of /etc/hosts:
*
* 1) Look for a non-comment, non-localhost line that contains the current
* hostname. Mark that line.
*
* 2) For each line in the existing /etc/hosts, add it to the new /etc/hosts
* unless it starts with 127.0.0.1 and is right after the initial comments
* (if any) and contains "localhost".
*/
/* Get the new /etc/hosts contents */
lines = g_strsplit_set (contents, "\n\r", 0);
new_contents = nm_policy_get_etc_hosts ((const char **) lines,
contents_len,
hostname,
FALLBACK_HOSTNAME,
&error);
g_strfreev (lines);
g_free (contents);
/* Find any existing hostname mapping */
for (line = lines; lines && *line; line++) {
/* Look for any line that (a) contains the current hostname, and
* (b) does not start with '127.0.0.1' and contain 'localhost'.
*/
if ( strlen (*line)
&& (*line[0] != '#')
&& find_token (*line, hostname)
&& !is_localhost_mapping (*line)) {
host_mapping = line;
break;
}
}
if (new_contents) {
nm_info ("Updating /etc/hosts with new system hostname");
/* Construct the new hosts file; replace any 127.0.0.1 entry that is at the
* beginning of the file or right after initial comments and contains
* the string 'localhost'. If there is no 127.0.0.1 entry at the beginning
* or after initial comments that contains 'localhost', add one there
* and ignore any other 127.0.0.1 entries that contain 'localhost'.
*/
for (line = lines, initial_comments = TRUE; lines && *line; line++) {
gboolean add_line = TRUE;
/* This is the first line after the initial comments */
if (strlen (*line) && initial_comments && (*line[0] != '#')) {
initial_comments = FALSE;
/* If some other line contained the hostname, make a simple
* localhost mapping and assume the user knows what they are doing
* with their manual hostname entry. Otherwise if the hostname
* wasn't found somewhere else, add it to the localhost mapping line
* to make sure it's mapped to something.
*/
if (host_mapping)
g_string_append (new_contents, "127.0.0.1");
else
g_string_append_printf (new_contents, "127.0.0.1\t%s", hostname);
if (strcmp (hostname, FALLBACK_HOSTNAME))
g_string_append_printf (new_contents, "\t" FALLBACK_HOSTNAME);
g_string_append (new_contents, "\tlocalhost\n");
added = TRUE;
/* Don't add the entry if it's supposed to be the actual localhost reverse mapping */
if (is_localhost_mapping (*line))
add_line = FALSE;
g_clear_error (&error);
/* And actually update /etc/hosts */
if (!g_file_set_contents (SYSCONFDIR "/hosts", new_contents->str, -1, &error)) {
nm_warning ("%s: couldn't update " SYSCONFDIR "/hosts: (%d) %s",
__func__, error ? error->code : 0,
(error && error->message) ? error->message : "(unknown)");
g_clear_error (&error);
} else {
success = TRUE;
*out_changed = TRUE;
}
if (add_line) {
g_string_append (new_contents, *line);
/* Only append the new line if this isn't the last line in the file */
if (*(line+1))
g_string_append_c (new_contents, '\n');
}
}
/* Hmm, /etc/hosts was empty for some reason */
if (!added) {
g_string_append (new_contents, "# Do not remove the following line, or various programs\n");
g_string_append (new_contents, "# that require network functionality will fail.\n");
g_string_append (new_contents, "127.0.0.1\t" FALLBACK_HOSTNAME "\tlocalhost\n");
}
error = NULL;
if (!g_file_set_contents (SYSCONFDIR "/hosts", new_contents->str, -1, &error)) {
nm_warning ("%s: couldn't update " SYSCONFDIR "/hosts: (%d) %s",
__func__, error ? error->code : 0,
(error && error->message) ? error->message : "(unknown)");
if (error)
g_error_free (error);
} else
g_string_free (new_contents, TRUE);
} else if (!error) {
/* No change required */
success = TRUE;
} else {
nm_warning ("%s: couldn't read " SYSCONFDIR "/hosts: (%d) %s",
__func__, error->code, error->message ? error->message : "(unknown)");
g_clear_error (&error);
}
g_string_free (new_contents, TRUE);
return success;
}
@ -450,6 +320,7 @@ set_system_hostname (const char *new_hostname, const char *msg)
char old_hostname[HOST_NAME_MAX + 1];
int ret = 0;
const char *name = new_hostname ? new_hostname : FALLBACK_HOSTNAME;
gboolean set_hostname = TRUE, changed = FALSE;
old_hostname[HOST_NAME_MAX] = '\0';
errno = 0;
@ -458,30 +329,40 @@ set_system_hostname (const char *new_hostname, const char *msg)
nm_warning ("%s: couldn't get the system hostname: (%d) %s",
__func__, errno, strerror (errno));
} else {
/* Do nothing if the hostname isn't actually changing */
/* Don't set the hostname if it isn't actually changing */
if ( (new_hostname && !strcmp (old_hostname, new_hostname))
|| (!new_hostname && !strcmp (old_hostname, FALLBACK_HOSTNAME)))
set_hostname = FALSE;
}
if (set_hostname) {
nm_info ("Setting system hostname to '%s' (%s)", name, msg);
ret = sethostname (name, strlen (name));
if (ret != 0) {
nm_warning ("%s: couldn't set the system hostname to '%s': (%d) %s",
__func__, name, errno, strerror (errno));
return;
}
nm_info ("Setting system hostname to '%s' (%s)", name, msg);
ret = sethostname (name, strlen (name));
if (ret == 0) {
if (!update_etc_hosts (name)) {
/* error updating /etc/hosts; fallback to localhost.localdomain */
nm_info ("Setting system hostname to '" FALLBACK_HOSTNAME "' (error updating /etc/hosts)");
ret = sethostname (FALLBACK_HOSTNAME, strlen (FALLBACK_HOSTNAME));
if (ret != 0) {
nm_warning ("%s: couldn't set the fallback system hostname (%s): (%d) %s",
__func__, FALLBACK_HOSTNAME, errno, strerror (errno));
}
}
nm_utils_call_dispatcher ("hostname", NULL, NULL, NULL);
} else {
nm_warning ("%s: couldn't set the system hostname to '%s': (%d) %s",
__func__, name, errno, strerror (errno));
}
/* But still always try updating /etc/hosts just in case the hostname
* changed while NM wasn't running; we need to make sure that /etc/hosts
* has valid mappings for '127.0.0.1' and the current system hostname. If
* those exist, update_etc_hosts() will just return and won't touch
* /etc/hosts at all.
*/
if (!update_etc_hosts (name, &changed)) {
/* error updating /etc/hosts; fallback to localhost.localdomain */
nm_info ("Setting system hostname to '" FALLBACK_HOSTNAME "' (error updating /etc/hosts)");
ret = sethostname (FALLBACK_HOSTNAME, strlen (FALLBACK_HOSTNAME));
if (ret != 0) {
nm_warning ("%s: couldn't set the fallback system hostname (%s): (%d) %s",
__func__, FALLBACK_HOSTNAME, errno, strerror (errno));
}
}
if (changed)
nm_utils_call_dispatcher ("hostname", NULL, NULL, NULL);
}
static void

173
src/nm-policy-hosts.c Normal file
View file

@ -0,0 +1,173 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager -- Network link manager
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2004 - 2010 Red Hat, Inc.
*/
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <netdb.h>
#include <ctype.h>
#include "nm-policy-hosts.h"
gboolean
nm_policy_hosts_find_token (const char *line, const char *token)
{
const char *start = line, *p = line;
g_return_val_if_fail (line != NULL, FALSE);
g_return_val_if_fail (token != NULL, FALSE);
g_return_val_if_fail (strlen (token) > 0, FALSE);
/* Walk through the line to find the next whitespace character */
while (p <= line + strlen (line)) {
if (isblank (*p) || (*p == '\0')) {
/* Token starts with 'start' and ends with 'end' */
if ((p > start) && *start && (p - start == strlen (token)) && !strncmp (start, token, (p - start)))
return TRUE; /* found */
/* not found; advance start and continue looking */
start = p + 1;
}
p++;
}
return FALSE;
}
static gboolean
is_local_mapping (const char *str, const char *hostname)
{
return ( !strncmp (str, "127.0.0.1", strlen ("127.0.0.1"))
&& nm_policy_hosts_find_token (str, hostname ? hostname : "localhost"));
}
GString *
nm_policy_get_etc_hosts (const char **lines,
gsize existing_len,
const char *hostname,
const char *fallback_hostname,
GError **error)
{
GString *contents = NULL;
const char **line;
gboolean found_host_nonlocal = FALSE;
gboolean found_host = FALSE;
gboolean found_localhost = FALSE;
gboolean initial_comments = TRUE;
gboolean added = FALSE;
g_return_val_if_fail (lines != NULL, FALSE);
g_return_val_if_fail (hostname != NULL, FALSE);
/* /etc/hosts needs at least two things:
*
* 1) current hostname mapped to any address
* 2) 'localhost' mapped to 127.0.0.1
*
* If both these conditions exist in /etc/hosts, we don't need to bother
* updating the file.
*/
/* Look for the two cases from above */
for (line = lines; lines && *line; line++) {
if (strlen (*line) && (*line[0] != '#')) {
if (nm_policy_hosts_find_token (*line, hostname)) {
if (!is_local_mapping (*line, "localhost")) {
/* hostname is not on a 127.0.0.1 line or the line does not
* contain 'localhost'.
*/
found_host_nonlocal = TRUE;
}
found_host = TRUE;
}
if (is_local_mapping (*line, "localhost")) {
/* a 127.0.0.1 line containing 'localhost' */
found_localhost = TRUE;
}
}
if (found_localhost && found_host)
return NULL; /* No update required */
}
contents = g_string_sized_new (existing_len ? existing_len + 100 : 200);
if (!contents) {
g_set_error_literal (error, 0, 0, "not enough memory");
return NULL;
}
/* Construct the new hosts file; replace any 127.0.0.1 entry that is at the
* beginning of the file or right after initial comments and contains
* the string 'localhost'. If there is no 127.0.0.1 entry at the beginning
* or after initial comments that contains 'localhost', add one there
* and ignore any other 127.0.0.1 entries that contain 'localhost'.
*/
for (line = lines, initial_comments = TRUE; lines && *line; line++) {
gboolean add_line = TRUE;
/* This is the first line after the initial comments */
if (strlen (*line) && initial_comments && (*line[0] != '#')) {
initial_comments = FALSE;
/* If some other line contained the hostname but not 'localhost',
* make a simple localhost mapping and assume the user knows what
* they are doing with their manual hostname entry. Otherwise if
* the hostname wasn't found somewhere else, add it to the localhost
* mapping line to make sure it's mapped to something.
*/
if (found_host_nonlocal)
g_string_append (contents, "127.0.0.1");
else
g_string_append_printf (contents, "127.0.0.1\t%s", hostname);
if (strcmp (hostname, fallback_hostname)) {
g_string_append_printf (contents, "\t%s", fallback_hostname);
/* Don't add a standalone 'localhost.localdomain' 127 mapping */
if (is_local_mapping (*line, fallback_hostname))
add_line = FALSE;
}
g_string_append (contents, "\tlocalhost\n");
added = TRUE;
/* Don't add the original line if it is a 'localhost' mapping */
if (is_local_mapping (*line, "localhost"))
add_line = FALSE;
}
if (add_line) {
g_string_append (contents, *line);
/* Only append the new line if this isn't the last line in the file */
if (*(line+1))
g_string_append_c (contents, '\n');
}
}
/* Hmm, /etc/hosts was empty for some reason */
if (!added) {
g_string_append (contents, "# Do not remove the following line, or various programs\n");
g_string_append (contents, "# that require network functionality will fail.\n");
g_string_append_printf (contents, "127.0.0.1\t%s\tlocalhost\n", fallback_hostname);
}
return contents;
}

36
src/nm-policy-hosts.h Normal file
View file

@ -0,0 +1,36 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager -- Network link manager
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2004 - 2010 Red Hat, Inc.
*/
#ifndef NM_POLICY_HOSTS_H
#define NM_POLICT_HOSTS_H
#include <glib.h>
GString *nm_policy_get_etc_hosts (const char **lines,
gsize existing_len,
const char *hostname,
const char *fallback_hostname,
GError **error);
/* Only for testcases; don't use outside of nm-policy-hosts.c */
gboolean nm_policy_hosts_find_token (const char *line, const char *token);
#endif /* NM_POLICY_HOSTS_H */

View file

@ -6,7 +6,9 @@ INCLUDES = \
-I$(top_srcdir)/src \
-I$(top_builddir)/src
noinst_PROGRAMS = test-dhcp-options
noinst_PROGRAMS = test-dhcp-options test-policy-hosts
####### DHCP options test #######
test_dhcp_options_SOURCES = \
test-dhcp-options.c
@ -24,10 +26,23 @@ test_dhcp_options_LDADD = \
$(GLIB_LIBS) \
$(DBUS_LIBS)
####### policy /etc/hosts test #######
test_policy_hosts_SOURCES = \
test-policy-hosts.c
test_policy_hosts_CPPFLAGS = \
$(GLIB_CFLAGS)
test_policy_hosts_LDADD = \
$(top_builddir)/src/libtest-policy-hosts.la \
$(GLIB_LIBS)
if WITH_TESTS
check-local: test-dhcp-options
$(abs_builddir)/test-dhcp-options
$(abs_builddir)/test-policy-hosts
endif

View file

@ -0,0 +1,394 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2010 Red Hat, Inc.
*
*/
#include <glib.h>
#include <string.h>
#include "nm-policy-hosts.h"
#define FALLBACK_HOSTNAME "localhost.localdomain"
static void
test_generic (const char *before,
const char *after,
const char *hostname,
gboolean expect_error)
{
char **lines;
GString *newc;
GError *error = NULL;
/* Get the new /etc/hosts contents */
lines = g_strsplit_set (before, "\n\r", 0);
newc = nm_policy_get_etc_hosts ((const char **) lines,
strlen (before),
hostname,
FALLBACK_HOSTNAME,
&error);
g_strfreev (lines);
if (expect_error) {
g_assert (newc == NULL);
g_assert (error != NULL);
g_clear_error (&error);
} else if (after == NULL) {
/* No change to /etc/hosts required */
g_assert (newc == NULL);
g_assert (error == NULL);
} else {
g_assert (newc != NULL);
g_assert (error == NULL);
#if 0
g_message ("\n--------------------------------------\n"
"%s"
"--------------------------------------",
newc->str);
#endif
g_assert (strlen (newc->str) == strlen (after));
g_assert (strcmp (newc->str, after) == 0);
g_string_free (newc, TRUE);
}
}
/*******************************************/
static const char *generic_before = \
"# Do not remove the following line, or various programs\n"
"# that require network functionality will fail.\n"
"127.0.0.1 localhost.localdomain localhost\n"
"::1 localhost6.localdomain6 localhost6\n"
"127.0.0.1 lcmd.us.intellitxt.com\n";
static void
test_hosts_generic (void)
{
test_generic (generic_before, NULL, "localhost.localdomain", FALSE);
}
/*******************************************/
static const char *generic_no_boilerplate_before = \
"127.0.0.1 localhost.localdomain localhost\n"
"::1 localhost6.localdomain6 localhost6\n"
"127.0.0.1 lcmd.us.intellitxt.com\n";
static void
test_hosts_generic_no_boilerplate (void)
{
test_generic (generic_no_boilerplate_before, NULL, "localhost.localdomain", FALSE);
}
/*******************************************/
static const char *generic_no_boilerplate_no_lh_before = \
"127.0.0.1 localhost.localdomain\n"
"::1 localhost6.localdomain6 localhost6\n"
"127.0.0.1 lcmd.us.intellitxt.com\n";
static const char *generic_no_boilerplate_no_lh_after = \
"127.0.0.1 localhost\n"
"127.0.0.1 localhost.localdomain\n"
"::1 localhost6.localdomain6 localhost6\n"
"127.0.0.1 lcmd.us.intellitxt.com\n";
static void
test_hosts_generic_no_boilerplate_no_lh (void)
{
test_generic (generic_no_boilerplate_no_lh_before,
generic_no_boilerplate_no_lh_after,
"localhost.localdomain",
FALSE);
}
/*******************************************/
static const char *generic_no_boilerplate_no_lh_no_host_before = \
"127.0.0.1 localhost.localdomain\n"
"::1 localhost6.localdomain6 localhost6\n"
"127.0.0.1 lcmd.us.intellitxt.com\n";
static const char *generic_no_boilerplate_no_lh_no_host_after = \
"127.0.0.1 comet localhost.localdomain localhost\n"
"::1 localhost6.localdomain6 localhost6\n"
"127.0.0.1 lcmd.us.intellitxt.com\n";
static void
test_hosts_generic_no_boilerplate_no_lh_no_host (void)
{
test_generic (generic_no_boilerplate_no_lh_no_host_before,
generic_no_boilerplate_no_lh_no_host_after,
"comet",
FALSE);
}
/*******************************************/
static const char *named_generic_before = \
"# Do not remove the following line, or various programs\n"
"# that require network functionality will fail.\n"
"127.0.0.1 playboy localhost\n"
"::1 localhost6.localdomain6 localhost6\n"
"127.0.0.1 lcmd.us.intellitxt.com\n";
static void
test_hosts_named_generic (void)
{
test_generic (named_generic_before, NULL, "playboy", FALSE);
}
/*******************************************/
static const char *named_non127_before = \
"# Do not remove the following line, or various programs\n"
"# that require network functionality will fail.\n"
"127.0.0.1 localhost.localdomain localhost\n"
"::1 localhost6.localdomain6 localhost6\n"
"127.0.0.1 lcmd.us.intellitxt.com\n"
"192.168.1.2 tomcat\n";
static void
test_hosts_named_non127 (void)
{
test_generic (named_non127_before, NULL, "tomcat", FALSE);
}
/*******************************************/
static const char *named2_non127_before = \
"# Do not remove the following line, or various programs\n"
"# that require network functionality will fail.\n"
"127.0.0.1 localhost.localdomain localhost\n"
"::1 localhost6.localdomain6 localhost6\n"
"127.0.0.1 lcmd.us.intellitxt.com\n"
"192.168.1.2 tomcat\n"
"127.0.0.1 lcmd.us.intellitxt.com\n"
"127.0.0.1 srx.main.ebayrtm.com\n"
"127.0.0.1 cdn5.tribalfusion.com\n";
static void
test_hosts_named2_non127 (void)
{
test_generic (named2_non127_before, NULL, "tomcat", FALSE);
}
/*******************************************/
static const char *named_no_lh_before = \
"# Do not remove the following line, or various programs\n"
"# that require network functionality will fail.\n"
"127.0.0.1 localhost.localdomain\n"
"::1 localhost6.localdomain6 localhost6\n"
"127.0.0.1 lcmd.us.intellitxt.com\n"
"192.168.1.2 tomcat\n";
static const char *named_no_lh_after = \
"# Do not remove the following line, or various programs\n"
"# that require network functionality will fail.\n"
"127.0.0.1 localhost.localdomain localhost\n"
"::1 localhost6.localdomain6 localhost6\n"
"127.0.0.1 lcmd.us.intellitxt.com\n"
"192.168.1.2 tomcat\n";
static void
test_hosts_named_no_localhost (void)
{
test_generic (named_no_lh_before, named_no_lh_after, "tomcat", FALSE);
}
/*******************************************/
static const char *no_lh_before = \
"# Do not remove the following line, or various programs\n"
"# that require network functionality will fail.\n"
"127.0.0.1 tomcat\n"
"::1 localhost6.localdomain6 localhost6\n"
"127.0.0.1 lcmd.us.intellitxt.com\n";
static const char *no_lh_after = \
"# Do not remove the following line, or various programs\n"
"# that require network functionality will fail.\n"
"127.0.0.1 localhost.localdomain localhost\n"
"127.0.0.1 tomcat\n"
"::1 localhost6.localdomain6 localhost6\n"
"127.0.0.1 lcmd.us.intellitxt.com\n";
static void
test_hosts_no_localhost (void)
{
test_generic (no_lh_before, no_lh_after, "tomcat", FALSE);
}
/*******************************************/
static const char *named_last_before = \
"# Do not remove the following line, or various programs\n"
"# that require network functionality will fail.\n"
"127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 sparcbook.ausil.us\n"
"::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 sparcbook.ausil.us\n";
static void
test_hosts_named_last (void)
{
test_generic (named_last_before, NULL, "sparcbook.ausil.us", FALSE);
}
/*******************************************/
static const char *no_host_before = \
"# Do not remove the following line, or various programs\n"
"# that require network functionality will fail.\n"
"::1 localhost6.localdomain6 localhost6\n"
"\n"
"127.0.0.1 lcmd.us.intellitxt.com\n"
"127.0.0.1 srx.main.ebayrtm.com\n"
"127.0.0.1 cdn5.tribalfusion.com\n"
"127.0.0.1 a.tribalfusion.com\n";
static const char *no_host_after = \
"# Do not remove the following line, or various programs\n"
"# that require network functionality will fail.\n"
"127.0.0.1 comet localhost.localdomain localhost\n"
"::1 localhost6.localdomain6 localhost6\n"
"\n"
"127.0.0.1 lcmd.us.intellitxt.com\n"
"127.0.0.1 srx.main.ebayrtm.com\n"
"127.0.0.1 cdn5.tribalfusion.com\n"
"127.0.0.1 a.tribalfusion.com\n";
static void
test_hosts_no_host (void)
{
test_generic (no_host_before, no_host_after, "comet", FALSE);
}
/*******************************************/
static const char *long_before = \
"# Do not remove the following line, or various programs\n"
"# that require network functionality will fail.\n"
"127.0.0.1 localhost.localdomain localhost comet\n"
"::1 localhost6.localdomain6 localhost6\n"
"\n"
"127.0.0.1 lcmd.us.intellitxt.com\n"
"127.0.0.1 adserver.adtech.de\n"
"127.0.0.1 a.as-us.falkag.net\n"
"127.0.0.1 a.as-eu.falkag.net\n"
"127.0.0.1 ads.doubleclick.com\n"
"\n"
"# random comment\n"
"127.0.0.1 m1.2mdn.net\n"
"127.0.0.1 ds.serving-sys.com\n"
"127.0.0.1 pagead2.googlesyndication.com\n"
"127.0.0.1 ad.doubleclick.com\n"
"127.0.0.1 ad.doubleclick.net\n"
"127.0.0.1 oascentral.movietickets.com\n"
"127.0.0.1 view.atdmt.com\n"
"127.0.0.1 ads.chumcity.com\n"
"127.0.0.1 ads.as4x.tmcs.net\n"
"127.0.0.1 n4403ad.doubleclick.net\n"
"127.0.0.1 www.assoc-amazon.com\n"
"127.0.0.1 s25.sitemeter.com\n"
"127.0.0.1 adlog.com.com\n"
"127.0.0.1 ahs.laptopmag.com\n"
"127.0.0.1 altfarm.mediaplex.com\n"
"127.0.0.1 ads.addynamix.com\n"
"127.0.0.1 srx.main.ebayrtm.com\n"
"127.0.0.1 cdn5.tribalfusion.com\n"
"127.0.0.1 a.tribalfusion.com\n";
static void
test_hosts_long (void)
{
test_generic (long_before, NULL, "comet", FALSE);
}
/*******************************************/
typedef struct {
const char *line;
const char *token;
gboolean expected;
} Foo;
static Foo foo[] = {
/* Using \t here to easily differentiate tabs vs. spaces for testing */
{ "127.0.0.1\tfoobar\tblah", "blah", TRUE },
{ "", "blah", FALSE },
{ "1.1.1.1\tbork\tfoo", "blah", FALSE },
{ "127.0.0.1 foobar\tblah", "blah", TRUE },
{ "127.0.0.1 foobar blah", "blah", TRUE },
{ "127.0.0.1 localhost", "localhost.localdomain", FALSE },
{ "192.168.1.1 blah borkbork", "blah", TRUE },
{ "192.168.1.1 foobar\tblah borkbork", "blah", TRUE },
{ "192.168.1.1\tfoobar\tblah\tborkbork", "blah", TRUE },
{ "192.168.1.1 \tfoobar \tblah \tborkbork\t ", "blah", TRUE },
{ "\t\t\t\t \t\t\tasdfadf a\t\t\t\t\t \t\t\t\t\t ", "blah", FALSE },
{ NULL, NULL, FALSE }
};
static void
test_find_token (void)
{
Foo *iter = &foo[0];
while (iter->line) {
gboolean found;
found = nm_policy_hosts_find_token (iter->line, iter->token);
if (found != iter->expected) {
g_warning ("find-token: unexpected token result %d for '%s' <= '%s' (expected %d)",
found, iter->line, iter->token, iter->expected);
}
g_assert (found == iter->expected);
iter++;
}
}
typedef void (*TCFunc)(void);
#define TESTCASE(t, d) g_test_create_case (#t, 0, d, NULL, (TCFunc) t, NULL)
int main (int argc, char **argv)
{
GTestSuite *suite;
g_test_init (&argc, &argv, NULL);
suite = g_test_get_root ();
g_test_suite_add (suite, TESTCASE (test_find_token, NULL));
g_test_suite_add (suite, TESTCASE (test_hosts_generic, NULL));
g_test_suite_add (suite, TESTCASE (test_hosts_generic_no_boilerplate, NULL));
g_test_suite_add (suite, TESTCASE (test_hosts_generic_no_boilerplate_no_lh, NULL));
g_test_suite_add (suite, TESTCASE (test_hosts_generic_no_boilerplate_no_lh_no_host, NULL));
g_test_suite_add (suite, TESTCASE (test_hosts_named_generic, NULL));
g_test_suite_add (suite, TESTCASE (test_hosts_named_non127, NULL));
g_test_suite_add (suite, TESTCASE (test_hosts_named2_non127, NULL));
g_test_suite_add (suite, TESTCASE (test_hosts_named_no_localhost, NULL));
g_test_suite_add (suite, TESTCASE (test_hosts_no_localhost, NULL));
g_test_suite_add (suite, TESTCASE (test_hosts_named_last, NULL));
g_test_suite_add (suite, TESTCASE (test_hosts_no_host, NULL));
g_test_suite_add (suite, TESTCASE (test_hosts_long, NULL));
return g_test_run ();
}