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