chiark / gitweb /
06c50b593ee3652e8818b561264c3aabe74fe38c
[elogind.git] / src / shared / net-util.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4  This file is part of systemd.
5
6  Copyright (C) 2013 Tom Gundersen <teg@jklm.no>
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 <netinet/ether.h>
23 #include <linux/if.h>
24 #include <arpa/inet.h>
25
26 #include "net-util.h"
27 #include "log.h"
28 #include "utf8.h"
29 #include "util.h"
30 #include "conf-parser.h"
31 #include "condition.h"
32
33 bool net_match_config(const struct ether_addr *match_mac,
34                       const char *match_path,
35                       const char *match_driver,
36                       const char *match_type,
37                       const char *match_name,
38                       Condition *match_host,
39                       Condition *match_virt,
40                       Condition *match_kernel,
41                       const char *dev_mac,
42                       const char *dev_path,
43                       const char *dev_driver,
44                       const char *dev_type,
45                       const char *dev_name) {
46
47         if (match_host && !condition_test_host(match_host))
48                 return 0;
49
50         if (match_virt && !condition_test_virtualization(match_virt))
51                 return 0;
52
53         if (match_kernel && !condition_test_kernel_command_line(match_kernel))
54                 return 0;
55
56         if (match_mac && (!dev_mac || memcmp(match_mac, ether_aton(dev_mac), ETH_ALEN)))
57                 return 0;
58
59         if (match_path && !streq_ptr(match_path, dev_path))
60                 return 0;
61
62         if (match_driver && !streq_ptr(match_driver, dev_driver))
63                 return 0;
64
65         if (match_type && !streq_ptr(match_type, dev_type))
66                 return 0;
67
68         if (match_name && !streq_ptr(match_name, dev_name))
69                 return 0;
70
71         return 1;
72 }
73
74 unsigned net_netmask_to_prefixlen(const struct in_addr *addr) {
75         assert(addr);
76
77         return 32 - u32ctz(be32toh(addr->s_addr));
78 }
79
80 int config_parse_net_condition(const char *unit,
81                                const char *filename,
82                                unsigned line,
83                                const char *section,
84                                unsigned section_line,
85                                const char *lvalue,
86                                int ltype,
87                                const char *rvalue,
88                                void *data,
89                                void *userdata) {
90
91         ConditionType cond = ltype;
92         Condition **ret = data;
93         bool negate;
94         Condition *c;
95         _cleanup_free_ char *s = NULL;
96
97         assert(filename);
98         assert(lvalue);
99         assert(rvalue);
100         assert(data);
101
102         negate = rvalue[0] == '!';
103         if (negate)
104                 rvalue++;
105
106         s = strdup(rvalue);
107         if (!s)
108                 return log_oom();
109
110         c = condition_new(cond, s, false, negate);
111         if (!c)
112                 return log_oom();
113
114         if (*ret)
115                 condition_free(*ret);
116
117         *ret = c;
118         return 0;
119 }
120
121 int config_parse_ifname(const char *unit,
122                         const char *filename,
123                         unsigned line,
124                         const char *section,
125                         unsigned section_line,
126                         const char *lvalue,
127                         int ltype,
128                         const char *rvalue,
129                         void *data,
130                         void *userdata) {
131
132         char **s = data;
133         char *n;
134
135         assert(filename);
136         assert(lvalue);
137         assert(rvalue);
138         assert(data);
139
140         n = strdup(rvalue);
141         if (!n)
142                 return log_oom();
143
144         if (!ascii_is_valid(n) || strlen(n) >= IFNAMSIZ) {
145                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
146                            "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
147                 free(n);
148                 return 0;
149         }
150
151         free(*s);
152         if (*n)
153                 *s = n;
154         else {
155                 free(n);
156                 *s = NULL;
157         }
158
159         return 0;
160 }
161
162 int config_parse_ifalias(const char *unit,
163                          const char *filename,
164                          unsigned line,
165                          const char *section,
166                          unsigned section_line,
167                          const char *lvalue,
168                          int ltype,
169                          const char *rvalue,
170                          void *data,
171                          void *userdata) {
172
173         char **s = data;
174         char *n;
175
176         assert(filename);
177         assert(lvalue);
178         assert(rvalue);
179         assert(data);
180
181         n = strdup(rvalue);
182         if (!n)
183                 return log_oom();
184
185         if (!ascii_is_valid(n) || strlen(n) >= IFALIASZ) {
186                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
187                            "Interface alias is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
188                 free(n);
189                 return 0;
190         }
191
192         free(*s);
193         if (*n)
194                 *s = n;
195         else {
196                 free(n);
197                 *s = NULL;
198         }
199
200         return 0;
201 }
202
203 int config_parse_hwaddr(const char *unit,
204                         const char *filename,
205                         unsigned line,
206                         const char *section,
207                         unsigned section_line,
208                         const char *lvalue,
209                         int ltype,
210                         const char *rvalue,
211                         void *data,
212                         void *userdata) {
213         struct ether_addr **hwaddr = data;
214         struct ether_addr *n;
215         int r;
216
217         assert(filename);
218         assert(lvalue);
219         assert(rvalue);
220         assert(data);
221
222         n = new0(struct ether_addr, 1);
223         if (!n)
224                 return log_oom();
225
226         r = sscanf(rvalue, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
227                    &n->ether_addr_octet[0],
228                    &n->ether_addr_octet[1],
229                    &n->ether_addr_octet[2],
230                    &n->ether_addr_octet[3],
231                    &n->ether_addr_octet[4],
232                    &n->ether_addr_octet[5]);
233         if (r != 6) {
234                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
235                            "Not a valid MAC address, ignoring assignment: %s", rvalue);
236                 free(n);
237                 return 0;
238         }
239
240         free(*hwaddr);
241         *hwaddr = n;
242
243         return 0;
244 }
245
246 int net_parse_inaddr(const char *address, unsigned char *family, void *dst) {
247         int r;
248
249         assert(address);
250         assert(family);
251         assert(dst);
252
253         /* IPv4 */
254         r = inet_pton(AF_INET, address, dst);
255         if (r > 0) {
256                 /* succsefully parsed IPv4 address */
257                 if (*family == AF_UNSPEC)
258                         *family = AF_INET;
259                 else if (*family != AF_INET)
260                         return -EINVAL;
261         } else  if (r < 0)
262                 return -errno;
263         else {
264                 /* not an IPv4 address, so let's try IPv6 */
265                 r = inet_pton(AF_INET6, address, dst);
266                 if (r > 0) {
267                         /* successfully parsed IPv6 address */
268                         if (*family == AF_UNSPEC)
269                                 *family = AF_INET6;
270                         else if (*family != AF_INET6)
271                                 return -EINVAL;
272                 } else if (r < 0)
273                         return -errno;
274                 else
275                         return -EINVAL;
276         }
277
278         return 0;
279 }