chiark / gitweb /
resolved: when there's already somebody listening on the LLMNR ports, simple disable...
[elogind.git] / src / network / sd-network.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2011 Lennart Poettering
7   Copyright 2014 Tom Gundersen
8
9   systemd is free software; you can redistribute it and/or modify it
10   under the terms of the GNU Lesser General Public License as published by
11   the Free Software Foundation; either version 2.1 of the License, or
12   (at your option) any later version.
13
14   systemd is distributed in the hope that it will be useful, but
15   WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17   Lesser General Public License for more details.
18
19   You should have received a copy of the GNU Lesser General Public License
20   along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 ***/
22
23 #include <unistd.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <sys/inotify.h>
27 #include <sys/poll.h>
28 #include <net/if.h>
29
30 #include "util.h"
31 #include "macro.h"
32 #include "strv.h"
33 #include "fileio.h"
34 #include "sd-network.h"
35 #include "network-internal.h"
36 #include "dhcp-lease-internal.h"
37
38 _public_ int sd_network_get_link_state(int ifindex, char **state) {
39         _cleanup_free_ char *s = NULL, *p = NULL;
40         int r;
41
42         assert_return(ifindex > 0, -EINVAL);
43         assert_return(state, -EINVAL);
44
45         if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0)
46                 return -ENOMEM;
47
48         r = parse_env_file(p, NEWLINE, "ADMIN_STATE", &s, NULL);
49         if (r == -ENOENT)
50                 return -ENODATA;
51         else if (r < 0)
52                 return r;
53         else if (!s)
54                 return -EIO;
55
56         if (streq(s, "initializing"))
57                 return -EBUSY;
58
59         *state = s;
60         s = NULL;
61
62         return 0;
63 }
64
65 _public_ int sd_network_get_operational_state(char **state) {
66         _cleanup_free_ char *s = NULL;
67         int r;
68
69         assert_return(state, -EINVAL);
70
71         r = parse_env_file("/run/systemd/netif/state", NEWLINE, "OPER_STATE",
72                            &s, NULL);
73         if (r == -ENOENT)
74                 return -ENODATA;
75         else if (r < 0)
76                 return r;
77         else if (!s)
78                 return -EIO;
79
80         *state = s;
81         s = NULL;
82
83         return 0;
84 }
85
86 _public_ int sd_network_get_link_operational_state(int ifindex, char **state) {
87         _cleanup_free_ char *s = NULL, *p = NULL;
88         int r;
89
90         assert_return(ifindex > 0, -EINVAL);
91         assert_return(state, -EINVAL);
92
93         if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0)
94                 return -ENOMEM;
95
96         r = parse_env_file(p, NEWLINE, "OPER_STATE", &s, NULL);
97         if (r == -ENOENT)
98                 return -ENODATA;
99         else if (r < 0)
100                 return r;
101         else if (!s)
102                 return -EIO;
103
104         *state = s;
105         s = NULL;
106
107         return 0;
108 }
109
110 _public_ int sd_network_get_llmnr(int ifindex, char **llmnr) {
111         _cleanup_free_ char *s = NULL, *p = NULL;
112         int r;
113
114         assert_return(ifindex > 0, -EINVAL);
115         assert_return(llmnr, -EINVAL);
116
117         r = parse_env_file(p, NEWLINE, "LLMNR", &s, NULL);
118         if (r == -ENOENT)
119                 return -ENODATA;
120         else if (r < 0)
121                 return r;
122
123         *llmnr = s;
124         s = NULL;
125
126         return 0;
127 }
128
129 _public_ int sd_network_get_dhcp_lease(int ifindex, sd_dhcp_lease **ret) {
130         _cleanup_free_ char *p = NULL, *s = NULL;
131         sd_dhcp_lease *lease = NULL;
132         int r;
133
134         assert_return(ifindex > 0, -EINVAL);
135         assert_return(ret, -EINVAL);
136
137         if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0)
138                 return -ENOMEM;
139
140         r = parse_env_file(p, NEWLINE, "DHCP_LEASE", &s, NULL);
141
142         if (r < 0)
143                 return r;
144         else if (!s)
145                 return -EIO;
146
147         r = dhcp_lease_load(s, &lease);
148         if (r < 0)
149                 return r;
150
151         *ret = lease;
152
153         return 0;
154 }
155
156 static int network_get_strv(const char *key, int ifindex, char ***ret) {
157         _cleanup_free_ char *p = NULL, *s = NULL;
158         _cleanup_strv_free_ char **a = NULL;
159         int r;
160
161         assert_return(ifindex > 0, -EINVAL);
162         assert_return(ret, -EINVAL);
163
164         if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0)
165                 return -ENOMEM;
166
167         r = parse_env_file(p, NEWLINE, key, &s, NULL);
168         if (r < 0)
169                 return r;
170         else if (!s) {
171                 *ret = NULL;
172
173                 return 0;
174         }
175
176         a = strv_split(s, " ");
177         if (!a)
178                 return -ENOMEM;
179
180         strv_uniq(a);
181         r = strv_length(a);
182
183         *ret = a;
184         a = NULL;
185
186         return r;
187 }
188
189 _public_ int sd_network_get_dns(int ifindex, char ***ret) {
190         return network_get_strv("DNS", ifindex, ret);
191 }
192
193 _public_ int sd_network_get_ntp(int ifindex, char ***ret) {
194         return network_get_strv("NTP", ifindex, ret);
195 }
196
197 static inline int MONITOR_TO_FD(sd_network_monitor *m) {
198         return (int) (unsigned long) m - 1;
199 }
200
201 static inline sd_network_monitor* FD_TO_MONITOR(int fd) {
202         return (sd_network_monitor*) (unsigned long) (fd + 1);
203 }
204
205 _public_ int sd_network_monitor_new(sd_network_monitor **m, const char *category) {
206         int fd, k;
207         bool good = false;
208
209         assert_return(m, -EINVAL);
210
211         fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
212         if (fd < 0)
213                 return -errno;
214
215         if (!category || streq(category, "links")) {
216                 k = inotify_add_watch(fd, "/run/systemd/netif/links/", IN_MOVED_TO|IN_DELETE);
217                 if (k < 0) {
218                         safe_close(fd);
219                         return -errno;
220                 }
221
222                 good = true;
223         }
224
225         if (!category || streq(category, "leases")) {
226                 k = inotify_add_watch(fd, "/run/systemd/netif/leases/", IN_MOVED_TO|IN_DELETE);
227                 if (k < 0) {
228                         safe_close(fd);
229                         return -errno;
230                 }
231
232                 good = true;
233         }
234
235         if (!good) {
236                 close_nointr(fd);
237                 return -EINVAL;
238         }
239
240         *m = FD_TO_MONITOR(fd);
241         return 0;
242 }
243
244 _public_ sd_network_monitor* sd_network_monitor_unref(sd_network_monitor *m) {
245         int fd;
246
247         assert_return(m, NULL);
248
249         fd = MONITOR_TO_FD(m);
250         close_nointr(fd);
251
252         return NULL;
253 }
254
255 _public_ int sd_network_monitor_flush(sd_network_monitor *m) {
256
257         assert_return(m, -EINVAL);
258
259         return flush_fd(MONITOR_TO_FD(m));
260 }
261
262 _public_ int sd_network_monitor_get_fd(sd_network_monitor *m) {
263
264         assert_return(m, -EINVAL);
265
266         return MONITOR_TO_FD(m);
267 }
268
269 _public_ int sd_network_monitor_get_events(sd_network_monitor *m) {
270
271         assert_return(m, -EINVAL);
272
273         /* For now we will only return POLLIN here, since we don't
274          * need anything else ever for inotify.  However, let's have
275          * this API to keep our options open should we later on need
276          * it. */
277         return POLLIN;
278 }
279
280 _public_ int sd_network_monitor_get_timeout(sd_network_monitor *m, uint64_t *timeout_usec) {
281
282         assert_return(m, -EINVAL);
283         assert_return(timeout_usec, -EINVAL);
284
285         /* For now we will only return (uint64_t) -1, since we don't
286          * need any timeout. However, let's have this API to keep our
287          * options open should we later on need it. */
288         *timeout_usec = (uint64_t) -1;
289         return 0;
290 }