]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/loopback-setup.c
socket: properly handle if our service vanished during runtime
[thirdparty/systemd.git] / src / core / loopback-setup.c
CommitLineData
d6c9574f 1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
af5bc85d
LP
2
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
af5bc85d
LP
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 16 Lesser General Public License for more details.
af5bc85d 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
af5bc85d
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <errno.h>
23#include <sys/socket.h>
24#include <net/if.h>
25#include <asm/types.h>
26#include <netinet/in.h>
27#include <string.h>
28#include <stdlib.h>
29#include <unistd.h>
af5bc85d
LP
30
31#include "util.h"
32#include "macro.h"
33#include "loopback-setup.h"
5bfcc1c6 34#include "socket-util.h"
81eca919
TG
35#include "sd-rtnl.h"
36#include "rtnl-util.h"
af5bc85d 37
81eca919
TG
38static int pipe_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
39 int *counter = userdata;
40 int r;
af5bc85d 41
81eca919 42 (*counter) --;
af5bc85d 43
81eca919 44 r = sd_rtnl_message_get_errno(m);
af5bc85d 45
81eca919 46 return r == -EEXIST ? 0 : r;
af5bc85d
LP
47}
48
0a0dc69b 49static int add_addresses(sd_rtnl *rtnl, int if_loopback, struct in_addr *ipv4_address, int *counter) {
cf6a8911 50 _cleanup_rtnl_message_unref_ sd_rtnl_message *ipv4 = NULL, *ipv6 = NULL;
af5bc85d
LP
51 int r;
52
151b9b96 53 r = sd_rtnl_message_new_addr(rtnl, &ipv4, RTM_NEWADDR, if_loopback, AF_INET);
5a723174
TG
54 if (r < 0)
55 return r;
56
57 r = sd_rtnl_message_addr_set_prefixlen(ipv4, 8);
58 if (r < 0)
59 return r;
60
61 r = sd_rtnl_message_addr_set_flags(ipv4, IFA_F_PERMANENT);
62 if (r < 0)
63 return r;
64
65 r = sd_rtnl_message_addr_set_scope(ipv4, RT_SCOPE_HOST);
81eca919
TG
66 if (r < 0)
67 return r;
af5bc85d 68
0a0dc69b 69 r = sd_rtnl_message_append_in_addr(ipv4, IFA_LOCAL, ipv4_address);
2c3ff76e 70 if (r < 0)
af5bc85d
LP
71 return r;
72
81eca919
TG
73 r = sd_rtnl_call_async(rtnl, ipv4, &pipe_handler, counter, 0, NULL);
74 if (r < 0)
75 return r;
76
77 (*counter) ++;
5bfcc1c6
FF
78
79 if (!socket_ipv6_is_supported())
80 return 0;
af5bc85d 81
151b9b96 82 r = sd_rtnl_message_new_addr(rtnl, &ipv6, RTM_NEWADDR, if_loopback, AF_INET6);
5a723174
TG
83 if (r < 0)
84 return r;
85
86 r = sd_rtnl_message_addr_set_prefixlen(ipv6, 128);
87 if (r < 0)
88 return r;
89
90 r = sd_rtnl_message_addr_set_flags(ipv6, IFA_F_PERMANENT);
91 if (r < 0)
92 return r;
93
94 r = sd_rtnl_message_addr_set_scope(ipv6, RT_SCOPE_HOST);
81eca919
TG
95 if (r < 0)
96 return r;
af5bc85d 97
0a0dc69b 98 r = sd_rtnl_message_append_in6_addr(ipv6, IFA_LOCAL, &in6addr_loopback);
81eca919
TG
99 if (r < 0)
100 return r;
af5bc85d 101
81eca919 102 r = sd_rtnl_call_async(rtnl, ipv6, &pipe_handler, counter, 0, NULL);
2c3ff76e 103 if (r < 0)
af5bc85d
LP
104 return r;
105
81eca919 106 (*counter) ++;
af5bc85d
LP
107
108 return 0;
109}
110
0a0dc69b 111static int start_interface(sd_rtnl *rtnl, int if_loopback, struct in_addr *ipv4_address, int *counter) {
cf6a8911 112 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
81eca919 113 int r;
af5bc85d 114
151b9b96 115 r = sd_rtnl_message_new_link(rtnl, &req, RTM_SETLINK, if_loopback);
fc25d7f8
TG
116 if (r < 0)
117 return r;
118
5d4795f3 119 r = sd_rtnl_message_link_set_flags(req, IFF_UP, IFF_UP);
81eca919
TG
120 if (r < 0)
121 return r;
af5bc85d 122
81eca919
TG
123 r = sd_rtnl_call_async(rtnl, req, &pipe_handler, counter, 0, NULL);
124 if (r < 0)
125 return r;
af5bc85d 126
81eca919 127 (*counter) ++;
5bfcc1c6 128
af5bc85d
LP
129 return 0;
130}
131
2c3ff76e 132static int check_loopback(void) {
e62d8c39 133 int r;
81eca919 134 _cleanup_close_ int fd = -1;
2c3ff76e
LP
135 union {
136 struct sockaddr sa;
137 struct sockaddr_in in;
b92bea5d
ZJS
138 } sa = {
139 .in.sin_family = AF_INET,
140 .in.sin_addr.s_addr = INADDR_LOOPBACK,
141 };
2c3ff76e
LP
142
143 /* If we failed to set up the loop back device, check whether
144 * it might already be set up */
145
146 fd = socket(AF_INET, SOCK_DGRAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0);
147 if (fd < 0)
148 return -errno;
149
2c3ff76e
LP
150 if (bind(fd, &sa.sa, sizeof(sa.in)) >= 0)
151 r = 1;
152 else
153 r = errno == EADDRNOTAVAIL ? 0 : -errno;
154
2c3ff76e
LP
155 return r;
156}
157
af5bc85d 158int loopback_setup(void) {
cf6a8911 159 _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
81eca919 160 int r, if_loopback, counter = 0;
2c3ff76e 161 bool eperm = false;
0a0dc69b 162 struct in_addr ipv4_address;
af5bc85d
LP
163
164 errno = 0;
2c3ff76e
LP
165 if_loopback = (int) if_nametoindex("lo");
166 if (if_loopback <= 0)
af5bc85d
LP
167 return errno ? -errno : -ENODEV;
168
0a0dc69b
TG
169 ipv4_address.s_addr = htonl(INADDR_LOOPBACK);
170
151b9b96 171 r = sd_rtnl_open(&rtnl, 0);
2c3ff76e 172 if (r < 0)
81eca919 173 return r;
af5bc85d 174
0a0dc69b 175 r = add_addresses(rtnl, if_loopback, &ipv4_address, &counter);
2c3ff76e 176 if (r < 0)
81eca919 177 return r;
af5bc85d 178
0a0dc69b 179 r = start_interface(rtnl, if_loopback, &ipv4_address, &counter);
81eca919
TG
180 if (r < 0)
181 return r;
2c3ff76e 182
81eca919
TG
183 while (counter > 0) {
184 r = sd_rtnl_wait(rtnl, 0);
185 if (r < 0)
186 return r;
187
188 r = sd_rtnl_process(rtnl, 0);
189 if (r < 0) {
190 if (r == -EPERM)
191 eperm = true;
192 else {
193 log_warning("Failed to configure loopback device: %s", strerror(-r));
194 return r;
195 }
196 }
5bfcc1c6 197 }
af5bc85d 198
2c3ff76e 199 if (eperm && check_loopback() < 0) {
81eca919
TG
200 log_warning("Failed to configure loopback device: %s", strerror(EPERM));
201 return -EPERM;
2c3ff76e
LP
202 }
203
e62d8c39 204 return 0;
af5bc85d 205}