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