blob: a20776dad6c741ea27557e78611d7aa1a9e115e9 [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 Kelley0fdf3c12018-10-05 23:35:54 +0100499 struct dhcp_match_name *m;
500 size_t nl;
501
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100502 state->domain = strip_hostname(state->client_hostname);
Simon Kelley0fdf3c12018-10-05 23:35:54 +0100503 nl = strlen(state->client_hostname);
Simon Kelley70c5e3e2012-02-06 22:05:15 +0000504
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100505 if (strlen(state->client_hostname) != 0)
Simon Kelley4cb1b322012-02-06 14:30:41 +0000506 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100507 state->hostname = state->client_hostname;
Simon Kelley0fdf3c12018-10-05 23:35:54 +0100508
Simon Kelley4cb1b322012-02-06 14:30:41 +0000509 if (!config)
510 {
511 /* Search again now we have a hostname.
Simon Kelley00e9ad52012-02-16 21:53:11 +0000512 Only accept configs without CLID here, (it won't match)
Simon Kelley4cb1b322012-02-06 14:30:41 +0000513 to avoid impersonation by name. */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100514 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 +0000515 if (new && !have_config(new, CONFIG_CLID) && !new->hwaddr)
516 config = new;
517 }
Simon Kelley0fdf3c12018-10-05 23:35:54 +0100518
519 for (m = daemon->dhcp_name_match; m; m = m->next)
520 {
521 size_t ml = strlen(m->name);
522 char save = 0;
523
524 if (nl < ml)
525 continue;
526 if (nl > ml)
527 {
528 save = state->client_hostname[ml];
529 state->client_hostname[ml] = 0;
530 }
531
532 if (hostname_isequal(state->client_hostname, m->name) &&
533 (save == 0 || m->wildcard))
534 {
535 m->netid->next = state->tags;
536 state->tags = m->netid;
537 }
538
539 if (save != 0)
540 state->client_hostname[ml] = save;
541 }
Simon Kelley4cb1b322012-02-06 14:30:41 +0000542 }
543 }
544 }
545
546 if (config)
547 {
548 struct dhcp_netid_list *list;
549
550 for (list = config->netid; list; list = list->next)
551 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100552 list->list->next = state->tags;
553 state->tags = list->list;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000554 }
555
556 /* set "known" tag for known hosts */
557 known_id.net = "known";
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100558 known_id.next = state->tags;
559 state->tags = &known_id;
Simon Kelley3634c542012-02-08 14:22:37 +0000560
561 if (have_config(config, CONFIG_DISABLE))
562 ignore = 1;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000563 }
Simon Kelleyb2a9c572017-04-30 18:21:31 +0100564 else if (state->clid &&
565 find_config(daemon->dhcp_conf, NULL, state->clid, state->clid_len, state->mac, state->mac_len, state->mac_type, NULL))
566 {
567 known_id.net = "known-othernet";
568 known_id.next = state->tags;
569 state->tags = &known_id;
570 }
571
Simon Kelleyc6309242013-03-07 20:59:28 +0000572#ifdef OPTION6_PREFIX_CLASS
Simon Kelley6e37ab52013-03-19 20:50:11 +0000573 /* OPTION_PREFIX_CLASS in ORO, send addresses in all prefix classes */
574 if (daemon->prefix_classes && (msg_type == DHCP6SOLICIT || msg_type == DHCP6REQUEST))
Simon Kelleyc6309242013-03-07 20:59:28 +0000575 {
Simon Kelley6e37ab52013-03-19 20:50:11 +0000576 void *oro;
577
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100578 if ((oro = opt6_find(state->packet_options, state->end, OPTION6_ORO, 0)))
Simon Kelley6e37ab52013-03-19 20:50:11 +0000579 for (i = 0; i < opt6_len(oro) - 1; i += 2)
580 if (opt6_uint(oro, i, 2) == OPTION6_PREFIX_CLASS)
581 {
582 dump_all_prefix_classes = 1;
583 break;
584 }
585
586 if (msg_type != DHCP6SOLICIT || dump_all_prefix_classes)
587 /* Add the tags associated with prefix classes so we can use the DHCP ranges.
588 Not done for SOLICIT as we add them one-at-time. */
589 for (p = daemon->prefix_classes; p ; p = p->next)
590 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100591 p->tag.next = state->tags;
592 state->tags = &p->tag;
Simon Kelley6e37ab52013-03-19 20:50:11 +0000593 }
594 }
Simon Kelleyc6309242013-03-07 20:59:28 +0000595#endif
596
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100597 tagif = run_tag_if(state->tags);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000598
Simon Kelley3634c542012-02-08 14:22:37 +0000599 /* if all the netids in the ignore list are present, ignore this client */
600 if (daemon->dhcp_ignore)
601 {
602 struct dhcp_netid_list *id_list;
603
Simon Kelley3634c542012-02-08 14:22:37 +0000604 for (id_list = daemon->dhcp_ignore; id_list; id_list = id_list->next)
605 if (match_netid(id_list->list, tagif, 0))
606 ignore = 1;
607 }
Simon Kelley00e9ad52012-02-16 21:53:11 +0000608
609 /* if all the netids in the ignore_name list are present, ignore client-supplied name */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100610 if (!state->hostname_auth)
Simon Kelley00e9ad52012-02-16 21:53:11 +0000611 {
612 struct dhcp_netid_list *id_list;
613
614 for (id_list = daemon->dhcp_ignore_names; id_list; id_list = id_list->next)
615 if ((!id_list->list) || match_netid(id_list->list, tagif, 0))
616 break;
617 if (id_list)
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100618 state->hostname = NULL;
Simon Kelley00e9ad52012-02-16 21:53:11 +0000619 }
620
Simon Kelley4cb1b322012-02-06 14:30:41 +0000621
622 switch (msg_type)
623 {
Simon Kelley70c5e3e2012-02-06 22:05:15 +0000624 default:
625 return 0;
Simon Kelleyc8f2dd82013-09-13 11:22:55 +0100626
627
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000628 case DHCP6SOLICIT:
629 {
Simon Kelleyde92b472013-03-15 18:25:10 +0000630 int address_assigned = 0;
Simon Kelleyc6309242013-03-07 20:59:28 +0000631 /* tags without all prefix-class tags */
Simon Kelley8f51a292013-09-21 14:07:12 +0100632 struct dhcp_netid *solicit_tags;
Simon Kelleyde92b472013-03-15 18:25:10 +0000633 struct dhcp_context *c;
Simon Kelleyc8f2dd82013-09-13 11:22:55 +0100634
635 *outmsgtypep = DHCP6ADVERTISE;
636
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100637 if (opt6_find(state->packet_options, state->end, OPTION6_RAPID_COMMIT, 0))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000638 {
Simon Kelleyc8f2dd82013-09-13 11:22:55 +0100639 *outmsgtypep = DHCP6REPLY;
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100640 state->lease_allocate = 1;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000641 o = new_opt6(OPTION6_RAPID_COMMIT);
642 end_opt6(o);
643 }
Simon Kelley3634c542012-02-08 14:22:37 +0000644
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +0100645 log6_quiet(state, "DHCPSOLICIT", NULL, ignore ? _("ignored") : NULL);
Simon Kelleyc8f2dd82013-09-13 11:22:55 +0100646
647 request_no_address:
Simon Kelley8f51a292013-09-21 14:07:12 +0100648 solicit_tags = tagif;
649
Simon Kelley3634c542012-02-08 14:22:37 +0000650 if (ignore)
651 return 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000652
Simon Kelley52a1ae72013-03-06 22:43:26 +0000653 /* reset USED bits in leases */
654 lease6_reset();
Simon Kelleyde92b472013-03-15 18:25:10 +0000655
656 /* Can use configured address max once per prefix */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100657 for (c = state->context; c; c = c->current)
Simon Kelleyde92b472013-03-15 18:25:10 +0000658 c->flags &= ~CONTEXT_CONF_USED;
659
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100660 for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000661 {
Simon Kelley4cb1b322012-02-06 14:30:41 +0000662 void *ia_option, *ia_end;
663 unsigned int min_time = 0xffffffff;
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000664 int t1cntr;
Simon Kelleyc6309242013-03-07 20:59:28 +0000665 int ia_counter;
666 /* set unless we're sending a particular prefix-class, when we
667 want only dhcp-ranges with the correct tags set and not those without any tags. */
668 int plain_range = 1;
Simon Kelleycc4baaa2013-08-05 15:03:44 +0100669 u32 lease_time;
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000670 struct dhcp_lease *ltmp;
Simon Kelley97f876b2018-08-21 22:06:36 +0100671 struct in6_addr req_addr, addr;
672
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100673 if (!check_ia(state, opt, &ia_end, &ia_option))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000674 continue;
675
Simon Kelley52a1ae72013-03-06 22:43:26 +0000676 /* reset USED bits in contexts - one address per prefix per IAID */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100677 for (c = state->context; c; c = c->current)
Simon Kelley52a1ae72013-03-06 22:43:26 +0000678 c->flags &= ~CONTEXT_USED;
Simon Kelleyc6309242013-03-07 20:59:28 +0000679
680#ifdef OPTION6_PREFIX_CLASS
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100681 if (daemon->prefix_classes && state->ia_type == OPTION6_IA_NA)
Simon Kelleyc6309242013-03-07 20:59:28 +0000682 {
Simon Kelley6e37ab52013-03-19 20:50:11 +0000683 void *prefix_opt;
Simon Kelleyc6309242013-03-07 20:59:28 +0000684 int prefix_class;
685
Simon Kelley6e37ab52013-03-19 20:50:11 +0000686 if (dump_all_prefix_classes)
687 /* OPTION_PREFIX_CLASS in ORO, send addresses in all prefix classes */
688 plain_range = 0;
Simon Kelleyc6309242013-03-07 20:59:28 +0000689 else
690 {
691 if ((prefix_opt = opt6_find(opt6_ptr(opt, 12), ia_end, OPTION6_PREFIX_CLASS, 2)))
692 {
693
694 prefix_class = opt6_uint(prefix_opt, 0, 2);
695
696 for (p = daemon->prefix_classes; p ; p = p->next)
697 if (p->class == prefix_class)
698 break;
699
700 if (!p)
701 my_syslog(MS_DHCP | LOG_WARNING, _("unknown prefix-class %d"), prefix_class);
702 else
703 {
704 /* add tag to list, and exclude undecorated dhcp-ranges */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100705 p->tag.next = state->tags;
Simon Kelleyc6309242013-03-07 20:59:28 +0000706 solicit_tags = run_tag_if(&p->tag);
707 plain_range = 0;
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100708 state->send_prefix_class = p;
Simon Kelleyc6309242013-03-07 20:59:28 +0000709 }
710 }
711 else
712 {
713 /* client didn't ask for a prefix class, lets see if we can find one. */
714 for (p = daemon->prefix_classes; p ; p = p->next)
715 {
716 p->tag.next = NULL;
717 if (match_netid(&p->tag, solicit_tags, 1))
718 break;
719 }
720
721 if (p)
722 {
723 plain_range = 0;
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100724 state->send_prefix_class = p;
Simon Kelleyc6309242013-03-07 20:59:28 +0000725 }
726 }
727
728 if (p && option_bool(OPT_LOG_OPTS))
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100729 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 +0000730 }
731 }
732#endif
733
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100734 o = build_ia(state, &t1cntr);
Vladislav Grishenkob9ff5c82014-10-06 14:34:24 +0100735 if (address_assigned)
736 address_assigned = 2;
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000737
Simon Kelleyc6309242013-03-07 20:59:28 +0000738 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 +0000739 {
Simon Kelley97f876b2018-08-21 22:06:36 +0100740 /* worry about alignment here. */
741 memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
Simon Kelleycc4baaa2013-08-05 15:03:44 +0100742
Simon Kelley97f876b2018-08-21 22:06:36 +0100743 if ((c = address6_valid(state->context, &req_addr, solicit_tags, plain_range)))
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000744 {
745 lease_time = c->lease_time;
746 /* If the client asks for an address on the same network as a configured address,
747 offer the configured address instead, to make moving to newly-configured
748 addresses automatic. */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100749 if (!(c->flags & CONTEXT_CONF_USED) && config_valid(config, c, &addr) && check_address(state, &addr))
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000750 {
Simon Kelley97f876b2018-08-21 22:06:36 +0100751 req_addr = addr;
Simon Kelleyde92b472013-03-15 18:25:10 +0000752 mark_config_used(c, &addr);
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000753 if (have_config(config, CONFIG_TIME))
754 lease_time = config->lease_time;
755 }
Simon Kelley97f876b2018-08-21 22:06:36 +0100756 else if (!(c = address6_available(state->context, &req_addr, solicit_tags, plain_range)))
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000757 continue; /* not an address we're allowed */
Simon Kelley97f876b2018-08-21 22:06:36 +0100758 else if (!check_address(state, &req_addr))
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000759 continue; /* address leased elsewhere */
760
761 /* add address to output packet */
Simon Kelleyc6309242013-03-07 20:59:28 +0000762#ifdef OPTION6_PREFIX_CLASS
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100763 if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA)
764 state->send_prefix_class = prefix_class_from_context(c);
Simon Kelleyc6309242013-03-07 20:59:28 +0000765#endif
Simon Kelley97f876b2018-08-21 22:06:36 +0100766 add_address(state, c, lease_time, ia_option, &min_time, &req_addr, now);
767 mark_context_used(state, &req_addr);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100768 get_context_tag(state, c);
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000769 address_assigned = 1;
770 }
Simon Kelley4cb1b322012-02-06 14:30:41 +0000771 }
772
Simon Kelleyde92b472013-03-15 18:25:10 +0000773 /* Suggest configured address(es) */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100774 for (c = state->context; c; c = c->current)
Simon Kelleya1a79ed2013-03-15 21:19:57 +0000775 if (!(c->flags & CONTEXT_CONF_USED) &&
776 match_netid(c->filter, solicit_tags, plain_range) &&
777 config_valid(config, c, &addr) &&
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100778 check_address(state, &addr))
Simon Kelleyde92b472013-03-15 18:25:10 +0000779 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100780 mark_config_used(state->context, &addr);
Simon Kelleyde92b472013-03-15 18:25:10 +0000781 if (have_config(config, CONFIG_TIME))
782 lease_time = config->lease_time;
Simon Kelleya1a79ed2013-03-15 21:19:57 +0000783 else
784 lease_time = c->lease_time;
Simon Kelleyde92b472013-03-15 18:25:10 +0000785 /* add address to output packet */
Simon Kelleyc6309242013-03-07 20:59:28 +0000786#ifdef OPTION6_PREFIX_CLASS
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100787 if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA)
788 state->send_prefix_class = prefix_class_from_context(c);
Simon Kelleyc6309242013-03-07 20:59:28 +0000789#endif
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100790 add_address(state, c, lease_time, NULL, &min_time, &addr, now);
791 mark_context_used(state, &addr);
792 get_context_tag(state, c);
Simon Kelleyde92b472013-03-15 18:25:10 +0000793 address_assigned = 1;
794 }
795
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000796 /* return addresses for existing leases */
797 ltmp = NULL;
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100798 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 +0000799 {
Simon Kelley97f876b2018-08-21 22:06:36 +0100800 req_addr = ltmp->addr6;
801 if ((c = address6_available(state->context, &req_addr, solicit_tags, plain_range)))
Simon Kelley4cb1b322012-02-06 14:30:41 +0000802 {
Simon Kelleyc6309242013-03-07 20:59:28 +0000803#ifdef OPTION6_PREFIX_CLASS
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100804 if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA)
805 state->send_prefix_class = prefix_class_from_context(c);
Simon Kelleyc6309242013-03-07 20:59:28 +0000806#endif
Simon Kelley97f876b2018-08-21 22:06:36 +0100807 add_address(state, c, c->lease_time, NULL, &min_time, &req_addr, now);
808 mark_context_used(state, &req_addr);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100809 get_context_tag(state, c);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000810 address_assigned = 1;
Simon Kelley4cb1b322012-02-06 14:30:41 +0000811 }
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000812 }
813
814 /* Return addresses for all valid contexts which don't yet have one */
Simon Kelley6586e832013-11-07 14:20:13 +0000815 while ((c = address6_allocate(state->context, state->clid, state->clid_len, state->ia_type == OPTION6_IA_TA,
816 state->iaid, ia_counter, solicit_tags, plain_range, &addr)))
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000817 {
Simon Kelleyc6309242013-03-07 20:59:28 +0000818#ifdef OPTION6_PREFIX_CLASS
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100819 if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA)
820 state->send_prefix_class = prefix_class_from_context(c);
Simon Kelleyc6309242013-03-07 20:59:28 +0000821#endif
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100822 add_address(state, c, c->lease_time, NULL, &min_time, &addr, now);
823 mark_context_used(state, &addr);
824 get_context_tag(state, c);
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000825 address_assigned = 1;
826 }
827
Vladislav Grishenkob9ff5c82014-10-06 14:34:24 +0100828 if (address_assigned != 1)
829 {
830 /* If the server will not assign any addresses to any IAs in a
831 subsequent Request from the client, the server MUST send an Advertise
832 message to the client that doesn't include any IA options. */
833 if (!state->lease_allocate)
834 {
835 save_counter(o);
836 continue;
837 }
838
839 /* If the server cannot assign any addresses to an IA in the message
840 from the client, the server MUST include the IA in the Reply message
841 with no addresses in the IA and a Status Code option in the IA
842 containing status code NoAddrsAvail. */
843 o1 = new_opt6(OPTION6_STATUS_CODE);
844 put_opt6_short(DHCP6NOADDRS);
845 put_opt6_string(_("address unavailable"));
846 end_opt6(o1);
847 }
848
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000849 end_ia(t1cntr, min_time, 0);
850 end_opt6(o);
Simon Kelley4cb1b322012-02-06 14:30:41 +0000851 }
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000852
853 if (address_assigned)
854 {
855 o1 = new_opt6(OPTION6_STATUS_CODE);
856 put_opt6_short(DHCP6SUCCESS);
Simon Kelleyde92b472013-03-15 18:25:10 +0000857 put_opt6_string(_("success"));
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000858 end_opt6(o1);
859
860 /* If --dhcp-authoritative is set, we can tell client not to wait for
861 other possible servers */
862 o = new_opt6(OPTION6_PREFERENCE);
863 put_opt6_char(option_bool(OPT_AUTHORITATIVE) ? 255 : 0);
864 end_opt6(o);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100865 tagif = add_options(state, 0);
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000866 }
867 else
868 {
869 /* no address, return error */
870 o1 = new_opt6(OPTION6_STATUS_CODE);
871 put_opt6_short(DHCP6NOADDRS);
Simon Kelleyde92b472013-03-15 18:25:10 +0000872 put_opt6_string(_("no addresses available"));
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000873 end_opt6(o1);
Simon Kelley338b3402015-04-20 21:34:05 +0100874
875 /* Some clients will ask repeatedly when we're not giving
876 out addresses because we're in stateless mode. Avoid spamming
877 the log in that case. */
878 for (c = state->context; c; c = c->current)
879 if (!(c->flags & CONTEXT_RA_STATELESS))
880 {
881 log6_packet(state, state->lease_allocate ? "DHCPREPLY" : "DHCPADVERTISE", NULL, _("no addresses available"));
882 break;
883 }
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000884 }
885
Simon Kelley4cb1b322012-02-06 14:30:41 +0000886 break;
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000887 }
888
889 case DHCP6REQUEST:
890 {
891 int address_assigned = 0;
Simon Kelleyc8f2dd82013-09-13 11:22:55 +0100892 int start = save_counter(-1);
893
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000894 /* set reply message type */
895 *outmsgtypep = DHCP6REPLY;
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100896 state->lease_allocate = 1;
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000897
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +0100898 log6_quiet(state, "DHCPREQUEST", NULL, ignore ? _("ignored") : NULL);
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000899
900 if (ignore)
901 return 0;
902
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100903 for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000904 {
905 void *ia_option, *ia_end;
906 unsigned int min_time = 0xffffffff;
907 int t1cntr;
908
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100909 if (!check_ia(state, opt, &ia_end, &ia_option))
Simon Kelley3a654c52013-03-06 22:17:48 +0000910 continue;
Simon Kelleyc8f2dd82013-09-13 11:22:55 +0100911
912 if (!ia_option)
913 {
Ville Skyttäfaaf3062018-01-14 17:32:52 +0000914 /* If we get a request with an IA_*A without addresses, treat it exactly like
Simon Kelleyc8f2dd82013-09-13 11:22:55 +0100915 a SOLICT with rapid commit set. */
916 save_counter(start);
917 goto request_no_address;
918 }
919
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100920 o = build_ia(state, &t1cntr);
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000921
922 for (; ia_option; ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
923 {
Simon Kelley97f876b2018-08-21 22:06:36 +0100924 struct in6_addr req_addr;
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000925 struct dhcp_context *dynamic, *c;
926 unsigned int lease_time;
Simon Kelleyde92b472013-03-15 18:25:10 +0000927 struct in6_addr addr;
928 int config_ok = 0;
Simon Kelley97f876b2018-08-21 22:06:36 +0100929
930 /* align. */
931 memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
Simon Kelleyde92b472013-03-15 18:25:10 +0000932
Simon Kelley97f876b2018-08-21 22:06:36 +0100933 if ((c = address6_valid(state->context, &req_addr, tagif, 1)))
934 config_ok = config_valid(config, c, &addr) && IN6_ARE_ADDR_EQUAL(&addr, &req_addr);
Simon Kelleyde92b472013-03-15 18:25:10 +0000935
Simon Kelley97f876b2018-08-21 22:06:36 +0100936 if ((dynamic = address6_available(state->context, &req_addr, tagif, 1)) || c)
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000937 {
Simon Kelleyde92b472013-03-15 18:25:10 +0000938 if (!dynamic && !config_ok)
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000939 {
940 /* Static range, not configured. */
941 o1 = new_opt6(OPTION6_STATUS_CODE);
Vladislav Grishenkob9ff5c82014-10-06 14:34:24 +0100942 put_opt6_short(DHCP6NOADDRS);
Simon Kelleyde92b472013-03-15 18:25:10 +0000943 put_opt6_string(_("address unavailable"));
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000944 end_opt6(o1);
945 }
Simon Kelley97f876b2018-08-21 22:06:36 +0100946 else if (!check_address(state, &req_addr))
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000947 {
948 /* Address leased to another DUID/IAID */
949 o1 = new_opt6(OPTION6_STATUS_CODE);
950 put_opt6_short(DHCP6UNSPEC);
Simon Kelleyde92b472013-03-15 18:25:10 +0000951 put_opt6_string(_("address in use"));
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000952 end_opt6(o1);
953 }
954 else
955 {
956 if (!dynamic)
957 dynamic = c;
958
959 lease_time = dynamic->lease_time;
960
Simon Kelleyde92b472013-03-15 18:25:10 +0000961 if (config_ok && have_config(config, CONFIG_TIME))
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000962 lease_time = config->lease_time;
963
Simon Kelley6e37ab52013-03-19 20:50:11 +0000964#ifdef OPTION6_PREFIX_CLASS
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100965 if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA)
966 state->send_prefix_class = prefix_class_from_context(c);
Simon Kelley6e37ab52013-03-19 20:50:11 +0000967#endif
Simon Kelley97f876b2018-08-21 22:06:36 +0100968 add_address(state, dynamic, lease_time, ia_option, &min_time, &req_addr, now);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +0100969 get_context_tag(state, dynamic);
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000970 address_assigned = 1;
971 }
972 }
Simon Kelleyde92b472013-03-15 18:25:10 +0000973 else
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000974 {
975 /* requested address not on the correct link */
976 o1 = new_opt6(OPTION6_STATUS_CODE);
977 put_opt6_short(DHCP6NOTONLINK);
Simon Kelleyde92b472013-03-15 18:25:10 +0000978 put_opt6_string(_("not on link"));
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000979 end_opt6(o1);
980 }
981 }
982
983 end_ia(t1cntr, min_time, 0);
984 end_opt6(o);
985 }
986
987 if (address_assigned)
988 {
989 o1 = new_opt6(OPTION6_STATUS_CODE);
990 put_opt6_short(DHCP6SUCCESS);
Simon Kelleyde92b472013-03-15 18:25:10 +0000991 put_opt6_string(_("success"));
Simon Kelleya6ebfac2013-03-06 20:52:35 +0000992 end_opt6(o1);
993 }
994 else
995 {
996 /* no address, return error */
997 o1 = new_opt6(OPTION6_STATUS_CODE);
998 put_opt6_short(DHCP6NOADDRS);
Simon Kelleyde92b472013-03-15 18:25:10 +0000999 put_opt6_string(_("no addresses available"));
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001000 end_opt6(o1);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001001 log6_packet(state, "DHCPREPLY", NULL, _("no addresses available"));
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001002 }
1003
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001004 tagif = add_options(state, 0);
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001005 break;
1006 }
1007
1008
Simon Kelley4cb1b322012-02-06 14:30:41 +00001009 case DHCP6RENEW:
1010 {
1011 /* set reply message type */
1012 *outmsgtypep = DHCP6REPLY;
1013
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01001014 log6_quiet(state, "DHCPRENEW", NULL, NULL);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001015
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001016 for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
Simon Kelley4cb1b322012-02-06 14:30:41 +00001017 {
Simon Kelley4cb1b322012-02-06 14:30:41 +00001018 void *ia_option, *ia_end;
1019 unsigned int min_time = 0xffffffff;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001020 int t1cntr, iacntr;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001021
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001022 if (!check_ia(state, opt, &ia_end, &ia_option))
Simon Kelley4cb1b322012-02-06 14:30:41 +00001023 continue;
1024
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001025 o = build_ia(state, &t1cntr);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001026 iacntr = save_counter(-1);
1027
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001028 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 +00001029 {
1030 struct dhcp_lease *lease = NULL;
Simon Kelley97f876b2018-08-21 22:06:36 +01001031 struct in6_addr req_addr;
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001032 unsigned int preferred_time = opt6_uint(ia_option, 16, 4);
1033 unsigned int valid_time = opt6_uint(ia_option, 20, 4);
Simon Kelleyde92b472013-03-15 18:25:10 +00001034 char *message = NULL;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001035 struct dhcp_context *this_context;
Simon Kelley97f876b2018-08-21 22:06:36 +01001036
1037 memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001038
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001039 if (!(lease = lease6_find(state->clid, state->clid_len,
1040 state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
Simon Kelley97f876b2018-08-21 22:06:36 +01001041 state->iaid, &req_addr)))
Simon Kelley4cb1b322012-02-06 14:30:41 +00001042 {
1043 /* If the server cannot find a client entry for the IA the server
1044 returns the IA containing no addresses with a Status Code option set
1045 to NoBinding in the Reply message. */
1046 save_counter(iacntr);
1047 t1cntr = 0;
1048
Simon Kelley97f876b2018-08-21 22:06:36 +01001049 log6_packet(state, "DHCPREPLY", &req_addr, _("lease not found"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00001050
1051 o1 = new_opt6(OPTION6_STATUS_CODE);
1052 put_opt6_short(DHCP6NOBINDING);
Simon Kelleyde92b472013-03-15 18:25:10 +00001053 put_opt6_string(_("no binding found"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00001054 end_opt6(o1);
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001055
1056 preferred_time = valid_time = 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001057 break;
1058 }
1059
Simon Kelley00e9ad52012-02-16 21:53:11 +00001060
Simon Kelley97f876b2018-08-21 22:06:36 +01001061 if ((this_context = address6_available(state->context, &req_addr, tagif, 1)) ||
1062 (this_context = address6_valid(state->context, &req_addr, tagif, 1)))
Simon Kelleyc8257542012-03-28 21:15:41 +01001063 {
Simon Kelleyde92b472013-03-15 18:25:10 +00001064 struct in6_addr addr;
1065 unsigned int lease_time;
1066
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001067 get_context_tag(state, this_context);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001068
Simon Kelley97f876b2018-08-21 22:06:36 +01001069 if (config_valid(config, this_context, &addr) && IN6_ARE_ADDR_EQUAL(&addr, &req_addr) && have_config(config, CONFIG_TIME))
Simon Kelleyde92b472013-03-15 18:25:10 +00001070 lease_time = config->lease_time;
1071 else
1072 lease_time = this_context->lease_time;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001073
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001074 calculate_times(this_context, &min_time, &valid_time, &preferred_time, lease_time);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001075
Simon Kelleyde92b472013-03-15 18:25:10 +00001076 lease_set_expires(lease, valid_time, now);
Simon Kelley89500e32013-09-20 16:29:20 +01001077 /* Update MAC record in case it's new information. */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001078 if (state->mac_len != 0)
1079 lease_set_hwaddr(lease, state->mac, state->clid, state->mac_len, state->mac_type, state->clid_len, now, 0);
1080 if (state->ia_type == OPTION6_IA_NA && state->hostname)
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001081 {
Simon Kelley97f876b2018-08-21 22:06:36 +01001082 char *addr_domain = get_domain6(&req_addr);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001083 if (!state->send_domain)
1084 state->send_domain = addr_domain;
1085 lease_set_hostname(lease, state->hostname, state->hostname_auth, addr_domain, state->domain);
1086 message = state->hostname;
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001087 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001088
Simon Kelleyde92b472013-03-15 18:25:10 +00001089
1090 if (preferred_time == 0)
1091 message = _("deprecated");
Simon Kelley4cb1b322012-02-06 14:30:41 +00001092 }
Simon Kelleyde92b472013-03-15 18:25:10 +00001093 else
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001094 {
1095 preferred_time = valid_time = 0;
1096 message = _("address invalid");
Simon Kelleya5ae1f82015-04-25 21:46:10 +01001097 }
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001098
Simon Kelleya5ae1f82015-04-25 21:46:10 +01001099 if (message && (message != state->hostname))
Simon Kelley97f876b2018-08-21 22:06:36 +01001100 log6_packet(state, "DHCPREPLY", &req_addr, message);
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01001101 else
Simon Kelley97f876b2018-08-21 22:06:36 +01001102 log6_quiet(state, "DHCPREPLY", &req_addr, message);
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01001103
Simon Kelley4cb1b322012-02-06 14:30:41 +00001104 o1 = new_opt6(OPTION6_IAADDR);
Simon Kelley97f876b2018-08-21 22:06:36 +01001105 put_opt6(&req_addr, sizeof(req_addr));
Simon Kelleyde92b472013-03-15 18:25:10 +00001106 put_opt6_long(preferred_time);
1107 put_opt6_long(valid_time);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001108 end_opt6(o1);
1109 }
1110
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001111 end_ia(t1cntr, min_time, 1);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001112 end_opt6(o);
1113 }
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001114
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001115 tagif = add_options(state, 0);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001116 break;
1117
1118 }
1119
1120 case DHCP6CONFIRM:
1121 {
Ilya Ponetaev2d75f2e2014-09-13 21:11:16 +01001122 int good_addr = 0;
1123
Simon Kelley4cb1b322012-02-06 14:30:41 +00001124 /* set reply message type */
1125 *outmsgtypep = DHCP6REPLY;
1126
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01001127 log6_quiet(state, "DHCPCONFIRM", NULL, NULL);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001128
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001129 for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
Simon Kelley4cb1b322012-02-06 14:30:41 +00001130 {
Simon Kelley4cb1b322012-02-06 14:30:41 +00001131 void *ia_option, *ia_end;
1132
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001133 for (check_ia(state, opt, &ia_end, &ia_option);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001134 ia_option;
1135 ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
1136 {
Simon Kelley97f876b2018-08-21 22:06:36 +01001137 struct in6_addr req_addr;
1138
1139 /* alignment */
1140 memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001141
Simon Kelley97f876b2018-08-21 22:06:36 +01001142 if (!address6_valid(state->context, &req_addr, tagif, 1))
Simon Kelley4cb1b322012-02-06 14:30:41 +00001143 {
1144 o1 = new_opt6(OPTION6_STATUS_CODE);
1145 put_opt6_short(DHCP6NOTONLINK);
Simon Kelleyde92b472013-03-15 18:25:10 +00001146 put_opt6_string(_("confirm failed"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00001147 end_opt6(o1);
Simon Kelley97f876b2018-08-21 22:06:36 +01001148 log6_quiet(state, "DHCPREPLY", &req_addr, _("confirm failed"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00001149 return 1;
1150 }
1151
Ilya Ponetaev2d75f2e2014-09-13 21:11:16 +01001152 good_addr = 1;
Simon Kelley97f876b2018-08-21 22:06:36 +01001153 log6_quiet(state, "DHCPREPLY", &req_addr, state->hostname);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001154 }
1155 }
Ilya Ponetaev2d75f2e2014-09-13 21:11:16 +01001156
1157 /* No addresses, no reply: RFC 3315 18.2.2 */
1158 if (!good_addr)
1159 return 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001160
1161 o1 = new_opt6(OPTION6_STATUS_CODE);
1162 put_opt6_short(DHCP6SUCCESS );
Simon Kelleyde92b472013-03-15 18:25:10 +00001163 put_opt6_string(_("all addresses still on link"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00001164 end_opt6(o1);
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001165 break;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001166 }
1167
1168 case DHCP6IREQ:
1169 {
Simon Kelleyd1e9a582012-10-23 17:00:57 +01001170 /* We can't discriminate contexts based on address, as we don't know it.
1171 If there is only one possible context, we can use its tags */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001172 if (state->context && state->context->netid.net && !state->context->current)
Simon Kelleyd1e9a582012-10-23 17:00:57 +01001173 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001174 state->context->netid.next = NULL;
1175 state->context_tags = &state->context->netid;
Simon Kelleyd1e9a582012-10-23 17:00:57 +01001176 }
Simon Kelley6bd109a2013-07-27 15:11:44 +01001177
1178 /* Similarly, we can't determine domain from address, but if the FQDN is
1179 given in --dhcp-host, we can use that, and failing that we can use the
1180 unqualified configured domain, if any. */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001181 if (state->hostname_auth)
1182 state->send_domain = state->domain;
Simon Kelley6bd109a2013-07-27 15:11:44 +01001183 else
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001184 state->send_domain = get_domain6(NULL);
Simon Kelley6bd109a2013-07-27 15:11:44 +01001185
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01001186 log6_quiet(state, "DHCPINFORMATION-REQUEST", NULL, ignore ? _("ignored") : state->hostname);
Simon Kelley3634c542012-02-08 14:22:37 +00001187 if (ignore)
1188 return 0;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001189 *outmsgtypep = DHCP6REPLY;
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001190 tagif = add_options(state, 1);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001191 break;
1192 }
1193
1194
1195 case DHCP6RELEASE:
1196 {
1197 /* set reply message type */
1198 *outmsgtypep = DHCP6REPLY;
1199
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01001200 log6_quiet(state, "DHCPRELEASE", NULL, NULL);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001201
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001202 for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
Simon Kelley4cb1b322012-02-06 14:30:41 +00001203 {
Simon Kelley4cb1b322012-02-06 14:30:41 +00001204 void *ia_option, *ia_end;
1205 int made_ia = 0;
1206
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001207 for (check_ia(state, opt, &ia_end, &ia_option);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001208 ia_option;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001209 ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
Simon Kelley4cb1b322012-02-06 14:30:41 +00001210 {
1211 struct dhcp_lease *lease;
Simon Kelley97f876b2018-08-21 22:06:36 +01001212 struct in6_addr addr;
1213
1214 /* align */
1215 memcpy(&addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001216 if ((lease = lease6_find(state->clid, state->clid_len, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
Simon Kelley97f876b2018-08-21 22:06:36 +01001217 state->iaid, &addr)))
Simon Kelley4cb1b322012-02-06 14:30:41 +00001218 lease_prune(lease, now);
1219 else
1220 {
1221 if (!made_ia)
1222 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001223 o = new_opt6(state->ia_type);
1224 put_opt6_long(state->iaid);
1225 if (state->ia_type == OPTION6_IA_NA)
Simon Kelley4cb1b322012-02-06 14:30:41 +00001226 {
1227 put_opt6_long(0);
1228 put_opt6_long(0);
1229 }
1230 made_ia = 1;
1231 }
1232
1233 o1 = new_opt6(OPTION6_IAADDR);
Simon Kelleyc5db8f92018-08-23 23:06:00 +01001234 put_opt6(&addr, IN6ADDRSZ);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001235 put_opt6_long(0);
1236 put_opt6_long(0);
1237 end_opt6(o1);
1238 }
1239 }
1240
1241 if (made_ia)
1242 {
1243 o1 = new_opt6(OPTION6_STATUS_CODE);
1244 put_opt6_short(DHCP6NOBINDING);
Simon Kelleyde92b472013-03-15 18:25:10 +00001245 put_opt6_string(_("no binding found"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00001246 end_opt6(o1);
1247
1248 end_opt6(o);
1249 }
1250 }
1251
1252 o1 = new_opt6(OPTION6_STATUS_CODE);
1253 put_opt6_short(DHCP6SUCCESS);
Simon Kelleyde92b472013-03-15 18:25:10 +00001254 put_opt6_string(_("release received"));
Simon Kelley4cb1b322012-02-06 14:30:41 +00001255 end_opt6(o1);
1256
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001257 break;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001258 }
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001259
1260 case DHCP6DECLINE:
1261 {
1262 /* set reply message type */
1263 *outmsgtypep = DHCP6REPLY;
1264
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01001265 log6_quiet(state, "DHCPDECLINE", NULL, NULL);
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001266
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001267 for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001268 {
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001269 void *ia_option, *ia_end;
1270 int made_ia = 0;
1271
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001272 for (check_ia(state, opt, &ia_end, &ia_option);
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001273 ia_option;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001274 ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001275 {
1276 struct dhcp_lease *lease;
Simon Kelley97f876b2018-08-21 22:06:36 +01001277 struct in6_addr addr;
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001278
Simon Kelley97f876b2018-08-21 22:06:36 +01001279 /* align */
1280 memcpy(&addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
1281
1282 if (have_config(config, CONFIG_ADDR6) && IN6_ARE_ADDR_EQUAL(&config->addr6, &addr))
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001283 {
Simon Kelleyceae00d2012-02-09 21:28:14 +00001284 prettyprint_time(daemon->dhcp_buff3, DECLINE_BACKOFF);
Simon Kelley97f876b2018-08-21 22:06:36 +01001285 inet_ntop(AF_INET6, &addr, daemon->addrbuff, ADDRSTRLEN);
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001286 my_syslog(MS_DHCP | LOG_WARNING, _("disabling DHCP static address %s for %s"),
Simon Kelleyceae00d2012-02-09 21:28:14 +00001287 daemon->addrbuff, daemon->dhcp_buff3);
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001288 config->flags |= CONFIG_DECLINED;
1289 config->decline_time = now;
1290 }
1291 else
1292 /* make sure this host gets a different address next time. */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001293 for (context_tmp = state->context; context_tmp; context_tmp = context_tmp->current)
1294 context_tmp->addr_epoch++;
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001295
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001296 if ((lease = lease6_find(state->clid, state->clid_len, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
Simon Kelley97f876b2018-08-21 22:06:36 +01001297 state->iaid, &addr)))
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001298 lease_prune(lease, now);
1299 else
1300 {
1301 if (!made_ia)
1302 {
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001303 o = new_opt6(state->ia_type);
1304 put_opt6_long(state->iaid);
1305 if (state->ia_type == OPTION6_IA_NA)
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001306 {
1307 put_opt6_long(0);
1308 put_opt6_long(0);
1309 }
1310 made_ia = 1;
1311 }
1312
1313 o1 = new_opt6(OPTION6_IAADDR);
Simon Kelley97f876b2018-08-21 22:06:36 +01001314 put_opt6(&addr, IN6ADDRSZ);
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001315 put_opt6_long(0);
1316 put_opt6_long(0);
1317 end_opt6(o1);
1318 }
1319 }
1320
1321 if (made_ia)
1322 {
1323 o1 = new_opt6(OPTION6_STATUS_CODE);
1324 put_opt6_short(DHCP6NOBINDING);
Simon Kelleyde92b472013-03-15 18:25:10 +00001325 put_opt6_string(_("no binding found"));
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001326 end_opt6(o1);
1327
1328 end_opt6(o);
1329 }
1330
1331 }
Ilya Ponetaev51943362014-09-13 21:19:01 +01001332
Josh Soref730c6742017-02-06 16:14:04 +00001333 /* We must answer with 'success' in global section anyway */
Ilya Ponetaev51943362014-09-13 21:19:01 +01001334 o1 = new_opt6(OPTION6_STATUS_CODE);
1335 put_opt6_short(DHCP6SUCCESS);
1336 put_opt6_string(_("success"));
1337 end_opt6(o1);
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001338 break;
Simon Kelley70c5e3e2012-02-06 22:05:15 +00001339 }
1340
Simon Kelley4cb1b322012-02-06 14:30:41 +00001341 }
1342
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001343 log_tags(tagif, state->xid);
1344 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 +00001345
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001346 return 1;
1347
1348}
1349
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001350static struct dhcp_netid *add_options(struct state *state, int do_refresh)
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001351{
Simon Kelley2763d4b2013-03-06 21:24:56 +00001352 void *oro;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001353 /* filter options based on tags, those we want get DHOPT_TAGOK bit set */
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001354 struct dhcp_netid *tagif = option_filter(state->tags, state->context_tags, daemon->dhcp_opts6);
1355 struct dhcp_opt *opt_cfg;
Simon Kelley871d4562013-07-27 21:32:32 +01001356 int done_dns = 0, done_refresh = !do_refresh, do_encap = 0;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001357 int i, o, o1;
1358
1359 oro = opt6_find(state->packet_options, state->end, OPTION6_ORO, 0);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001360
1361 for (opt_cfg = daemon->dhcp_opts6; opt_cfg; opt_cfg = opt_cfg->next)
1362 {
1363 /* netids match and not encapsulated? */
1364 if (!(opt_cfg->flags & DHOPT_TAGOK))
1365 continue;
1366
1367 if (!(opt_cfg->flags & DHOPT_FORCE) && oro)
1368 {
1369 for (i = 0; i < opt6_len(oro) - 1; i += 2)
1370 if (opt6_uint(oro, i, 2) == (unsigned)opt_cfg->opt)
1371 break;
1372
1373 /* option not requested */
1374 if (i >= opt6_len(oro) - 1)
1375 continue;
1376 }
1377
Simon Kelley871d4562013-07-27 21:32:32 +01001378 if (opt_cfg->opt == OPTION6_REFRESH_TIME)
1379 done_refresh = 1;
Simon Kelley5e3e4642015-08-25 23:08:39 +01001380
1381 if (opt_cfg->opt == OPTION6_DNS_SERVER)
1382 done_dns = 1;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001383
Simon Kelley27b78d92015-09-26 21:40:45 +01001384 if (opt_cfg->flags & DHOPT_ADDR6)
Simon Kelley4b86b652012-02-29 11:45:37 +00001385 {
Simon Kelleyc3a04082014-01-11 22:18:19 +00001386 int len, j;
1387 struct in6_addr *a;
1388
Simon Kelleyc3a04082014-01-11 22:18:19 +00001389 for (a = (struct in6_addr *)opt_cfg->val, len = opt_cfg->len, j = 0;
1390 j < opt_cfg->len; j += IN6ADDRSZ, a++)
1391 if ((IN6_IS_ADDR_ULA_ZERO(a) && IN6_IS_ADDR_UNSPECIFIED(state->ula_addr)) ||
1392 (IN6_IS_ADDR_LINK_LOCAL_ZERO(a) && IN6_IS_ADDR_UNSPECIFIED(state->ll_addr)))
1393 len -= IN6ADDRSZ;
1394
1395 if (len != 0)
1396 {
1397
1398 o = new_opt6(opt_cfg->opt);
1399
1400 for (a = (struct in6_addr *)opt_cfg->val, j = 0; j < opt_cfg->len; j+=IN6ADDRSZ, a++)
1401 {
1402 if (IN6_IS_ADDR_UNSPECIFIED(a))
1403 {
1404 if (!add_local_addrs(state->context))
1405 put_opt6(state->fallback, IN6ADDRSZ);
1406 }
1407 else if (IN6_IS_ADDR_ULA_ZERO(a))
1408 {
1409 if (!IN6_IS_ADDR_UNSPECIFIED(state->ula_addr))
1410 put_opt6(state->ula_addr, IN6ADDRSZ);
1411 }
1412 else if (IN6_IS_ADDR_LINK_LOCAL_ZERO(a))
1413 {
1414 if (!IN6_IS_ADDR_UNSPECIFIED(state->ll_addr))
1415 put_opt6(state->ll_addr, IN6ADDRSZ);
1416 }
1417 else
1418 put_opt6(a, IN6ADDRSZ);
Simon Kelley4b86b652012-02-29 11:45:37 +00001419 }
Simon Kelleyc3a04082014-01-11 22:18:19 +00001420
1421 end_opt6(o);
1422 }
Simon Kelley4b86b652012-02-29 11:45:37 +00001423 }
Simon Kelleyc3a04082014-01-11 22:18:19 +00001424 else
1425 {
1426 o = new_opt6(opt_cfg->opt);
1427 if (opt_cfg->val)
1428 put_opt6(opt_cfg->val, opt_cfg->len);
1429 end_opt6(o);
1430 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001431 }
1432
Simon Kelley871d4562013-07-27 21:32:32 +01001433 if (daemon->port == NAMESERVER_PORT && !done_dns)
Simon Kelley4cb1b322012-02-06 14:30:41 +00001434 {
1435 o = new_opt6(OPTION6_DNS_SERVER);
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001436 if (!add_local_addrs(state->context))
1437 put_opt6(state->fallback, IN6ADDRSZ);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001438 end_opt6(o);
1439 }
Simon Kelley871d4562013-07-27 21:32:32 +01001440
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001441 if (state->context && !done_refresh)
Simon Kelley871d4562013-07-27 21:32:32 +01001442 {
1443 struct dhcp_context *c;
1444 unsigned int lease_time = 0xffffffff;
1445
1446 /* Find the smallest lease tie of all contexts,
Josh Soref730c6742017-02-06 16:14:04 +00001447 subject to the RFC-4242 stipulation that this must not
Simon Kelley871d4562013-07-27 21:32:32 +01001448 be less than 600. */
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001449 for (c = state->context; c; c = c->next)
Simon Kelley871d4562013-07-27 21:32:32 +01001450 if (c->lease_time < lease_time)
1451 {
1452 if (c->lease_time < 600)
1453 lease_time = 600;
1454 else
1455 lease_time = c->lease_time;
1456 }
1457
1458 o = new_opt6(OPTION6_REFRESH_TIME);
1459 put_opt6_long(lease_time);
1460 end_opt6(o);
1461 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001462
1463 /* handle vendor-identifying vendor-encapsulated options,
1464 dhcp-option = vi-encap:13,17,....... */
1465 for (opt_cfg = daemon->dhcp_opts6; opt_cfg; opt_cfg = opt_cfg->next)
1466 opt_cfg->flags &= ~DHOPT_ENCAP_DONE;
Simon Kelley4b86b652012-02-29 11:45:37 +00001467
Simon Kelley4cb1b322012-02-06 14:30:41 +00001468 if (oro)
1469 for (i = 0; i < opt6_len(oro) - 1; i += 2)
1470 if (opt6_uint(oro, i, 2) == OPTION6_VENDOR_OPTS)
1471 do_encap = 1;
1472
1473 for (opt_cfg = daemon->dhcp_opts6; opt_cfg; opt_cfg = opt_cfg->next)
1474 {
1475 if (opt_cfg->flags & DHOPT_RFC3925)
1476 {
1477 int found = 0;
1478 struct dhcp_opt *oc;
1479
1480 if (opt_cfg->flags & DHOPT_ENCAP_DONE)
1481 continue;
1482
1483 for (oc = daemon->dhcp_opts6; oc; oc = oc->next)
1484 {
1485 oc->flags &= ~DHOPT_ENCAP_MATCH;
1486
1487 if (!(oc->flags & DHOPT_RFC3925) || opt_cfg->u.encap != oc->u.encap)
1488 continue;
1489
1490 oc->flags |= DHOPT_ENCAP_DONE;
1491 if (match_netid(oc->netid, tagif, 1))
1492 {
1493 /* option requested/forced? */
1494 if (!oro || do_encap || (oc->flags & DHOPT_FORCE))
1495 {
1496 oc->flags |= DHOPT_ENCAP_MATCH;
1497 found = 1;
1498 }
1499 }
1500 }
1501
1502 if (found)
1503 {
1504 o = new_opt6(OPTION6_VENDOR_OPTS);
1505 put_opt6_long(opt_cfg->u.encap);
1506
1507 for (oc = daemon->dhcp_opts6; oc; oc = oc->next)
1508 if (oc->flags & DHOPT_ENCAP_MATCH)
1509 {
1510 o1 = new_opt6(oc->opt);
1511 put_opt6(oc->val, oc->len);
1512 end_opt6(o1);
1513 }
1514 end_opt6(o);
1515 }
1516 }
1517 }
Simon Kelley07933802012-02-14 20:55:25 +00001518
1519
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001520 if (state->hostname)
Simon Kelley4cb1b322012-02-06 14:30:41 +00001521 {
1522 unsigned char *p;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001523 size_t len = strlen(state->hostname);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001524
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001525 if (state->send_domain)
Roy Marples3f3adae2013-07-25 16:22:46 +01001526 len += strlen(state->send_domain) + 2;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001527
1528 o = new_opt6(OPTION6_FQDN);
Roy Marples3f3adae2013-07-25 16:22:46 +01001529 if ((p = expand(len + 2)))
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001530 {
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001531 *(p++) = state->fqdn_flags;
Simon Kelley0549c732017-09-25 18:17:11 +01001532 p = do_rfc1035_name(p, state->hostname, NULL);
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001533 if (state->send_domain)
Roy Marples3f3adae2013-07-25 16:22:46 +01001534 {
Simon Kelley0549c732017-09-25 18:17:11 +01001535 p = do_rfc1035_name(p, state->send_domain, NULL);
Roy Marples3f3adae2013-07-25 16:22:46 +01001536 *p = 0;
1537 }
Simon Kelleyc5ad4e72012-02-24 16:06:20 +00001538 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001539 end_opt6(o);
1540 }
1541
1542
1543 /* logging */
1544 if (option_bool(OPT_LOG_OPTS) && oro)
1545 {
1546 char *q = daemon->namebuff;
1547 for (i = 0; i < opt6_len(oro) - 1; i += 2)
1548 {
1549 char *s = option_string(AF_INET6, opt6_uint(oro, i, 2), NULL, 0, NULL, 0);
1550 q += snprintf(q, MAXDNAME - (q - daemon->namebuff),
1551 "%d%s%s%s",
1552 opt6_uint(oro, i, 2),
1553 strlen(s) != 0 ? ":" : "",
1554 s,
1555 (i > opt6_len(oro) - 3) ? "" : ", ");
1556 if ( i > opt6_len(oro) - 3 || (q - daemon->namebuff) > 40)
1557 {
1558 q = daemon->namebuff;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001559 my_syslog(MS_DHCP | LOG_INFO, _("%u requested options: %s"), state->xid, daemon->namebuff);
Simon Kelley4cb1b322012-02-06 14:30:41 +00001560 }
1561 }
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001562 }
Simon Kelley4cb1b322012-02-06 14:30:41 +00001563
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001564 return tagif;
1565}
1566
1567static int add_local_addrs(struct dhcp_context *context)
1568{
1569 int done = 0;
Simon Kelley6c8f21e2012-03-12 15:06:55 +00001570
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001571 for (; context; context = context->current)
1572 if ((context->flags & CONTEXT_USED) && !IN6_IS_ADDR_UNSPECIFIED(&context->local6))
1573 {
1574 /* squash duplicates */
1575 struct dhcp_context *c;
1576 for (c = context->current; c; c = c->current)
1577 if ((c->flags & CONTEXT_USED) &&
1578 IN6_ARE_ADDR_EQUAL(&context->local6, &c->local6))
1579 break;
1580
1581 if (!c)
1582 {
1583 done = 1;
1584 put_opt6(&context->local6, IN6ADDRSZ);
1585 }
1586 }
1587
1588 return done;
Simon Kelley6c8f21e2012-03-12 15:06:55 +00001589}
1590
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001591
1592static void get_context_tag(struct state *state, struct dhcp_context *context)
1593{
1594 /* get tags from context if we've not used it before */
1595 if (context->netid.next == &context->netid && context->netid.net)
1596 {
1597 context->netid.next = state->context_tags;
1598 state->context_tags = &context->netid;
1599 if (!state->hostname_auth)
1600 {
1601 struct dhcp_netid_list *id_list;
1602
1603 for (id_list = daemon->dhcp_ignore_names; id_list; id_list = id_list->next)
1604 if ((!id_list->list) || match_netid(id_list->list, &context->netid, 0))
1605 break;
1606 if (id_list)
1607 state->hostname = NULL;
1608 }
1609 }
1610}
Simon Kelleyc6309242013-03-07 20:59:28 +00001611
1612#ifdef OPTION6_PREFIX_CLASS
1613static struct prefix_class *prefix_class_from_context(struct dhcp_context *context)
1614{
1615 struct prefix_class *p;
1616 struct dhcp_netid *t;
1617
1618 for (p = daemon->prefix_classes; p ; p = p->next)
1619 for (t = context->filter; t; t = t->next)
1620 if (strcmp(p->tag.net, t->net) == 0)
1621 return p;
1622
1623 return NULL;
1624}
1625#endif
1626
Simon Kelley3a654c52013-03-06 22:17:48 +00001627static int check_ia(struct state *state, void *opt, void **endp, void **ia_option)
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001628{
1629 state->ia_type = opt6_type(opt);
Simon Kelley3a654c52013-03-06 22:17:48 +00001630 *ia_option = NULL;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001631
1632 if (state->ia_type != OPTION6_IA_NA && state->ia_type != OPTION6_IA_TA)
Simon Kelley3a654c52013-03-06 22:17:48 +00001633 return 0;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001634
1635 if (state->ia_type == OPTION6_IA_NA && opt6_len(opt) < 12)
Simon Kelley3a654c52013-03-06 22:17:48 +00001636 return 0;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001637
1638 if (state->ia_type == OPTION6_IA_TA && opt6_len(opt) < 4)
Simon Kelley3a654c52013-03-06 22:17:48 +00001639 return 0;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001640
1641 *endp = opt6_ptr(opt, opt6_len(opt));
1642 state->iaid = opt6_uint(opt, 0, 4);
Simon Kelley3a654c52013-03-06 22:17:48 +00001643 *ia_option = opt6_find(opt6_ptr(opt, state->ia_type == OPTION6_IA_NA ? 12 : 4), *endp, OPTION6_IAADDR, 24);
1644
1645 return 1;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001646}
1647
1648
1649static int build_ia(struct state *state, int *t1cntr)
1650{
1651 int o = new_opt6(state->ia_type);
1652
1653 put_opt6_long(state->iaid);
1654 *t1cntr = 0;
1655
1656 if (state->ia_type == OPTION6_IA_NA)
1657 {
1658 /* save pointer */
1659 *t1cntr = save_counter(-1);
1660 /* so we can fill these in later */
1661 put_opt6_long(0);
1662 put_opt6_long(0);
1663 }
1664
1665 return o;
1666}
1667
1668static void end_ia(int t1cntr, unsigned int min_time, int do_fuzz)
1669{
1670 if (t1cntr != 0)
1671 {
Ville Skyttäfaaf3062018-01-14 17:32:52 +00001672 /* go back and fill in fields in IA_NA option */
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001673 int sav = save_counter(t1cntr);
1674 unsigned int t1, t2, fuzz = 0;
1675
1676 if (do_fuzz)
1677 {
1678 fuzz = rand16();
1679
1680 while (fuzz > (min_time/16))
1681 fuzz = fuzz/2;
1682 }
1683
1684 t1 = (min_time == 0xffffffff) ? 0xffffffff : min_time/2 - fuzz;
1685 t2 = (min_time == 0xffffffff) ? 0xffffffff : ((min_time/8)*7) - fuzz;
1686 put_opt6_long(t1);
1687 put_opt6_long(t2);
1688 save_counter(sav);
1689 }
1690}
1691
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001692static void add_address(struct state *state, struct dhcp_context *context, unsigned int lease_time, void *ia_option,
Simon Kelleyc8f2dd82013-09-13 11:22:55 +01001693 unsigned int *min_time, struct in6_addr *addr, time_t now)
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001694{
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001695 unsigned int valid_time = 0, preferred_time = 0;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001696 int o = new_opt6(OPTION6_IAADDR);
1697 struct dhcp_lease *lease;
1698
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001699 /* get client requested times */
1700 if (ia_option)
1701 {
1702 preferred_time = opt6_uint(ia_option, 16, 4);
1703 valid_time = opt6_uint(ia_option, 20, 4);
1704 }
1705
1706 calculate_times(context, min_time, &valid_time, &preferred_time, lease_time);
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001707
Simon Kelleyde92b472013-03-15 18:25:10 +00001708 put_opt6(addr, sizeof(*addr));
1709 put_opt6_long(preferred_time);
1710 put_opt6_long(valid_time);
1711
Simon Kelleyc6309242013-03-07 20:59:28 +00001712#ifdef OPTION6_PREFIX_CLASS
1713 if (state->send_prefix_class)
1714 {
1715 int o1 = new_opt6(OPTION6_PREFIX_CLASS);
1716 put_opt6_short(state->send_prefix_class->class);
1717 end_opt6(o1);
1718 }
1719#endif
1720
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001721 end_opt6(o);
1722
Simon Kelleyc8f2dd82013-09-13 11:22:55 +01001723 if (state->lease_allocate)
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001724 update_leases(state, context, addr, valid_time, now);
1725
1726 if ((lease = lease6_find_by_addr(addr, 128, 0)))
1727 lease->flags |= LEASE_USED;
1728
1729 /* get tags from context if we've not used it before */
1730 if (context->netid.next == &context->netid && context->netid.net)
1731 {
1732 context->netid.next = state->context_tags;
1733 state->context_tags = &context->netid;
1734
1735 if (!state->hostname_auth)
1736 {
1737 struct dhcp_netid_list *id_list;
1738
1739 for (id_list = daemon->dhcp_ignore_names; id_list; id_list = id_list->next)
1740 if ((!id_list->list) || match_netid(id_list->list, &context->netid, 0))
1741 break;
1742 if (id_list)
1743 state->hostname = NULL;
1744 }
1745 }
1746
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01001747 log6_quiet(state, state->lease_allocate ? "DHCPREPLY" : "DHCPADVERTISE", addr, state->hostname);
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001748
1749}
Simon Kelleyff59fc82013-03-07 11:00:26 +00001750
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001751static void mark_context_used(struct state *state, struct in6_addr *addr)
Simon Kelleyff59fc82013-03-07 11:00:26 +00001752{
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001753 struct dhcp_context *context;
1754
Simon Kelleyff59fc82013-03-07 11:00:26 +00001755 /* Mark that we have an address for this prefix. */
Simon Kelleyc6309242013-03-07 20:59:28 +00001756#ifdef OPTION6_PREFIX_CLASS
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001757 for (context = state->context; context; context = context->current)
Simon Kelleyc6309242013-03-07 20:59:28 +00001758 if (is_same_net6(addr, &context->start6, context->prefix) &&
1759 (!state->send_prefix_class || state->send_prefix_class == prefix_class_from_context(context)))
1760 context->flags |= CONTEXT_USED;
1761#else
Simon Kelleyf1af2bb2013-09-24 09:16:28 +01001762 for (context = state->context; context; context = context->current)
Simon Kelleyff59fc82013-03-07 11:00:26 +00001763 if (is_same_net6(addr, &context->start6, context->prefix))
1764 context->flags |= CONTEXT_USED;
Simon Kelleyc6309242013-03-07 20:59:28 +00001765#endif
Simon Kelleyff59fc82013-03-07 11:00:26 +00001766}
Simon Kelleyc6309242013-03-07 20:59:28 +00001767
Simon Kelleyde92b472013-03-15 18:25:10 +00001768static void mark_config_used(struct dhcp_context *context, struct in6_addr *addr)
1769{
1770 for (; context; context = context->current)
1771 if (is_same_net6(addr, &context->start6, context->prefix))
1772 context->flags |= CONTEXT_CONF_USED;
1773}
1774
1775/* make sure address not leased to another CLID/IAID */
1776static int check_address(struct state *state, struct in6_addr *addr)
1777{
1778 struct dhcp_lease *lease;
1779
1780 if (!(lease = lease6_find_by_addr(addr, 128, 0)))
1781 return 1;
1782
1783 if (lease->clid_len != state->clid_len ||
1784 memcmp(lease->clid, state->clid, state->clid_len) != 0 ||
Simon Kelley89500e32013-09-20 16:29:20 +01001785 lease->iaid != state->iaid)
Simon Kelleyde92b472013-03-15 18:25:10 +00001786 return 0;
1787
1788 return 1;
1789}
1790
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001791
1792/* Calculate valid and preferred times to send in leases/renewals.
1793
1794 Inputs are:
1795
1796 *valid_timep, *preferred_timep - requested times from IAADDR options.
1797 context->valid, context->preferred - times associated with subnet address on local interface.
1798 context->flags | CONTEXT_DEPRECATE - "deprecated" flag in dhcp-range.
1799 lease_time - configured time for context for individual client.
1800 *min_time - smallest valid time sent so far.
1801
1802 Outputs are :
1803
1804 *valid_timep, *preferred_timep - times to be send in IAADDR option.
1805 *min_time - smallest valid time sent so far, to calculate T1 and T2.
1806
1807 */
Simon Kelleyde92b472013-03-15 18:25:10 +00001808static void calculate_times(struct dhcp_context *context, unsigned int *min_time, unsigned int *valid_timep,
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001809 unsigned int *preferred_timep, unsigned int lease_time)
Simon Kelleyde92b472013-03-15 18:25:10 +00001810{
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001811 unsigned int req_preferred = *preferred_timep, req_valid = *valid_timep;
1812 unsigned int valid_time = lease_time, preferred_time = lease_time;
1813
1814 /* RFC 3315: "A server ignores the lifetimes set
1815 by the client if the preferred lifetime is greater than the valid
1816 lifetime. */
1817 if (req_preferred <= req_valid)
1818 {
1819 if (req_preferred != 0)
1820 {
1821 /* 0 == "no preference from client" */
1822 if (req_preferred < 120u)
1823 req_preferred = 120u; /* sanity */
1824
1825 if (req_preferred < preferred_time)
1826 preferred_time = req_preferred;
1827 }
1828
1829 if (req_valid != 0)
1830 /* 0 == "no preference from client" */
1831 {
1832 if (req_valid < 120u)
1833 req_valid = 120u; /* sanity */
1834
1835 if (req_valid < valid_time)
1836 valid_time = req_valid;
1837 }
1838 }
Simon Kelleyde92b472013-03-15 18:25:10 +00001839
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001840 /* deprecate (preferred == 0) which configured, or when local address
1841 is deprecated */
1842 if ((context->flags & CONTEXT_DEPRECATE) || context->preferred == 0)
Simon Kelleyde92b472013-03-15 18:25:10 +00001843 preferred_time = 0;
Simon Kelleycc4baaa2013-08-05 15:03:44 +01001844
Simon Kelleyde92b472013-03-15 18:25:10 +00001845 if (preferred_time != 0 && preferred_time < *min_time)
1846 *min_time = preferred_time;
1847
1848 if (valid_time != 0 && valid_time < *min_time)
1849 *min_time = valid_time;
1850
1851 *valid_timep = valid_time;
1852 *preferred_timep = preferred_time;
1853}
1854
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001855static void update_leases(struct state *state, struct dhcp_context *context, struct in6_addr *addr, unsigned int lease_time, time_t now)
1856{
1857 struct dhcp_lease *lease = lease6_find_by_addr(addr, 128, 0);
Vladislav Grishenko408c3682013-09-24 16:18:49 +01001858#ifdef HAVE_SCRIPT
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001859 struct dhcp_netid *tagif = run_tag_if(state->tags);
Vladislav Grishenko408c3682013-09-24 16:18:49 +01001860#endif
1861
1862 (void)context;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001863
1864 if (!lease)
1865 lease = lease6_allocate(addr, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA);
1866
1867 if (lease)
1868 {
1869 lease_set_expires(lease, lease_time, now);
Simon Kelley89500e32013-09-20 16:29:20 +01001870 lease_set_iaid(lease, state->iaid);
1871 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 +00001872 lease_set_interface(lease, state->interface, now);
1873 if (state->hostname && state->ia_type == OPTION6_IA_NA)
1874 {
1875 char *addr_domain = get_domain6(addr);
1876 if (!state->send_domain)
1877 state->send_domain = addr_domain;
1878 lease_set_hostname(lease, state->hostname, state->hostname_auth, addr_domain, state->domain);
1879 }
1880
1881#ifdef HAVE_SCRIPT
1882 if (daemon->lease_change_command)
1883 {
1884 void *class_opt;
1885 lease->flags |= LEASE_CHANGED;
1886 free(lease->extradata);
1887 lease->extradata = NULL;
1888 lease->extradata_size = lease->extradata_len = 0;
Simon Kelley6f9aaa92013-04-10 10:25:26 +01001889 lease->vendorclass_count = 0;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001890
1891 if ((class_opt = opt6_find(state->packet_options, state->end, OPTION6_VENDOR_CLASS, 4)))
1892 {
1893 void *enc_opt, *enc_end = opt6_ptr(class_opt, opt6_len(class_opt));
Simon Kelley6f9aaa92013-04-10 10:25:26 +01001894 lease->vendorclass_count++;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001895 /* send enterprise number first */
1896 sprintf(daemon->dhcp_buff2, "%u", opt6_uint(class_opt, 0, 4));
1897 lease_add_extradata(lease, (unsigned char *)daemon->dhcp_buff2, strlen(daemon->dhcp_buff2), 0);
1898
1899 if (opt6_len(class_opt) >= 6)
1900 for (enc_opt = opt6_ptr(class_opt, 4); enc_opt; enc_opt = opt6_next(enc_opt, enc_end))
1901 {
Simon Kelley6f9aaa92013-04-10 10:25:26 +01001902 lease->vendorclass_count++;
Simon Kelleya6ebfac2013-03-06 20:52:35 +00001903 lease_add_extradata(lease, opt6_ptr(enc_opt, 0), opt6_len(enc_opt), 0);
1904 }
1905 }
1906
1907 lease_add_extradata(lease, (unsigned char *)state->client_hostname,
1908 state->client_hostname ? strlen(state->client_hostname) : 0, 0);
1909
1910 /* space-concat tag set */
1911 if (!tagif && !context->netid.net)
1912 lease_add_extradata(lease, NULL, 0, 0);
1913 else
1914 {
1915 if (context->netid.net)
1916 lease_add_extradata(lease, (unsigned char *)context->netid.net, strlen(context->netid.net), tagif ? ' ' : 0);
1917
1918 if (tagif)
1919 {
1920 struct dhcp_netid *n;
1921 for (n = tagif; n; n = n->next)
1922 {
1923 struct dhcp_netid *n1;
1924 /* kill dupes */
1925 for (n1 = n->next; n1; n1 = n1->next)
1926 if (strcmp(n->net, n1->net) == 0)
1927 break;
1928 if (!n1)
1929 lease_add_extradata(lease, (unsigned char *)n->net, strlen(n->net), n->next ? ' ' : 0);
1930 }
1931 }
1932 }
1933
1934 if (state->link_address)
1935 inet_ntop(AF_INET6, state->link_address, daemon->addrbuff, ADDRSTRLEN);
1936
1937 lease_add_extradata(lease, (unsigned char *)daemon->addrbuff, state->link_address ? strlen(daemon->addrbuff) : 0, 0);
1938
1939 if ((class_opt = opt6_find(state->packet_options, state->end, OPTION6_USER_CLASS, 2)))
1940 {
1941 void *enc_opt, *enc_end = opt6_ptr(class_opt, opt6_len(class_opt));
1942 for (enc_opt = opt6_ptr(class_opt, 0); enc_opt; enc_opt = opt6_next(enc_opt, enc_end))
1943 lease_add_extradata(lease, opt6_ptr(enc_opt, 0), opt6_len(enc_opt), 0);
1944 }
1945 }
1946#endif
1947
1948 }
1949}
1950
1951
1952
Simon Kelley6c8f21e2012-03-12 15:06:55 +00001953static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_opts)
1954{
1955 void *opt;
1956 char *desc = nest ? "nest" : "sent";
Simon Kelley5cfea3d2012-03-12 17:28:27 +00001957
Simon Kelleyd81b42d2013-09-23 12:26:34 +01001958 if (!option_bool(OPT_LOG_OPTS) || start_opts == end_opts)
Simon Kelley5cfea3d2012-03-12 17:28:27 +00001959 return;
1960
1961 for (opt = start_opts; opt; opt = opt6_next(opt, end_opts))
1962 {
1963 int type = opt6_type(opt);
1964 void *ia_options = NULL;
1965 char *optname;
Simon Kelley4cb1b322012-02-06 14:30:41 +00001966
Simon Kelley5cfea3d2012-03-12 17:28:27 +00001967 if (type == OPTION6_IA_NA)
1968 {
1969 sprintf(daemon->namebuff, "IAID=%u T1=%u T2=%u",
1970 opt6_uint(opt, 0, 4), opt6_uint(opt, 4, 4), opt6_uint(opt, 8, 4));
1971 optname = "ia-na";
1972 ia_options = opt6_ptr(opt, 12);
1973 }
1974 else if (type == OPTION6_IA_TA)
1975 {
1976 sprintf(daemon->namebuff, "IAID=%u", opt6_uint(opt, 0, 4));
1977 optname = "ia-ta";
1978 ia_options = opt6_ptr(opt, 4);
1979 }
1980 else if (type == OPTION6_IAADDR)
1981 {
Simon Kelley97f876b2018-08-21 22:06:36 +01001982 struct in6_addr addr;
1983
1984 /* align */
1985 memcpy(&addr, opt6_ptr(opt, 0), IN6ADDRSZ);
1986 inet_ntop(AF_INET6, &addr, daemon->addrbuff, ADDRSTRLEN);
Simon Kelley5cfea3d2012-03-12 17:28:27 +00001987 sprintf(daemon->namebuff, "%s PL=%u VL=%u",
1988 daemon->addrbuff, opt6_uint(opt, 16, 4), opt6_uint(opt, 20, 4));
1989 optname = "iaaddr";
1990 ia_options = opt6_ptr(opt, 24);
1991 }
Simon Kelleyc6309242013-03-07 20:59:28 +00001992#ifdef OPTION6_PREFIX_CLASS
1993 else if (type == OPTION6_PREFIX_CLASS)
1994 {
1995 optname = "prefix-class";
1996 sprintf(daemon->namebuff, "class=%u", opt6_uint(opt, 0, 2));
1997 }
1998#endif
Simon Kelley5cfea3d2012-03-12 17:28:27 +00001999 else if (type == OPTION6_STATUS_CODE)
2000 {
2001 int len = sprintf(daemon->namebuff, "%u ", opt6_uint(opt, 0, 2));
2002 memcpy(daemon->namebuff + len, opt6_ptr(opt, 2), opt6_len(opt)-2);
2003 daemon->namebuff[len + opt6_len(opt) - 2] = 0;
2004 optname = "status";
2005 }
2006 else
2007 {
2008 /* account for flag byte on FQDN */
2009 int offset = type == OPTION6_FQDN ? 1 : 0;
2010 optname = option_string(AF_INET6, type, opt6_ptr(opt, offset), opt6_len(opt) - offset, daemon->namebuff, MAXDNAME);
2011 }
2012
2013 my_syslog(MS_DHCP | LOG_INFO, "%u %s size:%3d option:%3d %s %s",
2014 xid, desc, opt6_len(opt), type, optname, daemon->namebuff);
2015
2016 if (ia_options)
2017 log6_opts(1, xid, ia_options, opt6_ptr(opt, opt6_len(opt)));
2018 }
Simon Kelley6c8f21e2012-03-12 15:06:55 +00002019}
2020
Kevin Darbyshire-Bryant8c0b73d2013-10-11 11:56:33 +01002021static void log6_quiet(struct state *state, char *type, struct in6_addr *addr, char *string)
2022{
2023 if (option_bool(OPT_LOG_OPTS) || !option_bool(OPT_QUIET_DHCP6))
2024 log6_packet(state, type, addr, string);
2025}
2026
Simon Kelleya6ebfac2013-03-06 20:52:35 +00002027static void log6_packet(struct state *state, char *type, struct in6_addr *addr, char *string)
Simon Kelley4cb1b322012-02-06 14:30:41 +00002028{
Simon Kelleya6ebfac2013-03-06 20:52:35 +00002029 int clid_len = state->clid_len;
2030
Simon Kelley4cb1b322012-02-06 14:30:41 +00002031 /* avoid buffer overflow */
2032 if (clid_len > 100)
2033 clid_len = 100;
2034
Simon Kelleya6ebfac2013-03-06 20:52:35 +00002035 print_mac(daemon->namebuff, state->clid, clid_len);
Simon Kelley4cb1b322012-02-06 14:30:41 +00002036
2037 if (addr)
2038 {
Simon Kelleybf4e62c2016-07-22 21:37:59 +01002039 inet_ntop(AF_INET6, addr, daemon->dhcp_buff2, DHCP_BUFF_SZ - 1);
Simon Kelley4cb1b322012-02-06 14:30:41 +00002040 strcat(daemon->dhcp_buff2, " ");
2041 }
2042 else
2043 daemon->dhcp_buff2[0] = 0;
2044
2045 if(option_bool(OPT_LOG_OPTS))
Simon Kelley58dc02e2012-02-27 11:49:37 +00002046 my_syslog(MS_DHCP | LOG_INFO, "%u %s(%s) %s%s %s",
Simon Kelleya6ebfac2013-03-06 20:52:35 +00002047 state->xid,
Simon Kelley4cb1b322012-02-06 14:30:41 +00002048 type,
Simon Kelleya6ebfac2013-03-06 20:52:35 +00002049 state->iface_name,
Simon Kelley4cb1b322012-02-06 14:30:41 +00002050 daemon->dhcp_buff2,
Simon Kelley58dc02e2012-02-27 11:49:37 +00002051 daemon->namebuff,
Simon Kelley4cb1b322012-02-06 14:30:41 +00002052 string ? string : "");
2053 else
Simon Kelley58dc02e2012-02-27 11:49:37 +00002054 my_syslog(MS_DHCP | LOG_INFO, "%s(%s) %s%s %s",
Simon Kelley4cb1b322012-02-06 14:30:41 +00002055 type,
Simon Kelleya6ebfac2013-03-06 20:52:35 +00002056 state->iface_name,
Simon Kelley4cb1b322012-02-06 14:30:41 +00002057 daemon->dhcp_buff2,
Simon Kelley58dc02e2012-02-27 11:49:37 +00002058 daemon->namebuff,
Simon Kelley4cb1b322012-02-06 14:30:41 +00002059 string ? string : "");
2060}
2061
2062static void *opt6_find (void *opts, void *end, unsigned int search, unsigned int minsize)
Simon Kelleyc72daea2012-01-05 21:33:27 +00002063{
2064 u16 opt, opt_len;
2065 void *start;
2066
2067 if (!opts)
2068 return NULL;
2069
2070 while (1)
2071 {
2072 if (end - opts < 4)
2073 return NULL;
2074
2075 start = opts;
2076 GETSHORT(opt, opts);
2077 GETSHORT(opt_len, opts);
2078
2079 if (opt_len > (end - opts))
2080 return NULL;
2081
2082 if (opt == search && (opt_len >= minsize))
2083 return start;
2084
2085 opts += opt_len;
2086 }
2087}
2088
Simon Kelley4cb1b322012-02-06 14:30:41 +00002089static void *opt6_next(void *opts, void *end)
Simon Kelleyc72daea2012-01-05 21:33:27 +00002090{
2091 u16 opt_len;
2092
2093 if (end - opts < 4)
2094 return NULL;
2095
2096 opts += 2;
2097 GETSHORT(opt_len, opts);
2098
2099 if (opt_len >= (end - opts))
2100 return NULL;
2101
2102 return opts + opt_len;
2103}
Simon Kelleyc72daea2012-01-05 21:33:27 +00002104
2105static unsigned int opt6_uint(unsigned char *opt, int offset, int size)
2106{
2107 /* this worries about unaligned data and byte order */
2108 unsigned int ret = 0;
2109 int i;
2110 unsigned char *p = opt6_ptr(opt, offset);
2111
2112 for (i = 0; i < size; i++)
2113 ret = (ret << 8) | *p++;
2114
2115 return ret;
Simon Kelley4cb1b322012-02-06 14:30:41 +00002116}
Simon Kelleyc72daea2012-01-05 21:33:27 +00002117
Simon Kelley33702ab2015-12-28 23:17:15 +00002118void relay_upstream6(struct dhcp_relay *relay, ssize_t sz,
2119 struct in6_addr *peer_address, u32 scope_id, time_t now)
Simon Kelleyff7eea22013-09-04 18:01:38 +01002120{
2121 /* ->local is same value for all relays on ->current chain */
2122
2123 struct all_addr from;
2124 unsigned char *header;
2125 unsigned char *inbuff = daemon->dhcp_packet.iov_base;
2126 int msg_type = *inbuff;
2127 int hopcount;
2128 struct in6_addr multicast;
Simon Kelley8939c952013-09-25 11:49:34 +01002129 unsigned int maclen, mactype;
2130 unsigned char mac[DHCP_CHADDR_MAX];
Simon Kelleyff7eea22013-09-04 18:01:38 +01002131
2132 inet_pton(AF_INET6, ALL_SERVERS, &multicast);
Simon Kelley33702ab2015-12-28 23:17:15 +00002133 get_client_mac(peer_address, scope_id, mac, &maclen, &mactype, now);
Simon Kelley8939c952013-09-25 11:49:34 +01002134
Simon Kelleyff7eea22013-09-04 18:01:38 +01002135 /* source address == relay address */
2136 from.addr.addr6 = relay->local.addr.addr6;
2137
2138 /* Get hop count from nested relayed message */
2139 if (msg_type == DHCP6RELAYFORW)
2140 hopcount = *((unsigned char *)inbuff+1) + 1;
2141 else
2142 hopcount = 0;
2143
2144 /* RFC 3315 HOP_COUNT_LIMIT */
2145 if (hopcount > 32)
2146 return;
2147
Simon Kelleyfa785732016-07-22 20:56:01 +01002148 reset_counter();
Simon Kelleyff7eea22013-09-04 18:01:38 +01002149
2150 if ((header = put_opt6(NULL, 34)))
2151 {
2152 int o;
2153
2154 header[0] = DHCP6RELAYFORW;
2155 header[1] = hopcount;
2156 memcpy(&header[2], &relay->local.addr.addr6, IN6ADDRSZ);
2157 memcpy(&header[18], peer_address, IN6ADDRSZ);
Simon Kelley89500e32013-09-20 16:29:20 +01002158
2159 /* RFC-6939 */
Simon Kelley8939c952013-09-25 11:49:34 +01002160 if (maclen != 0)
Simon Kelley89500e32013-09-20 16:29:20 +01002161 {
2162 o = new_opt6(OPTION6_CLIENT_MAC);
Simon Kelley8939c952013-09-25 11:49:34 +01002163 put_opt6_short(mactype);
2164 put_opt6(mac, maclen);
Simon Kelley89500e32013-09-20 16:29:20 +01002165 end_opt6(o);
2166 }
Simon Kelleyff7eea22013-09-04 18:01:38 +01002167
2168 o = new_opt6(OPTION6_RELAY_MSG);
2169 put_opt6(inbuff, sz);
2170 end_opt6(o);
2171
2172 for (; relay; relay = relay->current)
2173 {
2174 union mysockaddr to;
2175
2176 to.sa.sa_family = AF_INET6;
2177 to.in6.sin6_addr = relay->server.addr.addr6;
2178 to.in6.sin6_port = htons(DHCPV6_SERVER_PORT);
2179 to.in6.sin6_flowinfo = 0;
2180 to.in6.sin6_scope_id = 0;
2181
2182 if (IN6_ARE_ADDR_EQUAL(&relay->server.addr.addr6, &multicast))
2183 {
2184 int multicast_iface;
2185 if (!relay->interface || strchr(relay->interface, '*') ||
2186 (multicast_iface = if_nametoindex(relay->interface)) == 0 ||
2187 setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &multicast_iface, sizeof(multicast_iface)) == -1)
2188 my_syslog(MS_DHCP | LOG_ERR, _("Cannot multicast to DHCPv6 server without correct interface"));
2189 }
2190
Simon Kelley6b1c4642016-07-22 20:59:16 +01002191 send_from(daemon->dhcp6fd, 0, daemon->outpacket.iov_base, save_counter(-1), &to, &from, 0);
Simon Kelleyff7eea22013-09-04 18:01:38 +01002192
2193 if (option_bool(OPT_LOG_OPTS))
2194 {
2195 inet_ntop(AF_INET6, &relay->local, daemon->addrbuff, ADDRSTRLEN);
2196 inet_ntop(AF_INET6, &relay->server, daemon->namebuff, ADDRSTRLEN);
2197 my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay %s -> %s"), daemon->addrbuff, daemon->namebuff);
2198 }
2199
2200 /* Save this for replies */
2201 relay->iface_index = scope_id;
2202 }
2203 }
2204}
2205
2206unsigned short relay_reply6(struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface)
2207{
2208 struct dhcp_relay *relay;
2209 struct in6_addr link;
2210 unsigned char *inbuff = daemon->dhcp_packet.iov_base;
2211
2212 /* must have at least msg_type+hopcount+link_address+peer_address+minimal size option
2213 which is 1 + 1 + 16 + 16 + 2 + 2 = 38 */
2214
2215 if (sz < 38 || *inbuff != DHCP6RELAYREPL)
2216 return 0;
2217
2218 memcpy(&link, &inbuff[2], IN6ADDRSZ);
2219
2220 for (relay = daemon->relay6; relay; relay = relay->next)
2221 if (IN6_ARE_ADDR_EQUAL(&link, &relay->local.addr.addr6) &&
2222 (!relay->interface || wildcard_match(relay->interface, arrival_interface)))
2223 break;
2224
Simon Kelleyfa785732016-07-22 20:56:01 +01002225 reset_counter();
Simon Kelleyff7eea22013-09-04 18:01:38 +01002226
2227 if (relay)
2228 {
2229 void *opt, *opts = inbuff + 34;
2230 void *end = inbuff + sz;
2231 for (opt = opts; opt; opt = opt6_next(opt, end))
2232 if (opt6_type(opt) == OPTION6_RELAY_MSG && opt6_len(opt) > 0)
2233 {
2234 int encap_type = *((unsigned char *)opt6_ptr(opt, 0));
2235 put_opt6(opt6_ptr(opt, 0), opt6_len(opt));
2236 memcpy(&peer->sin6_addr, &inbuff[18], IN6ADDRSZ);
2237 peer->sin6_scope_id = relay->iface_index;
2238 return encap_type == DHCP6RELAYREPL ? DHCPV6_SERVER_PORT : DHCPV6_CLIENT_PORT;
2239 }
2240 }
2241
2242 return 0;
2243}
2244
Simon Kelleyc72daea2012-01-05 21:33:27 +00002245#endif