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