blob: 21fcd9bb3e5f649c7c7a102f9934979237494c11 [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;
642 struct in6_addr *req_addr;
643 struct in6_addr addr;
Simon Kelleyc6309242013-03-07 20:59:28 +0000644
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100645 if (!check_ia(state, opt, &ia_end, &ia_option))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000646 continue;
647
Simon Kelley52a1ae72013-03-06 22:43:26 +0000648 /* reset USED bits in contexts - one address per prefix per IAID */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100649 for (c = state->context; c; c = c->current)
Simon Kelley52a1ae72013-03-06 22:43:26 +0000650 c->flags &= ~CONTEXT_USED;
Simon Kelleyc6309242013-03-07 20:59:28 +0000651
652#ifdef OPTION6_PREFIX_CLASS
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100653 if (daemon->prefix_classes && state->ia_type == OPTION6_IA_NA)
Simon Kelleyc6309242013-03-07 20:59:28 +0000654 {
Simon Kelley6e37ab52013-03-19 20:50:11 +0000655 void *prefix_opt;
Simon Kelleyc6309242013-03-07 20:59:28 +0000656 int prefix_class;
657
Simon Kelley6e37ab52013-03-19 20:50:11 +0000658 if (dump_all_prefix_classes)
659 /* OPTION_PREFIX_CLASS in ORO, send addresses in all prefix classes */
660 plain_range = 0;
Simon Kelleyc6309242013-03-07 20:59:28 +0000661 else
662 {
663 if ((prefix_opt = opt6_find(opt6_ptr(opt, 12), ia_end, OPTION6_PREFIX_CLASS, 2)))
664 {
665
666 prefix_class = opt6_uint(prefix_opt, 0, 2);
667
668 for (p = daemon->prefix_classes; p ; p = p->next)
669 if (p->class == prefix_class)
670 break;
671
672 if (!p)
673 my_syslog(MS_DHCP | LOG_WARNING, _("unknown prefix-class %d"), prefix_class);
674 else
675 {
676 /* add tag to list, and exclude undecorated dhcp-ranges */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100677 p->tag.next = state->tags;
Simon Kelleyc6309242013-03-07 20:59:28 +0000678 solicit_tags = run_tag_if(&p->tag);
679 plain_range = 0;
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100680 state->send_prefix_class = p;
Simon Kelleyc6309242013-03-07 20:59:28 +0000681 }
682 }
683 else
684 {
685 /* client didn't ask for a prefix class, lets see if we can find one. */
686 for (p = daemon->prefix_classes; p ; p = p->next)
687 {
688 p->tag.next = NULL;
689 if (match_netid(&p->tag, solicit_tags, 1))
690 break;
691 }
692
693 if (p)
694 {
695 plain_range = 0;
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100696 state->send_prefix_class = p;
Simon Kelleyc6309242013-03-07 20:59:28 +0000697 }
698 }
699
700 if (p && option_bool(OPT_LOG_OPTS))
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100701 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 +0000702 }
703 }
704#endif
705
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100706 o = build_ia(state, &t1cntr);
Vladislav Grishenkob9ff5c82014-10-06 14:34:24 +0100707 if (address_assigned)
708 address_assigned = 2;
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000709
Simon Kelleyc6309242013-03-07 20:59:28 +0000710 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 +0000711 {
712 req_addr = opt6_ptr(ia_option, 0);
Simon Kelleycc4baaa2013-08-05 15:03:44 +0100713
Simon Kelleyf1af2bb2013-09-24 09:16:28 +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 Kelleyde92b472013-03-15 18:25:10 +0000722 req_addr = &addr;
723 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 Kelleyf1af2bb2013-09-24 09:16:28 +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 Kelleyf1af2bb2013-09-24 09:16:28 +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 Kelleyf1af2bb2013-09-24 09:16:28 +0100737 add_address(state, c, lease_time, ia_option, &min_time, req_addr, now);
738 mark_context_used(state, req_addr);
739 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 Kelley89500e32013-09-20 16:29:20 +0100771 req_addr = &ltmp->addr6;
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100772 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 Kelleyf1af2bb2013-09-24 09:16:28 +0100778 add_address(state, c, c->lease_time, NULL, &min_time, req_addr, now);
779 mark_context_used(state, req_addr);
780 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 {
895 struct in6_addr *req_addr = opt6_ptr(ia_option, 0);
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;
900
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100901 if ((c = address6_valid(state->context, req_addr, tagif, 1)))
Simon Kelleyde92b472013-03-15 18:25:10 +0000902 config_ok = config_valid(config, c, &addr) && IN6_ARE_ADDR_EQUAL(&addr, req_addr);
903
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100904 if ((dynamic = address6_available(state->context, req_addr, tagif, 1)) || c)
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000905 {
Simon Kelleyde92b472013-03-15 18:25:10 +0000906 if (!dynamic && !config_ok)
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000907 {
908 /* Static range, not configured. */
909 o1 = new_opt6(OPTION6_STATUS_CODE);
Vladislav Grishenkob9ff5c82014-10-06 14:34:24 +0100910 put_opt6_short(DHCP6NOADDRS);
Simon Kelleyde92b472013-03-15 18:25:10 +0000911 put_opt6_string(_("address unavailable"));
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000912 end_opt6(o1);
913 }
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100914 else if (!check_address(state, req_addr))
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000915 {
916 /* Address leased to another DUID/IAID */
917 o1 = new_opt6(OPTION6_STATUS_CODE);
918 put_opt6_short(DHCP6UNSPEC);
Simon Kelleyde92b472013-03-15 18:25:10 +0000919 put_opt6_string(_("address in use"));
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000920 end_opt6(o1);
921 }
922 else
923 {
924 if (!dynamic)
925 dynamic = c;
926
927 lease_time = dynamic->lease_time;
928
Simon Kelleyde92b472013-03-15 18:25:10 +0000929 if (config_ok && have_config(config, CONFIG_TIME))
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000930 lease_time = config->lease_time;
931
Simon Kelley6e37ab52013-03-19 20:50:11 +0000932#ifdef OPTION6_PREFIX_CLASS
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100933 if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA)
934 state->send_prefix_class = prefix_class_from_context(c);
Simon Kelley6e37ab52013-03-19 20:50:11 +0000935#endif
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100936 add_address(state, dynamic, lease_time, ia_option, &min_time, req_addr, now);
937 get_context_tag(state, dynamic);
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000938 address_assigned = 1;
939 }
940 }
Simon Kelleyde92b472013-03-15 18:25:10 +0000941 else
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000942 {
943 /* requested address not on the correct link */
944 o1 = new_opt6(OPTION6_STATUS_CODE);
945 put_opt6_short(DHCP6NOTONLINK);
Simon Kelleyde92b472013-03-15 18:25:10 +0000946 put_opt6_string(_("not on link"));
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000947 end_opt6(o1);
948 }
949 }
950
951 end_ia(t1cntr, min_time, 0);
952 end_opt6(o);
953 }
954
955 if (address_assigned)
956 {
957 o1 = new_opt6(OPTION6_STATUS_CODE);
958 put_opt6_short(DHCP6SUCCESS);
Simon Kelleyde92b472013-03-15 18:25:10 +0000959 put_opt6_string(_("success"));
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000960 end_opt6(o1);
961 }
962 else
963 {
964 /* no address, return error */
965 o1 = new_opt6(OPTION6_STATUS_CODE);
966 put_opt6_short(DHCP6NOADDRS);
Simon Kelleyde92b472013-03-15 18:25:10 +0000967 put_opt6_string(_("no addresses available"));
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000968 end_opt6(o1);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100969 log6_packet(state, "DHCPREPLY", NULL, _("no addresses available"));
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000970 }
971
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100972 tagif = add_options(state, 0);
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000973 break;
974 }
975
976
Simon Kelley4cb1b322012-02-06 14:30:41 +0000977 case DHCP6RENEW:
978 {
979 /* set reply message type */
980 *outmsgtypep = DHCP6REPLY;
981
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +0100982 log6_quiet(state, "DHCPRENEW", NULL, NULL);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000983
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100984 for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000985 {
Simon Kelley4cb1b322012-02-06 14:30:41 +0000986 void *ia_option, *ia_end;
987 unsigned int min_time = 0xffffffff;
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000988 int t1cntr, iacntr;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000989
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100990 if (!check_ia(state, opt, &ia_end, &ia_option))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000991 continue;
992
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100993 o = build_ia(state, &t1cntr);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000994 iacntr = save_counter(-1);
995
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000996 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 +0000997 {
998 struct dhcp_lease *lease = NULL;
999 struct in6_addr *req_addr = opt6_ptr(ia_option, 0);
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001000 unsigned int preferred_time = opt6_uint(ia_option, 16, 4);
1001 unsigned int valid_time = opt6_uint(ia_option, 20, 4);
Simon Kelleyde92b472013-03-15 18:25:10 +00001002 char *message = NULL;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001003 struct dhcp_context *this_context;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001004
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001005 if (!(lease = lease6_find(state->clid, state->clid_len,
1006 state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
1007 state->iaid, req_addr)))
Simon Kelley4cb1b322012-02-06 14:30:41 +00001008 {
1009 /* If the server cannot find a client entry for the IA the server
1010 returns the IA containing no addresses with a Status Code option set
1011 to NoBinding in the Reply message. */
1012 save_counter(iacntr);
1013 t1cntr = 0;
1014
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001015 log6_packet(state, "DHCPREPLY", req_addr, _("lease not found"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00001016
1017 o1 = new_opt6(OPTION6_STATUS_CODE);
1018 put_opt6_short(DHCP6NOBINDING);
Simon Kelleyde92b472013-03-15 18:25:10 +00001019 put_opt6_string(_("no binding found"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00001020 end_opt6(o1);
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001021
1022 preferred_time = valid_time = 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001023 break;
1024 }
1025
Simon Kelley00e9ad52012-02-16 21:53:11 +00001026
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001027 if ((this_context = address6_available(state->context, req_addr, tagif, 1)) ||
1028 (this_context = address6_valid(state->context, req_addr, tagif, 1)))
Simon Kelleyc8257542012-03-28 21:15:41 +01001029 {
Simon Kelleyde92b472013-03-15 18:25:10 +00001030 struct in6_addr addr;
1031 unsigned int lease_time;
1032
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001033 get_context_tag(state, this_context);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001034
Simon Kelleyde92b472013-03-15 18:25:10 +00001035 if (config_valid(config, this_context, &addr) && IN6_ARE_ADDR_EQUAL(&addr, req_addr) && have_config(config, CONFIG_TIME))
1036 lease_time = config->lease_time;
1037 else
1038 lease_time = this_context->lease_time;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001039
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001040 calculate_times(this_context, &min_time, &valid_time, &preferred_time, lease_time);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001041
Simon Kelleyde92b472013-03-15 18:25:10 +00001042 lease_set_expires(lease, valid_time, now);
Simon Kelley89500e32013-09-20 16:29:20 +01001043 /* Update MAC record in case it's new information. */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001044 if (state->mac_len != 0)
1045 lease_set_hwaddr(lease, state->mac, state->clid, state->mac_len, state->mac_type, state->clid_len, now, 0);
1046 if (state->ia_type == OPTION6_IA_NA && state->hostname)
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001047 {
1048 char *addr_domain = get_domain6(req_addr);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001049 if (!state->send_domain)
1050 state->send_domain = addr_domain;
1051 lease_set_hostname(lease, state->hostname, state->hostname_auth, addr_domain, state->domain);
1052 message = state->hostname;
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001053 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001054
Simon Kelleyde92b472013-03-15 18:25:10 +00001055
1056 if (preferred_time == 0)
1057 message = _("deprecated");
Simon Kelley4cb1b322012-02-06 14:30:41 +00001058 }
Simon Kelleyde92b472013-03-15 18:25:10 +00001059 else
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001060 {
1061 preferred_time = valid_time = 0;
1062 message = _("address invalid");
Simon Kelleya5ae1f82015-04-25 21:46:10 +01001063 }
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001064
Simon Kelleya5ae1f82015-04-25 21:46:10 +01001065 if (message && (message != state->hostname))
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01001066 log6_packet(state, "DHCPREPLY", req_addr, message);
1067 else
1068 log6_quiet(state, "DHCPREPLY", req_addr, message);
1069
Simon Kelley4cb1b322012-02-06 14:30:41 +00001070 o1 = new_opt6(OPTION6_IAADDR);
1071 put_opt6(req_addr, sizeof(*req_addr));
Simon Kelleyde92b472013-03-15 18:25:10 +00001072 put_opt6_long(preferred_time);
1073 put_opt6_long(valid_time);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001074 end_opt6(o1);
1075 }
1076
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001077 end_ia(t1cntr, min_time, 1);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001078 end_opt6(o);
1079 }
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001080
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001081 tagif = add_options(state, 0);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001082 break;
1083
1084 }
1085
1086 case DHCP6CONFIRM:
1087 {
Ilya Ponetaev2d75f2e2014-09-13 21:11:16 +01001088 int good_addr = 0;
1089
Simon Kelley4cb1b322012-02-06 14:30:41 +00001090 /* set reply message type */
1091 *outmsgtypep = DHCP6REPLY;
1092
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01001093 log6_quiet(state, "DHCPCONFIRM", NULL, NULL);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001094
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001095 for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
Simon Kelley4cb1b322012-02-06 14:30:41 +00001096 {
Simon Kelley4cb1b322012-02-06 14:30:41 +00001097 void *ia_option, *ia_end;
1098
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001099 for (check_ia(state, opt, &ia_end, &ia_option);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001100 ia_option;
1101 ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
1102 {
1103 struct in6_addr *req_addr = opt6_ptr(ia_option, 0);
1104
Simon Kelley89130d92015-06-03 22:30:59 +01001105 if (!address6_valid(state->context, req_addr, tagif, 1))
Simon Kelley4cb1b322012-02-06 14:30:41 +00001106 {
1107 o1 = new_opt6(OPTION6_STATUS_CODE);
1108 put_opt6_short(DHCP6NOTONLINK);
Simon Kelleyde92b472013-03-15 18:25:10 +00001109 put_opt6_string(_("confirm failed"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00001110 end_opt6(o1);
1111 return 1;
1112 }
1113
Ilya Ponetaev2d75f2e2014-09-13 21:11:16 +01001114 good_addr = 1;
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01001115 log6_quiet(state, "DHCPREPLY", req_addr, state->hostname);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001116 }
1117 }
Ilya Ponetaev2d75f2e2014-09-13 21:11:16 +01001118
1119 /* No addresses, no reply: RFC 3315 18.2.2 */
1120 if (!good_addr)
1121 return 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001122
1123 o1 = new_opt6(OPTION6_STATUS_CODE);
1124 put_opt6_short(DHCP6SUCCESS );
Simon Kelleyde92b472013-03-15 18:25:10 +00001125 put_opt6_string(_("all addresses still on link"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00001126 end_opt6(o1);
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001127 break;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001128 }
1129
1130 case DHCP6IREQ:
1131 {
Simon Kelleyd1e9a582012-10-23 17:00:57 +01001132 /* We can't discriminate contexts based on address, as we don't know it.
1133 If there is only one possible context, we can use its tags */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001134 if (state->context && state->context->netid.net && !state->context->current)
Simon Kelleyd1e9a582012-10-23 17:00:57 +01001135 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001136 state->context->netid.next = NULL;
1137 state->context_tags = &state->context->netid;
Simon Kelleyd1e9a582012-10-23 17:00:57 +01001138 }
Simon Kelley6bd109a2013-07-27 15:11:44 +01001139
1140 /* Similarly, we can't determine domain from address, but if the FQDN is
1141 given in --dhcp-host, we can use that, and failing that we can use the
1142 unqualified configured domain, if any. */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001143 if (state->hostname_auth)
1144 state->send_domain = state->domain;
Simon Kelley6bd109a2013-07-27 15:11:44 +01001145 else
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001146 state->send_domain = get_domain6(NULL);
Simon Kelley6bd109a2013-07-27 15:11:44 +01001147
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01001148 log6_quiet(state, "DHCPINFORMATION-REQUEST", NULL, ignore ? _("ignored") : state->hostname);
Simon Kelley3634c542012-02-08 14:22:37 +00001149 if (ignore)
1150 return 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001151 *outmsgtypep = DHCP6REPLY;
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001152 tagif = add_options(state, 1);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001153 break;
1154 }
1155
1156
1157 case DHCP6RELEASE:
1158 {
1159 /* set reply message type */
1160 *outmsgtypep = DHCP6REPLY;
1161
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01001162 log6_quiet(state, "DHCPRELEASE", NULL, NULL);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001163
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001164 for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
Simon Kelley4cb1b322012-02-06 14:30:41 +00001165 {
Simon Kelley4cb1b322012-02-06 14:30:41 +00001166 void *ia_option, *ia_end;
1167 int made_ia = 0;
1168
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001169 for (check_ia(state, opt, &ia_end, &ia_option);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001170 ia_option;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001171 ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
Simon Kelley4cb1b322012-02-06 14:30:41 +00001172 {
1173 struct dhcp_lease *lease;
1174
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001175 if ((lease = lease6_find(state->clid, state->clid_len, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
1176 state->iaid, opt6_ptr(ia_option, 0))))
Simon Kelley4cb1b322012-02-06 14:30:41 +00001177 lease_prune(lease, now);
1178 else
1179 {
1180 if (!made_ia)
1181 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001182 o = new_opt6(state->ia_type);
1183 put_opt6_long(state->iaid);
1184 if (state->ia_type == OPTION6_IA_NA)
Simon Kelley4cb1b322012-02-06 14:30:41 +00001185 {
1186 put_opt6_long(0);
1187 put_opt6_long(0);
1188 }
1189 made_ia = 1;
1190 }
1191
1192 o1 = new_opt6(OPTION6_IAADDR);
1193 put_opt6(opt6_ptr(ia_option, 0), IN6ADDRSZ);
1194 put_opt6_long(0);
1195 put_opt6_long(0);
1196 end_opt6(o1);
1197 }
1198 }
1199
1200 if (made_ia)
1201 {
1202 o1 = new_opt6(OPTION6_STATUS_CODE);
1203 put_opt6_short(DHCP6NOBINDING);
Simon Kelleyde92b472013-03-15 18:25:10 +00001204 put_opt6_string(_("no binding found"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00001205 end_opt6(o1);
1206
1207 end_opt6(o);
1208 }
1209 }
1210
1211 o1 = new_opt6(OPTION6_STATUS_CODE);
1212 put_opt6_short(DHCP6SUCCESS);
Simon Kelleyde92b472013-03-15 18:25:10 +00001213 put_opt6_string(_("release received"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00001214 end_opt6(o1);
1215
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001216 break;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001217 }
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001218
1219 case DHCP6DECLINE:
1220 {
1221 /* set reply message type */
1222 *outmsgtypep = DHCP6REPLY;
1223
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01001224 log6_quiet(state, "DHCPDECLINE", NULL, NULL);
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001225
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001226 for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001227 {
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001228 void *ia_option, *ia_end;
1229 int made_ia = 0;
1230
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001231 for (check_ia(state, opt, &ia_end, &ia_option);
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001232 ia_option;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001233 ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001234 {
1235 struct dhcp_lease *lease;
1236 struct in6_addr *addrp = opt6_ptr(ia_option, 0);
1237
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001238 if (have_config(config, CONFIG_ADDR6) && IN6_ARE_ADDR_EQUAL(&config->addr6, addrp))
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001239 {
Simon Kelleyceae00d2012-02-09 21:28:14 +00001240 prettyprint_time(daemon->dhcp_buff3, DECLINE_BACKOFF);
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001241 inet_ntop(AF_INET6, addrp, daemon->addrbuff, ADDRSTRLEN);
1242 my_syslog(MS_DHCP | LOG_WARNING, _("disabling DHCP static address %s for %s"),
Simon Kelleyceae00d2012-02-09 21:28:14 +00001243 daemon->addrbuff, daemon->dhcp_buff3);
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001244 config->flags |= CONFIG_DECLINED;
1245 config->decline_time = now;
1246 }
1247 else
1248 /* make sure this host gets a different address next time. */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001249 for (context_tmp = state->context; context_tmp; context_tmp = context_tmp->current)
1250 context_tmp->addr_epoch++;
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001251
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001252 if ((lease = lease6_find(state->clid, state->clid_len, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
1253 state->iaid, opt6_ptr(ia_option, 0))))
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001254 lease_prune(lease, now);
1255 else
1256 {
1257 if (!made_ia)
1258 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001259 o = new_opt6(state->ia_type);
1260 put_opt6_long(state->iaid);
1261 if (state->ia_type == OPTION6_IA_NA)
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001262 {
1263 put_opt6_long(0);
1264 put_opt6_long(0);
1265 }
1266 made_ia = 1;
1267 }
1268
1269 o1 = new_opt6(OPTION6_IAADDR);
1270 put_opt6(opt6_ptr(ia_option, 0), IN6ADDRSZ);
1271 put_opt6_long(0);
1272 put_opt6_long(0);
1273 end_opt6(o1);
1274 }
1275 }
1276
1277 if (made_ia)
1278 {
1279 o1 = new_opt6(OPTION6_STATUS_CODE);
1280 put_opt6_short(DHCP6NOBINDING);
Simon Kelleyde92b472013-03-15 18:25:10 +00001281 put_opt6_string(_("no binding found"));
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001282 end_opt6(o1);
1283
1284 end_opt6(o);
1285 }
1286
1287 }
Ilya Ponetaev51943362014-09-13 21:19:01 +01001288
Josh Soref730c6742017-02-06 16:14:04 +00001289 /* We must answer with 'success' in global section anyway */
Ilya Ponetaev51943362014-09-13 21:19:01 +01001290 o1 = new_opt6(OPTION6_STATUS_CODE);
1291 put_opt6_short(DHCP6SUCCESS);
1292 put_opt6_string(_("success"));
1293 end_opt6(o1);
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001294 break;
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001295 }
1296
Simon Kelley4cb1b322012-02-06 14:30:41 +00001297 }
1298
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001299 log_tags(tagif, state->xid);
1300 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 +00001301
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001302 return 1;
1303
1304}
1305
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001306static struct dhcp_netid *add_options(struct state *state, int do_refresh)
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001307{
Simon Kelley2763d4b2013-03-06 21:24:56 +00001308 void *oro;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001309 /* filter options based on tags, those we want get DHOPT_TAGOK bit set */
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001310 struct dhcp_netid *tagif = option_filter(state->tags, state->context_tags, daemon->dhcp_opts6);
1311 struct dhcp_opt *opt_cfg;
Simon Kelley871d4562013-07-27 21:32:32 +01001312 int done_dns = 0, done_refresh = !do_refresh, do_encap = 0;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001313 int i, o, o1;
1314
1315 oro = opt6_find(state->packet_options, state->end, OPTION6_ORO, 0);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001316
1317 for (opt_cfg = daemon->dhcp_opts6; opt_cfg; opt_cfg = opt_cfg->next)
1318 {
1319 /* netids match and not encapsulated? */
1320 if (!(opt_cfg->flags & DHOPT_TAGOK))
1321 continue;
1322
1323 if (!(opt_cfg->flags & DHOPT_FORCE) && oro)
1324 {
1325 for (i = 0; i < opt6_len(oro) - 1; i += 2)
1326 if (opt6_uint(oro, i, 2) == (unsigned)opt_cfg->opt)
1327 break;
1328
1329 /* option not requested */
1330 if (i >= opt6_len(oro) - 1)
1331 continue;
1332 }
1333
Simon Kelley871d4562013-07-27 21:32:32 +01001334 if (opt_cfg->opt == OPTION6_REFRESH_TIME)
1335 done_refresh = 1;
Simon Kelley5e3e4642015-08-25 23:08:39 +01001336
1337 if (opt_cfg->opt == OPTION6_DNS_SERVER)
1338 done_dns = 1;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001339
Simon Kelley27b78d92015-09-26 21:40:45 +01001340 if (opt_cfg->flags & DHOPT_ADDR6)
Simon Kelley4b86b652012-02-29 11:45:37 +00001341 {
Simon Kelleyc3a04082014-01-11 22:18:19 +00001342 int len, j;
1343 struct in6_addr *a;
1344
Simon Kelleyc3a04082014-01-11 22:18:19 +00001345 for (a = (struct in6_addr *)opt_cfg->val, len = opt_cfg->len, j = 0;
1346 j < opt_cfg->len; j += IN6ADDRSZ, a++)
1347 if ((IN6_IS_ADDR_ULA_ZERO(a) && IN6_IS_ADDR_UNSPECIFIED(state->ula_addr)) ||
1348 (IN6_IS_ADDR_LINK_LOCAL_ZERO(a) && IN6_IS_ADDR_UNSPECIFIED(state->ll_addr)))
1349 len -= IN6ADDRSZ;
1350
1351 if (len != 0)
1352 {
1353
1354 o = new_opt6(opt_cfg->opt);
1355
1356 for (a = (struct in6_addr *)opt_cfg->val, j = 0; j < opt_cfg->len; j+=IN6ADDRSZ, a++)
1357 {
1358 if (IN6_IS_ADDR_UNSPECIFIED(a))
1359 {
1360 if (!add_local_addrs(state->context))
1361 put_opt6(state->fallback, IN6ADDRSZ);
1362 }
1363 else if (IN6_IS_ADDR_ULA_ZERO(a))
1364 {
1365 if (!IN6_IS_ADDR_UNSPECIFIED(state->ula_addr))
1366 put_opt6(state->ula_addr, IN6ADDRSZ);
1367 }
1368 else if (IN6_IS_ADDR_LINK_LOCAL_ZERO(a))
1369 {
1370 if (!IN6_IS_ADDR_UNSPECIFIED(state->ll_addr))
1371 put_opt6(state->ll_addr, IN6ADDRSZ);
1372 }
1373 else
1374 put_opt6(a, IN6ADDRSZ);
Simon Kelley4b86b652012-02-29 11:45:37 +00001375 }
Simon Kelleyc3a04082014-01-11 22:18:19 +00001376
1377 end_opt6(o);
1378 }
Simon Kelley4b86b652012-02-29 11:45:37 +00001379 }
Simon Kelleyc3a04082014-01-11 22:18:19 +00001380 else
1381 {
1382 o = new_opt6(opt_cfg->opt);
1383 if (opt_cfg->val)
1384 put_opt6(opt_cfg->val, opt_cfg->len);
1385 end_opt6(o);
1386 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001387 }
1388
Simon Kelley871d4562013-07-27 21:32:32 +01001389 if (daemon->port == NAMESERVER_PORT && !done_dns)
Simon Kelley4cb1b322012-02-06 14:30:41 +00001390 {
1391 o = new_opt6(OPTION6_DNS_SERVER);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001392 if (!add_local_addrs(state->context))
1393 put_opt6(state->fallback, IN6ADDRSZ);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001394 end_opt6(o);
1395 }
Simon Kelley871d4562013-07-27 21:32:32 +01001396
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001397 if (state->context && !done_refresh)
Simon Kelley871d4562013-07-27 21:32:32 +01001398 {
1399 struct dhcp_context *c;
1400 unsigned int lease_time = 0xffffffff;
1401
1402 /* Find the smallest lease tie of all contexts,
Josh Soref730c6742017-02-06 16:14:04 +00001403 subject to the RFC-4242 stipulation that this must not
Simon Kelley871d4562013-07-27 21:32:32 +01001404 be less than 600. */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001405 for (c = state->context; c; c = c->next)
Simon Kelley871d4562013-07-27 21:32:32 +01001406 if (c->lease_time < lease_time)
1407 {
1408 if (c->lease_time < 600)
1409 lease_time = 600;
1410 else
1411 lease_time = c->lease_time;
1412 }
1413
1414 o = new_opt6(OPTION6_REFRESH_TIME);
1415 put_opt6_long(lease_time);
1416 end_opt6(o);
1417 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001418
1419 /* handle vendor-identifying vendor-encapsulated options,
1420 dhcp-option = vi-encap:13,17,....... */
1421 for (opt_cfg = daemon->dhcp_opts6; opt_cfg; opt_cfg = opt_cfg->next)
1422 opt_cfg->flags &= ~DHOPT_ENCAP_DONE;
Simon Kelley4b86b652012-02-29 11:45:37 +00001423
Simon Kelley4cb1b322012-02-06 14:30:41 +00001424 if (oro)
1425 for (i = 0; i < opt6_len(oro) - 1; i += 2)
1426 if (opt6_uint(oro, i, 2) == OPTION6_VENDOR_OPTS)
1427 do_encap = 1;
1428
1429 for (opt_cfg = daemon->dhcp_opts6; opt_cfg; opt_cfg = opt_cfg->next)
1430 {
1431 if (opt_cfg->flags & DHOPT_RFC3925)
1432 {
1433 int found = 0;
1434 struct dhcp_opt *oc;
1435
1436 if (opt_cfg->flags & DHOPT_ENCAP_DONE)
1437 continue;
1438
1439 for (oc = daemon->dhcp_opts6; oc; oc = oc->next)
1440 {
1441 oc->flags &= ~DHOPT_ENCAP_MATCH;
1442
1443 if (!(oc->flags & DHOPT_RFC3925) || opt_cfg->u.encap != oc->u.encap)
1444 continue;
1445
1446 oc->flags |= DHOPT_ENCAP_DONE;
1447 if (match_netid(oc->netid, tagif, 1))
1448 {
1449 /* option requested/forced? */
1450 if (!oro || do_encap || (oc->flags & DHOPT_FORCE))
1451 {
1452 oc->flags |= DHOPT_ENCAP_MATCH;
1453 found = 1;
1454 }
1455 }
1456 }
1457
1458 if (found)
1459 {
1460 o = new_opt6(OPTION6_VENDOR_OPTS);
1461 put_opt6_long(opt_cfg->u.encap);
1462
1463 for (oc = daemon->dhcp_opts6; oc; oc = oc->next)
1464 if (oc->flags & DHOPT_ENCAP_MATCH)
1465 {
1466 o1 = new_opt6(oc->opt);
1467 put_opt6(oc->val, oc->len);
1468 end_opt6(o1);
1469 }
1470 end_opt6(o);
1471 }
1472 }
1473 }
Simon Kelley07933802012-02-14 20:55:25 +00001474
1475
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001476 if (state->hostname)
Simon Kelley4cb1b322012-02-06 14:30:41 +00001477 {
1478 unsigned char *p;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001479 size_t len = strlen(state->hostname);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001480
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001481 if (state->send_domain)
Roy Marples3f3adae2013-07-25 16:22:46 +01001482 len += strlen(state->send_domain) + 2;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001483
1484 o = new_opt6(OPTION6_FQDN);
Roy Marples3f3adae2013-07-25 16:22:46 +01001485 if ((p = expand(len + 2)))
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001486 {
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001487 *(p++) = state->fqdn_flags;
Simon Kelley0549c732017-09-25 18:17:11 +01001488 p = do_rfc1035_name(p, state->hostname, NULL);
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001489 if (state->send_domain)
Roy Marples3f3adae2013-07-25 16:22:46 +01001490 {
Simon Kelley0549c732017-09-25 18:17:11 +01001491 p = do_rfc1035_name(p, state->send_domain, NULL);
Roy Marples3f3adae2013-07-25 16:22:46 +01001492 *p = 0;
1493 }
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001494 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001495 end_opt6(o);
1496 }
1497
1498
1499 /* logging */
1500 if (option_bool(OPT_LOG_OPTS) && oro)
1501 {
1502 char *q = daemon->namebuff;
1503 for (i = 0; i < opt6_len(oro) - 1; i += 2)
1504 {
1505 char *s = option_string(AF_INET6, opt6_uint(oro, i, 2), NULL, 0, NULL, 0);
1506 q += snprintf(q, MAXDNAME - (q - daemon->namebuff),
1507 "%d%s%s%s",
1508 opt6_uint(oro, i, 2),
1509 strlen(s) != 0 ? ":" : "",
1510 s,
1511 (i > opt6_len(oro) - 3) ? "" : ", ");
1512 if ( i > opt6_len(oro) - 3 || (q - daemon->namebuff) > 40)
1513 {
1514 q = daemon->namebuff;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001515 my_syslog(MS_DHCP | LOG_INFO, _("%u requested options: %s"), state->xid, daemon->namebuff);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001516 }
1517 }
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001518 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001519
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001520 return tagif;
1521}
1522
1523static int add_local_addrs(struct dhcp_context *context)
1524{
1525 int done = 0;
Simon Kelley6c8f21e2012-03-12 15:06:55 +00001526
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001527 for (; context; context = context->current)
1528 if ((context->flags & CONTEXT_USED) && !IN6_IS_ADDR_UNSPECIFIED(&context->local6))
1529 {
1530 /* squash duplicates */
1531 struct dhcp_context *c;
1532 for (c = context->current; c; c = c->current)
1533 if ((c->flags & CONTEXT_USED) &&
1534 IN6_ARE_ADDR_EQUAL(&context->local6, &c->local6))
1535 break;
1536
1537 if (!c)
1538 {
1539 done = 1;
1540 put_opt6(&context->local6, IN6ADDRSZ);
1541 }
1542 }
1543
1544 return done;
Simon Kelley6c8f21e2012-03-12 15:06:55 +00001545}
1546
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001547
1548static void get_context_tag(struct state *state, struct dhcp_context *context)
1549{
1550 /* get tags from context if we've not used it before */
1551 if (context->netid.next == &context->netid && context->netid.net)
1552 {
1553 context->netid.next = state->context_tags;
1554 state->context_tags = &context->netid;
1555 if (!state->hostname_auth)
1556 {
1557 struct dhcp_netid_list *id_list;
1558
1559 for (id_list = daemon->dhcp_ignore_names; id_list; id_list = id_list->next)
1560 if ((!id_list->list) || match_netid(id_list->list, &context->netid, 0))
1561 break;
1562 if (id_list)
1563 state->hostname = NULL;
1564 }
1565 }
1566}
Simon Kelleyc6309242013-03-07 20:59:28 +00001567
1568#ifdef OPTION6_PREFIX_CLASS
1569static struct prefix_class *prefix_class_from_context(struct dhcp_context *context)
1570{
1571 struct prefix_class *p;
1572 struct dhcp_netid *t;
1573
1574 for (p = daemon->prefix_classes; p ; p = p->next)
1575 for (t = context->filter; t; t = t->next)
1576 if (strcmp(p->tag.net, t->net) == 0)
1577 return p;
1578
1579 return NULL;
1580}
1581#endif
1582
Simon Kelley3a654c52013-03-06 22:17:48 +00001583static int check_ia(struct state *state, void *opt, void **endp, void **ia_option)
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001584{
1585 state->ia_type = opt6_type(opt);
Simon Kelley3a654c52013-03-06 22:17:48 +00001586 *ia_option = NULL;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001587
1588 if (state->ia_type != OPTION6_IA_NA && state->ia_type != OPTION6_IA_TA)
Simon Kelley3a654c52013-03-06 22:17:48 +00001589 return 0;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001590
1591 if (state->ia_type == OPTION6_IA_NA && opt6_len(opt) < 12)
Simon Kelley3a654c52013-03-06 22:17:48 +00001592 return 0;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001593
1594 if (state->ia_type == OPTION6_IA_TA && opt6_len(opt) < 4)
Simon Kelley3a654c52013-03-06 22:17:48 +00001595 return 0;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001596
1597 *endp = opt6_ptr(opt, opt6_len(opt));
1598 state->iaid = opt6_uint(opt, 0, 4);
Simon Kelley3a654c52013-03-06 22:17:48 +00001599 *ia_option = opt6_find(opt6_ptr(opt, state->ia_type == OPTION6_IA_NA ? 12 : 4), *endp, OPTION6_IAADDR, 24);
1600
1601 return 1;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001602}
1603
1604
1605static int build_ia(struct state *state, int *t1cntr)
1606{
1607 int o = new_opt6(state->ia_type);
1608
1609 put_opt6_long(state->iaid);
1610 *t1cntr = 0;
1611
1612 if (state->ia_type == OPTION6_IA_NA)
1613 {
1614 /* save pointer */
1615 *t1cntr = save_counter(-1);
1616 /* so we can fill these in later */
1617 put_opt6_long(0);
1618 put_opt6_long(0);
1619 }
1620
1621 return o;
1622}
1623
1624static void end_ia(int t1cntr, unsigned int min_time, int do_fuzz)
1625{
1626 if (t1cntr != 0)
1627 {
Ville Skyttäfaaf3062018-01-14 17:32:52 +00001628 /* go back and fill in fields in IA_NA option */
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001629 int sav = save_counter(t1cntr);
1630 unsigned int t1, t2, fuzz = 0;
1631
1632 if (do_fuzz)
1633 {
1634 fuzz = rand16();
1635
1636 while (fuzz > (min_time/16))
1637 fuzz = fuzz/2;
1638 }
1639
1640 t1 = (min_time == 0xffffffff) ? 0xffffffff : min_time/2 - fuzz;
1641 t2 = (min_time == 0xffffffff) ? 0xffffffff : ((min_time/8)*7) - fuzz;
1642 put_opt6_long(t1);
1643 put_opt6_long(t2);
1644 save_counter(sav);
1645 }
1646}
1647
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001648static void add_address(struct state *state, struct dhcp_context *context, unsigned int lease_time, void *ia_option,
Simon Kelleyc8f2dd82013-09-13 11:22:55 +01001649 unsigned int *min_time, struct in6_addr *addr, time_t now)
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001650{
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001651 unsigned int valid_time = 0, preferred_time = 0;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001652 int o = new_opt6(OPTION6_IAADDR);
1653 struct dhcp_lease *lease;
1654
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001655 /* get client requested times */
1656 if (ia_option)
1657 {
1658 preferred_time = opt6_uint(ia_option, 16, 4);
1659 valid_time = opt6_uint(ia_option, 20, 4);
1660 }
1661
1662 calculate_times(context, min_time, &valid_time, &preferred_time, lease_time);
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001663
Simon Kelleyde92b472013-03-15 18:25:10 +00001664 put_opt6(addr, sizeof(*addr));
1665 put_opt6_long(preferred_time);
1666 put_opt6_long(valid_time);
1667
Simon Kelleyc6309242013-03-07 20:59:28 +00001668#ifdef OPTION6_PREFIX_CLASS
1669 if (state->send_prefix_class)
1670 {
1671 int o1 = new_opt6(OPTION6_PREFIX_CLASS);
1672 put_opt6_short(state->send_prefix_class->class);
1673 end_opt6(o1);
1674 }
1675#endif
1676
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001677 end_opt6(o);
1678
Simon Kelleyc8f2dd82013-09-13 11:22:55 +01001679 if (state->lease_allocate)
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001680 update_leases(state, context, addr, valid_time, now);
1681
1682 if ((lease = lease6_find_by_addr(addr, 128, 0)))
1683 lease->flags |= LEASE_USED;
1684
1685 /* get tags from context if we've not used it before */
1686 if (context->netid.next == &context->netid && context->netid.net)
1687 {
1688 context->netid.next = state->context_tags;
1689 state->context_tags = &context->netid;
1690
1691 if (!state->hostname_auth)
1692 {
1693 struct dhcp_netid_list *id_list;
1694
1695 for (id_list = daemon->dhcp_ignore_names; id_list; id_list = id_list->next)
1696 if ((!id_list->list) || match_netid(id_list->list, &context->netid, 0))
1697 break;
1698 if (id_list)
1699 state->hostname = NULL;
1700 }
1701 }
1702
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01001703 log6_quiet(state, state->lease_allocate ? "DHCPREPLY" : "DHCPADVERTISE", addr, state->hostname);
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001704
1705}
Simon Kelleyff59fc82013-03-07 11:00:26 +00001706
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001707static void mark_context_used(struct state *state, struct in6_addr *addr)
Simon Kelleyff59fc82013-03-07 11:00:26 +00001708{
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001709 struct dhcp_context *context;
1710
Simon Kelleyff59fc82013-03-07 11:00:26 +00001711 /* Mark that we have an address for this prefix. */
Simon Kelleyc6309242013-03-07 20:59:28 +00001712#ifdef OPTION6_PREFIX_CLASS
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001713 for (context = state->context; context; context = context->current)
Simon Kelleyc6309242013-03-07 20:59:28 +00001714 if (is_same_net6(addr, &context->start6, context->prefix) &&
1715 (!state->send_prefix_class || state->send_prefix_class == prefix_class_from_context(context)))
1716 context->flags |= CONTEXT_USED;
1717#else
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001718 for (context = state->context; context; context = context->current)
Simon Kelleyff59fc82013-03-07 11:00:26 +00001719 if (is_same_net6(addr, &context->start6, context->prefix))
1720 context->flags |= CONTEXT_USED;
Simon Kelleyc6309242013-03-07 20:59:28 +00001721#endif
Simon Kelleyff59fc82013-03-07 11:00:26 +00001722}
Simon Kelleyc6309242013-03-07 20:59:28 +00001723
Simon Kelleyde92b472013-03-15 18:25:10 +00001724static void mark_config_used(struct dhcp_context *context, struct in6_addr *addr)
1725{
1726 for (; context; context = context->current)
1727 if (is_same_net6(addr, &context->start6, context->prefix))
1728 context->flags |= CONTEXT_CONF_USED;
1729}
1730
1731/* make sure address not leased to another CLID/IAID */
1732static int check_address(struct state *state, struct in6_addr *addr)
1733{
1734 struct dhcp_lease *lease;
1735
1736 if (!(lease = lease6_find_by_addr(addr, 128, 0)))
1737 return 1;
1738
1739 if (lease->clid_len != state->clid_len ||
1740 memcmp(lease->clid, state->clid, state->clid_len) != 0 ||
Simon Kelley89500e32013-09-20 16:29:20 +01001741 lease->iaid != state->iaid)
Simon Kelleyde92b472013-03-15 18:25:10 +00001742 return 0;
1743
1744 return 1;
1745}
1746
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001747
1748/* Calculate valid and preferred times to send in leases/renewals.
1749
1750 Inputs are:
1751
1752 *valid_timep, *preferred_timep - requested times from IAADDR options.
1753 context->valid, context->preferred - times associated with subnet address on local interface.
1754 context->flags | CONTEXT_DEPRECATE - "deprecated" flag in dhcp-range.
1755 lease_time - configured time for context for individual client.
1756 *min_time - smallest valid time sent so far.
1757
1758 Outputs are :
1759
1760 *valid_timep, *preferred_timep - times to be send in IAADDR option.
1761 *min_time - smallest valid time sent so far, to calculate T1 and T2.
1762
1763 */
Simon Kelleyde92b472013-03-15 18:25:10 +00001764static void calculate_times(struct dhcp_context *context, unsigned int *min_time, unsigned int *valid_timep,
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001765 unsigned int *preferred_timep, unsigned int lease_time)
Simon Kelleyde92b472013-03-15 18:25:10 +00001766{
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001767 unsigned int req_preferred = *preferred_timep, req_valid = *valid_timep;
1768 unsigned int valid_time = lease_time, preferred_time = lease_time;
1769
1770 /* RFC 3315: "A server ignores the lifetimes set
1771 by the client if the preferred lifetime is greater than the valid
1772 lifetime. */
1773 if (req_preferred <= req_valid)
1774 {
1775 if (req_preferred != 0)
1776 {
1777 /* 0 == "no preference from client" */
1778 if (req_preferred < 120u)
1779 req_preferred = 120u; /* sanity */
1780
1781 if (req_preferred < preferred_time)
1782 preferred_time = req_preferred;
1783 }
1784
1785 if (req_valid != 0)
1786 /* 0 == "no preference from client" */
1787 {
1788 if (req_valid < 120u)
1789 req_valid = 120u; /* sanity */
1790
1791 if (req_valid < valid_time)
1792 valid_time = req_valid;
1793 }
1794 }
Simon Kelleyde92b472013-03-15 18:25:10 +00001795
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001796 /* deprecate (preferred == 0) which configured, or when local address
1797 is deprecated */
1798 if ((context->flags & CONTEXT_DEPRECATE) || context->preferred == 0)
Simon Kelleyde92b472013-03-15 18:25:10 +00001799 preferred_time = 0;
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001800
Simon Kelleyde92b472013-03-15 18:25:10 +00001801 if (preferred_time != 0 && preferred_time < *min_time)
1802 *min_time = preferred_time;
1803
1804 if (valid_time != 0 && valid_time < *min_time)
1805 *min_time = valid_time;
1806
1807 *valid_timep = valid_time;
1808 *preferred_timep = preferred_time;
1809}
1810
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001811static void update_leases(struct state *state, struct dhcp_context *context, struct in6_addr *addr, unsigned int lease_time, time_t now)
1812{
1813 struct dhcp_lease *lease = lease6_find_by_addr(addr, 128, 0);
Vladislav Grishenko408c3682013-09-24 16:18:49 +01001814#ifdef HAVE_SCRIPT
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001815 struct dhcp_netid *tagif = run_tag_if(state->tags);
Vladislav Grishenko408c3682013-09-24 16:18:49 +01001816#endif
1817
1818 (void)context;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001819
1820 if (!lease)
1821 lease = lease6_allocate(addr, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA);
1822
1823 if (lease)
1824 {
1825 lease_set_expires(lease, lease_time, now);
Simon Kelley89500e32013-09-20 16:29:20 +01001826 lease_set_iaid(lease, state->iaid);
1827 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 +00001828 lease_set_interface(lease, state->interface, now);
1829 if (state->hostname && state->ia_type == OPTION6_IA_NA)
1830 {
1831 char *addr_domain = get_domain6(addr);
1832 if (!state->send_domain)
1833 state->send_domain = addr_domain;
1834 lease_set_hostname(lease, state->hostname, state->hostname_auth, addr_domain, state->domain);
1835 }
1836
1837#ifdef HAVE_SCRIPT
1838 if (daemon->lease_change_command)
1839 {
1840 void *class_opt;
1841 lease->flags |= LEASE_CHANGED;
1842 free(lease->extradata);
1843 lease->extradata = NULL;
1844 lease->extradata_size = lease->extradata_len = 0;
Simon Kelley6f9aaa92013-04-10 10:25:26 +01001845 lease->vendorclass_count = 0;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001846
1847 if ((class_opt = opt6_find(state->packet_options, state->end, OPTION6_VENDOR_CLASS, 4)))
1848 {
1849 void *enc_opt, *enc_end = opt6_ptr(class_opt, opt6_len(class_opt));
Simon Kelley6f9aaa92013-04-10 10:25:26 +01001850 lease->vendorclass_count++;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001851 /* send enterprise number first */
1852 sprintf(daemon->dhcp_buff2, "%u", opt6_uint(class_opt, 0, 4));
1853 lease_add_extradata(lease, (unsigned char *)daemon->dhcp_buff2, strlen(daemon->dhcp_buff2), 0);
1854
1855 if (opt6_len(class_opt) >= 6)
1856 for (enc_opt = opt6_ptr(class_opt, 4); enc_opt; enc_opt = opt6_next(enc_opt, enc_end))
1857 {
Simon Kelley6f9aaa92013-04-10 10:25:26 +01001858 lease->vendorclass_count++;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001859 lease_add_extradata(lease, opt6_ptr(enc_opt, 0), opt6_len(enc_opt), 0);
1860 }
1861 }
1862
1863 lease_add_extradata(lease, (unsigned char *)state->client_hostname,
1864 state->client_hostname ? strlen(state->client_hostname) : 0, 0);
1865
1866 /* space-concat tag set */
1867 if (!tagif && !context->netid.net)
1868 lease_add_extradata(lease, NULL, 0, 0);
1869 else
1870 {
1871 if (context->netid.net)
1872 lease_add_extradata(lease, (unsigned char *)context->netid.net, strlen(context->netid.net), tagif ? ' ' : 0);
1873
1874 if (tagif)
1875 {
1876 struct dhcp_netid *n;
1877 for (n = tagif; n; n = n->next)
1878 {
1879 struct dhcp_netid *n1;
1880 /* kill dupes */
1881 for (n1 = n->next; n1; n1 = n1->next)
1882 if (strcmp(n->net, n1->net) == 0)
1883 break;
1884 if (!n1)
1885 lease_add_extradata(lease, (unsigned char *)n->net, strlen(n->net), n->next ? ' ' : 0);
1886 }
1887 }
1888 }
1889
1890 if (state->link_address)
1891 inet_ntop(AF_INET6, state->link_address, daemon->addrbuff, ADDRSTRLEN);
1892
1893 lease_add_extradata(lease, (unsigned char *)daemon->addrbuff, state->link_address ? strlen(daemon->addrbuff) : 0, 0);
1894
1895 if ((class_opt = opt6_find(state->packet_options, state->end, OPTION6_USER_CLASS, 2)))
1896 {
1897 void *enc_opt, *enc_end = opt6_ptr(class_opt, opt6_len(class_opt));
1898 for (enc_opt = opt6_ptr(class_opt, 0); enc_opt; enc_opt = opt6_next(enc_opt, enc_end))
1899 lease_add_extradata(lease, opt6_ptr(enc_opt, 0), opt6_len(enc_opt), 0);
1900 }
1901 }
1902#endif
1903
1904 }
1905}
1906
1907
1908
Simon Kelley6c8f21e2012-03-12 15:06:55 +00001909static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_opts)
1910{
1911 void *opt;
1912 char *desc = nest ? "nest" : "sent";
Simon Kelley5cfea3d2012-03-12 17:28:27 +00001913
Simon Kelleyd81b42d2013-09-23 12:26:34 +01001914 if (!option_bool(OPT_LOG_OPTS) || start_opts == end_opts)
Simon Kelley5cfea3d2012-03-12 17:28:27 +00001915 return;
1916
1917 for (opt = start_opts; opt; opt = opt6_next(opt, end_opts))
1918 {
1919 int type = opt6_type(opt);
1920 void *ia_options = NULL;
1921 char *optname;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001922
Simon Kelley5cfea3d2012-03-12 17:28:27 +00001923 if (type == OPTION6_IA_NA)
1924 {
1925 sprintf(daemon->namebuff, "IAID=%u T1=%u T2=%u",
1926 opt6_uint(opt, 0, 4), opt6_uint(opt, 4, 4), opt6_uint(opt, 8, 4));
1927 optname = "ia-na";
1928 ia_options = opt6_ptr(opt, 12);
1929 }
1930 else if (type == OPTION6_IA_TA)
1931 {
1932 sprintf(daemon->namebuff, "IAID=%u", opt6_uint(opt, 0, 4));
1933 optname = "ia-ta";
1934 ia_options = opt6_ptr(opt, 4);
1935 }
1936 else if (type == OPTION6_IAADDR)
1937 {
1938 inet_ntop(AF_INET6, opt6_ptr(opt, 0), daemon->addrbuff, ADDRSTRLEN);
1939 sprintf(daemon->namebuff, "%s PL=%u VL=%u",
1940 daemon->addrbuff, opt6_uint(opt, 16, 4), opt6_uint(opt, 20, 4));
1941 optname = "iaaddr";
1942 ia_options = opt6_ptr(opt, 24);
1943 }
Simon Kelleyc6309242013-03-07 20:59:28 +00001944#ifdef OPTION6_PREFIX_CLASS
1945 else if (type == OPTION6_PREFIX_CLASS)
1946 {
1947 optname = "prefix-class";
1948 sprintf(daemon->namebuff, "class=%u", opt6_uint(opt, 0, 2));
1949 }
1950#endif
Simon Kelley5cfea3d2012-03-12 17:28:27 +00001951 else if (type == OPTION6_STATUS_CODE)
1952 {
1953 int len = sprintf(daemon->namebuff, "%u ", opt6_uint(opt, 0, 2));
1954 memcpy(daemon->namebuff + len, opt6_ptr(opt, 2), opt6_len(opt)-2);
1955 daemon->namebuff[len + opt6_len(opt) - 2] = 0;
1956 optname = "status";
1957 }
1958 else
1959 {
1960 /* account for flag byte on FQDN */
1961 int offset = type == OPTION6_FQDN ? 1 : 0;
1962 optname = option_string(AF_INET6, type, opt6_ptr(opt, offset), opt6_len(opt) - offset, daemon->namebuff, MAXDNAME);
1963 }
1964
1965 my_syslog(MS_DHCP | LOG_INFO, "%u %s size:%3d option:%3d %s %s",
1966 xid, desc, opt6_len(opt), type, optname, daemon->namebuff);
1967
1968 if (ia_options)
1969 log6_opts(1, xid, ia_options, opt6_ptr(opt, opt6_len(opt)));
1970 }
Simon Kelley6c8f21e2012-03-12 15:06:55 +00001971}
1972
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01001973static void log6_quiet(struct state *state, char *type, struct in6_addr *addr, char *string)
1974{
1975 if (option_bool(OPT_LOG_OPTS) || !option_bool(OPT_QUIET_DHCP6))
1976 log6_packet(state, type, addr, string);
1977}
1978
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001979static void log6_packet(struct state *state, char *type, struct in6_addr *addr, char *string)
Simon Kelley4cb1b322012-02-06 14:30:41 +00001980{
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001981 int clid_len = state->clid_len;
1982
Simon Kelley4cb1b322012-02-06 14:30:41 +00001983 /* avoid buffer overflow */
1984 if (clid_len > 100)
1985 clid_len = 100;
1986
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001987 print_mac(daemon->namebuff, state->clid, clid_len);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001988
1989 if (addr)
1990 {
Simon Kelleybf4e62c2016-07-22 21:37:59 +01001991 inet_ntop(AF_INET6, addr, daemon->dhcp_buff2, DHCP_BUFF_SZ - 1);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001992 strcat(daemon->dhcp_buff2, " ");
1993 }
1994 else
1995 daemon->dhcp_buff2[0] = 0;
1996
1997 if(option_bool(OPT_LOG_OPTS))
Simon Kelley58dc02e2012-02-27 11:49:37 +00001998 my_syslog(MS_DHCP | LOG_INFO, "%u %s(%s) %s%s %s",
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001999 state->xid,
Simon Kelley4cb1b322012-02-06 14:30:41 +00002000 type,
Simon Kelleya6ebfac2013-03-06 20:52:35 +00002001 state->iface_name,
Simon Kelley4cb1b322012-02-06 14:30:41 +00002002 daemon->dhcp_buff2,
Simon Kelley58dc02e2012-02-27 11:49:37 +00002003 daemon->namebuff,
Simon Kelley4cb1b322012-02-06 14:30:41 +00002004 string ? string : "");
2005 else
Simon Kelley58dc02e2012-02-27 11:49:37 +00002006 my_syslog(MS_DHCP | LOG_INFO, "%s(%s) %s%s %s",
Simon Kelley4cb1b322012-02-06 14:30:41 +00002007 type,
Simon Kelleya6ebfac2013-03-06 20:52:35 +00002008 state->iface_name,
Simon Kelley4cb1b322012-02-06 14:30:41 +00002009 daemon->dhcp_buff2,
Simon Kelley58dc02e2012-02-27 11:49:37 +00002010 daemon->namebuff,
Simon Kelley4cb1b322012-02-06 14:30:41 +00002011 string ? string : "");
2012}
2013
2014static void *opt6_find (void *opts, void *end, unsigned int search, unsigned int minsize)
Simon Kelleyc72daea2012-01-05 21:33:27 +00002015{
2016 u16 opt, opt_len;
2017 void *start;
2018
2019 if (!opts)
2020 return NULL;
2021
2022 while (1)
2023 {
2024 if (end - opts < 4)
2025 return NULL;
2026
2027 start = opts;
2028 GETSHORT(opt, opts);
2029 GETSHORT(opt_len, opts);
2030
2031 if (opt_len > (end - opts))
2032 return NULL;
2033
2034 if (opt == search && (opt_len >= minsize))
2035 return start;
2036
2037 opts += opt_len;
2038 }
2039}
2040
Simon Kelley4cb1b322012-02-06 14:30:41 +00002041static void *opt6_next(void *opts, void *end)
Simon Kelleyc72daea2012-01-05 21:33:27 +00002042{
2043 u16 opt_len;
2044
2045 if (end - opts < 4)
2046 return NULL;
2047
2048 opts += 2;
2049 GETSHORT(opt_len, opts);
2050
2051 if (opt_len >= (end - opts))
2052 return NULL;
2053
2054 return opts + opt_len;
2055}
Simon Kelleyc72daea2012-01-05 21:33:27 +00002056
2057static unsigned int opt6_uint(unsigned char *opt, int offset, int size)
2058{
2059 /* this worries about unaligned data and byte order */
2060 unsigned int ret = 0;
2061 int i;
2062 unsigned char *p = opt6_ptr(opt, offset);
2063
2064 for (i = 0; i < size; i++)
2065 ret = (ret << 8) | *p++;
2066
2067 return ret;
Simon Kelley4cb1b322012-02-06 14:30:41 +00002068}
Simon Kelleyc72daea2012-01-05 21:33:27 +00002069
Simon Kelley33702ab2015-12-28 23:17:15 +00002070void relay_upstream6(struct dhcp_relay *relay, ssize_t sz,
2071 struct in6_addr *peer_address, u32 scope_id, time_t now)
Simon Kelleyff7eea22013-09-04 18:01:38 +01002072{
2073 /* ->local is same value for all relays on ->current chain */
2074
2075 struct all_addr from;
2076 unsigned char *header;
2077 unsigned char *inbuff = daemon->dhcp_packet.iov_base;
2078 int msg_type = *inbuff;
2079 int hopcount;
2080 struct in6_addr multicast;
Simon Kelley8939c952013-09-25 11:49:34 +01002081 unsigned int maclen, mactype;
2082 unsigned char mac[DHCP_CHADDR_MAX];
Simon Kelleyff7eea22013-09-04 18:01:38 +01002083
2084 inet_pton(AF_INET6, ALL_SERVERS, &multicast);
Simon Kelley33702ab2015-12-28 23:17:15 +00002085 get_client_mac(peer_address, scope_id, mac, &maclen, &mactype, now);
Simon Kelley8939c952013-09-25 11:49:34 +01002086
Simon Kelleyff7eea22013-09-04 18:01:38 +01002087 /* source address == relay address */
2088 from.addr.addr6 = relay->local.addr.addr6;
2089
2090 /* Get hop count from nested relayed message */
2091 if (msg_type == DHCP6RELAYFORW)
2092 hopcount = *((unsigned char *)inbuff+1) + 1;
2093 else
2094 hopcount = 0;
2095
2096 /* RFC 3315 HOP_COUNT_LIMIT */
2097 if (hopcount > 32)
2098 return;
2099
Simon Kelleyfa785732016-07-22 20:56:01 +01002100 reset_counter();
Simon Kelleyff7eea22013-09-04 18:01:38 +01002101
2102 if ((header = put_opt6(NULL, 34)))
2103 {
2104 int o;
2105
2106 header[0] = DHCP6RELAYFORW;
2107 header[1] = hopcount;
2108 memcpy(&header[2], &relay->local.addr.addr6, IN6ADDRSZ);
2109 memcpy(&header[18], peer_address, IN6ADDRSZ);
Simon Kelley89500e32013-09-20 16:29:20 +01002110
2111 /* RFC-6939 */
Simon Kelley8939c952013-09-25 11:49:34 +01002112 if (maclen != 0)
Simon Kelley89500e32013-09-20 16:29:20 +01002113 {
2114 o = new_opt6(OPTION6_CLIENT_MAC);
Simon Kelley8939c952013-09-25 11:49:34 +01002115 put_opt6_short(mactype);
2116 put_opt6(mac, maclen);
Simon Kelley89500e32013-09-20 16:29:20 +01002117 end_opt6(o);
2118 }
Simon Kelleyff7eea22013-09-04 18:01:38 +01002119
2120 o = new_opt6(OPTION6_RELAY_MSG);
2121 put_opt6(inbuff, sz);
2122 end_opt6(o);
2123
2124 for (; relay; relay = relay->current)
2125 {
2126 union mysockaddr to;
2127
2128 to.sa.sa_family = AF_INET6;
2129 to.in6.sin6_addr = relay->server.addr.addr6;
2130 to.in6.sin6_port = htons(DHCPV6_SERVER_PORT);
2131 to.in6.sin6_flowinfo = 0;
2132 to.in6.sin6_scope_id = 0;
2133
2134 if (IN6_ARE_ADDR_EQUAL(&relay->server.addr.addr6, &multicast))
2135 {
2136 int multicast_iface;
2137 if (!relay->interface || strchr(relay->interface, '*') ||
2138 (multicast_iface = if_nametoindex(relay->interface)) == 0 ||
2139 setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &multicast_iface, sizeof(multicast_iface)) == -1)
2140 my_syslog(MS_DHCP | LOG_ERR, _("Cannot multicast to DHCPv6 server without correct interface"));
2141 }
2142
Simon Kelley6b1c4642016-07-22 20:59:16 +01002143 send_from(daemon->dhcp6fd, 0, daemon->outpacket.iov_base, save_counter(-1), &to, &from, 0);
Simon Kelleyff7eea22013-09-04 18:01:38 +01002144
2145 if (option_bool(OPT_LOG_OPTS))
2146 {
2147 inet_ntop(AF_INET6, &relay->local, daemon->addrbuff, ADDRSTRLEN);
2148 inet_ntop(AF_INET6, &relay->server, daemon->namebuff, ADDRSTRLEN);
2149 my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay %s -> %s"), daemon->addrbuff, daemon->namebuff);
2150 }
2151
2152 /* Save this for replies */
2153 relay->iface_index = scope_id;
2154 }
2155 }
2156}
2157
2158unsigned short relay_reply6(struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface)
2159{
2160 struct dhcp_relay *relay;
2161 struct in6_addr link;
2162 unsigned char *inbuff = daemon->dhcp_packet.iov_base;
2163
2164 /* must have at least msg_type+hopcount+link_address+peer_address+minimal size option
2165 which is 1 + 1 + 16 + 16 + 2 + 2 = 38 */
2166
2167 if (sz < 38 || *inbuff != DHCP6RELAYREPL)
2168 return 0;
2169
2170 memcpy(&link, &inbuff[2], IN6ADDRSZ);
2171
2172 for (relay = daemon->relay6; relay; relay = relay->next)
2173 if (IN6_ARE_ADDR_EQUAL(&link, &relay->local.addr.addr6) &&
2174 (!relay->interface || wildcard_match(relay->interface, arrival_interface)))
2175 break;
2176
Simon Kelleyfa785732016-07-22 20:56:01 +01002177 reset_counter();
Simon Kelleyff7eea22013-09-04 18:01:38 +01002178
2179 if (relay)
2180 {
2181 void *opt, *opts = inbuff + 34;
2182 void *end = inbuff + sz;
2183 for (opt = opts; opt; opt = opt6_next(opt, end))
2184 if (opt6_type(opt) == OPTION6_RELAY_MSG && opt6_len(opt) > 0)
2185 {
2186 int encap_type = *((unsigned char *)opt6_ptr(opt, 0));
2187 put_opt6(opt6_ptr(opt, 0), opt6_len(opt));
2188 memcpy(&peer->sin6_addr, &inbuff[18], IN6ADDRSZ);
2189 peer->sin6_scope_id = relay->iface_index;
2190 return encap_type == DHCP6RELAYREPL ? DHCPV6_SERVER_PORT : DHCPV6_CLIENT_PORT;
2191 }
2192 }
2193
2194 return 0;
2195}
2196
Simon Kelleyc72daea2012-01-05 21:33:27 +00002197#endif