chiark / gitweb /
Remove duplicate includes
[elogind.git] / src / nss-myhostname / netlink.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2008-2011 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
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
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
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <sys/socket.h>
23 #include <sys/un.h>
24 #include <asm/types.h>
25 #include <inttypes.h>
26 #include <linux/netlink.h>
27 #include <linux/rtnetlink.h>
28 #include <string.h>
29 #include <assert.h>
30 #include <errno.h>
31 #include <limits.h>
32 #include <arpa/inet.h>
33 #include <unistd.h>
34 #include <stdlib.h>
35
36 #include "ifconf.h"
37
38 #define SEQ 4711
39
40 static int read_reply(int fd, struct address **list, unsigned *n_list) {
41         ssize_t bytes;
42         struct cmsghdr *cmsg;
43         struct ucred *ucred;
44         struct nlmsghdr *p;
45         uint8_t cred_buffer[CMSG_SPACE(sizeof(struct ucred))];
46         struct {
47                 struct nlmsghdr hdr;
48                 struct ifaddrmsg ifaddrmsg;
49                 uint8_t payload[16*1024];
50         } resp;
51         struct iovec iov = {
52                 .iov_base = &resp,
53                 .iov_len = sizeof(resp),
54         };
55         struct msghdr msg = {
56                 .msg_name = NULL,
57                 .msg_namelen = 0,
58                 .msg_iov = &iov,
59                 .msg_iovlen = 1,
60                 .msg_control = cred_buffer,
61                 .msg_controllen = sizeof(cred_buffer),
62                 .msg_flags = 0,
63         };
64
65         assert(fd >= 0);
66         assert(list);
67
68         bytes = recvmsg(fd, &msg, 0);
69         if (bytes < 0)
70                 return -errno;
71
72         cmsg = CMSG_FIRSTHDR(&msg);
73         if (!cmsg || cmsg->cmsg_type != SCM_CREDENTIALS)
74                 return -EIO;
75
76         ucred = (struct ucred*) CMSG_DATA(cmsg);
77         if (ucred->uid != 0 || ucred->pid != 0)
78                 return 0;
79
80         for (p = &resp.hdr; bytes > 0; p = NLMSG_NEXT(p, bytes)) {
81                 struct ifaddrmsg *ifaddrmsg;
82                 struct rtattr *a;
83                 size_t l;
84                 void *local = NULL, *address = NULL;
85
86                 if (!NLMSG_OK(p, (size_t) bytes))
87                         return -EIO;
88
89                 if (p->nlmsg_seq != SEQ)
90                         continue;
91
92                 if (p->nlmsg_type == NLMSG_DONE)
93                         return 1;
94
95                 if (p->nlmsg_type == NLMSG_ERROR) {
96                         struct nlmsgerr *nlmsgerr;
97
98                         nlmsgerr = NLMSG_DATA(p);
99                         return -nlmsgerr->error;
100                 }
101
102                 if (p->nlmsg_type != RTM_NEWADDR)
103                         continue;
104
105                 ifaddrmsg = NLMSG_DATA(p);
106
107                 if (ifaddrmsg->ifa_family != AF_INET &&
108                     ifaddrmsg->ifa_family != AF_INET6)
109                         continue;
110
111                 if (ifaddrmsg->ifa_scope == RT_SCOPE_HOST ||
112                     ifaddrmsg->ifa_scope == RT_SCOPE_NOWHERE)
113                         continue;
114
115                 if (ifaddrmsg->ifa_flags & IFA_F_DEPRECATED)
116                         continue;
117
118                 l = NLMSG_PAYLOAD(p, sizeof(struct ifaddrmsg));
119                 a = IFA_RTA(ifaddrmsg);
120
121                 while (RTA_OK(a, l)) {
122
123                         if (a->rta_type == IFA_ADDRESS)
124                                 address = RTA_DATA(a);
125                         else if (a->rta_type == IFA_LOCAL)
126                                 local = RTA_DATA(a);
127
128                         a = RTA_NEXT(a, l);
129                 }
130
131                 if (local)
132                         address = local;
133
134                 if (!address)
135                         continue;
136
137                 *list = realloc(*list, (*n_list+1) * sizeof(struct address));
138                 if (!*list)
139                         return -ENOMEM;
140
141                 (*list)[*n_list].family = ifaddrmsg->ifa_family;
142                 (*list)[*n_list].scope = ifaddrmsg->ifa_scope;
143                 memcpy((*list)[*n_list].address,
144                        address, ifaddrmsg->ifa_family == AF_INET ? 4 : 16);
145                 (*list)[*n_list].ifindex = ifaddrmsg->ifa_index;
146
147                 (*n_list)++;
148         }
149
150         return 0;
151 }
152
153
154 int ifconf_acquire_addresses(struct address **_list, unsigned *_n_list) {
155
156         struct {
157                 struct nlmsghdr hdr;
158                 struct rtgenmsg gen;
159         } req = { {
160                         .nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
161                         .nlmsg_type = RTM_GETADDR,
162                         .nlmsg_flags = NLM_F_REQUEST|NLM_F_DUMP|NLM_F_ACK,
163                         .nlmsg_seq = SEQ,
164                         .nlmsg_pid = 0,
165                 }, {
166                         .rtgen_family = AF_UNSPEC,
167                 }
168         };
169         int r, on = 1;
170         struct address *list = NULL;
171         unsigned n_list = 0;
172         int fd;
173
174         fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
175         if (fd < 0)
176                 return -errno;
177
178         if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
179                 r = -errno;
180                 goto finish;
181         }
182
183         if (send(fd, &req, req.hdr.nlmsg_len, 0) < 0) {
184                 r = -errno;
185                 goto finish;
186         }
187
188         while((r = read_reply(fd, &list, &n_list)) == 0)
189                 ;
190
191 finish:
192         close(fd);
193
194         if (r < 0) {
195                 free(list);
196                 return r;
197         }
198
199         if (n_list)
200                 qsort(list, n_list, sizeof(struct address), address_compare);
201
202         *_list = list;
203         *_n_list = n_list;
204
205         return 0;
206 }