1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include "alloc-util.h"
4 #include "ether-addr-util.h"
5 #include "hashmap.h"
6 #include "networkd-dhcp-server-static-lease.h"
7 #include "networkd-network.h"
8 #include "networkd-util.h"
9
10 DEFINE_SECTION_CLEANUP_FUNCTIONS(DHCPStaticLease, dhcp_static_lease_free);
11
dhcp_static_lease_free(DHCPStaticLease * static_lease)12 DHCPStaticLease *dhcp_static_lease_free(DHCPStaticLease *static_lease) {
13 if (!static_lease)
14 return NULL;
15
16 if (static_lease->network && static_lease->section)
17 hashmap_remove(static_lease->network->dhcp_static_leases_by_section, static_lease->section);
18
19 config_section_free(static_lease->section);
20 free(static_lease->client_id);
21 return mfree(static_lease);
22 }
23
dhcp_static_lease_new(DHCPStaticLease ** ret)24 static int dhcp_static_lease_new(DHCPStaticLease **ret) {
25 DHCPStaticLease *p;
26
27 assert(ret);
28
29 p = new0(DHCPStaticLease, 1);
30 if (!p)
31 return -ENOMEM;
32
33 *ret = TAKE_PTR(p);
34 return 0;
35 }
36
lease_new_static(Network * network,const char * filename,unsigned section_line,DHCPStaticLease ** ret)37 static int lease_new_static(Network *network, const char *filename, unsigned section_line, DHCPStaticLease **ret) {
38 _cleanup_(config_section_freep) ConfigSection *n = NULL;
39 _cleanup_(dhcp_static_lease_freep) DHCPStaticLease *static_lease = NULL;
40 int r;
41
42 assert(network);
43 assert(filename);
44 assert(section_line > 0);
45 assert(ret);
46
47 r = config_section_new(filename, section_line, &n);
48 if (r < 0)
49 return r;
50
51 static_lease = hashmap_get(network->dhcp_static_leases_by_section, n);
52 if (static_lease) {
53 *ret = TAKE_PTR(static_lease);
54 return 0;
55 }
56
57 r = dhcp_static_lease_new(&static_lease);
58 if (r < 0)
59 return r;
60
61 static_lease->network = network;
62 static_lease->section = TAKE_PTR(n);
63 r = hashmap_ensure_put(&network->dhcp_static_leases_by_section, &config_section_hash_ops, static_lease->section, static_lease);
64 if (r < 0)
65 return r;
66
67 *ret = TAKE_PTR(static_lease);
68 return 0;
69 }
70
static_lease_verify(DHCPStaticLease * static_lease)71 static int static_lease_verify(DHCPStaticLease *static_lease) {
72 if (section_is_invalid(static_lease->section))
73 return -EINVAL;
74
75 if (in4_addr_is_null(&static_lease->address))
76 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
77 "%s: DHCP static lease without Address= field configured. "
78 "Ignoring [DHCPServerStaticLease] section from line %u.",
79 static_lease->section->filename, static_lease->section->line);
80
81 /* TODO: check that the address is in the pool. */
82
83 if (static_lease->client_id_size == 0 || !static_lease->client_id)
84 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
85 "%s: DHCP static lease without MACAddress= field configured. "
86 "Ignoring [DHCPServerStaticLease] section from line %u.",
87 static_lease->section->filename, static_lease->section->line);
88
89 assert(static_lease->client_id_size == ETH_ALEN + 1);
90
91 return 0;
92 }
93
network_drop_invalid_static_leases(Network * network)94 void network_drop_invalid_static_leases(Network *network) {
95 DHCPStaticLease *static_lease;
96
97 assert(network);
98
99 HASHMAP_FOREACH(static_lease, network->dhcp_static_leases_by_section)
100 if (static_lease_verify(static_lease) < 0)
101 dhcp_static_lease_free(static_lease);
102 }
103
config_parse_dhcp_static_lease_address(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)104 int config_parse_dhcp_static_lease_address(
105 const char *unit,
106 const char *filename,
107 unsigned line,
108 const char *section,
109 unsigned section_line,
110 const char *lvalue,
111 int ltype,
112 const char *rvalue,
113 void *data,
114 void *userdata) {
115
116 _cleanup_(dhcp_static_lease_free_or_set_invalidp) DHCPStaticLease *lease = NULL;
117 Network *network = userdata;
118 union in_addr_union addr;
119 int r;
120
121 assert(filename);
122 assert(lvalue);
123 assert(rvalue);
124 assert(network);
125
126 r = lease_new_static(network, filename, section_line, &lease);
127 if (r < 0)
128 return log_oom();
129
130 if (isempty(rvalue)) {
131 lease->address.s_addr = 0;
132 TAKE_PTR(lease);
133 return 0;
134 }
135
136 r = in_addr_from_string(AF_INET, rvalue, &addr);
137 if (r < 0) {
138 log_syntax(unit, LOG_WARNING, filename, line, r,
139 "Failed to parse IPv4 address for DHCPv4 static lease, ignoring assignment: %s", rvalue);
140 return 0;
141 }
142 if (in4_addr_is_null(&addr.in)) {
143 log_syntax(unit, LOG_WARNING, filename, line, 0,
144 "IPv4 address for DHCPv4 static lease cannot be the ANY address, ignoring assignment: %s", rvalue);
145 return 0;
146 }
147
148 lease->address = addr.in;
149
150 TAKE_PTR(lease);
151 return 0;
152 }
153
config_parse_dhcp_static_lease_hwaddr(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)154 int config_parse_dhcp_static_lease_hwaddr(
155 const char *unit,
156 const char *filename,
157 unsigned line,
158 const char *section,
159 unsigned section_line,
160 const char *lvalue,
161 int ltype,
162 const char *rvalue,
163 void *data,
164 void *userdata) {
165
166 _cleanup_(dhcp_static_lease_free_or_set_invalidp) DHCPStaticLease *lease = NULL;
167 Network *network = userdata;
168 struct ether_addr hwaddr;
169 uint8_t *c;
170 int r;
171
172 assert(filename);
173 assert(lvalue);
174 assert(rvalue);
175 assert(network);
176
177 r = lease_new_static(network, filename, section_line, &lease);
178 if (r < 0)
179 return log_oom();
180
181 if (isempty(rvalue)) {
182 lease->client_id = mfree(lease->client_id);
183 lease->client_id_size = 0;
184 return 0;
185 }
186
187 r = parse_ether_addr(rvalue, &hwaddr);
188 if (r < 0) {
189 log_syntax(unit, LOG_WARNING, filename, line, r,
190 "Failed to parse MAC address for DHCPv4 static lease, ignoring assignment: %s", rvalue);
191 return 0;
192 }
193 if (ether_addr_is_null(&hwaddr) || (hwaddr.ether_addr_octet[0] & 0x01)) {
194 log_syntax(unit, LOG_WARNING, filename, line, 0,
195 "MAC address for DHCPv4 static lease cannot be null or multicast, ignoring assignment: %s", rvalue);
196 return 0;
197 }
198
199 c = new(uint8_t, ETH_ALEN + 1);
200 if (!c)
201 return log_oom();
202
203 /* set client id type to 1: Ethernet Link-Layer (RFC 2132) */
204 c[0] = 0x01;
205 memcpy(c + 1, &hwaddr, ETH_ALEN);
206
207 free_and_replace(lease->client_id, c);
208 lease->client_id_size = ETH_ALEN + 1;
209
210 TAKE_PTR(lease);
211 return 0;
212 }
213