• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/odhcpd/src/dhcpv6.c

  1 /**
  2  * Copyright (C) 2012-2013 Steven Barth <steven@midlink.org>
  3  * Copyright (C) 2018 Hans Dedecker <dedeckeh@gmail.com>
  4  *
  5  * This program is free software; you can redistribute it and/or modify
  6  * it under the terms of the GNU General Public License v2 as published by
  7  * the Free Software Foundation.
  8  *
  9  * This program is distributed in the hope that it will be useful,
 10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 12  * GNU General Public License for more details.
 13  *
 14  *
 15  */
 16 
 17 #include <errno.h>
 18 #include <unistd.h>
 19 #include <stddef.h>
 20 #include <resolv.h>
 21 #include <sys/timerfd.h>
 22 #include <arpa/inet.h>
 23 
 24 #include <libubox/utils.h>
 25 
 26 #include "odhcpd.h"
 27 #include "dhcpv6.h"
 28 #include "dhcpv6-pxe.h"
 29 #ifdef DHCPV4_SUPPORT
 30 #include "dhcpv4.h"
 31 #endif
 32 
 33 static void relay_client_request(struct sockaddr_in6 *source,
 34                 const void *data, size_t len, struct interface *iface);
 35 static void relay_server_response(uint8_t *data, size_t len);
 36 
 37 static void handle_dhcpv6(void *addr, void *data, size_t len,
 38                 struct interface *iface, void *dest);
 39 static void handle_client_request(void *addr, void *data, size_t len,
 40                 struct interface *iface, void *dest_addr);
 41 
 42 
 43 /* Create socket and register events */
 44 int dhcpv6_init(void)
 45 {
 46         return dhcpv6_ia_init();
 47 }
 48 
 49 int dhcpv6_setup_interface(struct interface *iface, bool enable)
 50 {
 51         int ret = 0;
 52 
 53         enable = enable && (iface->dhcpv6 != MODE_DISABLED);
 54 
 55         if (iface->dhcpv6_event.uloop.fd >= 0) {
 56                 uloop_fd_delete(&iface->dhcpv6_event.uloop);
 57                 close(iface->dhcpv6_event.uloop.fd);
 58                 iface->dhcpv6_event.uloop.fd = -1;
 59         }
 60 
 61         /* Configure multicast settings */
 62         if (enable) {
 63                 struct sockaddr_in6 bind_addr = {AF_INET6, htons(DHCPV6_SERVER_PORT),
 64                                         0, IN6ADDR_ANY_INIT, 0};
 65                 struct ipv6_mreq mreq;
 66                 int val = 1;
 67 
 68                 iface->dhcpv6_event.uloop.fd = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP);
 69                 if (iface->dhcpv6_event.uloop.fd < 0) {
 70                         error("socket(AF_INET6): %m");
 71                         ret = -1;
 72                         goto out;
 73                 }
 74 
 75                 /* Basic IPv6 configuration */
 76                 if (setsockopt(iface->dhcpv6_event.uloop.fd, SOL_SOCKET, SO_BINDTODEVICE,
 77                                         iface->ifname, strlen(iface->ifname)) < 0) {
 78                         error("setsockopt(SO_BINDTODEVICE): %m");
 79                         ret = -1;
 80                         goto out;
 81                 }
 82 
 83                 if (setsockopt(iface->dhcpv6_event.uloop.fd, IPPROTO_IPV6, IPV6_V6ONLY,
 84                                         &val, sizeof(val)) < 0) {
 85                         error("setsockopt(IPV6_V6ONLY): %m");
 86                         ret = -1;
 87                         goto out;
 88                 }
 89 
 90                 if (setsockopt(iface->dhcpv6_event.uloop.fd, SOL_SOCKET, SO_REUSEADDR,
 91                                         &val, sizeof(val)) < 0) {
 92                         error("setsockopt(SO_REUSEADDR): %m");
 93                         ret = -1;
 94                         goto out;
 95                 }
 96 
 97                 if (setsockopt(iface->dhcpv6_event.uloop.fd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
 98                                         &val, sizeof(val)) < 0) {
 99                         error("setsockopt(IPV6_RECVPKTINFO): %m");
100                         ret = -1;
101                         goto out;
102                 }
103 
104                 val = DHCPV6_HOP_COUNT_LIMIT;
105                 if (setsockopt(iface->dhcpv6_event.uloop.fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
106                                         &val, sizeof(val)) < 0) {
107                         error("setsockopt(IPV6_MULTICAST_HOPS): %m");
108                         ret = -1;
109                         goto out;
110                 }
111 
112                 val = 0;
113                 if (setsockopt(iface->dhcpv6_event.uloop.fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
114                                         &val, sizeof(val)) < 0) {
115                         error("setsockopt(IPV6_MULTICAST_LOOP): %m");
116                         ret = -1;
117                         goto out;
118                 }
119 
120                 if (bind(iface->dhcpv6_event.uloop.fd, (struct sockaddr*)&bind_addr,
121                                         sizeof(bind_addr)) < 0) {
122                         error("bind(): %m");
123                         ret = -1;
124                         goto out;
125                 }
126 
127                 memset(&mreq, 0, sizeof(mreq));
128                 inet_pton(AF_INET6, ALL_DHCPV6_RELAYS, &mreq.ipv6mr_multiaddr);
129                 mreq.ipv6mr_interface = iface->ifindex;
130 
131                 if (setsockopt(iface->dhcpv6_event.uloop.fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP,
132                                         &mreq, sizeof(mreq)) < 0) {
133                         error("setsockopt(IPV6_ADD_MEMBERSHIP): %m");
134                         ret = -1;
135                         goto out;
136                 }
137 
138                 if (iface->dhcpv6 == MODE_SERVER) {
139                         memset(&mreq, 0, sizeof(mreq));
140                         inet_pton(AF_INET6, ALL_DHCPV6_SERVERS, &mreq.ipv6mr_multiaddr);
141                         mreq.ipv6mr_interface = iface->ifindex;
142 
143                         if (setsockopt(iface->dhcpv6_event.uloop.fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP,
144                                                 &mreq, sizeof(mreq)) < 0) {
145                                 error("setsockopt(IPV6_ADD_MEMBERSHIP): %m");
146                                 ret = -1;
147                                 goto out;
148                         }
149                 }
150 
151                 iface->dhcpv6_event.handle_dgram = handle_dhcpv6;
152                 odhcpd_register(&iface->dhcpv6_event);
153         }
154 
155         ret = dhcpv6_ia_setup_interface(iface, enable);
156 
157 out:
158         if (ret < 0 && iface->dhcpv6_event.uloop.fd >= 0) {
159                 close(iface->dhcpv6_event.uloop.fd);
160                 iface->dhcpv6_event.uloop.fd = -1;
161         }
162 
163         return ret;
164 }
165 
166 enum {
167         IOV_NESTED = 0,
168         IOV_DEST,
169         IOV_CLIENTID,
170         IOV_MAXRT,
171 #define IOV_STAT IOV_MAXRT
172         IOV_RAPID_COMMIT,
173         IOV_DNS,
174         IOV_DNS_ADDR,
175         IOV_SEARCH,
176         IOV_SEARCH_DOMAIN,
177         IOV_PDBUF,
178 #define IOV_REFRESH IOV_PDBUF
179         IOV_CERID,
180         IOV_DHCPV6_RAW,
181         IOV_NTP,
182         IOV_NTP_ADDR,
183         IOV_SNTP,
184         IOV_SNTP_ADDR,
185         IOV_RELAY_MSG,
186         IOV_DHCPV4O6_SERVER,
187         IOV_DNR,
188         IOV_BOOTFILE_URL,
189         IOV_POSIX_TZ,
190         IOV_POSIX_TZ_STR,
191         IOV_TZDB_TZ,
192         IOV_TZDB_TZ_STR,
193         IOV_TOTAL
194 };
195 
196 static void handle_nested_message(uint8_t *data, size_t len,
197                                   struct dhcpv6_client_header **c_hdr, uint8_t **opts,
198                                   uint8_t **end, struct iovec iov[IOV_TOTAL])
199 {
200         struct dhcpv6_relay_header *r_hdr = (struct dhcpv6_relay_header *)data;
201         uint16_t otype, olen;
202         uint8_t *odata;
203 
204         if (iov[IOV_NESTED].iov_base == NULL) {
205                 iov[IOV_NESTED].iov_base = data;
206                 iov[IOV_NESTED].iov_len = len;
207         }
208 
209         if (len < sizeof(struct dhcpv6_client_header))
210                 return;
211 
212         if (r_hdr->msg_type != DHCPV6_MSG_RELAY_FORW) {
213                 iov[IOV_NESTED].iov_len = data - (uint8_t *)iov[IOV_NESTED].iov_base;
214                 *c_hdr = (void *)data;
215                 *opts = (uint8_t *)&(*c_hdr)[1];
216                 *end = data + len;
217                 return;
218         }
219 
220         dhcpv6_for_each_option(r_hdr->options, data + len, otype, olen, odata) {
221                 if (otype == DHCPV6_OPT_RELAY_MSG) {
222                         iov[IOV_RELAY_MSG].iov_base = odata + olen;
223                         iov[IOV_RELAY_MSG].iov_len = (((uint8_t *)iov[IOV_NESTED].iov_base) +
224                                         iov[IOV_NESTED].iov_len) - (odata + olen);
225                         handle_nested_message(odata, olen, c_hdr, opts, end, iov);
226                         return;
227                 }
228         }
229 }
230 
231 
232 static void update_nested_message(uint8_t *data, size_t len, ssize_t pdiff)
233 {
234         struct dhcpv6_relay_header *hdr = (struct dhcpv6_relay_header*)data;
235         if (hdr->msg_type != DHCPV6_MSG_RELAY_FORW)
236                 return;
237 
238         hdr->msg_type = DHCPV6_MSG_RELAY_REPL;
239 
240         uint16_t otype, olen;
241         uint8_t *odata;
242         dhcpv6_for_each_option(hdr->options, data + len, otype, olen, odata) {
243                 if (otype == DHCPV6_OPT_RELAY_MSG) {
244                         olen += pdiff;
245                         odata[-2] = (olen >> 8) & 0xff;
246                         odata[-1] = olen & 0xff;
247                         update_nested_message(odata, olen - pdiff, pdiff);
248                         return;
249                 }
250         }
251 }
252 
253 #ifdef DHCPV4_SUPPORT
254 
255 struct dhcpv4_msg_data {
256         uint8_t *msg;
257         size_t maxsize;
258         ssize_t len;
259 };
260 
261 static ssize_t dhcpv6_4o6_send_reply(struct iovec *iov, size_t iov_len,
262                                      _unused struct sockaddr *dest,
263                                      _unused socklen_t dest_len,
264                                      void *opaque)
265 {
266         struct dhcpv4_msg_data *reply = opaque;
267         size_t len = 0;
268 
269         for (size_t i = 0; i < iov_len; i++)
270                 len += iov[i].iov_len;
271 
272         if (len > reply->maxsize) {
273                 error("4o6: reply too large, %zu > %zu", len, reply->maxsize);
274                 reply->len = -1;
275                 return -1;
276         }
277 
278         for (size_t i = 0, off = 0; i < iov_len; i++) {
279                 memcpy(reply->msg + off, iov[i].iov_base, iov[i].iov_len);
280                 off += iov[i].iov_len;
281         }
282         reply->len = len;
283 
284         return len;
285 }
286 
287 static ssize_t dhcpv6_4o6_query(uint8_t *buf, size_t buflen,
288                                 struct interface *iface,
289                                 const struct sockaddr_in6 *addr,
290                                 const void *data, const uint8_t *end)
291 {
292         const struct dhcpv6_client_header *hdr = data;
293         uint16_t otype, olen, msgv4_len = 0;
294         uint8_t *msgv4_data = NULL;
295         uint8_t *start = (uint8_t *)&hdr[1], *odata;
296         struct sockaddr_in addrv4;
297         struct dhcpv4_msg_data reply = { .msg = buf, .maxsize = buflen, .len = -1 };
298 
299         dhcpv6_for_each_option(start, end, otype, olen, odata) {
300                 if (otype == DHCPV6_OPT_DHCPV4_MSG) {
301                         msgv4_data = odata;
302                         msgv4_len = olen;
303                 }
304         }
305 
306         if (!msgv4_data || msgv4_len == 0) {
307                 error("4o6: missing DHCPv4 message option (%d)", DHCPV6_OPT_DHCPV4_MSG);
308                 return -1;
309         }
310 
311         // Dummy IPv4 address
312         memset(&addrv4, 0, sizeof(addrv4));
313         addrv4.sin_family = AF_INET;
314         addrv4.sin_addr.s_addr = INADDR_ANY;
315         addrv4.sin_port = htons(DHCPV4_CLIENT_PORT);
316 
317         dhcpv4_handle_msg(&addrv4, msgv4_data, msgv4_len,
318                           iface, NULL, dhcpv6_4o6_send_reply, &reply);
319 
320         return reply.len;
321 }
322 #endif  /* DHCPV4_SUPPORT */
323 
324 /* Simple DHCPv6-server for information requests */
325 static void handle_client_request(void *addr, void *data, size_t len,
326                 struct interface *iface, void *dest_addr)
327 {
328         struct dhcpv6_client_header *hdr = data;
329         uint8_t *opts = (uint8_t *)&hdr[1], *opts_end = (uint8_t *)data + len;
330         bool o_rapid_commit = false;
331 
332         if (len < sizeof(*hdr))
333                 return;
334 
335         switch (hdr->msg_type) {
336         /* Valid message types for clients */
337         case DHCPV6_MSG_SOLICIT:
338         case DHCPV6_MSG_REQUEST:
339         case DHCPV6_MSG_CONFIRM:
340         case DHCPV6_MSG_RENEW:
341         case DHCPV6_MSG_REBIND:
342         case DHCPV6_MSG_RELEASE:
343         case DHCPV6_MSG_DECLINE:
344         case DHCPV6_MSG_INFORMATION_REQUEST:
345         case DHCPV6_MSG_RELAY_FORW:
346 #ifdef DHCPV4_SUPPORT
347         /* if we include DHCPV4 support, handle this message type */
348         case DHCPV6_MSG_DHCPV4_QUERY:
349 #endif
350                 break;
351         /* Invalid message types for clients i.e. server messages */
352         case DHCPV6_MSG_ADVERTISE:
353         case DHCPV6_MSG_REPLY:
354         case DHCPV6_MSG_RECONFIGURE:
355         case DHCPV6_MSG_RELAY_REPL:
356 #ifndef DHCPV4_SUPPORT
357         /* if we omit DHCPV4 support, ignore this client message type */
358         case DHCPV6_MSG_DHCPV4_QUERY:
359 #endif
360         case DHCPV6_MSG_DHCPV4_RESPONSE:
361         default:
362                 return;
363         }
364 
365         debug("Got a DHCPv6-request on %s", iface->name);
366 
367         /* Construct reply message */
368         struct _packed {
369                 uint8_t msg_type;
370                 uint8_t tr_id[3];
371                 uint16_t serverid_type;
372                 uint16_t serverid_length;
373                 uint8_t serverid_buf[DUID_MAX_LEN];
374         } dest = {
375                 .msg_type = DHCPV6_MSG_REPLY,
376                 .serverid_type = htons(DHCPV6_OPT_SERVERID),
377                 .serverid_length = 0,
378                 .serverid_buf = { 0 },
379         };
380 
381         if (config.default_duid_len > 0) {
382                 memcpy(dest.serverid_buf, config.default_duid, config.default_duid_len);
383                 dest.serverid_length = htons(config.default_duid_len);
384         } else {
385                 uint16_t duid_ll_hdr[] = { htons(DUID_TYPE_LL), htons(ARPHRD_ETHER) };
386                 memcpy(dest.serverid_buf, duid_ll_hdr, sizeof(duid_ll_hdr));
387                 odhcpd_get_mac(iface, &dest.serverid_buf[sizeof(duid_ll_hdr)]);
388                 dest.serverid_length = htons(sizeof(duid_ll_hdr) + ETH_ALEN);
389         }
390 
391         struct _packed {
392                 uint16_t type;
393                 uint16_t len;
394                 uint8_t buf[DUID_MAX_LEN];
395         } clientid = {
396                 .type = htons(DHCPV6_OPT_CLIENTID),
397                 .len = 0,
398                 .buf = { 0 },
399         };
400 
401         struct __attribute__((packed)) {
402                 uint16_t type;
403                 uint16_t len;
404                 uint32_t value;
405         } maxrt = {htons(DHCPV6_OPT_SOL_MAX_RT), htons(sizeof(maxrt) - 4),
406                         htonl(60)};
407 
408         struct __attribute__((packed)) {
409                 uint16_t type;
410                 uint16_t len;
411         } rapid_commit = {htons(DHCPV6_OPT_RAPID_COMMIT), 0};
412 
413         struct __attribute__((packed)) {
414                 uint16_t type;
415                 uint16_t len;
416                 uint16_t value;
417         } stat = {htons(DHCPV6_OPT_STATUS), htons(sizeof(stat) - 4),
418                         htons(DHCPV6_STATUS_USEMULTICAST)};
419 
420         struct __attribute__((packed)) {
421                 uint16_t type;
422                 uint16_t len;
423                 uint32_t value;
424         } refresh = {htons(DHCPV6_OPT_INFO_REFRESH), htons(sizeof(uint32_t)),
425                         htonl(600)};
426 
427         struct in6_addr dns_addr, *dns_addr_ptr = iface->dns;
428         size_t dns_cnt = iface->dns_cnt;
429 
430         if ((dns_cnt == 0) &&
431                 !odhcpd_get_interface_dns_addr(iface, &dns_addr)) {
432                 dns_addr_ptr = &dns_addr;
433                 dns_cnt = 1;
434         }
435 
436         struct {
437                 uint16_t type;
438                 uint16_t len;
439         } dns = {htons(DHCPV6_OPT_DNS_SERVERS), htons(dns_cnt * sizeof(*dns_addr_ptr))};
440 
441         /* SNTP */
442         struct in6_addr *sntp_addr_ptr = iface->dhcpv6_sntp;
443         size_t sntp_cnt = 0;
444         struct {
445                 uint16_t type;
446                 uint16_t len;
447         } dhcpv6_sntp;
448 
449         /* RFC 4833 - Timezones */
450         bool posix_want = false;
451         uint8_t *posix_ptr = sys_conf.posix_tz;
452         uint16_t posix_len = sys_conf.posix_tz_len;
453         /* RFC 4833 - OPTION_NEW_POSIX_TIMEZONE (41)
454          * e.g. EST5EDT4,M3.2.0/02:00,M11.1.0/02:00
455          * Variable-length opaque tz_string blob.
456          */
457         struct {
458                 uint16_t type;
459                 uint16_t len;
460         } posix_tz;
461 
462         bool tzdb_want = false;
463         uint8_t *tzdb_ptr = sys_conf.tzdb_tz;
464         uint16_t tzdb_len = sys_conf.tzdb_tz_len;
465         /* RFC 4833 - OPTION_NEW_TZDB_TIMEZONE (42)
466          * e.g. Europe/Zurich
467          * Variable-length opaque tz_name blob.
468          */
469         struct {
470                 uint16_t type;
471                 uint16_t len;
472         } tzdb_tz;
473 
474         /* NTP */
475         uint8_t *ntp_ptr = iface->dhcpv6_ntp;
476         uint16_t ntp_len = iface->dhcpv6_ntp_len;
477         size_t ntp_cnt = 0;
478         struct {
479                 uint16_t type;
480                 uint16_t len;
481         } ntp;
482 
483         /* DNR */
484         struct dhcpv6_dnr {
485                 uint16_t type;
486                 uint16_t len;
487                 uint16_t priority;
488                 uint16_t adn_len;
489                 uint8_t body[];
490         };
491         struct dhcpv6_dnr *dnrs = NULL;
492         size_t dnrs_len = 0;
493 
494         uint16_t otype, olen;
495         uint8_t *odata;
496         uint16_t *reqopts = NULL;
497         size_t reqopts_cnt = 0;
498 
499         /* FIXME: this should be merged with the second loop further down */
500         dhcpv6_for_each_option(opts, opts_end, otype, olen, odata) {
501                 /* Requested options, array of uint16_t, RFC 8415 ยง21.7 */
502                 if (otype == DHCPV6_OPT_ORO) {
503                         reqopts_cnt = olen / sizeof(uint16_t);
504                         reqopts = (uint16_t *)odata;
505                         break;
506                 }
507         }
508 
509         /* Requested options */
510         for (size_t i = 0; i < reqopts_cnt; i++) {
511                 uint16_t opt = ntohs(reqopts[i]);
512 
513                 switch (opt) {
514                 case DHCPV6_OPT_SNTP_SERVERS:
515                         sntp_cnt = iface->dhcpv6_sntp_cnt;
516                         dhcpv6_sntp.type = htons(DHCPV6_OPT_SNTP_SERVERS);
517                         dhcpv6_sntp.len = htons(sntp_cnt * sizeof(*sntp_addr_ptr));
518                         break;
519 
520                 case DHCPV6_OPT_NTP_SERVERS:
521                         ntp_cnt = iface->dhcpv6_ntp_cnt;
522                         ntp.type = htons(DHCPV6_OPT_NTP_SERVERS);
523                         ntp.len = htons(ntp_len);
524                         break;
525 
526                 case DHCPV6_OPT_NEW_POSIX_TIMEZONE:
527                         posix_want = true;
528                         posix_tz.type = htons(DHCPV6_OPT_NEW_POSIX_TIMEZONE);
529                         posix_tz.len  = htons(posix_len);
530                         break;
531 
532                 case DHCPV6_OPT_NEW_TZDB_TIMEZONE:
533                         tzdb_want = true;
534                         tzdb_tz.type = htons(DHCPV6_OPT_NEW_TZDB_TIMEZONE);
535                         tzdb_tz.len  = htons(tzdb_len);
536                         break;
537 
538                 case DHCPV6_OPT_DNR:
539                         for (size_t i = 0; i < iface->dnr_cnt; i++) {
540                                 struct dnr_options *dnr = &iface->dnr[i];
541 
542                                 if (dnr->addr6_cnt == 0 && dnr->addr4_cnt > 0)
543                                         continue;
544 
545                                 dnrs_len += sizeof(struct dhcpv6_dnr);
546                                 dnrs_len += dnr->adn_len;
547 
548                                 if (dnr->addr6_cnt > 0 || dnr->svc_len > 0) {
549                                         dnrs_len += sizeof(uint16_t);
550                                         dnrs_len += dnr->addr6_cnt * sizeof(*dnr->addr6);
551                                         dnrs_len += dnr->svc_len;
552                                 }
553                         }
554 
555                         dnrs = alloca(dnrs_len);
556                         uint8_t *pos = (uint8_t *)dnrs;
557 
558                         for (size_t i = 0; i < iface->dnr_cnt; i++) {
559                                 struct dnr_options *dnr = &iface->dnr[i];
560                                 struct dhcpv6_dnr *d6dnr = (struct dhcpv6_dnr *)pos;
561                                 uint16_t d6dnr_type_be = htons(DHCPV6_OPT_DNR);
562                                 uint16_t d6dnr_len = 2 * sizeof(uint16_t) + dnr->adn_len;
563                                 uint16_t d6dnr_len_be;
564                                 uint16_t d6dnr_priority_be = htons(dnr->priority);
565                                 uint16_t d6dnr_adn_len_be = htons(dnr->adn_len);
566 
567                                 if (dnr->addr6_cnt == 0 && dnr->addr4_cnt > 0)
568                                         continue;
569 
570                                 /* memcpy as the struct is unaligned */
571                                 memcpy(&d6dnr->type, &d6dnr_type_be, sizeof(d6dnr_type_be));
572                                 memcpy(&d6dnr->priority, &d6dnr_priority_be, sizeof(d6dnr_priority_be));
573                                 memcpy(&d6dnr->adn_len, &d6dnr_adn_len_be, sizeof(d6dnr_adn_len_be));
574 
575                                 pos = d6dnr->body;
576                                 memcpy(pos, dnr->adn, dnr->adn_len);
577                                 pos += dnr->adn_len;
578 
579                                 if (dnr->addr6_cnt > 0 || dnr->svc_len > 0) {
580                                         uint16_t addr6_len = dnr->addr6_cnt * sizeof(*dnr->addr6);
581                                         uint16_t addr6_len_be = htons(addr6_len);
582 
583                                         memcpy(pos, &addr6_len_be, sizeof(addr6_len_be));
584                                         pos += sizeof(addr6_len_be);
585                                         memcpy(pos, dnr->addr6, addr6_len);
586                                         pos += addr6_len;
587                                         memcpy(pos, dnr->svc, dnr->svc_len);
588                                         pos += dnr->svc_len;
589 
590                                         d6dnr_len += sizeof(addr6_len_be) + addr6_len + dnr->svc_len;
591                                 }
592 
593                                 d6dnr_len_be = htons(d6dnr_len);
594                                 memcpy(&d6dnr->len, &d6dnr_len_be, sizeof(d6dnr_len_be));
595                         }
596                         break;
597                 }
598         }
599 
600         /* DNS Search options */
601         uint8_t search_buf[256], *search_domain = iface->search;
602         size_t search_len = iface->search_len;
603 
604         if (!search_domain && !res_init() && _res.dnsrch[0] && _res.dnsrch[0][0]) {
605                 int len = dn_comp(_res.dnsrch[0], search_buf,
606                                 sizeof(search_buf), NULL, NULL);
607                 if (len > 0) {
608                         search_domain = search_buf;
609                         search_len = len;
610                 }
611         }
612 
613         struct {
614                 uint16_t type;
615                 uint16_t len;
616         } search = {htons(DHCPV6_OPT_DNS_DOMAIN), htons(search_len)};
617 
618 
619         struct __attribute__((packed)) dhcpv4o6_server {
620                 uint16_t type;
621                 uint16_t len;
622                 struct in6_addr addr;
623         } dhcpv4o6_server = {htons(DHCPV6_OPT_4O6_SERVER), htons(sizeof(struct in6_addr)),
624                         IN6ADDR_ANY_INIT};
625 
626         struct dhcpv6_cer_id cerid = {
627 #ifdef EXT_CER_ID
628                 .type = htons(EXT_CER_ID),
629 #endif
630                 .len = htons(36),
631                 .addr = iface->dhcpv6_pd_cer,
632         };
633 
634 
635         uint8_t pdbuf[512];
636         struct iovec iov[IOV_TOTAL] = {
637                 [IOV_NESTED] = {NULL, 0},
638                 [IOV_DEST] = {&dest, offsetof(typeof(dest), serverid_buf) + ntohs(dest.serverid_length) },
639                 [IOV_CLIENTID] = {&clientid, 0},
640                 [IOV_MAXRT] = {&maxrt, sizeof(maxrt)},
641                 [IOV_RAPID_COMMIT] = {&rapid_commit, 0},
642                 [IOV_DNS] = {&dns, (dns_cnt) ? sizeof(dns) : 0},
643                 [IOV_DNS_ADDR] = {dns_addr_ptr, dns_cnt * sizeof(*dns_addr_ptr)},
644                 [IOV_SEARCH] = {&search, (search_len) ? sizeof(search) : 0},
645                 [IOV_SEARCH_DOMAIN] = {search_domain, search_len},
646                 [IOV_PDBUF] = {pdbuf, 0},
647                 [IOV_CERID] = {&cerid, 0},
648                 [IOV_DHCPV6_RAW] = {iface->dhcpv6_raw, iface->dhcpv6_raw_len},
649                 [IOV_NTP] = {&ntp, (ntp_cnt) ? sizeof(ntp) : 0},
650                 [IOV_NTP_ADDR] = {ntp_ptr, (ntp_cnt) ? ntp_len : 0},
651                 [IOV_SNTP] = {&dhcpv6_sntp, (sntp_cnt) ? sizeof(dhcpv6_sntp) : 0},
652                 [IOV_SNTP_ADDR] = {sntp_addr_ptr, sntp_cnt * sizeof(*sntp_addr_ptr)},
653                 [IOV_POSIX_TZ] = {&posix_tz, (posix_want) ? sizeof(posix_tz) : 0},
654                 [IOV_POSIX_TZ_STR] = {posix_ptr, (posix_want) ? posix_len : 0 },
655                 [IOV_TZDB_TZ] = {&tzdb_tz, (tzdb_want) ? sizeof(tzdb_tz) : 0},
656                 [IOV_TZDB_TZ_STR] = {tzdb_ptr, (tzdb_want) ? tzdb_len : 0 },
657                 [IOV_DNR] = {dnrs, dnrs_len},
658                 [IOV_RELAY_MSG] = {NULL, 0},
659                 [IOV_DHCPV4O6_SERVER] = {&dhcpv4o6_server, 0},
660                 [IOV_BOOTFILE_URL] = {NULL, 0}
661         };
662 
663         if (hdr->msg_type == DHCPV6_MSG_RELAY_FORW)
664                 handle_nested_message(data, len, &hdr, &opts, &opts_end, iov);
665 
666         if (!IN6_IS_ADDR_MULTICAST((struct in6_addr *)dest_addr) && iov[IOV_NESTED].iov_len == 0 &&
667             (hdr->msg_type == DHCPV6_MSG_SOLICIT || hdr->msg_type == DHCPV6_MSG_CONFIRM ||
668              hdr->msg_type == DHCPV6_MSG_REBIND || hdr->msg_type == DHCPV6_MSG_INFORMATION_REQUEST))
669                 return;
670 
671         memcpy(dest.tr_id, hdr->transaction_id, sizeof(dest.tr_id));
672 
673         /* Go through options and find what we need */
674         dhcpv6_for_each_option(opts, opts_end, otype, olen, odata) {
675                 if (otype == DHCPV6_OPT_CLIENTID && olen <= DUID_MAX_LEN) {
676                         clientid.len = htons(olen);
677                         memcpy(clientid.buf, odata, olen);
678                         iov[IOV_CLIENTID].iov_len = offsetof(typeof(clientid), buf) + olen;
679                 } else if (otype == DHCPV6_OPT_SERVERID) {
680                         if (olen != ntohs(dest.serverid_length) ||
681                             memcmp(odata, &dest.serverid_buf, olen))
682                                 return; /* Not for us */
683                 } else if (iface->filter_class && otype == DHCPV6_OPT_USER_CLASS) {
684                         uint8_t *c = odata, *cend = &odata[olen];
685                         for (; &c[2] <= cend && &c[2 + (c[0] << 8) + c[1]] <= cend; c = &c[2 + (c[0] << 8) + c[1]]) {
686                                 size_t elen = strlen(iface->filter_class);
687                                 if (((((size_t)c[0]) << 8) | c[1]) == elen && !memcmp(&c[2], iface->filter_class, elen))
688                                         return; /* Ignore from homenet */
689                         }
690                 } else if (otype == DHCPV6_OPT_IA_PD) {
691 #ifdef EXT_CER_ID
692                         iov[IOV_CERID].iov_len = sizeof(cerid);
693 
694                         if (IN6_IS_ADDR_UNSPECIFIED(&cerid.addr)) {
695                                 struct odhcpd_ipaddr *addrs;
696                                 ssize_t len = netlink_get_interface_addrs(0, true, &addrs);
697 
698                                 for (ssize_t i = 0; i < len; ++i)
699                                         if (IN6_IS_ADDR_UNSPECIFIED(&cerid.addr)
700                                                         || memcmp(&addrs[i].addr, &cerid.addr, sizeof(cerid.addr)) < 0)
701                                                 cerid.addr = addrs[i].addr.in6;
702 
703                                 free(addrs);
704                         }
705 #endif
706                 } else if (otype == DHCPV6_OPT_RAPID_COMMIT && hdr->msg_type == DHCPV6_MSG_SOLICIT) {
707                         iov[IOV_RAPID_COMMIT].iov_len = sizeof(rapid_commit);
708                         o_rapid_commit = true;
709                 } else if (otype == DHCPV6_OPT_ORO) {
710                         for (int i=0; i < olen/2; i++) {
711                                 uint16_t option = ntohs(((uint16_t *)odata)[i]);
712 
713                                 switch (option) {
714 #ifdef DHCPV4_SUPPORT
715                                 case DHCPV6_OPT_4O6_SERVER:
716                                         if (iface->dhcpv4) {
717                                                 /* According to RFC 7341, 7.2. DHCP 4o6 Server Address Option Format:
718                                                  * This option may also carry no IPv6 addresses, which instructs the
719                                                  * client to use the All_DHCP_Relay_Agents_and_Servers multicast address
720                                                  * as the destination address.
721                                                  *
722                                                  * The ISC dhclient logs a missing IPv6 address as an error but seems to
723                                                  * work anyway:
724                                                  * dhcp4-o-dhcp6-server: expecting at least 16 bytes; got 0
725                                                  *
726                                                  * Include the All_DHCP_Relay_Agents_and_Servers multicast address
727                                                  * to make it explicit which address to use. */
728                                                 struct dhcpv4o6_server *server = iov[IOV_DHCPV4O6_SERVER].iov_base;
729 
730                                                 inet_pton(AF_INET6, ALL_DHCPV6_RELAYS, &server->addr);
731 
732                                                 iov[IOV_DHCPV4O6_SERVER].iov_len = sizeof(dhcpv4o6_server);
733                                         }
734                                         break;
735 #endif /* DHCPV4_SUPPORT */
736                                 default:
737                                         break;
738                                 }
739                         }
740                 } else if (otype == DHCPV6_OPT_CLIENT_ARCH) {
741                         uint16_t arch_code = ntohs(((uint16_t*)odata)[0]);
742                         ipv6_pxe_serve_boot_url(arch_code, &iov[IOV_BOOTFILE_URL]);
743                 }
744         }
745 
746         if (!IN6_IS_ADDR_MULTICAST((struct in6_addr *)dest_addr) && iov[IOV_NESTED].iov_len == 0 &&
747             (hdr->msg_type == DHCPV6_MSG_REQUEST || hdr->msg_type == DHCPV6_MSG_RENEW ||
748              hdr->msg_type == DHCPV6_MSG_RELEASE || hdr->msg_type == DHCPV6_MSG_DECLINE)) {
749                 iov[IOV_STAT].iov_base = &stat;
750                 iov[IOV_STAT].iov_len = sizeof(stat);
751 
752                 for (ssize_t i = IOV_STAT + 1; i < IOV_TOTAL; ++i)
753                         iov[i].iov_len = 0;
754 
755                 odhcpd_send(iface->dhcpv6_event.uloop.fd, addr, iov, ARRAY_SIZE(iov), iface);
756                 return;
757         }
758 
759         if (hdr->msg_type == DHCPV6_MSG_SOLICIT && !o_rapid_commit) {
760                 dest.msg_type = DHCPV6_MSG_ADVERTISE;
761         } else if (hdr->msg_type == DHCPV6_MSG_INFORMATION_REQUEST) {
762                 iov[IOV_REFRESH].iov_base = &refresh;
763                 iov[IOV_REFRESH].iov_len = sizeof(refresh);
764 
765                 /* Return inf max rt option in reply to information request */
766                 maxrt.type = htons(DHCPV6_OPT_INF_MAX_RT);
767         }
768 
769 #ifdef DHCPV4_SUPPORT
770         if (hdr->msg_type == DHCPV6_MSG_DHCPV4_QUERY) {
771                 struct _packed dhcpv4_msg_data {
772                         uint16_t type;
773                         uint16_t len;
774                         uint8_t msg[1];
775                 } *msg_opt = (struct dhcpv4_msg_data*)pdbuf;
776                 ssize_t msglen;
777 
778                 memset(pdbuf, 0, sizeof(pdbuf));
779 
780                 msglen = dhcpv6_4o6_query(msg_opt->msg, sizeof(pdbuf) - sizeof(*msg_opt) + 1,
781                                                 iface, addr, (const void *)hdr, opts_end);
782                 if (msglen <= 0) {
783                         error("4o6: query failed");
784                         return;
785                 }
786 
787                 msg_opt->type = htons(DHCPV6_OPT_DHCPV4_MSG);
788                 msg_opt->len = htons(msglen);
789                 iov[IOV_PDBUF].iov_len = sizeof(*msg_opt) - 1 + msglen;
790                 dest.msg_type = DHCPV6_MSG_DHCPV4_RESPONSE;
791         } else
792 #endif  /* DHCPV4_SUPPORT */
793 
794         if (hdr->msg_type != DHCPV6_MSG_INFORMATION_REQUEST) {
795                 ssize_t ialen = dhcpv6_ia_handle_IAs(pdbuf, sizeof(pdbuf), iface, addr, (const void *)hdr, opts_end);
796 
797                 iov[IOV_PDBUF].iov_len = ialen;
798                 if (ialen < 0 ||
799                     (ialen == 0 && (hdr->msg_type == DHCPV6_MSG_REBIND || hdr->msg_type == DHCPV6_MSG_CONFIRM)))
800                         return;
801         }
802 
803         if (iov[IOV_NESTED].iov_len > 0) /* Update length */
804                 update_nested_message(data, len, iov[IOV_DEST].iov_len + iov[IOV_MAXRT].iov_len +
805                                       iov[IOV_RAPID_COMMIT].iov_len + iov[IOV_DNS].iov_len +
806                                       iov[IOV_DNS_ADDR].iov_len + iov[IOV_SEARCH].iov_len +
807                                       iov[IOV_SEARCH_DOMAIN].iov_len + iov[IOV_PDBUF].iov_len +
808                                       iov[IOV_DHCPV4O6_SERVER].iov_len +
809                                       iov[IOV_CERID].iov_len + iov[IOV_DHCPV6_RAW].iov_len +
810                                       iov[IOV_NTP].iov_len + iov[IOV_NTP_ADDR].iov_len +
811                                       iov[IOV_SNTP].iov_len + iov[IOV_SNTP_ADDR].iov_len +
812                                       iov[IOV_POSIX_TZ].iov_len + iov[IOV_POSIX_TZ_STR].iov_len + 
813                                       iov[IOV_TZDB_TZ].iov_len + iov[IOV_TZDB_TZ_STR].iov_len +
814                                       iov[IOV_DNR].iov_len + iov[IOV_BOOTFILE_URL].iov_len -
815                                       (4 + opts_end - opts));
816 
817         debug("Sending a DHCPv6-%s on %s", iov[IOV_NESTED].iov_len ? "relay-reply" : "reply", iface->name);
818 
819         odhcpd_send(iface->dhcpv6_event.uloop.fd, addr, iov, ARRAY_SIZE(iov), iface);
820 }
821 
822 
823 /* Central DHCPv6-relay handler */
824 static void handle_dhcpv6(void *addr, void *data, size_t len,
825                 struct interface *iface, void *dest_addr)
826 {
827         if (iface->dhcpv6 == MODE_SERVER) {
828                 handle_client_request(addr, data, len, iface, dest_addr);
829         } else if (iface->dhcpv6 == MODE_RELAY) {
830                 if (iface->master)
831                         relay_server_response(data, len);
832                 else
833                         relay_client_request(addr, data, len, iface);
834         }
835 }
836 
837 
838 /* Relay server response (regular relay server handling) */
839 static void relay_server_response(uint8_t *data, size_t len)
840 {
841         /* Information we need to gather */
842         uint8_t *payload_data = NULL;
843         size_t payload_len = 0;
844         int32_t ifaceidx = 0;
845         struct sockaddr_in6 target = {AF_INET6, htons(DHCPV6_CLIENT_PORT),
846                 0, IN6ADDR_ANY_INIT, 0};
847         int otype, olen;
848         uint8_t *odata, *end = data + len;
849         /* Relay DHCPv6 reply from server to client */
850         struct dhcpv6_relay_header *h = (void*)data;
851 
852         debug("Got a DHCPv6-relay-reply");
853 
854         if (len < sizeof(*h) || h->msg_type != DHCPV6_MSG_RELAY_REPL)
855                 return;
856 
857         memcpy(&target.sin6_addr, &h->peer_address, sizeof(struct in6_addr));
858 
859         /* Go through options and find what we need */
860         dhcpv6_for_each_option(h->options, end, otype, olen, odata) {
861                 if (otype == DHCPV6_OPT_INTERFACE_ID
862                                 && olen == sizeof(ifaceidx)) {
863                         memcpy(&ifaceidx, odata, sizeof(ifaceidx));
864                 } else if (otype == DHCPV6_OPT_RELAY_MSG) {
865                         payload_data = odata;
866                         payload_len = olen;
867                 }
868         }
869 
870         /* Invalid interface-id or basic payload */
871         struct interface *iface = odhcpd_get_interface_by_index(ifaceidx);
872         if (!iface || iface->master || !payload_data || payload_len < 4)
873                 return;
874 
875         bool is_authenticated = false;
876         struct in6_addr *dns_ptr = NULL;
877         size_t dns_count = 0;
878 
879         /* If the payload is relay-reply we have to send to the server port */
880         if (payload_data[0] == DHCPV6_MSG_RELAY_REPL) {
881                 target.sin6_port = htons(DHCPV6_SERVER_PORT);
882         } else { /* Go through the payload data */
883                 struct dhcpv6_client_header *h = (void*)payload_data;
884                 end = payload_data + payload_len;
885 
886                 dhcpv6_for_each_option(&h[1], end, otype, olen, odata) {
887                         if (otype == DHCPV6_OPT_DNS_SERVERS && olen >= 16) {
888                                 dns_ptr = (struct in6_addr*)odata;
889                                 dns_count = olen / 16;
890                         } else if (otype == DHCPV6_OPT_AUTH) {
891                                 is_authenticated = true;
892                         }
893                 }
894         }
895 
896         /* Rewrite DNS servers if requested */
897         if (iface->always_rewrite_dns && dns_ptr && dns_count > 0) {
898                 if (is_authenticated)
899                         return; /* Impossible to rewrite */
900 
901                 const struct in6_addr *rewrite = iface->dns;
902                 struct in6_addr addr;
903                 size_t rewrite_cnt = iface->dns_cnt;
904 
905                 if (rewrite_cnt == 0) {
906                         if (odhcpd_get_interface_dns_addr(iface, &addr))
907                                 return; /* Unable to get interface address */
908 
909                         rewrite = &addr;
910                         rewrite_cnt = 1;
911                 }
912 
913                 /* Copy over any other addresses */
914                 for (size_t i = 0; i < dns_count; ++i) {
915                         size_t j = (i < rewrite_cnt) ? i : rewrite_cnt - 1;
916                         memcpy(&dns_ptr[i], &rewrite[j], sizeof(*rewrite));
917                 }
918         }
919 
920         struct iovec iov = {payload_data, payload_len};
921 
922         debug("Sending a DHCPv6-reply on %s", iface->name);
923 
924         odhcpd_send(iface->dhcpv6_event.uloop.fd, &target, &iov, 1, iface);
925 }
926 
927 static struct odhcpd_ipaddr *relay_link_address(struct interface *iface)
928 {
929         struct odhcpd_ipaddr *addr = NULL;
930         time_t now = odhcpd_time();
931 
932         for (size_t i = 0; i < iface->addr6_len; i++) {
933                 if (iface->addr6[i].valid_lt <= (uint32_t)now)
934                         continue;
935 
936                 if (iface->addr6[i].preferred_lt > (uint32_t)now) {
937                         addr = &iface->addr6[i];
938                         break;
939                 }
940 
941                 if (!addr || (iface->addr6[i].valid_lt > addr->valid_lt))
942                         addr = &iface->addr6[i];
943         }
944 
945         return addr;
946 }
947 
948 /* Relay client request (regular DHCPv6-relay) */
949 static void relay_client_request(struct sockaddr_in6 *source,
950                 const void *data, size_t len, struct interface *iface)
951 {
952         const struct dhcpv6_relay_header *h = data;
953         /* Construct our forwarding envelope */
954         struct dhcpv6_relay_forward_envelope hdr = {
955                 .msg_type = DHCPV6_MSG_RELAY_FORW,
956                 .hop_count = 0,
957                 .interface_id_type = htons(DHCPV6_OPT_INTERFACE_ID),
958                 .interface_id_len = htons(sizeof(uint32_t)),
959                 .relay_message_type = htons(DHCPV6_OPT_RELAY_MSG),
960                 .relay_message_len = htons(len),
961         };
962         struct iovec iov[2] = {{&hdr, sizeof(hdr)}, {(void *)data, len}};
963         struct interface *c;
964         struct odhcpd_ipaddr *ip;
965         struct sockaddr_in6 s;
966 
967         switch (h->msg_type) {
968         /* Valid message types from clients */
969         case DHCPV6_MSG_SOLICIT:
970         case DHCPV6_MSG_REQUEST:
971         case DHCPV6_MSG_CONFIRM:
972         case DHCPV6_MSG_RENEW:
973         case DHCPV6_MSG_REBIND:
974         case DHCPV6_MSG_RELEASE:
975         case DHCPV6_MSG_DECLINE:
976         case DHCPV6_MSG_INFORMATION_REQUEST:
977         case DHCPV6_MSG_RELAY_FORW:
978         case DHCPV6_MSG_DHCPV4_QUERY:
979                 break;
980         /* Invalid message types from clients i.e. server messages */
981         case DHCPV6_MSG_ADVERTISE:
982         case DHCPV6_MSG_REPLY:
983         case DHCPV6_MSG_RECONFIGURE:
984         case DHCPV6_MSG_RELAY_REPL:
985         case DHCPV6_MSG_DHCPV4_RESPONSE:
986                 return;
987         default:
988                 break;
989         }
990 
991         debug("Got a DHCPv6-request on %s", iface->name);
992 
993         if (h->msg_type == DHCPV6_MSG_RELAY_FORW) { /* handle relay-forward */
994                 if (h->hop_count >= DHCPV6_HOP_COUNT_LIMIT)
995                         return; /* Invalid hop count */
996 
997                 hdr.hop_count = h->hop_count + 1;
998         }
999 
1000         /* use memcpy here as the destination fields are unaligned */
1001         memcpy(&hdr.peer_address, &source->sin6_addr, sizeof(struct in6_addr));
1002         memcpy(&hdr.interface_id_data, &iface->ifindex, sizeof(iface->ifindex));
1003 
1004         /* Detect public IP of slave interface to use as link-address */
1005         ip = relay_link_address(iface);
1006         if (ip)
1007                 memcpy(&hdr.link_address, &ip->addr.in6, sizeof(hdr.link_address));
1008 
1009         memset(&s, 0, sizeof(s));
1010         s.sin6_family = AF_INET6;
1011         s.sin6_port = htons(DHCPV6_SERVER_PORT);
1012         inet_pton(AF_INET6, ALL_DHCPV6_SERVERS, &s.sin6_addr);
1013 
1014         avl_for_each_element(&interfaces, c, avl) {
1015                 if (!c->master || c->dhcpv6 != MODE_RELAY)
1016                         continue;
1017 
1018                 if (!ip) {
1019                         /* No suitable address! Is the slave not configured yet?
1020                          * Detect public IP of master interface and use it instead
1021                          * This is WRONG and probably violates the RFC. However
1022                          * otherwise we have a hen and egg problem because the
1023                          * slave-interface cannot be auto-configured. */
1024                         ip = relay_link_address(c);
1025                         if (!ip)
1026                                 continue; /* Could not obtain a suitable address */
1027 
1028                         memcpy(&hdr.link_address, &ip->addr.in6, sizeof(hdr.link_address));
1029                         ip = NULL;
1030                 }
1031 
1032                 debug("Sending a DHCPv6-relay-forward on %s", c->name);
1033 
1034                 odhcpd_send(c->dhcpv6_event.uloop.fd, &s, iov, 2, c);
1035         }
1036 }
1037 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt