blob: ee1cf17c3de4b8dfaa19fb8e657e2ab4d4ca5d51 [file] [log] [blame]
Simon Kelleyd1ced3a2018-01-01 22:18:03 +00001/* dnsmasq is Copyright (c) 2000-2018 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;
Simon Kelleyc8f2dd82013-09-13 11:22:55 +010024 int clid_len, iaid, 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;
Simon Kelleya6ebfac2013-03-06 20:52:35 +000028 unsigned int xid, fqdn_flags;
29 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 Kelleyc6309242013-03-07 20:59:28 +000034#ifdef OPTION6_PREFIX_CLASS
35 struct prefix_class *send_prefix_class;
36#endif
Simon Kelleya6ebfac2013-03-06 20:52:35 +000037};
38
Simon Kelley8939c952013-09-25 11:49:34 +010039static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz,
40 struct in6_addr *client_addr, int is_unicast, time_t now);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +010041static 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 +000042static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_opts);
Simon Kelleya6ebfac2013-03-06 20:52:35 +000043static void log6_packet(struct state *state, char *type, struct in6_addr *addr, char *string);
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +010044static void log6_quiet(struct state *state, char *type, struct in6_addr *addr, char *string);
Simon Kelley4cb1b322012-02-06 14:30:41 +000045static void *opt6_find (void *opts, void *end, unsigned int search, unsigned int minsize);
46static void *opt6_next(void *opts, void *end);
47static unsigned int opt6_uint(unsigned char *opt, int offset, int size);
Simon Kelleya6ebfac2013-03-06 20:52:35 +000048static void get_context_tag(struct state *state, struct dhcp_context *context);
Simon Kelley3a654c52013-03-06 22:17:48 +000049static int check_ia(struct state *state, void *opt, void **endp, void **ia_option);
Simon Kelleya6ebfac2013-03-06 20:52:35 +000050static int build_ia(struct state *state, int *t1cntr);
51static void end_ia(int t1cntr, unsigned int min_time, int do_fuzz);
Simon Kelleyc6309242013-03-07 20:59:28 +000052#ifdef OPTION6_PREFIX_CLASS
53static struct prefix_class *prefix_class_from_context(struct dhcp_context *context);
54#endif
Simon Kelleyf1af2bb2013-09-24 09:16:28 +010055static void mark_context_used(struct state *state, struct in6_addr *addr);
Simon Kelleyde92b472013-03-15 18:25:10 +000056static void mark_config_used(struct dhcp_context *context, struct in6_addr *addr);
57static int check_address(struct state *state, struct in6_addr *addr);
Simon Kelleycc4baaa2013-08-05 15:03:44 +010058static void add_address(struct state *state, struct dhcp_context *context, unsigned int lease_time, void *ia_option,
Simon Kelleyc8f2dd82013-09-13 11:22:55 +010059 unsigned int *min_time, struct in6_addr *addr, time_t now);
Simon Kelleya6ebfac2013-03-06 20:52:35 +000060static void update_leases(struct state *state, struct dhcp_context *context, struct in6_addr *addr, unsigned int lease_time, time_t now);
61static int add_local_addrs(struct dhcp_context *context);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +010062static struct dhcp_netid *add_options(struct state *state, int do_refresh);
Simon Kelleyde92b472013-03-15 18:25:10 +000063static void calculate_times(struct dhcp_context *context, unsigned int *min_time, unsigned int *valid_timep,
Simon Kelleycc4baaa2013-08-05 15:03:44 +010064 unsigned int *preferred_timep, unsigned int lease_time);
Simon Kelley62779782012-02-10 21:19:25 +000065
Simon Kelley4cb1b322012-02-06 14:30:41 +000066#define opt6_len(opt) ((int)(opt6_uint(opt, -2, 2)))
67#define opt6_type(opt) (opt6_uint(opt, -4, 2))
68#define opt6_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[4+(i)]))
69
Tanguy Bouzelocef1d7422013-10-03 11:06:31 +010070#define opt6_user_vendor_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[2+(i)]))
71#define opt6_user_vendor_len(opt) ((int)(opt6_uint(opt, -4, 2)))
72#define opt6_user_vendor_next(opt, end) (opt6_next(((void *) opt) - 2, end))
73
Simon Kelley4cb1b322012-02-06 14:30:41 +000074
Simon Kelley1d0f91c2012-03-12 11:56:22 +000075unsigned short dhcp6_reply(struct dhcp_context *context, int interface, char *iface_name,
Simon Kelleyc3a04082014-01-11 22:18:19 +000076 struct in6_addr *fallback, struct in6_addr *ll_addr, struct in6_addr *ula_addr,
77 size_t sz, struct in6_addr *client_addr, time_t now)
Simon Kelleyc72daea2012-01-05 21:33:27 +000078{
Simon Kelley4cb1b322012-02-06 14:30:41 +000079 struct dhcp_vendor *vendor;
Simon Kelley1d0f91c2012-03-12 11:56:22 +000080 int msg_type;
Simon Kelleyf1af2bb2013-09-24 09:16:28 +010081 struct state state;
Simon Kelley1d0f91c2012-03-12 11:56:22 +000082
83 if (sz <= 4)
84 return 0;
85
86 msg_type = *((unsigned char *)daemon->dhcp_packet.iov_base);
87
Simon Kelley4cb1b322012-02-06 14:30:41 +000088 /* Mark these so we only match each at most once, to avoid tangled linked lists */
89 for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
90 vendor->netid.next = &vendor->netid;
Simon Kelleyc72daea2012-01-05 21:33:27 +000091
Simon Kelleyfa785732016-07-22 20:56:01 +010092 reset_counter();
Simon Kelleyf1af2bb2013-09-24 09:16:28 +010093 state.context = context;
94 state.interface = interface;
95 state.iface_name = iface_name;
96 state.fallback = fallback;
Simon Kelleyc3a04082014-01-11 22:18:19 +000097 state.ll_addr = ll_addr;
98 state.ula_addr = ula_addr;
Simon Kelley8939c952013-09-25 11:49:34 +010099 state.mac_len = 0;
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100100 state.tags = NULL;
101 state.link_address = NULL;
102
Simon Kelley8939c952013-09-25 11:49:34 +0100103 if (dhcp6_maybe_relay(&state, daemon->dhcp_packet.iov_base, sz, client_addr,
104 IN6_IS_ADDR_MULTICAST(client_addr), now))
Simon Kelley1d0f91c2012-03-12 11:56:22 +0000105 return msg_type == DHCP6RELAYFORW ? DHCPV6_SERVER_PORT : DHCPV6_CLIENT_PORT;
Simon Kelleyc72daea2012-01-05 21:33:27 +0000106
107 return 0;
108}
109
Simon Kelley4cb1b322012-02-06 14:30:41 +0000110/* This cost me blood to write, it will probably cost you blood to understand - srk. */
Simon Kelley8939c952013-09-25 11:49:34 +0100111static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz,
112 struct in6_addr *client_addr, int is_unicast, time_t now)
Simon Kelley4cb1b322012-02-06 14:30:41 +0000113{
114 void *end = inbuff + sz;
115 void *opts = inbuff + 34;
116 int msg_type = *((unsigned char *)inbuff);
117 unsigned char *outmsgtypep;
118 void *opt;
119 struct dhcp_vendor *vendor;
120
Josh Soref730c6742017-02-06 16:14:04 +0000121 /* if not an encapsulated relayed message, just do the stuff */
Simon Kelley4cb1b322012-02-06 14:30:41 +0000122 if (msg_type != DHCP6RELAYFORW)
123 {
124 /* if link_address != NULL if points to the link address field of the
125 innermost nested RELAYFORW message, which is where we find the
126 address of the network on which we can allocate an address.
Simon Kelley8939c952013-09-25 11:49:34 +0100127 Recalculate the available contexts using that information.
128
129 link_address == NULL means there's no relay in use, so we try and find the client's
130 MAC address from the local ND cache. */
Simon Kelley4cb1b322012-02-06 14:30:41 +0000131
Simon Kelley8939c952013-09-25 11:49:34 +0100132 if (!state->link_address)
Simon Kelley33702ab2015-12-28 23:17:15 +0000133 get_client_mac(client_addr, state->interface, state->mac, &state->mac_len, &state->mac_type, now);
Simon Kelley8939c952013-09-25 11:49:34 +0100134 else
Simon Kelley4cb1b322012-02-06 14:30:41 +0000135 {
136 struct dhcp_context *c;
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100137 state->context = NULL;
Simon Kelleybaeb3ad2013-01-10 11:47:38 +0000138
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100139 if (!IN6_IS_ADDR_LOOPBACK(state->link_address) &&
140 !IN6_IS_ADDR_LINKLOCAL(state->link_address) &&
141 !IN6_IS_ADDR_MULTICAST(state->link_address))
Simon Kelleybaeb3ad2013-01-10 11:47:38 +0000142 for (c = daemon->dhcp6; c; c = c->next)
143 if ((c->flags & CONTEXT_DHCP) &&
Simon Kelleyef1a94a2013-07-26 13:59:03 +0100144 !(c->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100145 is_same_net6(state->link_address, &c->start6, c->prefix) &&
146 is_same_net6(state->link_address, &c->end6, c->prefix))
Simon Kelleybaeb3ad2013-01-10 11:47:38 +0000147 {
Simon Kelley8ac97872013-03-30 21:34:19 +0000148 c->preferred = c->valid = 0xffffffff;
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100149 c->current = state->context;
150 state->context = c;
Simon Kelleybaeb3ad2013-01-10 11:47:38 +0000151 }
Simon Kelley4cb1b322012-02-06 14:30:41 +0000152
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100153 if (!state->context)
Simon Kelley4cb1b322012-02-06 14:30:41 +0000154 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100155 inet_ntop(AF_INET6, state->link_address, daemon->addrbuff, ADDRSTRLEN);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000156 my_syslog(MS_DHCP | LOG_WARNING,
157 _("no address range available for DHCPv6 request from relay at %s"),
158 daemon->addrbuff);
159 return 0;
160 }
161 }
Simon Kelley8939c952013-09-25 11:49:34 +0100162
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100163 if (!state->context)
Simon Kelley4cb1b322012-02-06 14:30:41 +0000164 {
165 my_syslog(MS_DHCP | LOG_WARNING,
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100166 _("no address range available for DHCPv6 request via %s"), state->iface_name);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000167 return 0;
168 }
169
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100170 return dhcp6_no_relay(state, msg_type, inbuff, sz, is_unicast, now);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000171 }
172
173 /* must have at least msg_type+hopcount+link_address+peer_address+minimal size option
174 which is 1 + 1 + 16 + 16 + 2 + 2 = 38 */
175 if (sz < 38)
176 return 0;
177
178 /* copy header stuff into reply message and set type to reply */
Simon Kelleyff7eea22013-09-04 18:01:38 +0100179 if (!(outmsgtypep = put_opt6(inbuff, 34)))
180 return 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000181 *outmsgtypep = DHCP6RELAYREPL;
182
183 /* look for relay options and set tags if found. */
184 for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
185 {
186 int mopt;
187
188 if (vendor->match_type == MATCH_SUBSCRIBER)
189 mopt = OPTION6_SUBSCRIBER_ID;
190 else if (vendor->match_type == MATCH_REMOTE)
191 mopt = OPTION6_REMOTE_ID;
192 else
193 continue;
194
195 if ((opt = opt6_find(opts, end, mopt, 1)) &&
196 vendor->len == opt6_len(opt) &&
197 memcmp(vendor->data, opt6_ptr(opt, 0), vendor->len) == 0 &&
198 vendor->netid.next != &vendor->netid)
199 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100200 vendor->netid.next = state->tags;
201 state->tags = &vendor->netid;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000202 break;
203 }
204 }
205
Simon Kelley89500e32013-09-20 16:29:20 +0100206 /* RFC-6939 */
207 if ((opt = opt6_find(opts, end, OPTION6_CLIENT_MAC, 3)))
208 {
Simon Kelley3d4ff1b2017-09-25 18:52:50 +0100209 if (opt6_len(opt) - 2 > DHCP_CHADDR_MAX) {
210 return 0;
211 }
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100212 state->mac_type = opt6_uint(opt, 0, 2);
213 state->mac_len = opt6_len(opt) - 2;
Simon Kelley8939c952013-09-25 11:49:34 +0100214 memcpy(&state->mac[0], opt6_ptr(opt, 2), state->mac_len);
Simon Kelley89500e32013-09-20 16:29:20 +0100215 }
216
Simon Kelley4cb1b322012-02-06 14:30:41 +0000217 for (opt = opts; opt; opt = opt6_next(opt, end))
218 {
yiwenchen499d8dd2018-02-14 22:26:54 +0000219 if (opt6_ptr(opt, 0) + opt6_len(opt) > end)
Simon Kelley33e3f102017-09-25 20:05:11 +0100220 return 0;
yiwenchen499d8dd2018-02-14 22:26:54 +0000221
Simon Kelley4cb1b322012-02-06 14:30:41 +0000222 int o = new_opt6(opt6_type(opt));
223 if (opt6_type(opt) == OPTION6_RELAY_MSG)
224 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100225 struct in6_addr align;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000226 /* the packet data is unaligned, copy to aligned storage */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100227 memcpy(&align, inbuff + 2, IN6ADDRSZ);
228 state->link_address = &align;
229 /* zero is_unicast since that is now known to refer to the
Simon Kelley4cb1b322012-02-06 14:30:41 +0000230 relayed packet, not the original sent by the client */
Simon Kelley8939c952013-09-25 11:49:34 +0100231 if (!dhcp6_maybe_relay(state, opt6_ptr(opt, 0), opt6_len(opt), client_addr, 0, now))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000232 return 0;
233 }
Simon Kelley89500e32013-09-20 16:29:20 +0100234 else if (opt6_type(opt) != OPTION6_CLIENT_MAC)
Simon Kelley4cb1b322012-02-06 14:30:41 +0000235 put_opt6(opt6_ptr(opt, 0), opt6_len(opt));
236 end_opt6(o);
237 }
238
239 return 1;
240}
241
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100242static 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 +0000243{
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000244 void *opt;
245 int i, o, o1, start_opts;
246 struct dhcp_opt *opt_cfg;
247 struct dhcp_netid *tagif;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000248 struct dhcp_config *config = NULL;
Simon Kelley0d28af82012-09-20 21:24:06 +0100249 struct dhcp_netid known_id, iface_id, v6_id;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000250 unsigned char *outmsgtypep;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000251 struct dhcp_vendor *vendor;
252 struct dhcp_context *context_tmp;
Simon Kelley89500e32013-09-20 16:29:20 +0100253 struct dhcp_mac *mac_opt;
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000254 unsigned int ignore = 0;
Simon Kelleyc6309242013-03-07 20:59:28 +0000255#ifdef OPTION6_PREFIX_CLASS
Simon Kelley6e37ab52013-03-19 20:50:11 +0000256 struct prefix_class *p;
257 int dump_all_prefix_classes = 0;
Simon Kelleyc6309242013-03-07 20:59:28 +0000258#endif
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000259
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100260 state->packet_options = inbuff + 4;
261 state->end = inbuff + sz;
262 state->clid = NULL;
263 state->clid_len = 0;
264 state->lease_allocate = 0;
265 state->context_tags = NULL;
266 state->domain = NULL;
267 state->send_domain = NULL;
268 state->hostname_auth = 0;
269 state->hostname = NULL;
270 state->client_hostname = NULL;
Josh Soref730c6742017-02-06 16:14:04 +0000271 state->fqdn_flags = 0x01; /* default to send if we receive no FQDN option */
Simon Kelleyc6309242013-03-07 20:59:28 +0000272#ifdef OPTION6_PREFIX_CLASS
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100273 state->send_prefix_class = NULL;
Simon Kelleyc6309242013-03-07 20:59:28 +0000274#endif
Simon Kelley4cb1b322012-02-06 14:30:41 +0000275
Simon Kelleyceae00d2012-02-09 21:28:14 +0000276 /* set tag with name == interface */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100277 iface_id.net = state->iface_name;
278 iface_id.next = state->tags;
279 state->tags = &iface_id;
Simon Kelleyceae00d2012-02-09 21:28:14 +0000280
Simon Kelley23780dd2012-10-23 17:04:37 +0100281 /* set tag "dhcpv6" */
282 v6_id.net = "dhcpv6";
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100283 v6_id.next = state->tags;
284 state->tags = &v6_id;
Simon Kelley0d28af82012-09-20 21:24:06 +0100285
Simon Kelley4cb1b322012-02-06 14:30:41 +0000286 /* copy over transaction-id, and save pointer to message type */
Simon Kelleyff7eea22013-09-04 18:01:38 +0100287 if (!(outmsgtypep = put_opt6(inbuff, 4)))
288 return 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000289 start_opts = save_counter(-1);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100290 state->xid = outmsgtypep[3] | outmsgtypep[2] << 8 | outmsgtypep[1] << 16;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000291
292 /* We're going to be linking tags from all context we use.
293 mark them as unused so we don't link one twice and break the list */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100294 for (context_tmp = state->context; context_tmp; context_tmp = context_tmp->current)
Simon Kelley4cb1b322012-02-06 14:30:41 +0000295 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100296 context_tmp->netid.next = &context_tmp->netid;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000297
298 if (option_bool(OPT_LOG_OPTS))
299 {
300 inet_ntop(AF_INET6, &context_tmp->start6, daemon->dhcp_buff, ADDRSTRLEN);
301 inet_ntop(AF_INET6, &context_tmp->end6, daemon->dhcp_buff2, ADDRSTRLEN);
302 if (context_tmp->flags & (CONTEXT_STATIC))
303 my_syslog(MS_DHCP | LOG_INFO, _("%u available DHCPv6 subnet: %s/%d"),
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100304 state->xid, daemon->dhcp_buff, context_tmp->prefix);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000305 else
306 my_syslog(MS_DHCP | LOG_INFO, _("%u available DHCP range: %s -- %s"),
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100307 state->xid, daemon->dhcp_buff, daemon->dhcp_buff2);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000308 }
309 }
310
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100311 if ((opt = opt6_find(state->packet_options, state->end, OPTION6_CLIENT_ID, 1)))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000312 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100313 state->clid = opt6_ptr(opt, 0);
314 state->clid_len = opt6_len(opt);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000315 o = new_opt6(OPTION6_CLIENT_ID);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100316 put_opt6(state->clid, state->clid_len);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000317 end_opt6(o);
318 }
319 else if (msg_type != DHCP6IREQ)
320 return 0;
321
Ilya Ponetaev7f68f822014-09-13 20:52:27 +0100322 /* server-id must match except for SOLICIT, CONFIRM and REBIND messages */
323 if (msg_type != DHCP6SOLICIT && msg_type != DHCP6CONFIRM && msg_type != DHCP6IREQ && msg_type != DHCP6REBIND &&
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100324 (!(opt = opt6_find(state->packet_options, state->end, OPTION6_SERVER_ID, 1)) ||
Simon Kelley4cb1b322012-02-06 14:30:41 +0000325 opt6_len(opt) != daemon->duid_len ||
326 memcmp(opt6_ptr(opt, 0), daemon->duid, daemon->duid_len) != 0))
327 return 0;
328
329 o = new_opt6(OPTION6_SERVER_ID);
330 put_opt6(daemon->duid, daemon->duid_len);
331 end_opt6(o);
332
333 if (is_unicast &&
334 (msg_type == DHCP6REQUEST || msg_type == DHCP6RENEW || msg_type == DHCP6RELEASE || msg_type == DHCP6DECLINE))
335
336 {
Ilya Ponetaev976afc92014-09-13 20:56:14 +0100337 *outmsgtypep = DHCP6REPLY;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000338 o1 = new_opt6(OPTION6_STATUS_CODE);
339 put_opt6_short(DHCP6USEMULTI);
340 put_opt6_string("Use multicast");
341 end_opt6(o1);
342 return 1;
343 }
344
345 /* match vendor and user class options */
346 for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
347 {
348 int mopt;
349
350 if (vendor->match_type == MATCH_VENDOR)
351 mopt = OPTION6_VENDOR_CLASS;
352 else if (vendor->match_type == MATCH_USER)
353 mopt = OPTION6_USER_CLASS;
354 else
355 continue;
356
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100357 if ((opt = opt6_find(state->packet_options, state->end, mopt, 2)))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000358 {
359 void *enc_opt, *enc_end = opt6_ptr(opt, opt6_len(opt));
Simon Kelleya5c72ab2012-02-10 13:42:47 +0000360 int offset = 0;
361
362 if (mopt == OPTION6_VENDOR_CLASS)
363 {
364 if (opt6_len(opt) < 4)
365 continue;
366
367 if (vendor->enterprise != opt6_uint(opt, 0, 4))
368 continue;
369
370 offset = 4;
371 }
372
Tanguy Bouzelocef1d7422013-10-03 11:06:31 +0100373 /* Note that format if user/vendor classes is different to DHCP options - no option types. */
374 for (enc_opt = opt6_ptr(opt, offset); enc_opt; enc_opt = opt6_user_vendor_next(enc_opt, enc_end))
375 for (i = 0; i <= (opt6_user_vendor_len(enc_opt) - vendor->len); i++)
376 if (memcmp(vendor->data, opt6_user_vendor_ptr(enc_opt, i), vendor->len) == 0)
Simon Kelley4cb1b322012-02-06 14:30:41 +0000377 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100378 vendor->netid.next = state->tags;
379 state->tags = &vendor->netid;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000380 break;
381 }
382 }
383 }
Simon Kelley3634c542012-02-08 14:22:37 +0000384
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100385 if (option_bool(OPT_LOG_OPTS) && (opt = opt6_find(state->packet_options, state->end, OPTION6_VENDOR_CLASS, 4)))
386 my_syslog(MS_DHCP | LOG_INFO, _("%u vendor class: %u"), state->xid, opt6_uint(opt, 0, 4));
Simon Kelley1567fea2012-03-12 22:15:35 +0000387
Simon Kelley3634c542012-02-08 14:22:37 +0000388 /* dhcp-match. If we have hex-and-wildcards, look for a left-anchored match.
389 Otherwise assume the option is an array, and look for a matching element.
Josh Soref730c6742017-02-06 16:14:04 +0000390 If no data given, existence of the option is enough. This code handles
Simon Kelley3634c542012-02-08 14:22:37 +0000391 V-I opts too. */
392 for (opt_cfg = daemon->dhcp_match6; opt_cfg; opt_cfg = opt_cfg->next)
393 {
Simon Kelleyceae00d2012-02-09 21:28:14 +0000394 int match = 0;
395
Simon Kelley3634c542012-02-08 14:22:37 +0000396 if (opt_cfg->flags & DHOPT_RFC3925)
397 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100398 for (opt = opt6_find(state->packet_options, state->end, OPTION6_VENDOR_OPTS, 4);
Simon Kelley3634c542012-02-08 14:22:37 +0000399 opt;
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100400 opt = opt6_find(opt6_next(opt, state->end), state->end, OPTION6_VENDOR_OPTS, 4))
Simon Kelley3634c542012-02-08 14:22:37 +0000401 {
402 void *vopt;
403 void *vend = opt6_ptr(opt, opt6_len(opt));
404
405 for (vopt = opt6_find(opt6_ptr(opt, 4), vend, opt_cfg->opt, 0);
406 vopt;
407 vopt = opt6_find(opt6_next(vopt, vend), vend, opt_cfg->opt, 0))
Simon Kelleyceae00d2012-02-09 21:28:14 +0000408 if ((match = match_bytes(opt_cfg, opt6_ptr(vopt, 0), opt6_len(vopt))))
Simon Kelley3634c542012-02-08 14:22:37 +0000409 break;
410 }
411 if (match)
412 break;
413 }
414 else
415 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100416 if (!(opt = opt6_find(state->packet_options, state->end, opt_cfg->opt, 1)))
Simon Kelley3634c542012-02-08 14:22:37 +0000417 continue;
418
419 match = match_bytes(opt_cfg, opt6_ptr(opt, 0), opt6_len(opt));
420 }
421
422 if (match)
423 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100424 opt_cfg->netid->next = state->tags;
425 state->tags = opt_cfg->netid;
Simon Kelley3634c542012-02-08 14:22:37 +0000426 }
427 }
Simon Kelley89500e32013-09-20 16:29:20 +0100428
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100429 if (state->mac_len != 0)
Simon Kelleyd81b42d2013-09-23 12:26:34 +0100430 {
431 if (option_bool(OPT_LOG_OPTS))
Simon Kelley89500e32013-09-20 16:29:20 +0100432 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100433 print_mac(daemon->dhcp_buff, state->mac, state->mac_len);
434 my_syslog(MS_DHCP | LOG_INFO, _("%u client MAC address: %s"), state->xid, daemon->dhcp_buff);
Simon Kelley89500e32013-09-20 16:29:20 +0100435 }
Simon Kelleyd81b42d2013-09-23 12:26:34 +0100436
437 for (mac_opt = daemon->dhcp_macs; mac_opt; mac_opt = mac_opt->next)
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100438 if ((unsigned)mac_opt->hwaddr_len == state->mac_len &&
439 ((unsigned)mac_opt->hwaddr_type == state->mac_type || mac_opt->hwaddr_type == 0) &&
440 memcmp_masked(mac_opt->hwaddr, state->mac, state->mac_len, mac_opt->mask))
Simon Kelleyd81b42d2013-09-23 12:26:34 +0100441 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100442 mac_opt->netid.next = state->tags;
443 state->tags = &mac_opt->netid;
Simon Kelleyd81b42d2013-09-23 12:26:34 +0100444 }
445 }
Simon Kelley4cb1b322012-02-06 14:30:41 +0000446
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100447 if ((opt = opt6_find(state->packet_options, state->end, OPTION6_FQDN, 1)))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000448 {
449 /* RFC4704 refers */
450 int len = opt6_len(opt) - 1;
451
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100452 state->fqdn_flags = opt6_uint(opt, 0, 1);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000453
454 /* Always force update, since the client has no way to do it itself. */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100455 if (!option_bool(OPT_FQDN_UPDATE) && !(state->fqdn_flags & 0x01))
456 state->fqdn_flags |= 0x03;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000457
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100458 state->fqdn_flags &= ~0x04;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000459
460 if (len != 0 && len < 255)
461 {
Simon Kelleyfbbc1452012-03-30 20:48:20 +0100462 unsigned char *pp, *op = opt6_ptr(opt, 1);
463 char *pq = daemon->dhcp_buff;
464
465 pp = op;
466 while (*op != 0 && ((op + (*op)) - pp) < len)
467 {
468 memcpy(pq, op+1, *op);
469 pq += *op;
470 op += (*op)+1;
471 *(pq++) = '.';
472 }
473
474 if (pq != daemon->dhcp_buff)
475 pq--;
476 *pq = 0;
477
478 if (legal_hostname(daemon->dhcp_buff))
479 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100480 state->client_hostname = daemon->dhcp_buff;
Simon Kelleyfbbc1452012-03-30 20:48:20 +0100481 if (option_bool(OPT_LOG_OPTS))
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100482 my_syslog(MS_DHCP | LOG_INFO, _("%u client provides name: %s"), state->xid, state->client_hostname);
Simon Kelleyfbbc1452012-03-30 20:48:20 +0100483 }
Simon Kelley4cb1b322012-02-06 14:30:41 +0000484 }
485 }
486
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100487 if (state->clid)
Simon Kelley4cb1b322012-02-06 14:30:41 +0000488 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100489 config = find_config(daemon->dhcp_conf, state->context, state->clid, state->clid_len, state->mac, state->mac_len, state->mac_type, NULL);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000490
491 if (have_config(config, CONFIG_NAME))
492 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100493 state->hostname = config->hostname;
494 state->domain = config->domain;
495 state->hostname_auth = 1;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000496 }
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100497 else if (state->client_hostname)
Simon Kelley4cb1b322012-02-06 14:30:41 +0000498 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100499 state->domain = strip_hostname(state->client_hostname);
Simon Kelley70c5e3e2012-02-06 22:05:15 +0000500
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100501 if (strlen(state->client_hostname) != 0)
Simon Kelley4cb1b322012-02-06 14:30:41 +0000502 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100503 state->hostname = state->client_hostname;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000504 if (!config)
505 {
506 /* Search again now we have a hostname.
Simon Kelley00e9ad52012-02-16 21:53:11 +0000507 Only accept configs without CLID here, (it won't match)
Simon Kelley4cb1b322012-02-06 14:30:41 +0000508 to avoid impersonation by name. */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100509 struct dhcp_config *new = find_config(daemon->dhcp_conf, state->context, NULL, 0, NULL, 0, 0, state->hostname);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000510 if (new && !have_config(new, CONFIG_CLID) && !new->hwaddr)
511 config = new;
512 }
513 }
514 }
515 }
516
517 if (config)
518 {
519 struct dhcp_netid_list *list;
520
521 for (list = config->netid; list; list = list->next)
522 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100523 list->list->next = state->tags;
524 state->tags = list->list;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000525 }
526
527 /* set "known" tag for known hosts */
528 known_id.net = "known";
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100529 known_id.next = state->tags;
530 state->tags = &known_id;
Simon Kelley3634c542012-02-08 14:22:37 +0000531
532 if (have_config(config, CONFIG_DISABLE))
533 ignore = 1;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000534 }
Simon Kelleyb2a9c572017-04-30 18:21:31 +0100535 else if (state->clid &&
536 find_config(daemon->dhcp_conf, NULL, state->clid, state->clid_len, state->mac, state->mac_len, state->mac_type, NULL))
537 {
538 known_id.net = "known-othernet";
539 known_id.next = state->tags;
540 state->tags = &known_id;
541 }
542
Simon Kelleyc6309242013-03-07 20:59:28 +0000543#ifdef OPTION6_PREFIX_CLASS
Simon Kelley6e37ab52013-03-19 20:50:11 +0000544 /* OPTION_PREFIX_CLASS in ORO, send addresses in all prefix classes */
545 if (daemon->prefix_classes && (msg_type == DHCP6SOLICIT || msg_type == DHCP6REQUEST))
Simon Kelleyc6309242013-03-07 20:59:28 +0000546 {
Simon Kelley6e37ab52013-03-19 20:50:11 +0000547 void *oro;
548
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100549 if ((oro = opt6_find(state->packet_options, state->end, OPTION6_ORO, 0)))
Simon Kelley6e37ab52013-03-19 20:50:11 +0000550 for (i = 0; i < opt6_len(oro) - 1; i += 2)
551 if (opt6_uint(oro, i, 2) == OPTION6_PREFIX_CLASS)
552 {
553 dump_all_prefix_classes = 1;
554 break;
555 }
556
557 if (msg_type != DHCP6SOLICIT || dump_all_prefix_classes)
558 /* Add the tags associated with prefix classes so we can use the DHCP ranges.
559 Not done for SOLICIT as we add them one-at-time. */
560 for (p = daemon->prefix_classes; p ; p = p->next)
561 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100562 p->tag.next = state->tags;
563 state->tags = &p->tag;
Simon Kelley6e37ab52013-03-19 20:50:11 +0000564 }
565 }
Simon Kelleyc6309242013-03-07 20:59:28 +0000566#endif
567
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100568 tagif = run_tag_if(state->tags);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000569
Simon Kelley3634c542012-02-08 14:22:37 +0000570 /* if all the netids in the ignore list are present, ignore this client */
571 if (daemon->dhcp_ignore)
572 {
573 struct dhcp_netid_list *id_list;
574
Simon Kelley3634c542012-02-08 14:22:37 +0000575 for (id_list = daemon->dhcp_ignore; id_list; id_list = id_list->next)
576 if (match_netid(id_list->list, tagif, 0))
577 ignore = 1;
578 }
Simon Kelley00e9ad52012-02-16 21:53:11 +0000579
580 /* if all the netids in the ignore_name list are present, ignore client-supplied name */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100581 if (!state->hostname_auth)
Simon Kelley00e9ad52012-02-16 21:53:11 +0000582 {
583 struct dhcp_netid_list *id_list;
584
585 for (id_list = daemon->dhcp_ignore_names; id_list; id_list = id_list->next)
586 if ((!id_list->list) || match_netid(id_list->list, tagif, 0))
587 break;
588 if (id_list)
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100589 state->hostname = NULL;
Simon Kelley00e9ad52012-02-16 21:53:11 +0000590 }
591
Simon Kelley4cb1b322012-02-06 14:30:41 +0000592
593 switch (msg_type)
594 {
Simon Kelley70c5e3e2012-02-06 22:05:15 +0000595 default:
596 return 0;
Simon Kelleyc8f2dd82013-09-13 11:22:55 +0100597
598
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000599 case DHCP6SOLICIT:
600 {
Simon Kelleyde92b472013-03-15 18:25:10 +0000601 int address_assigned = 0;
Simon Kelleyc6309242013-03-07 20:59:28 +0000602 /* tags without all prefix-class tags */
Simon Kelley8f51a292013-09-21 14:07:12 +0100603 struct dhcp_netid *solicit_tags;
Simon Kelleyde92b472013-03-15 18:25:10 +0000604 struct dhcp_context *c;
Simon Kelleyc8f2dd82013-09-13 11:22:55 +0100605
606 *outmsgtypep = DHCP6ADVERTISE;
607
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100608 if (opt6_find(state->packet_options, state->end, OPTION6_RAPID_COMMIT, 0))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000609 {
Simon Kelleyc8f2dd82013-09-13 11:22:55 +0100610 *outmsgtypep = DHCP6REPLY;
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100611 state->lease_allocate = 1;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000612 o = new_opt6(OPTION6_RAPID_COMMIT);
613 end_opt6(o);
614 }
Simon Kelley3634c542012-02-08 14:22:37 +0000615
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +0100616 log6_quiet(state, "DHCPSOLICIT", NULL, ignore ? _("ignored") : NULL);
Simon Kelleyc8f2dd82013-09-13 11:22:55 +0100617
618 request_no_address:
Simon Kelley8f51a292013-09-21 14:07:12 +0100619 solicit_tags = tagif;
620
Simon Kelley3634c542012-02-08 14:22:37 +0000621 if (ignore)
622 return 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000623
Simon Kelley52a1ae72013-03-06 22:43:26 +0000624 /* reset USED bits in leases */
625 lease6_reset();
Simon Kelleyde92b472013-03-15 18:25:10 +0000626
627 /* Can use configured address max once per prefix */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100628 for (c = state->context; c; c = c->current)
Simon Kelleyde92b472013-03-15 18:25:10 +0000629 c->flags &= ~CONTEXT_CONF_USED;
630
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100631 for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000632 {
Simon Kelley4cb1b322012-02-06 14:30:41 +0000633 void *ia_option, *ia_end;
634 unsigned int min_time = 0xffffffff;
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000635 int t1cntr;
Simon Kelleyc6309242013-03-07 20:59:28 +0000636 int ia_counter;
637 /* set unless we're sending a particular prefix-class, when we
638 want only dhcp-ranges with the correct tags set and not those without any tags. */
639 int plain_range = 1;
Simon Kelleycc4baaa2013-08-05 15:03:44 +0100640 u32 lease_time;
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000641 struct dhcp_lease *ltmp;
Simon Kelley97f876b2018-08-21 22:06:36 +0100642 struct in6_addr req_addr, addr;
643
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100644 if (!check_ia(state, opt, &ia_end, &ia_option))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000645 continue;
646
Simon Kelley52a1ae72013-03-06 22:43:26 +0000647 /* reset USED bits in contexts - one address per prefix per IAID */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100648 for (c = state->context; c; c = c->current)
Simon Kelley52a1ae72013-03-06 22:43:26 +0000649 c->flags &= ~CONTEXT_USED;
Simon Kelleyc6309242013-03-07 20:59:28 +0000650
651#ifdef OPTION6_PREFIX_CLASS
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100652 if (daemon->prefix_classes && state->ia_type == OPTION6_IA_NA)
Simon Kelleyc6309242013-03-07 20:59:28 +0000653 {
Simon Kelley6e37ab52013-03-19 20:50:11 +0000654 void *prefix_opt;
Simon Kelleyc6309242013-03-07 20:59:28 +0000655 int prefix_class;
656
Simon Kelley6e37ab52013-03-19 20:50:11 +0000657 if (dump_all_prefix_classes)
658 /* OPTION_PREFIX_CLASS in ORO, send addresses in all prefix classes */
659 plain_range = 0;
Simon Kelleyc6309242013-03-07 20:59:28 +0000660 else
661 {
662 if ((prefix_opt = opt6_find(opt6_ptr(opt, 12), ia_end, OPTION6_PREFIX_CLASS, 2)))
663 {
664
665 prefix_class = opt6_uint(prefix_opt, 0, 2);
666
667 for (p = daemon->prefix_classes; p ; p = p->next)
668 if (p->class == prefix_class)
669 break;
670
671 if (!p)
672 my_syslog(MS_DHCP | LOG_WARNING, _("unknown prefix-class %d"), prefix_class);
673 else
674 {
675 /* add tag to list, and exclude undecorated dhcp-ranges */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100676 p->tag.next = state->tags;
Simon Kelleyc6309242013-03-07 20:59:28 +0000677 solicit_tags = run_tag_if(&p->tag);
678 plain_range = 0;
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100679 state->send_prefix_class = p;
Simon Kelleyc6309242013-03-07 20:59:28 +0000680 }
681 }
682 else
683 {
684 /* client didn't ask for a prefix class, lets see if we can find one. */
685 for (p = daemon->prefix_classes; p ; p = p->next)
686 {
687 p->tag.next = NULL;
688 if (match_netid(&p->tag, solicit_tags, 1))
689 break;
690 }
691
692 if (p)
693 {
694 plain_range = 0;
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100695 state->send_prefix_class = p;
Simon Kelleyc6309242013-03-07 20:59:28 +0000696 }
697 }
698
699 if (p && option_bool(OPT_LOG_OPTS))
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100700 my_syslog(MS_DHCP | LOG_INFO, "%u prefix class %d tag:%s", state->xid, p->class, p->tag.net);
Simon Kelleyc6309242013-03-07 20:59:28 +0000701 }
702 }
703#endif
704
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100705 o = build_ia(state, &t1cntr);
Vladislav Grishenkob9ff5c82014-10-06 14:34:24 +0100706 if (address_assigned)
707 address_assigned = 2;
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000708
Simon Kelleyc6309242013-03-07 20:59:28 +0000709 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 +0000710 {
Simon Kelley97f876b2018-08-21 22:06:36 +0100711 /* worry about alignment here. */
712 memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
Simon Kelleycc4baaa2013-08-05 15:03:44 +0100713
Simon Kelley97f876b2018-08-21 22:06:36 +0100714 if ((c = address6_valid(state->context, &req_addr, solicit_tags, plain_range)))
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000715 {
716 lease_time = c->lease_time;
717 /* If the client asks for an address on the same network as a configured address,
718 offer the configured address instead, to make moving to newly-configured
719 addresses automatic. */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100720 if (!(c->flags & CONTEXT_CONF_USED) && config_valid(config, c, &addr) && check_address(state, &addr))
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000721 {
Simon Kelley97f876b2018-08-21 22:06:36 +0100722 req_addr = addr;
Simon Kelleyde92b472013-03-15 18:25:10 +0000723 mark_config_used(c, &addr);
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000724 if (have_config(config, CONFIG_TIME))
725 lease_time = config->lease_time;
726 }
Simon Kelley97f876b2018-08-21 22:06:36 +0100727 else if (!(c = address6_available(state->context, &req_addr, solicit_tags, plain_range)))
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000728 continue; /* not an address we're allowed */
Simon Kelley97f876b2018-08-21 22:06:36 +0100729 else if (!check_address(state, &req_addr))
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000730 continue; /* address leased elsewhere */
731
732 /* add address to output packet */
Simon Kelleyc6309242013-03-07 20:59:28 +0000733#ifdef OPTION6_PREFIX_CLASS
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100734 if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA)
735 state->send_prefix_class = prefix_class_from_context(c);
Simon Kelleyc6309242013-03-07 20:59:28 +0000736#endif
Simon Kelley97f876b2018-08-21 22:06:36 +0100737 add_address(state, c, lease_time, ia_option, &min_time, &req_addr, now);
738 mark_context_used(state, &req_addr);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100739 get_context_tag(state, c);
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000740 address_assigned = 1;
741 }
Simon Kelley4cb1b322012-02-06 14:30:41 +0000742 }
743
Simon Kelleyde92b472013-03-15 18:25:10 +0000744 /* Suggest configured address(es) */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100745 for (c = state->context; c; c = c->current)
Simon Kelleya1a79ed2013-03-15 21:19:57 +0000746 if (!(c->flags & CONTEXT_CONF_USED) &&
747 match_netid(c->filter, solicit_tags, plain_range) &&
748 config_valid(config, c, &addr) &&
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100749 check_address(state, &addr))
Simon Kelleyde92b472013-03-15 18:25:10 +0000750 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100751 mark_config_used(state->context, &addr);
Simon Kelleyde92b472013-03-15 18:25:10 +0000752 if (have_config(config, CONFIG_TIME))
753 lease_time = config->lease_time;
Simon Kelleya1a79ed2013-03-15 21:19:57 +0000754 else
755 lease_time = c->lease_time;
Simon Kelleyde92b472013-03-15 18:25:10 +0000756 /* add address to output packet */
Simon Kelleyc6309242013-03-07 20:59:28 +0000757#ifdef OPTION6_PREFIX_CLASS
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100758 if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA)
759 state->send_prefix_class = prefix_class_from_context(c);
Simon Kelleyc6309242013-03-07 20:59:28 +0000760#endif
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100761 add_address(state, c, lease_time, NULL, &min_time, &addr, now);
762 mark_context_used(state, &addr);
763 get_context_tag(state, c);
Simon Kelleyde92b472013-03-15 18:25:10 +0000764 address_assigned = 1;
765 }
766
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000767 /* return addresses for existing leases */
768 ltmp = NULL;
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100769 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 +0000770 {
Simon Kelley97f876b2018-08-21 22:06:36 +0100771 req_addr = ltmp->addr6;
772 if ((c = address6_available(state->context, &req_addr, solicit_tags, plain_range)))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000773 {
Simon Kelleyc6309242013-03-07 20:59:28 +0000774#ifdef OPTION6_PREFIX_CLASS
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100775 if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA)
776 state->send_prefix_class = prefix_class_from_context(c);
Simon Kelleyc6309242013-03-07 20:59:28 +0000777#endif
Simon Kelley97f876b2018-08-21 22:06:36 +0100778 add_address(state, c, c->lease_time, NULL, &min_time, &req_addr, now);
779 mark_context_used(state, &req_addr);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100780 get_context_tag(state, c);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000781 address_assigned = 1;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000782 }
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000783 }
784
785 /* Return addresses for all valid contexts which don't yet have one */
Simon Kelley6586e832013-11-07 14:20:13 +0000786 while ((c = address6_allocate(state->context, state->clid, state->clid_len, state->ia_type == OPTION6_IA_TA,
787 state->iaid, ia_counter, solicit_tags, plain_range, &addr)))
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000788 {
Simon Kelleyc6309242013-03-07 20:59:28 +0000789#ifdef OPTION6_PREFIX_CLASS
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100790 if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA)
791 state->send_prefix_class = prefix_class_from_context(c);
Simon Kelleyc6309242013-03-07 20:59:28 +0000792#endif
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100793 add_address(state, c, c->lease_time, NULL, &min_time, &addr, now);
794 mark_context_used(state, &addr);
795 get_context_tag(state, c);
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000796 address_assigned = 1;
797 }
798
Vladislav Grishenkob9ff5c82014-10-06 14:34:24 +0100799 if (address_assigned != 1)
800 {
801 /* If the server will not assign any addresses to any IAs in a
802 subsequent Request from the client, the server MUST send an Advertise
803 message to the client that doesn't include any IA options. */
804 if (!state->lease_allocate)
805 {
806 save_counter(o);
807 continue;
808 }
809
810 /* If the server cannot assign any addresses to an IA in the message
811 from the client, the server MUST include the IA in the Reply message
812 with no addresses in the IA and a Status Code option in the IA
813 containing status code NoAddrsAvail. */
814 o1 = new_opt6(OPTION6_STATUS_CODE);
815 put_opt6_short(DHCP6NOADDRS);
816 put_opt6_string(_("address unavailable"));
817 end_opt6(o1);
818 }
819
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000820 end_ia(t1cntr, min_time, 0);
821 end_opt6(o);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000822 }
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000823
824 if (address_assigned)
825 {
826 o1 = new_opt6(OPTION6_STATUS_CODE);
827 put_opt6_short(DHCP6SUCCESS);
Simon Kelleyde92b472013-03-15 18:25:10 +0000828 put_opt6_string(_("success"));
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000829 end_opt6(o1);
830
831 /* If --dhcp-authoritative is set, we can tell client not to wait for
832 other possible servers */
833 o = new_opt6(OPTION6_PREFERENCE);
834 put_opt6_char(option_bool(OPT_AUTHORITATIVE) ? 255 : 0);
835 end_opt6(o);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100836 tagif = add_options(state, 0);
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000837 }
838 else
839 {
840 /* no address, return error */
841 o1 = new_opt6(OPTION6_STATUS_CODE);
842 put_opt6_short(DHCP6NOADDRS);
Simon Kelleyde92b472013-03-15 18:25:10 +0000843 put_opt6_string(_("no addresses available"));
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000844 end_opt6(o1);
Simon Kelley338b3402015-04-20 21:34:05 +0100845
846 /* Some clients will ask repeatedly when we're not giving
847 out addresses because we're in stateless mode. Avoid spamming
848 the log in that case. */
849 for (c = state->context; c; c = c->current)
850 if (!(c->flags & CONTEXT_RA_STATELESS))
851 {
852 log6_packet(state, state->lease_allocate ? "DHCPREPLY" : "DHCPADVERTISE", NULL, _("no addresses available"));
853 break;
854 }
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000855 }
856
Simon Kelley4cb1b322012-02-06 14:30:41 +0000857 break;
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000858 }
859
860 case DHCP6REQUEST:
861 {
862 int address_assigned = 0;
Simon Kelleyc8f2dd82013-09-13 11:22:55 +0100863 int start = save_counter(-1);
864
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000865 /* set reply message type */
866 *outmsgtypep = DHCP6REPLY;
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100867 state->lease_allocate = 1;
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000868
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +0100869 log6_quiet(state, "DHCPREQUEST", NULL, ignore ? _("ignored") : NULL);
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000870
871 if (ignore)
872 return 0;
873
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100874 for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000875 {
876 void *ia_option, *ia_end;
877 unsigned int min_time = 0xffffffff;
878 int t1cntr;
879
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100880 if (!check_ia(state, opt, &ia_end, &ia_option))
Simon Kelley3a654c52013-03-06 22:17:48 +0000881 continue;
Simon Kelleyc8f2dd82013-09-13 11:22:55 +0100882
883 if (!ia_option)
884 {
Ville Skyttäfaaf3062018-01-14 17:32:52 +0000885 /* If we get a request with an IA_*A without addresses, treat it exactly like
Simon Kelleyc8f2dd82013-09-13 11:22:55 +0100886 a SOLICT with rapid commit set. */
887 save_counter(start);
888 goto request_no_address;
889 }
890
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100891 o = build_ia(state, &t1cntr);
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000892
893 for (; ia_option; ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
894 {
Simon Kelley97f876b2018-08-21 22:06:36 +0100895 struct in6_addr req_addr;
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000896 struct dhcp_context *dynamic, *c;
897 unsigned int lease_time;
Simon Kelleyde92b472013-03-15 18:25:10 +0000898 struct in6_addr addr;
899 int config_ok = 0;
Simon Kelley97f876b2018-08-21 22:06:36 +0100900
901 /* align. */
902 memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
Simon Kelleyde92b472013-03-15 18:25:10 +0000903
Simon Kelley97f876b2018-08-21 22:06:36 +0100904 if ((c = address6_valid(state->context, &req_addr, tagif, 1)))
905 config_ok = config_valid(config, c, &addr) && IN6_ARE_ADDR_EQUAL(&addr, &req_addr);
Simon Kelleyde92b472013-03-15 18:25:10 +0000906
Simon Kelley97f876b2018-08-21 22:06:36 +0100907 if ((dynamic = address6_available(state->context, &req_addr, tagif, 1)) || c)
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000908 {
Simon Kelleyde92b472013-03-15 18:25:10 +0000909 if (!dynamic && !config_ok)
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000910 {
911 /* Static range, not configured. */
912 o1 = new_opt6(OPTION6_STATUS_CODE);
Vladislav Grishenkob9ff5c82014-10-06 14:34:24 +0100913 put_opt6_short(DHCP6NOADDRS);
Simon Kelleyde92b472013-03-15 18:25:10 +0000914 put_opt6_string(_("address unavailable"));
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000915 end_opt6(o1);
916 }
Simon Kelley97f876b2018-08-21 22:06:36 +0100917 else if (!check_address(state, &req_addr))
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000918 {
919 /* Address leased to another DUID/IAID */
920 o1 = new_opt6(OPTION6_STATUS_CODE);
921 put_opt6_short(DHCP6UNSPEC);
Simon Kelleyde92b472013-03-15 18:25:10 +0000922 put_opt6_string(_("address in use"));
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000923 end_opt6(o1);
924 }
925 else
926 {
927 if (!dynamic)
928 dynamic = c;
929
930 lease_time = dynamic->lease_time;
931
Simon Kelleyde92b472013-03-15 18:25:10 +0000932 if (config_ok && have_config(config, CONFIG_TIME))
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000933 lease_time = config->lease_time;
934
Simon Kelley6e37ab52013-03-19 20:50:11 +0000935#ifdef OPTION6_PREFIX_CLASS
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100936 if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA)
937 state->send_prefix_class = prefix_class_from_context(c);
Simon Kelley6e37ab52013-03-19 20:50:11 +0000938#endif
Simon Kelley97f876b2018-08-21 22:06:36 +0100939 add_address(state, dynamic, lease_time, ia_option, &min_time, &req_addr, now);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100940 get_context_tag(state, dynamic);
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000941 address_assigned = 1;
942 }
943 }
Simon Kelleyde92b472013-03-15 18:25:10 +0000944 else
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000945 {
946 /* requested address not on the correct link */
947 o1 = new_opt6(OPTION6_STATUS_CODE);
948 put_opt6_short(DHCP6NOTONLINK);
Simon Kelleyde92b472013-03-15 18:25:10 +0000949 put_opt6_string(_("not on link"));
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000950 end_opt6(o1);
951 }
952 }
953
954 end_ia(t1cntr, min_time, 0);
955 end_opt6(o);
956 }
957
958 if (address_assigned)
959 {
960 o1 = new_opt6(OPTION6_STATUS_CODE);
961 put_opt6_short(DHCP6SUCCESS);
Simon Kelleyde92b472013-03-15 18:25:10 +0000962 put_opt6_string(_("success"));
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000963 end_opt6(o1);
964 }
965 else
966 {
967 /* no address, return error */
968 o1 = new_opt6(OPTION6_STATUS_CODE);
969 put_opt6_short(DHCP6NOADDRS);
Simon Kelleyde92b472013-03-15 18:25:10 +0000970 put_opt6_string(_("no addresses available"));
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000971 end_opt6(o1);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100972 log6_packet(state, "DHCPREPLY", NULL, _("no addresses available"));
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000973 }
974
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100975 tagif = add_options(state, 0);
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000976 break;
977 }
978
979
Simon Kelley4cb1b322012-02-06 14:30:41 +0000980 case DHCP6RENEW:
981 {
982 /* set reply message type */
983 *outmsgtypep = DHCP6REPLY;
984
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +0100985 log6_quiet(state, "DHCPRENEW", NULL, NULL);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000986
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100987 for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000988 {
Simon Kelley4cb1b322012-02-06 14:30:41 +0000989 void *ia_option, *ia_end;
990 unsigned int min_time = 0xffffffff;
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000991 int t1cntr, iacntr;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000992
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100993 if (!check_ia(state, opt, &ia_end, &ia_option))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000994 continue;
995
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100996 o = build_ia(state, &t1cntr);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000997 iacntr = save_counter(-1);
998
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000999 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 +00001000 {
1001 struct dhcp_lease *lease = NULL;
Simon Kelley97f876b2018-08-21 22:06:36 +01001002 struct in6_addr req_addr;
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001003 unsigned int preferred_time = opt6_uint(ia_option, 16, 4);
1004 unsigned int valid_time = opt6_uint(ia_option, 20, 4);
Simon Kelleyde92b472013-03-15 18:25:10 +00001005 char *message = NULL;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001006 struct dhcp_context *this_context;
Simon Kelley97f876b2018-08-21 22:06:36 +01001007
1008 memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001009
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001010 if (!(lease = lease6_find(state->clid, state->clid_len,
1011 state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
Simon Kelley97f876b2018-08-21 22:06:36 +01001012 state->iaid, &req_addr)))
Simon Kelley4cb1b322012-02-06 14:30:41 +00001013 {
1014 /* If the server cannot find a client entry for the IA the server
1015 returns the IA containing no addresses with a Status Code option set
1016 to NoBinding in the Reply message. */
1017 save_counter(iacntr);
1018 t1cntr = 0;
1019
Simon Kelley97f876b2018-08-21 22:06:36 +01001020 log6_packet(state, "DHCPREPLY", &req_addr, _("lease not found"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00001021
1022 o1 = new_opt6(OPTION6_STATUS_CODE);
1023 put_opt6_short(DHCP6NOBINDING);
Simon Kelleyde92b472013-03-15 18:25:10 +00001024 put_opt6_string(_("no binding found"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00001025 end_opt6(o1);
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001026
1027 preferred_time = valid_time = 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001028 break;
1029 }
1030
Simon Kelley00e9ad52012-02-16 21:53:11 +00001031
Simon Kelley97f876b2018-08-21 22:06:36 +01001032 if ((this_context = address6_available(state->context, &req_addr, tagif, 1)) ||
1033 (this_context = address6_valid(state->context, &req_addr, tagif, 1)))
Simon Kelleyc8257542012-03-28 21:15:41 +01001034 {
Simon Kelleyde92b472013-03-15 18:25:10 +00001035 struct in6_addr addr;
1036 unsigned int lease_time;
1037
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001038 get_context_tag(state, this_context);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001039
Simon Kelley97f876b2018-08-21 22:06:36 +01001040 if (config_valid(config, this_context, &addr) && IN6_ARE_ADDR_EQUAL(&addr, &req_addr) && have_config(config, CONFIG_TIME))
Simon Kelleyde92b472013-03-15 18:25:10 +00001041 lease_time = config->lease_time;
1042 else
1043 lease_time = this_context->lease_time;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001044
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001045 calculate_times(this_context, &min_time, &valid_time, &preferred_time, lease_time);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001046
Simon Kelleyde92b472013-03-15 18:25:10 +00001047 lease_set_expires(lease, valid_time, now);
Simon Kelley89500e32013-09-20 16:29:20 +01001048 /* Update MAC record in case it's new information. */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001049 if (state->mac_len != 0)
1050 lease_set_hwaddr(lease, state->mac, state->clid, state->mac_len, state->mac_type, state->clid_len, now, 0);
1051 if (state->ia_type == OPTION6_IA_NA && state->hostname)
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001052 {
Simon Kelley97f876b2018-08-21 22:06:36 +01001053 char *addr_domain = get_domain6(&req_addr);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001054 if (!state->send_domain)
1055 state->send_domain = addr_domain;
1056 lease_set_hostname(lease, state->hostname, state->hostname_auth, addr_domain, state->domain);
1057 message = state->hostname;
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001058 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001059
Simon Kelleyde92b472013-03-15 18:25:10 +00001060
1061 if (preferred_time == 0)
1062 message = _("deprecated");
Simon Kelley4cb1b322012-02-06 14:30:41 +00001063 }
Simon Kelleyde92b472013-03-15 18:25:10 +00001064 else
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001065 {
1066 preferred_time = valid_time = 0;
1067 message = _("address invalid");
Simon Kelleya5ae1f82015-04-25 21:46:10 +01001068 }
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001069
Simon Kelleya5ae1f82015-04-25 21:46:10 +01001070 if (message && (message != state->hostname))
Simon Kelley97f876b2018-08-21 22:06:36 +01001071 log6_packet(state, "DHCPREPLY", &req_addr, message);
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01001072 else
Simon Kelley97f876b2018-08-21 22:06:36 +01001073 log6_quiet(state, "DHCPREPLY", &req_addr, message);
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01001074
Simon Kelley4cb1b322012-02-06 14:30:41 +00001075 o1 = new_opt6(OPTION6_IAADDR);
Simon Kelley97f876b2018-08-21 22:06:36 +01001076 put_opt6(&req_addr, sizeof(req_addr));
Simon Kelleyde92b472013-03-15 18:25:10 +00001077 put_opt6_long(preferred_time);
1078 put_opt6_long(valid_time);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001079 end_opt6(o1);
1080 }
1081
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001082 end_ia(t1cntr, min_time, 1);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001083 end_opt6(o);
1084 }
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001085
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001086 tagif = add_options(state, 0);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001087 break;
1088
1089 }
1090
1091 case DHCP6CONFIRM:
1092 {
Ilya Ponetaev2d75f2e2014-09-13 21:11:16 +01001093 int good_addr = 0;
1094
Simon Kelley4cb1b322012-02-06 14:30:41 +00001095 /* set reply message type */
1096 *outmsgtypep = DHCP6REPLY;
1097
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01001098 log6_quiet(state, "DHCPCONFIRM", NULL, NULL);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001099
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001100 for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
Simon Kelley4cb1b322012-02-06 14:30:41 +00001101 {
Simon Kelley4cb1b322012-02-06 14:30:41 +00001102 void *ia_option, *ia_end;
1103
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001104 for (check_ia(state, opt, &ia_end, &ia_option);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001105 ia_option;
1106 ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
1107 {
Simon Kelley97f876b2018-08-21 22:06:36 +01001108 struct in6_addr req_addr;
1109
1110 /* alignment */
1111 memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001112
Simon Kelley97f876b2018-08-21 22:06:36 +01001113 if (!address6_valid(state->context, &req_addr, tagif, 1))
Simon Kelley4cb1b322012-02-06 14:30:41 +00001114 {
1115 o1 = new_opt6(OPTION6_STATUS_CODE);
1116 put_opt6_short(DHCP6NOTONLINK);
Simon Kelleyde92b472013-03-15 18:25:10 +00001117 put_opt6_string(_("confirm failed"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00001118 end_opt6(o1);
Simon Kelley97f876b2018-08-21 22:06:36 +01001119 log6_quiet(state, "DHCPREPLY", &req_addr, _("confirm failed"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00001120 return 1;
1121 }
1122
Ilya Ponetaev2d75f2e2014-09-13 21:11:16 +01001123 good_addr = 1;
Simon Kelley97f876b2018-08-21 22:06:36 +01001124 log6_quiet(state, "DHCPREPLY", &req_addr, state->hostname);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001125 }
1126 }
Ilya Ponetaev2d75f2e2014-09-13 21:11:16 +01001127
1128 /* No addresses, no reply: RFC 3315 18.2.2 */
1129 if (!good_addr)
1130 return 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001131
1132 o1 = new_opt6(OPTION6_STATUS_CODE);
1133 put_opt6_short(DHCP6SUCCESS );
Simon Kelleyde92b472013-03-15 18:25:10 +00001134 put_opt6_string(_("all addresses still on link"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00001135 end_opt6(o1);
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001136 break;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001137 }
1138
1139 case DHCP6IREQ:
1140 {
Simon Kelleyd1e9a582012-10-23 17:00:57 +01001141 /* We can't discriminate contexts based on address, as we don't know it.
1142 If there is only one possible context, we can use its tags */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001143 if (state->context && state->context->netid.net && !state->context->current)
Simon Kelleyd1e9a582012-10-23 17:00:57 +01001144 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001145 state->context->netid.next = NULL;
1146 state->context_tags = &state->context->netid;
Simon Kelleyd1e9a582012-10-23 17:00:57 +01001147 }
Simon Kelley6bd109a2013-07-27 15:11:44 +01001148
1149 /* Similarly, we can't determine domain from address, but if the FQDN is
1150 given in --dhcp-host, we can use that, and failing that we can use the
1151 unqualified configured domain, if any. */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001152 if (state->hostname_auth)
1153 state->send_domain = state->domain;
Simon Kelley6bd109a2013-07-27 15:11:44 +01001154 else
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001155 state->send_domain = get_domain6(NULL);
Simon Kelley6bd109a2013-07-27 15:11:44 +01001156
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01001157 log6_quiet(state, "DHCPINFORMATION-REQUEST", NULL, ignore ? _("ignored") : state->hostname);
Simon Kelley3634c542012-02-08 14:22:37 +00001158 if (ignore)
1159 return 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001160 *outmsgtypep = DHCP6REPLY;
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001161 tagif = add_options(state, 1);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001162 break;
1163 }
1164
1165
1166 case DHCP6RELEASE:
1167 {
1168 /* set reply message type */
1169 *outmsgtypep = DHCP6REPLY;
1170
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01001171 log6_quiet(state, "DHCPRELEASE", NULL, NULL);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001172
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001173 for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
Simon Kelley4cb1b322012-02-06 14:30:41 +00001174 {
Simon Kelley4cb1b322012-02-06 14:30:41 +00001175 void *ia_option, *ia_end;
1176 int made_ia = 0;
1177
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001178 for (check_ia(state, opt, &ia_end, &ia_option);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001179 ia_option;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001180 ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
Simon Kelley4cb1b322012-02-06 14:30:41 +00001181 {
1182 struct dhcp_lease *lease;
Simon Kelley97f876b2018-08-21 22:06:36 +01001183 struct in6_addr addr;
1184
1185 /* align */
1186 memcpy(&addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001187 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 +01001188 state->iaid, &addr)))
Simon Kelley4cb1b322012-02-06 14:30:41 +00001189 lease_prune(lease, now);
1190 else
1191 {
1192 if (!made_ia)
1193 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001194 o = new_opt6(state->ia_type);
1195 put_opt6_long(state->iaid);
1196 if (state->ia_type == OPTION6_IA_NA)
Simon Kelley4cb1b322012-02-06 14:30:41 +00001197 {
1198 put_opt6_long(0);
1199 put_opt6_long(0);
1200 }
1201 made_ia = 1;
1202 }
1203
1204 o1 = new_opt6(OPTION6_IAADDR);
1205 put_opt6(opt6_ptr(ia_option, 0), IN6ADDRSZ);
1206 put_opt6_long(0);
1207 put_opt6_long(0);
1208 end_opt6(o1);
1209 }
1210 }
1211
1212 if (made_ia)
1213 {
1214 o1 = new_opt6(OPTION6_STATUS_CODE);
1215 put_opt6_short(DHCP6NOBINDING);
Simon Kelleyde92b472013-03-15 18:25:10 +00001216 put_opt6_string(_("no binding found"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00001217 end_opt6(o1);
1218
1219 end_opt6(o);
1220 }
1221 }
1222
1223 o1 = new_opt6(OPTION6_STATUS_CODE);
1224 put_opt6_short(DHCP6SUCCESS);
Simon Kelleyde92b472013-03-15 18:25:10 +00001225 put_opt6_string(_("release received"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00001226 end_opt6(o1);
1227
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001228 break;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001229 }
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001230
1231 case DHCP6DECLINE:
1232 {
1233 /* set reply message type */
1234 *outmsgtypep = DHCP6REPLY;
1235
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01001236 log6_quiet(state, "DHCPDECLINE", NULL, NULL);
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001237
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001238 for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001239 {
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001240 void *ia_option, *ia_end;
1241 int made_ia = 0;
1242
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001243 for (check_ia(state, opt, &ia_end, &ia_option);
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001244 ia_option;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001245 ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001246 {
1247 struct dhcp_lease *lease;
Simon Kelley97f876b2018-08-21 22:06:36 +01001248 struct in6_addr addr;
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001249
Simon Kelley97f876b2018-08-21 22:06:36 +01001250 /* align */
1251 memcpy(&addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
1252
1253 if (have_config(config, CONFIG_ADDR6) && IN6_ARE_ADDR_EQUAL(&config->addr6, &addr))
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001254 {
Simon Kelleyceae00d2012-02-09 21:28:14 +00001255 prettyprint_time(daemon->dhcp_buff3, DECLINE_BACKOFF);
Simon Kelley97f876b2018-08-21 22:06:36 +01001256 inet_ntop(AF_INET6, &addr, daemon->addrbuff, ADDRSTRLEN);
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001257 my_syslog(MS_DHCP | LOG_WARNING, _("disabling DHCP static address %s for %s"),
Simon Kelleyceae00d2012-02-09 21:28:14 +00001258 daemon->addrbuff, daemon->dhcp_buff3);
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001259 config->flags |= CONFIG_DECLINED;
1260 config->decline_time = now;
1261 }
1262 else
1263 /* make sure this host gets a different address next time. */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001264 for (context_tmp = state->context; context_tmp; context_tmp = context_tmp->current)
1265 context_tmp->addr_epoch++;
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001266
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001267 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 +01001268 state->iaid, &addr)))
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001269 lease_prune(lease, now);
1270 else
1271 {
1272 if (!made_ia)
1273 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001274 o = new_opt6(state->ia_type);
1275 put_opt6_long(state->iaid);
1276 if (state->ia_type == OPTION6_IA_NA)
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001277 {
1278 put_opt6_long(0);
1279 put_opt6_long(0);
1280 }
1281 made_ia = 1;
1282 }
1283
1284 o1 = new_opt6(OPTION6_IAADDR);
Simon Kelley97f876b2018-08-21 22:06:36 +01001285 put_opt6(&addr, IN6ADDRSZ);
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001286 put_opt6_long(0);
1287 put_opt6_long(0);
1288 end_opt6(o1);
1289 }
1290 }
1291
1292 if (made_ia)
1293 {
1294 o1 = new_opt6(OPTION6_STATUS_CODE);
1295 put_opt6_short(DHCP6NOBINDING);
Simon Kelleyde92b472013-03-15 18:25:10 +00001296 put_opt6_string(_("no binding found"));
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001297 end_opt6(o1);
1298
1299 end_opt6(o);
1300 }
1301
1302 }
Ilya Ponetaev51943362014-09-13 21:19:01 +01001303
Josh Soref730c6742017-02-06 16:14:04 +00001304 /* We must answer with 'success' in global section anyway */
Ilya Ponetaev51943362014-09-13 21:19:01 +01001305 o1 = new_opt6(OPTION6_STATUS_CODE);
1306 put_opt6_short(DHCP6SUCCESS);
1307 put_opt6_string(_("success"));
1308 end_opt6(o1);
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001309 break;
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001310 }
1311
Simon Kelley4cb1b322012-02-06 14:30:41 +00001312 }
1313
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001314 log_tags(tagif, state->xid);
1315 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 +00001316
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001317 return 1;
1318
1319}
1320
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001321static struct dhcp_netid *add_options(struct state *state, int do_refresh)
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001322{
Simon Kelley2763d4b2013-03-06 21:24:56 +00001323 void *oro;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001324 /* filter options based on tags, those we want get DHOPT_TAGOK bit set */
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001325 struct dhcp_netid *tagif = option_filter(state->tags, state->context_tags, daemon->dhcp_opts6);
1326 struct dhcp_opt *opt_cfg;
Simon Kelley871d4562013-07-27 21:32:32 +01001327 int done_dns = 0, done_refresh = !do_refresh, do_encap = 0;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001328 int i, o, o1;
1329
1330 oro = opt6_find(state->packet_options, state->end, OPTION6_ORO, 0);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001331
1332 for (opt_cfg = daemon->dhcp_opts6; opt_cfg; opt_cfg = opt_cfg->next)
1333 {
1334 /* netids match and not encapsulated? */
1335 if (!(opt_cfg->flags & DHOPT_TAGOK))
1336 continue;
1337
1338 if (!(opt_cfg->flags & DHOPT_FORCE) && oro)
1339 {
1340 for (i = 0; i < opt6_len(oro) - 1; i += 2)
1341 if (opt6_uint(oro, i, 2) == (unsigned)opt_cfg->opt)
1342 break;
1343
1344 /* option not requested */
1345 if (i >= opt6_len(oro) - 1)
1346 continue;
1347 }
1348
Simon Kelley871d4562013-07-27 21:32:32 +01001349 if (opt_cfg->opt == OPTION6_REFRESH_TIME)
1350 done_refresh = 1;
Simon Kelley5e3e4642015-08-25 23:08:39 +01001351
1352 if (opt_cfg->opt == OPTION6_DNS_SERVER)
1353 done_dns = 1;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001354
Simon Kelley27b78d92015-09-26 21:40:45 +01001355 if (opt_cfg->flags & DHOPT_ADDR6)
Simon Kelley4b86b652012-02-29 11:45:37 +00001356 {
Simon Kelleyc3a04082014-01-11 22:18:19 +00001357 int len, j;
1358 struct in6_addr *a;
1359
Simon Kelleyc3a04082014-01-11 22:18:19 +00001360 for (a = (struct in6_addr *)opt_cfg->val, len = opt_cfg->len, j = 0;
1361 j < opt_cfg->len; j += IN6ADDRSZ, a++)
1362 if ((IN6_IS_ADDR_ULA_ZERO(a) && IN6_IS_ADDR_UNSPECIFIED(state->ula_addr)) ||
1363 (IN6_IS_ADDR_LINK_LOCAL_ZERO(a) && IN6_IS_ADDR_UNSPECIFIED(state->ll_addr)))
1364 len -= IN6ADDRSZ;
1365
1366 if (len != 0)
1367 {
1368
1369 o = new_opt6(opt_cfg->opt);
1370
1371 for (a = (struct in6_addr *)opt_cfg->val, j = 0; j < opt_cfg->len; j+=IN6ADDRSZ, a++)
1372 {
1373 if (IN6_IS_ADDR_UNSPECIFIED(a))
1374 {
1375 if (!add_local_addrs(state->context))
1376 put_opt6(state->fallback, IN6ADDRSZ);
1377 }
1378 else if (IN6_IS_ADDR_ULA_ZERO(a))
1379 {
1380 if (!IN6_IS_ADDR_UNSPECIFIED(state->ula_addr))
1381 put_opt6(state->ula_addr, IN6ADDRSZ);
1382 }
1383 else if (IN6_IS_ADDR_LINK_LOCAL_ZERO(a))
1384 {
1385 if (!IN6_IS_ADDR_UNSPECIFIED(state->ll_addr))
1386 put_opt6(state->ll_addr, IN6ADDRSZ);
1387 }
1388 else
1389 put_opt6(a, IN6ADDRSZ);
Simon Kelley4b86b652012-02-29 11:45:37 +00001390 }
Simon Kelleyc3a04082014-01-11 22:18:19 +00001391
1392 end_opt6(o);
1393 }
Simon Kelley4b86b652012-02-29 11:45:37 +00001394 }
Simon Kelleyc3a04082014-01-11 22:18:19 +00001395 else
1396 {
1397 o = new_opt6(opt_cfg->opt);
1398 if (opt_cfg->val)
1399 put_opt6(opt_cfg->val, opt_cfg->len);
1400 end_opt6(o);
1401 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001402 }
1403
Simon Kelley871d4562013-07-27 21:32:32 +01001404 if (daemon->port == NAMESERVER_PORT && !done_dns)
Simon Kelley4cb1b322012-02-06 14:30:41 +00001405 {
1406 o = new_opt6(OPTION6_DNS_SERVER);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001407 if (!add_local_addrs(state->context))
1408 put_opt6(state->fallback, IN6ADDRSZ);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001409 end_opt6(o);
1410 }
Simon Kelley871d4562013-07-27 21:32:32 +01001411
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001412 if (state->context && !done_refresh)
Simon Kelley871d4562013-07-27 21:32:32 +01001413 {
1414 struct dhcp_context *c;
1415 unsigned int lease_time = 0xffffffff;
1416
1417 /* Find the smallest lease tie of all contexts,
Josh Soref730c6742017-02-06 16:14:04 +00001418 subject to the RFC-4242 stipulation that this must not
Simon Kelley871d4562013-07-27 21:32:32 +01001419 be less than 600. */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001420 for (c = state->context; c; c = c->next)
Simon Kelley871d4562013-07-27 21:32:32 +01001421 if (c->lease_time < lease_time)
1422 {
1423 if (c->lease_time < 600)
1424 lease_time = 600;
1425 else
1426 lease_time = c->lease_time;
1427 }
1428
1429 o = new_opt6(OPTION6_REFRESH_TIME);
1430 put_opt6_long(lease_time);
1431 end_opt6(o);
1432 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001433
1434 /* handle vendor-identifying vendor-encapsulated options,
1435 dhcp-option = vi-encap:13,17,....... */
1436 for (opt_cfg = daemon->dhcp_opts6; opt_cfg; opt_cfg = opt_cfg->next)
1437 opt_cfg->flags &= ~DHOPT_ENCAP_DONE;
Simon Kelley4b86b652012-02-29 11:45:37 +00001438
Simon Kelley4cb1b322012-02-06 14:30:41 +00001439 if (oro)
1440 for (i = 0; i < opt6_len(oro) - 1; i += 2)
1441 if (opt6_uint(oro, i, 2) == OPTION6_VENDOR_OPTS)
1442 do_encap = 1;
1443
1444 for (opt_cfg = daemon->dhcp_opts6; opt_cfg; opt_cfg = opt_cfg->next)
1445 {
1446 if (opt_cfg->flags & DHOPT_RFC3925)
1447 {
1448 int found = 0;
1449 struct dhcp_opt *oc;
1450
1451 if (opt_cfg->flags & DHOPT_ENCAP_DONE)
1452 continue;
1453
1454 for (oc = daemon->dhcp_opts6; oc; oc = oc->next)
1455 {
1456 oc->flags &= ~DHOPT_ENCAP_MATCH;
1457
1458 if (!(oc->flags & DHOPT_RFC3925) || opt_cfg->u.encap != oc->u.encap)
1459 continue;
1460
1461 oc->flags |= DHOPT_ENCAP_DONE;
1462 if (match_netid(oc->netid, tagif, 1))
1463 {
1464 /* option requested/forced? */
1465 if (!oro || do_encap || (oc->flags & DHOPT_FORCE))
1466 {
1467 oc->flags |= DHOPT_ENCAP_MATCH;
1468 found = 1;
1469 }
1470 }
1471 }
1472
1473 if (found)
1474 {
1475 o = new_opt6(OPTION6_VENDOR_OPTS);
1476 put_opt6_long(opt_cfg->u.encap);
1477
1478 for (oc = daemon->dhcp_opts6; oc; oc = oc->next)
1479 if (oc->flags & DHOPT_ENCAP_MATCH)
1480 {
1481 o1 = new_opt6(oc->opt);
1482 put_opt6(oc->val, oc->len);
1483 end_opt6(o1);
1484 }
1485 end_opt6(o);
1486 }
1487 }
1488 }
Simon Kelley07933802012-02-14 20:55:25 +00001489
1490
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001491 if (state->hostname)
Simon Kelley4cb1b322012-02-06 14:30:41 +00001492 {
1493 unsigned char *p;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001494 size_t len = strlen(state->hostname);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001495
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001496 if (state->send_domain)
Roy Marples3f3adae2013-07-25 16:22:46 +01001497 len += strlen(state->send_domain) + 2;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001498
1499 o = new_opt6(OPTION6_FQDN);
Roy Marples3f3adae2013-07-25 16:22:46 +01001500 if ((p = expand(len + 2)))
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001501 {
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001502 *(p++) = state->fqdn_flags;
Simon Kelley0549c732017-09-25 18:17:11 +01001503 p = do_rfc1035_name(p, state->hostname, NULL);
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001504 if (state->send_domain)
Roy Marples3f3adae2013-07-25 16:22:46 +01001505 {
Simon Kelley0549c732017-09-25 18:17:11 +01001506 p = do_rfc1035_name(p, state->send_domain, NULL);
Roy Marples3f3adae2013-07-25 16:22:46 +01001507 *p = 0;
1508 }
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001509 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001510 end_opt6(o);
1511 }
1512
1513
1514 /* logging */
1515 if (option_bool(OPT_LOG_OPTS) && oro)
1516 {
1517 char *q = daemon->namebuff;
1518 for (i = 0; i < opt6_len(oro) - 1; i += 2)
1519 {
1520 char *s = option_string(AF_INET6, opt6_uint(oro, i, 2), NULL, 0, NULL, 0);
1521 q += snprintf(q, MAXDNAME - (q - daemon->namebuff),
1522 "%d%s%s%s",
1523 opt6_uint(oro, i, 2),
1524 strlen(s) != 0 ? ":" : "",
1525 s,
1526 (i > opt6_len(oro) - 3) ? "" : ", ");
1527 if ( i > opt6_len(oro) - 3 || (q - daemon->namebuff) > 40)
1528 {
1529 q = daemon->namebuff;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001530 my_syslog(MS_DHCP | LOG_INFO, _("%u requested options: %s"), state->xid, daemon->namebuff);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001531 }
1532 }
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001533 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001534
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001535 return tagif;
1536}
1537
1538static int add_local_addrs(struct dhcp_context *context)
1539{
1540 int done = 0;
Simon Kelley6c8f21e2012-03-12 15:06:55 +00001541
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001542 for (; context; context = context->current)
1543 if ((context->flags & CONTEXT_USED) && !IN6_IS_ADDR_UNSPECIFIED(&context->local6))
1544 {
1545 /* squash duplicates */
1546 struct dhcp_context *c;
1547 for (c = context->current; c; c = c->current)
1548 if ((c->flags & CONTEXT_USED) &&
1549 IN6_ARE_ADDR_EQUAL(&context->local6, &c->local6))
1550 break;
1551
1552 if (!c)
1553 {
1554 done = 1;
1555 put_opt6(&context->local6, IN6ADDRSZ);
1556 }
1557 }
1558
1559 return done;
Simon Kelley6c8f21e2012-03-12 15:06:55 +00001560}
1561
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001562
1563static void get_context_tag(struct state *state, struct dhcp_context *context)
1564{
1565 /* get tags from context if we've not used it before */
1566 if (context->netid.next == &context->netid && context->netid.net)
1567 {
1568 context->netid.next = state->context_tags;
1569 state->context_tags = &context->netid;
1570 if (!state->hostname_auth)
1571 {
1572 struct dhcp_netid_list *id_list;
1573
1574 for (id_list = daemon->dhcp_ignore_names; id_list; id_list = id_list->next)
1575 if ((!id_list->list) || match_netid(id_list->list, &context->netid, 0))
1576 break;
1577 if (id_list)
1578 state->hostname = NULL;
1579 }
1580 }
1581}
Simon Kelleyc6309242013-03-07 20:59:28 +00001582
1583#ifdef OPTION6_PREFIX_CLASS
1584static struct prefix_class *prefix_class_from_context(struct dhcp_context *context)
1585{
1586 struct prefix_class *p;
1587 struct dhcp_netid *t;
1588
1589 for (p = daemon->prefix_classes; p ; p = p->next)
1590 for (t = context->filter; t; t = t->next)
1591 if (strcmp(p->tag.net, t->net) == 0)
1592 return p;
1593
1594 return NULL;
1595}
1596#endif
1597
Simon Kelley3a654c52013-03-06 22:17:48 +00001598static int check_ia(struct state *state, void *opt, void **endp, void **ia_option)
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001599{
1600 state->ia_type = opt6_type(opt);
Simon Kelley3a654c52013-03-06 22:17:48 +00001601 *ia_option = NULL;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001602
1603 if (state->ia_type != OPTION6_IA_NA && state->ia_type != OPTION6_IA_TA)
Simon Kelley3a654c52013-03-06 22:17:48 +00001604 return 0;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001605
1606 if (state->ia_type == OPTION6_IA_NA && opt6_len(opt) < 12)
Simon Kelley3a654c52013-03-06 22:17:48 +00001607 return 0;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001608
1609 if (state->ia_type == OPTION6_IA_TA && opt6_len(opt) < 4)
Simon Kelley3a654c52013-03-06 22:17:48 +00001610 return 0;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001611
1612 *endp = opt6_ptr(opt, opt6_len(opt));
1613 state->iaid = opt6_uint(opt, 0, 4);
Simon Kelley3a654c52013-03-06 22:17:48 +00001614 *ia_option = opt6_find(opt6_ptr(opt, state->ia_type == OPTION6_IA_NA ? 12 : 4), *endp, OPTION6_IAADDR, 24);
1615
1616 return 1;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001617}
1618
1619
1620static int build_ia(struct state *state, int *t1cntr)
1621{
1622 int o = new_opt6(state->ia_type);
1623
1624 put_opt6_long(state->iaid);
1625 *t1cntr = 0;
1626
1627 if (state->ia_type == OPTION6_IA_NA)
1628 {
1629 /* save pointer */
1630 *t1cntr = save_counter(-1);
1631 /* so we can fill these in later */
1632 put_opt6_long(0);
1633 put_opt6_long(0);
1634 }
1635
1636 return o;
1637}
1638
1639static void end_ia(int t1cntr, unsigned int min_time, int do_fuzz)
1640{
1641 if (t1cntr != 0)
1642 {
Ville Skyttäfaaf3062018-01-14 17:32:52 +00001643 /* go back and fill in fields in IA_NA option */
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001644 int sav = save_counter(t1cntr);
1645 unsigned int t1, t2, fuzz = 0;
1646
1647 if (do_fuzz)
1648 {
1649 fuzz = rand16();
1650
1651 while (fuzz > (min_time/16))
1652 fuzz = fuzz/2;
1653 }
1654
1655 t1 = (min_time == 0xffffffff) ? 0xffffffff : min_time/2 - fuzz;
1656 t2 = (min_time == 0xffffffff) ? 0xffffffff : ((min_time/8)*7) - fuzz;
1657 put_opt6_long(t1);
1658 put_opt6_long(t2);
1659 save_counter(sav);
1660 }
1661}
1662
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001663static void add_address(struct state *state, struct dhcp_context *context, unsigned int lease_time, void *ia_option,
Simon Kelleyc8f2dd82013-09-13 11:22:55 +01001664 unsigned int *min_time, struct in6_addr *addr, time_t now)
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001665{
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001666 unsigned int valid_time = 0, preferred_time = 0;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001667 int o = new_opt6(OPTION6_IAADDR);
1668 struct dhcp_lease *lease;
1669
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001670 /* get client requested times */
1671 if (ia_option)
1672 {
1673 preferred_time = opt6_uint(ia_option, 16, 4);
1674 valid_time = opt6_uint(ia_option, 20, 4);
1675 }
1676
1677 calculate_times(context, min_time, &valid_time, &preferred_time, lease_time);
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001678
Simon Kelleyde92b472013-03-15 18:25:10 +00001679 put_opt6(addr, sizeof(*addr));
1680 put_opt6_long(preferred_time);
1681 put_opt6_long(valid_time);
1682
Simon Kelleyc6309242013-03-07 20:59:28 +00001683#ifdef OPTION6_PREFIX_CLASS
1684 if (state->send_prefix_class)
1685 {
1686 int o1 = new_opt6(OPTION6_PREFIX_CLASS);
1687 put_opt6_short(state->send_prefix_class->class);
1688 end_opt6(o1);
1689 }
1690#endif
1691
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001692 end_opt6(o);
1693
Simon Kelleyc8f2dd82013-09-13 11:22:55 +01001694 if (state->lease_allocate)
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001695 update_leases(state, context, addr, valid_time, now);
1696
1697 if ((lease = lease6_find_by_addr(addr, 128, 0)))
1698 lease->flags |= LEASE_USED;
1699
1700 /* get tags from context if we've not used it before */
1701 if (context->netid.next == &context->netid && context->netid.net)
1702 {
1703 context->netid.next = state->context_tags;
1704 state->context_tags = &context->netid;
1705
1706 if (!state->hostname_auth)
1707 {
1708 struct dhcp_netid_list *id_list;
1709
1710 for (id_list = daemon->dhcp_ignore_names; id_list; id_list = id_list->next)
1711 if ((!id_list->list) || match_netid(id_list->list, &context->netid, 0))
1712 break;
1713 if (id_list)
1714 state->hostname = NULL;
1715 }
1716 }
1717
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01001718 log6_quiet(state, state->lease_allocate ? "DHCPREPLY" : "DHCPADVERTISE", addr, state->hostname);
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001719
1720}
Simon Kelleyff59fc82013-03-07 11:00:26 +00001721
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001722static void mark_context_used(struct state *state, struct in6_addr *addr)
Simon Kelleyff59fc82013-03-07 11:00:26 +00001723{
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001724 struct dhcp_context *context;
1725
Simon Kelleyff59fc82013-03-07 11:00:26 +00001726 /* Mark that we have an address for this prefix. */
Simon Kelleyc6309242013-03-07 20:59:28 +00001727#ifdef OPTION6_PREFIX_CLASS
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001728 for (context = state->context; context; context = context->current)
Simon Kelleyc6309242013-03-07 20:59:28 +00001729 if (is_same_net6(addr, &context->start6, context->prefix) &&
1730 (!state->send_prefix_class || state->send_prefix_class == prefix_class_from_context(context)))
1731 context->flags |= CONTEXT_USED;
1732#else
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001733 for (context = state->context; context; context = context->current)
Simon Kelleyff59fc82013-03-07 11:00:26 +00001734 if (is_same_net6(addr, &context->start6, context->prefix))
1735 context->flags |= CONTEXT_USED;
Simon Kelleyc6309242013-03-07 20:59:28 +00001736#endif
Simon Kelleyff59fc82013-03-07 11:00:26 +00001737}
Simon Kelleyc6309242013-03-07 20:59:28 +00001738
Simon Kelleyde92b472013-03-15 18:25:10 +00001739static void mark_config_used(struct dhcp_context *context, struct in6_addr *addr)
1740{
1741 for (; context; context = context->current)
1742 if (is_same_net6(addr, &context->start6, context->prefix))
1743 context->flags |= CONTEXT_CONF_USED;
1744}
1745
1746/* make sure address not leased to another CLID/IAID */
1747static int check_address(struct state *state, struct in6_addr *addr)
1748{
1749 struct dhcp_lease *lease;
1750
1751 if (!(lease = lease6_find_by_addr(addr, 128, 0)))
1752 return 1;
1753
1754 if (lease->clid_len != state->clid_len ||
1755 memcmp(lease->clid, state->clid, state->clid_len) != 0 ||
Simon Kelley89500e32013-09-20 16:29:20 +01001756 lease->iaid != state->iaid)
Simon Kelleyde92b472013-03-15 18:25:10 +00001757 return 0;
1758
1759 return 1;
1760}
1761
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001762
1763/* Calculate valid and preferred times to send in leases/renewals.
1764
1765 Inputs are:
1766
1767 *valid_timep, *preferred_timep - requested times from IAADDR options.
1768 context->valid, context->preferred - times associated with subnet address on local interface.
1769 context->flags | CONTEXT_DEPRECATE - "deprecated" flag in dhcp-range.
1770 lease_time - configured time for context for individual client.
1771 *min_time - smallest valid time sent so far.
1772
1773 Outputs are :
1774
1775 *valid_timep, *preferred_timep - times to be send in IAADDR option.
1776 *min_time - smallest valid time sent so far, to calculate T1 and T2.
1777
1778 */
Simon Kelleyde92b472013-03-15 18:25:10 +00001779static void calculate_times(struct dhcp_context *context, unsigned int *min_time, unsigned int *valid_timep,
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001780 unsigned int *preferred_timep, unsigned int lease_time)
Simon Kelleyde92b472013-03-15 18:25:10 +00001781{
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001782 unsigned int req_preferred = *preferred_timep, req_valid = *valid_timep;
1783 unsigned int valid_time = lease_time, preferred_time = lease_time;
1784
1785 /* RFC 3315: "A server ignores the lifetimes set
1786 by the client if the preferred lifetime is greater than the valid
1787 lifetime. */
1788 if (req_preferred <= req_valid)
1789 {
1790 if (req_preferred != 0)
1791 {
1792 /* 0 == "no preference from client" */
1793 if (req_preferred < 120u)
1794 req_preferred = 120u; /* sanity */
1795
1796 if (req_preferred < preferred_time)
1797 preferred_time = req_preferred;
1798 }
1799
1800 if (req_valid != 0)
1801 /* 0 == "no preference from client" */
1802 {
1803 if (req_valid < 120u)
1804 req_valid = 120u; /* sanity */
1805
1806 if (req_valid < valid_time)
1807 valid_time = req_valid;
1808 }
1809 }
Simon Kelleyde92b472013-03-15 18:25:10 +00001810
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001811 /* deprecate (preferred == 0) which configured, or when local address
1812 is deprecated */
1813 if ((context->flags & CONTEXT_DEPRECATE) || context->preferred == 0)
Simon Kelleyde92b472013-03-15 18:25:10 +00001814 preferred_time = 0;
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001815
Simon Kelleyde92b472013-03-15 18:25:10 +00001816 if (preferred_time != 0 && preferred_time < *min_time)
1817 *min_time = preferred_time;
1818
1819 if (valid_time != 0 && valid_time < *min_time)
1820 *min_time = valid_time;
1821
1822 *valid_timep = valid_time;
1823 *preferred_timep = preferred_time;
1824}
1825
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001826static void update_leases(struct state *state, struct dhcp_context *context, struct in6_addr *addr, unsigned int lease_time, time_t now)
1827{
1828 struct dhcp_lease *lease = lease6_find_by_addr(addr, 128, 0);
Vladislav Grishenko408c3682013-09-24 16:18:49 +01001829#ifdef HAVE_SCRIPT
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001830 struct dhcp_netid *tagif = run_tag_if(state->tags);
Vladislav Grishenko408c3682013-09-24 16:18:49 +01001831#endif
1832
1833 (void)context;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001834
1835 if (!lease)
1836 lease = lease6_allocate(addr, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA);
1837
1838 if (lease)
1839 {
1840 lease_set_expires(lease, lease_time, now);
Simon Kelley89500e32013-09-20 16:29:20 +01001841 lease_set_iaid(lease, state->iaid);
1842 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 +00001843 lease_set_interface(lease, state->interface, now);
1844 if (state->hostname && state->ia_type == OPTION6_IA_NA)
1845 {
1846 char *addr_domain = get_domain6(addr);
1847 if (!state->send_domain)
1848 state->send_domain = addr_domain;
1849 lease_set_hostname(lease, state->hostname, state->hostname_auth, addr_domain, state->domain);
1850 }
1851
1852#ifdef HAVE_SCRIPT
1853 if (daemon->lease_change_command)
1854 {
1855 void *class_opt;
1856 lease->flags |= LEASE_CHANGED;
1857 free(lease->extradata);
1858 lease->extradata = NULL;
1859 lease->extradata_size = lease->extradata_len = 0;
Simon Kelley6f9aaa92013-04-10 10:25:26 +01001860 lease->vendorclass_count = 0;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001861
1862 if ((class_opt = opt6_find(state->packet_options, state->end, OPTION6_VENDOR_CLASS, 4)))
1863 {
1864 void *enc_opt, *enc_end = opt6_ptr(class_opt, opt6_len(class_opt));
Simon Kelley6f9aaa92013-04-10 10:25:26 +01001865 lease->vendorclass_count++;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001866 /* send enterprise number first */
1867 sprintf(daemon->dhcp_buff2, "%u", opt6_uint(class_opt, 0, 4));
1868 lease_add_extradata(lease, (unsigned char *)daemon->dhcp_buff2, strlen(daemon->dhcp_buff2), 0);
1869
1870 if (opt6_len(class_opt) >= 6)
1871 for (enc_opt = opt6_ptr(class_opt, 4); enc_opt; enc_opt = opt6_next(enc_opt, enc_end))
1872 {
Simon Kelley6f9aaa92013-04-10 10:25:26 +01001873 lease->vendorclass_count++;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001874 lease_add_extradata(lease, opt6_ptr(enc_opt, 0), opt6_len(enc_opt), 0);
1875 }
1876 }
1877
1878 lease_add_extradata(lease, (unsigned char *)state->client_hostname,
1879 state->client_hostname ? strlen(state->client_hostname) : 0, 0);
1880
1881 /* space-concat tag set */
1882 if (!tagif && !context->netid.net)
1883 lease_add_extradata(lease, NULL, 0, 0);
1884 else
1885 {
1886 if (context->netid.net)
1887 lease_add_extradata(lease, (unsigned char *)context->netid.net, strlen(context->netid.net), tagif ? ' ' : 0);
1888
1889 if (tagif)
1890 {
1891 struct dhcp_netid *n;
1892 for (n = tagif; n; n = n->next)
1893 {
1894 struct dhcp_netid *n1;
1895 /* kill dupes */
1896 for (n1 = n->next; n1; n1 = n1->next)
1897 if (strcmp(n->net, n1->net) == 0)
1898 break;
1899 if (!n1)
1900 lease_add_extradata(lease, (unsigned char *)n->net, strlen(n->net), n->next ? ' ' : 0);
1901 }
1902 }
1903 }
1904
1905 if (state->link_address)
1906 inet_ntop(AF_INET6, state->link_address, daemon->addrbuff, ADDRSTRLEN);
1907
1908 lease_add_extradata(lease, (unsigned char *)daemon->addrbuff, state->link_address ? strlen(daemon->addrbuff) : 0, 0);
1909
1910 if ((class_opt = opt6_find(state->packet_options, state->end, OPTION6_USER_CLASS, 2)))
1911 {
1912 void *enc_opt, *enc_end = opt6_ptr(class_opt, opt6_len(class_opt));
1913 for (enc_opt = opt6_ptr(class_opt, 0); enc_opt; enc_opt = opt6_next(enc_opt, enc_end))
1914 lease_add_extradata(lease, opt6_ptr(enc_opt, 0), opt6_len(enc_opt), 0);
1915 }
1916 }
1917#endif
1918
1919 }
1920}
1921
1922
1923
Simon Kelley6c8f21e2012-03-12 15:06:55 +00001924static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_opts)
1925{
1926 void *opt;
1927 char *desc = nest ? "nest" : "sent";
Simon Kelley5cfea3d2012-03-12 17:28:27 +00001928
Simon Kelleyd81b42d2013-09-23 12:26:34 +01001929 if (!option_bool(OPT_LOG_OPTS) || start_opts == end_opts)
Simon Kelley5cfea3d2012-03-12 17:28:27 +00001930 return;
1931
1932 for (opt = start_opts; opt; opt = opt6_next(opt, end_opts))
1933 {
1934 int type = opt6_type(opt);
1935 void *ia_options = NULL;
1936 char *optname;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001937
Simon Kelley5cfea3d2012-03-12 17:28:27 +00001938 if (type == OPTION6_IA_NA)
1939 {
1940 sprintf(daemon->namebuff, "IAID=%u T1=%u T2=%u",
1941 opt6_uint(opt, 0, 4), opt6_uint(opt, 4, 4), opt6_uint(opt, 8, 4));
1942 optname = "ia-na";
1943 ia_options = opt6_ptr(opt, 12);
1944 }
1945 else if (type == OPTION6_IA_TA)
1946 {
1947 sprintf(daemon->namebuff, "IAID=%u", opt6_uint(opt, 0, 4));
1948 optname = "ia-ta";
1949 ia_options = opt6_ptr(opt, 4);
1950 }
1951 else if (type == OPTION6_IAADDR)
1952 {
Simon Kelley97f876b2018-08-21 22:06:36 +01001953 struct in6_addr addr;
1954
1955 /* align */
1956 memcpy(&addr, opt6_ptr(opt, 0), IN6ADDRSZ);
1957 inet_ntop(AF_INET6, &addr, daemon->addrbuff, ADDRSTRLEN);
Simon Kelley5cfea3d2012-03-12 17:28:27 +00001958 sprintf(daemon->namebuff, "%s PL=%u VL=%u",
1959 daemon->addrbuff, opt6_uint(opt, 16, 4), opt6_uint(opt, 20, 4));
1960 optname = "iaaddr";
1961 ia_options = opt6_ptr(opt, 24);
1962 }
Simon Kelleyc6309242013-03-07 20:59:28 +00001963#ifdef OPTION6_PREFIX_CLASS
1964 else if (type == OPTION6_PREFIX_CLASS)
1965 {
1966 optname = "prefix-class";
1967 sprintf(daemon->namebuff, "class=%u", opt6_uint(opt, 0, 2));
1968 }
1969#endif
Simon Kelley5cfea3d2012-03-12 17:28:27 +00001970 else if (type == OPTION6_STATUS_CODE)
1971 {
1972 int len = sprintf(daemon->namebuff, "%u ", opt6_uint(opt, 0, 2));
1973 memcpy(daemon->namebuff + len, opt6_ptr(opt, 2), opt6_len(opt)-2);
1974 daemon->namebuff[len + opt6_len(opt) - 2] = 0;
1975 optname = "status";
1976 }
1977 else
1978 {
1979 /* account for flag byte on FQDN */
1980 int offset = type == OPTION6_FQDN ? 1 : 0;
1981 optname = option_string(AF_INET6, type, opt6_ptr(opt, offset), opt6_len(opt) - offset, daemon->namebuff, MAXDNAME);
1982 }
1983
1984 my_syslog(MS_DHCP | LOG_INFO, "%u %s size:%3d option:%3d %s %s",
1985 xid, desc, opt6_len(opt), type, optname, daemon->namebuff);
1986
1987 if (ia_options)
1988 log6_opts(1, xid, ia_options, opt6_ptr(opt, opt6_len(opt)));
1989 }
Simon Kelley6c8f21e2012-03-12 15:06:55 +00001990}
1991
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01001992static void log6_quiet(struct state *state, char *type, struct in6_addr *addr, char *string)
1993{
1994 if (option_bool(OPT_LOG_OPTS) || !option_bool(OPT_QUIET_DHCP6))
1995 log6_packet(state, type, addr, string);
1996}
1997
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001998static void log6_packet(struct state *state, char *type, struct in6_addr *addr, char *string)
Simon Kelley4cb1b322012-02-06 14:30:41 +00001999{
Simon Kelleya6ebfac2013-03-06 20:52:35 +00002000 int clid_len = state->clid_len;
2001
Simon Kelley4cb1b322012-02-06 14:30:41 +00002002 /* avoid buffer overflow */
2003 if (clid_len > 100)
2004 clid_len = 100;
2005
Simon Kelleya6ebfac2013-03-06 20:52:35 +00002006 print_mac(daemon->namebuff, state->clid, clid_len);
Simon Kelley4cb1b322012-02-06 14:30:41 +00002007
2008 if (addr)
2009 {
Simon Kelleybf4e62c2016-07-22 21:37:59 +01002010 inet_ntop(AF_INET6, addr, daemon->dhcp_buff2, DHCP_BUFF_SZ - 1);
Simon Kelley4cb1b322012-02-06 14:30:41 +00002011 strcat(daemon->dhcp_buff2, " ");
2012 }
2013 else
2014 daemon->dhcp_buff2[0] = 0;
2015
2016 if(option_bool(OPT_LOG_OPTS))
Simon Kelley58dc02e2012-02-27 11:49:37 +00002017 my_syslog(MS_DHCP | LOG_INFO, "%u %s(%s) %s%s %s",
Simon Kelleya6ebfac2013-03-06 20:52:35 +00002018 state->xid,
Simon Kelley4cb1b322012-02-06 14:30:41 +00002019 type,
Simon Kelleya6ebfac2013-03-06 20:52:35 +00002020 state->iface_name,
Simon Kelley4cb1b322012-02-06 14:30:41 +00002021 daemon->dhcp_buff2,
Simon Kelley58dc02e2012-02-27 11:49:37 +00002022 daemon->namebuff,
Simon Kelley4cb1b322012-02-06 14:30:41 +00002023 string ? string : "");
2024 else
Simon Kelley58dc02e2012-02-27 11:49:37 +00002025 my_syslog(MS_DHCP | LOG_INFO, "%s(%s) %s%s %s",
Simon Kelley4cb1b322012-02-06 14:30:41 +00002026 type,
Simon Kelleya6ebfac2013-03-06 20:52:35 +00002027 state->iface_name,
Simon Kelley4cb1b322012-02-06 14:30:41 +00002028 daemon->dhcp_buff2,
Simon Kelley58dc02e2012-02-27 11:49:37 +00002029 daemon->namebuff,
Simon Kelley4cb1b322012-02-06 14:30:41 +00002030 string ? string : "");
2031}
2032
2033static void *opt6_find (void *opts, void *end, unsigned int search, unsigned int minsize)
Simon Kelleyc72daea2012-01-05 21:33:27 +00002034{
2035 u16 opt, opt_len;
2036 void *start;
2037
2038 if (!opts)
2039 return NULL;
2040
2041 while (1)
2042 {
2043 if (end - opts < 4)
2044 return NULL;
2045
2046 start = opts;
2047 GETSHORT(opt, opts);
2048 GETSHORT(opt_len, opts);
2049
2050 if (opt_len > (end - opts))
2051 return NULL;
2052
2053 if (opt == search && (opt_len >= minsize))
2054 return start;
2055
2056 opts += opt_len;
2057 }
2058}
2059
Simon Kelley4cb1b322012-02-06 14:30:41 +00002060static void *opt6_next(void *opts, void *end)
Simon Kelleyc72daea2012-01-05 21:33:27 +00002061{
2062 u16 opt_len;
2063
2064 if (end - opts < 4)
2065 return NULL;
2066
2067 opts += 2;
2068 GETSHORT(opt_len, opts);
2069
2070 if (opt_len >= (end - opts))
2071 return NULL;
2072
2073 return opts + opt_len;
2074}
Simon Kelleyc72daea2012-01-05 21:33:27 +00002075
2076static unsigned int opt6_uint(unsigned char *opt, int offset, int size)
2077{
2078 /* this worries about unaligned data and byte order */
2079 unsigned int ret = 0;
2080 int i;
2081 unsigned char *p = opt6_ptr(opt, offset);
2082
2083 for (i = 0; i < size; i++)
2084 ret = (ret << 8) | *p++;
2085
2086 return ret;
Simon Kelley4cb1b322012-02-06 14:30:41 +00002087}
Simon Kelleyc72daea2012-01-05 21:33:27 +00002088
Simon Kelley33702ab2015-12-28 23:17:15 +00002089void relay_upstream6(struct dhcp_relay *relay, ssize_t sz,
2090 struct in6_addr *peer_address, u32 scope_id, time_t now)
Simon Kelleyff7eea22013-09-04 18:01:38 +01002091{
2092 /* ->local is same value for all relays on ->current chain */
2093
2094 struct all_addr from;
2095 unsigned char *header;
2096 unsigned char *inbuff = daemon->dhcp_packet.iov_base;
2097 int msg_type = *inbuff;
2098 int hopcount;
2099 struct in6_addr multicast;
Simon Kelley8939c952013-09-25 11:49:34 +01002100 unsigned int maclen, mactype;
2101 unsigned char mac[DHCP_CHADDR_MAX];
Simon Kelleyff7eea22013-09-04 18:01:38 +01002102
2103 inet_pton(AF_INET6, ALL_SERVERS, &multicast);
Simon Kelley33702ab2015-12-28 23:17:15 +00002104 get_client_mac(peer_address, scope_id, mac, &maclen, &mactype, now);
Simon Kelley8939c952013-09-25 11:49:34 +01002105
Simon Kelleyff7eea22013-09-04 18:01:38 +01002106 /* source address == relay address */
2107 from.addr.addr6 = relay->local.addr.addr6;
2108
2109 /* Get hop count from nested relayed message */
2110 if (msg_type == DHCP6RELAYFORW)
2111 hopcount = *((unsigned char *)inbuff+1) + 1;
2112 else
2113 hopcount = 0;
2114
2115 /* RFC 3315 HOP_COUNT_LIMIT */
2116 if (hopcount > 32)
2117 return;
2118
Simon Kelleyfa785732016-07-22 20:56:01 +01002119 reset_counter();
Simon Kelleyff7eea22013-09-04 18:01:38 +01002120
2121 if ((header = put_opt6(NULL, 34)))
2122 {
2123 int o;
2124
2125 header[0] = DHCP6RELAYFORW;
2126 header[1] = hopcount;
2127 memcpy(&header[2], &relay->local.addr.addr6, IN6ADDRSZ);
2128 memcpy(&header[18], peer_address, IN6ADDRSZ);
Simon Kelley89500e32013-09-20 16:29:20 +01002129
2130 /* RFC-6939 */
Simon Kelley8939c952013-09-25 11:49:34 +01002131 if (maclen != 0)
Simon Kelley89500e32013-09-20 16:29:20 +01002132 {
2133 o = new_opt6(OPTION6_CLIENT_MAC);
Simon Kelley8939c952013-09-25 11:49:34 +01002134 put_opt6_short(mactype);
2135 put_opt6(mac, maclen);
Simon Kelley89500e32013-09-20 16:29:20 +01002136 end_opt6(o);
2137 }
Simon Kelleyff7eea22013-09-04 18:01:38 +01002138
2139 o = new_opt6(OPTION6_RELAY_MSG);
2140 put_opt6(inbuff, sz);
2141 end_opt6(o);
2142
2143 for (; relay; relay = relay->current)
2144 {
2145 union mysockaddr to;
2146
2147 to.sa.sa_family = AF_INET6;
2148 to.in6.sin6_addr = relay->server.addr.addr6;
2149 to.in6.sin6_port = htons(DHCPV6_SERVER_PORT);
2150 to.in6.sin6_flowinfo = 0;
2151 to.in6.sin6_scope_id = 0;
2152
2153 if (IN6_ARE_ADDR_EQUAL(&relay->server.addr.addr6, &multicast))
2154 {
2155 int multicast_iface;
2156 if (!relay->interface || strchr(relay->interface, '*') ||
2157 (multicast_iface = if_nametoindex(relay->interface)) == 0 ||
2158 setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &multicast_iface, sizeof(multicast_iface)) == -1)
2159 my_syslog(MS_DHCP | LOG_ERR, _("Cannot multicast to DHCPv6 server without correct interface"));
2160 }
2161
Simon Kelley6b1c4642016-07-22 20:59:16 +01002162 send_from(daemon->dhcp6fd, 0, daemon->outpacket.iov_base, save_counter(-1), &to, &from, 0);
Simon Kelleyff7eea22013-09-04 18:01:38 +01002163
2164 if (option_bool(OPT_LOG_OPTS))
2165 {
2166 inet_ntop(AF_INET6, &relay->local, daemon->addrbuff, ADDRSTRLEN);
2167 inet_ntop(AF_INET6, &relay->server, daemon->namebuff, ADDRSTRLEN);
2168 my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay %s -> %s"), daemon->addrbuff, daemon->namebuff);
2169 }
2170
2171 /* Save this for replies */
2172 relay->iface_index = scope_id;
2173 }
2174 }
2175}
2176
2177unsigned short relay_reply6(struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface)
2178{
2179 struct dhcp_relay *relay;
2180 struct in6_addr link;
2181 unsigned char *inbuff = daemon->dhcp_packet.iov_base;
2182
2183 /* must have at least msg_type+hopcount+link_address+peer_address+minimal size option
2184 which is 1 + 1 + 16 + 16 + 2 + 2 = 38 */
2185
2186 if (sz < 38 || *inbuff != DHCP6RELAYREPL)
2187 return 0;
2188
2189 memcpy(&link, &inbuff[2], IN6ADDRSZ);
2190
2191 for (relay = daemon->relay6; relay; relay = relay->next)
2192 if (IN6_ARE_ADDR_EQUAL(&link, &relay->local.addr.addr6) &&
2193 (!relay->interface || wildcard_match(relay->interface, arrival_interface)))
2194 break;
2195
Simon Kelleyfa785732016-07-22 20:56:01 +01002196 reset_counter();
Simon Kelleyff7eea22013-09-04 18:01:38 +01002197
2198 if (relay)
2199 {
2200 void *opt, *opts = inbuff + 34;
2201 void *end = inbuff + sz;
2202 for (opt = opts; opt; opt = opt6_next(opt, end))
2203 if (opt6_type(opt) == OPTION6_RELAY_MSG && opt6_len(opt) > 0)
2204 {
2205 int encap_type = *((unsigned char *)opt6_ptr(opt, 0));
2206 put_opt6(opt6_ptr(opt, 0), opt6_len(opt));
2207 memcpy(&peer->sin6_addr, &inbuff[18], IN6ADDRSZ);
2208 peer->sin6_scope_id = relay->iface_index;
2209 return encap_type == DHCP6RELAYREPL ? DHCPV6_SERVER_PORT : DHCPV6_CLIENT_PORT;
2210 }
2211 }
2212
2213 return 0;
2214}
2215
Simon Kelleyc72daea2012-01-05 21:33:27 +00002216#endif