Path: blob/a-new-beginning/SharedDependencies/Sources/libslirp/dhcpv6.c
2 views
/* SPDX-License-Identifier: BSD-3-Clause */1/*2* SLIRP stateless DHCPv63*4* We only support stateless DHCPv6, e.g. for network booting.5* See RFC 3315, RFC 3736, RFC 3646 and RFC 5970 for details.6*7* Copyright 2016 Thomas Huth, Red Hat Inc.8*9* Redistribution and use in source and binary forms, with or without10* modification, are permitted provided that the following conditions11* are met:12*13* 1. Redistributions of source code must retain the above14* copyright notice, this list of conditions and the following15* disclaimer.16*17* 2. Redistributions in binary form must reproduce the above18* copyright notice, this list of conditions and the following19* disclaimer in the documentation and/or other materials provided20* with the distribution.21*22* 3. Neither the name of the copyright holder nor the names of its23* contributors may be used to endorse or promote products derived24* from this software without specific prior written permission.25*26* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS27* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT28* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS29* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE30* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,31* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES32* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR33* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)34* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,35* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)36* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED37* OF THE POSSIBILITY OF SUCH DAMAGE.38*/3940#include "slirp.h"41#include "dhcpv6.h"4243/* DHCPv6 message types */44#define MSGTYPE_REPLY 745#define MSGTYPE_INFO_REQUEST 114647/* DHCPv6 option types */48#define OPTION_CLIENTID 149#define OPTION_IAADDR 550#define OPTION_ORO 651#define OPTION_DNS_SERVERS 2352#define OPTION_BOOTFILE_URL 595354struct requested_infos {55uint8_t *client_id;56int client_id_len;57bool want_dns;58bool want_boot_url;59};6061/**62* Analyze the info request message sent by the client to see what data it63* provided and what it wants to have. The information is gathered in the64* "requested_infos" struct. Note that client_id (if provided) points into65* the odata region, thus the caller must keep odata valid as long as it66* needs to access the requested_infos struct.67*/68static int dhcpv6_parse_info_request(Slirp *slirp, uint8_t *odata, int olen,69struct requested_infos *ri)70{71int i, req_opt;7273while (olen > 4) {74/* Parse one option */75int option = odata[0] << 8 | odata[1];76int len = odata[2] << 8 | odata[3];7778if (len + 4 > olen) {79slirp->cb->guest_error("Guest sent bad DHCPv6 packet!",80slirp->opaque);81return -E2BIG;82}8384switch (option) {85case OPTION_IAADDR:86/* According to RFC3315, we must discard requests with IA option */87return -EINVAL;88case OPTION_CLIENTID:89if (len > 256) {90/* Avoid very long IDs which could cause problems later */91return -E2BIG;92}93ri->client_id = odata + 4;94ri->client_id_len = len;95break;96case OPTION_ORO: /* Option request option */97if (len & 1) {98return -EINVAL;99}100/* Check which options the client wants to have */101for (i = 0; i < len; i += 2) {102req_opt = odata[4 + i] << 8 | odata[4 + i + 1];103switch (req_opt) {104case OPTION_DNS_SERVERS:105ri->want_dns = true;106break;107case OPTION_BOOTFILE_URL:108ri->want_boot_url = true;109break;110default:111DEBUG_MISC("dhcpv6: Unsupported option request %d",112req_opt);113}114}115break;116default:117DEBUG_MISC("dhcpv6 info req: Unsupported option %d, len=%d", option,118len);119}120121odata += len + 4;122olen -= len + 4;123}124125return 0;126}127128129/**130* Handle information request messages131*/132static void dhcpv6_info_request(Slirp *slirp, struct sockaddr_in6 *srcsas,133uint32_t xid, uint8_t *odata, int olen)134{135struct requested_infos ri = { NULL };136struct sockaddr_in6 sa6, da6;137struct mbuf *m;138uint8_t *resp;139140if (dhcpv6_parse_info_request(slirp, odata, olen, &ri) < 0) {141return;142}143144m = m_get(slirp);145if (!m) {146return;147}148memset(m->m_data, 0, m->m_size);149m->m_data += IF_MAXLINKHDR;150resp = (uint8_t *)m->m_data + sizeof(struct ip6) + sizeof(struct udphdr);151152/* Fill in response */153*resp++ = MSGTYPE_REPLY;154*resp++ = (uint8_t)(xid >> 16);155*resp++ = (uint8_t)(xid >> 8);156*resp++ = (uint8_t)xid;157158if (ri.client_id) {159*resp++ = OPTION_CLIENTID >> 8; /* option-code high byte */160*resp++ = OPTION_CLIENTID; /* option-code low byte */161*resp++ = ri.client_id_len >> 8; /* option-len high byte */162*resp++ = ri.client_id_len; /* option-len low byte */163memcpy(resp, ri.client_id, ri.client_id_len);164resp += ri.client_id_len;165}166if (ri.want_dns) {167*resp++ = OPTION_DNS_SERVERS >> 8; /* option-code high byte */168*resp++ = OPTION_DNS_SERVERS; /* option-code low byte */169*resp++ = 0; /* option-len high byte */170*resp++ = 16; /* option-len low byte */171memcpy(resp, &slirp->vnameserver_addr6, 16);172resp += 16;173}174if (ri.want_boot_url) {175uint8_t *sa = slirp->vhost_addr6.s6_addr;176int slen, smaxlen;177178*resp++ = OPTION_BOOTFILE_URL >> 8; /* option-code high byte */179*resp++ = OPTION_BOOTFILE_URL; /* option-code low byte */180smaxlen = (uint8_t *)m->m_data + slirp->if_mtu - (resp + 2);181slen = slirp_fmt((char *)resp + 2, smaxlen,182"tftp://[%02x%02x:%02x%02x:%02x%02x:%02x%02x:"183"%02x%02x:%02x%02x:%02x%02x:%02x%02x]/%s",184sa[0], sa[1], sa[2], sa[3], sa[4], sa[5], sa[6], sa[7],185sa[8], sa[9], sa[10], sa[11], sa[12], sa[13], sa[14],186sa[15], slirp->bootp_filename);187*resp++ = slen >> 8; /* option-len high byte */188*resp++ = slen; /* option-len low byte */189resp += slen;190}191192sa6.sin6_addr = slirp->vhost_addr6;193sa6.sin6_port = DHCPV6_SERVER_PORT;194da6.sin6_addr = srcsas->sin6_addr;195da6.sin6_port = srcsas->sin6_port;196m->m_data += sizeof(struct ip6) + sizeof(struct udphdr);197m->m_len = resp - (uint8_t *)m->m_data;198udp6_output(NULL, m, &sa6, &da6);199}200201/**202* Handle DHCPv6 messages sent by the client203*/204void dhcpv6_input(struct sockaddr_in6 *srcsas, struct mbuf *m)205{206uint8_t *data = (uint8_t *)m->m_data + sizeof(struct udphdr);207int data_len = m->m_len - sizeof(struct udphdr);208uint32_t xid;209210if (data_len < 4) {211return;212}213214xid = ntohl(*(uint32_t *)data) & 0xffffff;215216switch (data[0]) {217case MSGTYPE_INFO_REQUEST:218dhcpv6_info_request(m->slirp, srcsas, xid, &data[4], data_len - 4);219break;220default:221DEBUG_MISC("dhcpv6_input: Unsupported message type 0x%x", data[0]);222}223}224225226