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