blob: 982c68a7916211c5649ccdd678f7b51a6cc0396f [file] [log] [blame]
Simon Kelleyc8e8f5c2021-01-24 21:59:37 +00001/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
Simon Kelleyc72daea2012-01-05 21:33:27 +00002
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; version 2 dated June, 1991, or
6 (at your option) version 3 dated 29 June, 2007.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <http://www.gnu.org/licenses/>.
15*/
16
17
18#include "dnsmasq.h"
19
20#ifdef HAVE_DHCP6
21
Simon Kelleya6ebfac2013-03-06 20:52:35 +000022struct state {
23 unsigned char *clid;
Dominik DL6ER456a3192019-10-20 18:51:52 +020024 int clid_len, ia_type, interface, hostname_auth, lease_allocate;
Simon Kelleya6ebfac2013-03-06 20:52:35 +000025 char *client_hostname, *hostname, *domain, *send_domain;
26 struct dhcp_context *context;
Simon Kelleyc3a04082014-01-11 22:18:19 +000027 struct in6_addr *link_address, *fallback, *ll_addr, *ula_addr;
Dominik DL6ER456a3192019-10-20 18:51:52 +020028 unsigned int xid, fqdn_flags, iaid;
Simon Kelleya6ebfac2013-03-06 20:52:35 +000029 char *iface_name;
30 void *packet_options, *end;
31 struct dhcp_netid *tags, *context_tags;
Simon Kelley8939c952013-09-25 11:49:34 +010032 unsigned char mac[DHCP_CHADDR_MAX];
Simon Kelley89500e32013-09-20 16:29:20 +010033 unsigned int mac_len, mac_type;
Simon Kelleya6ebfac2013-03-06 20:52:35 +000034};
35
Simon Kelley8939c952013-09-25 11:49:34 +010036static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz,
37 struct in6_addr *client_addr, int is_unicast, time_t now);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +010038static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_t sz, int is_unicast, time_t now);
Simon Kelley6c8f21e2012-03-12 15:06:55 +000039static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_opts);
Simon Kelleya6ebfac2013-03-06 20:52:35 +000040static void log6_packet(struct state *state, char *type, struct in6_addr *addr, char *string);
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +010041static void log6_quiet(struct state *state, char *type, struct in6_addr *addr, char *string);
Simon Kelley4cb1b322012-02-06 14:30:41 +000042static void *opt6_find (void *opts, void *end, unsigned int search, unsigned int minsize);
43static void *opt6_next(void *opts, void *end);
44static unsigned int opt6_uint(unsigned char *opt, int offset, int size);
Simon Kelleya6ebfac2013-03-06 20:52:35 +000045static void get_context_tag(struct state *state, struct dhcp_context *context);
Simon Kelley3a654c52013-03-06 22:17:48 +000046static int check_ia(struct state *state, void *opt, void **endp, void **ia_option);
Simon Kelleya6ebfac2013-03-06 20:52:35 +000047static int build_ia(struct state *state, int *t1cntr);
48static void end_ia(int t1cntr, unsigned int min_time, int do_fuzz);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +010049static void mark_context_used(struct state *state, struct in6_addr *addr);
Simon Kelleyde92b472013-03-15 18:25:10 +000050static void mark_config_used(struct dhcp_context *context, struct in6_addr *addr);
51static int check_address(struct state *state, struct in6_addr *addr);
Simon Kelleyc125c1d2020-03-05 17:10:14 +000052static int config_valid(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr, struct state *state, time_t now);
53static struct addrlist *config_implies(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr);
Simon Kelleycc4baaa2013-08-05 15:03:44 +010054static void add_address(struct state *state, struct dhcp_context *context, unsigned int lease_time, void *ia_option,
Simon Kelleyc8f2dd82013-09-13 11:22:55 +010055 unsigned int *min_time, struct in6_addr *addr, time_t now);
Simon Kelleya6ebfac2013-03-06 20:52:35 +000056static void update_leases(struct state *state, struct dhcp_context *context, struct in6_addr *addr, unsigned int lease_time, time_t now);
57static int add_local_addrs(struct dhcp_context *context);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +010058static struct dhcp_netid *add_options(struct state *state, int do_refresh);
Simon Kelleyde92b472013-03-15 18:25:10 +000059static void calculate_times(struct dhcp_context *context, unsigned int *min_time, unsigned int *valid_timep,
Simon Kelleycc4baaa2013-08-05 15:03:44 +010060 unsigned int *preferred_timep, unsigned int lease_time);
Simon Kelley62779782012-02-10 21:19:25 +000061
Simon Kelley4cb1b322012-02-06 14:30:41 +000062#define opt6_len(opt) ((int)(opt6_uint(opt, -2, 2)))
63#define opt6_type(opt) (opt6_uint(opt, -4, 2))
64#define opt6_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[4+(i)]))
65
Tanguy Bouzelocef1d7422013-10-03 11:06:31 +010066#define opt6_user_vendor_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[2+(i)]))
67#define opt6_user_vendor_len(opt) ((int)(opt6_uint(opt, -4, 2)))
68#define opt6_user_vendor_next(opt, end) (opt6_next(((void *) opt) - 2, end))
69
Simon Kelley4cb1b322012-02-06 14:30:41 +000070
Simon Kelley1d0f91c2012-03-12 11:56:22 +000071unsigned short dhcp6_reply(struct dhcp_context *context, int interface, char *iface_name,
Simon Kelleyc3a04082014-01-11 22:18:19 +000072 struct in6_addr *fallback, struct in6_addr *ll_addr, struct in6_addr *ula_addr,
73 size_t sz, struct in6_addr *client_addr, time_t now)
Simon Kelleyc72daea2012-01-05 21:33:27 +000074{
Simon Kelley4cb1b322012-02-06 14:30:41 +000075 struct dhcp_vendor *vendor;
Simon Kelley1d0f91c2012-03-12 11:56:22 +000076 int msg_type;
Simon Kelleyf1af2bb2013-09-24 09:16:28 +010077 struct state state;
Simon Kelley1d0f91c2012-03-12 11:56:22 +000078
79 if (sz <= 4)
80 return 0;
81
82 msg_type = *((unsigned char *)daemon->dhcp_packet.iov_base);
83
Simon Kelley4cb1b322012-02-06 14:30:41 +000084 /* Mark these so we only match each at most once, to avoid tangled linked lists */
85 for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
86 vendor->netid.next = &vendor->netid;
Simon Kelleyc72daea2012-01-05 21:33:27 +000087
Simon Kelleyfa785732016-07-22 20:56:01 +010088 reset_counter();
Simon Kelleyf1af2bb2013-09-24 09:16:28 +010089 state.context = context;
90 state.interface = interface;
91 state.iface_name = iface_name;
92 state.fallback = fallback;
Simon Kelleyc3a04082014-01-11 22:18:19 +000093 state.ll_addr = ll_addr;
94 state.ula_addr = ula_addr;
Simon Kelley8939c952013-09-25 11:49:34 +010095 state.mac_len = 0;
Simon Kelleyf1af2bb2013-09-24 09:16:28 +010096 state.tags = NULL;
97 state.link_address = NULL;
98
Simon Kelley8939c952013-09-25 11:49:34 +010099 if (dhcp6_maybe_relay(&state, daemon->dhcp_packet.iov_base, sz, client_addr,
100 IN6_IS_ADDR_MULTICAST(client_addr), now))
Simon Kelley1d0f91c2012-03-12 11:56:22 +0000101 return msg_type == DHCP6RELAYFORW ? DHCPV6_SERVER_PORT : DHCPV6_CLIENT_PORT;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000102
103 return 0;
104}
105
Simon Kelley4cb1b322012-02-06 14:30:41 +0000106/* This cost me blood to write, it will probably cost you blood to understand - srk. */
Simon Kelley8939c952013-09-25 11:49:34 +0100107static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz,
108 struct in6_addr *client_addr, int is_unicast, time_t now)
Simon Kelley4cb1b322012-02-06 14:30:41 +0000109{
110 void *end = inbuff + sz;
111 void *opts = inbuff + 34;
112 int msg_type = *((unsigned char *)inbuff);
113 unsigned char *outmsgtypep;
114 void *opt;
115 struct dhcp_vendor *vendor;
116
Josh Soref730c6742017-02-06 16:14:04 +0000117 /* if not an encapsulated relayed message, just do the stuff */
Simon Kelley4cb1b322012-02-06 14:30:41 +0000118 if (msg_type != DHCP6RELAYFORW)
119 {
120 /* if link_address != NULL if points to the link address field of the
121 innermost nested RELAYFORW message, which is where we find the
122 address of the network on which we can allocate an address.
Simon Kelley8939c952013-09-25 11:49:34 +0100123 Recalculate the available contexts using that information.
124
125 link_address == NULL means there's no relay in use, so we try and find the client's
126 MAC address from the local ND cache. */
Simon Kelley4cb1b322012-02-06 14:30:41 +0000127
Simon Kelley8939c952013-09-25 11:49:34 +0100128 if (!state->link_address)
Simon Kelley33702ab2015-12-28 23:17:15 +0000129 get_client_mac(client_addr, state->interface, state->mac, &state->mac_len, &state->mac_type, now);
Simon Kelley8939c952013-09-25 11:49:34 +0100130 else
Simon Kelley4cb1b322012-02-06 14:30:41 +0000131 {
132 struct dhcp_context *c;
Simon Kelleyae5b7e02019-03-27 22:33:28 +0000133 struct shared_network *share = NULL;
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100134 state->context = NULL;
Simon Kelleyae5b7e02019-03-27 22:33:28 +0000135
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100136 if (!IN6_IS_ADDR_LOOPBACK(state->link_address) &&
137 !IN6_IS_ADDR_LINKLOCAL(state->link_address) &&
138 !IN6_IS_ADDR_MULTICAST(state->link_address))
Simon Kelleybaeb3ad2013-01-10 11:47:38 +0000139 for (c = daemon->dhcp6; c; c = c->next)
Simon Kelleyae5b7e02019-03-27 22:33:28 +0000140 {
141 for (share = daemon->shared_networks; share; share = share->next)
142 {
143 if (share->shared_addr.s_addr != 0)
144 continue;
145
146 if (share->if_index != 0 ||
147 !IN6_ARE_ADDR_EQUAL(state->link_address, &share->match_addr6))
148 continue;
149
150 if ((c->flags & CONTEXT_DHCP) &&
151 !(c->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
152 is_same_net6(&share->shared_addr6, &c->start6, c->prefix) &&
153 is_same_net6(&share->shared_addr6, &c->end6, c->prefix))
154 break;
155 }
156
157 if (share ||
158 ((c->flags & CONTEXT_DHCP) &&
159 !(c->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
160 is_same_net6(state->link_address, &c->start6, c->prefix) &&
161 is_same_net6(state->link_address, &c->end6, c->prefix)))
162 {
163 c->preferred = c->valid = 0xffffffff;
164 c->current = state->context;
165 state->context = c;
166 }
167 }
Simon Kelley4cb1b322012-02-06 14:30:41 +0000168
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100169 if (!state->context)
Simon Kelley4cb1b322012-02-06 14:30:41 +0000170 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100171 inet_ntop(AF_INET6, state->link_address, daemon->addrbuff, ADDRSTRLEN);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000172 my_syslog(MS_DHCP | LOG_WARNING,
173 _("no address range available for DHCPv6 request from relay at %s"),
174 daemon->addrbuff);
175 return 0;
176 }
177 }
Simon Kelley8939c952013-09-25 11:49:34 +0100178
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100179 if (!state->context)
Simon Kelley4cb1b322012-02-06 14:30:41 +0000180 {
181 my_syslog(MS_DHCP | LOG_WARNING,
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100182 _("no address range available for DHCPv6 request via %s"), state->iface_name);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000183 return 0;
184 }
185
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100186 return dhcp6_no_relay(state, msg_type, inbuff, sz, is_unicast, now);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000187 }
188
189 /* must have at least msg_type+hopcount+link_address+peer_address+minimal size option
190 which is 1 + 1 + 16 + 16 + 2 + 2 = 38 */
191 if (sz < 38)
192 return 0;
193
194 /* copy header stuff into reply message and set type to reply */
Simon Kelleyff7eea22013-09-04 18:01:38 +0100195 if (!(outmsgtypep = put_opt6(inbuff, 34)))
196 return 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000197 *outmsgtypep = DHCP6RELAYREPL;
198
199 /* look for relay options and set tags if found. */
200 for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
201 {
202 int mopt;
203
204 if (vendor->match_type == MATCH_SUBSCRIBER)
205 mopt = OPTION6_SUBSCRIBER_ID;
206 else if (vendor->match_type == MATCH_REMOTE)
207 mopt = OPTION6_REMOTE_ID;
208 else
209 continue;
210
211 if ((opt = opt6_find(opts, end, mopt, 1)) &&
212 vendor->len == opt6_len(opt) &&
213 memcmp(vendor->data, opt6_ptr(opt, 0), vendor->len) == 0 &&
214 vendor->netid.next != &vendor->netid)
215 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100216 vendor->netid.next = state->tags;
217 state->tags = &vendor->netid;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000218 break;
219 }
220 }
221
Simon Kelley89500e32013-09-20 16:29:20 +0100222 /* RFC-6939 */
223 if ((opt = opt6_find(opts, end, OPTION6_CLIENT_MAC, 3)))
224 {
Simon Kelley3d4ff1b2017-09-25 18:52:50 +0100225 if (opt6_len(opt) - 2 > DHCP_CHADDR_MAX) {
226 return 0;
227 }
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100228 state->mac_type = opt6_uint(opt, 0, 2);
229 state->mac_len = opt6_len(opt) - 2;
Simon Kelley8939c952013-09-25 11:49:34 +0100230 memcpy(&state->mac[0], opt6_ptr(opt, 2), state->mac_len);
Simon Kelley89500e32013-09-20 16:29:20 +0100231 }
232
Simon Kelley4cb1b322012-02-06 14:30:41 +0000233 for (opt = opts; opt; opt = opt6_next(opt, end))
234 {
yiwenchen499d8dd2018-02-14 22:26:54 +0000235 if (opt6_ptr(opt, 0) + opt6_len(opt) > end)
Simon Kelley33e3f102017-09-25 20:05:11 +0100236 return 0;
yiwenchen499d8dd2018-02-14 22:26:54 +0000237
Simon Kelleyf8c77ed2019-01-10 21:58:18 +0000238 /* Don't copy MAC address into reply. */
239 if (opt6_type(opt) != OPTION6_CLIENT_MAC)
Simon Kelley4cb1b322012-02-06 14:30:41 +0000240 {
Simon Kelleyf8c77ed2019-01-10 21:58:18 +0000241 int o = new_opt6(opt6_type(opt));
242 if (opt6_type(opt) == OPTION6_RELAY_MSG)
243 {
244 struct in6_addr align;
245 /* the packet data is unaligned, copy to aligned storage */
246 memcpy(&align, inbuff + 2, IN6ADDRSZ);
247 state->link_address = &align;
248 /* zero is_unicast since that is now known to refer to the
249 relayed packet, not the original sent by the client */
250 if (!dhcp6_maybe_relay(state, opt6_ptr(opt, 0), opt6_len(opt), client_addr, 0, now))
251 return 0;
252 }
253 else
254 put_opt6(opt6_ptr(opt, 0), opt6_len(opt));
255 end_opt6(o);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000256 }
Simon Kelley4cb1b322012-02-06 14:30:41 +0000257 }
258
259 return 1;
260}
261
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100262static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_t sz, int is_unicast, time_t now)
Simon Kelley4cb1b322012-02-06 14:30:41 +0000263{
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000264 void *opt;
265 int i, o, o1, start_opts;
266 struct dhcp_opt *opt_cfg;
267 struct dhcp_netid *tagif;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000268 struct dhcp_config *config = NULL;
Simon Kelley0d28af82012-09-20 21:24:06 +0100269 struct dhcp_netid known_id, iface_id, v6_id;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000270 unsigned char *outmsgtypep;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000271 struct dhcp_vendor *vendor;
272 struct dhcp_context *context_tmp;
Simon Kelley89500e32013-09-20 16:29:20 +0100273 struct dhcp_mac *mac_opt;
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000274 unsigned int ignore = 0;
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000275
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100276 state->packet_options = inbuff + 4;
277 state->end = inbuff + sz;
278 state->clid = NULL;
279 state->clid_len = 0;
280 state->lease_allocate = 0;
281 state->context_tags = NULL;
282 state->domain = NULL;
283 state->send_domain = NULL;
284 state->hostname_auth = 0;
285 state->hostname = NULL;
286 state->client_hostname = NULL;
Josh Soref730c6742017-02-06 16:14:04 +0000287 state->fqdn_flags = 0x01; /* default to send if we receive no FQDN option */
Simon Kelley4cb1b322012-02-06 14:30:41 +0000288
Simon Kelleyceae00d2012-02-09 21:28:14 +0000289 /* set tag with name == interface */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100290 iface_id.net = state->iface_name;
291 iface_id.next = state->tags;
292 state->tags = &iface_id;
Simon Kelleyceae00d2012-02-09 21:28:14 +0000293
Simon Kelley23780dd2012-10-23 17:04:37 +0100294 /* set tag "dhcpv6" */
295 v6_id.net = "dhcpv6";
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100296 v6_id.next = state->tags;
297 state->tags = &v6_id;
Simon Kelley0d28af82012-09-20 21:24:06 +0100298
Simon Kelley4cb1b322012-02-06 14:30:41 +0000299 /* copy over transaction-id, and save pointer to message type */
Simon Kelleyff7eea22013-09-04 18:01:38 +0100300 if (!(outmsgtypep = put_opt6(inbuff, 4)))
301 return 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000302 start_opts = save_counter(-1);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100303 state->xid = outmsgtypep[3] | outmsgtypep[2] << 8 | outmsgtypep[1] << 16;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000304
305 /* We're going to be linking tags from all context we use.
306 mark them as unused so we don't link one twice and break the list */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100307 for (context_tmp = state->context; context_tmp; context_tmp = context_tmp->current)
Simon Kelley4cb1b322012-02-06 14:30:41 +0000308 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100309 context_tmp->netid.next = &context_tmp->netid;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000310
311 if (option_bool(OPT_LOG_OPTS))
312 {
313 inet_ntop(AF_INET6, &context_tmp->start6, daemon->dhcp_buff, ADDRSTRLEN);
314 inet_ntop(AF_INET6, &context_tmp->end6, daemon->dhcp_buff2, ADDRSTRLEN);
315 if (context_tmp->flags & (CONTEXT_STATIC))
316 my_syslog(MS_DHCP | LOG_INFO, _("%u available DHCPv6 subnet: %s/%d"),
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100317 state->xid, daemon->dhcp_buff, context_tmp->prefix);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000318 else
319 my_syslog(MS_DHCP | LOG_INFO, _("%u available DHCP range: %s -- %s"),
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100320 state->xid, daemon->dhcp_buff, daemon->dhcp_buff2);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000321 }
322 }
323
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100324 if ((opt = opt6_find(state->packet_options, state->end, OPTION6_CLIENT_ID, 1)))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000325 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100326 state->clid = opt6_ptr(opt, 0);
327 state->clid_len = opt6_len(opt);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000328 o = new_opt6(OPTION6_CLIENT_ID);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100329 put_opt6(state->clid, state->clid_len);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000330 end_opt6(o);
331 }
332 else if (msg_type != DHCP6IREQ)
333 return 0;
334
Ilya Ponetaev7f68f822014-09-13 20:52:27 +0100335 /* server-id must match except for SOLICIT, CONFIRM and REBIND messages */
336 if (msg_type != DHCP6SOLICIT && msg_type != DHCP6CONFIRM && msg_type != DHCP6IREQ && msg_type != DHCP6REBIND &&
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100337 (!(opt = opt6_find(state->packet_options, state->end, OPTION6_SERVER_ID, 1)) ||
Simon Kelley4cb1b322012-02-06 14:30:41 +0000338 opt6_len(opt) != daemon->duid_len ||
339 memcmp(opt6_ptr(opt, 0), daemon->duid, daemon->duid_len) != 0))
340 return 0;
341
342 o = new_opt6(OPTION6_SERVER_ID);
343 put_opt6(daemon->duid, daemon->duid_len);
344 end_opt6(o);
345
346 if (is_unicast &&
347 (msg_type == DHCP6REQUEST || msg_type == DHCP6RENEW || msg_type == DHCP6RELEASE || msg_type == DHCP6DECLINE))
348
349 {
Ilya Ponetaev976afc92014-09-13 20:56:14 +0100350 *outmsgtypep = DHCP6REPLY;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000351 o1 = new_opt6(OPTION6_STATUS_CODE);
352 put_opt6_short(DHCP6USEMULTI);
353 put_opt6_string("Use multicast");
354 end_opt6(o1);
355 return 1;
356 }
357
358 /* match vendor and user class options */
359 for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
360 {
361 int mopt;
362
363 if (vendor->match_type == MATCH_VENDOR)
364 mopt = OPTION6_VENDOR_CLASS;
365 else if (vendor->match_type == MATCH_USER)
366 mopt = OPTION6_USER_CLASS;
367 else
368 continue;
369
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100370 if ((opt = opt6_find(state->packet_options, state->end, mopt, 2)))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000371 {
372 void *enc_opt, *enc_end = opt6_ptr(opt, opt6_len(opt));
Simon Kelleya5c72ab2012-02-10 13:42:47 +0000373 int offset = 0;
374
375 if (mopt == OPTION6_VENDOR_CLASS)
376 {
377 if (opt6_len(opt) < 4)
378 continue;
379
380 if (vendor->enterprise != opt6_uint(opt, 0, 4))
381 continue;
382
383 offset = 4;
384 }
385
Tanguy Bouzelocef1d7422013-10-03 11:06:31 +0100386 /* Note that format if user/vendor classes is different to DHCP options - no option types. */
387 for (enc_opt = opt6_ptr(opt, offset); enc_opt; enc_opt = opt6_user_vendor_next(enc_opt, enc_end))
388 for (i = 0; i <= (opt6_user_vendor_len(enc_opt) - vendor->len); i++)
389 if (memcmp(vendor->data, opt6_user_vendor_ptr(enc_opt, i), vendor->len) == 0)
Simon Kelley4cb1b322012-02-06 14:30:41 +0000390 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100391 vendor->netid.next = state->tags;
392 state->tags = &vendor->netid;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000393 break;
394 }
395 }
396 }
Simon Kelley3634c542012-02-08 14:22:37 +0000397
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100398 if (option_bool(OPT_LOG_OPTS) && (opt = opt6_find(state->packet_options, state->end, OPTION6_VENDOR_CLASS, 4)))
399 my_syslog(MS_DHCP | LOG_INFO, _("%u vendor class: %u"), state->xid, opt6_uint(opt, 0, 4));
Simon Kelley1567fea2012-03-12 22:15:35 +0000400
Simon Kelley3634c542012-02-08 14:22:37 +0000401 /* dhcp-match. If we have hex-and-wildcards, look for a left-anchored match.
402 Otherwise assume the option is an array, and look for a matching element.
Josh Soref730c6742017-02-06 16:14:04 +0000403 If no data given, existence of the option is enough. This code handles
Simon Kelley3634c542012-02-08 14:22:37 +0000404 V-I opts too. */
405 for (opt_cfg = daemon->dhcp_match6; opt_cfg; opt_cfg = opt_cfg->next)
406 {
Simon Kelleyceae00d2012-02-09 21:28:14 +0000407 int match = 0;
408
Simon Kelley3634c542012-02-08 14:22:37 +0000409 if (opt_cfg->flags & DHOPT_RFC3925)
410 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100411 for (opt = opt6_find(state->packet_options, state->end, OPTION6_VENDOR_OPTS, 4);
Simon Kelley3634c542012-02-08 14:22:37 +0000412 opt;
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100413 opt = opt6_find(opt6_next(opt, state->end), state->end, OPTION6_VENDOR_OPTS, 4))
Simon Kelley3634c542012-02-08 14:22:37 +0000414 {
415 void *vopt;
416 void *vend = opt6_ptr(opt, opt6_len(opt));
417
418 for (vopt = opt6_find(opt6_ptr(opt, 4), vend, opt_cfg->opt, 0);
419 vopt;
420 vopt = opt6_find(opt6_next(vopt, vend), vend, opt_cfg->opt, 0))
Simon Kelleyceae00d2012-02-09 21:28:14 +0000421 if ((match = match_bytes(opt_cfg, opt6_ptr(vopt, 0), opt6_len(vopt))))
Simon Kelley3634c542012-02-08 14:22:37 +0000422 break;
423 }
424 if (match)
425 break;
426 }
427 else
428 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100429 if (!(opt = opt6_find(state->packet_options, state->end, opt_cfg->opt, 1)))
Simon Kelley3634c542012-02-08 14:22:37 +0000430 continue;
431
432 match = match_bytes(opt_cfg, opt6_ptr(opt, 0), opt6_len(opt));
433 }
434
435 if (match)
436 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100437 opt_cfg->netid->next = state->tags;
438 state->tags = opt_cfg->netid;
Simon Kelley3634c542012-02-08 14:22:37 +0000439 }
440 }
Simon Kelley89500e32013-09-20 16:29:20 +0100441
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100442 if (state->mac_len != 0)
Simon Kelleyd81b42d2013-09-23 12:26:34 +0100443 {
444 if (option_bool(OPT_LOG_OPTS))
Simon Kelley89500e32013-09-20 16:29:20 +0100445 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100446 print_mac(daemon->dhcp_buff, state->mac, state->mac_len);
447 my_syslog(MS_DHCP | LOG_INFO, _("%u client MAC address: %s"), state->xid, daemon->dhcp_buff);
Simon Kelley89500e32013-09-20 16:29:20 +0100448 }
Simon Kelleyd81b42d2013-09-23 12:26:34 +0100449
450 for (mac_opt = daemon->dhcp_macs; mac_opt; mac_opt = mac_opt->next)
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100451 if ((unsigned)mac_opt->hwaddr_len == state->mac_len &&
452 ((unsigned)mac_opt->hwaddr_type == state->mac_type || mac_opt->hwaddr_type == 0) &&
453 memcmp_masked(mac_opt->hwaddr, state->mac, state->mac_len, mac_opt->mask))
Simon Kelleyd81b42d2013-09-23 12:26:34 +0100454 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100455 mac_opt->netid.next = state->tags;
456 state->tags = &mac_opt->netid;
Simon Kelleyd81b42d2013-09-23 12:26:34 +0100457 }
458 }
Simon Kelley4cb1b322012-02-06 14:30:41 +0000459
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100460 if ((opt = opt6_find(state->packet_options, state->end, OPTION6_FQDN, 1)))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000461 {
462 /* RFC4704 refers */
463 int len = opt6_len(opt) - 1;
464
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100465 state->fqdn_flags = opt6_uint(opt, 0, 1);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000466
467 /* Always force update, since the client has no way to do it itself. */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100468 if (!option_bool(OPT_FQDN_UPDATE) && !(state->fqdn_flags & 0x01))
469 state->fqdn_flags |= 0x03;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000470
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100471 state->fqdn_flags &= ~0x04;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000472
473 if (len != 0 && len < 255)
474 {
Simon Kelleyfbbc1452012-03-30 20:48:20 +0100475 unsigned char *pp, *op = opt6_ptr(opt, 1);
476 char *pq = daemon->dhcp_buff;
477
478 pp = op;
479 while (*op != 0 && ((op + (*op)) - pp) < len)
480 {
481 memcpy(pq, op+1, *op);
482 pq += *op;
483 op += (*op)+1;
484 *(pq++) = '.';
485 }
486
487 if (pq != daemon->dhcp_buff)
488 pq--;
489 *pq = 0;
490
491 if (legal_hostname(daemon->dhcp_buff))
492 {
Simon Kelley34d41472019-12-05 23:44:29 +0000493 struct dhcp_match_name *m;
494 size_t nl = strlen(daemon->dhcp_buff);
495
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100496 state->client_hostname = daemon->dhcp_buff;
Simon Kelley34d41472019-12-05 23:44:29 +0000497
Simon Kelleyfbbc1452012-03-30 20:48:20 +0100498 if (option_bool(OPT_LOG_OPTS))
Simon Kelley34d41472019-12-05 23:44:29 +0000499 my_syslog(MS_DHCP | LOG_INFO, _("%u client provides name: %s"), state->xid, state->client_hostname);
500
501 for (m = daemon->dhcp_name_match; m; m = m->next)
502 {
503 size_t ml = strlen(m->name);
504 char save = 0;
505
506 if (nl < ml)
507 continue;
508 if (nl > ml)
509 {
510 save = state->client_hostname[ml];
511 state->client_hostname[ml] = 0;
512 }
513
514 if (hostname_isequal(state->client_hostname, m->name) &&
515 (save == 0 || m->wildcard))
516 {
517 m->netid->next = state->tags;
518 state->tags = m->netid;
519 }
520
521 if (save != 0)
522 state->client_hostname[ml] = save;
523 }
Simon Kelleyfbbc1452012-03-30 20:48:20 +0100524 }
Simon Kelley4cb1b322012-02-06 14:30:41 +0000525 }
526 }
527
Simon Kelley6ebdc952019-10-30 21:04:27 +0000528 if (state->clid &&
Simon Kelley52ec7832020-02-07 21:05:54 +0000529 (config = find_config(daemon->dhcp_conf, state->context, state->clid, state->clid_len,
530 state->mac, state->mac_len, state->mac_type, NULL, run_tag_if(state->tags))) &&
Simon Kelley6ebdc952019-10-30 21:04:27 +0000531 have_config(config, CONFIG_NAME))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000532 {
Simon Kelley6ebdc952019-10-30 21:04:27 +0000533 state->hostname = config->hostname;
534 state->domain = config->domain;
535 state->hostname_auth = 1;
536 }
537 else if (state->client_hostname)
538 {
539 state->domain = strip_hostname(state->client_hostname);
Simon Kelley34d41472019-12-05 23:44:29 +0000540
Simon Kelley6ebdc952019-10-30 21:04:27 +0000541 if (strlen(state->client_hostname) != 0)
Simon Kelley4cb1b322012-02-06 14:30:41 +0000542 {
Simon Kelley6ebdc952019-10-30 21:04:27 +0000543 state->hostname = state->client_hostname;
Simon Kelley70c5e3e2012-02-06 22:05:15 +0000544
Simon Kelley6ebdc952019-10-30 21:04:27 +0000545 if (!config)
Simon Kelley4cb1b322012-02-06 14:30:41 +0000546 {
Simon Kelley6ebdc952019-10-30 21:04:27 +0000547 /* Search again now we have a hostname.
548 Only accept configs without CLID here, (it won't match)
549 to avoid impersonation by name. */
Simon Kelley52ec7832020-02-07 21:05:54 +0000550 struct dhcp_config *new = find_config(daemon->dhcp_conf, state->context, NULL, 0, NULL, 0, 0, state->hostname, run_tag_if(state->tags));
Simon Kelley6ebdc952019-10-30 21:04:27 +0000551 if (new && !have_config(new, CONFIG_CLID) && !new->hwaddr)
552 config = new;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000553 }
554 }
555 }
Simon Kelley34d41472019-12-05 23:44:29 +0000556
Simon Kelley4cb1b322012-02-06 14:30:41 +0000557 if (config)
558 {
559 struct dhcp_netid_list *list;
560
561 for (list = config->netid; list; list = list->next)
562 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100563 list->list->next = state->tags;
564 state->tags = list->list;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000565 }
566
567 /* set "known" tag for known hosts */
568 known_id.net = "known";
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100569 known_id.next = state->tags;
570 state->tags = &known_id;
Simon Kelley3634c542012-02-08 14:22:37 +0000571
572 if (have_config(config, CONFIG_DISABLE))
573 ignore = 1;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000574 }
Simon Kelleyb2a9c572017-04-30 18:21:31 +0100575 else if (state->clid &&
Simon Kelley52ec7832020-02-07 21:05:54 +0000576 find_config(daemon->dhcp_conf, NULL, state->clid, state->clid_len,
577 state->mac, state->mac_len, state->mac_type, NULL, run_tag_if(state->tags)))
Simon Kelleyb2a9c572017-04-30 18:21:31 +0100578 {
579 known_id.net = "known-othernet";
580 known_id.next = state->tags;
581 state->tags = &known_id;
582 }
583
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100584 tagif = run_tag_if(state->tags);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000585
Simon Kelley3634c542012-02-08 14:22:37 +0000586 /* if all the netids in the ignore list are present, ignore this client */
587 if (daemon->dhcp_ignore)
588 {
589 struct dhcp_netid_list *id_list;
590
Simon Kelley3634c542012-02-08 14:22:37 +0000591 for (id_list = daemon->dhcp_ignore; id_list; id_list = id_list->next)
592 if (match_netid(id_list->list, tagif, 0))
593 ignore = 1;
594 }
Simon Kelley00e9ad52012-02-16 21:53:11 +0000595
596 /* if all the netids in the ignore_name list are present, ignore client-supplied name */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100597 if (!state->hostname_auth)
Simon Kelley00e9ad52012-02-16 21:53:11 +0000598 {
599 struct dhcp_netid_list *id_list;
600
601 for (id_list = daemon->dhcp_ignore_names; id_list; id_list = id_list->next)
602 if ((!id_list->list) || match_netid(id_list->list, tagif, 0))
603 break;
604 if (id_list)
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100605 state->hostname = NULL;
Simon Kelley00e9ad52012-02-16 21:53:11 +0000606 }
607
Simon Kelley4cb1b322012-02-06 14:30:41 +0000608
609 switch (msg_type)
610 {
Simon Kelley70c5e3e2012-02-06 22:05:15 +0000611 default:
612 return 0;
Simon Kelleyc8f2dd82013-09-13 11:22:55 +0100613
614
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000615 case DHCP6SOLICIT:
616 {
Simon Kelleyde92b472013-03-15 18:25:10 +0000617 int address_assigned = 0;
Simon Kelleyc6309242013-03-07 20:59:28 +0000618 /* tags without all prefix-class tags */
Simon Kelley8f51a292013-09-21 14:07:12 +0100619 struct dhcp_netid *solicit_tags;
Simon Kelleyde92b472013-03-15 18:25:10 +0000620 struct dhcp_context *c;
Simon Kelleyc8f2dd82013-09-13 11:22:55 +0100621
622 *outmsgtypep = DHCP6ADVERTISE;
623
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100624 if (opt6_find(state->packet_options, state->end, OPTION6_RAPID_COMMIT, 0))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000625 {
Simon Kelleyc8f2dd82013-09-13 11:22:55 +0100626 *outmsgtypep = DHCP6REPLY;
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100627 state->lease_allocate = 1;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000628 o = new_opt6(OPTION6_RAPID_COMMIT);
629 end_opt6(o);
630 }
Simon Kelley3634c542012-02-08 14:22:37 +0000631
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +0100632 log6_quiet(state, "DHCPSOLICIT", NULL, ignore ? _("ignored") : NULL);
Simon Kelleyc8f2dd82013-09-13 11:22:55 +0100633
634 request_no_address:
Simon Kelley8f51a292013-09-21 14:07:12 +0100635 solicit_tags = tagif;
636
Simon Kelley3634c542012-02-08 14:22:37 +0000637 if (ignore)
638 return 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000639
Simon Kelley52a1ae72013-03-06 22:43:26 +0000640 /* reset USED bits in leases */
641 lease6_reset();
Simon Kelleyde92b472013-03-15 18:25:10 +0000642
643 /* Can use configured address max once per prefix */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100644 for (c = state->context; c; c = c->current)
Simon Kelleyde92b472013-03-15 18:25:10 +0000645 c->flags &= ~CONTEXT_CONF_USED;
646
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100647 for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000648 {
Simon Kelley4cb1b322012-02-06 14:30:41 +0000649 void *ia_option, *ia_end;
650 unsigned int min_time = 0xffffffff;
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000651 int t1cntr;
Simon Kelleyc6309242013-03-07 20:59:28 +0000652 int ia_counter;
653 /* set unless we're sending a particular prefix-class, when we
654 want only dhcp-ranges with the correct tags set and not those without any tags. */
655 int plain_range = 1;
Simon Kelleycc4baaa2013-08-05 15:03:44 +0100656 u32 lease_time;
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000657 struct dhcp_lease *ltmp;
Simon Kelley97f876b2018-08-21 22:06:36 +0100658 struct in6_addr req_addr, addr;
659
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100660 if (!check_ia(state, opt, &ia_end, &ia_option))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000661 continue;
662
Simon Kelley52a1ae72013-03-06 22:43:26 +0000663 /* reset USED bits in contexts - one address per prefix per IAID */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100664 for (c = state->context; c; c = c->current)
Simon Kelley52a1ae72013-03-06 22:43:26 +0000665 c->flags &= ~CONTEXT_USED;
Simon Kelleyc6309242013-03-07 20:59:28 +0000666
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100667 o = build_ia(state, &t1cntr);
Vladislav Grishenkob9ff5c82014-10-06 14:34:24 +0100668 if (address_assigned)
669 address_assigned = 2;
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000670
Simon Kelleyc6309242013-03-07 20:59:28 +0000671 for (ia_counter = 0; ia_option; ia_counter++, ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000672 {
Simon Kelley97f876b2018-08-21 22:06:36 +0100673 /* worry about alignment here. */
674 memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
Simon Kelleycc4baaa2013-08-05 15:03:44 +0100675
Simon Kelley97f876b2018-08-21 22:06:36 +0100676 if ((c = address6_valid(state->context, &req_addr, solicit_tags, plain_range)))
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000677 {
678 lease_time = c->lease_time;
679 /* If the client asks for an address on the same network as a configured address,
680 offer the configured address instead, to make moving to newly-configured
681 addresses automatic. */
Simon Kelleyc125c1d2020-03-05 17:10:14 +0000682 if (!(c->flags & CONTEXT_CONF_USED) && config_valid(config, c, &addr, state, now))
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000683 {
Simon Kelley97f876b2018-08-21 22:06:36 +0100684 req_addr = addr;
Simon Kelleyde92b472013-03-15 18:25:10 +0000685 mark_config_used(c, &addr);
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000686 if (have_config(config, CONFIG_TIME))
687 lease_time = config->lease_time;
688 }
Simon Kelley97f876b2018-08-21 22:06:36 +0100689 else if (!(c = address6_available(state->context, &req_addr, solicit_tags, plain_range)))
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000690 continue; /* not an address we're allowed */
Simon Kelley97f876b2018-08-21 22:06:36 +0100691 else if (!check_address(state, &req_addr))
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000692 continue; /* address leased elsewhere */
693
694 /* add address to output packet */
Simon Kelley97f876b2018-08-21 22:06:36 +0100695 add_address(state, c, lease_time, ia_option, &min_time, &req_addr, now);
696 mark_context_used(state, &req_addr);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100697 get_context_tag(state, c);
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000698 address_assigned = 1;
699 }
Simon Kelley4cb1b322012-02-06 14:30:41 +0000700 }
701
Simon Kelleyde92b472013-03-15 18:25:10 +0000702 /* Suggest configured address(es) */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100703 for (c = state->context; c; c = c->current)
Simon Kelleya1a79ed2013-03-15 21:19:57 +0000704 if (!(c->flags & CONTEXT_CONF_USED) &&
705 match_netid(c->filter, solicit_tags, plain_range) &&
Simon Kelleyc125c1d2020-03-05 17:10:14 +0000706 config_valid(config, c, &addr, state, now))
Simon Kelleyde92b472013-03-15 18:25:10 +0000707 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100708 mark_config_used(state->context, &addr);
Simon Kelleyde92b472013-03-15 18:25:10 +0000709 if (have_config(config, CONFIG_TIME))
710 lease_time = config->lease_time;
Simon Kelleya1a79ed2013-03-15 21:19:57 +0000711 else
712 lease_time = c->lease_time;
Simon Kelley6c1e9ac2020-01-07 22:04:07 +0000713
Simon Kelleyde92b472013-03-15 18:25:10 +0000714 /* add address to output packet */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100715 add_address(state, c, lease_time, NULL, &min_time, &addr, now);
716 mark_context_used(state, &addr);
717 get_context_tag(state, c);
Simon Kelleyde92b472013-03-15 18:25:10 +0000718 address_assigned = 1;
719 }
720
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000721 /* return addresses for existing leases */
722 ltmp = NULL;
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100723 while ((ltmp = lease6_find_by_client(ltmp, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, state->clid, state->clid_len, state->iaid)))
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000724 {
Simon Kelley97f876b2018-08-21 22:06:36 +0100725 req_addr = ltmp->addr6;
726 if ((c = address6_available(state->context, &req_addr, solicit_tags, plain_range)))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000727 {
Simon Kelley97f876b2018-08-21 22:06:36 +0100728 add_address(state, c, c->lease_time, NULL, &min_time, &req_addr, now);
729 mark_context_used(state, &req_addr);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100730 get_context_tag(state, c);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000731 address_assigned = 1;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000732 }
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000733 }
734
735 /* Return addresses for all valid contexts which don't yet have one */
Simon Kelley6586e832013-11-07 14:20:13 +0000736 while ((c = address6_allocate(state->context, state->clid, state->clid_len, state->ia_type == OPTION6_IA_TA,
737 state->iaid, ia_counter, solicit_tags, plain_range, &addr)))
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000738 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100739 add_address(state, c, c->lease_time, NULL, &min_time, &addr, now);
740 mark_context_used(state, &addr);
741 get_context_tag(state, c);
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000742 address_assigned = 1;
743 }
744
Vladislav Grishenkob9ff5c82014-10-06 14:34:24 +0100745 if (address_assigned != 1)
746 {
747 /* If the server will not assign any addresses to any IAs in a
748 subsequent Request from the client, the server MUST send an Advertise
749 message to the client that doesn't include any IA options. */
750 if (!state->lease_allocate)
751 {
752 save_counter(o);
753 continue;
754 }
755
756 /* If the server cannot assign any addresses to an IA in the message
757 from the client, the server MUST include the IA in the Reply message
758 with no addresses in the IA and a Status Code option in the IA
759 containing status code NoAddrsAvail. */
760 o1 = new_opt6(OPTION6_STATUS_CODE);
761 put_opt6_short(DHCP6NOADDRS);
762 put_opt6_string(_("address unavailable"));
763 end_opt6(o1);
764 }
765
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000766 end_ia(t1cntr, min_time, 0);
767 end_opt6(o);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000768 }
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000769
770 if (address_assigned)
771 {
772 o1 = new_opt6(OPTION6_STATUS_CODE);
773 put_opt6_short(DHCP6SUCCESS);
Simon Kelleyde92b472013-03-15 18:25:10 +0000774 put_opt6_string(_("success"));
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000775 end_opt6(o1);
776
777 /* If --dhcp-authoritative is set, we can tell client not to wait for
778 other possible servers */
779 o = new_opt6(OPTION6_PREFERENCE);
780 put_opt6_char(option_bool(OPT_AUTHORITATIVE) ? 255 : 0);
781 end_opt6(o);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100782 tagif = add_options(state, 0);
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000783 }
784 else
785 {
786 /* no address, return error */
787 o1 = new_opt6(OPTION6_STATUS_CODE);
788 put_opt6_short(DHCP6NOADDRS);
Simon Kelleyde92b472013-03-15 18:25:10 +0000789 put_opt6_string(_("no addresses available"));
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000790 end_opt6(o1);
Simon Kelley338b3402015-04-20 21:34:05 +0100791
792 /* Some clients will ask repeatedly when we're not giving
793 out addresses because we're in stateless mode. Avoid spamming
794 the log in that case. */
795 for (c = state->context; c; c = c->current)
796 if (!(c->flags & CONTEXT_RA_STATELESS))
797 {
798 log6_packet(state, state->lease_allocate ? "DHCPREPLY" : "DHCPADVERTISE", NULL, _("no addresses available"));
799 break;
800 }
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000801 }
802
Simon Kelley4cb1b322012-02-06 14:30:41 +0000803 break;
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000804 }
805
806 case DHCP6REQUEST:
807 {
808 int address_assigned = 0;
Simon Kelleyc8f2dd82013-09-13 11:22:55 +0100809 int start = save_counter(-1);
810
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000811 /* set reply message type */
812 *outmsgtypep = DHCP6REPLY;
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100813 state->lease_allocate = 1;
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000814
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +0100815 log6_quiet(state, "DHCPREQUEST", NULL, ignore ? _("ignored") : NULL);
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000816
817 if (ignore)
818 return 0;
819
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100820 for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000821 {
822 void *ia_option, *ia_end;
823 unsigned int min_time = 0xffffffff;
824 int t1cntr;
825
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100826 if (!check_ia(state, opt, &ia_end, &ia_option))
Simon Kelley3a654c52013-03-06 22:17:48 +0000827 continue;
Simon Kelleyc8f2dd82013-09-13 11:22:55 +0100828
829 if (!ia_option)
830 {
Ville Skyttäfaaf3062018-01-14 17:32:52 +0000831 /* If we get a request with an IA_*A without addresses, treat it exactly like
Simon Kelleyc8f2dd82013-09-13 11:22:55 +0100832 a SOLICT with rapid commit set. */
833 save_counter(start);
834 goto request_no_address;
835 }
836
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100837 o = build_ia(state, &t1cntr);
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000838
839 for (; ia_option; ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
840 {
Simon Kelley97f876b2018-08-21 22:06:36 +0100841 struct in6_addr req_addr;
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000842 struct dhcp_context *dynamic, *c;
843 unsigned int lease_time;
Simon Kelleyde92b472013-03-15 18:25:10 +0000844 int config_ok = 0;
Simon Kelley97f876b2018-08-21 22:06:36 +0100845
846 /* align. */
847 memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
Simon Kelleyde92b472013-03-15 18:25:10 +0000848
Simon Kelley97f876b2018-08-21 22:06:36 +0100849 if ((c = address6_valid(state->context, &req_addr, tagif, 1)))
Simon Kelleyc125c1d2020-03-05 17:10:14 +0000850 config_ok = (config_implies(config, c, &req_addr) != NULL);
Simon Kelleyde92b472013-03-15 18:25:10 +0000851
Simon Kelley97f876b2018-08-21 22:06:36 +0100852 if ((dynamic = address6_available(state->context, &req_addr, tagif, 1)) || c)
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000853 {
Simon Kelleyde92b472013-03-15 18:25:10 +0000854 if (!dynamic && !config_ok)
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000855 {
856 /* Static range, not configured. */
857 o1 = new_opt6(OPTION6_STATUS_CODE);
Vladislav Grishenkob9ff5c82014-10-06 14:34:24 +0100858 put_opt6_short(DHCP6NOADDRS);
Simon Kelleyde92b472013-03-15 18:25:10 +0000859 put_opt6_string(_("address unavailable"));
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000860 end_opt6(o1);
861 }
Simon Kelley97f876b2018-08-21 22:06:36 +0100862 else if (!check_address(state, &req_addr))
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000863 {
864 /* Address leased to another DUID/IAID */
865 o1 = new_opt6(OPTION6_STATUS_CODE);
866 put_opt6_short(DHCP6UNSPEC);
Simon Kelleyde92b472013-03-15 18:25:10 +0000867 put_opt6_string(_("address in use"));
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000868 end_opt6(o1);
869 }
870 else
871 {
872 if (!dynamic)
873 dynamic = c;
874
875 lease_time = dynamic->lease_time;
876
Simon Kelleyde92b472013-03-15 18:25:10 +0000877 if (config_ok && have_config(config, CONFIG_TIME))
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000878 lease_time = config->lease_time;
879
Simon Kelley97f876b2018-08-21 22:06:36 +0100880 add_address(state, dynamic, lease_time, ia_option, &min_time, &req_addr, now);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100881 get_context_tag(state, dynamic);
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000882 address_assigned = 1;
883 }
884 }
Simon Kelleyde92b472013-03-15 18:25:10 +0000885 else
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000886 {
887 /* requested address not on the correct link */
888 o1 = new_opt6(OPTION6_STATUS_CODE);
889 put_opt6_short(DHCP6NOTONLINK);
Simon Kelleyde92b472013-03-15 18:25:10 +0000890 put_opt6_string(_("not on link"));
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000891 end_opt6(o1);
892 }
893 }
894
895 end_ia(t1cntr, min_time, 0);
896 end_opt6(o);
897 }
898
899 if (address_assigned)
900 {
901 o1 = new_opt6(OPTION6_STATUS_CODE);
902 put_opt6_short(DHCP6SUCCESS);
Simon Kelleyde92b472013-03-15 18:25:10 +0000903 put_opt6_string(_("success"));
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000904 end_opt6(o1);
905 }
906 else
907 {
908 /* no address, return error */
909 o1 = new_opt6(OPTION6_STATUS_CODE);
910 put_opt6_short(DHCP6NOADDRS);
Simon Kelleyde92b472013-03-15 18:25:10 +0000911 put_opt6_string(_("no addresses available"));
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000912 end_opt6(o1);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100913 log6_packet(state, "DHCPREPLY", NULL, _("no addresses available"));
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000914 }
915
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100916 tagif = add_options(state, 0);
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000917 break;
918 }
919
920
Simon Kelley4cb1b322012-02-06 14:30:41 +0000921 case DHCP6RENEW:
922 {
923 /* set reply message type */
924 *outmsgtypep = DHCP6REPLY;
925
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +0100926 log6_quiet(state, "DHCPRENEW", NULL, NULL);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000927
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100928 for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000929 {
Simon Kelley4cb1b322012-02-06 14:30:41 +0000930 void *ia_option, *ia_end;
931 unsigned int min_time = 0xffffffff;
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000932 int t1cntr, iacntr;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000933
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100934 if (!check_ia(state, opt, &ia_end, &ia_option))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000935 continue;
936
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100937 o = build_ia(state, &t1cntr);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000938 iacntr = save_counter(-1);
939
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000940 for (; ia_option; ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000941 {
942 struct dhcp_lease *lease = NULL;
Simon Kelley97f876b2018-08-21 22:06:36 +0100943 struct in6_addr req_addr;
Simon Kelleycc4baaa2013-08-05 15:03:44 +0100944 unsigned int preferred_time = opt6_uint(ia_option, 16, 4);
945 unsigned int valid_time = opt6_uint(ia_option, 20, 4);
Simon Kelleyde92b472013-03-15 18:25:10 +0000946 char *message = NULL;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000947 struct dhcp_context *this_context;
Simon Kelley97f876b2018-08-21 22:06:36 +0100948
949 memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000950
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100951 if (!(lease = lease6_find(state->clid, state->clid_len,
952 state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
Simon Kelley97f876b2018-08-21 22:06:36 +0100953 state->iaid, &req_addr)))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000954 {
955 /* If the server cannot find a client entry for the IA the server
956 returns the IA containing no addresses with a Status Code option set
957 to NoBinding in the Reply message. */
958 save_counter(iacntr);
959 t1cntr = 0;
960
Simon Kelley97f876b2018-08-21 22:06:36 +0100961 log6_packet(state, "DHCPREPLY", &req_addr, _("lease not found"));
Simon Kelley4cb1b322012-02-06 14:30:41 +0000962
963 o1 = new_opt6(OPTION6_STATUS_CODE);
964 put_opt6_short(DHCP6NOBINDING);
Simon Kelleyde92b472013-03-15 18:25:10 +0000965 put_opt6_string(_("no binding found"));
Simon Kelley4cb1b322012-02-06 14:30:41 +0000966 end_opt6(o1);
Simon Kelleycc4baaa2013-08-05 15:03:44 +0100967
968 preferred_time = valid_time = 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000969 break;
970 }
971
Simon Kelley00e9ad52012-02-16 21:53:11 +0000972
Simon Kelley97f876b2018-08-21 22:06:36 +0100973 if ((this_context = address6_available(state->context, &req_addr, tagif, 1)) ||
974 (this_context = address6_valid(state->context, &req_addr, tagif, 1)))
Simon Kelleyc8257542012-03-28 21:15:41 +0100975 {
Simon Kelleyde92b472013-03-15 18:25:10 +0000976 unsigned int lease_time;
977
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100978 get_context_tag(state, this_context);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000979
Simon Kelley79aba0f2020-02-03 23:58:45 +0000980 if (config_implies(config, this_context, &req_addr) && have_config(config, CONFIG_TIME))
Simon Kelleyde92b472013-03-15 18:25:10 +0000981 lease_time = config->lease_time;
982 else
983 lease_time = this_context->lease_time;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000984
Simon Kelleycc4baaa2013-08-05 15:03:44 +0100985 calculate_times(this_context, &min_time, &valid_time, &preferred_time, lease_time);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000986
Simon Kelleyde92b472013-03-15 18:25:10 +0000987 lease_set_expires(lease, valid_time, now);
Simon Kelley89500e32013-09-20 16:29:20 +0100988 /* Update MAC record in case it's new information. */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100989 if (state->mac_len != 0)
990 lease_set_hwaddr(lease, state->mac, state->clid, state->mac_len, state->mac_type, state->clid_len, now, 0);
991 if (state->ia_type == OPTION6_IA_NA && state->hostname)
Simon Kelley70c5e3e2012-02-06 22:05:15 +0000992 {
Simon Kelley97f876b2018-08-21 22:06:36 +0100993 char *addr_domain = get_domain6(&req_addr);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100994 if (!state->send_domain)
995 state->send_domain = addr_domain;
996 lease_set_hostname(lease, state->hostname, state->hostname_auth, addr_domain, state->domain);
997 message = state->hostname;
Simon Kelley70c5e3e2012-02-06 22:05:15 +0000998 }
Simon Kelley4cb1b322012-02-06 14:30:41 +0000999
Simon Kelleyde92b472013-03-15 18:25:10 +00001000
1001 if (preferred_time == 0)
1002 message = _("deprecated");
Simon Kelley4cb1b322012-02-06 14:30:41 +00001003 }
Simon Kelleyde92b472013-03-15 18:25:10 +00001004 else
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001005 {
1006 preferred_time = valid_time = 0;
1007 message = _("address invalid");
Simon Kelleya5ae1f82015-04-25 21:46:10 +01001008 }
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001009
Simon Kelleya5ae1f82015-04-25 21:46:10 +01001010 if (message && (message != state->hostname))
Simon Kelley97f876b2018-08-21 22:06:36 +01001011 log6_packet(state, "DHCPREPLY", &req_addr, message);
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01001012 else
Simon Kelley97f876b2018-08-21 22:06:36 +01001013 log6_quiet(state, "DHCPREPLY", &req_addr, message);
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01001014
Simon Kelley4cb1b322012-02-06 14:30:41 +00001015 o1 = new_opt6(OPTION6_IAADDR);
Simon Kelley97f876b2018-08-21 22:06:36 +01001016 put_opt6(&req_addr, sizeof(req_addr));
Simon Kelleyde92b472013-03-15 18:25:10 +00001017 put_opt6_long(preferred_time);
1018 put_opt6_long(valid_time);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001019 end_opt6(o1);
1020 }
1021
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001022 end_ia(t1cntr, min_time, 1);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001023 end_opt6(o);
1024 }
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001025
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001026 tagif = add_options(state, 0);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001027 break;
1028
1029 }
1030
1031 case DHCP6CONFIRM:
1032 {
Ilya Ponetaev2d75f2e2014-09-13 21:11:16 +01001033 int good_addr = 0;
1034
Simon Kelley4cb1b322012-02-06 14:30:41 +00001035 /* set reply message type */
1036 *outmsgtypep = DHCP6REPLY;
1037
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01001038 log6_quiet(state, "DHCPCONFIRM", NULL, NULL);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001039
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001040 for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
Simon Kelley4cb1b322012-02-06 14:30:41 +00001041 {
Simon Kelley4cb1b322012-02-06 14:30:41 +00001042 void *ia_option, *ia_end;
1043
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001044 for (check_ia(state, opt, &ia_end, &ia_option);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001045 ia_option;
1046 ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
1047 {
Simon Kelley97f876b2018-08-21 22:06:36 +01001048 struct in6_addr req_addr;
1049
1050 /* alignment */
1051 memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001052
Simon Kelley97f876b2018-08-21 22:06:36 +01001053 if (!address6_valid(state->context, &req_addr, tagif, 1))
Simon Kelley4cb1b322012-02-06 14:30:41 +00001054 {
1055 o1 = new_opt6(OPTION6_STATUS_CODE);
1056 put_opt6_short(DHCP6NOTONLINK);
Simon Kelleyde92b472013-03-15 18:25:10 +00001057 put_opt6_string(_("confirm failed"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00001058 end_opt6(o1);
Simon Kelley97f876b2018-08-21 22:06:36 +01001059 log6_quiet(state, "DHCPREPLY", &req_addr, _("confirm failed"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00001060 return 1;
1061 }
1062
Ilya Ponetaev2d75f2e2014-09-13 21:11:16 +01001063 good_addr = 1;
Simon Kelley97f876b2018-08-21 22:06:36 +01001064 log6_quiet(state, "DHCPREPLY", &req_addr, state->hostname);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001065 }
1066 }
Ilya Ponetaev2d75f2e2014-09-13 21:11:16 +01001067
1068 /* No addresses, no reply: RFC 3315 18.2.2 */
1069 if (!good_addr)
1070 return 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001071
1072 o1 = new_opt6(OPTION6_STATUS_CODE);
1073 put_opt6_short(DHCP6SUCCESS );
Simon Kelleyde92b472013-03-15 18:25:10 +00001074 put_opt6_string(_("all addresses still on link"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00001075 end_opt6(o1);
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001076 break;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001077 }
1078
1079 case DHCP6IREQ:
1080 {
Simon Kelleyd1e9a582012-10-23 17:00:57 +01001081 /* We can't discriminate contexts based on address, as we don't know it.
1082 If there is only one possible context, we can use its tags */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001083 if (state->context && state->context->netid.net && !state->context->current)
Simon Kelleyd1e9a582012-10-23 17:00:57 +01001084 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001085 state->context->netid.next = NULL;
1086 state->context_tags = &state->context->netid;
Simon Kelleyd1e9a582012-10-23 17:00:57 +01001087 }
Simon Kelley6bd109a2013-07-27 15:11:44 +01001088
1089 /* Similarly, we can't determine domain from address, but if the FQDN is
1090 given in --dhcp-host, we can use that, and failing that we can use the
1091 unqualified configured domain, if any. */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001092 if (state->hostname_auth)
1093 state->send_domain = state->domain;
Simon Kelley6bd109a2013-07-27 15:11:44 +01001094 else
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001095 state->send_domain = get_domain6(NULL);
Simon Kelley6bd109a2013-07-27 15:11:44 +01001096
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01001097 log6_quiet(state, "DHCPINFORMATION-REQUEST", NULL, ignore ? _("ignored") : state->hostname);
Simon Kelley3634c542012-02-08 14:22:37 +00001098 if (ignore)
1099 return 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001100 *outmsgtypep = DHCP6REPLY;
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001101 tagif = add_options(state, 1);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001102 break;
1103 }
1104
1105
1106 case DHCP6RELEASE:
1107 {
1108 /* set reply message type */
1109 *outmsgtypep = DHCP6REPLY;
1110
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01001111 log6_quiet(state, "DHCPRELEASE", NULL, NULL);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001112
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001113 for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
Simon Kelley4cb1b322012-02-06 14:30:41 +00001114 {
Simon Kelley4cb1b322012-02-06 14:30:41 +00001115 void *ia_option, *ia_end;
1116 int made_ia = 0;
1117
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001118 for (check_ia(state, opt, &ia_end, &ia_option);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001119 ia_option;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001120 ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
Simon Kelley4cb1b322012-02-06 14:30:41 +00001121 {
1122 struct dhcp_lease *lease;
Simon Kelley97f876b2018-08-21 22:06:36 +01001123 struct in6_addr addr;
1124
1125 /* align */
1126 memcpy(&addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001127 if ((lease = lease6_find(state->clid, state->clid_len, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
Simon Kelley97f876b2018-08-21 22:06:36 +01001128 state->iaid, &addr)))
Simon Kelley4cb1b322012-02-06 14:30:41 +00001129 lease_prune(lease, now);
1130 else
1131 {
1132 if (!made_ia)
1133 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001134 o = new_opt6(state->ia_type);
1135 put_opt6_long(state->iaid);
1136 if (state->ia_type == OPTION6_IA_NA)
Simon Kelley4cb1b322012-02-06 14:30:41 +00001137 {
1138 put_opt6_long(0);
1139 put_opt6_long(0);
1140 }
1141 made_ia = 1;
1142 }
1143
1144 o1 = new_opt6(OPTION6_IAADDR);
Simon Kelleyc5db8f92018-08-23 23:06:00 +01001145 put_opt6(&addr, IN6ADDRSZ);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001146 put_opt6_long(0);
1147 put_opt6_long(0);
1148 end_opt6(o1);
1149 }
1150 }
1151
1152 if (made_ia)
1153 {
1154 o1 = new_opt6(OPTION6_STATUS_CODE);
1155 put_opt6_short(DHCP6NOBINDING);
Simon Kelleyde92b472013-03-15 18:25:10 +00001156 put_opt6_string(_("no binding found"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00001157 end_opt6(o1);
1158
1159 end_opt6(o);
1160 }
1161 }
1162
1163 o1 = new_opt6(OPTION6_STATUS_CODE);
1164 put_opt6_short(DHCP6SUCCESS);
Simon Kelleyde92b472013-03-15 18:25:10 +00001165 put_opt6_string(_("release received"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00001166 end_opt6(o1);
1167
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001168 break;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001169 }
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001170
1171 case DHCP6DECLINE:
1172 {
1173 /* set reply message type */
1174 *outmsgtypep = DHCP6REPLY;
1175
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01001176 log6_quiet(state, "DHCPDECLINE", NULL, NULL);
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001177
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001178 for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001179 {
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001180 void *ia_option, *ia_end;
1181 int made_ia = 0;
1182
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001183 for (check_ia(state, opt, &ia_end, &ia_option);
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001184 ia_option;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001185 ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001186 {
1187 struct dhcp_lease *lease;
Simon Kelley97f876b2018-08-21 22:06:36 +01001188 struct in6_addr addr;
Simon Kelleyc125c1d2020-03-05 17:10:14 +00001189 struct addrlist *addr_list;
1190
Simon Kelley97f876b2018-08-21 22:06:36 +01001191 /* align */
1192 memcpy(&addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
1193
Simon Kelleyc125c1d2020-03-05 17:10:14 +00001194 if ((addr_list = config_implies(config, state->context, &addr)))
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001195 {
Simon Kelleyceae00d2012-02-09 21:28:14 +00001196 prettyprint_time(daemon->dhcp_buff3, DECLINE_BACKOFF);
Simon Kelley97f876b2018-08-21 22:06:36 +01001197 inet_ntop(AF_INET6, &addr, daemon->addrbuff, ADDRSTRLEN);
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001198 my_syslog(MS_DHCP | LOG_WARNING, _("disabling DHCP static address %s for %s"),
Simon Kelleyceae00d2012-02-09 21:28:14 +00001199 daemon->addrbuff, daemon->dhcp_buff3);
Simon Kelleyc125c1d2020-03-05 17:10:14 +00001200 addr_list->flags |= ADDRLIST_DECLINED;
1201 addr_list->decline_time = now;
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001202 }
1203 else
1204 /* make sure this host gets a different address next time. */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001205 for (context_tmp = state->context; context_tmp; context_tmp = context_tmp->current)
1206 context_tmp->addr_epoch++;
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001207
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001208 if ((lease = lease6_find(state->clid, state->clid_len, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
Simon Kelley97f876b2018-08-21 22:06:36 +01001209 state->iaid, &addr)))
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001210 lease_prune(lease, now);
1211 else
1212 {
1213 if (!made_ia)
1214 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001215 o = new_opt6(state->ia_type);
1216 put_opt6_long(state->iaid);
1217 if (state->ia_type == OPTION6_IA_NA)
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001218 {
1219 put_opt6_long(0);
1220 put_opt6_long(0);
1221 }
1222 made_ia = 1;
1223 }
1224
1225 o1 = new_opt6(OPTION6_IAADDR);
Simon Kelley97f876b2018-08-21 22:06:36 +01001226 put_opt6(&addr, IN6ADDRSZ);
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001227 put_opt6_long(0);
1228 put_opt6_long(0);
1229 end_opt6(o1);
1230 }
1231 }
1232
1233 if (made_ia)
1234 {
1235 o1 = new_opt6(OPTION6_STATUS_CODE);
1236 put_opt6_short(DHCP6NOBINDING);
Simon Kelleyde92b472013-03-15 18:25:10 +00001237 put_opt6_string(_("no binding found"));
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001238 end_opt6(o1);
1239
1240 end_opt6(o);
1241 }
1242
1243 }
Ilya Ponetaev51943362014-09-13 21:19:01 +01001244
Josh Soref730c6742017-02-06 16:14:04 +00001245 /* We must answer with 'success' in global section anyway */
Ilya Ponetaev51943362014-09-13 21:19:01 +01001246 o1 = new_opt6(OPTION6_STATUS_CODE);
1247 put_opt6_short(DHCP6SUCCESS);
1248 put_opt6_string(_("success"));
1249 end_opt6(o1);
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001250 break;
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001251 }
1252
Simon Kelley4cb1b322012-02-06 14:30:41 +00001253 }
1254
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001255 log_tags(tagif, state->xid);
1256 log6_opts(0, state->xid, daemon->outpacket.iov_base + start_opts, daemon->outpacket.iov_base + save_counter(-1));
Simon Kelley4cb1b322012-02-06 14:30:41 +00001257
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001258 return 1;
1259
1260}
1261
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001262static struct dhcp_netid *add_options(struct state *state, int do_refresh)
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001263{
Simon Kelley2763d4b2013-03-06 21:24:56 +00001264 void *oro;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001265 /* filter options based on tags, those we want get DHOPT_TAGOK bit set */
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001266 struct dhcp_netid *tagif = option_filter(state->tags, state->context_tags, daemon->dhcp_opts6);
1267 struct dhcp_opt *opt_cfg;
Simon Kelley871d4562013-07-27 21:32:32 +01001268 int done_dns = 0, done_refresh = !do_refresh, do_encap = 0;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001269 int i, o, o1;
1270
1271 oro = opt6_find(state->packet_options, state->end, OPTION6_ORO, 0);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001272
1273 for (opt_cfg = daemon->dhcp_opts6; opt_cfg; opt_cfg = opt_cfg->next)
1274 {
1275 /* netids match and not encapsulated? */
1276 if (!(opt_cfg->flags & DHOPT_TAGOK))
1277 continue;
1278
1279 if (!(opt_cfg->flags & DHOPT_FORCE) && oro)
1280 {
1281 for (i = 0; i < opt6_len(oro) - 1; i += 2)
1282 if (opt6_uint(oro, i, 2) == (unsigned)opt_cfg->opt)
1283 break;
1284
1285 /* option not requested */
1286 if (i >= opt6_len(oro) - 1)
1287 continue;
1288 }
1289
Simon Kelley871d4562013-07-27 21:32:32 +01001290 if (opt_cfg->opt == OPTION6_REFRESH_TIME)
1291 done_refresh = 1;
Simon Kelley5e3e4642015-08-25 23:08:39 +01001292
1293 if (opt_cfg->opt == OPTION6_DNS_SERVER)
1294 done_dns = 1;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001295
Simon Kelley27b78d92015-09-26 21:40:45 +01001296 if (opt_cfg->flags & DHOPT_ADDR6)
Simon Kelley4b86b652012-02-29 11:45:37 +00001297 {
Simon Kelleyc3a04082014-01-11 22:18:19 +00001298 int len, j;
1299 struct in6_addr *a;
1300
Simon Kelleyc3a04082014-01-11 22:18:19 +00001301 for (a = (struct in6_addr *)opt_cfg->val, len = opt_cfg->len, j = 0;
1302 j < opt_cfg->len; j += IN6ADDRSZ, a++)
1303 if ((IN6_IS_ADDR_ULA_ZERO(a) && IN6_IS_ADDR_UNSPECIFIED(state->ula_addr)) ||
1304 (IN6_IS_ADDR_LINK_LOCAL_ZERO(a) && IN6_IS_ADDR_UNSPECIFIED(state->ll_addr)))
1305 len -= IN6ADDRSZ;
1306
1307 if (len != 0)
1308 {
1309
1310 o = new_opt6(opt_cfg->opt);
1311
1312 for (a = (struct in6_addr *)opt_cfg->val, j = 0; j < opt_cfg->len; j+=IN6ADDRSZ, a++)
1313 {
Vladislav Grishenkodded78b2020-03-08 15:34:34 +00001314 struct in6_addr *p = NULL;
1315
Simon Kelleyc3a04082014-01-11 22:18:19 +00001316 if (IN6_IS_ADDR_UNSPECIFIED(a))
1317 {
1318 if (!add_local_addrs(state->context))
Vladislav Grishenkodded78b2020-03-08 15:34:34 +00001319 p = state->fallback;
Simon Kelleyc3a04082014-01-11 22:18:19 +00001320 }
1321 else if (IN6_IS_ADDR_ULA_ZERO(a))
1322 {
1323 if (!IN6_IS_ADDR_UNSPECIFIED(state->ula_addr))
Vladislav Grishenkodded78b2020-03-08 15:34:34 +00001324 p = state->ula_addr;
Simon Kelleyc3a04082014-01-11 22:18:19 +00001325 }
1326 else if (IN6_IS_ADDR_LINK_LOCAL_ZERO(a))
1327 {
1328 if (!IN6_IS_ADDR_UNSPECIFIED(state->ll_addr))
Vladislav Grishenkodded78b2020-03-08 15:34:34 +00001329 p = state->ll_addr;
Simon Kelleyc3a04082014-01-11 22:18:19 +00001330 }
1331 else
Vladislav Grishenkodded78b2020-03-08 15:34:34 +00001332 p = a;
1333
1334 if (!p)
1335 continue;
1336 else if (opt_cfg->opt == OPTION6_NTP_SERVER)
1337 {
1338 if (IN6_IS_ADDR_MULTICAST(p))
1339 o1 = new_opt6(NTP_SUBOPTION_MC_ADDR);
1340 else
1341 o1 = new_opt6(NTP_SUBOPTION_SRV_ADDR);
1342 put_opt6(p, IN6ADDRSZ);
1343 end_opt6(o1);
1344 }
1345 else
1346 put_opt6(p, IN6ADDRSZ);
Simon Kelley4b86b652012-02-29 11:45:37 +00001347 }
Simon Kelleyc3a04082014-01-11 22:18:19 +00001348
1349 end_opt6(o);
1350 }
Simon Kelley4b86b652012-02-29 11:45:37 +00001351 }
Simon Kelleyc3a04082014-01-11 22:18:19 +00001352 else
1353 {
1354 o = new_opt6(opt_cfg->opt);
1355 if (opt_cfg->val)
1356 put_opt6(opt_cfg->val, opt_cfg->len);
1357 end_opt6(o);
1358 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001359 }
1360
Simon Kelley871d4562013-07-27 21:32:32 +01001361 if (daemon->port == NAMESERVER_PORT && !done_dns)
Simon Kelley4cb1b322012-02-06 14:30:41 +00001362 {
1363 o = new_opt6(OPTION6_DNS_SERVER);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001364 if (!add_local_addrs(state->context))
1365 put_opt6(state->fallback, IN6ADDRSZ);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001366 end_opt6(o);
1367 }
Simon Kelley871d4562013-07-27 21:32:32 +01001368
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001369 if (state->context && !done_refresh)
Simon Kelley871d4562013-07-27 21:32:32 +01001370 {
1371 struct dhcp_context *c;
1372 unsigned int lease_time = 0xffffffff;
1373
1374 /* Find the smallest lease tie of all contexts,
Josh Soref730c6742017-02-06 16:14:04 +00001375 subject to the RFC-4242 stipulation that this must not
Simon Kelley871d4562013-07-27 21:32:32 +01001376 be less than 600. */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001377 for (c = state->context; c; c = c->next)
Simon Kelley871d4562013-07-27 21:32:32 +01001378 if (c->lease_time < lease_time)
1379 {
1380 if (c->lease_time < 600)
1381 lease_time = 600;
1382 else
1383 lease_time = c->lease_time;
1384 }
1385
1386 o = new_opt6(OPTION6_REFRESH_TIME);
1387 put_opt6_long(lease_time);
1388 end_opt6(o);
1389 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001390
1391 /* handle vendor-identifying vendor-encapsulated options,
1392 dhcp-option = vi-encap:13,17,....... */
1393 for (opt_cfg = daemon->dhcp_opts6; opt_cfg; opt_cfg = opt_cfg->next)
1394 opt_cfg->flags &= ~DHOPT_ENCAP_DONE;
Simon Kelley4b86b652012-02-29 11:45:37 +00001395
Simon Kelley4cb1b322012-02-06 14:30:41 +00001396 if (oro)
1397 for (i = 0; i < opt6_len(oro) - 1; i += 2)
1398 if (opt6_uint(oro, i, 2) == OPTION6_VENDOR_OPTS)
1399 do_encap = 1;
1400
1401 for (opt_cfg = daemon->dhcp_opts6; opt_cfg; opt_cfg = opt_cfg->next)
1402 {
1403 if (opt_cfg->flags & DHOPT_RFC3925)
1404 {
1405 int found = 0;
1406 struct dhcp_opt *oc;
1407
1408 if (opt_cfg->flags & DHOPT_ENCAP_DONE)
1409 continue;
1410
1411 for (oc = daemon->dhcp_opts6; oc; oc = oc->next)
1412 {
1413 oc->flags &= ~DHOPT_ENCAP_MATCH;
1414
1415 if (!(oc->flags & DHOPT_RFC3925) || opt_cfg->u.encap != oc->u.encap)
1416 continue;
1417
1418 oc->flags |= DHOPT_ENCAP_DONE;
1419 if (match_netid(oc->netid, tagif, 1))
1420 {
1421 /* option requested/forced? */
1422 if (!oro || do_encap || (oc->flags & DHOPT_FORCE))
1423 {
1424 oc->flags |= DHOPT_ENCAP_MATCH;
1425 found = 1;
1426 }
1427 }
1428 }
1429
1430 if (found)
1431 {
1432 o = new_opt6(OPTION6_VENDOR_OPTS);
1433 put_opt6_long(opt_cfg->u.encap);
1434
1435 for (oc = daemon->dhcp_opts6; oc; oc = oc->next)
1436 if (oc->flags & DHOPT_ENCAP_MATCH)
1437 {
1438 o1 = new_opt6(oc->opt);
1439 put_opt6(oc->val, oc->len);
1440 end_opt6(o1);
1441 }
1442 end_opt6(o);
1443 }
1444 }
1445 }
Simon Kelley07933802012-02-14 20:55:25 +00001446
1447
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001448 if (state->hostname)
Simon Kelley4cb1b322012-02-06 14:30:41 +00001449 {
1450 unsigned char *p;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001451 size_t len = strlen(state->hostname);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001452
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001453 if (state->send_domain)
Roy Marples3f3adae2013-07-25 16:22:46 +01001454 len += strlen(state->send_domain) + 2;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001455
1456 o = new_opt6(OPTION6_FQDN);
Roy Marples3f3adae2013-07-25 16:22:46 +01001457 if ((p = expand(len + 2)))
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001458 {
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001459 *(p++) = state->fqdn_flags;
Simon Kelley0549c732017-09-25 18:17:11 +01001460 p = do_rfc1035_name(p, state->hostname, NULL);
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001461 if (state->send_domain)
Roy Marples3f3adae2013-07-25 16:22:46 +01001462 {
Simon Kelley0549c732017-09-25 18:17:11 +01001463 p = do_rfc1035_name(p, state->send_domain, NULL);
Roy Marples3f3adae2013-07-25 16:22:46 +01001464 *p = 0;
1465 }
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001466 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001467 end_opt6(o);
1468 }
1469
1470
1471 /* logging */
1472 if (option_bool(OPT_LOG_OPTS) && oro)
1473 {
1474 char *q = daemon->namebuff;
1475 for (i = 0; i < opt6_len(oro) - 1; i += 2)
1476 {
1477 char *s = option_string(AF_INET6, opt6_uint(oro, i, 2), NULL, 0, NULL, 0);
1478 q += snprintf(q, MAXDNAME - (q - daemon->namebuff),
1479 "%d%s%s%s",
1480 opt6_uint(oro, i, 2),
1481 strlen(s) != 0 ? ":" : "",
1482 s,
1483 (i > opt6_len(oro) - 3) ? "" : ", ");
1484 if ( i > opt6_len(oro) - 3 || (q - daemon->namebuff) > 40)
1485 {
1486 q = daemon->namebuff;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001487 my_syslog(MS_DHCP | LOG_INFO, _("%u requested options: %s"), state->xid, daemon->namebuff);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001488 }
1489 }
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001490 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001491
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001492 return tagif;
1493}
1494
1495static int add_local_addrs(struct dhcp_context *context)
1496{
1497 int done = 0;
Simon Kelley6c8f21e2012-03-12 15:06:55 +00001498
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001499 for (; context; context = context->current)
1500 if ((context->flags & CONTEXT_USED) && !IN6_IS_ADDR_UNSPECIFIED(&context->local6))
1501 {
1502 /* squash duplicates */
1503 struct dhcp_context *c;
1504 for (c = context->current; c; c = c->current)
1505 if ((c->flags & CONTEXT_USED) &&
1506 IN6_ARE_ADDR_EQUAL(&context->local6, &c->local6))
1507 break;
1508
1509 if (!c)
1510 {
1511 done = 1;
1512 put_opt6(&context->local6, IN6ADDRSZ);
1513 }
1514 }
1515
1516 return done;
Simon Kelley6c8f21e2012-03-12 15:06:55 +00001517}
1518
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001519
1520static void get_context_tag(struct state *state, struct dhcp_context *context)
1521{
1522 /* get tags from context if we've not used it before */
1523 if (context->netid.next == &context->netid && context->netid.net)
1524 {
1525 context->netid.next = state->context_tags;
1526 state->context_tags = &context->netid;
1527 if (!state->hostname_auth)
1528 {
1529 struct dhcp_netid_list *id_list;
1530
1531 for (id_list = daemon->dhcp_ignore_names; id_list; id_list = id_list->next)
1532 if ((!id_list->list) || match_netid(id_list->list, &context->netid, 0))
1533 break;
1534 if (id_list)
1535 state->hostname = NULL;
1536 }
1537 }
1538}
Simon Kelleyc6309242013-03-07 20:59:28 +00001539
Simon Kelley3a654c52013-03-06 22:17:48 +00001540static int check_ia(struct state *state, void *opt, void **endp, void **ia_option)
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001541{
1542 state->ia_type = opt6_type(opt);
Simon Kelley3a654c52013-03-06 22:17:48 +00001543 *ia_option = NULL;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001544
1545 if (state->ia_type != OPTION6_IA_NA && state->ia_type != OPTION6_IA_TA)
Simon Kelley3a654c52013-03-06 22:17:48 +00001546 return 0;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001547
1548 if (state->ia_type == OPTION6_IA_NA && opt6_len(opt) < 12)
Simon Kelley3a654c52013-03-06 22:17:48 +00001549 return 0;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001550
1551 if (state->ia_type == OPTION6_IA_TA && opt6_len(opt) < 4)
Simon Kelley3a654c52013-03-06 22:17:48 +00001552 return 0;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001553
1554 *endp = opt6_ptr(opt, opt6_len(opt));
1555 state->iaid = opt6_uint(opt, 0, 4);
Simon Kelley3a654c52013-03-06 22:17:48 +00001556 *ia_option = opt6_find(opt6_ptr(opt, state->ia_type == OPTION6_IA_NA ? 12 : 4), *endp, OPTION6_IAADDR, 24);
1557
1558 return 1;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001559}
1560
1561
1562static int build_ia(struct state *state, int *t1cntr)
1563{
1564 int o = new_opt6(state->ia_type);
1565
1566 put_opt6_long(state->iaid);
1567 *t1cntr = 0;
1568
1569 if (state->ia_type == OPTION6_IA_NA)
1570 {
1571 /* save pointer */
1572 *t1cntr = save_counter(-1);
1573 /* so we can fill these in later */
1574 put_opt6_long(0);
1575 put_opt6_long(0);
1576 }
1577
1578 return o;
1579}
1580
1581static void end_ia(int t1cntr, unsigned int min_time, int do_fuzz)
1582{
1583 if (t1cntr != 0)
1584 {
Ville Skyttäfaaf3062018-01-14 17:32:52 +00001585 /* go back and fill in fields in IA_NA option */
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001586 int sav = save_counter(t1cntr);
1587 unsigned int t1, t2, fuzz = 0;
1588
1589 if (do_fuzz)
1590 {
1591 fuzz = rand16();
1592
1593 while (fuzz > (min_time/16))
1594 fuzz = fuzz/2;
1595 }
1596
1597 t1 = (min_time == 0xffffffff) ? 0xffffffff : min_time/2 - fuzz;
1598 t2 = (min_time == 0xffffffff) ? 0xffffffff : ((min_time/8)*7) - fuzz;
1599 put_opt6_long(t1);
1600 put_opt6_long(t2);
1601 save_counter(sav);
1602 }
1603}
1604
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001605static void add_address(struct state *state, struct dhcp_context *context, unsigned int lease_time, void *ia_option,
Simon Kelleyc8f2dd82013-09-13 11:22:55 +01001606 unsigned int *min_time, struct in6_addr *addr, time_t now)
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001607{
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001608 unsigned int valid_time = 0, preferred_time = 0;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001609 int o = new_opt6(OPTION6_IAADDR);
1610 struct dhcp_lease *lease;
1611
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001612 /* get client requested times */
1613 if (ia_option)
1614 {
1615 preferred_time = opt6_uint(ia_option, 16, 4);
1616 valid_time = opt6_uint(ia_option, 20, 4);
1617 }
1618
1619 calculate_times(context, min_time, &valid_time, &preferred_time, lease_time);
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001620
Simon Kelleyde92b472013-03-15 18:25:10 +00001621 put_opt6(addr, sizeof(*addr));
1622 put_opt6_long(preferred_time);
1623 put_opt6_long(valid_time);
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001624 end_opt6(o);
1625
Simon Kelleyc8f2dd82013-09-13 11:22:55 +01001626 if (state->lease_allocate)
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001627 update_leases(state, context, addr, valid_time, now);
1628
1629 if ((lease = lease6_find_by_addr(addr, 128, 0)))
1630 lease->flags |= LEASE_USED;
1631
1632 /* get tags from context if we've not used it before */
1633 if (context->netid.next == &context->netid && context->netid.net)
1634 {
1635 context->netid.next = state->context_tags;
1636 state->context_tags = &context->netid;
1637
1638 if (!state->hostname_auth)
1639 {
1640 struct dhcp_netid_list *id_list;
1641
1642 for (id_list = daemon->dhcp_ignore_names; id_list; id_list = id_list->next)
1643 if ((!id_list->list) || match_netid(id_list->list, &context->netid, 0))
1644 break;
1645 if (id_list)
1646 state->hostname = NULL;
1647 }
1648 }
1649
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01001650 log6_quiet(state, state->lease_allocate ? "DHCPREPLY" : "DHCPADVERTISE", addr, state->hostname);
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001651
1652}
Simon Kelleyff59fc82013-03-07 11:00:26 +00001653
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001654static void mark_context_used(struct state *state, struct in6_addr *addr)
Simon Kelleyff59fc82013-03-07 11:00:26 +00001655{
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001656 struct dhcp_context *context;
1657
Simon Kelleyff59fc82013-03-07 11:00:26 +00001658 /* Mark that we have an address for this prefix. */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001659 for (context = state->context; context; context = context->current)
Simon Kelleyff59fc82013-03-07 11:00:26 +00001660 if (is_same_net6(addr, &context->start6, context->prefix))
1661 context->flags |= CONTEXT_USED;
1662}
Simon Kelleyc6309242013-03-07 20:59:28 +00001663
Simon Kelleyde92b472013-03-15 18:25:10 +00001664static void mark_config_used(struct dhcp_context *context, struct in6_addr *addr)
1665{
1666 for (; context; context = context->current)
1667 if (is_same_net6(addr, &context->start6, context->prefix))
1668 context->flags |= CONTEXT_CONF_USED;
1669}
1670
1671/* make sure address not leased to another CLID/IAID */
1672static int check_address(struct state *state, struct in6_addr *addr)
1673{
1674 struct dhcp_lease *lease;
1675
1676 if (!(lease = lease6_find_by_addr(addr, 128, 0)))
1677 return 1;
1678
1679 if (lease->clid_len != state->clid_len ||
1680 memcmp(lease->clid, state->clid, state->clid_len) != 0 ||
Simon Kelley89500e32013-09-20 16:29:20 +01001681 lease->iaid != state->iaid)
Simon Kelleyde92b472013-03-15 18:25:10 +00001682 return 0;
1683
1684 return 1;
1685}
1686
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001687
Simon Kelley79aba0f2020-02-03 23:58:45 +00001688/* return true of *addr could have been generated from config. */
Simon Kelleyc125c1d2020-03-05 17:10:14 +00001689static struct addrlist *config_implies(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr)
Simon Kelley79aba0f2020-02-03 23:58:45 +00001690{
1691 int prefix;
1692 struct in6_addr wild_addr;
Simon Kelley137286e2020-02-06 22:09:30 +00001693 struct addrlist *addr_list;
1694
Simon Kelley79aba0f2020-02-03 23:58:45 +00001695 if (!config || !(config->flags & CONFIG_ADDR6))
Simon Kelleyc125c1d2020-03-05 17:10:14 +00001696 return NULL;
Simon Kelley79aba0f2020-02-03 23:58:45 +00001697
Simon Kelley137286e2020-02-06 22:09:30 +00001698 for (addr_list = config->addr6; addr_list; addr_list = addr_list->next)
Simon Kelley79aba0f2020-02-03 23:58:45 +00001699 {
Simon Kelley137286e2020-02-06 22:09:30 +00001700 prefix = (addr_list->flags & ADDRLIST_PREFIX) ? addr_list->prefixlen : 128;
1701 wild_addr = addr_list->addr.addr6;
Simon Kelley79aba0f2020-02-03 23:58:45 +00001702
Simon Kelley137286e2020-02-06 22:09:30 +00001703 if ((addr_list->flags & ADDRLIST_WILDCARD) && context->prefix == 64)
1704 {
1705 wild_addr = context->start6;
1706 setaddr6part(&wild_addr, addr6part(&addr_list->addr.addr6));
1707 }
1708 else if (!is_same_net6(&context->start6, addr, context->prefix))
1709 continue;
1710
1711 if (is_same_net6(&wild_addr, addr, prefix))
Simon Kelleyc125c1d2020-03-05 17:10:14 +00001712 return addr_list;
Simon Kelley79aba0f2020-02-03 23:58:45 +00001713 }
1714
Simon Kelleyc125c1d2020-03-05 17:10:14 +00001715 return NULL;
Simon Kelley79aba0f2020-02-03 23:58:45 +00001716}
1717
Simon Kelleyc125c1d2020-03-05 17:10:14 +00001718static int config_valid(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr, struct state *state, time_t now)
Simon Kelley79aba0f2020-02-03 23:58:45 +00001719{
Simon Kelleyf0641882020-02-10 21:25:12 +00001720 u64 addrpart, i, addresses;
Simon Kelley137286e2020-02-06 22:09:30 +00001721 struct addrlist *addr_list;
1722
Simon Kelley79aba0f2020-02-03 23:58:45 +00001723 if (!config || !(config->flags & CONFIG_ADDR6))
1724 return 0;
1725
Simon Kelley137286e2020-02-06 22:09:30 +00001726 for (addr_list = config->addr6; addr_list; addr_list = addr_list->next)
Kevin Darbyshire-Bryantb594e8d2020-03-06 10:31:17 +00001727 if (!(addr_list->flags & ADDRLIST_DECLINED) ||
Simon Kelleyc125c1d2020-03-05 17:10:14 +00001728 difftime(now, addr_list->decline_time) >= (float)DECLINE_BACKOFF)
1729 {
1730 addrpart = addr6part(&addr_list->addr.addr6);
1731 addresses = 1;
1732
1733 if (addr_list->flags & ADDRLIST_PREFIX)
Petr Menšík46bdfe62020-03-08 15:56:19 +00001734 addresses = (u64)1<<(128-addr_list->prefixlen);
Simon Kelleyc125c1d2020-03-05 17:10:14 +00001735
1736 if ((addr_list->flags & ADDRLIST_WILDCARD))
1737 {
1738 if (context->prefix != 64)
1739 continue;
1740
1741 *addr = context->start6;
1742 }
1743 else if (is_same_net6(&context->start6, &addr_list->addr.addr6, context->prefix))
1744 *addr = addr_list->addr.addr6;
1745 else
1746 continue;
1747
1748 for (i = 0 ; i < addresses; i++)
1749 {
1750 setaddr6part(addr, addrpart+i);
1751
1752 if (check_address(state, addr))
1753 return 1;
1754 }
1755 }
1756
Simon Kelley137286e2020-02-06 22:09:30 +00001757 return 0;
Simon Kelley79aba0f2020-02-03 23:58:45 +00001758}
1759
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001760/* Calculate valid and preferred times to send in leases/renewals.
1761
1762 Inputs are:
1763
1764 *valid_timep, *preferred_timep - requested times from IAADDR options.
1765 context->valid, context->preferred - times associated with subnet address on local interface.
1766 context->flags | CONTEXT_DEPRECATE - "deprecated" flag in dhcp-range.
1767 lease_time - configured time for context for individual client.
1768 *min_time - smallest valid time sent so far.
1769
1770 Outputs are :
1771
1772 *valid_timep, *preferred_timep - times to be send in IAADDR option.
1773 *min_time - smallest valid time sent so far, to calculate T1 and T2.
1774
1775 */
Simon Kelleyde92b472013-03-15 18:25:10 +00001776static void calculate_times(struct dhcp_context *context, unsigned int *min_time, unsigned int *valid_timep,
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001777 unsigned int *preferred_timep, unsigned int lease_time)
Simon Kelleyde92b472013-03-15 18:25:10 +00001778{
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001779 unsigned int req_preferred = *preferred_timep, req_valid = *valid_timep;
1780 unsigned int valid_time = lease_time, preferred_time = lease_time;
1781
1782 /* RFC 3315: "A server ignores the lifetimes set
1783 by the client if the preferred lifetime is greater than the valid
1784 lifetime. */
1785 if (req_preferred <= req_valid)
1786 {
1787 if (req_preferred != 0)
1788 {
1789 /* 0 == "no preference from client" */
1790 if (req_preferred < 120u)
1791 req_preferred = 120u; /* sanity */
1792
1793 if (req_preferred < preferred_time)
1794 preferred_time = req_preferred;
1795 }
1796
1797 if (req_valid != 0)
1798 /* 0 == "no preference from client" */
1799 {
1800 if (req_valid < 120u)
1801 req_valid = 120u; /* sanity */
1802
1803 if (req_valid < valid_time)
1804 valid_time = req_valid;
1805 }
1806 }
Simon Kelleyde92b472013-03-15 18:25:10 +00001807
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001808 /* deprecate (preferred == 0) which configured, or when local address
1809 is deprecated */
1810 if ((context->flags & CONTEXT_DEPRECATE) || context->preferred == 0)
Simon Kelleyde92b472013-03-15 18:25:10 +00001811 preferred_time = 0;
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001812
Simon Kelleyde92b472013-03-15 18:25:10 +00001813 if (preferred_time != 0 && preferred_time < *min_time)
1814 *min_time = preferred_time;
1815
1816 if (valid_time != 0 && valid_time < *min_time)
1817 *min_time = valid_time;
1818
1819 *valid_timep = valid_time;
1820 *preferred_timep = preferred_time;
1821}
1822
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001823static void update_leases(struct state *state, struct dhcp_context *context, struct in6_addr *addr, unsigned int lease_time, time_t now)
1824{
1825 struct dhcp_lease *lease = lease6_find_by_addr(addr, 128, 0);
Vladislav Grishenko408c3682013-09-24 16:18:49 +01001826#ifdef HAVE_SCRIPT
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001827 struct dhcp_netid *tagif = run_tag_if(state->tags);
Vladislav Grishenko408c3682013-09-24 16:18:49 +01001828#endif
1829
1830 (void)context;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001831
1832 if (!lease)
1833 lease = lease6_allocate(addr, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA);
1834
1835 if (lease)
1836 {
1837 lease_set_expires(lease, lease_time, now);
Simon Kelley89500e32013-09-20 16:29:20 +01001838 lease_set_iaid(lease, state->iaid);
1839 lease_set_hwaddr(lease, state->mac, state->clid, state->mac_len, state->mac_type, state->clid_len, now, 0);
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001840 lease_set_interface(lease, state->interface, now);
1841 if (state->hostname && state->ia_type == OPTION6_IA_NA)
1842 {
1843 char *addr_domain = get_domain6(addr);
1844 if (!state->send_domain)
1845 state->send_domain = addr_domain;
1846 lease_set_hostname(lease, state->hostname, state->hostname_auth, addr_domain, state->domain);
1847 }
1848
1849#ifdef HAVE_SCRIPT
1850 if (daemon->lease_change_command)
1851 {
1852 void *class_opt;
1853 lease->flags |= LEASE_CHANGED;
1854 free(lease->extradata);
1855 lease->extradata = NULL;
1856 lease->extradata_size = lease->extradata_len = 0;
Simon Kelley6f9aaa92013-04-10 10:25:26 +01001857 lease->vendorclass_count = 0;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001858
1859 if ((class_opt = opt6_find(state->packet_options, state->end, OPTION6_VENDOR_CLASS, 4)))
1860 {
1861 void *enc_opt, *enc_end = opt6_ptr(class_opt, opt6_len(class_opt));
Simon Kelley6f9aaa92013-04-10 10:25:26 +01001862 lease->vendorclass_count++;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001863 /* send enterprise number first */
1864 sprintf(daemon->dhcp_buff2, "%u", opt6_uint(class_opt, 0, 4));
1865 lease_add_extradata(lease, (unsigned char *)daemon->dhcp_buff2, strlen(daemon->dhcp_buff2), 0);
1866
1867 if (opt6_len(class_opt) >= 6)
1868 for (enc_opt = opt6_ptr(class_opt, 4); enc_opt; enc_opt = opt6_next(enc_opt, enc_end))
1869 {
Simon Kelley6f9aaa92013-04-10 10:25:26 +01001870 lease->vendorclass_count++;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001871 lease_add_extradata(lease, opt6_ptr(enc_opt, 0), opt6_len(enc_opt), 0);
1872 }
1873 }
1874
1875 lease_add_extradata(lease, (unsigned char *)state->client_hostname,
1876 state->client_hostname ? strlen(state->client_hostname) : 0, 0);
1877
1878 /* space-concat tag set */
1879 if (!tagif && !context->netid.net)
1880 lease_add_extradata(lease, NULL, 0, 0);
1881 else
1882 {
1883 if (context->netid.net)
1884 lease_add_extradata(lease, (unsigned char *)context->netid.net, strlen(context->netid.net), tagif ? ' ' : 0);
1885
1886 if (tagif)
1887 {
1888 struct dhcp_netid *n;
1889 for (n = tagif; n; n = n->next)
1890 {
1891 struct dhcp_netid *n1;
1892 /* kill dupes */
1893 for (n1 = n->next; n1; n1 = n1->next)
1894 if (strcmp(n->net, n1->net) == 0)
1895 break;
1896 if (!n1)
1897 lease_add_extradata(lease, (unsigned char *)n->net, strlen(n->net), n->next ? ' ' : 0);
1898 }
1899 }
1900 }
1901
1902 if (state->link_address)
1903 inet_ntop(AF_INET6, state->link_address, daemon->addrbuff, ADDRSTRLEN);
1904
1905 lease_add_extradata(lease, (unsigned char *)daemon->addrbuff, state->link_address ? strlen(daemon->addrbuff) : 0, 0);
1906
1907 if ((class_opt = opt6_find(state->packet_options, state->end, OPTION6_USER_CLASS, 2)))
1908 {
1909 void *enc_opt, *enc_end = opt6_ptr(class_opt, opt6_len(class_opt));
1910 for (enc_opt = opt6_ptr(class_opt, 0); enc_opt; enc_opt = opt6_next(enc_opt, enc_end))
1911 lease_add_extradata(lease, opt6_ptr(enc_opt, 0), opt6_len(enc_opt), 0);
1912 }
1913 }
1914#endif
1915
1916 }
1917}
1918
1919
1920
Simon Kelley6c8f21e2012-03-12 15:06:55 +00001921static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_opts)
1922{
1923 void *opt;
1924 char *desc = nest ? "nest" : "sent";
Simon Kelley5cfea3d2012-03-12 17:28:27 +00001925
Simon Kelleyd81b42d2013-09-23 12:26:34 +01001926 if (!option_bool(OPT_LOG_OPTS) || start_opts == end_opts)
Simon Kelley5cfea3d2012-03-12 17:28:27 +00001927 return;
1928
1929 for (opt = start_opts; opt; opt = opt6_next(opt, end_opts))
1930 {
1931 int type = opt6_type(opt);
1932 void *ia_options = NULL;
1933 char *optname;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001934
Simon Kelley5cfea3d2012-03-12 17:28:27 +00001935 if (type == OPTION6_IA_NA)
1936 {
1937 sprintf(daemon->namebuff, "IAID=%u T1=%u T2=%u",
1938 opt6_uint(opt, 0, 4), opt6_uint(opt, 4, 4), opt6_uint(opt, 8, 4));
1939 optname = "ia-na";
1940 ia_options = opt6_ptr(opt, 12);
1941 }
1942 else if (type == OPTION6_IA_TA)
1943 {
1944 sprintf(daemon->namebuff, "IAID=%u", opt6_uint(opt, 0, 4));
1945 optname = "ia-ta";
1946 ia_options = opt6_ptr(opt, 4);
1947 }
1948 else if (type == OPTION6_IAADDR)
1949 {
Simon Kelley97f876b2018-08-21 22:06:36 +01001950 struct in6_addr addr;
1951
1952 /* align */
1953 memcpy(&addr, opt6_ptr(opt, 0), IN6ADDRSZ);
1954 inet_ntop(AF_INET6, &addr, daemon->addrbuff, ADDRSTRLEN);
Simon Kelley5cfea3d2012-03-12 17:28:27 +00001955 sprintf(daemon->namebuff, "%s PL=%u VL=%u",
1956 daemon->addrbuff, opt6_uint(opt, 16, 4), opt6_uint(opt, 20, 4));
1957 optname = "iaaddr";
1958 ia_options = opt6_ptr(opt, 24);
1959 }
1960 else if (type == OPTION6_STATUS_CODE)
1961 {
1962 int len = sprintf(daemon->namebuff, "%u ", opt6_uint(opt, 0, 2));
1963 memcpy(daemon->namebuff + len, opt6_ptr(opt, 2), opt6_len(opt)-2);
1964 daemon->namebuff[len + opt6_len(opt) - 2] = 0;
1965 optname = "status";
1966 }
1967 else
1968 {
1969 /* account for flag byte on FQDN */
1970 int offset = type == OPTION6_FQDN ? 1 : 0;
1971 optname = option_string(AF_INET6, type, opt6_ptr(opt, offset), opt6_len(opt) - offset, daemon->namebuff, MAXDNAME);
1972 }
1973
1974 my_syslog(MS_DHCP | LOG_INFO, "%u %s size:%3d option:%3d %s %s",
1975 xid, desc, opt6_len(opt), type, optname, daemon->namebuff);
1976
1977 if (ia_options)
1978 log6_opts(1, xid, ia_options, opt6_ptr(opt, opt6_len(opt)));
1979 }
Simon Kelley6c8f21e2012-03-12 15:06:55 +00001980}
1981
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01001982static void log6_quiet(struct state *state, char *type, struct in6_addr *addr, char *string)
1983{
1984 if (option_bool(OPT_LOG_OPTS) || !option_bool(OPT_QUIET_DHCP6))
1985 log6_packet(state, type, addr, string);
1986}
1987
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001988static void log6_packet(struct state *state, char *type, struct in6_addr *addr, char *string)
Simon Kelley4cb1b322012-02-06 14:30:41 +00001989{
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001990 int clid_len = state->clid_len;
1991
Simon Kelley4cb1b322012-02-06 14:30:41 +00001992 /* avoid buffer overflow */
1993 if (clid_len > 100)
1994 clid_len = 100;
1995
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001996 print_mac(daemon->namebuff, state->clid, clid_len);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001997
1998 if (addr)
1999 {
Simon Kelleybf4e62c2016-07-22 21:37:59 +01002000 inet_ntop(AF_INET6, addr, daemon->dhcp_buff2, DHCP_BUFF_SZ - 1);
Simon Kelley4cb1b322012-02-06 14:30:41 +00002001 strcat(daemon->dhcp_buff2, " ");
2002 }
2003 else
2004 daemon->dhcp_buff2[0] = 0;
2005
2006 if(option_bool(OPT_LOG_OPTS))
Simon Kelley58dc02e2012-02-27 11:49:37 +00002007 my_syslog(MS_DHCP | LOG_INFO, "%u %s(%s) %s%s %s",
Simon Kelleya6ebfac2013-03-06 20:52:35 +00002008 state->xid,
Simon Kelley4cb1b322012-02-06 14:30:41 +00002009 type,
Simon Kelleya6ebfac2013-03-06 20:52:35 +00002010 state->iface_name,
Simon Kelley4cb1b322012-02-06 14:30:41 +00002011 daemon->dhcp_buff2,
Simon Kelley58dc02e2012-02-27 11:49:37 +00002012 daemon->namebuff,
Simon Kelley4cb1b322012-02-06 14:30:41 +00002013 string ? string : "");
2014 else
Simon Kelley58dc02e2012-02-27 11:49:37 +00002015 my_syslog(MS_DHCP | LOG_INFO, "%s(%s) %s%s %s",
Simon Kelley4cb1b322012-02-06 14:30:41 +00002016 type,
Simon Kelleya6ebfac2013-03-06 20:52:35 +00002017 state->iface_name,
Simon Kelley4cb1b322012-02-06 14:30:41 +00002018 daemon->dhcp_buff2,
Simon Kelley58dc02e2012-02-27 11:49:37 +00002019 daemon->namebuff,
Simon Kelley4cb1b322012-02-06 14:30:41 +00002020 string ? string : "");
2021}
2022
2023static void *opt6_find (void *opts, void *end, unsigned int search, unsigned int minsize)
Simon Kelleyc72daea2012-01-05 21:33:27 +00002024{
2025 u16 opt, opt_len;
2026 void *start;
2027
2028 if (!opts)
2029 return NULL;
2030
2031 while (1)
2032 {
2033 if (end - opts < 4)
2034 return NULL;
2035
2036 start = opts;
2037 GETSHORT(opt, opts);
2038 GETSHORT(opt_len, opts);
2039
2040 if (opt_len > (end - opts))
2041 return NULL;
2042
2043 if (opt == search && (opt_len >= minsize))
2044 return start;
2045
2046 opts += opt_len;
2047 }
2048}
2049
Simon Kelley4cb1b322012-02-06 14:30:41 +00002050static void *opt6_next(void *opts, void *end)
Simon Kelleyc72daea2012-01-05 21:33:27 +00002051{
2052 u16 opt_len;
2053
2054 if (end - opts < 4)
2055 return NULL;
2056
2057 opts += 2;
2058 GETSHORT(opt_len, opts);
2059
2060 if (opt_len >= (end - opts))
2061 return NULL;
2062
2063 return opts + opt_len;
2064}
Simon Kelleyc72daea2012-01-05 21:33:27 +00002065
2066static unsigned int opt6_uint(unsigned char *opt, int offset, int size)
2067{
2068 /* this worries about unaligned data and byte order */
2069 unsigned int ret = 0;
2070 int i;
2071 unsigned char *p = opt6_ptr(opt, offset);
2072
2073 for (i = 0; i < size; i++)
2074 ret = (ret << 8) | *p++;
2075
2076 return ret;
Simon Kelley4cb1b322012-02-06 14:30:41 +00002077}
Simon Kelleyc72daea2012-01-05 21:33:27 +00002078
Simon Kelley33702ab2015-12-28 23:17:15 +00002079void relay_upstream6(struct dhcp_relay *relay, ssize_t sz,
2080 struct in6_addr *peer_address, u32 scope_id, time_t now)
Simon Kelleyff7eea22013-09-04 18:01:38 +01002081{
2082 /* ->local is same value for all relays on ->current chain */
2083
Simon Kelleycc921df2019-01-02 22:48:59 +00002084 union all_addr from;
Simon Kelleyff7eea22013-09-04 18:01:38 +01002085 unsigned char *header;
2086 unsigned char *inbuff = daemon->dhcp_packet.iov_base;
2087 int msg_type = *inbuff;
2088 int hopcount;
2089 struct in6_addr multicast;
Simon Kelley8939c952013-09-25 11:49:34 +01002090 unsigned int maclen, mactype;
2091 unsigned char mac[DHCP_CHADDR_MAX];
Simon Kelleyff7eea22013-09-04 18:01:38 +01002092
2093 inet_pton(AF_INET6, ALL_SERVERS, &multicast);
Simon Kelley33702ab2015-12-28 23:17:15 +00002094 get_client_mac(peer_address, scope_id, mac, &maclen, &mactype, now);
Simon Kelley8939c952013-09-25 11:49:34 +01002095
Simon Kelleyff7eea22013-09-04 18:01:38 +01002096 /* source address == relay address */
Simon Kelleycc921df2019-01-02 22:48:59 +00002097 from.addr6 = relay->local.addr6;
Simon Kelleyff7eea22013-09-04 18:01:38 +01002098
2099 /* Get hop count from nested relayed message */
2100 if (msg_type == DHCP6RELAYFORW)
2101 hopcount = *((unsigned char *)inbuff+1) + 1;
2102 else
2103 hopcount = 0;
2104
2105 /* RFC 3315 HOP_COUNT_LIMIT */
2106 if (hopcount > 32)
2107 return;
2108
Simon Kelleyfa785732016-07-22 20:56:01 +01002109 reset_counter();
Simon Kelleyff7eea22013-09-04 18:01:38 +01002110
2111 if ((header = put_opt6(NULL, 34)))
2112 {
2113 int o;
2114
2115 header[0] = DHCP6RELAYFORW;
2116 header[1] = hopcount;
Simon Kelleycc921df2019-01-02 22:48:59 +00002117 memcpy(&header[2], &relay->local.addr6, IN6ADDRSZ);
Simon Kelleyff7eea22013-09-04 18:01:38 +01002118 memcpy(&header[18], peer_address, IN6ADDRSZ);
Simon Kelley89500e32013-09-20 16:29:20 +01002119
2120 /* RFC-6939 */
Simon Kelley8939c952013-09-25 11:49:34 +01002121 if (maclen != 0)
Simon Kelley89500e32013-09-20 16:29:20 +01002122 {
2123 o = new_opt6(OPTION6_CLIENT_MAC);
Simon Kelley8939c952013-09-25 11:49:34 +01002124 put_opt6_short(mactype);
2125 put_opt6(mac, maclen);
Simon Kelley89500e32013-09-20 16:29:20 +01002126 end_opt6(o);
2127 }
Simon Kelleyff7eea22013-09-04 18:01:38 +01002128
2129 o = new_opt6(OPTION6_RELAY_MSG);
2130 put_opt6(inbuff, sz);
2131 end_opt6(o);
2132
2133 for (; relay; relay = relay->current)
2134 {
2135 union mysockaddr to;
2136
2137 to.sa.sa_family = AF_INET6;
Simon Kelleycc921df2019-01-02 22:48:59 +00002138 to.in6.sin6_addr = relay->server.addr6;
Simon Kelleyff7eea22013-09-04 18:01:38 +01002139 to.in6.sin6_port = htons(DHCPV6_SERVER_PORT);
2140 to.in6.sin6_flowinfo = 0;
2141 to.in6.sin6_scope_id = 0;
2142
Simon Kelleycc921df2019-01-02 22:48:59 +00002143 if (IN6_ARE_ADDR_EQUAL(&relay->server.addr6, &multicast))
Simon Kelleyff7eea22013-09-04 18:01:38 +01002144 {
2145 int multicast_iface;
2146 if (!relay->interface || strchr(relay->interface, '*') ||
2147 (multicast_iface = if_nametoindex(relay->interface)) == 0 ||
2148 setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &multicast_iface, sizeof(multicast_iface)) == -1)
2149 my_syslog(MS_DHCP | LOG_ERR, _("Cannot multicast to DHCPv6 server without correct interface"));
2150 }
2151
Simon Kelley6b1c4642016-07-22 20:59:16 +01002152 send_from(daemon->dhcp6fd, 0, daemon->outpacket.iov_base, save_counter(-1), &to, &from, 0);
Simon Kelleyff7eea22013-09-04 18:01:38 +01002153
2154 if (option_bool(OPT_LOG_OPTS))
2155 {
2156 inet_ntop(AF_INET6, &relay->local, daemon->addrbuff, ADDRSTRLEN);
2157 inet_ntop(AF_INET6, &relay->server, daemon->namebuff, ADDRSTRLEN);
2158 my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay %s -> %s"), daemon->addrbuff, daemon->namebuff);
2159 }
2160
2161 /* Save this for replies */
2162 relay->iface_index = scope_id;
2163 }
2164 }
2165}
2166
2167unsigned short relay_reply6(struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface)
2168{
2169 struct dhcp_relay *relay;
2170 struct in6_addr link;
2171 unsigned char *inbuff = daemon->dhcp_packet.iov_base;
2172
2173 /* must have at least msg_type+hopcount+link_address+peer_address+minimal size option
2174 which is 1 + 1 + 16 + 16 + 2 + 2 = 38 */
2175
2176 if (sz < 38 || *inbuff != DHCP6RELAYREPL)
2177 return 0;
2178
2179 memcpy(&link, &inbuff[2], IN6ADDRSZ);
2180
2181 for (relay = daemon->relay6; relay; relay = relay->next)
Simon Kelleycc921df2019-01-02 22:48:59 +00002182 if (IN6_ARE_ADDR_EQUAL(&link, &relay->local.addr6) &&
Simon Kelleyff7eea22013-09-04 18:01:38 +01002183 (!relay->interface || wildcard_match(relay->interface, arrival_interface)))
2184 break;
2185
Simon Kelleyfa785732016-07-22 20:56:01 +01002186 reset_counter();
Simon Kelleyff7eea22013-09-04 18:01:38 +01002187
2188 if (relay)
2189 {
2190 void *opt, *opts = inbuff + 34;
2191 void *end = inbuff + sz;
2192 for (opt = opts; opt; opt = opt6_next(opt, end))
2193 if (opt6_type(opt) == OPTION6_RELAY_MSG && opt6_len(opt) > 0)
2194 {
2195 int encap_type = *((unsigned char *)opt6_ptr(opt, 0));
2196 put_opt6(opt6_ptr(opt, 0), opt6_len(opt));
2197 memcpy(&peer->sin6_addr, &inbuff[18], IN6ADDRSZ);
2198 peer->sin6_scope_id = relay->iface_index;
2199 return encap_type == DHCP6RELAYREPL ? DHCPV6_SERVER_PORT : DHCPV6_CLIENT_PORT;
2200 }
2201 }
2202
2203 return 0;
2204}
2205
Simon Kelleyc72daea2012-01-05 21:33:27 +00002206#endif