]>
git.ipfire.org Git - people/ms/systemd.git/blob - loopback-setup.c
1 /*-*- Mode: C; c-basic-offset: 8 -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
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
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
23 #include <sys/socket.h>
25 #include <asm/types.h>
26 #include <netinet/in.h>
30 #include <linux/netlink.h>
31 #include <linux/rtnetlink.h>
35 #include "loopback-setup.h"
39 REQUEST_ADDRESS_IPV4
= 1,
40 REQUEST_ADDRESS_IPV6
= 2,
45 #define NLMSG_TAIL(nmsg) \
46 ((struct rtattr *) (((uint8_t*) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
48 static int add_rtattr(struct nlmsghdr
*n
, size_t max_length
, int type
, const void *data
, size_t data_length
) {
52 length
= RTA_LENGTH(data_length
);
54 if (NLMSG_ALIGN(n
->nlmsg_len
) + RTA_ALIGN(length
) > max_length
)
59 rta
->rta_len
= length
;
60 memcpy(RTA_DATA(rta
), data
, data_length
);
61 n
->nlmsg_len
= NLMSG_ALIGN(n
->nlmsg_len
) + RTA_ALIGN(length
);
66 static ssize_t
sendto_loop(int fd
, const void *buf
, size_t buf_len
, int flags
, const struct sockaddr
*sa
, socklen_t sa_len
) {
71 if ((l
= sendto(fd
, buf
, buf_len
, flags
, sa
, sa_len
)) >= 0)
79 static ssize_t
recvfrom_loop(int fd
, void *buf
, size_t buf_len
, int flags
, struct sockaddr
*sa
, socklen_t
*sa_len
) {
84 if ((l
= recvfrom(fd
, buf
, buf_len
, flags
, sa
, sa_len
)) >= 0)
92 static int add_adresses(int fd
, int if_loopback
) {
95 struct sockaddr_nl nl
;
98 struct nlmsghdr header
;
99 uint8_t buf
[NLMSG_ALIGN(sizeof(struct nlmsghdr
)) +
100 NLMSG_ALIGN(sizeof(struct ifaddrmsg
)) +
101 RTA_LENGTH(sizeof(struct in6_addr
))];
104 struct ifaddrmsg
*ifaddrmsg
;
105 uint32_t ipv4_address
= htonl(INADDR_LOOPBACK
);
110 request
.header
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct ifaddrmsg
));
111 request
.header
.nlmsg_type
= RTM_NEWADDR
;
112 request
.header
.nlmsg_flags
= NLM_F_REQUEST
|NLM_F_CREATE
|NLM_F_ACK
;
113 request
.header
.nlmsg_seq
= REQUEST_ADDRESS_IPV4
;
115 ifaddrmsg
= NLMSG_DATA(&request
.header
);
116 ifaddrmsg
->ifa_family
= AF_INET
;
117 ifaddrmsg
->ifa_prefixlen
= 8;
118 ifaddrmsg
->ifa_flags
= IFA_F_PERMANENT
;
119 ifaddrmsg
->ifa_scope
= RT_SCOPE_HOST
;
120 ifaddrmsg
->ifa_index
= if_loopback
;
122 if ((r
= add_rtattr(&request
.header
, sizeof(request
), IFA_LOCAL
, &ipv4_address
, sizeof(ipv4_address
))) < 0)
126 sa
.nl
.nl_family
= AF_NETLINK
;
128 if (sendto_loop(fd
, &request
, request
.header
.nlmsg_len
, 0, &sa
.sa
, sizeof(sa
)) < 0)
131 request
.header
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct ifaddrmsg
));
132 request
.header
.nlmsg_seq
= REQUEST_ADDRESS_IPV6
;
134 ifaddrmsg
->ifa_family
= AF_INET6
;
135 ifaddrmsg
->ifa_prefixlen
= 128;
137 if ((r
= add_rtattr(&request
.header
, sizeof(request
), IFA_LOCAL
, &in6addr_loopback
, sizeof(in6addr_loopback
))) < 0)
140 if (sendto_loop(fd
, &request
, request
.header
.nlmsg_len
, 0, &sa
.sa
, sizeof(sa
)) < 0)
146 static int start_interface(int fd
, int if_loopback
) {
149 struct sockaddr_nl nl
;
152 struct nlmsghdr header
;
153 uint8_t buf
[NLMSG_ALIGN(sizeof(struct nlmsghdr
)) +
154 NLMSG_ALIGN(sizeof(struct ifinfomsg
))];
157 struct ifinfomsg
*ifinfomsg
;
161 request
.header
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct ifinfomsg
));
162 request
.header
.nlmsg_type
= RTM_NEWLINK
;
163 request
.header
.nlmsg_flags
= NLM_F_REQUEST
|NLM_F_ACK
;
164 request
.header
.nlmsg_seq
= REQUEST_FLAGS
;
166 ifinfomsg
= NLMSG_DATA(&request
.header
);
167 ifinfomsg
->ifi_family
= AF_UNSPEC
;
168 ifinfomsg
->ifi_index
= if_loopback
;
169 ifinfomsg
->ifi_flags
= IFF_UP
;
170 ifinfomsg
->ifi_change
= IFF_UP
;
173 sa
.nl
.nl_family
= AF_NETLINK
;
175 if (sendto_loop(fd
, &request
, request
.header
.nlmsg_len
, 0, &sa
.sa
, sizeof(sa
)) < 0)
181 static int read_response(int fd
) {
184 struct sockaddr_nl nl
;
187 struct nlmsghdr header
;
188 uint8_t buf
[NLMSG_ALIGN(sizeof(struct nlmsghdr
)) +
189 NLMSG_ALIGN(sizeof(struct nlmsgerr
))];
193 socklen_t sa_len
= sizeof(sa
);
194 struct nlmsgerr
*nlmsgerr
;
196 if ((l
= recvfrom_loop(fd
, &response
, sizeof(response
), 0, &sa
.sa
, &sa_len
)) < 0)
199 if (sa_len
!= sizeof(sa
.nl
) ||
200 sa
.nl
.nl_family
!= AF_NETLINK
)
203 if (sa
.nl
.nl_pid
!= 0)
206 if ((size_t) l
< sizeof(struct nlmsghdr
))
209 if (response
.header
.nlmsg_type
!= NLMSG_ERROR
||
210 (pid_t
) response
.header
.nlmsg_pid
!= getpid() ||
211 response
.header
.nlmsg_seq
>= REQUEST_ALL
)
214 if ((size_t) l
< NLMSG_LENGTH(sizeof(struct nlmsgerr
)) ||
215 response
.header
.nlmsg_len
< NLMSG_LENGTH(sizeof(struct nlmsgerr
)))
218 nlmsgerr
= NLMSG_DATA(&response
.header
);
220 if (nlmsgerr
->error
< 0 && nlmsgerr
->error
!= -EEXIST
)
221 return nlmsgerr
->error
;
223 return response
.header
.nlmsg_seq
;
226 int loopback_setup(void) {
230 struct sockaddr_nl nl
;
231 struct sockaddr_storage storage
;
233 int requests
= REQUEST_NONE
;
238 if ((if_loopback
= (int) if_nametoindex("lo")) <= 0)
239 return errno
? -errno
: -ENODEV
;
241 if ((fd
= socket(PF_NETLINK
, SOCK_RAW
, NETLINK_ROUTE
)) < 0)
245 sa
.nl
.nl_family
= AF_NETLINK
;
247 if (bind(fd
, &sa
.sa
, sizeof(sa
)) < 0) {
252 if ((r
= add_adresses(fd
, if_loopback
)) < 0)
255 if ((r
= start_interface(fd
, if_loopback
)) < 0)
259 if ((r
= read_response(fd
)) < 0)
264 } while (requests
!= REQUEST_ALL
);
270 log_error("Failed to configure loopback device: %s", strerror(-r
));
273 close_nointr_nofail(fd
);