blob: 2e611b314705284d367b8a5c7344e97219ec228a [file] [log] [blame]
Simon Kelley2a8710a2020-01-05 16:40:06 +00001/* dnsmasq is Copyright (c) 2000-2020 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 Kelley79aba0f2020-02-03 23:58:45 +000052static int config_valid(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr, struct state *state);
53static int 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 Kelley79aba0f2020-02-03 23:58:45 +0000682 if (!(c->flags & CONTEXT_CONF_USED) && config_valid(config, c, &addr, state))
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 Kelley79aba0f2020-02-03 23:58:45 +0000706 config_valid(config, c, &addr, state))
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 Kelley79aba0f2020-02-03 23:58:45 +0000850 config_ok = config_implies(config, c, &req_addr);
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 Kelley70c5e3e2012-02-06 22:05:15 +00001189
Simon Kelley97f876b2018-08-21 22:06:36 +01001190 /* align */
1191 memcpy(&addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
1192
1193 if (have_config(config, CONFIG_ADDR6) && IN6_ARE_ADDR_EQUAL(&config->addr6, &addr))
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001194 {
Simon Kelleyceae00d2012-02-09 21:28:14 +00001195 prettyprint_time(daemon->dhcp_buff3, DECLINE_BACKOFF);
Simon Kelley97f876b2018-08-21 22:06:36 +01001196 inet_ntop(AF_INET6, &addr, daemon->addrbuff, ADDRSTRLEN);
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001197 my_syslog(MS_DHCP | LOG_WARNING, _("disabling DHCP static address %s for %s"),
Simon Kelleyceae00d2012-02-09 21:28:14 +00001198 daemon->addrbuff, daemon->dhcp_buff3);
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001199 config->flags |= CONFIG_DECLINED;
1200 config->decline_time = now;
1201 }
1202 else
1203 /* make sure this host gets a different address next time. */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001204 for (context_tmp = state->context; context_tmp; context_tmp = context_tmp->current)
1205 context_tmp->addr_epoch++;
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001206
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001207 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 +01001208 state->iaid, &addr)))
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001209 lease_prune(lease, now);
1210 else
1211 {
1212 if (!made_ia)
1213 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001214 o = new_opt6(state->ia_type);
1215 put_opt6_long(state->iaid);
1216 if (state->ia_type == OPTION6_IA_NA)
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001217 {
1218 put_opt6_long(0);
1219 put_opt6_long(0);
1220 }
1221 made_ia = 1;
1222 }
1223
1224 o1 = new_opt6(OPTION6_IAADDR);
Simon Kelley97f876b2018-08-21 22:06:36 +01001225 put_opt6(&addr, IN6ADDRSZ);
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001226 put_opt6_long(0);
1227 put_opt6_long(0);
1228 end_opt6(o1);
1229 }
1230 }
1231
1232 if (made_ia)
1233 {
1234 o1 = new_opt6(OPTION6_STATUS_CODE);
1235 put_opt6_short(DHCP6NOBINDING);
Simon Kelleyde92b472013-03-15 18:25:10 +00001236 put_opt6_string(_("no binding found"));
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001237 end_opt6(o1);
1238
1239 end_opt6(o);
1240 }
1241
1242 }
Ilya Ponetaev51943362014-09-13 21:19:01 +01001243
Josh Soref730c6742017-02-06 16:14:04 +00001244 /* We must answer with 'success' in global section anyway */
Ilya Ponetaev51943362014-09-13 21:19:01 +01001245 o1 = new_opt6(OPTION6_STATUS_CODE);
1246 put_opt6_short(DHCP6SUCCESS);
1247 put_opt6_string(_("success"));
1248 end_opt6(o1);
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001249 break;
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001250 }
1251
Simon Kelley4cb1b322012-02-06 14:30:41 +00001252 }
1253
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001254 log_tags(tagif, state->xid);
1255 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 +00001256
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001257 return 1;
1258
1259}
1260
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001261static struct dhcp_netid *add_options(struct state *state, int do_refresh)
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001262{
Simon Kelley2763d4b2013-03-06 21:24:56 +00001263 void *oro;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001264 /* filter options based on tags, those we want get DHOPT_TAGOK bit set */
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001265 struct dhcp_netid *tagif = option_filter(state->tags, state->context_tags, daemon->dhcp_opts6);
1266 struct dhcp_opt *opt_cfg;
Simon Kelley871d4562013-07-27 21:32:32 +01001267 int done_dns = 0, done_refresh = !do_refresh, do_encap = 0;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001268 int i, o, o1;
1269
1270 oro = opt6_find(state->packet_options, state->end, OPTION6_ORO, 0);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001271
1272 for (opt_cfg = daemon->dhcp_opts6; opt_cfg; opt_cfg = opt_cfg->next)
1273 {
1274 /* netids match and not encapsulated? */
1275 if (!(opt_cfg->flags & DHOPT_TAGOK))
1276 continue;
1277
1278 if (!(opt_cfg->flags & DHOPT_FORCE) && oro)
1279 {
1280 for (i = 0; i < opt6_len(oro) - 1; i += 2)
1281 if (opt6_uint(oro, i, 2) == (unsigned)opt_cfg->opt)
1282 break;
1283
1284 /* option not requested */
1285 if (i >= opt6_len(oro) - 1)
1286 continue;
1287 }
1288
Simon Kelley871d4562013-07-27 21:32:32 +01001289 if (opt_cfg->opt == OPTION6_REFRESH_TIME)
1290 done_refresh = 1;
Simon Kelley5e3e4642015-08-25 23:08:39 +01001291
1292 if (opt_cfg->opt == OPTION6_DNS_SERVER)
1293 done_dns = 1;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001294
Simon Kelley27b78d92015-09-26 21:40:45 +01001295 if (opt_cfg->flags & DHOPT_ADDR6)
Simon Kelley4b86b652012-02-29 11:45:37 +00001296 {
Simon Kelleyc3a04082014-01-11 22:18:19 +00001297 int len, j;
1298 struct in6_addr *a;
1299
Simon Kelleyc3a04082014-01-11 22:18:19 +00001300 for (a = (struct in6_addr *)opt_cfg->val, len = opt_cfg->len, j = 0;
1301 j < opt_cfg->len; j += IN6ADDRSZ, a++)
1302 if ((IN6_IS_ADDR_ULA_ZERO(a) && IN6_IS_ADDR_UNSPECIFIED(state->ula_addr)) ||
1303 (IN6_IS_ADDR_LINK_LOCAL_ZERO(a) && IN6_IS_ADDR_UNSPECIFIED(state->ll_addr)))
1304 len -= IN6ADDRSZ;
1305
1306 if (len != 0)
1307 {
1308
1309 o = new_opt6(opt_cfg->opt);
1310
1311 for (a = (struct in6_addr *)opt_cfg->val, j = 0; j < opt_cfg->len; j+=IN6ADDRSZ, a++)
1312 {
1313 if (IN6_IS_ADDR_UNSPECIFIED(a))
1314 {
1315 if (!add_local_addrs(state->context))
1316 put_opt6(state->fallback, IN6ADDRSZ);
1317 }
1318 else if (IN6_IS_ADDR_ULA_ZERO(a))
1319 {
1320 if (!IN6_IS_ADDR_UNSPECIFIED(state->ula_addr))
1321 put_opt6(state->ula_addr, IN6ADDRSZ);
1322 }
1323 else if (IN6_IS_ADDR_LINK_LOCAL_ZERO(a))
1324 {
1325 if (!IN6_IS_ADDR_UNSPECIFIED(state->ll_addr))
1326 put_opt6(state->ll_addr, IN6ADDRSZ);
1327 }
1328 else
1329 put_opt6(a, IN6ADDRSZ);
Simon Kelley4b86b652012-02-29 11:45:37 +00001330 }
Simon Kelleyc3a04082014-01-11 22:18:19 +00001331
1332 end_opt6(o);
1333 }
Simon Kelley4b86b652012-02-29 11:45:37 +00001334 }
Simon Kelleyc3a04082014-01-11 22:18:19 +00001335 else
1336 {
1337 o = new_opt6(opt_cfg->opt);
1338 if (opt_cfg->val)
1339 put_opt6(opt_cfg->val, opt_cfg->len);
1340 end_opt6(o);
1341 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001342 }
1343
Simon Kelley871d4562013-07-27 21:32:32 +01001344 if (daemon->port == NAMESERVER_PORT && !done_dns)
Simon Kelley4cb1b322012-02-06 14:30:41 +00001345 {
1346 o = new_opt6(OPTION6_DNS_SERVER);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001347 if (!add_local_addrs(state->context))
1348 put_opt6(state->fallback, IN6ADDRSZ);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001349 end_opt6(o);
1350 }
Simon Kelley871d4562013-07-27 21:32:32 +01001351
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001352 if (state->context && !done_refresh)
Simon Kelley871d4562013-07-27 21:32:32 +01001353 {
1354 struct dhcp_context *c;
1355 unsigned int lease_time = 0xffffffff;
1356
1357 /* Find the smallest lease tie of all contexts,
Josh Soref730c6742017-02-06 16:14:04 +00001358 subject to the RFC-4242 stipulation that this must not
Simon Kelley871d4562013-07-27 21:32:32 +01001359 be less than 600. */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001360 for (c = state->context; c; c = c->next)
Simon Kelley871d4562013-07-27 21:32:32 +01001361 if (c->lease_time < lease_time)
1362 {
1363 if (c->lease_time < 600)
1364 lease_time = 600;
1365 else
1366 lease_time = c->lease_time;
1367 }
1368
1369 o = new_opt6(OPTION6_REFRESH_TIME);
1370 put_opt6_long(lease_time);
1371 end_opt6(o);
1372 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001373
1374 /* handle vendor-identifying vendor-encapsulated options,
1375 dhcp-option = vi-encap:13,17,....... */
1376 for (opt_cfg = daemon->dhcp_opts6; opt_cfg; opt_cfg = opt_cfg->next)
1377 opt_cfg->flags &= ~DHOPT_ENCAP_DONE;
Simon Kelley4b86b652012-02-29 11:45:37 +00001378
Simon Kelley4cb1b322012-02-06 14:30:41 +00001379 if (oro)
1380 for (i = 0; i < opt6_len(oro) - 1; i += 2)
1381 if (opt6_uint(oro, i, 2) == OPTION6_VENDOR_OPTS)
1382 do_encap = 1;
1383
1384 for (opt_cfg = daemon->dhcp_opts6; opt_cfg; opt_cfg = opt_cfg->next)
1385 {
1386 if (opt_cfg->flags & DHOPT_RFC3925)
1387 {
1388 int found = 0;
1389 struct dhcp_opt *oc;
1390
1391 if (opt_cfg->flags & DHOPT_ENCAP_DONE)
1392 continue;
1393
1394 for (oc = daemon->dhcp_opts6; oc; oc = oc->next)
1395 {
1396 oc->flags &= ~DHOPT_ENCAP_MATCH;
1397
1398 if (!(oc->flags & DHOPT_RFC3925) || opt_cfg->u.encap != oc->u.encap)
1399 continue;
1400
1401 oc->flags |= DHOPT_ENCAP_DONE;
1402 if (match_netid(oc->netid, tagif, 1))
1403 {
1404 /* option requested/forced? */
1405 if (!oro || do_encap || (oc->flags & DHOPT_FORCE))
1406 {
1407 oc->flags |= DHOPT_ENCAP_MATCH;
1408 found = 1;
1409 }
1410 }
1411 }
1412
1413 if (found)
1414 {
1415 o = new_opt6(OPTION6_VENDOR_OPTS);
1416 put_opt6_long(opt_cfg->u.encap);
1417
1418 for (oc = daemon->dhcp_opts6; oc; oc = oc->next)
1419 if (oc->flags & DHOPT_ENCAP_MATCH)
1420 {
1421 o1 = new_opt6(oc->opt);
1422 put_opt6(oc->val, oc->len);
1423 end_opt6(o1);
1424 }
1425 end_opt6(o);
1426 }
1427 }
1428 }
Simon Kelley07933802012-02-14 20:55:25 +00001429
1430
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001431 if (state->hostname)
Simon Kelley4cb1b322012-02-06 14:30:41 +00001432 {
1433 unsigned char *p;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001434 size_t len = strlen(state->hostname);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001435
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001436 if (state->send_domain)
Roy Marples3f3adae2013-07-25 16:22:46 +01001437 len += strlen(state->send_domain) + 2;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001438
1439 o = new_opt6(OPTION6_FQDN);
Roy Marples3f3adae2013-07-25 16:22:46 +01001440 if ((p = expand(len + 2)))
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001441 {
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001442 *(p++) = state->fqdn_flags;
Simon Kelley0549c732017-09-25 18:17:11 +01001443 p = do_rfc1035_name(p, state->hostname, NULL);
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001444 if (state->send_domain)
Roy Marples3f3adae2013-07-25 16:22:46 +01001445 {
Simon Kelley0549c732017-09-25 18:17:11 +01001446 p = do_rfc1035_name(p, state->send_domain, NULL);
Roy Marples3f3adae2013-07-25 16:22:46 +01001447 *p = 0;
1448 }
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001449 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001450 end_opt6(o);
1451 }
1452
1453
1454 /* logging */
1455 if (option_bool(OPT_LOG_OPTS) && oro)
1456 {
1457 char *q = daemon->namebuff;
1458 for (i = 0; i < opt6_len(oro) - 1; i += 2)
1459 {
1460 char *s = option_string(AF_INET6, opt6_uint(oro, i, 2), NULL, 0, NULL, 0);
1461 q += snprintf(q, MAXDNAME - (q - daemon->namebuff),
1462 "%d%s%s%s",
1463 opt6_uint(oro, i, 2),
1464 strlen(s) != 0 ? ":" : "",
1465 s,
1466 (i > opt6_len(oro) - 3) ? "" : ", ");
1467 if ( i > opt6_len(oro) - 3 || (q - daemon->namebuff) > 40)
1468 {
1469 q = daemon->namebuff;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001470 my_syslog(MS_DHCP | LOG_INFO, _("%u requested options: %s"), state->xid, daemon->namebuff);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001471 }
1472 }
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001473 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001474
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001475 return tagif;
1476}
1477
1478static int add_local_addrs(struct dhcp_context *context)
1479{
1480 int done = 0;
Simon Kelley6c8f21e2012-03-12 15:06:55 +00001481
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001482 for (; context; context = context->current)
1483 if ((context->flags & CONTEXT_USED) && !IN6_IS_ADDR_UNSPECIFIED(&context->local6))
1484 {
1485 /* squash duplicates */
1486 struct dhcp_context *c;
1487 for (c = context->current; c; c = c->current)
1488 if ((c->flags & CONTEXT_USED) &&
1489 IN6_ARE_ADDR_EQUAL(&context->local6, &c->local6))
1490 break;
1491
1492 if (!c)
1493 {
1494 done = 1;
1495 put_opt6(&context->local6, IN6ADDRSZ);
1496 }
1497 }
1498
1499 return done;
Simon Kelley6c8f21e2012-03-12 15:06:55 +00001500}
1501
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001502
1503static void get_context_tag(struct state *state, struct dhcp_context *context)
1504{
1505 /* get tags from context if we've not used it before */
1506 if (context->netid.next == &context->netid && context->netid.net)
1507 {
1508 context->netid.next = state->context_tags;
1509 state->context_tags = &context->netid;
1510 if (!state->hostname_auth)
1511 {
1512 struct dhcp_netid_list *id_list;
1513
1514 for (id_list = daemon->dhcp_ignore_names; id_list; id_list = id_list->next)
1515 if ((!id_list->list) || match_netid(id_list->list, &context->netid, 0))
1516 break;
1517 if (id_list)
1518 state->hostname = NULL;
1519 }
1520 }
1521}
Simon Kelleyc6309242013-03-07 20:59:28 +00001522
Simon Kelley3a654c52013-03-06 22:17:48 +00001523static int check_ia(struct state *state, void *opt, void **endp, void **ia_option)
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001524{
1525 state->ia_type = opt6_type(opt);
Simon Kelley3a654c52013-03-06 22:17:48 +00001526 *ia_option = NULL;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001527
1528 if (state->ia_type != OPTION6_IA_NA && state->ia_type != OPTION6_IA_TA)
Simon Kelley3a654c52013-03-06 22:17:48 +00001529 return 0;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001530
1531 if (state->ia_type == OPTION6_IA_NA && opt6_len(opt) < 12)
Simon Kelley3a654c52013-03-06 22:17:48 +00001532 return 0;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001533
1534 if (state->ia_type == OPTION6_IA_TA && opt6_len(opt) < 4)
Simon Kelley3a654c52013-03-06 22:17:48 +00001535 return 0;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001536
1537 *endp = opt6_ptr(opt, opt6_len(opt));
1538 state->iaid = opt6_uint(opt, 0, 4);
Simon Kelley3a654c52013-03-06 22:17:48 +00001539 *ia_option = opt6_find(opt6_ptr(opt, state->ia_type == OPTION6_IA_NA ? 12 : 4), *endp, OPTION6_IAADDR, 24);
1540
1541 return 1;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001542}
1543
1544
1545static int build_ia(struct state *state, int *t1cntr)
1546{
1547 int o = new_opt6(state->ia_type);
1548
1549 put_opt6_long(state->iaid);
1550 *t1cntr = 0;
1551
1552 if (state->ia_type == OPTION6_IA_NA)
1553 {
1554 /* save pointer */
1555 *t1cntr = save_counter(-1);
1556 /* so we can fill these in later */
1557 put_opt6_long(0);
1558 put_opt6_long(0);
1559 }
1560
1561 return o;
1562}
1563
1564static void end_ia(int t1cntr, unsigned int min_time, int do_fuzz)
1565{
1566 if (t1cntr != 0)
1567 {
Ville Skyttäfaaf3062018-01-14 17:32:52 +00001568 /* go back and fill in fields in IA_NA option */
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001569 int sav = save_counter(t1cntr);
1570 unsigned int t1, t2, fuzz = 0;
1571
1572 if (do_fuzz)
1573 {
1574 fuzz = rand16();
1575
1576 while (fuzz > (min_time/16))
1577 fuzz = fuzz/2;
1578 }
1579
1580 t1 = (min_time == 0xffffffff) ? 0xffffffff : min_time/2 - fuzz;
1581 t2 = (min_time == 0xffffffff) ? 0xffffffff : ((min_time/8)*7) - fuzz;
1582 put_opt6_long(t1);
1583 put_opt6_long(t2);
1584 save_counter(sav);
1585 }
1586}
1587
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001588static void add_address(struct state *state, struct dhcp_context *context, unsigned int lease_time, void *ia_option,
Simon Kelleyc8f2dd82013-09-13 11:22:55 +01001589 unsigned int *min_time, struct in6_addr *addr, time_t now)
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001590{
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001591 unsigned int valid_time = 0, preferred_time = 0;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001592 int o = new_opt6(OPTION6_IAADDR);
1593 struct dhcp_lease *lease;
1594
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001595 /* get client requested times */
1596 if (ia_option)
1597 {
1598 preferred_time = opt6_uint(ia_option, 16, 4);
1599 valid_time = opt6_uint(ia_option, 20, 4);
1600 }
1601
1602 calculate_times(context, min_time, &valid_time, &preferred_time, lease_time);
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001603
Simon Kelleyde92b472013-03-15 18:25:10 +00001604 put_opt6(addr, sizeof(*addr));
1605 put_opt6_long(preferred_time);
1606 put_opt6_long(valid_time);
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001607 end_opt6(o);
1608
Simon Kelleyc8f2dd82013-09-13 11:22:55 +01001609 if (state->lease_allocate)
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001610 update_leases(state, context, addr, valid_time, now);
1611
1612 if ((lease = lease6_find_by_addr(addr, 128, 0)))
1613 lease->flags |= LEASE_USED;
1614
1615 /* get tags from context if we've not used it before */
1616 if (context->netid.next == &context->netid && context->netid.net)
1617 {
1618 context->netid.next = state->context_tags;
1619 state->context_tags = &context->netid;
1620
1621 if (!state->hostname_auth)
1622 {
1623 struct dhcp_netid_list *id_list;
1624
1625 for (id_list = daemon->dhcp_ignore_names; id_list; id_list = id_list->next)
1626 if ((!id_list->list) || match_netid(id_list->list, &context->netid, 0))
1627 break;
1628 if (id_list)
1629 state->hostname = NULL;
1630 }
1631 }
1632
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01001633 log6_quiet(state, state->lease_allocate ? "DHCPREPLY" : "DHCPADVERTISE", addr, state->hostname);
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001634
1635}
Simon Kelleyff59fc82013-03-07 11:00:26 +00001636
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001637static void mark_context_used(struct state *state, struct in6_addr *addr)
Simon Kelleyff59fc82013-03-07 11:00:26 +00001638{
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001639 struct dhcp_context *context;
1640
Simon Kelleyff59fc82013-03-07 11:00:26 +00001641 /* Mark that we have an address for this prefix. */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001642 for (context = state->context; context; context = context->current)
Simon Kelleyff59fc82013-03-07 11:00:26 +00001643 if (is_same_net6(addr, &context->start6, context->prefix))
1644 context->flags |= CONTEXT_USED;
1645}
Simon Kelleyc6309242013-03-07 20:59:28 +00001646
Simon Kelleyde92b472013-03-15 18:25:10 +00001647static void mark_config_used(struct dhcp_context *context, struct in6_addr *addr)
1648{
1649 for (; context; context = context->current)
1650 if (is_same_net6(addr, &context->start6, context->prefix))
1651 context->flags |= CONTEXT_CONF_USED;
1652}
1653
1654/* make sure address not leased to another CLID/IAID */
1655static int check_address(struct state *state, struct in6_addr *addr)
1656{
1657 struct dhcp_lease *lease;
1658
1659 if (!(lease = lease6_find_by_addr(addr, 128, 0)))
1660 return 1;
1661
1662 if (lease->clid_len != state->clid_len ||
1663 memcmp(lease->clid, state->clid, state->clid_len) != 0 ||
Simon Kelley89500e32013-09-20 16:29:20 +01001664 lease->iaid != state->iaid)
Simon Kelleyde92b472013-03-15 18:25:10 +00001665 return 0;
1666
1667 return 1;
1668}
1669
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001670
Simon Kelley79aba0f2020-02-03 23:58:45 +00001671/* return true of *addr could have been generated from config. */
1672static int config_implies(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr)
1673{
1674 int prefix;
1675 struct in6_addr wild_addr;
Simon Kelley137286e2020-02-06 22:09:30 +00001676 struct addrlist *addr_list;
1677
Simon Kelley79aba0f2020-02-03 23:58:45 +00001678 if (!config || !(config->flags & CONFIG_ADDR6))
1679 return 0;
1680
Simon Kelley137286e2020-02-06 22:09:30 +00001681 for (addr_list = config->addr6; addr_list; addr_list = addr_list->next)
Simon Kelley79aba0f2020-02-03 23:58:45 +00001682 {
Simon Kelley137286e2020-02-06 22:09:30 +00001683 prefix = (addr_list->flags & ADDRLIST_PREFIX) ? addr_list->prefixlen : 128;
1684 wild_addr = addr_list->addr.addr6;
Simon Kelley79aba0f2020-02-03 23:58:45 +00001685
Simon Kelley137286e2020-02-06 22:09:30 +00001686 if ((addr_list->flags & ADDRLIST_WILDCARD) && context->prefix == 64)
1687 {
1688 wild_addr = context->start6;
1689 setaddr6part(&wild_addr, addr6part(&addr_list->addr.addr6));
1690 }
1691 else if (!is_same_net6(&context->start6, addr, context->prefix))
1692 continue;
1693
1694 if (is_same_net6(&wild_addr, addr, prefix))
1695 return 1;
Simon Kelley79aba0f2020-02-03 23:58:45 +00001696 }
1697
Simon Kelley79aba0f2020-02-03 23:58:45 +00001698 return 0;
1699}
1700
1701static int config_valid(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr, struct state *state)
1702{
1703 u64 addrpart;
Simon Kelley137286e2020-02-06 22:09:30 +00001704 struct addrlist *addr_list;
1705
Simon Kelley79aba0f2020-02-03 23:58:45 +00001706 if (!config || !(config->flags & CONFIG_ADDR6))
1707 return 0;
1708
Simon Kelley137286e2020-02-06 22:09:30 +00001709 for (addr_list = config->addr6; addr_list; addr_list = addr_list->next)
Simon Kelley79aba0f2020-02-03 23:58:45 +00001710 {
Simon Kelley137286e2020-02-06 22:09:30 +00001711 addrpart = addr6part(&addr_list->addr.addr6);
Simon Kelley79aba0f2020-02-03 23:58:45 +00001712
Simon Kelley137286e2020-02-06 22:09:30 +00001713 if ((addr_list->flags & ADDRLIST_WILDCARD))
1714 {
1715 if (context->prefix != 64)
1716 continue;
1717
1718 *addr = context->start6;
1719 setaddr6part(addr, addrpart);
1720 }
1721 else if (is_same_net6(&context->start6, &addr_list->addr.addr6, context->prefix))
1722 *addr = addr_list->addr.addr6;
1723 else
1724 continue;
1725
1726 while(1)
1727 {
1728 if (check_address(state, addr))
1729 return 1;
1730
1731 if (!(addr_list->flags & ADDRLIST_PREFIX))
1732 break;
1733
1734 addrpart++;
1735 setaddr6part(addr, addrpart);
1736 if (!is_same_net6(addr, &addr_list->addr.addr6, addr_list->prefixlen))
1737 break;
1738 }
1739 }
1740
1741 return 0;
Simon Kelley79aba0f2020-02-03 23:58:45 +00001742}
1743
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001744/* Calculate valid and preferred times to send in leases/renewals.
1745
1746 Inputs are:
1747
1748 *valid_timep, *preferred_timep - requested times from IAADDR options.
1749 context->valid, context->preferred - times associated with subnet address on local interface.
1750 context->flags | CONTEXT_DEPRECATE - "deprecated" flag in dhcp-range.
1751 lease_time - configured time for context for individual client.
1752 *min_time - smallest valid time sent so far.
1753
1754 Outputs are :
1755
1756 *valid_timep, *preferred_timep - times to be send in IAADDR option.
1757 *min_time - smallest valid time sent so far, to calculate T1 and T2.
1758
1759 */
Simon Kelleyde92b472013-03-15 18:25:10 +00001760static void calculate_times(struct dhcp_context *context, unsigned int *min_time, unsigned int *valid_timep,
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001761 unsigned int *preferred_timep, unsigned int lease_time)
Simon Kelleyde92b472013-03-15 18:25:10 +00001762{
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001763 unsigned int req_preferred = *preferred_timep, req_valid = *valid_timep;
1764 unsigned int valid_time = lease_time, preferred_time = lease_time;
1765
1766 /* RFC 3315: "A server ignores the lifetimes set
1767 by the client if the preferred lifetime is greater than the valid
1768 lifetime. */
1769 if (req_preferred <= req_valid)
1770 {
1771 if (req_preferred != 0)
1772 {
1773 /* 0 == "no preference from client" */
1774 if (req_preferred < 120u)
1775 req_preferred = 120u; /* sanity */
1776
1777 if (req_preferred < preferred_time)
1778 preferred_time = req_preferred;
1779 }
1780
1781 if (req_valid != 0)
1782 /* 0 == "no preference from client" */
1783 {
1784 if (req_valid < 120u)
1785 req_valid = 120u; /* sanity */
1786
1787 if (req_valid < valid_time)
1788 valid_time = req_valid;
1789 }
1790 }
Simon Kelleyde92b472013-03-15 18:25:10 +00001791
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001792 /* deprecate (preferred == 0) which configured, or when local address
1793 is deprecated */
1794 if ((context->flags & CONTEXT_DEPRECATE) || context->preferred == 0)
Simon Kelleyde92b472013-03-15 18:25:10 +00001795 preferred_time = 0;
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001796
Simon Kelleyde92b472013-03-15 18:25:10 +00001797 if (preferred_time != 0 && preferred_time < *min_time)
1798 *min_time = preferred_time;
1799
1800 if (valid_time != 0 && valid_time < *min_time)
1801 *min_time = valid_time;
1802
1803 *valid_timep = valid_time;
1804 *preferred_timep = preferred_time;
1805}
1806
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001807static void update_leases(struct state *state, struct dhcp_context *context, struct in6_addr *addr, unsigned int lease_time, time_t now)
1808{
1809 struct dhcp_lease *lease = lease6_find_by_addr(addr, 128, 0);
Vladislav Grishenko408c3682013-09-24 16:18:49 +01001810#ifdef HAVE_SCRIPT
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001811 struct dhcp_netid *tagif = run_tag_if(state->tags);
Vladislav Grishenko408c3682013-09-24 16:18:49 +01001812#endif
1813
1814 (void)context;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001815
1816 if (!lease)
1817 lease = lease6_allocate(addr, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA);
1818
1819 if (lease)
1820 {
1821 lease_set_expires(lease, lease_time, now);
Simon Kelley89500e32013-09-20 16:29:20 +01001822 lease_set_iaid(lease, state->iaid);
1823 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 +00001824 lease_set_interface(lease, state->interface, now);
1825 if (state->hostname && state->ia_type == OPTION6_IA_NA)
1826 {
1827 char *addr_domain = get_domain6(addr);
1828 if (!state->send_domain)
1829 state->send_domain = addr_domain;
1830 lease_set_hostname(lease, state->hostname, state->hostname_auth, addr_domain, state->domain);
1831 }
1832
1833#ifdef HAVE_SCRIPT
1834 if (daemon->lease_change_command)
1835 {
1836 void *class_opt;
1837 lease->flags |= LEASE_CHANGED;
1838 free(lease->extradata);
1839 lease->extradata = NULL;
1840 lease->extradata_size = lease->extradata_len = 0;
Simon Kelley6f9aaa92013-04-10 10:25:26 +01001841 lease->vendorclass_count = 0;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001842
1843 if ((class_opt = opt6_find(state->packet_options, state->end, OPTION6_VENDOR_CLASS, 4)))
1844 {
1845 void *enc_opt, *enc_end = opt6_ptr(class_opt, opt6_len(class_opt));
Simon Kelley6f9aaa92013-04-10 10:25:26 +01001846 lease->vendorclass_count++;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001847 /* send enterprise number first */
1848 sprintf(daemon->dhcp_buff2, "%u", opt6_uint(class_opt, 0, 4));
1849 lease_add_extradata(lease, (unsigned char *)daemon->dhcp_buff2, strlen(daemon->dhcp_buff2), 0);
1850
1851 if (opt6_len(class_opt) >= 6)
1852 for (enc_opt = opt6_ptr(class_opt, 4); enc_opt; enc_opt = opt6_next(enc_opt, enc_end))
1853 {
Simon Kelley6f9aaa92013-04-10 10:25:26 +01001854 lease->vendorclass_count++;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001855 lease_add_extradata(lease, opt6_ptr(enc_opt, 0), opt6_len(enc_opt), 0);
1856 }
1857 }
1858
1859 lease_add_extradata(lease, (unsigned char *)state->client_hostname,
1860 state->client_hostname ? strlen(state->client_hostname) : 0, 0);
1861
1862 /* space-concat tag set */
1863 if (!tagif && !context->netid.net)
1864 lease_add_extradata(lease, NULL, 0, 0);
1865 else
1866 {
1867 if (context->netid.net)
1868 lease_add_extradata(lease, (unsigned char *)context->netid.net, strlen(context->netid.net), tagif ? ' ' : 0);
1869
1870 if (tagif)
1871 {
1872 struct dhcp_netid *n;
1873 for (n = tagif; n; n = n->next)
1874 {
1875 struct dhcp_netid *n1;
1876 /* kill dupes */
1877 for (n1 = n->next; n1; n1 = n1->next)
1878 if (strcmp(n->net, n1->net) == 0)
1879 break;
1880 if (!n1)
1881 lease_add_extradata(lease, (unsigned char *)n->net, strlen(n->net), n->next ? ' ' : 0);
1882 }
1883 }
1884 }
1885
1886 if (state->link_address)
1887 inet_ntop(AF_INET6, state->link_address, daemon->addrbuff, ADDRSTRLEN);
1888
1889 lease_add_extradata(lease, (unsigned char *)daemon->addrbuff, state->link_address ? strlen(daemon->addrbuff) : 0, 0);
1890
1891 if ((class_opt = opt6_find(state->packet_options, state->end, OPTION6_USER_CLASS, 2)))
1892 {
1893 void *enc_opt, *enc_end = opt6_ptr(class_opt, opt6_len(class_opt));
1894 for (enc_opt = opt6_ptr(class_opt, 0); enc_opt; enc_opt = opt6_next(enc_opt, enc_end))
1895 lease_add_extradata(lease, opt6_ptr(enc_opt, 0), opt6_len(enc_opt), 0);
1896 }
1897 }
1898#endif
1899
1900 }
1901}
1902
1903
1904
Simon Kelley6c8f21e2012-03-12 15:06:55 +00001905static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_opts)
1906{
1907 void *opt;
1908 char *desc = nest ? "nest" : "sent";
Simon Kelley5cfea3d2012-03-12 17:28:27 +00001909
Simon Kelleyd81b42d2013-09-23 12:26:34 +01001910 if (!option_bool(OPT_LOG_OPTS) || start_opts == end_opts)
Simon Kelley5cfea3d2012-03-12 17:28:27 +00001911 return;
1912
1913 for (opt = start_opts; opt; opt = opt6_next(opt, end_opts))
1914 {
1915 int type = opt6_type(opt);
1916 void *ia_options = NULL;
1917 char *optname;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001918
Simon Kelley5cfea3d2012-03-12 17:28:27 +00001919 if (type == OPTION6_IA_NA)
1920 {
1921 sprintf(daemon->namebuff, "IAID=%u T1=%u T2=%u",
1922 opt6_uint(opt, 0, 4), opt6_uint(opt, 4, 4), opt6_uint(opt, 8, 4));
1923 optname = "ia-na";
1924 ia_options = opt6_ptr(opt, 12);
1925 }
1926 else if (type == OPTION6_IA_TA)
1927 {
1928 sprintf(daemon->namebuff, "IAID=%u", opt6_uint(opt, 0, 4));
1929 optname = "ia-ta";
1930 ia_options = opt6_ptr(opt, 4);
1931 }
1932 else if (type == OPTION6_IAADDR)
1933 {
Simon Kelley97f876b2018-08-21 22:06:36 +01001934 struct in6_addr addr;
1935
1936 /* align */
1937 memcpy(&addr, opt6_ptr(opt, 0), IN6ADDRSZ);
1938 inet_ntop(AF_INET6, &addr, daemon->addrbuff, ADDRSTRLEN);
Simon Kelley5cfea3d2012-03-12 17:28:27 +00001939 sprintf(daemon->namebuff, "%s PL=%u VL=%u",
1940 daemon->addrbuff, opt6_uint(opt, 16, 4), opt6_uint(opt, 20, 4));
1941 optname = "iaaddr";
1942 ia_options = opt6_ptr(opt, 24);
1943 }
1944 else if (type == OPTION6_STATUS_CODE)
1945 {
1946 int len = sprintf(daemon->namebuff, "%u ", opt6_uint(opt, 0, 2));
1947 memcpy(daemon->namebuff + len, opt6_ptr(opt, 2), opt6_len(opt)-2);
1948 daemon->namebuff[len + opt6_len(opt) - 2] = 0;
1949 optname = "status";
1950 }
1951 else
1952 {
1953 /* account for flag byte on FQDN */
1954 int offset = type == OPTION6_FQDN ? 1 : 0;
1955 optname = option_string(AF_INET6, type, opt6_ptr(opt, offset), opt6_len(opt) - offset, daemon->namebuff, MAXDNAME);
1956 }
1957
1958 my_syslog(MS_DHCP | LOG_INFO, "%u %s size:%3d option:%3d %s %s",
1959 xid, desc, opt6_len(opt), type, optname, daemon->namebuff);
1960
1961 if (ia_options)
1962 log6_opts(1, xid, ia_options, opt6_ptr(opt, opt6_len(opt)));
1963 }
Simon Kelley6c8f21e2012-03-12 15:06:55 +00001964}
1965
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01001966static void log6_quiet(struct state *state, char *type, struct in6_addr *addr, char *string)
1967{
1968 if (option_bool(OPT_LOG_OPTS) || !option_bool(OPT_QUIET_DHCP6))
1969 log6_packet(state, type, addr, string);
1970}
1971
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001972static void log6_packet(struct state *state, char *type, struct in6_addr *addr, char *string)
Simon Kelley4cb1b322012-02-06 14:30:41 +00001973{
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001974 int clid_len = state->clid_len;
1975
Simon Kelley4cb1b322012-02-06 14:30:41 +00001976 /* avoid buffer overflow */
1977 if (clid_len > 100)
1978 clid_len = 100;
1979
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001980 print_mac(daemon->namebuff, state->clid, clid_len);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001981
1982 if (addr)
1983 {
Simon Kelleybf4e62c2016-07-22 21:37:59 +01001984 inet_ntop(AF_INET6, addr, daemon->dhcp_buff2, DHCP_BUFF_SZ - 1);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001985 strcat(daemon->dhcp_buff2, " ");
1986 }
1987 else
1988 daemon->dhcp_buff2[0] = 0;
1989
1990 if(option_bool(OPT_LOG_OPTS))
Simon Kelley58dc02e2012-02-27 11:49:37 +00001991 my_syslog(MS_DHCP | LOG_INFO, "%u %s(%s) %s%s %s",
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001992 state->xid,
Simon Kelley4cb1b322012-02-06 14:30:41 +00001993 type,
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001994 state->iface_name,
Simon Kelley4cb1b322012-02-06 14:30:41 +00001995 daemon->dhcp_buff2,
Simon Kelley58dc02e2012-02-27 11:49:37 +00001996 daemon->namebuff,
Simon Kelley4cb1b322012-02-06 14:30:41 +00001997 string ? string : "");
1998 else
Simon Kelley58dc02e2012-02-27 11:49:37 +00001999 my_syslog(MS_DHCP | LOG_INFO, "%s(%s) %s%s %s",
Simon Kelley4cb1b322012-02-06 14:30:41 +00002000 type,
Simon Kelleya6ebfac2013-03-06 20:52:35 +00002001 state->iface_name,
Simon Kelley4cb1b322012-02-06 14:30:41 +00002002 daemon->dhcp_buff2,
Simon Kelley58dc02e2012-02-27 11:49:37 +00002003 daemon->namebuff,
Simon Kelley4cb1b322012-02-06 14:30:41 +00002004 string ? string : "");
2005}
2006
2007static void *opt6_find (void *opts, void *end, unsigned int search, unsigned int minsize)
Simon Kelleyc72daea2012-01-05 21:33:27 +00002008{
2009 u16 opt, opt_len;
2010 void *start;
2011
2012 if (!opts)
2013 return NULL;
2014
2015 while (1)
2016 {
2017 if (end - opts < 4)
2018 return NULL;
2019
2020 start = opts;
2021 GETSHORT(opt, opts);
2022 GETSHORT(opt_len, opts);
2023
2024 if (opt_len > (end - opts))
2025 return NULL;
2026
2027 if (opt == search && (opt_len >= minsize))
2028 return start;
2029
2030 opts += opt_len;
2031 }
2032}
2033
Simon Kelley4cb1b322012-02-06 14:30:41 +00002034static void *opt6_next(void *opts, void *end)
Simon Kelleyc72daea2012-01-05 21:33:27 +00002035{
2036 u16 opt_len;
2037
2038 if (end - opts < 4)
2039 return NULL;
2040
2041 opts += 2;
2042 GETSHORT(opt_len, opts);
2043
2044 if (opt_len >= (end - opts))
2045 return NULL;
2046
2047 return opts + opt_len;
2048}
Simon Kelleyc72daea2012-01-05 21:33:27 +00002049
2050static unsigned int opt6_uint(unsigned char *opt, int offset, int size)
2051{
2052 /* this worries about unaligned data and byte order */
2053 unsigned int ret = 0;
2054 int i;
2055 unsigned char *p = opt6_ptr(opt, offset);
2056
2057 for (i = 0; i < size; i++)
2058 ret = (ret << 8) | *p++;
2059
2060 return ret;
Simon Kelley4cb1b322012-02-06 14:30:41 +00002061}
Simon Kelleyc72daea2012-01-05 21:33:27 +00002062
Simon Kelley33702ab2015-12-28 23:17:15 +00002063void relay_upstream6(struct dhcp_relay *relay, ssize_t sz,
2064 struct in6_addr *peer_address, u32 scope_id, time_t now)
Simon Kelleyff7eea22013-09-04 18:01:38 +01002065{
2066 /* ->local is same value for all relays on ->current chain */
2067
Simon Kelleycc921df2019-01-02 22:48:59 +00002068 union all_addr from;
Simon Kelleyff7eea22013-09-04 18:01:38 +01002069 unsigned char *header;
2070 unsigned char *inbuff = daemon->dhcp_packet.iov_base;
2071 int msg_type = *inbuff;
2072 int hopcount;
2073 struct in6_addr multicast;
Simon Kelley8939c952013-09-25 11:49:34 +01002074 unsigned int maclen, mactype;
2075 unsigned char mac[DHCP_CHADDR_MAX];
Simon Kelleyff7eea22013-09-04 18:01:38 +01002076
2077 inet_pton(AF_INET6, ALL_SERVERS, &multicast);
Simon Kelley33702ab2015-12-28 23:17:15 +00002078 get_client_mac(peer_address, scope_id, mac, &maclen, &mactype, now);
Simon Kelley8939c952013-09-25 11:49:34 +01002079
Simon Kelleyff7eea22013-09-04 18:01:38 +01002080 /* source address == relay address */
Simon Kelleycc921df2019-01-02 22:48:59 +00002081 from.addr6 = relay->local.addr6;
Simon Kelleyff7eea22013-09-04 18:01:38 +01002082
2083 /* Get hop count from nested relayed message */
2084 if (msg_type == DHCP6RELAYFORW)
2085 hopcount = *((unsigned char *)inbuff+1) + 1;
2086 else
2087 hopcount = 0;
2088
2089 /* RFC 3315 HOP_COUNT_LIMIT */
2090 if (hopcount > 32)
2091 return;
2092
Simon Kelleyfa785732016-07-22 20:56:01 +01002093 reset_counter();
Simon Kelleyff7eea22013-09-04 18:01:38 +01002094
2095 if ((header = put_opt6(NULL, 34)))
2096 {
2097 int o;
2098
2099 header[0] = DHCP6RELAYFORW;
2100 header[1] = hopcount;
Simon Kelleycc921df2019-01-02 22:48:59 +00002101 memcpy(&header[2], &relay->local.addr6, IN6ADDRSZ);
Simon Kelleyff7eea22013-09-04 18:01:38 +01002102 memcpy(&header[18], peer_address, IN6ADDRSZ);
Simon Kelley89500e32013-09-20 16:29:20 +01002103
2104 /* RFC-6939 */
Simon Kelley8939c952013-09-25 11:49:34 +01002105 if (maclen != 0)
Simon Kelley89500e32013-09-20 16:29:20 +01002106 {
2107 o = new_opt6(OPTION6_CLIENT_MAC);
Simon Kelley8939c952013-09-25 11:49:34 +01002108 put_opt6_short(mactype);
2109 put_opt6(mac, maclen);
Simon Kelley89500e32013-09-20 16:29:20 +01002110 end_opt6(o);
2111 }
Simon Kelleyff7eea22013-09-04 18:01:38 +01002112
2113 o = new_opt6(OPTION6_RELAY_MSG);
2114 put_opt6(inbuff, sz);
2115 end_opt6(o);
2116
2117 for (; relay; relay = relay->current)
2118 {
2119 union mysockaddr to;
2120
2121 to.sa.sa_family = AF_INET6;
Simon Kelleycc921df2019-01-02 22:48:59 +00002122 to.in6.sin6_addr = relay->server.addr6;
Simon Kelleyff7eea22013-09-04 18:01:38 +01002123 to.in6.sin6_port = htons(DHCPV6_SERVER_PORT);
2124 to.in6.sin6_flowinfo = 0;
2125 to.in6.sin6_scope_id = 0;
2126
Simon Kelleycc921df2019-01-02 22:48:59 +00002127 if (IN6_ARE_ADDR_EQUAL(&relay->server.addr6, &multicast))
Simon Kelleyff7eea22013-09-04 18:01:38 +01002128 {
2129 int multicast_iface;
2130 if (!relay->interface || strchr(relay->interface, '*') ||
2131 (multicast_iface = if_nametoindex(relay->interface)) == 0 ||
2132 setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &multicast_iface, sizeof(multicast_iface)) == -1)
2133 my_syslog(MS_DHCP | LOG_ERR, _("Cannot multicast to DHCPv6 server without correct interface"));
2134 }
2135
Simon Kelley6b1c4642016-07-22 20:59:16 +01002136 send_from(daemon->dhcp6fd, 0, daemon->outpacket.iov_base, save_counter(-1), &to, &from, 0);
Simon Kelleyff7eea22013-09-04 18:01:38 +01002137
2138 if (option_bool(OPT_LOG_OPTS))
2139 {
2140 inet_ntop(AF_INET6, &relay->local, daemon->addrbuff, ADDRSTRLEN);
2141 inet_ntop(AF_INET6, &relay->server, daemon->namebuff, ADDRSTRLEN);
2142 my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay %s -> %s"), daemon->addrbuff, daemon->namebuff);
2143 }
2144
2145 /* Save this for replies */
2146 relay->iface_index = scope_id;
2147 }
2148 }
2149}
2150
2151unsigned short relay_reply6(struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface)
2152{
2153 struct dhcp_relay *relay;
2154 struct in6_addr link;
2155 unsigned char *inbuff = daemon->dhcp_packet.iov_base;
2156
2157 /* must have at least msg_type+hopcount+link_address+peer_address+minimal size option
2158 which is 1 + 1 + 16 + 16 + 2 + 2 = 38 */
2159
2160 if (sz < 38 || *inbuff != DHCP6RELAYREPL)
2161 return 0;
2162
2163 memcpy(&link, &inbuff[2], IN6ADDRSZ);
2164
2165 for (relay = daemon->relay6; relay; relay = relay->next)
Simon Kelleycc921df2019-01-02 22:48:59 +00002166 if (IN6_ARE_ADDR_EQUAL(&link, &relay->local.addr6) &&
Simon Kelleyff7eea22013-09-04 18:01:38 +01002167 (!relay->interface || wildcard_match(relay->interface, arrival_interface)))
2168 break;
2169
Simon Kelleyfa785732016-07-22 20:56:01 +01002170 reset_counter();
Simon Kelleyff7eea22013-09-04 18:01:38 +01002171
2172 if (relay)
2173 {
2174 void *opt, *opts = inbuff + 34;
2175 void *end = inbuff + sz;
2176 for (opt = opts; opt; opt = opt6_next(opt, end))
2177 if (opt6_type(opt) == OPTION6_RELAY_MSG && opt6_len(opt) > 0)
2178 {
2179 int encap_type = *((unsigned char *)opt6_ptr(opt, 0));
2180 put_opt6(opt6_ptr(opt, 0), opt6_len(opt));
2181 memcpy(&peer->sin6_addr, &inbuff[18], IN6ADDRSZ);
2182 peer->sin6_scope_id = relay->iface_index;
2183 return encap_type == DHCP6RELAYREPL ? DHCPV6_SERVER_PORT : DHCPV6_CLIENT_PORT;
2184 }
2185 }
2186
2187 return 0;
2188}
2189
Simon Kelleyc72daea2012-01-05 21:33:27 +00002190#endif