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