]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/loopback-setup.c
rtnl: replace message_append by typesafe versions
[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>
81eca919 27#include <linux/rtnetlink.h>
af5bc85d
LP
28#include <string.h>
29#include <stdlib.h>
30#include <unistd.h>
af5bc85d
LP
31
32#include "util.h"
33#include "macro.h"
34#include "loopback-setup.h"
5bfcc1c6 35#include "socket-util.h"
81eca919
TG
36#include "sd-rtnl.h"
37#include "rtnl-util.h"
af5bc85d 38
81eca919
TG
39static int pipe_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
40 int *counter = userdata;
41 int r;
af5bc85d 42
81eca919 43 (*counter) --;
af5bc85d 44
81eca919 45 r = sd_rtnl_message_get_errno(m);
af5bc85d 46
81eca919 47 return r == -EEXIST ? 0 : r;
af5bc85d
LP
48}
49
0a0dc69b 50static int add_addresses(sd_rtnl *rtnl, int if_loopback, struct in_addr *ipv4_address, int *counter) {
81eca919 51 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *ipv4 = NULL, *ipv6 = NULL;
af5bc85d
LP
52 int r;
53
81eca919
TG
54 r = sd_rtnl_message_addr_new(RTM_NEWADDR, if_loopback, AF_INET, 8, IFA_F_PERMANENT, RT_SCOPE_HOST, &ipv4);
55 if (r < 0)
56 return r;
af5bc85d 57
0a0dc69b 58 r = sd_rtnl_message_append_in_addr(ipv4, IFA_LOCAL, ipv4_address);
2c3ff76e 59 if (r < 0)
af5bc85d
LP
60 return r;
61
81eca919
TG
62 r = sd_rtnl_call_async(rtnl, ipv4, &pipe_handler, counter, 0, NULL);
63 if (r < 0)
64 return r;
65
66 (*counter) ++;
5bfcc1c6
FF
67
68 if (!socket_ipv6_is_supported())
69 return 0;
af5bc85d 70
81eca919
TG
71 r = sd_rtnl_message_addr_new(RTM_NEWADDR, if_loopback, AF_INET6, 128, 0, 0, &ipv6);
72 if (r < 0)
73 return r;
af5bc85d 74
0a0dc69b 75 r = sd_rtnl_message_append_in6_addr(ipv6, IFA_LOCAL, &in6addr_loopback);
81eca919
TG
76 if (r < 0)
77 return r;
af5bc85d 78
81eca919 79 r = sd_rtnl_call_async(rtnl, ipv6, &pipe_handler, counter, 0, NULL);
2c3ff76e 80 if (r < 0)
af5bc85d
LP
81 return r;
82
81eca919 83 (*counter) ++;
af5bc85d
LP
84
85 return 0;
86}
87
0a0dc69b 88static int start_interface(sd_rtnl *rtnl, int if_loopback, struct in_addr *ipv4_address, int *counter) {
81eca919
TG
89 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
90 int r;
af5bc85d 91
fc25d7f8
TG
92 r = sd_rtnl_message_link_new(RTM_NEWLINK, if_loopback, &req);
93 if (r < 0)
94 return r;
95
96 r = sd_rtnl_message_link_set_flags(req, IFF_UP);
81eca919
TG
97 if (r < 0)
98 return r;
af5bc85d 99
0a0dc69b 100 r = sd_rtnl_message_append_in_addr(req, IFA_LOCAL, ipv4_address);
81eca919
TG
101 if (r < 0)
102 return r;
af5bc85d 103
81eca919
TG
104 r = sd_rtnl_call_async(rtnl, req, &pipe_handler, counter, 0, NULL);
105 if (r < 0)
106 return r;
af5bc85d 107
81eca919 108 (*counter) ++;
5bfcc1c6 109
af5bc85d
LP
110 return 0;
111}
112
2c3ff76e 113static int check_loopback(void) {
e62d8c39 114 int r;
81eca919 115 _cleanup_close_ int fd = -1;
2c3ff76e
LP
116 union {
117 struct sockaddr sa;
118 struct sockaddr_in in;
b92bea5d
ZJS
119 } sa = {
120 .in.sin_family = AF_INET,
121 .in.sin_addr.s_addr = INADDR_LOOPBACK,
122 };
2c3ff76e
LP
123
124 /* If we failed to set up the loop back device, check whether
125 * it might already be set up */
126
127 fd = socket(AF_INET, SOCK_DGRAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0);
128 if (fd < 0)
129 return -errno;
130
2c3ff76e
LP
131 if (bind(fd, &sa.sa, sizeof(sa.in)) >= 0)
132 r = 1;
133 else
134 r = errno == EADDRNOTAVAIL ? 0 : -errno;
135
2c3ff76e
LP
136 return r;
137}
138
af5bc85d 139int loopback_setup(void) {
81eca919
TG
140 _cleanup_sd_rtnl_unref_ sd_rtnl *rtnl = NULL;
141 int r, if_loopback, counter = 0;
2c3ff76e 142 bool eperm = false;
0a0dc69b 143 struct in_addr ipv4_address;
af5bc85d
LP
144
145 errno = 0;
2c3ff76e
LP
146 if_loopback = (int) if_nametoindex("lo");
147 if (if_loopback <= 0)
af5bc85d
LP
148 return errno ? -errno : -ENODEV;
149
0a0dc69b
TG
150 ipv4_address.s_addr = htonl(INADDR_LOOPBACK);
151
81eca919 152 r = sd_rtnl_open(0, &rtnl);
2c3ff76e 153 if (r < 0)
81eca919 154 return r;
af5bc85d 155
0a0dc69b 156 r = add_addresses(rtnl, if_loopback, &ipv4_address, &counter);
2c3ff76e 157 if (r < 0)
81eca919 158 return r;
af5bc85d 159
0a0dc69b 160 r = start_interface(rtnl, if_loopback, &ipv4_address, &counter);
81eca919
TG
161 if (r < 0)
162 return r;
2c3ff76e 163
81eca919
TG
164 while (counter > 0) {
165 r = sd_rtnl_wait(rtnl, 0);
166 if (r < 0)
167 return r;
168
169 r = sd_rtnl_process(rtnl, 0);
170 if (r < 0) {
171 if (r == -EPERM)
172 eperm = true;
173 else {
174 log_warning("Failed to configure loopback device: %s", strerror(-r));
175 return r;
176 }
177 }
5bfcc1c6 178 }
af5bc85d 179
2c3ff76e 180 if (eperm && check_loopback() < 0) {
81eca919
TG
181 log_warning("Failed to configure loopback device: %s", strerror(EPERM));
182 return -EPERM;
2c3ff76e
LP
183 }
184
e62d8c39 185 return 0;
af5bc85d 186}