loopback-setup.c revision fc25d7f8050f262fa6cafeb2a1032e6eb3e7b412
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering/***
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering This file is part of systemd.
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering Copyright 2010 Lennart Poettering
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering systemd is free software; you can redistribute it and/or modify it
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering under the terms of the GNU Lesser General Public License as published by
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering the Free Software Foundation; either version 2.1 of the License, or
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering (at your option) any later version.
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering systemd is distributed in the hope that it will be useful, but
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering Lesser General Public License for more details.
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering You should have received a copy of the GNU Lesser General Public License
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering***/
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering#include <errno.h>
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering#include <sys/socket.h>
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering#include <net/if.h>
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering#include <asm/types.h>
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering#include <netinet/in.h>
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering#include <linux/rtnetlink.h>
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering#include <string.h>
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering#include <stdlib.h>
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering#include <unistd.h>
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering#include "util.h"
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering#include "macro.h"
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering#include "loopback-setup.h"
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering#include "socket-util.h"
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering#include "sd-rtnl.h"
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering#include "rtnl-util.h"
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poetteringstatic int pipe_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering int *counter = userdata;
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering int r;
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering (*counter) --;
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering r = sd_rtnl_message_get_errno(m);
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering return r == -EEXIST ? 0 : r;
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering}
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poetteringstatic int add_adresses(sd_rtnl *rtnl, int if_loopback, uint32_t ipv4_address, int *counter) {
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *ipv4 = NULL, *ipv6 = NULL;
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering int r;
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering r = sd_rtnl_message_addr_new(RTM_NEWADDR, if_loopback, AF_INET, 8, IFA_F_PERMANENT, RT_SCOPE_HOST, &ipv4);
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering if (r < 0)
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering return r;
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering r = sd_rtnl_message_append(ipv4, IFA_LOCAL, &ipv4_address);
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering if (r < 0)
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering return r;
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering r = sd_rtnl_call_async(rtnl, ipv4, &pipe_handler, counter, 0, NULL);
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering if (r < 0)
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering return r;
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering (*counter) ++;
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering if (!socket_ipv6_is_supported())
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering return 0;
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering r = sd_rtnl_message_addr_new(RTM_NEWADDR, if_loopback, AF_INET6, 128, 0, 0, &ipv6);
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering if (r < 0)
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering return r;
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering r = sd_rtnl_message_append(ipv6, IFA_LOCAL, &in6addr_loopback);
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering if (r < 0)
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering return r;
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering r = sd_rtnl_call_async(rtnl, ipv6, &pipe_handler, counter, 0, NULL);
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering if (r < 0)
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering return r;
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering
08bcebf36eb85f5e75b968de8c648e6614cc534bLennart Poettering (*counter) ++;
return 0;
}
static int start_interface(sd_rtnl *rtnl, int if_loopback, uint32_t ipv4_address, int *counter) {
_cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
int r;
r = sd_rtnl_message_link_new(RTM_NEWLINK, if_loopback, &req);
if (r < 0)
return r;
r = sd_rtnl_message_link_set_flags(req, IFF_UP);
if (r < 0)
return r;
r = sd_rtnl_message_append(req, IFA_LOCAL, &ipv4_address);
if (r < 0)
return r;
r = sd_rtnl_call_async(rtnl, req, &pipe_handler, counter, 0, NULL);
if (r < 0)
return r;
(*counter) ++;
return 0;
}
static int check_loopback(void) {
int r;
_cleanup_close_ int fd = -1;
union {
struct sockaddr sa;
struct sockaddr_in in;
} sa = {
.in.sin_family = AF_INET,
.in.sin_addr.s_addr = INADDR_LOOPBACK,
};
/* If we failed to set up the loop back device, check whether
* it might already be set up */
fd = socket(AF_INET, SOCK_DGRAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0);
if (fd < 0)
return -errno;
if (bind(fd, &sa.sa, sizeof(sa.in)) >= 0)
r = 1;
else
r = errno == EADDRNOTAVAIL ? 0 : -errno;
return r;
}
int loopback_setup(void) {
_cleanup_sd_rtnl_unref_ sd_rtnl *rtnl = NULL;
int r, if_loopback, counter = 0;
bool eperm = false;
uint32_t ipv4_address = htonl(INADDR_LOOPBACK);
errno = 0;
if_loopback = (int) if_nametoindex("lo");
if (if_loopback <= 0)
return errno ? -errno : -ENODEV;
r = sd_rtnl_open(0, &rtnl);
if (r < 0)
return r;
r = add_adresses(rtnl, if_loopback, ipv4_address, &counter);
if (r < 0)
return r;
r = start_interface(rtnl, if_loopback, ipv4_address, &counter);
if (r < 0)
return r;
while (counter > 0) {
r = sd_rtnl_wait(rtnl, 0);
if (r < 0)
return r;
r = sd_rtnl_process(rtnl, 0);
if (r < 0) {
if (r == -EPERM)
eperm = true;
else {
log_warning("Failed to configure loopback device: %s", strerror(-r));
return r;
}
}
}
if (eperm && check_loopback() < 0) {
log_warning("Failed to configure loopback device: %s", strerror(EPERM));
return -EPERM;
}
return 0;
}