chiark / gitweb /
sd-dhcp-client/net-util: make netmask_to_prefixlen generic
[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
32 bool net_match_config(const struct ether_addr *match_mac,
33                       const char *match_path,
34                       const char *match_driver,
35                       const char *match_type,
36                       const char *match_name,
37                       const char *dev_mac,
38                       const char *dev_path,
39                       const char *dev_driver,
40                       const char *dev_type,
41                       const char *dev_name) {
42
43         if (match_mac && (!dev_mac || memcmp(match_mac, ether_aton(dev_mac), ETH_ALEN)))
44                 return 0;
45
46         if (match_path && !streq_ptr(match_path, dev_path))
47                 return 0;
48
49         if (match_driver && !streq_ptr(match_driver, dev_driver))
50                 return 0;
51
52         if (match_type && !streq_ptr(match_type, dev_type))
53                 return 0;
54
55         if (match_name && !streq_ptr(match_name, dev_name))
56                 return 0;
57
58         return 1;
59 }
60
61 unsigned net_netmask_to_prefixlen(const struct in_addr *addr) {
62         unsigned len = 0;
63         uint32_t mask;
64
65         assert(addr);
66
67         mask = be32toh(addr->s_addr);
68         while (mask) {
69                 len++;
70                 mask = mask << 1;
71         }
72
73         return len;
74 }
75
76 int config_parse_ifname(const char *unit,
77                         const char *filename,
78                         unsigned line,
79                         const char *section,
80                         unsigned section_line,
81                         const char *lvalue,
82                         int ltype,
83                         const char *rvalue,
84                         void *data,
85                         void *userdata) {
86
87         char **s = data;
88         char *n;
89
90         assert(filename);
91         assert(lvalue);
92         assert(rvalue);
93         assert(data);
94
95         n = strdup(rvalue);
96         if (!n)
97                 return log_oom();
98
99         if (!ascii_is_valid(n) || strlen(n) >= IFNAMSIZ) {
100                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
101                            "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
102                 free(n);
103                 return 0;
104         }
105
106         free(*s);
107         if (*n)
108                 *s = n;
109         else {
110                 free(n);
111                 *s = NULL;
112         }
113
114         return 0;
115 }
116
117 int config_parse_ifalias(const char *unit,
118                          const char *filename,
119                          unsigned line,
120                          const char *section,
121                          unsigned section_line,
122                          const char *lvalue,
123                          int ltype,
124                          const char *rvalue,
125                          void *data,
126                          void *userdata) {
127
128         char **s = data;
129         char *n;
130
131         assert(filename);
132         assert(lvalue);
133         assert(rvalue);
134         assert(data);
135
136         n = strdup(rvalue);
137         if (!n)
138                 return log_oom();
139
140         if (!ascii_is_valid(n) || strlen(n) >= IFALIASZ) {
141                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
142                            "Interface alias is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
143                 free(n);
144                 return 0;
145         }
146
147         free(*s);
148         if (*n)
149                 *s = n;
150         else {
151                 free(n);
152                 *s = NULL;
153         }
154
155         return 0;
156 }
157
158 int config_parse_hwaddr(const char *unit,
159                         const char *filename,
160                         unsigned line,
161                         const char *section,
162                         unsigned section_line,
163                         const char *lvalue,
164                         int ltype,
165                         const char *rvalue,
166                         void *data,
167                         void *userdata) {
168         struct ether_addr **hwaddr = data;
169         struct ether_addr *n;
170         int r;
171
172         assert(filename);
173         assert(lvalue);
174         assert(rvalue);
175         assert(data);
176
177         n = new0(struct ether_addr, 1);
178         if (!n)
179                 return log_oom();
180
181         r = sscanf(rvalue, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
182                    &n->ether_addr_octet[0],
183                    &n->ether_addr_octet[1],
184                    &n->ether_addr_octet[2],
185                    &n->ether_addr_octet[3],
186                    &n->ether_addr_octet[4],
187                    &n->ether_addr_octet[5]);
188         if (r != 6) {
189                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
190                            "Not a valid MAC address, ignoring assignment: %s", rvalue);
191                 free(n);
192                 return 0;
193         }
194
195         free(*hwaddr);
196         *hwaddr = n;
197
198         return 0;
199 }
200
201 int net_parse_inaddr(const char *address, unsigned char *family, void *dst) {
202         int r;
203
204         assert(address);
205         assert(family);
206         assert(dst);
207
208         /* IPv4 */
209         r = inet_pton(AF_INET, address, dst);
210         if (r > 0) {
211                 /* succsefully parsed IPv4 address */
212                 if (*family == AF_UNSPEC)
213                         *family = AF_INET;
214                 else if (*family != AF_INET)
215                         return -EINVAL;
216         } else  if (r < 0)
217                 return -errno;
218         else {
219                 /* not an IPv4 address, so let's try IPv6 */
220                 r = inet_pton(AF_INET6, address, dst);
221                 if (r > 0) {
222                         /* successfully parsed IPv6 address */
223                         if (*family == AF_UNSPEC)
224                                 *family = AF_INET6;
225                         else if (*family != AF_INET6)
226                                 return -EINVAL;
227                 } else if (r < 0)
228                         return -errno;
229                 else
230                         return -EINVAL;
231         }
232
233         return 0;
234 }